/* ============================================================
   Introduction page — cinematic intro animation
   Scoped entirely to the About/Introduction hero media.
   Does NOT alter the final layout: the resting state equals
   the original .page-feature image box exactly.
   Honors prefers-reduced-motion and a localStorage skip flag.
   ============================================================ */

/* The media container keeps its normal grid placement. The
   intro only adds transforms/overlays on top; at rest it is
   visually identical to the original feature image. */
.intro-media{position:relative}

/* Fixed-aspect stage so the <video> and base <img> share one
   coordinate box (1782x1080 = 1.65:1, the ratio of the final
   introduction image). The 16:9 clip is cover-cropped to it and
   crossfades to the exact still, so the resting frame matches. */
.intro-stage{position:relative;display:block;width:100%;max-width:990px;margin:0 auto;aspect-ratio:1782 / 1080;overflow:hidden;background:var(--surface,#fff)}
.intro-stage .hero-panels{position:absolute;inset:0;width:100%;height:100%}
.intro-stage .intro-video{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;display:block;margin:0;max-height:none;pointer-events:none}
/* The animated video sits above the base still while it plays; GSAP drives its
   opacity (shown at start, faded back to the exact base still at the end). */
.intro-stage .intro-video{z-index:2;opacity:0}

/* Fixed backdrop behind the enlarged media — white, to match the site background. */
.intro-backdrop{position:fixed;inset:0;z-index:90;background:var(--surface,#fff);opacity:0;pointer-events:none}

/* ---- States driven by the inline head guard / JS ---- */
/* While the intro is armed, hide the copy and lift the media
   above the backdrop. Set before first paint to avoid FOUC. */
.intro-active .page-title > *{opacity:0;transform:translateY(22px);will-change:opacity,transform}
.intro-active .intro-media{z-index:95;opacity:0;will-change:transform}
.intro-active .intro-backdrop{opacity:1}
.intro-active .intro-stage .zoom-cue{opacity:0}
/* Cover the resting triptych (panels + 2 white dividers) from the first paint,
   so it can't flash before the clip fades in. The clip is opaque (object-fit
   cover), so the panels stay hidden beneath it; GSAP fades the clip back to 0
   at the end to reveal the exact resting panels underneath. */
.intro-active .intro-stage .intro-video{opacity:1}

/* Reduced motion OR repeat visit: never arm the intro — the page
   renders straight to its normal final layout (no overlay shown). */
@media (prefers-reduced-motion:reduce){
  .intro-active .page-title > *{opacity:1;transform:none}
  .intro-active .intro-media{opacity:1;z-index:auto}
  .intro-active .intro-backdrop{display:none}
}

/* About page only (this stylesheet loads only on the Introduction page):
   widen the feature-media column and tighten the copy so the two hero
   columns match height and align neatly. Desktop only — below 920px the
   hero stacks, so the base single-column layout/type is left untouched.
   Does not affect the intro animation (it measures the live size at runtime). */
@media (min-width:921px){
  .page-hero-inner{grid-template-columns:minmax(0,1fr) minmax(0,1.4fr)}
  /* smaller headline (-20px at desktop) + tighter eyebrow->h1 gap (-12px) */
  .page-title h1{font-size:clamp(44px,5.7vw,76px);margin:6px 0 18px}
  .page-title p{font-size:18.5px;line-height:1.5}
}

/* ============================================================
   Interactive 3-panel hero (replaces the single intro image).
   Three clean image cells + two CSS divider lines tile to the
   exact 1782x1080 triptych. On reveal each side cell + its
   divider slide off, the centre cell eases 1.08 -> 1.0, and the
   capability cards behind the side cells fade/slide toward centre.
   GPU transforms only; no layout shift.
   ============================================================ */
.hero-panels{overflow:hidden;background:var(--surface,#fff)}

/* 3 image cells + 2 white dividers — flat flex, exact proportions, seamless */
.panel-row{position:absolute;inset:0;z-index:2;display:flex;height:100%}
.panel-row .pcell{position:relative;height:100%;overflow:hidden;backface-visibility:hidden}
.panel-row .pcell--left{flex:0 0 32.604%}                          /* 581 / 1782 */
.panel-row .pcell--mid{flex:0 0 32.884%;transform-origin:50% 50%}  /* 586 / 1782 */
.panel-row .pcell--right{flex:0 0 32.604%}                         /* 581 / 1782 */
.panel-row .pdiv{flex:0 0 0.9540%;height:100%;background:#fff}      /* 17 / 1782 */
.panel-row .pimg{width:100%;height:100%;object-fit:cover;display:block}
.panel-row .pcell,.panel-row .pdiv{will-change:transform}

/* capability cards sit behind the side cells; revealed when those slide away.
   Two equal rows rather than a centred flex stack: the columns are separate
   elements, so centring each one placed Build/Ship and Brand/Design at
   different heights whenever their paragraphs wrapped to a different number of
   lines (Ship takes 2 where the others take 3 on wide screens). Splitting the
   full height into two identical rows and starting each card at its row top
   makes the icons and headings line up across the columns at any line count.
   Vertical padding is a percentage so it tracks the stage's fixed 1782/1080
   ratio: 8.5% of width is ~14% of height, which keeps the pair sitting where
   the centred version put it. */
.hero-cards{position:absolute;top:0;height:100%;z-index:1;display:grid;grid-template-rows:1fr 1fr;
  align-items:start;gap:clamp(14px,2.2vw,30px);padding:8.5% clamp(12px,2vw,26px);box-sizing:border-box}
/* on a small stage the four cards nearly fill the frame, so give the rows the
   space back rather than clipping the last line against overflow:hidden */
@media(max-width:560px){.hero-cards{padding-block:3%;gap:clamp(8px,2.2vw,30px)}}
/* justify-items, not align-items: in grid the inline axis is the horizontal one */
.hero-cards--left{left:0;width:33.558%;justify-items:end;text-align:right}   /* (581+17)/1782 — mirrors right col toward centre */
.hero-cards--right{right:0;width:33.558%;justify-items:start}
.hero-cards--left .cap-card__ic{margin-left:auto}   /* push icon to the right edge */
/* min-height:0 overrides a grid item's automatic minimum, which would otherwise
   let a tall card grow its row and drag the second row out of step with the
   other column at small sizes */
.cap-card{max-width:100%;min-height:0;opacity:0;will-change:transform,opacity}
.hero-cards--left .cap-card{transform:translateX(-34px)}
.hero-cards--right .cap-card{transform:translateX(34px)}
.cap-card__ic{display:flex;width:clamp(24px,2.1vw,32px);height:clamp(24px,2.1vw,32px);color:var(--accent);margin:0 0 clamp(6px,.8vw,10px)}
.cap-card__ic svg{width:100%;height:100%}
.cap-card h2{font-family:var(--font-head,inherit);font-weight:800;letter-spacing:-.01em;font-size:clamp(15px,1.55vw,21px);line-height:1.1;color:var(--ink);margin:0 0 4px}
.cap-card p{font-size:clamp(11px,1.04vw,14px);line-height:1.4;color:var(--muted);margin:0}
/* Desktop-only forced breaks (Brand), so its paragraph sets in three lines like
   the rest. Hidden below the hero's 921px stacking point, where the card is far
   narrower and the text is better left to wrap on its own. The source keeps a
   space before the first break and the existing &nbsp; pair after the second, so
   with the breaks suppressed the paragraph reads exactly as it did before. */
.cap-card .lb{display:none}
@media(min-width:921px){.cap-card .lb{display:inline}}

.intro-stage[data-hero-reveal]{cursor:pointer}

/* Instant reveal fallback (reduced-motion, or any no-GSAP path): JS adds .is-revealed */
.is-revealed .pcell--left,.is-revealed .pdiv--1{transform:translateY(116%)}
.is-revealed .pcell--right,.is-revealed .pdiv--2{transform:translateY(-116%)}
.is-revealed .pcell--mid{transform:scale(1)}
.is-revealed .cap-card{opacity:1;transform:none}

/* Phones: the stage keeps its 1782/1080 ratio, so at 360-430px it is only
   ~190-230px tall with two ~105px columns. The descriptions wrapped to three
   and four lines there and the Design card overflowed the stage's hidden
   overflow, clipping its last line. The icon and label already carry the
   meaning at this size, so the description steps out below 560px. The reveal,
   its timing, and every other element are untouched. */
@media(max-width:560px){
  .cap-card p{display:none}
  .cap-card h2{font-size:14px}
  .cap-card__ic{width:22px;height:22px;margin-bottom:8px}
}
