/* ============================================================================
   HERO — the container, its layers, and the carousel that rides on top
   Structure comes from assets/js/hero-config.js; the engine writes the boxes.

   The frame is one full-bleed stage. Every layer fills it and they stack by z.
   There is no grid and no column split: a card that wants to cover half the
   hero does it with its own padding, not by the container carving up space.
   ========================================================================== */

.hero {
  background: var(--box);
  border-bottom: var(--ringer);
}

/* Every layer is absolutely positioned against this. `overflow: hidden` is
   what lets cards sit one viewport off stage without growing the page. */
.hero__frame {
  position: relative;
  overflow: hidden;
  isolation: isolate;
  background: var(--sky);
  height: min(calc(100vh - var(--nav-h)), 860px);
  height: min(calc(100svh - var(--nav-h)), 860px);
  min-height: 560px;
  touch-action: pan-y;
}

/* --------------------------------------------------------------- layer ---- */
/* One per entry in HERO_CONFIG.layers. The engine writes z-index,
   pointer-events and the transform; everything else is here. */
.hero-layer {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  will-change: transform;
}

/* Content the resolver builds, whatever type it turned out to be. */
.hero-content__img,
.hero-content__frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  border: 0;
  display: block;
}

.hero-content__img { object-fit: cover; }

/* ----------------------------------------------------- diorama · stage ---- */
.hero__stage {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: var(--sky);
}

.hero__layers {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity var(--dur-fade) var(--ease-fade);
}

/* One plate — the WHOLE plate. The engine writes width/height/left/top so the
   box holds the entire master at cover size, then translate3d + scale on top.

   `object-fit: fill` rather than `cover` on purpose: the box already matches
   the source's aspect exactly, so fill is lossless, and cover would reintroduce
   the crop this geometry exists to avoid. A plate is free to overflow the
   stage; the stage clips it at the frame, which is the whole bleed idea. */
.hero__layer {
  position: absolute;
  /* Placeholders only — measure() overwrites all four before the stack is ever
     revealed. They exist so a plate can never render at its intrinsic 2450px
     if anything goes wrong between build() and measure(). */
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: fill;
  transform-origin: 50% 55%;
  will-change: transform;
  backface-visibility: hidden;
}

/* The flattened comp paints immediately, holds the frame while the nine plates
   decode, and is all that ever shows under reduced motion or no-JS. */
.hero__static {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: none;
  object-fit: cover;
  object-position: 50% 55%;
}

.hero__stage[data-diorama-ready] .hero__layers { opacity: 1; }
.hero__stage[data-diorama-ready] .hero__static { visibility: hidden; }

@media (prefers-reduced-motion: reduce) {
  .hero__layers { display: none; }
  .hero__static { visibility: visible !important; }
}

/* --------------------------------------------------------- annotation ---- */
/* The callouts layer never takes a click — it is pointing at the scene, not
   offering anything. The engine sets pointer-events from the config; this is
   belt and braces for anything nested inside. */
.hero-layer[data-layer="annotation"] * { pointer-events: none; }

/* ------------------------------------------------------ HCAR · carousel --- */
.hcar {
  position: absolute;
  inset: 0;
}

.hcar__card {
  position: absolute;
  inset: 0;
  display: flex;
  overflow: hidden;

  /* Three independent nudges compose into one transform: --ox/--oy is the
     card's authored offset, --sx/--sy is where the transition has it right
     now, --sc is its scale. The engine only ever writes the pieces. */
  --ox: 0px;
  --oy: 0px;
  --sx: 0%;
  --sy: 0%;
  --sc: 1;
  transform: translate(calc(var(--ox) + var(--sx)), calc(var(--oy) + var(--sy)))
             scale(var(--sc));
  will-change: transform, opacity;
}

/* A blank card is a hole in the stack. Nothing to paint, nothing to catch. */
.hcar__card[data-blank] {
  background: none;
  pointer-events: none;
}

.hcar__controls {
  position: absolute;
  left: var(--gutter);
  bottom: var(--s4);
  z-index: 5;
  display: flex;
  align-items: center;
  gap: var(--s2);
}

.hcar__dots {
  display: flex;
  gap: var(--s1);
  list-style: none;
  padding: 0;
  margin: 0;
}

.hcar__dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: var(--radius-pill);
  background: var(--ink);
  opacity: 0.35;
  cursor: pointer;
  transition: width var(--dur-fast) var(--ease-slide), opacity var(--dur-fast);
}

/* The blank card's dot is drawn hollow — it is a stop on the cycle, but what
   it shows is the scene rather than a panel, and a filled dot would promise
   content that isn't coming. */
.hcar__dot[data-blank] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--ink);
}

.hcar__dot[aria-current="true"] { width: 24px; opacity: 1; }

.hcar__arrow {
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 2px solid var(--ink);
  border-radius: var(--radius-pill);
  background: transparent;
  color: var(--ink);
  cursor: pointer;
  line-height: 1;
}

.hcar__arrow:hover { background: var(--ink); color: var(--paper-warm); }

/* While the blank card is up the controls sit over the diorama, so they take
   the same paper-white-on-hard-shadow treatment the callouts do. */
.hcar[data-showing="blank"] .hcar__dot { background: var(--paper-warm); }
.hcar[data-showing="blank"] .hcar__dot[data-blank] {
  background: none;
  box-shadow: inset 0 0 0 2px var(--paper-warm), 2px 2px 0 var(--box);
}
.hcar[data-showing="blank"] .hcar__arrow {
  border-color: var(--paper-warm);
  color: var(--paper-warm);
  box-shadow: 2px 2px 0 var(--box);
}
.hcar[data-showing="blank"] .hcar__arrow:hover {
  background: var(--paper-warm);
  color: var(--box);
}

