/* ============================================================
   Origin — 1:1 build of the Figma frame (226:2), re-hung on the site's
   horizontal grid.

   The Figma artboard floats its own margins (headings from x=83, body from
   x=92, everything ending at x=1854). The site has ONE source of truth for the
   page edge — `--gutter` in styles.css, which is literally the nav's left/right
   padding — so this page drops the artboard margins and pins to that instead:

     .origin-frame  = max-width 120rem + margin auto + padding 0 var(--gutter)
                      → byte-for-byte the same box as <header>.
     .origin-inner  = the positioning context, so a child at left:0 starts on
                      the "FloriumStudio" F and a child at right:0 ends on the
                      "Reach out" t.

   Everything left-hand (Origin, Mindset, both narrow paragraphs) is anchored to
   left:0; everything right-hand (Driven, Think, both wide paragraphs) to
   right:0. The interior words (By, &, Design, Execute) hold their proportional
   place: the artboard's content box is 1771px wide and the nav's is 1840px, so
   their offset is the Figma offset × 1840/1771.

   Type sizes, vertical positions and column widths are untouched from Figma, so
   every paragraph still breaks on exactly the same words as the artboard.
   Authored in rem against the site's 1920 design root (value = figma-px / 16).

   STRUCTURE: the artboard composition lives entirely inside the ≥820px query,
   and the phone stack entirely inside the ≤819px one. Nothing is undone across
   the breakpoint — the absolute placement is per-element (#ids), and an id
   outranks any class-level reset, so a desktop-first rule here would leak its
   heights and widths into the phone layout instead of being overridden.
   ============================================================ */

@font-face {
    font-family: 'Geist Mono';
    src: url('geist-font-v1.7.2/geist-font/GeistMono/webfonts/GeistMono-Regular.woff2') format('woff2');
    font-weight: 400;
    font-display: swap;
}

:root {
    /* THE WHOLE PAGE IS BLACK — the field's churn reads far better inverted, so
       what used to be only the People band is now the entire document. The
       artboard was white; this is a deliberate departure from it.

       Set as tokens rather than as hard-coded colours so everything in
       styles.css that already reads them — body, the header, --border-style —
       follows without being touched. */
    --color-bg: #000000;
    --color-text: #ffffff;

    /* Body copy and the service notes, lifted off the artboard grey the way the
       People band's field always was. #666 on black is unreadable. */
    --mono-grey: #8f8f8f;
}

/* ------------------------------------------------------------
   Shared — box, type, colour. No positioning.
   ------------------------------------------------------------ */
/* The team band bleeds past the frame to the full viewport width, so the page
   has to tolerate a child wider than itself. `clip` rather than `hidden`: it
   does not create a scroll container, so the fixed header is unaffected.

   It has to be set on BOTH. An overflow on <body> alone propagates up to the
   viewport and leaves the body itself visible — so the bleed escaped and put a
   horizontal scrollbar on the page. Naming it on <html> stops the propagation
   and lets the body actually do the clipping. */
html, body { overflow-x: clip; }

/* The page ENDS black (see the footer, far below), so the canvas is black and
   the body paints its white over the top of it. body's background-color would
   otherwise propagate to the canvas and there would be white in every direction
   the document does not reach — most visibly on an overscroll bounce at the
   bottom, right after the black footer. Giving html a background of its own is
   what stops that propagation. */
