/* ═══════════════════════════════════════════════════════════════════════════
   MOBILE — a different page, not a squeezed one.

   Loaded via <link media="(max-width: 860px)">, so above 860px the browser
   never applies a single rule in this file. The desktop build is untouched by
   construction rather than by discipline.

   The desktop grammar is pinned viewport-height acts with scrubbed animation.
   On a phone that produced 16.6 screens of scroll, most of it dead. Here the
   engine is never mounted (see index.html), so there is no pin, no scrub and
   no cue reveal — every act is an ordinary block sized to its content, and the
   page reads as a long-form article that happens to be a landing page.

   The one deliberate motion is the brain, which assembles as its section
   arrives. Everything else is still.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── 1 · undo the pinned-stage geometry ───────────────────────────────────
   The engine is not mounted, so it adds no classes and writes no inline
   heights — but the page's own CSS still positions these for a pinned stage. */
.sc-act--pinned { height: auto !important; min-height: 0 !important; }
.sc-stage,
[data-sc-stage] {
  position: static !important;
  height: auto !important;
  min-height: 0 !important;
  overflow: visible !important;
}

/* `translate` is its own property in modern CSS and `transform: none` does NOT
   reset it — the lead copy carries `translate: 0 -50%` to centre itself against
   a pinned stage, which drags it up into the photograph by half its height. */
.sc-copy, .sc-copy--lead, .sc-copy--trail, .hero-copy,
.stage-copy, .whatis__stage, .whatis__copy, .whatis__mark,
.close, .hero-plate, .field, .roombox,
.resolve {
  position: static !important;
  inset: auto !important;
  transform: none !important;
  translate: none !important;
  rotate: none !important;
  scale: none !important;
  width: auto !important;
  height: auto !important;
  max-width: none !important;
}

/* scrollcraft.css ships `[data-sc-cue] { opacity: 0 }` and relies on the engine
   to reveal each block. With no engine there is no reveal to wait for. */
[data-sc-cue], [data-sc-cue] *,
[data-sc-kinetic], [data-sc-kinetic] * {
  opacity: 1 !important;
  transform: none !important;
  translate: none !important;
  transition: none !important;
  will-change: auto !important;
}

/* nothing left for these to sit over */
.sc-scrim, .wbg, .feed__orb, .whatis__mark { display: none !important; }

.hero-act [data-sc-stage] > *, .whatis__in, .slot, .slot img {
  transform: none !important; translate: none !important; scale: none !important;
  opacity: 1 !important; filter: none !important;
}

/* ── 2 · type ──────────────────────────────────────────────────────────────
   The fluid root bottoms out at its 16px floor on a phone, which puts body
   copy at 0.82rem = 13.1px. This page is to be read, so it gets 17px. */
:root {
  --sc-t-sm:   1.0625rem;
  --sc-t-base: 1.0625rem;
  --sc-t-xs:   0.8125rem;
}
.body, .lede { max-width: none; line-height: 1.62; }
.body + .body { margin-top: 16px; }
h1, h2 { text-wrap: balance; }
.sig, .eyebrow { letter-spacing: .18em; font-size: 10.5px; }

/* ── 3 · the page as a stack ──────────────────────────────────────────────*/
main > section { display: block; padding: 40px 0; background: var(--sc-canvas); }
main > section [data-sc-stage] { display: block; }
/* ── the header ───────────────────────────────────────────────────────────
   STICKY, not fixed. On desktop the bar is fixed and its background fades to
   transparent, so the hero runs up underneath it and the chrome floats over
   the picture. Solid black cannot float over anything - it would simply crop
   the top of whatever is beneath it - so here the bar takes its own place in
   the flow and sticks from there. Everything below starts under it by exactly
   its own height, with no offset to keep in sync by hand.

   `inset: auto` first: the desktop rule sets `inset: 0 0 auto 0`, and a sticky
   box honours left/right offsets too.

   The Talk to us button is held right by the space-between the desktop rule
   already sets, and it stands down over the closing act - body.at-close in
   index.html - because the page makes that same offer itself down there, and
   the header's copy of it would only point at where the reader already is. */