/* A dark card inverts its own text and controls. Cards declare `tone` in
   hero-cards.js and the engine writes it here — no guessing at backgrounds. */
.hcar[data-tone="dark"] {
  --slide-ink: var(--paper-warm);
  --slide-ink-soft: var(--sand);
}

.hcar[data-tone="dark"]:not([data-showing="blank"]) .hcar__dot {
  background: var(--paper-warm);
}
.hcar[data-tone="dark"]:not([data-showing="blank"]) .hcar__arrow {
  border-color: var(--paper-warm);
  color: var(--paper-warm);
}
.hcar[data-tone="dark"]:not([data-showing="blank"]) .hcar__arrow:hover {
  background: var(--paper-warm);
  color: var(--box);
}

/* --------------------------------------------------------- card panel ---- */
/* The shared look for a full-bleed type card. Content sits in a measured
   column against the left edge — full-width centred type at this size reads
   as a splash screen, and the diorama sliding away behind it should feel like
   a billboard turning over, not a modal opening. */
.hero-panel {
  flex: 1;
  display: flex;
  align-items: center;
  padding: var(--s5) var(--gutter);
  color: var(--slide-ink, var(--ink));
}

.hero-panel__inner {
  width: 100%;
  /* Fluid measure, not a `ch` count: at billboard size the limit that matters
     is a fraction of the frame, and a ch-based max-width collapses to the
     longest word while the eyebrows and the email underneath wrap to shreds. */
  max-width: clamp(18rem, 46vw, 46rem);
  display: flex;
  flex-direction: column;
  gap: var(--s3);
}

.hero-panel__inner--wide { max-width: min(46ch, 46vw); }

.hero-panel__eyebrow { color: inherit; opacity: 0.82; }

/* Bigger than it was: this card is the whole viewport now, not a 38% column,
   so the type has to hold a frame four times the width. Billboard scale. */
.hero-panel__headline {
  font-size: clamp(3rem, 6.4vw, 6.5rem);
  line-height: 0.9;
  letter-spacing: -0.015em;
  text-transform: uppercase;
  margin: 0;
  color: inherit;
}

.hero-panel__subline {
  font-family: var(--font-display);
  font-variation-settings: var(--display-variation);
  font-size: clamp(1.25rem, 2.1vw, 2rem);
  font-weight: 900;
  line-height: 1.1;
  margin: 0;
  color: inherit;
  opacity: 0.9;
}

.hero-panel__note {
  font-size: clamp(0.9375rem, 1.15vw, 1.0625rem);
  line-height: 1.55;
  margin: 0;
  max-width: 46ch;
  color: inherit;
  opacity: 0.78;
}

.hero-panel__note code {
  font-size: 0.875em;
  padding: 1px 5px;
  border-radius: 3px;
  background: rgba(23, 21, 20, 0.09);
}

.hcar[data-tone="dark"] .hero-panel__note code {
  background: rgba(255, 249, 238, 0.16);
}

.hero-panel__contact {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: var(--s2);
}

.hero-panel__email {
  font-family: var(--font-display);
  font-variation-settings: var(--display-variation);
  font-size: clamp(1.0625rem, 1.7vw, 1.5rem);
  font-weight: 900;
  color: inherit;
  text-decoration: none;
  border-bottom: 3px solid var(--rust);
  align-self: flex-start;
  overflow-wrap: break-word;
}

.hero-panel__email:hover { color: var(--rust-deep); }

/* ------------------------------------------------- callout fitting ----
   The callouts point at the figure, so their dots are welded to him and only
   the type can give. It scales with the viewport so the labels stay in
   proportion to the scene instead of ballooning on a wide monitor. The clamps
   saturate at their authored values rather than ending at a breakpoint, so
   there is no pop as the window crosses a width. */
@media (min-width: 768px) {
  .hero-layer[data-layer="annotation"] .annotation__label {
    font-size: clamp(0.5625rem, 0.72vw, var(--type-eyebrow));
    letter-spacing: clamp(0.08em, 0.15vw, 0.14em);
  }

  .hero-layer[data-layer="annotation"] .annotation__leader {
    width: clamp(16px, 3.4vw, var(--alen, 56px));
  }
}

/* --------------------------------------------------------- tilt chip ---- */
.hero__tilt {
  position: absolute;
  right: var(--s3);
  top: var(--s3);
  z-index: 40;
  display: none;
  border: var(--ringer);
  border-radius: var(--radius-pill);
  background: var(--paper-warm);
  color: var(--ink);
  padding: 8px var(--s3);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  cursor: pointer;
  box-shadow: var(--shadow-hard);
}

.hero__tilt[data-available="true"] { display: block; }

/* -------------------------------------------------------- responsive ----
   Nothing restructures. Every layer was already the full frame, so the only
   thing that changes on a narrow screen is how much room the type asks for. */
@media (max-width: 767px) {
  .hero__frame {
    height: min(calc(100vh - var(--nav-h)), 680px);
    height: min(calc(100svh - var(--nav-h)), 680px);
    min-height: 480px;
  }

  .hero-panel { padding: var(--s5) var(--gutter) calc(var(--s5) + 34px); }
  .hero-panel__inner { gap: var(--s2); }
  .hero-panel__note { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .hcar__card { transition: none !important; }
}

/* The comedic fine-print strip: static, never moves, never tints. */
.hero-strip {
  background: var(--paper-warm);
  border-top: var(--ringer);
  padding: var(--s3) var(--gutter);
}

.hero-strip p {
  max-width: 96ch;
  margin-inline: auto;
  text-align: center;
  font-size: 0.75rem;
  line-height: 1.55;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