html { background: #000000; }

/* The nav strip is transparent on THIS page only (origin.css loads nowhere else).
   Everywhere else the header paints var(--color-bg) to occlude what scrolls under
   it; here the field is meant to run all the way to the top of the screen with
   the links floating on it, which a painted strip cuts off. Readability is no
   longer conditional — the page is black throughout, so the links are simply
   white and nav-theme.js has nothing left to switch. */
header { background: transparent; }
/* The page is dark from top to bottom, so the nav is white the whole way down
   and the pixel tulip is inverted throughout — no longer something nav-theme.js
   has to switch on and off per section. */
.nav-logo { filter: invert(1); }

.origin-frame {
    width: 100%;
    max-width: 120rem;
    margin: 0 auto;
    padding: 0 var(--gutter);
}

/* ============================================================
   The cube — this page's opening. See origin-cube.js.

   It is an OVERLAY, not a section: the page underneath is real and already
   running, which is why picking a section can hand straight over to a live band
   instead of loading one. The overlay only holds the page still and covers it.
   ============================================================ */
/* Hidden unless the pre-paint gate in the <head> has decided the cube is
   opening this page. `display: none` rather than `opacity: 0`, so on a phone or
   without WebGL the overlay never paints at all — and so that when it IS
   opening, the black is up on the first frame instead of fading in over a page
   the visitor has already read. */
.cube-root {
    position: fixed;
    inset: 0;
    z-index: 90;                    /* over the page, under the consent panel */
    display: none;
}
html.cube-up .cube-root { display: block; }

/* The black ground. A LAYER rather than a background on .cube-root, so the
   wordmark and the canvas have something to sit on that is not the root's own
   paint — the root is what fades on the hand-over, and it has to take the whole
   stack with it in one go. */
#veil {
    position: fixed;
    inset: 0;
    z-index: 0;
    background: #000000;
    pointer-events: none;
}

/* ---- the Figma layout, 1:1 (frame 196:2, 1920×1080) ----
   Copied from studio-cube.html unchanged — this IS that page's layout; the only
   thing that differs is what the six faces are made of.

   --u is one design px (100vw/1920, uncapped — the hero scales as a whole). The
   giant "Studio" is bottom-anchored with the frame's exact 110px overhang past
   the bottom edge, so it stays cropped on every aspect ratio; the list holds
   Figma's x=1471 / y=102. Both sit BEHIND the transparent WebGL canvas, so the
   cube's faces occlude them and the see-through padding doesn't. */
.fig-stage {
    --u: calc(100vw / 1920);
    position: fixed; inset: 0;
    z-index: 1;
    pointer-events: none;
    font-family: 'Geist Sans', sans-serif;
    font-weight: 400;
    color: #ffffff;
    overflow: hidden;
}
.fig-studio {
    position: absolute;
    left: 0;
    bottom: calc(-110 * var(--u));          /* Figma: text block runs 110px past the frame */
    font-size: calc(500 * var(--u));
    line-height: 1.3;                        /* 650 / 500 */
    letter-spacing: -0.02em;                 /* -10px at 500 */
    white-space: nowrap;
}

/* The list is its own fixed layer ABOVE the canvas (a child of .fig-stage could
   never receive clicks through it) — same Figma coords, now interactive. */
.fig-nav {
    --u: calc(100vw / 1920);
    position: fixed;
    left: calc(1471 * var(--u));
    top: calc(102 * var(--u));
    z-index: 3;
    list-style: none;
    font-family: 'Geist Sans', sans-serif;
    font-weight: 400;
    color: #ffffff;
    /* The site's standard body size, not the Figma frame's 48px — same as
       work.html's "All work" / intro text (styles: 1.75rem / 2rem). Deliberate
       departure from the 1:1 frame. */
    font-size: 1.75rem;
    line-height: 2rem;
    letter-spacing: -0.02em;
}
.fig-nav li { cursor: pointer; width: max-content; }
/* Once a section has been picked the list scrambles out with the rest of the
   overlay's text — so it must NOT be hidden here, only made unclickable. An
   opacity: 0 would swallow the very transition it is part of. */
.cube-root.is-entering .fig-nav { pointer-events: none; }
.cube-root.is-entering #stage { pointer-events: none; }

/* ---- cube view ---- */
#stage {
    position: fixed; inset: 0;
    z-index: 2;
    cursor: grab;
    touch-action: none;
}
#stage.is-grabbing { cursor: grabbing; }
#stage canvas { display: block; }

/* ---- docked ----
   The cube does not leave when it hands the page over: it shrinks to the corner
   and stays there, still turning, as a live index of the six sections. Hovering
   a face names it; clicking one jumps the page to that band.

   The ROOT has to stop covering the page — it is `position: fixed; inset: 0`
   for the opening, and left that way it would eat every click on the document
   underneath. Everything but the little canvas becomes non-interactive. */