:root { --bar-h: calc(54px + env(safe-area-inset-top)); }  /* 12 + logo 30 + 12 */
.bar {
  position: sticky; inset: auto; top: 0;
  background: #000;
  /* the notch, which the page opts into with viewport-fit=cover */
  padding: calc(12px + env(safe-area-inset-top)) var(--sc-gutter) 12px;
  /* solid now, so nothing should fall through it to whatever scrolls beneath */
  pointer-events: auto;
}
/* The header's Talk to us stands down for the WHOLE of the last page. The
   act's own button is the one in view down there, so the header's copy of it
   would be the same ask twice on one screen.
   index.html hands that job to body.at-close, which trips at intersectionRatio
   > 0.5 - right for a pinned desktop act that snaps to filling the screen, but
   here the close is an ordinary block scrolled into a few hundred pixels at a
   time, so half a screen of it sat under a header still offering. The mobile
   script sets .at-close-m at threshold 0 instead: the moment any of the last
   page is on screen. */
body.at-close-m .bar .btn {
  opacity: 0; transform: translateY(-6px); pointer-events: none;
}

/* photographs break the column, edge to edge */
.hero-plate, .field {
  margin-inline: 0 !important; padding-inline: 0 !important; border-radius: 0;
}
/* The two product screens do NOT. They are interface rather than photography:
   run to the edges they read as the page's own chrome instead of a thing being
   shown, and the transcript inside ran straight into the screen edge. They sit
   in the same column as the copy, on the same gutter, so they line up with it.
   The rounded corner comes back with the inset - it was only zeroed because a
   radius on a full-bleed block clips against nothing. */
.live__media, .calls__side {
  margin-inline: 0 !important;   /* .live__media is margin-left:auto on desktop */
  padding-inline: var(--sc-gutter);
}
/* both blocks carry the gutter now, so what is inside them must not carry it
   a second time or it lands at twice the inset */
.calls__side .calls__tag, .live__media .live__ctrl { padding-inline: 0; }
.live__screen, .calls__screen { overflow: hidden; }

/* ── a headline laid into its own photograph ──────────────────────────────
   Two acts on this page put a line over a picture. On desktop each is a
   pinned stage: the photograph fills the screen, a scrim darkens part of it,
   the words sit on that. Nothing is pinned here, so the band is built - and
   the PHOTOGRAPH KEEPS ITS OWN SHAPE. Stretching one to fill a portrait act
   cropped a 3:2 or 16:9 frame to roughly 1:2, which threw the room away.

   The heading carries the picture as its own background rather than
   overlapping a separate <img>: one box, so the band cannot drift out of
   register with the words inside it at any width. Both images are decorative
   (alt="") so hiding the <img> loses nothing.

   NOT flex. Each heading is a text node either side of a coloured <span>, and
   flex makes every one of those a separate item - the sentence came out as
   two columns side by side. `align-content` positions the block's own content
   without touching the inline flow. Where it is unsupported the words sit at
   the top of the band, which is a shrug rather than a break.

   Which part of the picture gets darkened, and where the words sit in it, is
   the difference between the two - so each passes its own scrim and anchor. */
.hero-act [data-sc-stage] > h1, #talk .close h2 {
  margin: 0;
  /* desktop holds these to 20ch, which here shrinks the band to the width of
     the words rather than the width of the screen */
  width: 100%; max-width: none;
  aspect-ratio: var(--band-ar);
  display: block; align-content: var(--band-anchor, center);
  line-height: 1.2;
  background-image: var(--band-scrim), var(--band-img);
  background-size: cover;
  background-position: center;
}

/* hero — the opening claim ON the picture, along its darkened top edge. The
   plate goes: the h1 carries the photograph itself now, so keeping the <img>
   as well would be the same picture twice, once above the other. */