.cube-root.is-docked {
    display: block;
    inset: auto;
    z-index: 40;                    /* above the page, below the consent panel */
    pointer-events: none;
}
.cube-root.is-docked #veil,
.cube-root.is-docked .fig-stage,
.cube-root.is-docked .fig-nav { display: none; }

.cube-root.is-docked #stage {
    position: fixed;
    inset: auto;
    right: var(--gutter);
    bottom: 2.5rem;
    width: 8.5rem;
    height: 8.5rem;
    pointer-events: auto;
    cursor: pointer;
    /* A GROUND. The faces are live renders of the same scramble field the page is
       made of, so the cube can never separate itself from the background by colour
       or texture — only by edge and value. Measured before this: the cube averaged
       3.2/255 where the body copy beside it averaged 11, over a background of pure
       0, with no border.
       The plate is the PAGE's own colour at part strength over a blurred backdrop,
       rather than a flat swatch: the field running behind the corner is what the
       cube was competing with, and blurring it removes that texture instead of
       hiding it — the cube keeps sitting IN the page rather than on top of it. */
    box-sizing: border-box;
    background: rgba(0, 0, 0, 0.55);                                 /* fallback */
    background: color-mix(in srgb, var(--color-bg) 55%, transparent);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border: 1px solid rgba(255, 255, 255, 0.16);
    /* Only the box is animated; the module watches its integer width and
       re-frames the renderer when it actually changes. right/bottom stay put so
       it grows up and to the left, into the page rather than off the corner. */
    transition: width 0.34s ease, height 0.34s ease;
}
/* Hover opens it right up — 4x the resting box. Small enough at rest to be a
   corner control, big enough on hover to actually read the six faces and pick
   one. right/bottom stay pinned so all of that growth goes up and to the left,
   into the page. */
.cube-root.is-docked #stage:hover { width: 34rem; height: 34rem; }

/* The hovered face's name, sitting to the left of the cube on the same
   baseline as the bottom of it. Empty until something is hovered. */
.cube-dock-label {
    position: fixed;
    right: calc(var(--gutter) + 10rem);
    bottom: 2.5rem;
    z-index: 41;
    margin: 0;
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1.75rem;
    line-height: 2rem;
    letter-spacing: -0.02em;
    color: #ffffff;
    white-space: nowrap;
    pointer-events: none;
    display: none;
}
.cube-root.is-docked .cube-dock-label { display: block; }

/* While the cube is up the page reads as the dark Studio frame, so the shared
   header renders white-on-black exactly as it does on studio-cube.html. Scoped
   to the class rather than :root, because this page is white underneath and
   goes back to being white the moment the cube lands. */
html.cube-up { --color-bg: #000000; --color-text: #ffffff; }
html.cube-up .nav-logo { filter: invert(1); }   /* black pixel tulip → white */

/* Short desktop windows: keep the list off the header without moving it
   sideways. No phone rules — the cube does not mount below 1100px, so the whole
   overlay is absent there rather than restyled. */
@media (min-width: 820px) and (max-height: 700px) {
    .fig-nav { top: max(calc(102 * var(--u)), 6rem); }
}

/* NOT `overflow: hidden` while the cube is up, however tempting. The landing
   works by scrolling the real page to the target band and MEASURING where it
   lands, and a hidden overflow makes window.scrollTo a no-op — the zoom would
   then solve its camera against a rectangle the page never actually shows.
   The module blocks wheel, touch and the scrolling keys instead.

   The scrollbar is hidden by making its THUMB transparent rather than by
   removing it (`scrollbar-width: none`). Removing it gives the page back its
   width, and the whole layout reflows ~15px wider the instant the cube is torn
   down. Measured: the face landed on 1380.0 and the band was 1365 a frame
   later. Keep the gutter. */
html.cube-up::-webkit-scrollbar-thumb { background: transparent; }

/* (The canvas is black for the whole page — see the top of this file. That is
   also what fills the scrollbar gutter beside the cube overlay, which is
   `position: fixed` and so stops short of it.) */

/* The cookie banner is not allowed to open on top of the cube. It is the first
   thing this page shows and the banner lands right across it; consent.js has no
   idea the cube exists, so the banner simply waits here and appears the moment
   the overlay goes. Nothing is skipped — the element is built either way. */
html.cube-up .fl-cc-banner { display: none; }

/* ------------------------------------------------------------
   People — the team section.

   A full-height black band, the field kept but held 100px short of the
   bottom, and only the section word left on it. The busts go in here.
   ------------------------------------------------------------ */
#band-6::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 100vw;
    margin-left: -50vw;   /* centred on the section, which is centred in the page */
    background: #000000;
    z-index: 0;           /* under the word (1) and the field (2) */
}

/* Band 6 no longer needs its own colours — the page arrived at them. Its
   full-bleed ::before is likewise now invisible against an identical ground, and
   is kept only so the band still stands alone if the page ever goes light. */

/* ------------------------------------------------------------
   The page ends black. Once People arrives the ground never goes back to
   white — the footer sits in the same black the band bleeds.

   The footer takes the colour by overriding --color-text rather than by
   restyling its parts: the rule, the type and the SVG wordmark (fill is
   `var(--color-text)` in the markup) all read that one token, so this flips
   every one of them together and nothing in styles.css has to know.
   ------------------------------------------------------------ */
.origin-frame > footer {
    position: relative;
    --color-text: #ffffff;
    color: #ffffff;
    /* The rule has to be set on its own. `footer { border-top: var(--border-style) }`
       looks like it would follow --color-text, but a custom property's value is
       substituted where it is DECLARED — --border-style computes to
       `2px solid #010101` up on :root and inherits down already resolved, so
       overriding the token here cannot reach inside it. Measured: black on
       black. The SVG wordmark's `fill="var(--color-text)"` DOES follow, because
       that var() sits in the markup and resolves on the element itself. */
    border-top-color: #ffffff;
}
/* The black itself, bleeding the full viewport width exactly as #band-6 does.

   z-index 0, NOT -1. Once html has a background of its own, body's white stops
   propagating to the canvas and is painted as an ordinary block background —
   which comes AFTER negative-z-index descendants in the paint order. At -1 the
   black went under body's white, and since the footer's type is white too the
   whole footer vanished. #band-6::before has always been 0 for the same reason;
   this now matches it, with the content lifted above. */
.origin-frame > footer::before {
    content: '';
    position: absolute;
    top: 0;
    bottom: 0;
    left: 50%;
    width: 100vw;
    margin-left: -50vw;
    background: #000000;
    z-index: 0;
}
.origin-frame > footer > * { position: relative; z-index: 1; }

/* The people: one face, one colour, no rules between them. Geist throughout —
   the field behind is the only monospace on this band, and the list reading in
   the same voice as the section word is what separates it from the churn.
   Shared across both breakpoints; only the placement differs.

   nav.js attaches the site's hover scramble to each row (all four cells at
   once), which is why every cell is a plain leaf <span>. */
.person > * {
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1.75rem;
    line-height: 2rem;
    letter-spacing: 0;
    color: #ffffff;
}

.origin-inner {
    position: relative;
}

.origin-d,
.origin-b {
    font-weight: 400;
    letter-spacing: 0;    /* the frame's tracking is 0; the site body default is -0.02em */
}

.origin-d {
    font-family: var(--font-sans);
    color: var(--color-text);
    white-space: nowrap;
}

/* Body copy shares the field's voice: same monospace, same grey. Note this
   re-wraps the paragraphs — Geist Mono is wider per character than Geist Sans,
   so they no longer break on the artboard's words. Deliberate. */
.origin-b {
    font-family: 'Geist Mono', ui-monospace, Menlo, monospace;
    color: var(--mono-grey);
}