.hero-act { padding-top: 0; }
.hero-act [data-sc-stage] { display: flex; flex-direction: column; }
.hero-plate { display: none; }
.hero-copy { padding: 22px var(--sc-gutter) 0; }
.hero-act [data-sc-stage] > h1 {
  --band-img: url(assets/hero.jpg);
  --band-ar: 2200 / 1467;
  --band-anchor: start;
  /* Down the frame rather than across it. The words run the full width here,
     so there is no clear side to push them to - the darkening has to be the
     top edge they sit on. It is gone by two-thirds down, which leaves the
     table and the room itself untouched. */
  --band-scrim: linear-gradient(to bottom,
    color-mix(in oklab, var(--sc-canvas) 90%, transparent) 0%,
    color-mix(in oklab, var(--sc-canvas) 80%, transparent) 30%,
    color-mix(in oklab, var(--sc-canvas) 34%, transparent) 56%,
    transparent 78%);
  padding: 26px var(--sc-gutter) 0;
  font-size: clamp(2rem, 1.2rem + 4.2vw, 2.7rem);
  /* NOT balanced. `text-wrap: balance` (set on every h1/h2 further up) evens
     the lines out, which broke this after "training". Filling each line in
     turn puts "Taking training to the" on the first, which is what it should
     read - and it fits at this size from 390px up. Narrower than that it falls
     back a word at a time on its own; the alternative was shrinking the type
     on every phone to suit the smallest.
     `wrap`, not `normal`: the shorthand takes wrap | nowrap | balance | stable
     | pretty, so `normal` is invalid, is dropped, and leaves balance standing. */
  text-wrap: wrap;
}

/* whatis — heading, then the brain, then the argument. The brain is moved
   between them by the mobile script; stranded under three paragraphs it was
   both the wrong shape for the section and too late to be worth animating. */
.whatis__copy { padding: 0 var(--sc-gutter); text-align: left !important; }
.whatis__copy h2 { font-size: clamp(1.9rem, 1.1rem + 4vw, 2.6rem) !important; }
/* the m-brain block is created by the mobile script; no desktop rule names it.
   THIS is the still state: brain and lockup, stacked, nothing moving. It is
   what a reduced-motion reader gets, and what everyone sees before the
   section arrives. The chip cluster in section 4 is layered over it. */
.m-brain { display: block; padding: 26px 0 8px; text-align: center; }
.m-brain__img { display: block; width: min(58%, 226px); height: auto;
  margin: 0 auto; }
.m-brain__logo { display: inline-flex; margin-top: 14px; --logo-h: 30px; }
.m-chips, .m-brain__orb, .m-float, .m-slide { display: none; }

/* method */
.field { display: grid !important; grid-template-columns: repeat(2, 1fr);
  gap: 2px; padding: 0 !important; margin: 0 !important; }
.field .slot { aspect-ratio: 16 / 10; border-radius: 0; }
.roombox { display: none !important; }
/* ── the scale act ────────────────────────────────────────────────────────
   Heading, then two photographs, then the argument.

   A REAL GRID, with the pictures as <img> under object-fit: cover. An earlier
   attempt put them on the heading as two background layers at
   `background-size: 50% 100%`, which does not crop to half the box - it SCALES
   the image to exactly that size, so both were squeezed from 16:10 into 4:5
   and everyone in them stretched. cover crops; a two-value background-size
   does not.

   The tile is 1.52, read off the reference shot and near enough the ratio they
   had in the 2x2 grid, so the magnification is what it was.

   The heading sits ABOVE the band rather than on it. At this height it could
   not be laid on it: three lines come to 203px against a 128px band, so it
   would have overhung the pictures by 75px onto the copy. */
#method [data-sc-stage] { display: flex !important; flex-direction: column; }
.stage-copy { padding: 0; background: none !important; }
/* lifted out of .stage-copy by the mobile script, so it carries its own gutter
   and its own place in the order */
#method [data-sc-stage] > h2 {
  order: -1; margin: 0 0 20px; max-width: none;
  padding: 0 var(--sc-gutter);
  /* the size is set by `.stage-copy h2`, and moving this out of .stage-copy
     stopped that selector matching - it fell back to the base h2 and lost a
     third of its size. Restated here, same value, so the move is a move. */
  font-size: 2.41rem;
}
#method .field { display: grid !important; grid-template-columns: repeat(2, 1fr);
  gap: 0; }
#method .field .slot { aspect-ratio: 1.52; border-radius: 0; }
#method .stage-copy .body { padding: 0 var(--sc-gutter); }
#method .stage-copy .body:first-of-type { margin-top: 0; padding-top: 24px; }
#method .stage-copy__in > :last-child { padding-bottom: 22px; }