/* The canvas origin.js lays over a paragraph. The <p> keeps the layout and the
   real words (still selectable, still read by assistive tech); only its ink is
   turned off, by the script, once the canvas is in place. */
.mono-canvas--block {
    position: absolute;
    left: 0;
    top: 0;
    pointer-events: none;
}

/* ------------------------------------------------------------
   Services — the Capabilities grid.

   Twelve columns, each item four wide, stepping centre → left+right →
   centre → left+right → centre. Seven items land in five rows with the
   middle column carrying the odd ones, which is what gives the block its
   scatter without any of it being placed by hand.
   ------------------------------------------------------------ */
.svc-list {
    list-style: none;
    display: grid;
    grid-template-columns: repeat(12, 1fr);
    column-gap: 0.625rem;
}

.svc-label {
    font-family: var(--font-sans);
    font-weight: 400;
    font-size: 1.6875rem;      /* 27 */
    line-height: 1.5rem;
    letter-spacing: -0.015em;
    color: var(--color-text);
}

.svc-note {
    font-family: 'Geist Mono', ui-monospace, Menlo, monospace;
    font-weight: 400;
    font-size: 1.125rem;       /* 18 */
    line-height: 1.40625rem;
    letter-spacing: 0;
    color: var(--mono-grey);
    margin-top: 0.75rem;
}

/* The reveal. origin.js splits a label into words and characters, then walks a
   state along them as the item rises through the viewport: not yet, flashing,
   settled. Only the state that changes is written back to the DOM. */
.svc-label .char {
    display: inline-block;
    white-space: pre;
}
.svc-label .char[data-s="0"] { color: transparent; }
/* The mid-reveal flash is a filled block with knocked-out type. On a black page
   the block has to be the LIGHT one, or it is black on black and the character
   simply vanishes for its flashing frames. `color` already follows --color-bg. */
.svc-label .char[data-s="1"] {
    color: var(--color-bg);
    background: var(--color-text);
    border-radius: 0.1875rem;
}

/* The mono field — small grey text running behind the display words.

   Four equal columns across the page's content box. The gap sits BETWEEN the
   columns rather than as padding inside each one, so the field spans the full
   width — first column starting on the nav's left edge, fourth column ending on
   its right edge — instead of the last one stopping a gutter short.

   Decorative: hidden from assistive tech, unselectable, click-through. */
.mono-field {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    column-gap: 2.5rem;
    user-select: none;
    -webkit-user-select: none;
    pointer-events: none;
}

/* Geist Mono, not Geist Pixel: the scramble swaps characters between fixed
   grid cells, which only holds if every character has the same advance. Geist
   Pixel Square is proportional (six different advance widths — '.' is 2.66px
   where 'W' is 12.77px at 14px), so a grid built on it would not line up. */
.mono-col {
    font-family: 'Geist Mono', ui-monospace, Menlo, monospace;
    font-weight: 400;
    font-size: 0.875rem;      /* 14 */
    line-height: 1.75;        /* 24.5 */
    letter-spacing: 0;
    /* BRIGHTER than --mono-grey (which the body copy uses). This is the
       strongest ink in the field, not its average: origin.js weights every token
       class down from here — keywords land on this value, comments far dimmer.
       Set it to the body grey and the whole field only ever gets fainter. */
    color: #d8d8d8;
}

/* ============================================================
   Desktop — the artboard composition.

   The page alternates between two kinds of section, and the split is what makes
   the mono field possible: a band owns the display words AND the grey text
   behind them, a copy section owns the body paragraphs and nothing else. The
   field is clipped to its band, so it can never reach the paragraphs.

   Each section is absolutely placed at its Figma y, and its children are placed
   relative to the section — so the composition is unchanged, the words just now
   have a local origin to sit against.
   ============================================================ */
@media (min-width: 820px) {
    .origin-inner {
        /* Ends at the bottom of the team band — a screen tall, plus the block
           the people are listed in. Both numbers live in #band-6 below and this
           has to be the sum of them, or the page ends mid-band. */
        height: calc(506.8125rem + 100vh + 100px);
    }

    .origin-band,
    .origin-copy {
        position: absolute;
        left: 0;
        right: 0;
    }

    /* Every band is the same height: first word top → last word box bottom
       (646+195-149 = 692). The two the artboard defined set the rhythm — a
       band every 1464, its copy 876 below it — and the four after them carry
       it on. */
    .origin-band { height: 43.25rem; }
    .origin-copy { height: 27.5rem; }

    #band-1 { top: 9.3125rem;   }
    #copy-1 { top: 64.0625rem;  height: 20.625rem; }   /* artboard's own */
    #band-2 { top: 100.8125rem; }
    #copy-2 { top: 154.1875rem; }
    #band-3 { top: 192.3125rem; }
    #copy-3 { top: 247.0625rem; }
    #band-4 { top: 283.8125rem; }
    /* Capabilities and Processes both carry a services grid instead of a
       paragraph pair, so each is taller than the rhythm allows — everything
       below them is pushed down by the 20rem difference rather than the grid
       being squeezed into the slot. */
    #copy-4 { top: 338.5625rem; height: 46rem; }
    #band-5 { top: 395.3125rem; }
    #copy-5 { top: 450.0625rem; height: 46rem; }

    /* The team band ends the page: a full screen of black for the section word
       over the field, then 30rem more of it for the people themselves.

       It has to run PAST the fold. At exactly 100vh the black could only ever
       fill the screen at one precise scroll position — anywhere else you caught
       white above it or below it, which is what read as the band being too
       short. The extra 30rem is also what the busts will hang in.

       The field still stops 100px short of the FIRST screen, so it never runs
       down into the list. */
    #band-6 { top: 506.8125rem; height: calc(100vh + 100px); }
    /* The field fills the WHOLE band — it used to stop 100px short of the first
       screen, which left most of this section as bare black. Both numbers have
       to be the band's own height: .mono-field inherits inset: 0, and the
       columns are sized explicitly because the shared rule below fixes them at
       one band's worth (42.875rem) and this band is far taller. */
    #band-6 .mono-col   { height: calc(100vh + 100px); }

    /* ---- the people ----
       Four columns on the page's own twelve: who / what they are / what they do
       / where they are. The last is pushed to the right edge so the row spans
       the full measure, the same left-edge-to-right-edge rule the bands follow.
       On the first screen, under the section word and OVER the field — z-index
       3 puts it above the field's canvas layer (2), so the churn runs behind
       the names rather than stopping for them. */
    .people-list {
        position: absolute;
        top: 42vh;
        left: 0;
        right: 0;
        z-index: 3;
        list-style: none;
    }
    .person {
        display: grid;
        grid-template-columns: repeat(12, 1fr);
        column-gap: 2.5rem;
        align-items: baseline;
        padding: 3rem 0;
    }
    .person__name  { grid-column: 1 / span 3; }
    .person__role  { grid-column: 4 / span 3; }
    .person__skill { grid-column: 7 / span 4; }
    .person__where { grid-column: 11 / span 2; justify-self: end; }

    /* People is the one section word that does NOT sit at the top of its band.
       The nav is transparent here, so at top:0 the word runs up into the strip and
       collides with the links; this drops it clear of them and lets the black show
       through the nav on its own. The other bands are unaffected — they start
       under white, where the strip reads as page. */
    #people { top: 9rem; }

    .origin-d,
    .origin-b {
        position: absolute;
        z-index: 1;
    }

    /* Display type — 150 / 195 */
    .origin-d {
        font-size: 9.375rem;
        line-height: 12.1875rem;
    }

    /* Body type — the site's body voice, 1.75rem / 2rem, the same pairing used
       by .faq-item__a, .agency-note and .work-intro-text. (The artboard set
       this copy at 42/55, but that was Geist Sans at display scale; in the
       field's monospace at the site's body size it sits with the rest of the
       pages.) */
    .origin-b {
        font-size: 1.75rem;
        line-height: 2rem;
    }

    /* ---- The four display words, in every band ----
       The artboard placed these once and both of its sections used the same
       four positions, so they are stated once here rather than per word. The
       staircase: section name on the left edge, then right edge, then two
       steps in. The <p>s inside .mono-field are a different parent, so they do
       not enter this count. */
    .origin-band > .origin-d:nth-of-type(1) { top: 0;          left: 0; }
    .origin-band > .origin-d:nth-of-type(2) { top: 9.4375rem;  right: 0; }
    .origin-band > .origin-d:nth-of-type(3) { top: 21.625rem;  left: 26.6234rem; }
    .origin-band > .origin-d:nth-of-type(4) { top: 31.0625rem; left: 55.5844rem; }

    /* ---- The paired paragraphs, in every copy section ---- */
    .origin-copy > .origin-b:nth-of-type(1) { top: 0; left: 0;  width: 36.75rem; }   /* 588 */
    .origin-copy > .origin-b:nth-of-type(2) { top: 0; right: 0; width: 55.875rem; }  /* 894 */

    /* ---- The services zigzag ---- */
    .svc-list { row-gap: 3rem; }
    .svc:nth-child(1) { grid-column: 5 / span 4;  grid-row: 1; }
    .svc:nth-child(2) { grid-column: 1 / span 4;  grid-row: 2; }
    .svc:nth-child(3) { grid-column: 9 / span 4;  grid-row: 2; }
    .svc:nth-child(4) { grid-column: 5 / span 4;  grid-row: 3; }
    .svc:nth-child(5) { grid-column: 1 / span 4;  grid-row: 4; }
    .svc:nth-child(6) { grid-column: 9 / span 4;  grid-row: 4; }
    .svc:nth-child(7) { grid-column: 5 / span 4;  grid-row: 5; }

    /* The one exception the artboard actually drew: its first paragraph sits
       13px lower than the one beside it. */
    #intro { top: 0.8125rem; }

    /* ---- The pixel field fills its band and is clipped to it ----
       z-index 2 puts it OVER the display words rather than behind them: the
       grey runs straight across the black letterforms. */
    .mono-field {
        position: absolute;
        inset: 0;
        z-index: 2;
        overflow: hidden;
    }

    /* Exactly 28 lines — 28 × 24.5 = 686, the largest whole number of lines that
       fits the 692 band. Each column is written slightly long and clipped here,
       so the field always reaches the bottom of its band and the cut always
       lands cleanly between two lines instead of through one.

       Both the type and the column width are rem, so they scale together: the
       wrap, and therefore the line count, is identical at every desktop width. */
    .mono-col {
        height: 42.875rem;
        overflow: hidden;
    }

    /* origin.js swaps each column's <p> for this once the fonts are ready. It
       is built to exactly rows × line-height, so it needs no clipping of its
       own; the <p> above stays as the pre-script (and no-script) state. */
    .mono-canvas {
        display: block;
    }

    /* The page does not go back to white after People — the black carries on
       through the footer to the end of the document. So no margin (a gap here
       would be a white stripe across the seam); the breathing room is padding
       INSIDE the black instead. */
    .origin-frame > footer { margin-top: 0; padding-top: 10rem; }
}