/* expert + delivers */
.live, .calls { display: block !important; padding: 0 !important; }
.live__copy, .calls__copy { padding: 0 var(--sc-gutter); }
.live__media, .calls__side { margin-top: 20px; }
.calls__tag { padding: 0 var(--sc-gutter); }
/* The mobile script lifts the two heading lines out of .calls__copy and sets
   them ahead of the screen, so the act reads heading, clip, argument. Out of
   that box they are direct children of .calls and carry their own gutter. */
.calls > .sig, .calls > h2 { padding: 0 var(--sc-gutter); }
.calls > h2 { margin-bottom: 4px; }
.calls > .calls__copy { margin-top: 22px; }
/* the clip plays here, so it is the image and the standalone poster is not
   needed - the video carries call-poster.jpg as its own poster attribute for
   the case where autoplay is refused. 832x520 against the frame's 1280x800 is
   the same 1.6, so height:auto fills it exactly. */
.calls__screen .sc-stage__poster { display: none !important; }
.calls__screen video {
  position: static !important; opacity: 1 !important;
  width: 100% !important; height: auto !important; display: block;
}
.live__ctrl { justify-content: flex-start; padding: 0 var(--sc-gutter); }
/* the closing line of the Call Scenarios act: absolute against the pinned
   stage on desktop, an ordinary paragraph here */
.resolve { display: block; margin: 24px 0 0; padding: 0 var(--sc-gutter) !important; }

/* close */
.close__in { padding: 0 var(--sc-gutter) !important; }
/* ONE ASK AT A TIME, settled the other way round from desktop: the sticky
   header keeps the offer, so the closing act's own button - the one sitting
   just above the 2026 credit - would be the second copy of it on screen. The
   heading and the lede still make the case; the button to act on it is a
   thumb-reach away at the top of the screen. */
/* the act's own ask, centred under the lede, with room between it and the
   credit - flush against the footer it read as part of it */
.close .ctas { display: flex; justify-content: center; margin: 26px 0 0; }
.close .ctas .btn { margin: 0; }
/* No rule above the footer: on desktop it divides the credit from a pinned
   closing act that shares its screen. Here nothing shares the screen with it,
   so the line was drawing a border around nothing.
   It sits ON the bottom of the page - the section gives up its closing
   padding so there is no strip of canvas below the credit. env() keeps the
   text clear of the home indicator on a notched phone, which the page already
   opts into with viewport-fit=cover. */
/* the close — the words down the darkened LEFT of the frame, as on desktop,
   with the right of it hers */
#talk .close h2 {
  --band-img: url(assets/close.jpg);
  --band-ar: 1920 / 1080;
  --band-scrim: linear-gradient(to right,
    color-mix(in oklab, var(--sc-canvas) 92%, transparent) 0%,
    color-mix(in oklab, var(--sc-canvas) 80%, transparent) 34%,
    color-mix(in oklab, var(--sc-canvas) 34%, transparent) 70%,
    color-mix(in oklab, var(--sc-canvas) 8%, transparent) 100%);
  padding: 0 40% 0 var(--sc-gutter);
  font-size: clamp(1.45rem, .87rem + 2.6vw, 2rem) !important;
  text-wrap: pretty;
}
#talk { padding: 0 !important; }
#talk .sc-stage__poster { display: none !important; }
/* the closing padding is what keeps the button off the credit; it is stated
   here rather than in the .ctas rule above because this shorthand is later in
   the file and was flattening it */
#talk .close__in { padding: 0 0 46px !important; display: block; }
#talk .close .lede { padding: 22px var(--sc-gutter) 0; margin: 0; }
#talk .close .ctas { padding: 0 var(--sc-gutter); }
.foot { border-top: 0;
  padding: 20px var(--sc-gutter) calc(26px + env(safe-area-inset-bottom)); }