/* ============================================================
   Mobile — same rule as the rest of the site: below 820px the root switches to
   the 1400px artboard scale, so the desktop composition is re-authored rather
   than shrunk. Everything collapses into one column that still starts and ends
   on the nav's edges; the staggered left/right rhythm is kept.
   ============================================================ */
@media (max-width: 819px) {
    .origin-inner {
        padding: 14rem 0 20rem;    /* clears the fixed mobile header */
    }

    .origin-band,
    .origin-copy {
        display: flex;
        flex-direction: column;
        align-items: flex-start;
    }

    /* The band has to be a containing block for its own field. Desktop gets this
       free — there the bands are position:absolute — but in the mobile flow they
       are static, so a field with inset:0 anchors to .origin-inner instead and
       spans the WHOLE page: every band's field lands on top of every section,
       services copy included. This one line is what keeps each field inside the
       band it belongs to. */
    .origin-band { position: relative; }

    .origin-d {
        font-size: 12.5rem;        /* 200 design px */
        line-height: 1.2;
    }

    .origin-b {
        font-size: 3.25rem;        /* 52 design px — the site's mobile body size */
        line-height: 1.3;
        align-self: stretch;
    }

    /* The desktop staircase, flattened: left edge → right edge → indent →
       right edge. Stated by position rather than by name, so every section
       gets it. */
    .origin-band > .origin-d:nth-of-type(2),
    .origin-band > .origin-d:nth-of-type(4) { align-self: flex-end; }
    .origin-band > .origin-d:nth-of-type(3) { margin-left: 25%; }

    /* Rhythm of the stack. The first band needs none — .origin-inner's own
       padding already clears the header. */
    .origin-band { margin-top: 20rem; }
    .origin-band:first-child { margin-top: 0; }
    .origin-copy { margin-top: 8rem; }
    .origin-copy > .origin-b:nth-of-type(2) { margin-top: 4rem; }

    /* The team band keeps its full-screen black on a phone. It has to be
       positioned here — the sections are static in the mobile flow, and without
       this the bleed would resolve against .origin-inner and black the page. */
    #band-6 {
        position: relative;
        min-height: 100vh;
        justify-content: center;
        padding: 8rem 0;
    }

    /* Four columns of credits do not fit a phone. Each person becomes a block:
       name, then the three facts under it. In flow, not absolute — the mobile
       band is a flex column, so the desktop placement has to be undone here. */
    .people-list {
        position: static;
        align-self: stretch;
        margin-top: 10rem;
    }

    /* .origin-inner keeps 20rem of bottom padding on a phone, which sits
       BETWEEN the band and the footer — so the black has to start that far
       above the footer's own box or the seam is a white stripe. */
    .origin-frame > footer { padding-top: 6rem; }
    .origin-frame > footer::before { top: -20rem; }
    .person {
        display: block;
        padding: 4rem 0;
    }
    .person > * {
        display: block;
        font-size: 3.25rem;        /* the site's mobile body size */
        line-height: 1.3;
    }
    .person__name { margin-bottom: 1.5rem; }

    /* The services zigzag needs twelve columns to be a zigzag; on a phone it is
       one column, stacked, at the sizes the rest of the mobile page uses. */
    .svc-list {
        grid-template-columns: 1fr;
        row-gap: 9rem;
    }
    .svc { grid-column: 1 / -1; }

    .svc-label {
        font-size: 5.25rem;        /* 84 design px */
        line-height: 1.15;
    }
    .svc-note {
        font-size: 3.25rem;        /* 52 design px — the site's mobile body size */
        line-height: 1.3;
        margin-top: 2rem;
    }

    /* The field runs on phones too. It is a texture rather than something anyone
       reads, so it keeps all four columns and just takes a size that suits the
       narrower box: .mono-col's 0.875rem measures 3.9px against the fluid mobile
       root, which is why this used to be switched off outright. The positioning
       comes from the >=820 block, which does not apply here, so it is repeated. */
    .mono-field {
        position: absolute;
        inset: 0;
        /* Same layering as desktop — over the band's own display words, which is
           the effect. It only ever covers those now that the band contains it. */
        z-index: 2;
        overflow: hidden;
        column-gap: 1.25rem;
    }
    .mono-col {
        font-size: 2.25rem;        /* ~10px at the mobile root */
        line-height: 1.75;
        overflow: hidden;
    }
    .mono-canvas { display: block; }

    /* ---- the docked cube on a phone ----
       There is no opening at this width (origin-cube.js mounts straight into the
       docked state), so this IS the cube. Both numbers have to be restated because
       the mobile root is fluid — the desktop 8.5rem would measure 38px here, and its
       2.5rem bottom 11px. Sat higher than the desktop one so it clears the thumb and
       the consent banner rather than hugging the corner. */
    .cube-root.is-docked #stage {
        width: 24rem;                /* ~107px at 390 */
        height: 24rem;
        bottom: 9rem;                /* ~40px — lifted off the edge */
    }
}