/* ── 4 · the brain: zoom, then the six slide out ──────────────────────────
   The "Zoom + Slide Out" design. Unlike the chip-cluster build this one opens
   on the FINISHED brain and lockup - there is no cluster to assemble - and the
   whole composition eases up from 0.62 while the six sources come back out of
   the brain, top first, alternating sides, out of a gold slit in its flank.

   MOBILE ONLY, twice over: this file is loaded media="(max-width: 860px)" and
   the desktop act is a scrubbed thing in index.html that never sees a rule
   from here. No engine, no scroll coupling - a timed CSS animation that starts
   when the section arrives.

   The source runs 12s; everything here is that timeline x 0.72:
     zoom      0 -> 1.7s        ->  0 -> 1.22s, from 0.62 about (540,520)
     lockup    0.5s             ->  0.36s
     slide     2.5s + 0.68 each ->  1.80s + 0.49 each, over 1.66s
     total     12s              ->  8.64s                                   */
@media (prefers-reduced-motion: no-preference) {
  .m-brain {
    /* Decorative, aria-hidden, and nothing in it is interactive - but it hangs
       over what follows it by its own negative bottom margin, so its layers
       were swallowing taps meant for the control underneath. */
    pointer-events: none;
    position: relative; width: 100%; aspect-ratio: 1 / 1.45;
    padding: 0; margin: 18px 0 0;
    --dur: 8.64s;
    /* No cluster ever fills the lower half here, so the frame gives that
       height back from the start rather than animating it away. */
    margin-bottom: -49.7%;
    /* the whole composition eases up, as the source does, about the point the
       brain and its lockup balance on */
    transform-origin: 50% 36.1%;
  }
  .m-brain > * { position: absolute; margin: 0; }

  .m-brain__img {
    left: 50%; top: 29.9%; width: 61.1%; height: auto;
    /* CENTRING IS `translate`, NOT `transform`: the individual properties
       compose as translate . rotate . scale . transform, so a transform
       translate would be applied inside any scale and shrink with it. */
    translate: -50% -50%;
    filter: brightness(1.2);
  }
  .m-brain__logo {
    left: 50%; top: 55.3%; margin: 0;
    translate: -50% 0;
    --logo-h: clamp(26px, 8vw, 38px);
    opacity: 0;
  }

  .m-slide { display: block; inset: 0; pointer-events: none; }
  .m-line {
    position: absolute; left: 0; top: var(--y); width: 100%; margin: 0;
    font-family: var(--sc-font-display);
    /* The page's own colouring: ink for the sentence, and the accent gold on
       the one phrase each line already carries from the desktop list it is
       cloned from. Nothing overrides those spans, so they come through here
       exactly as they do everywhere else on the page. */
    color: var(--sc-ink);
    /* the source's 36pt in a 1080 frame is 11.7px here, under this page's
       floor for serif at body size; nudged up rather than set to it */
    font-size: clamp(11px, 3.3vw, 17px); line-height: 1.16;
    /* bold in both options: weight is doing some of the work contrast cannot,
       and it costs nothing on the dimmed one */
    font-weight: 700;
    text-align: center; white-space: nowrap;
    text-shadow: 0 1px 2px rgba(0,0,0,.95), 0 2px 18px rgba(0,0,0,.95),
                 0 0 44px rgba(0,0,0,.85);
  }
  .m-line__cut {
    position: absolute; left: var(--slit); top: -6%;
    width: .37%; height: 112%; border-radius: 3px;
    background: var(--sc-accent); box-shadow: 0 0 24px var(--sc-accent);
    opacity: 0;
  }
  .m-line__t {
    display: block; opacity: 0;
    clip-path: inset(-40% var(--r0) -40% var(--l0));
  }

  .m-float { display: block; inset: 0; z-index: 0;
    --float-dur: 24s;               /* one card's crossing, end to end */
    /* CLIPPED, not just masked. A card's track runs from -24% to 106% so it is
       clear of the frame at both ends - and a mask only changes what is
       painted, not what is laid out, so the overhang widened the document and
       the page scrolled sideways. */
    overflow: hidden;
    -webkit-mask-image: linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%);
    mask-image: linear-gradient(to right, transparent 0, #000 14%, #000 86%, transparent 100%); }
  .m-float figure {
    position: absolute; margin: 0; overflow: hidden;
    top: var(--y); width: var(--w); aspect-ratio: 16 / 10;
    border-radius: 5px;
    /* the page's own cyan, as a hairline. .5px is one device pixel on a phone,
       where 1px is two and reads as a drawn frame rather than a screen edge;
       the glow that was under it is gone for the same reason. */
    border: .5px solid rgba(95, 212, 232, .7);
    box-shadow: 0 12px 30px -14px rgba(0, 0, 0, .8);
    opacity: 0;
  }
  .m-float img { width: 100%; height: 100%; object-fit: cover; display: block;
    filter: brightness(1.35) saturate(1.1); }

  /* nothing runs until the section is reached */
  .whatis.is-seen .m-brain       { animation: m-zoom 1.22s cubic-bezier(.33,1,.68,1) both; }
  .whatis.is-seen .m-brain__img  { animation: m-dim .79s cubic-bezier(.65,0,.35,1) 1.58s both; }
  .whatis.is-seen .m-brain__logo { animation: m-lock-in .54s cubic-bezier(.34,1.56,.64,1) .36s both; }
  .whatis.is-seen .m-line__t {
    animation: m-unroll 1.66s cubic-bezier(.33,1,.68,1) both calc(1.8s + var(--i) * .49s);
  }
  .whatis.is-seen .m-line__cut {
    animation: m-cut 1.66s linear both calc(1.8s + var(--i) * .49s);
  }
  .whatis.is-seen .m-float figure {
    animation: m-cross var(--float-dur) linear infinite
                       calc(var(--i) * (var(--float-dur) / -9)),
               m-fade var(--dur) linear both;
  }
}

/* The brain settles back far enough for the wordmark yellow to be read on it,
   0.47, a shade lighter than the source's own 0.42.

   The ink carries the sentence and clears 3:1; the gold phrase inside it is
   the weaker half, because gold's luminance (0.488) sits close to a half-lit
   brain's, and dimming drags the ground THROUGH it rather than away from it -
   which is why the trough in the table below is in the middle rather than at
   one end. What softens is emphasis, not meaning: these lines are decorative
   and every word of them is repeated in the paragraphs beneath.
   It clears 3:1 rather than 4.5:1; these lines are decorative and every word of
   them is repeated in the paragraphs below, so the shortfall costs no meaning.

   Dimming is not simply "more contrast": the ground travels THROUGH the text's
   own brightness on its way down, so there is a worst point in the middle, not
   at one end. For the accent gold (L 0.488) that trough is around 0.7, where
   the two sit at 1.15:1 and the words all but vanish. The wordmark yellow
   (L 0.643) is higher up, so it clears the trough sooner. Measured:

              ground   gold #E4B24A   ink #F3ECE4
     1.2      0.989      1.93:1          1.42:1
     0.70     0.418      1.15:1          1.48:1
     0.50     0.205      2.11:1          2.71:1
     0.42     0.143      2.79:1          3.59:1
     0.45     0.166      2.49:1          3.21:1   <- here
     0.40     0.129      2.94:1          3.86:1
     0.35     0.099      3.61:1          4.72:1
     0.30     0.074      4.35:1          5.60:1                                */
@keyframes m-dim { to { filter: brightness(.47); } }

/* up from 0.62, as the source opens */
@keyframes m-zoom { from { scale: .62; } to { scale: 1; } }

/* the window onto the line opens from the slit outward in both directions at
   once, and the line settles the last few pixels inward as it lands */
@keyframes m-unroll {
  from { clip-path: inset(-40% var(--r0) -40% var(--l0));
         transform: translateX(var(--dx)); opacity: 0; }
  20%  { opacity: 1; }
  to   { clip-path: inset(-40% var(--r1) -40% var(--l1));
         transform: translateX(0); opacity: 1; }
}
/* a cut, not a fade: up fast, gone by halfway, as the line clears it */
@keyframes m-cut {
  0%   { opacity: 0; }
  24%  { opacity: .85; }
  50%, 100% { opacity: 0; }
}
@keyframes m-lock-in { from { opacity: 0; scale: .9; } to { opacity: 1; scale: 1; } }

/* left of the frame to right of it, so each card is clear at both ends */
@keyframes m-cross { from { left: -24%; } to { left: 106%; } }
/* the evidence arrives once the argument has, not before */
@keyframes m-fade {
  0%, 74%   { opacity: 0; }
  88%, 100% { opacity: .85; }
}
}
