/* ==========================================================================
   Typeface — Clash Display and Clash Grotesk, self-hosted
   Two files, both variable, both served from this origin. That last part is
   not a preference: the CSP header is `font-src 'self'`, so a Google Fonts
   link would be blocked by the site's own policy — and the home page states
   0 third-party requests as a measured figure, which a webfont CDN would
   quietly turn into a lie.

   Clash Display is a display face. It is set on headings, the poster
   headlines, the outlined numerals and the promise headwords, and nowhere
   near running copy — its lowercase is drawn to be seen at 4rem, not read at
   17px. Clash Grotesk carries everything else.

   font-display: swap, so the text is readable in the fallback from the first
   paint and the swap costs a reflow rather than a blank screen. Until the two
   files are in /assets/fonts/ the stacks below fall through to system-ui and
   the site looks exactly as it does today.
   ========================================================================== */

@font-face {
  font-family: "Clash Display";
  src: url("../fonts/ClashDisplay-Variable.woff2") format("woff2");
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Clash Grotesk";
  src: url("../fonts/ClashGrotesk-Variable.woff2") format("woff2");
  font-weight: 200 700;
  font-style: normal;
  font-display: swap;
}

/* ==========================================================================
   Hayanezu — main.css
   Tokens, reset, layout, components.
   All motion lives in motion.css.

   Visual direction: the Land of Nomo reference's composure — a drifting sky,
   organic edges instead of hard rules, generous air, fine grain over
   everything — on a dark grey ground, with the brand lilac (#C9A2FF) doing
   the accent work. Dark GREY rather than black: black flattens a gradient sky
   into a void and leaves the grain nothing to sit on.

   The accent tokens are named --accent, not --lilac: the hue has changed once
   already and naming a token after its current colour is how a palette ends up
   with a variable called --cyan holding a purple.
   ========================================================================== */

/* --- 1. Design tokens ----------------------------------------------------- */

:root {
  /* Colour — the accent. Lilac is the brand and it leads; the gradient runs
     into a deeper violet only far enough to give it depth on a dark ground.

     THIS BLOCK IS THE NO-JAVASCRIPT BASELINE, NOT THE SOURCE OF TRUTH.
     palette.js owns the accent and the four sky stops and overwrites all
     twelve properties on :root as soon as it runs: each page sits at its own
     point in one family and a navigation travels between them. What is
     written here is the home page's point, so with JavaScript off the site
     keeps exactly the palette it has always had.

     To change the brand hue now, edit BASE in palette.js and nothing else.
     Every glow, wake, focus ring, aurora blob and shader uniform derives
     from these tokens — the 60 hand-written rgba() copies of the accent that
     used to be scattered through both stylesheets are gone, replaced by
     rgb(var(--accent-rgb) / a). The README's table of four places to edit is
     one place now.

     Both ends stay light enough to carry --shade text: the gradient is the
     background of .btn--solid, ::selection and the pressed view toggle, so
     its DARKEST point has to clear 4.5:1 on the graphite shade (#16181B).
     That is no longer a swatch you can check by eye but a surface — run
     `node scripts/check-contrast.js`, which walks every reachable point
     (every page, every navigation between them, every position of the scroll
     drift, and the light / inverse rooms) and prints the worst.

     --accent-2 is a shade lighter than the #8B6BFF this site shipped with:
     OKLCH L 0.655 rather than 0.6345. At the old lightness the rotation
     bottomed out at 4.64:1, too little air above the floor for a value that
     now moves. The colour difference is barely visible; the margin is not. */
  --accent:   #C9A2FF;
  --accent-2: #9075FF;
  --grad:   linear-gradient(66deg, var(--accent), var(--accent-2));

  /* The same two colours as bare channel triplets. Every translucent use of
     the accent reads one of these, so alpha stays tunable per effect without
     the colour itself being written out a second time. */
  --accent-rgb:   201 162 255;
  --accent-2-rgb: 144 117 255;
  --accent-glow: rgb(var(--accent-rgb) / 0.42);

  /* Colour — ground and ink. Dark grey, not black: black flattens a gradient
     sky into a void, and the grain has nothing to sit on. The page field is
     a lifted graphite; --shade stays the original #16181B so text sitting on
     the accent gradient (.btn--solid, ::selection) keeps its contrast floor.
     --ink-rgb is the text colour's channels: white on dark rooms, graphite
     on light and inverse rooms. Shadows use --shade-rgb, which does not flip
     with the page field. --on-shade-rgb stays white, for copy that lives on
     dark instruments (contact chips, the sky band, the laptop screen). */
  --ground:   #21252B;
  --ground-rgb: 33 37 43;
  --ground-2: #282D35;
  --ground-3: #2F353E;
  --shade:    #16181B;
  --shade-rgb: 22 24 27;
  --ink:      #FFFFFF;
  --ink-rgb:  255 255 255;
  --on-shade-rgb: 255 255 255;
  --white:    #FFFFFF;

  --text:       rgb(var(--ink-rgb) / 0.92);
  --text-dim:   rgb(var(--ink-rgb) / 0.74);
  --text-faint: rgb(var(--ink-rgb) / 0.50);
  --rule:       rgb(var(--ink-rgb) / 0.13);
  --rule-soft:  rgb(var(--ink-rgb) / 0.07);

  /* Colour — the sky. Deep violets and indigos the lilac can glow out of,
     rather than pastels, which turn to mud on a dark ground. They keep the
     hue variety the teal set had (violet / indigo / plum) so the field still
     travels across the width instead of reading as one flat tint.
     These are no longer mirrored in the scene.js shader. The shader takes
     them as uniforms and palette.js fills both from the same numbers, so the
     old "change them together or they drift apart" hazard is gone. */
  --sky-1: #2E2154;
  --sky-2: #221C46;
  --sky-3: #402A63;
  --sky-4: #2A2050;
  --sky-1-rgb: 46 33 84;
  --sky-2-rgb: 34 28 70;
  --sky-3-rgb: 64 42 99;
  --sky-4-rgb: 42 32 80;

  /* Spacing — 4px base */
  --s-1: 4px;  --s-2: 8px;  --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px; --s-7: 48px; --s-8: 64px;
  --s-9: 96px; --s-10: 128px;

  /* Type. Clash Display for anything set large, Clash Grotesk for the rest;
     both declared at the top of this file. Inter stays in the stack as the
     first fallback for anyone who has it, then system-ui.
     Do NOT link Google Fonts: the CSP is font-src 'self' and the home page
     states "0 third-party requests" as a measured figure. */
  --font-display: "Clash Display", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-ui:      "Clash Grotesk", Inter, ui-sans-serif, system-ui, -apple-system, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono:    ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  /* Type scale — fluid. The headline is a sentence, not two words, so the
     hero step is a good deal smaller than a display-word build would use. */
  --t-hero:  clamp(2.125rem, 4.6vw, 4rem);
  --t-h1:    clamp(1.75rem, 3.4vw, 2.875rem);
  --t-h2:    clamp(1.375rem, 2.2vw, 1.875rem);
  --t-body:  clamp(1rem, 1.05vw, 1.0625rem);
  --t-label: 0.6875rem;
  --t-micro: 0.625rem;

  --track: 0.12em;

  /* Motion */
  --e-out:  cubic-bezier(0.16, 1, 0.3, 1);
  --e-io:   cubic-bezier(0.65, 0, 0.35, 1);
  --e-soft: cubic-bezier(0.32, 0.72, 0.24, 1);
  --d-fast: 160ms;  --d-mid: 380ms;  --d-slow: 900ms;

  /* Geometry */
  --radius:      999px;
  --radius-card: 24px;
  --border: 1px solid var(--rule);
  --max:    1320px;
  --gutter: clamp(20px, 5vw, 72px);
  --header-h: 72px;

  /* Experience layer — the same palette, with enough material information
     for surfaces to feel lit rather than simply filled. */
  --surface: rgb(var(--ink-rgb) / 0.045);
  --surface-hi: rgb(var(--ink-rgb) / 0.075);
  --edge-hi: rgb(var(--ink-rgb) / 0.20);
  --shadow-deep: 0 34px 100px -48px rgb(var(--shade-rgb) / 0.92);
}

/* Contact is the inverted room: the page is the lilac, the instruments
   (form, chips, footer, cubes) are the graphite shade. Tokens here are
   the no-JS baseline; palette.js writes --ground from the live accent
   once it runs. */
html.is-inverse {
  --ground: #C9A2FF;
  --ground-rgb: 201 162 255;
  --ground-2: #16181B;
  --ground-3: #1D2025;
  --ink: #16181B;
  --ink-rgb: 22 24 27;
  --text: rgb(var(--ink-rgb) / 0.92);
  --text-dim: rgb(var(--ink-rgb) / 0.86);
  --text-faint: rgb(var(--ink-rgb) / 0.80);
  --rule: rgb(var(--ink-rgb) / 0.20);
  --rule-soft: rgb(var(--ink-rgb) / 0.11);
  --surface: rgb(var(--ink-rgb) / 0.08);
  --surface-hi: rgb(var(--ink-rgb) / 0.14);
  --edge-hi: rgb(var(--ink-rgb) / 0.28);
}

/* Work is the paper room: warm stock, graphite ink. Sibling of
   is-inverse; palette.js assigns it from LIGHT_PAGES so it travels
   with the navigation rather than cutting. */
html.is-light {
  --ground: #F4F1EA;
  --ground-rgb: 244 241 234;
  --ground-2: #EBE6DC;
  --ground-3: #E0D9CC;
  --ink: #16181B;
  --ink-rgb: 22 24 27;
  --text: rgb(var(--ink-rgb) / 0.92);
  --text-dim: rgb(var(--ink-rgb) / 0.78);
  --text-faint: rgb(var(--ink-rgb) / 0.66);
  --rule: rgb(var(--ink-rgb) / 0.14);
  --rule-soft: rgb(var(--ink-rgb) / 0.08);
  --surface: rgb(var(--ink-rgb) / 0.04);
  --surface-hi: rgb(var(--ink-rgb) / 0.07);
  --edge-hi: rgb(var(--ink-rgb) / 0.16);
  --shadow-deep: 0 34px 100px -48px rgb(var(--shade-rgb) / 0.28);
}

/* --- 2. Reset ------------------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + var(--s-5));
  overflow-x: clip;
}

body {
  margin: 0;
  background: var(--ground);
  color: var(--text);
  transition: background-color 720ms var(--e-out), color 720ms var(--e-out);
  font-family: var(--font-ui);
  font-size: var(--t-body);
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;
}

h1, h2, h3, h4, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
img, svg, video { display: block; max-width: 100%; }
img { height: auto; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: inherit; text-decoration: none; }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}
.hero .display:focus,
.hero .display:focus-visible,
.page-hero .display:focus,
.page-hero .display:focus-visible,
.page-head .display:focus,
.page-head .display:focus-visible,
h1[tabindex="-1"]:focus,
h1[tabindex="-1"]:focus-visible {
  outline: none;
  box-shadow: none;
}

::selection { background: var(--accent); color: var(--shade); }

/* --- 3. Utilities --------------------------------------------------------- */

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute;
  top: 0; left: 0;
  z-index: 600;
  padding: var(--s-3) var(--s-5);
  background: var(--accent);
  color: var(--shade);
  border-radius: 0 0 var(--radius) 0;
  font: 600 var(--t-label)/1 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  transform: translateY(-105%);
}
.skip-link:focus { transform: translateY(0); }

.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px))
                  max(var(--gutter), env(safe-area-inset-right, 0px));
}

.label {
  font: 600 var(--t-label)/1.4 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-faint);
}
.micro {
  font: 500 var(--t-micro)/1.4 var(--font-ui);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
}

/* The hero's standfirst line. It carries the positioning ("IP firm upstairs"),
   so it is not decoration and must not be set at --text-faint: 10px uppercase
   at 50% ink over the sky reads as a smudge. Dimmed ink, one step larger and
   a little less tracking clears 8:1 there, and the measure keeps the two
   sentences from breaking mid-phrase. */
.hero__note {
  color: var(--text-dim);
  font-size: 0.6875rem;
  letter-spacing: 0.12em;
  max-width: 42ch;
  text-wrap: balance;
  margin-top: var(--s-6);
}
.statement {
  display: block;
  font-family: var(--font-display);
  font-size: var(--t-h2);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.25;
  color: var(--text);
}
.emph { color: var(--text); font-weight: 400; }
.mt-3 { margin-top: var(--s-3); }
.mt-4 { margin-top: var(--s-4); }
.mt-5 { margin-top: var(--s-5); }
.mt-6 { margin-top: var(--s-6); }
.mt-7 { margin-top: var(--s-7); }
.mt-8 { margin-top: var(--s-8); }
.mt-9 { margin-top: var(--s-9); }
.mark--sm { height: 24px; }
.field__hint { text-transform: none; letter-spacing: 0; font-weight: 500; }
/* An eyebrow above the headline. Wide tracking, small, and it earns its
   place by carrying the name's meaning as a mark rather than as a gloss
   buried in the sentence below. */
.eyebrow {
  font: 600 var(--t-label)/1 var(--font-ui);
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--s-6);
}
.eyebrow [lang="ja"] { letter-spacing: 0.16em; font-size: 1.15em; vertical-align: -0.04em; }

.lede { font-size: 1.0625rem; color: var(--text-dim); max-width: 48ch; line-height: 1.8; }

/* One measure for body copy. Ledes stay shorter; chips, specs and card
   lists opt out so a row of terms is not squeezed to a paragraph width. */
main :where(p, li) { max-width: 68ch; }
main :where(.spec, .creds, .promises, .team, .projects, .qs, .checks, .nav, .word-field) li,
main .word { max-width: none; }

.display {
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.16;
  letter-spacing: -0.015em;
  text-wrap: balance;
}
.h-hero { font-size: var(--t-hero); letter-spacing: -0.02em; }
.h-1    { font-size: var(--t-h1); }
.h-2    { font-size: var(--t-h2); }

/* One word, or one line, carrying the accent gradient. Used sparingly —
   it is the loudest thing on the page. */
.grad {
  background: var(--grad);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

.section { padding-block: clamp(64px, 8vw, 128px); }
.section--tight { padding-block: clamp(40px, 5vw, 72px); }
.rule-top { border-top: 1px solid var(--rule-soft); }
@media (max-width: 639px) {
  .section { padding-block: 48px; }
  .page-head.page-hero { padding-block: 40px 24px; }
  .band { margin-inline: var(--gutter); padding-block: 32px; }
  .pull { max-width: none; }
}

/* --- 4. Grain ------------------------------------------------------------- */
/* Fine noise over everything. A decoded PNG tile, not live SVG turbulence —
   the filter used to be recomputed across the whole viewport on every
   composite. */

.grain {
  position: fixed;
  inset: 0;
  z-index: 400;
  pointer-events: none;
  opacity: 0.055;
  /* A decoded PNG tile, not live SVG turbulence. The filter used to be
     recomputed across the whole viewport on every composite. */
  background-image: url("../img/grain.png");
  background-size: 128px 128px;
}


html.is-light .grain { opacity: 0.035; }

/* --- 4b. The galaxy field -------------------------------------------------
   The page field, not a grey wash: the same night the hero stands in, carried
   behind every room. Four parts, deepest first - a nebula built from the
   page's own --sky tokens, so each room inherits its hue from palette.js and
   there is no second palette to keep in step; three star sheets that twinkle
   out of phase; and a vignette that keeps the corners deep. The layer sits at
   z-index -1, which paints it over the canvas background and under every
   piece of content, so nothing in the document needs a stacking context. */

.galaxy {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  contain: strict;
}
.galaxy > * { position: absolute; inset: -8%; display: block; }

/* Four clouds, placed off-centre so the field never reads as a symmetrical
   vignette, drifting far too slowly to catch in the act. */
.galaxy__nebula {
  background-image:
    radial-gradient(48vw 40vw at 10% 4%, rgb(var(--sky-3-rgb) / 0.62), transparent 66%),
    radial-gradient(40vw 36vw at 92% 20%, rgb(var(--accent-2-rgb) / 0.20), transparent 68%),
    radial-gradient(56vw 46vw at 74% 92%, rgb(var(--sky-1-rgb) / 0.55), transparent 70%),
    radial-gradient(36vw 32vw at 26% 74%, rgb(var(--sky-4-rgb) / 0.40), transparent 68%);
}

/* Three depths of star, moved at three speeds by pieces.js, so the field has
   parallax rather than one flat sheet of specks. */
.galaxy__stars {
  /* Deep enough below the fold that a full tile of parallax never uncovers
     the bottom edge. */
  inset: -8% -8% -820px -8%;
  background-repeat: repeat;
  transform: translate3d(0, var(--star-shift, 0px), 0);
}
.galaxy > .galaxy__stars--far { display: none; }
.galaxy__stars--mid { opacity: 0.62; }
.galaxy__stars--near { opacity: 0.75; }
.galaxy__stars--mid {
  background-image:
    radial-gradient(1.3px 1.3px at 95px 423px, rgb(255 255 255 / 0.66), transparent 62%),
    radial-gradient(1.6px 1.6px at 292px 244px, rgb(255 255 255 / 0.74), transparent 62%),
    radial-gradient(1.6px 1.6px at 233px 378px, rgb(255 255 255 / 0.6), transparent 62%),
    radial-gradient(1.3px 1.3px at 267px 379px, rgb(255 255 255 / 0.53), transparent 62%),
    radial-gradient(1.3px 1.3px at 373px 510px, rgb(255 255 255 / 0.47), transparent 62%),
    radial-gradient(1.6px 1.6px at 249px 378px, rgb(255 255 255 / 0.62), transparent 62%),
    radial-gradient(1.6px 1.6px at 330px 143px, rgb(255 255 255 / 0.67), transparent 62%),
    radial-gradient(1.6px 1.6px at 99px 318px, rgb(255 255 255 / 0.53), transparent 62%),
    radial-gradient(1.3px 1.3px at 103px 487px, rgb(255 255 255 / 0.54), transparent 62%),
    radial-gradient(1.6px 1.6px at 152px 356px, rgb(255 255 255 / 0.74), transparent 62%),
    radial-gradient(1.6px 1.6px at 157px 260px, rgb(255 255 255 / 0.73), transparent 62%),
    radial-gradient(1.3px 1.3px at 380px 262px, rgb(255 255 255 / 0.66), transparent 62%);
  background-size: 520px 520px;
}
.galaxy__stars--near {
  background-image:
    radial-gradient(2.2px 2.2px at 127px 324px, rgb(255 255 255 / 0.75), rgb(var(--accent-rgb) / 0.26) 38%, transparent 72%),
    radial-gradient(2.2px 2.2px at 268px 750px, rgb(255 255 255 / 0.92), rgb(var(--accent-rgb) / 0.32) 38%, transparent 72%),
    radial-gradient(2.8px 2.8px at 97px 250px, rgb(255 255 255 / 0.93), rgb(var(--accent-rgb) / 0.33) 38%, transparent 72%),
    radial-gradient(2.8px 2.8px at 361px 404px, rgb(255 255 255 / 0.88), rgb(var(--accent-rgb) / 0.31) 38%, transparent 72%),
    radial-gradient(2.8px 2.8px at 499px 47px, rgb(255 255 255 / 0.91), rgb(var(--accent-rgb) / 0.32) 38%, transparent 72%),
    radial-gradient(2.8px 2.8px at 710px 189px, rgb(255 255 255 / 0.71), rgb(var(--accent-rgb) / 0.25) 38%, transparent 72%),
    radial-gradient(2.8px 2.8px at 102px 114px, rgb(255 255 255 / 0.74), rgb(var(--accent-rgb) / 0.26) 38%, transparent 72%);
  background-size: 780px 780px;
}

/* Deep corners: the room is lit from the middle, like a stage. */
.galaxy__veil {
  inset: 0;
  background-image: radial-gradient(120% 86% at 50% 34%, transparent 38%, rgb(var(--shade-rgb) / 0.55) 100%);
}

/* Rooms. palette.js already turns the hue per page; these only say how much
   of the night each room wants. */
html[data-room="about"] .galaxy__nebula { opacity: 0.72; }
html[data-room="about"] .galaxy__veil { background-image: radial-gradient(116% 84% at 50% 30%, transparent 30%, rgb(var(--shade-rgb) / 0.78) 100%); }
html[data-room="about"] .galaxy__stars { --twinkle-hi: 0.62; }
html[data-room="ownership"] .galaxy__nebula { opacity: 0.90; }
html[data-room="branding"] .galaxy__stars { --twinkle-hi: 0.88; }
html[data-room="contact"] .galaxy__nebula { opacity: 1.08; }
html[data-room="contact"] .galaxy__stars--near { --twinkle-hi: 0.95; }
html[data-room="lost"] .galaxy__nebula { opacity: 0.50; }
html[data-room="lost"] .galaxy__stars { opacity: 0.35; }

/* The paper room. Stars would be invisible on stock, so Work gets dust and
   grey weather instead - the same field, lit from the other side. */
html.is-light .galaxy__nebula {
  background-image:
    radial-gradient(52vw 42vw at 8% 2%, rgb(var(--sky-3-rgb) / 0.10), transparent 68%),
    radial-gradient(44vw 38vw at 94% 22%, rgb(var(--shade-rgb) / 0.05), transparent 70%),
    radial-gradient(58vw 48vw at 76% 94%, rgb(var(--sky-1-rgb) / 0.08), transparent 72%);
}
html.is-light .galaxy__stars { display: none; }
html.is-light .galaxy__veil { background-image: radial-gradient(118% 88% at 50% 32%, transparent 46%, rgb(var(--shade-rgb) / 0.10) 100%); }

@media (prefers-reduced-motion: reduce) {
  .galaxy__stars { transform: none; }
  .galaxy__stars--mid { opacity: 0.50; }
  .galaxy__stars--near { opacity: 0.62; }
}
@media (max-width: 639px) {
  .galaxy > .galaxy__stars--mid { display: none; }
}
html.is-light .sound-control,
html.is-light .install-control {
  color: rgb(var(--on-shade-rgb) / 0.92);
}
html.is-light .sound-control__copy small {
  color: rgb(var(--on-shade-rgb) / 0.50);
}
/* --- 5. Links & buttons --------------------------------------------------- */

.link {
  position: relative;
  display: inline;
  color: var(--text);
  background-image: var(--grad);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  padding-bottom: 2px;
}
.link:hover, .link:focus-visible { color: var(--accent); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-3);
  min-height: 52px;
  padding: var(--s-3) var(--s-6);
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: transparent;
  color: var(--text);
  font: 600 0.8125rem/1 var(--font-ui);
  letter-spacing: 0.06em;
  cursor: pointer;
  will-change: transform;
}
.btn:hover, .btn:focus-visible { border-color: rgb(var(--ink-rgb) / 0.34); transform: translateY(-2px); }

.btn--solid {
  border-color: transparent;
  background: var(--grad);
  color: var(--shade);
  box-shadow: 0 6px 24px -8px var(--accent-glow);
}
.btn--solid:hover, .btn--solid:focus-visible {
  border-color: transparent;
  box-shadow: 0 14px 34px -10px var(--accent-glow);
}

/* --- 6. Mark -------------------------------------------------------------- */

/* The mark, applied as a CSS mask over a background — so one definition
   drives every instance (header, footer, loader, cursor, 404) and each one
   recolours with its own text colour or the accent gradient.

   The mask is an inline data: URI rather than url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 1000 806.8'%3E%3Cpath fill-rule='evenodd' d='M92.0 57.9 C87.4 65.5 93.4 51.1 85.4 70.5 C77.3 89.8 72.7 101.2 65.2 122.4 C57.6 143.7 61.8 132.0 60.2 141.3 C58.6 150.6 58.3 141.8 59.9 153.5 C61.5 165.3 61.6 165.9 65.5 180.3 C69.4 194.8 63.0 175.8 72.8 201.9 C82.6 227.9 88.8 244.0 98.3 267.0 C107.7 290.1 98.1 268.2 104.2 278.6 C110.4 289.0 108.8 287.7 118.8 301.8 C128.8 315.9 122.1 310.0 137.7 325.6 C153.2 341.2 152.7 339.6 170.7 353.7 C188.8 367.8 180.2 361.4 197.9 372.6 C215.6 383.8 210.9 381.5 229.6 391.1 C248.4 400.8 238.9 396.6 260.4 404.7 C282.0 412.8 286.7 413.0 301.5 418.3 C316.2 423.5 306.9 420.4 309.7 422.2 C312.5 424.1 312.1 422.5 310.7 424.6 C309.3 426.6 308.6 427.3 305.1 429.2 C301.6 431.1 306.0 430.2 299.1 430.8 C292.3 431.4 293.0 431.5 282.3 431.2 C271.5 430.9 275.3 431.2 263.4 429.8 C251.5 428.5 260.7 431.3 242.6 426.5 C224.4 421.8 218.9 419.6 202.8 414.0 C186.8 408.3 197.3 412.1 188.9 407.7 C180.6 403.2 188.6 409.0 175.0 399.1 C161.5 389.1 157.8 386.3 143.9 374.6 C130.0 362.9 136.0 367.7 128.7 360.0 C121.5 352.4 124.7 353.4 119.8 349.1 C114.9 344.8 116.5 346.1 112.5 345.8 C108.5 345.5 109.2 346.4 106.6 348.1 C103.9 349.8 106.8 345.8 103.6 351.4 C100.4 357.1 104.2 352.0 96.0 367.0 C87.7 382.0 85.5 385.8 76.1 401.4 C66.7 417.0 70.5 411.0 64.5 418.9 C58.6 426.9 61.2 423.6 56.3 427.9 C51.3 432.1 58.2 429.1 48.0 433.2 C37.8 437.2 36.2 436.4 22.2 441.4 C8.2 446.5 8.0 445.8 1.3 450.0 C-5.3 454.3 0.4 385.2 0.0 455.7 C-0.4 526.1 -0.3 613.5 0.0 685.0 C0.3 756.5 0.7 691.0 1.0 693.9 C2.3 693.3 2.6 694.3 5.0 692.3 C7.3 690.2 6.9 688.5 8.9 687.0 C10.9 685.5 10.4 686.2 11.6 687.3 C12.8 688.4 13.4 686.9 12.9 690.6 C12.4 694.3 13.4 692.1 9.9 699.5 C6.5 707.0 4.2 708.8 1.3 715.4 C-1.6 722.1 0.6 694.4 0.3 721.7 C0.0 749.0 0.3 778.5 0.3 806.4 C150.4 806.5 317.4 806.8 455.0 806.8 C592.6 806.7 456.2 807.7 459.0 806.1 C461.7 804.5 460.6 803.5 464.3 801.5 C467.9 799.4 457.3 800.1 471.2 799.1 C485.1 798.1 491.7 799.2 510.6 798.1 C529.5 797.1 511.4 800.2 534.1 795.5 C556.7 790.8 562.3 789.1 586.0 782.6 C609.8 776.0 592.7 779.2 613.2 773.7 C633.6 768.1 627.3 770.9 654.2 764.1 C681.1 757.2 642.8 768.9 702.8 750.8 C762.9 732.8 801.3 721.7 854.4 703.8 C907.5 686.0 860.6 702.8 879.9 691.3 C899.1 679.7 901.8 677.1 918.6 665.5 C935.4 653.8 918.8 667.9 935.8 652.5 C952.8 637.2 956.2 634.0 975.2 614.2 C994.1 594.3 991.6 596.9 999.0 586.4 C1006.5 575.8 1000.4 582.6 1000.0 579.1 C999.6 575.6 1002.8 582.1 997.7 574.8 C992.5 567.4 993.5 571.3 982.8 554.6 C972.1 537.9 983.3 552.3 961.9 519.2 C940.6 486.1 933.4 478.1 911.6 444.4 C889.9 410.8 905.2 431.2 889.5 407.0 C873.8 382.8 877.0 391.0 859.4 363.7 C841.7 336.4 846.9 341.2 830.6 316.0 C814.3 290.8 815.1 292.8 805.1 279.6 C795.1 266.4 802.4 276.2 797.2 272.0 C791.9 267.8 794.2 269.5 787.6 265.7 C780.9 261.9 797.7 269.1 775.0 259.4 C752.3 249.8 739.0 244.1 711.8 233.6 C684.6 223.1 699.5 230.2 684.3 224.4 C669.1 218.5 671.9 218.4 661.2 214.1 C650.4 209.8 663.6 215.9 648.6 210.1 C633.6 204.4 637.7 204.5 611.2 194.9 C584.7 185.3 582.8 186.3 560.2 178.0 C537.7 169.8 551.6 173.5 536.1 167.4 C520.6 161.4 524.9 164.4 508.6 157.8 C492.3 151.3 495.4 153.1 481.8 145.6 C468.2 138.1 477.5 144.8 463.3 132.7 C449.1 120.6 453.2 125.0 434.5 105.2 C415.7 85.5 418.1 85.2 400.7 66.8 C383.4 48.5 390.5 58.8 376.6 44.0 C362.7 29.2 363.0 27.1 354.4 17.5 C345.8 8.0 354.4 16.1 347.8 12.2 C341.1 8.4 342.0 8.1 332.2 4.6 C322.5 1.2 323.3 2.1 315.4 0.7 C307.4 -0.7 312.3 -1.3 305.8 0.0 C299.2 1.3 299.6 1.2 293.5 5.0 C287.5 8.7 291.0 6.0 285.6 12.6 C280.1 19.1 281.6 16.8 275.3 26.8 C269.1 36.8 267.9 38.6 264.7 46.0 C261.5 53.4 263.5 47.8 264.7 51.6 C265.9 55.4 258.7 47.9 268.7 58.6 C278.7 69.2 287.1 75.6 298.1 87.0 C309.2 98.4 299.6 87.6 305.4 96.6 C311.3 105.7 307.9 96.4 317.7 117.1 C327.4 137.9 329.9 140.6 337.9 165.8 C345.8 191.0 342.4 187.9 344.1 201.2 C345.9 214.5 344.7 205.6 343.8 210.1 C342.9 214.7 342.9 214.6 341.2 216.4 C339.5 218.2 340.4 217.1 338.2 216.1 C336.0 215.1 337.5 221.5 333.9 213.1 C330.3 204.7 333.4 206.1 326.3 188.0 C319.1 169.8 320.8 174.2 310.1 152.5 C299.3 130.9 302.1 134.6 290.5 115.8 C279.0 97.1 283.0 103.7 271.7 90.0 C260.4 76.3 267.0 83.1 252.8 70.2 C238.6 57.2 236.7 56.5 224.4 47.0 C212.0 37.5 219.9 43.2 211.8 38.4 C203.6 33.5 207.2 35.1 197.2 30.8 C187.2 26.4 190.6 27.0 178.4 23.8 C166.1 20.6 166.5 21.1 156.5 20.2 C146.5 19.3 153.5 19.4 144.9 20.8 C136.4 22.3 137.4 21.7 128.1 25.1 C118.7 28.6 122.1 26.4 113.8 32.4 C105.6 38.5 107.1 37.7 100.6 45.3 C94.0 53.0 96.6 50.4 92.0 57.9 Z M532.4 369.6 C533.6 367.5 532.6 366.1 536.1 365.0 C539.5 363.9 535.3 362.1 544.0 366.0 C552.7 369.9 553.7 372.0 565.2 377.9 C576.7 383.8 567.9 380.2 582.4 385.5 C596.9 390.8 592.5 387.6 613.5 395.4 C634.5 403.3 632.3 402.2 652.5 411.6 C672.8 421.1 658.2 413.7 681.0 426.9 C703.8 440.1 712.3 444.9 728.7 455.7 C745.0 466.4 733.8 458.6 735.6 462.6 C737.4 466.6 736.1 466.0 734.6 468.9 C733.1 471.8 734.9 470.2 730.6 472.2 C726.4 474.2 729.3 471.8 720.4 475.5 C711.4 479.2 710.9 480.9 700.9 484.4 C690.8 488.0 693.8 486.4 687.0 487.4 C680.1 488.4 684.7 488.3 678.0 487.8 C671.4 487.3 674.7 488.6 664.8 485.8 C654.9 483.0 658.1 484.6 644.9 478.5 C631.7 472.3 634.2 473.3 620.8 465.3 C607.4 457.2 617.7 465.6 600.3 451.7 C582.8 437.8 576.4 432.0 562.5 418.9 C548.6 405.8 562.4 420.3 553.9 408.0 C545.5 395.7 541.0 388.7 534.4 377.9 C527.9 367.1 532.7 374.4 532.1 371.9 C531.5 369.5 531.2 371.7 532.4 369.6 Z M648.2 560.2 C653.0 563.9 648.9 562.6 646.9 564.9 C644.9 567.1 653.6 565.9 641.6 567.8 C629.6 569.8 624.7 569.0 606.9 571.5 C589.1 574.0 615.9 572.5 582.4 576.1 C548.9 579.7 533.1 580.6 495.4 583.4 C457.6 586.2 475.5 583.9 456.7 585.4 C437.8 586.9 444.3 587.4 432.5 588.4 C420.7 589.3 423.9 589.1 417.3 588.7 C410.6 588.3 412.6 587.6 410.3 587.0 C410.6 586.4 407.6 587.5 411.0 585.0 C414.4 582.6 409.3 583.2 421.6 578.8 C433.9 574.3 428.0 578.4 452.0 570.2 C476.0 561.9 478.1 559.4 501.7 551.3 C525.2 543.2 515.0 548.7 530.4 543.0 C545.9 537.4 541.8 537.1 553.3 532.4 C564.8 527.8 561.9 528.9 568.8 527.5 C575.8 526.1 572.6 527.2 576.4 527.8 C580.3 528.4 573.7 525.0 581.7 529.5 C589.8 533.9 588.5 535.7 603.2 542.7 C618.0 549.6 617.5 547.4 631.0 552.6 C644.5 557.9 643.5 556.6 648.2 560.2 Z'/%3E%3C/svg%3E"),
   and that is load-bearing: Chrome and Safari treat file:// pages as opaque
   origins and refuse to load an EXTERNAL SVG as a mask, so the mark silently
   disappeared everywhere when the site was opened straight off disk. A data
   URI has no origin to fail, and it costs one request fewer.

   assets/img/mouse-head.svg is the source of truth: the running-mouse
   silhouette, applied as a PNG data-URI mask so it recolours and stays
   file://-safe. See "The mark" in README.md. */
.mark {
  display: block;
  flex: none;
  aspect-ratio: 1000 / 399;
  --mark-mask: url("data:image/png;base64,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");
  background-color: currentColor;
  -webkit-mask: var(--mark-mask) center / contain no-repeat;
          mask: var(--mark-mask) center / contain no-repeat;
}
.mark--grad { background-color: transparent; background-image: var(--grad); }

/* The mouse head used to be the on-screen pointer as well as the mark, with
   the native cursor hidden under it. It is not any more: the pointer is the
   visitor's own. A replaced cursor costs a frame of lag on every movement no
   matter how well it is written, overrides the shape the operating system
   uses to say what a thing does — a text beam over text, a resize arrow on an
   edge — and quietly ignores whatever cursor size or contrast setting someone
   has chosen for themselves.

   pointer.js is unchanged as an ENGINE: it still tracks position and velocity
   and every effect on the site still subscribes to it. It simply no longer
   draws anything. This also removed the third copy of the mark's data URI
   from this stylesheet. */

/* --- 7. Header ------------------------------------------------------------ */

.header {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: 90;
  height: var(--header-h);
}
/* The blur lives on a pseudo-element, NOT on .header itself: backdrop-filter
   makes an element a containing block for `position: fixed` descendants, which
   would trap the full-screen mobile nav panel inside the header. */
.header::before {
  content: none;
}
.header__inner {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-5);
  height: 100%;
}
.header__inner > .brand { order: 1; }
.header__inner > .nav { order: 2; margin-left: auto; }
.header__inner > .lang { order: 3; flex: none; }
.header__inner > .nav-toggle { order: 4; }
.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 44px;
  padding: 6px 16px 6px 10px;
  color: var(--text);
  border: 1px solid rgb(var(--accent-rgb) / 0.28);
  border-radius: var(--radius);
  background:
    linear-gradient(155deg, rgb(var(--accent-rgb) / 0.18), transparent 48%),
    rgba(var(--ground-rgb) / 0.62);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
          backdrop-filter: blur(8px) saturate(120%);
  box-shadow:
    0 16px 40px -24px rgb(var(--shade-rgb) / 0.88),
    0 0 24px -12px rgb(var(--accent-rgb) / 0.28),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.14);
}
.brand .mark {
  height: 26px;
  filter: drop-shadow(0 0 10px rgb(var(--accent-rgb) / 0.22));
}
.brand__word {
  font: 700 0.8125rem/1 var(--font-ui);
  letter-spacing: 0.2em;
  text-transform: uppercase;
}
.brand:hover {
  border-color: rgb(var(--accent-rgb) / 0.55);
  box-shadow:
    0 16px 40px -24px rgb(var(--shade-rgb) / 0.88),
    0 0 28px -10px rgb(var(--accent-rgb) / 0.4),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.18);
}
.brand:hover .brand__word { color: var(--accent); }

.nav { display: flex; align-items: center; gap: var(--s-6); }
.nav__list { display: flex; align-items: center; gap: var(--s-6); }

/* The travelling marker (nav.js). One rule that glides between the links,
   rather than six that each grow their own — the row reads as one object
   being moved rather than six that light up. It rests on the current page.

   `position: relative` on the list makes it the offset parent, which is what
   lets nav.js position the marker with offsetLeft and not have to unpick a
   scroll offset or a transform every time the row moves. */
.nav__list.is-marked { position: relative; }
.nav__marker {
  position: absolute;
  left: 0;
  bottom: 2px;
  height: 2px;
  width: 0;
  border-radius: 2px;
  background: var(--grad);
  box-shadow: 0 0 12px rgb(var(--accent-rgb) / 0.55);
  opacity: 0;
  pointer-events: none;
  transform: translate3d(0,0,0);
  /* The width and the travel are eased together so it stretches slightly into
     the move, the way the cursor and the hero's stars do. */
  transition: transform 420ms var(--e-out), width 420ms var(--e-out),
              opacity 240ms var(--e-out);
}
.nav__marker.is-on { opacity: 1; }
/* With the marker doing the work, the per-link underline would be a second
   rule drawing the same thing. It stays in the stylesheet as the no-JS hover
   state and is stood down only once nav.js has actually built the marker. */
.nav__list.is-marked .nav__link::after { display: none; }
/* The row is the primary navigation of the whole site and it was set at
   13px, lighter than the body copy and quieter than the footer links under
   it. It is the display face now at 15px, which is the smallest step that
   reads as a considered piece of typography rather than as chrome. */
.nav__link {
  position: relative;
  display: block;
  padding-block: var(--s-3);
  font: 600 0.9375rem/1 var(--font-display);
  letter-spacing: -0.005em;
  color: var(--text-dim);
  transition: color var(--d-fast) var(--e-out);
}
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: 2px;
  width: 100%; height: 2px;
  border-radius: 2px;
  background: var(--grad);
  transform: scaleX(0);
  /* Draws in from the left, retracts to the right — the origin swaps on
     hover, so the rule follows the cursor through rather than growing and
     shrinking from the same end like a progress bar. One line of CSS for the
     difference between an underline that animates and one that behaves. */
  transform-origin: right;
  transition: transform 320ms var(--e-out);
}
.nav__link:hover, .nav__link:focus-visible { color: var(--text); }
.nav__link:hover::after, .nav__link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}
/* The page you are on keeps its rule and its accent, and does not animate. */
.nav__link[aria-current="page"] { color: var(--accent); }
.nav__link[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

.lang {
  display: inline-flex;
  align-items: center;
  gap: 0;
  min-height: 44px;
  padding: 4px;
  border: 1px solid rgb(var(--accent-rgb) / 0.22);
  border-radius: 999px;
  background:
    linear-gradient(155deg, rgb(var(--accent-rgb) / 0.10), transparent 52%),
    rgba(var(--ground-rgb) / 0.55);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
          backdrop-filter: blur(8px) saturate(120%);
  box-shadow:
    0 16px 40px -24px rgb(var(--shade-rgb) / 0.8),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.10);
}
.lang a {
  font: 600 0.68rem/1 var(--font-ui);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
  min-width: 36px;
  min-height: 32px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 10px;
  border-radius: 999px;
}
.lang a:hover, .lang a:focus-visible { color: var(--text); }
.lang a[aria-current] {
  color: var(--shade);
  background: var(--grad);
}
.lang span[aria-hidden] { display: none; }
.lang.is-live { position: relative; }
.lang__thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  height: calc(100% - 8px);
  width: 36px;
  border-radius: 999px;
  background: var(--grad);
  box-shadow: 0 6px 16px -8px rgb(var(--accent-rgb) / 0.55),
              inset 0 1px 0 rgb(var(--ink-rgb) / 0.22);
  pointer-events: none;
  opacity: 0;
  transform: translate3d(0, 0, 0);
  transition: transform 340ms var(--e-out), width 340ms var(--e-out),
              opacity 200ms var(--e-out);
}
.lang.is-live .lang__thumb.is-on { opacity: 1; }
.lang.is-live a[aria-current] { background: transparent; color: var(--shade); }
.lang.is-live a {
  position: relative;
  z-index: 1;
  transition: color var(--d-fast) var(--e-out), transform 180ms var(--e-out);
}
.lang.is-live a:hover,
.lang.is-live a:focus-visible { transform: translateY(-1px); }
.lang:active { transform: scale(0.97); }

.nav-toggle {
  display: none;
  align-items: center;
  gap: var(--s-2);
  min-height: 44px;
  padding: var(--s-2) var(--s-5);
  border: 1px solid rgb(var(--accent-rgb) / 0.28);
  border-radius: var(--radius);
  background:
    linear-gradient(155deg, rgb(var(--accent-rgb) / 0.14), transparent 50%),
    rgba(var(--ground-rgb) / 0.55);
  -webkit-backdrop-filter: blur(8px) saturate(120%);
          backdrop-filter: blur(8px) saturate(120%);
  box-shadow:
    0 16px 40px -24px rgb(var(--shade-rgb) / 0.8),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.10);
  font: 600 0.8125rem/1 var(--font-ui);
  letter-spacing: 0.04em;
  color: var(--text);
  cursor: pointer;
}
.nav-toggle:hover { border-color: rgb(var(--accent-rgb) / 0.55); }

/* Shown only inside the mobile panel — declared before the media query so the
   query wins. */
.nav__email { display: none; }

@media (max-width: 1099px) {
  /* Only when nav.js is running. Without it the button is inert — the panel
     it opens is opened by script and by nothing else — so with JavaScript off
     this rendered a "Menu" control on every phone that did nothing at all
     when pressed. A dead control is worse than no control: it tells the
     visitor the navigation is behind it and then refuses to produce it.
     Hidden, the footer's own list of all six pages is the navigation, which
     is present on every page and needs no script. */
  html.has-navx .nav-toggle { display: inline-flex; }
  .header__inner { gap: var(--s-2); }
  .brand { padding: 4px 12px 4px 8px; }
  .brand .mark { height: 22px; }
  .nav-toggle,
  .navx-trigger { padding: 6px 10px; }
  .nav {
    position: fixed;
    inset: var(--header-h) 0 0 0;
    z-index: 89;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    gap: var(--s-6);
    padding: var(--gutter);
    background: var(--ground);
    visibility: hidden;
    opacity: 0;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
  }
  body.nav-open .nav { visibility: visible; opacity: 1; }
  html.navx-open,
  body.nav-open { overflow: hidden; }
  .nav__list { flex-direction: column; align-items: flex-start; gap: 2px; }
  .nav__link { font-size: var(--t-h2); font-family: var(--font-display); font-weight: 600; }
  .header__inner > .lang { order: 2; margin-left: auto; }
  .header__inner > .nav-toggle { order: 3; }
  .header__inner > .nav { order: 4; margin-left: 0; }
  .lang { margin-top: 0; }
  .nav__email { display: block; }
}

/* --- 8. Footer ------------------------------------------------------------ */

.footer {
  border-top: 1px solid var(--rule-soft);
  padding-block: var(--s-9) var(--s-5);
  background: var(--ground);
  position: relative;
  z-index: 2;
}
.footer__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--s-7); }
.footer h2 {
  font: 600 var(--t-micro)/1.4 var(--font-ui);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-faint);
  margin-bottom: var(--s-4);
}
.footer__brand { display: flex; align-items: center; gap: var(--s-3); margin-bottom: var(--s-3); }
.footer__brand .mark { height: 20px; }
.footer__brand .mark--sm { height: 24px; }
.footer li + li { margin-top: var(--s-2); }
.footer a { color: var(--text-dim); }
.footer a:hover, .footer a:focus-visible { color: var(--accent); }
.footer__addr { font-style: normal; color: var(--text-faint); font-size: 0.875rem; line-height: 1.8; }
.footer__legal { display: flex; flex-wrap: wrap; gap: var(--s-3) var(--s-5); margin-left: auto; }
.footer__legal .link { color: inherit; }
@media (max-width: 639px) { .footer__legal { margin-left: 0; } }
.footer__bottom {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-3) var(--s-5);
  align-items: center;
  margin-top: var(--s-7);
  padding-top: var(--s-5);
  border-top: 1px solid var(--rule-soft);
  font-size: 0.8125rem;
  color: var(--text-faint);
}
@media (max-width: 859px) { .footer__grid { grid-template-columns: 1fr; gap: var(--s-6); } }

/* --- 9. Page shell -------------------------------------------------------- */

.main { padding-top: var(--header-h); position: relative; z-index: 2; }
.page-head { padding-block: clamp(56px, 8vw, 112px) clamp(32px, 5vw, 64px); position: relative; }
.page-head .label { margin-bottom: var(--s-5); }
.page-head p { margin-top: var(--s-5); }

/* Inner heroes. One shape, four variants. The homepage keeps its own
   .hero stage; this is the room you walk into after that. Height follows
   the copy and art so the next section is not a blank fold away. */
.page-head.page-hero {
  min-height: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  position: relative;
  overflow: hidden;
  padding-block: clamp(72px, 10vh, 128px) clamp(56px, 8vh, 96px);
  width: 100%;
  max-width: none;
}
#after-hero { scroll-margin-top: calc(var(--header-h) + var(--s-4)); }
.page-head.page-hero::before { content: none; animation: none; background: none; }
.page-hero__sky {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
}
.page-hero__copy {
  position: relative;
  z-index: 2;
  width: 100%;
}
.page-hero .h-hero {
  font-size: clamp(2.5rem, 6.2vw, 5.25rem);
  line-height: 1.05;
}
.page-hero--object .h-hero {
  max-width: min(56rem, 62vw);
}
.page-hero--object .h-1,
.page-hero--object .lede,
.page-hero--object .hero__cta {
  max-width: min(38rem, 52vw);
}
.page-hero--folio .h-1,
.page-hero--folio .lede {
  max-width: min(28rem, 38vw);
}
.page-head:has(.page-art--keep) .h-1,
.page-head:has(.page-art--keep) .lede,
.page-head:has(.page-art--emblem) .lede,
.page-head:has(.page-art--cubes) .lede {
  max-width: min(38rem, 52vw);
}

/* Authored lines in the source, not <br>. Desktop keeps the breaks;
   below 640px they collapse so the heading wraps as a sentence. */
.page-hero .display > .ln { display: block; }
@media (min-width: 640px) {
  .page-hero .display > .ln { white-space: nowrap; }
}
@media (max-width: 639px) {
  .page-hero .display > .ln,
  .page-hero .display.is-split > .ln,
  .page-hero .display.is-split .ln__i {
    display: inline;
    overflow: visible;
    padding: 0;
    margin: 0;
  }
  .page-hero .display > .ln + .ln::before { content: " "; }
}

.page-hero__cue {
  position: absolute;
  left: 50%;
  bottom: clamp(16px, 3vh, 32px);
  z-index: 3;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  transform: translateX(-50%);
  color: var(--text-faint);
}
.page-hero__cue::before {
  content: "";
  width: 1px;
  height: 22px;
  border-radius: 2px;
  background: var(--grad);
  transform-origin: 50% 0;
}
.page-hero__cue::after {
  content: "";
  position: absolute;
  bottom: 8px;
  width: 7px;
  height: 7px;
  border-right: 1px solid var(--accent);
  border-bottom: 1px solid var(--accent);
  transform: rotate(45deg);
}

@media (max-width: 1099px) {
  .page-head.page-hero { min-height: 0; }
  .page-hero--object .h-hero,
  .page-hero--object .h-1,
  .page-hero--object .lede,
  .page-hero--object .hero__cta,
  .page-hero--folio .h-1,
  .page-hero--folio .lede,
  .page-hero--type .h-hero,
  .page-head:has(.page-art--keep) .h-1,
  .page-head:has(.page-art--keep) .lede,
  .page-head:has(.page-art--emblem) .h-hero,
  .page-head:has(.page-art--emblem) .lede,
  .page-head:has(.page-art--cubes) .h-hero,
  .page-head:has(.page-art--cubes) .lede,
  .page-head:has(.page-art--desk) .h-1,
  .page-head:has(.page-art--desk) .lede,
  .page-head:has(.page-art--desk) .hero__cta { max-width: none; }
  .page-hero .display > .ln { white-space: normal; }
  /* Object art sits under the copy. Absolute placement at this width
     covered the lede on Websites and shoved the branding mark off-canvas. */
  .page-hero--object .markfield,
  .page-hero--object .page-art,
  .page-hero--object .page-art--desk,
  .page-hero--object .page-art--emblem,
  .page-hero--object .page-art--cubes {
    position: relative;
    inset: auto;
    right: auto;
    left: auto;
    top: auto;
    bottom: auto;
    transform: none;
    width: min(280px, 78vw);
    max-width: 100%;
    height: auto;
    margin: var(--s-6) 0 0 0;
    z-index: 1;
    opacity: 0.92;
  }
  .page-hero--object .markfield {
    width: min(340px, 88vw);
    aspect-ratio: 1000 / 399;
    filter: drop-shadow(0 0 24px rgb(var(--accent-rgb) / 0.18));
  }
  .page-hero--object .page-art--cubes { height: 200px; width: min(260px, 72vw); }
  .page-hero--object .page-hero__cue {
    position: relative;
    left: auto;
    bottom: auto;
    transform: none;
    margin: var(--s-5) auto 0;
  }
}

/* --- 10. Hero and the aurora ---------------------------------------------- */

.hero {
  position: relative;
  min-height: clamp(520px, 82vh, 860px);
  display: flex;
  align-items: center;
  padding-block: var(--s-10) var(--s-9);
  overflow: hidden;
}
.hero__inner { position: relative; z-index: 2; }
.hero p { margin-top: var(--s-6); }
.hero__cta { margin-top: var(--s-7); display: flex; flex-wrap: wrap; gap: var(--s-4); }

/* The headline owns the hero's one decisive speed moment. Its children stay
   normal, readable text until main.js opts them into the entry sequence. */
.title-warp {
  position: relative;
  width: fit-content;
  max-width: 100%;
  perspective: 1100px;
  perspective-origin: 18% 50%;
  isolation: isolate;
}
.warp-line {
  display: block;
  position: relative;
  z-index: 2;
  transform-origin: 0 50%;
  backface-visibility: hidden;
  will-change: transform, filter, opacity;
}
.title-warp__wake,
.title-warp__flash {
  position: absolute;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
}
.title-warp__wake {
  display: none;
  left: -18vw;
  top: 54%;
  width: min(82vw, 1040px);
  height: 3px;
  border-radius: 999px;
  background: linear-gradient(90deg,
    rgb(var(--accent-rgb) / 0), rgb(var(--accent-rgb) / 0.14) 28%,
    rgba(255,255,255,0.96) 64%, rgb(var(--accent-rgb) / 0));
  box-shadow: 0 0 12px rgb(var(--accent-rgb) / 0.72), 0 0 36px rgb(var(--accent-rgb) / 0.26);
  transform-origin: 0 50%;
}
.title-warp__flash {
  inset: -35% -12%;
  background: radial-gradient(ellipse at 22% 52%,
    rgba(255,255,255,0.28), rgb(var(--accent-rgb) / 0.15) 22%, rgb(var(--accent-rgb) / 0) 64%);
  mix-blend-mode: screen;
}

/* --- The stage -----------------------------------------------------------
   A perspective container holding the sky and three ridges at different
   translateZ. Because they are genuinely at different depths inside one
   preserve-3d parent, tilting the stage moves them by different amounts AND
   foreshortens them — parallax that is a property of the geometry rather
   than three elements being nudged by different constants.

   NOTE: overflow must not be set on .hero__scene. Any overflow other than
   visible on a preserve-3d element forces it to flatten, and the whole thing
   collapses to 2D. .hero clips instead — it is outside the 3D context. */

.hero__stage {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  perspective: 1400px;
  perspective-origin: 50% 40%;
}
.hero__scene {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  will-change: transform;
}

/* The WebGL field. Hidden until scene.js has proved the shader compiles, so
   a device without WebGL simply keeps the CSS sky below and never flickers. */
.sky {
  position: absolute;
  inset: -12%;
  width: 124%;
  height: 124%;
  opacity: 0;
  transform: translateZ(-420px) scale(1.34);
}
.has-sky .sky { opacity: 1; }
.has-sky .aurora { opacity: 0; }

/* The CSS sky. Five soft washes drifting on their own long cycles. This is
   the no-JavaScript and no-WebGL state, and it is a complete hero on its own
   — the canvas above is only ever an upgrade. */
.aurora {
  position: absolute;
  inset: -20% -10% auto -10%;
  height: 130%;
  z-index: 0;
  pointer-events: none;
  transform: translateZ(-420px) scale(1.34);
}
.aurora__blob {
  position: absolute;
  border-radius: 50%;
  will-change: transform;
}
/* radial-gradient rather than filter: blur() — visually the same at this
   softness, and it costs the compositor nothing to move around. */
.aurora__blob--1 { width: 62vw; height: 62vw; left: -8vw;  top: -14vw;
  background: radial-gradient(circle, var(--sky-1) 0%, rgb(var(--sky-1-rgb) / 0) 66%); }
.aurora__blob--2 { width: 54vw; height: 54vw; right: -6vw; top: -6vw;
  background: radial-gradient(circle, var(--sky-2) 0%, rgb(var(--sky-2-rgb) / 0) 66%); }
.aurora__blob--3 { width: 58vw; height: 58vw; right: 6vw;  bottom: -18vw;
  background: radial-gradient(circle, var(--sky-3) 0%, rgb(var(--sky-3-rgb) / 0) 66%); }
.aurora__blob--4 { width: 40vw; height: 40vw; left: 18vw;  bottom: -10vw;
  background: radial-gradient(circle, var(--sky-4) 0%, rgb(var(--sky-4-rgb) / 0) 66%); }
.aurora__blob--5 { width: 34vw; height: 34vw; left: 42vw;  top: 4vw;
  background: radial-gradient(circle, rgb(var(--accent-rgb) / 0.16) 0%, rgb(var(--accent-rgb) / 0) 70%); }

/* Inner pages: one blob, slower, quieter. Not a clone of the homepage
   stage — no translateZ, no WebGL, tinted by the page's live sky stop. */
.aurora.aurora--quiet {
  inset: -28% -18% auto -12%;
  height: 108%;
  transform: none;
  opacity: 0.48;
}
.aurora--quiet .aurora__blob {
  width: 78vw;
  height: 78vw;
  left: 22%;
  top: -28%;
  right: auto;
  bottom: auto;
  will-change: auto;
}
html.is-light .aurora.aurora--quiet { opacity: 0.26; }

.mote {
  position: absolute;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--grad);
  opacity: 0;
  will-change: transform, opacity;
}

/* The horizon, in three ridges at three depths. Each scale compensates for
   the shrink its translateZ causes, so all three still span the width. */
.ridge {
  position: absolute;
  left: -6%; right: -6%; bottom: -2px;
  line-height: 0;
  pointer-events: none;
}
.ridge svg { width: 112%; height: auto; display: block; }
.ridge--far  { transform: translateZ(-240px) scale(1.19); }
.ridge--mid  { transform: translateZ(-110px) scale(1.09); }
.ridge--near { transform: translateZ(0); }
.ridge--far  path { fill: #262233; }
.ridge--mid  path { fill: #1E1B28; }
.ridge--near path { fill: var(--ground); }

/* Motes sit nearest the viewer, so they travel furthest when the stage
   tilts. That is the whole reason they are on their own layer. */
/* The warp drive (warp.js). It sits BEHIND all three ridges, so the horizon
   is a silhouette against it and the stars never streak over the foreground:
   you are standing on the dark side of something, watching it go past.

   -330px is between the sky (-420) and the far ridge (-240), and the scale is
   what that depth costs back: at perspective 1400px, (1400 + 330) / 1400.
   Change one and you must change the other or the canvas stops covering the
   hero when the stage tilts. */
.warp {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: translateZ(-330px) scale(1.24);
  pointer-events: none;
  image-rendering: auto;
}

/* --- 11. Index list (home: what we do) ------------------------------------ */

.index { border-top: 1px solid var(--rule-soft); perspective: 900px; }
.index__item { border-bottom: 1px solid var(--rule-soft); }
.index__link {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--s-5);
  padding-block: var(--s-6);
}
.index__num {
  font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: 0.18em;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.index__title { font-family: var(--font-display); font-size: var(--t-h2); font-weight: 600; line-height: 1.1; }
.index__meta { font-size: 0.875rem; color: var(--text-faint); text-align: right; }
.index__link:hover .index__meta { color: var(--text-dim); }
@media (max-width: 720px) {
  .index__link { grid-template-columns: 3rem 1fr; }
  .index__meta { grid-column: 2; text-align: left; }
}

/* --- 12. Bands ------------------------------------------------------------ */
/* Soft pastel panels with a large radius, rather than full-bleed slabs
   divided by hard rules. */

.band {
  background:
    linear-gradient(145deg, var(--surface-hi), rgb(var(--ink-rgb) / 0.018) 48%, rgb(var(--accent-2-rgb) / 0.035)),
    var(--ground-2);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-card);
  padding-block: clamp(40px, 6vw, 88px);
  margin-inline: var(--gutter);
  margin-block: clamp(24px, 4vw, 56px);
  box-shadow: var(--shadow-deep), inset 0 1px 0 rgb(var(--ink-rgb) / 0.045);
  overflow: hidden;
}
/* Inside a panel the gutter is the panel's, not the page's. */
.band > .wrap { padding-inline: clamp(24px, 3.5vw, 56px); }
.band--sky {
  background: linear-gradient(140deg, var(--sky-1) 0%, var(--sky-3) 52%, var(--sky-4) 100%);
  border: 1px solid rgb(var(--accent-rgb) / 0.16);
}
.band__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--s-6);
  align-items: start;
}
.band__grid > .display { max-width: 24ch; }
.band__grid p { color: var(--text-dim); }
.band__grid p + p { margin-top: var(--s-4); }
.band--sky { color: rgb(var(--on-shade-rgb) / 0.92); }
.band--sky .band__grid p { color: rgb(var(--on-shade-rgb) / 0.74); }
.band--sky .micro,
.band--sky .label { color: rgb(var(--on-shade-rgb) / 0.50); }
.band--sky .link,
.band--sky .statement,
.band--sky .pull,
.band--sky .qs li { color: rgb(var(--on-shade-rgb) / 0.92); }
.band--sky .spec b { color: rgb(var(--on-shade-rgb) / 0.74); }

/* A pull quote in the band fills the column the heading used to leave empty. */
@media (min-width: 860px) {
  .band__grid:has(> .pull) {
    grid-template-columns: minmax(18rem, 0.88fr) minmax(0, 1.12fr);
    column-gap: var(--s-8);
    row-gap: var(--s-5);
  }
  .band__grid:has(> .pull) > .display {
    grid-column: 1 / -1;
    max-width: 28ch;
  }
  .band__grid:has(> .pull) > .pull {
    grid-column: 1;
    margin: 0;
    align-self: start;
  }
  .band__grid:has(> .pull) > .ownable { grid-column: 1; }
  .band__grid:has(> .pull) > div {
    grid-column: 2;
    grid-row: 2 / -1;
  }
}

/* Sentences that were buried mid-run, set as the largest thing in the room. */
.pull {
  margin-block: clamp(28px, 4.5vw, 64px);
  max-width: 22ch;
  font-family: var(--font-display);
  font-size: var(--t-h1);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.18;
  color: var(--text);
}
.pull p {
  margin: 0;
  max-width: none;
  color: inherit;
  font: inherit;
  line-height: inherit;
}
.section > .wrap > .pull { max-width: 28ch; }

/* The band sits inside .wrap, so it needs its own inner rhythm. */
.band-wrap { padding-inline: var(--gutter); max-width: var(--max); margin-inline: auto; }

/* --- 13. Services --------------------------------------------------------- */

.buckets { display: grid; gap: 0; }
.bucket {
  border-top: 1px solid var(--rule-soft);
  padding-block: clamp(40px, 6vw, 80px);
  scroll-margin-top: calc(var(--header-h) + var(--s-5));
}
.bucket:last-child { border-bottom: 1px solid var(--rule-soft); }
.bucket__grid {
  display: grid;
  grid-template-columns: 4rem minmax(0, 1fr) minmax(0, 0.62fr);
  gap: var(--s-6) var(--s-7);
  align-items: start;
}
.bucket__num {
  font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: 0.18em;
  padding-top: 0.7em;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.bucket__title { font-family: var(--font-display); font-size: var(--t-h2); font-weight: 600; line-height: 1.1; }
.bucket__desc { margin-top: var(--s-5); color: var(--text-dim); max-width: 68ch; }
.bucket__services { margin-top: var(--s-6); display: flex; flex-wrap: wrap; gap: var(--s-2); }
.bucket__services li {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--s-2) var(--s-4);
  font: 500 0.75rem/1.4 var(--font-ui);
  color: var(--text-dim);
}
@media (max-width: 980px) {
  .bucket__grid { grid-template-columns: 3.5rem minmax(0, 1fr); }
  .bucket__media { grid-column: 2; }
}
@media (max-width: 600px) {
  .bucket__grid { grid-template-columns: 1fr; }
  .bucket__media { grid-column: 1; }
  .bucket__num { padding-top: 0; }
}

/* --- 14. Media placeholders ----------------------------------------------- */

.ph {
  position: relative;
  width: 100%;
  border: 1px dashed var(--rule);
  border-radius: var(--radius-card);
  background: rgb(var(--ink-rgb) / 0.03);
  display: grid;
  place-items: center;
  color: var(--text-faint);
  font: 500 var(--t-micro)/1.4 var(--font-ui);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  text-align: center;
  padding: var(--s-4);
}
.ph--43 { aspect-ratio: 4 / 3; }
.bucket__media .ph { max-width: 420px; margin-left: auto; }
.ph--34 { aspect-ratio: 3 / 4; }

/* --- 15. Team ------------------------------------------------------------- */

.team { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-6); }
.team--few { grid-template-columns: repeat(auto-fit, minmax(200px, 260px)); }
.team__name { margin-top: var(--s-4); font-family: var(--font-display); font-weight: 600; font-size: 1.125rem; }
.team__role { color: var(--text-faint); font-size: 0.875rem; }

/* --- 16. Steps ------------------------------------------------------------ */

.steps { counter-reset: step; display: grid; gap: 0; }
.steps li {
  counter-increment: step;
  display: grid;
  grid-template-columns: 4rem 1fr;
  gap: var(--s-5);
  padding-block: var(--s-6);
  border-top: 1px solid var(--rule-soft);
}
.steps li:last-child { border-bottom: 1px solid var(--rule-soft); }
.steps li::before {
  content: "0" counter(step);
  font: 600 var(--t-micro)/2 var(--font-ui);
  letter-spacing: 0.18em;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.steps h3 { font-family: var(--font-display); font-size: 1.25rem; font-weight: 600; }
.steps p { margin-top: var(--s-2); color: var(--text-dim); max-width: 62ch; }
@media (max-width: 600px) { .steps li { grid-template-columns: 1fr; gap: var(--s-2); } }

/* --- 17. Credential list -------------------------------------------------- */

.creds { display: flex; flex-wrap: wrap; gap: var(--s-2); margin-top: var(--s-5); }
.creds li {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  padding: var(--s-2) var(--s-4);
  font: 500 0.75rem/1.5 var(--font-ui);
  color: var(--text-dim);
}

/* --- 18. Contact ---------------------------------------------------------- */

.contact__grid {
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
  gap: var(--s-8);
  align-items: start;
}
@media (max-width: 859px) { .contact__grid { grid-template-columns: 1fr; gap: var(--s-7); } }

.detail + .detail { margin-top: var(--s-6); }
.detail h2 { margin-bottom: var(--s-2); }
.detail a { font-size: 1.125rem; }

.form {
  --mx: 50%;
  --my: 20%;
  position: relative;
  display: grid;
  gap: var(--s-5);
  isolation: isolate;
}
.field { display: grid; gap: var(--s-2); }
.field > label, .fieldset > legend {
  font: 600 var(--t-label)/1.4 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-faint);
  padding: 0;
}
.field input, .field select, .field textarea {
  width: 100%;
  min-height: 52px;
  padding: var(--s-4);
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.03), transparent 42%),
    var(--ground-2);
  border: 1px solid var(--rule);
  border-radius: 16px;
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 1rem;
  box-shadow:
    inset 0 2px 6px rgb(var(--shade-rgb) / 0.28),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.04);
  transform: translateZ(0);
}
.field textarea { min-height: 150px; resize: vertical; border-radius: 20px; }
.field input:hover, .field select:hover, .field textarea:hover {
  border-color: rgb(var(--ink-rgb) / 0.22);
}
.field input:focus, .field select:focus, .field textarea:focus {
  border-color: var(--accent);
  outline: none;
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.05), transparent 46%),
    var(--ground-3);
  box-shadow:
    0 10px 28px -18px rgb(var(--shade-rgb) / 0.7),
    0 0 0 3px rgb(var(--accent-rgb) / 0.20),
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.08);
  transform: translateY(-1px);
}
.field--filled label { color: var(--text-dim); }
.field--focus label { color: var(--accent); }

.fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: var(--s-3); }
.checks {
  position: relative;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 6px;
  padding: 5px;
  border-radius: 22px;
  background: rgb(var(--shade-rgb) / 0.18);
  box-shadow: inset 0 1px 4px rgb(var(--shade-rgb) / 0.28);
}
.check {
  position: relative;
  z-index: 1;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-height: 48px;
  padding: var(--s-2) var(--s-4);
  border: 1px solid transparent;
  border-radius: var(--radius);
  cursor: pointer;
  font-size: 0.9375rem;
  color: var(--text-dim);
}
.check:hover { color: var(--text); }
.check input { accent-color: var(--accent); width: 16px; height: 16px; min-height: 0; }
.check:has(input:checked) { color: var(--text); }

.field__error {
  display: none;
  align-items: center;
  gap: var(--s-2);
  color: #FF8A80;
  font-size: 0.875rem;
}
.field__error::before {
  content: "!";
  display: grid;
  place-items: center;
  width: 18px; height: 18px;
  flex: none;
  border: 1px solid currentColor;
  border-radius: 50%;
  font-weight: 700;
  font-size: 11px;
  line-height: 1;
}
.field--error .field__error { display: flex; }
.field--error input, .field--error textarea { border-color: #FF8A80; }

.form__status { min-height: 1.5em; font-size: 0.9375rem; color: var(--accent); }
.form__note { font-size: 0.875rem; color: var(--text-faint); }
.form .btn--solid:active {
  transform: translateY(2px);
  box-shadow: inset 0 3px 10px rgb(var(--shade-rgb) / 0.28);
}

/* Inverse contact: dark-grey instruments on the lilac field.
   Page ink is graphite; instruments keep --shade fills and --on-shade-rgb
   copy so one token swap cannot wash the chips to lilac. */
html.is-inverse .grain { opacity: 0.07; }
html.is-inverse .grad {
  background: none;
  color: var(--text);
  -webkit-background-clip: unset;
          background-clip: unset;
}
html.is-inverse ::selection { background: var(--shade); color: var(--ground); }
html.is-inverse .brand,
html.is-inverse .lang,
html.is-inverse .nav-toggle,
html.is-inverse .nav__list {
  background:
    linear-gradient(155deg, rgb(var(--on-shade-rgb) / 0.08), transparent 48%),
    rgb(var(--shade-rgb) / 0.78);
  border-color: rgb(var(--shade-rgb) / 0.55);
  box-shadow:
    0 18px 40px -22px rgb(var(--shade-rgb) / 0.55),
    inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.10);
  color: rgb(var(--on-shade-rgb) / 0.92);
}
html.is-inverse .brand__word,
html.is-inverse .nav__link,
html.is-inverse .lang a { color: rgb(var(--on-shade-rgb) / 0.74); }
html.is-inverse .brand:hover .brand__word,
html.is-inverse .nav__link:hover,
html.is-inverse .nav__link:focus-visible,
html.is-inverse .lang a:hover,
html.is-inverse .lang a:focus-visible { color: rgb(var(--on-shade-rgb) / 1); }
html.is-inverse .nav__link[aria-current="page"] { color: rgb(var(--on-shade-rgb) / 1); }
html.is-inverse .lang a[aria-current] { color: var(--shade); }
html.is-inverse .lang.is-live a[aria-current] { color: var(--shade); }
html.is-inverse .nav-toggle { color: rgb(var(--on-shade-rgb) / 0.88); }
html.is-inverse .btn:hover,
html.is-inverse .btn:focus-visible { border-color: rgb(var(--shade-rgb) / 0.42); }
html.is-inverse .btn--solid {
  background: var(--shade);
  color: var(--ground);
  box-shadow: 0 14px 32px -16px rgb(var(--shade-rgb) / 0.55);
}
html.is-inverse .footer {
  background: var(--shade);
  color: rgb(var(--on-shade-rgb) / 0.78);
  border-top-color: rgb(var(--on-shade-rgb) / 0.08);
}
html.is-inverse .footer h2,
html.is-inverse .footer .micro { color: rgb(var(--on-shade-rgb) / 0.50); }
html.is-inverse .footer a,
html.is-inverse .footer__addr { color: rgb(var(--on-shade-rgb) / 0.74); }
html.is-inverse .footer .brand__word { color: rgb(var(--on-shade-rgb) / 0.92); }
html.is-inverse .cube i {
  border-color: rgb(var(--shade-rgb) / 0.78);
  background: rgb(var(--shade-rgb) / 0.06);
}
html.is-inverse .cube i:nth-child(4),
html.is-inverse .cube i:nth-child(5),
html.is-inverse .cube i:nth-child(6) {
  border-color: rgb(var(--shade-rgb) / 0.38);
}
html.is-inverse .keep::after {
  background: linear-gradient(90deg, transparent, rgb(var(--shade-rgb) / 0.45), transparent);
}
html.is-inverse .detail {
  padding: 18px 20px;
  border-radius: 22px;
  background:
    linear-gradient(160deg, rgb(var(--on-shade-rgb) / 0.06), transparent 46%),
    var(--shade);
  border: 1px solid rgb(var(--shade-rgb) / 0.4);
  box-shadow:
    0 22px 48px -28px rgb(var(--shade-rgb) / 0.55),
    inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.08);
  color: rgb(var(--on-shade-rgb) / 0.82);
}
html.is-inverse .detail + .detail { margin-top: var(--s-4); }
html.is-inverse .detail h2 { color: rgb(var(--on-shade-rgb) / 0.50); }
html.is-inverse .detail a,
html.is-inverse .detail .footer__addr,
html.is-inverse .detail address,
html.is-inverse .detail p { color: rgb(var(--on-shade-rgb) / 0.78); }
.detail .footer__addr { font-size: 1rem; color: var(--text-dim); }
html.is-inverse .detail .link { color: rgb(var(--on-shade-rgb) / 0.92); }
html.is-inverse .form {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 32px;
  background:
    radial-gradient(120% 90% at var(--mx) var(--my), rgb(var(--on-shade-rgb) / 0.08), transparent 42%),
    linear-gradient(165deg, var(--ground-3), var(--shade) 58%, #121417);
  border: 1px solid rgb(var(--on-shade-rgb) / 0.08);
  box-shadow:
    0 40px 80px -36px rgb(var(--shade-rgb) / 0.62),
    inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.12);
  color: rgb(var(--on-shade-rgb) / 0.88);
}
html.is-inverse .form .field > label,
html.is-inverse .form .fieldset > legend { color: rgb(var(--on-shade-rgb) / 0.50); }
html.is-inverse .form .field--filled label,
html.is-inverse .form .field--focus label { color: var(--accent); }
html.is-inverse .form .field input,
html.is-inverse .form .field select,
html.is-inverse .form .field textarea {
  color: rgb(var(--on-shade-rgb) / 0.92);
  background:
    linear-gradient(180deg, rgb(var(--on-shade-rgb) / 0.04), transparent 48%),
    #0F1114;
  border-color: rgb(var(--on-shade-rgb) / 0.10);
}
html.is-inverse .form .field input:hover,
html.is-inverse .form .field select:hover,
html.is-inverse .form .field textarea:hover {
  border-color: rgb(var(--on-shade-rgb) / 0.22);
}
html.is-inverse .form .checks {
  background: rgb(var(--shade-rgb) / 0.35);
}
html.is-inverse .form .check { color: rgb(var(--on-shade-rgb) / 0.74); }
html.is-inverse .form .check:hover,
html.is-inverse .form .check:has(input:checked) { color: rgb(var(--on-shade-rgb) / 1); }
html.is-inverse .form .form__note { color: rgb(var(--on-shade-rgb) / 0.50); }
html.is-inverse .form .btn--solid {
  background: var(--grad);
  color: var(--shade);
}

/* --- 19. 404 -------------------------------------------------------------- */

.notfound {
  position: relative;
  min-height: calc(100vh - var(--header-h) - 160px);
  min-height: calc(100svh - var(--header-h) - 160px);
  display: flex;
  align-items: center;
  padding-block: var(--s-9);
  overflow: hidden;
}
.notfound__mark {
  position: absolute;
  right: -6%;
  top: 50%;
  transform: translateY(-50%);
  width: min(46vw, 520px);
  height: auto;
  opacity: 0.13;
  z-index: 0;
  pointer-events: none;
}
.notfound__inner { position: relative; z-index: 2; }
.notfound__links { margin-top: var(--s-7); display: flex; flex-wrap: wrap; gap: var(--s-3); }
@media (max-width: 859px) { .notfound__mark { opacity: 0.1; right: -20%; } }

/* --- 20. Loader ----------------------------------------------------------- */
/* Injected by JS only — never in the markup, so a JS failure cannot gate the page. */

.loader {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: var(--ground);
}
.loader__stage { position: relative; display: grid; place-items: center; width: min(90vw, 520px); }
.loader__bloom {
  position: absolute;
  width: 420px; height: 420px;
  border-radius: 50%;
  background: radial-gradient(circle, rgb(var(--accent-rgb) / 0.30) 0%, rgb(var(--accent-rgb) / 0.08) 42%, rgb(var(--shade-rgb) / 0) 70%);
  z-index: 1;
}
.loader__mark { position: relative; z-index: 2; width: clamp(76px, 12vw, 128px); }
.loader__read {
  position: relative;
  z-index: 2;
  margin-top: var(--s-8);
  font: 600 var(--t-label)/1 var(--font-ui);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--text-faint);
  font-variant-numeric: tabular-nums;
}
/* A real stopwatch — see loader.js. Tabular figures so it does not jitter
   while it counts. */
.loader__read b {
  font-family: var(--font-mono);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* --- 21. Ticker ----------------------------------------------------------- */
/* Entirely aria-hidden: everything in it is a second copy of the services
   list, which is a real list elsewhere on the page. */

.ticker {
  overflow: hidden;
  padding-block: var(--s-6);
  border-block: 1px solid var(--rule-soft);
}
.ticker__track { display: flex; width: max-content; will-change: transform; }
.ticker__set { display: flex; align-items: center; gap: var(--s-7); padding-right: var(--s-7); }
.ticker__set li {
  display: flex;
  align-items: center;
  gap: var(--s-7);
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(1rem, 2vw, 1.625rem);
  letter-spacing: -0.01em;
  color: var(--text-dim);
}
.ticker__set li::after {
  content: "";
  flex: none;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--grad);
}

/* --- 22. Stats ------------------------------------------------------------ */

.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: var(--s-7); margin-top: var(--s-7); }
.stat { border-top: 2px solid transparent; border-image: var(--grad) 1; padding-top: var(--s-5); }
.stat__num {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(2.5rem, 5vw, 3.75rem);
  line-height: 1;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.stat__unit { font-size: 0.3em; letter-spacing: 0.1em; text-transform: uppercase; margin-left: 0.4em; vertical-align: 0.9em; }
.stat__label { margin-top: var(--s-4); color: var(--text-dim); font-size: 0.875rem; max-width: 32ch; }

/* --- 23. Spec list -------------------------------------------------------- */
/* Two-column rows: the term first (what a scanner looks for), the claim
   in plain English to its right. */

.spec { display: grid; gap: 0; margin-top: var(--s-5); }
.spec li {
  display: grid;
  grid-template-columns: minmax(11rem, 0.4fr) minmax(0, 1fr);
  gap: var(--s-3) var(--s-6);
  align-items: baseline;
  padding-block: var(--s-4);
  border-top: 1px solid var(--rule-soft);
  color: var(--text-dim);
  max-width: none;
}
.spec li:last-child { border-bottom: 1px solid var(--rule-soft); }
.spec b { color: var(--text-dim); font-weight: 400; }
.spec span {
  order: -1;
  font: 650 0.8125rem/1.45 var(--font-ui);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  text-align: left;
  white-space: normal;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
@media (max-width: 600px) {
  .spec li { grid-template-columns: 1fr; gap: var(--s-2); }
}

/* --- 24. Pace line -------------------------------------------------------- */

.bucket__pace {
  display: inline-flex;
  align-items: center;
  gap: var(--s-3);
  margin-top: var(--s-5);
  font: 600 var(--t-micro)/1 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  color: var(--text-faint);
}
.bucket__pace::before { content: ""; width: 22px; height: 2px; border-radius: 2px; background: var(--grad); }

/* --- 26. Drift view ------------------------------------------------------- */

.field-view { display: block; }

.word {
  position: absolute;
  display: block;
  padding: var(--s-2) var(--s-4);
  border-radius: var(--radius);
  background: var(--ground-3);
  box-shadow: 0 2px 14px -6px rgb(var(--shade-rgb) / 0.6);
  font: 500 clamp(0.8125rem, 1.3vw, 1.0625rem)/1.3 var(--font-ui);
  letter-spacing: -0.005em;
  color: var(--text);
  white-space: nowrap;
  will-change: transform;
}
.word:nth-child(4n+2) {
  background: var(--grad);
  color: var(--shade);
  box-shadow: 0 4px 20px -8px var(--accent-glow);
}
.word:hover, .word:focus-visible { box-shadow: 0 6px 24px -8px var(--accent-glow); }

[data-word-field] {
  position: relative;
  height: clamp(360px, 74vh, 600px);
  margin-top: var(--s-6);
}
@media (max-width: 900px), (prefers-reduced-motion: reduce) {
  [data-word-field] {
    position: static;
    height: auto;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 10px;
  }
  [data-word-field] .word {
    position: static !important;
    left: auto !important;
    top: auto !important;
    white-space: normal;
  }
}

/* --- 27. Accent rule ------------------------------------------------------ */
/* A hairline that draws out from under a heading. One element, no layout
   cost, and it is where the accent gradient introduces itself on every page. */

.shot-rule {
  display: block;
  width: min(100%, 560px);
  height: 2px;
  border-radius: 2px;
  margin-top: var(--s-6);
  background: var(--grad);
  transform-origin: left center;
}

/* --- 28. Promises --------------------------------------------------------- */
/* The four-part promise block: Fast / Yours / Independent / Protected. One
   word carries each idea, so the word is set at heading size and the
   explanation stays quiet underneath it. */

/* Six promises in three columns, not six in a ragged five.

   This was `repeat(auto-fit, minmax(210px, 1fr))`, which at desktop width
   resolved to five or six columns — so a six-item list left ONE card alone on
   a second row with four empty columns beside it, and every card was narrow
   enough to break "six-month" across a line with a hyphen. Both problems are
   the same problem: 210px is not a column, it is a gutter with words in it.

   The counts differ per page — 6 on home and /ownership/, 5 on /websites/,
   4 on /branding/ — so the column count is chosen to leave no card stranded:
   three columns fits 6 as 3+3 and 5 as 3+2, and a list of exactly four takes
   a single row of four instead of 3+1. */
.promises {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s-7) var(--s-6);
  margin-top: var(--s-7);
  counter-reset: promise;
}
.promises:has(> :last-child:nth-child(4)) { grid-template-columns: repeat(4, minmax(0, 1fr)); }
@media (max-width: 1099px) {
  .promises,
  .promises:has(> :last-child:nth-child(4)) { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 639px) {
  .promises,
  .promises:has(> :last-child:nth-child(4)) { grid-template-columns: minmax(0, 1fr); }
}
.promise::before {
  content: "";
  display: block;
  width: 40px; height: 2px;
  border-radius: 2px;
  background: var(--grad);
  margin-bottom: var(--s-5);
}
.promise__word {
  font-family: var(--font-display);
  font-size: var(--t-h2);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
}
/* p + p, not a bare `p`: .promise__word is itself a <p>, and `.promise p`
   (0,1,1) would outrank the class rule above (0,1,0) and dim the headword. */
.promise p + p { margin-top: var(--s-3); color: var(--text-dim); }

/* --- 29. Project previews ------------------------------------------------- */
/* Portfolio is the point of the site, so this is the one grid that gets to be
   large. .ph placeholders hold the aspect ratio until real work exists. */

.projects {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  gap: var(--s-9) var(--s-6);
  margin-top: var(--s-7);
}
/* Three across on a desktop wrap. auto-fit + 420px min dropped the third
   card onto its own row and stretched each media slot wider than the
   booklet, which left a dead gutter down the right of every panel. */
.projects--wide {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  justify-items: start;
  align-items: start;
}
.projects--wide .project { width: 100%; }
.projects--wide .project__media,
.projects--wide .book__bar {
  width: 100%;
  max-width: 430px;
}
.projects--wide .book { width: 100%; }
@media (max-width: 1099px) {
  .projects--wide {
    grid-template-columns: 1fr;
    justify-items: start;
  }
}
.project__scope {
  display: block;
  margin-top: var(--s-5);
  font: 600 var(--t-micro)/1.5 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.project__client {
  margin-top: var(--s-2);
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: 600;
  letter-spacing: -0.02em;
}
.project__line { margin-top: var(--s-3); color: var(--text-dim); max-width: 46ch; }
.project__cta {
  display: inline-block;
  margin-top: var(--s-4);
  font: 600 0.8125rem/1 var(--font-ui);
  letter-spacing: 0.06em;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

/* --- 30. Question list ---------------------------------------------------- */
/* The questions a branding project generates that are not design questions.
   Set at body size but in the display face, so they read as things a client
   actually said rather than as body copy. */

.qs { display: grid; gap: var(--s-4); margin-block: var(--s-6); }
.qs li {
  padding-left: var(--s-5);
  border-left: 2px solid var(--rule);
  font-family: var(--font-display);
  font-size: 1.0625rem;
  line-height: 1.5;
  color: var(--text);
}
.qs--accent li { border-left-color: transparent; border-image: var(--grad) 1; }

/* --- 31. Handover strip --------------------------------------------------- */
/* Recurring on every case study. It is the proof of the whole proposition, so
   it is a fixed shape that repeats rather than prose that varies. */

.handover {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--s-3) var(--s-6);
  align-items: baseline;
  margin-top: var(--s-6);
  padding: var(--s-5) var(--s-6);
  border: 1px solid var(--rule);
  border-radius: var(--radius-card);
  background: rgb(var(--ink-rgb) / 0.03);
}
.handover + .handover { margin-top: var(--s-3); }
.handover__label {
  font: 600 var(--t-micro)/1.6 var(--font-ui);
  letter-spacing: var(--track);
  text-transform: uppercase;
  white-space: nowrap;
  background: var(--grad);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.handover__items { color: var(--text-dim); font-size: 0.9375rem; }
@media (max-width: 600px) { .handover { grid-template-columns: 1fr; } }

/* --- 32. Inline code ------------------------------------------------------ */
/* Used sparingly, for the few places the copy names a real file or element
   (llms.txt, h1). Without this it falls back to the browser's monospace at a
   size that does not match the body. */

code {
  font: 500 0.9em/1.5 var(--font-mono);
  color: var(--text);
  background: rgb(var(--ink-rgb) / 0.06);
  border: 1px solid var(--rule-soft);
  border-radius: 5px;
  padding: 0.08em 0.38em;
}

/* --- 33. Header states ---------------------------------------------------- */
/* Added by scroll.js. The header starts transparent over the hero, takes a
   ground once you have left it, and tucks away while you are reading
   downward. It returns the moment you scroll up — a header you have to hunt
   for is worse than one that never moved. */

/* The promotion hint for the tuck — but ONLY above the breakpoint.

   `will-change: transform` makes an element a containing block for
   `position: fixed` descendants, exactly as `backdrop-filter` does. That is
   the same trap section 7 already avoids by putting the header's blur on a
   pseudo-element rather than on .header itself, and this rule walked straight
   back into it: below 760px the nav is a fixed full-screen panel INSIDE the
   header, so it resolved its `inset: 72px 0 0 0` against the header's own
   88px box and came out 40px tall with its links pushed off the top of the
   screen. The menu opened onto nothing.

   Above 1100px there is no fixed panel in there, so the hint is free. */
@media (min-width: 1100px) {
  .header { will-change: transform; }
}

/* The header is a cluster of glass chips now, not a slab. Scroll.js
   toggles `.is-solid`; `.is-tucked` is no longer applied. The chips
   carry their own ground, so the pseudos stay empty. */
.has-scrollstate .header::before { opacity: 0; }
.has-scrollstate .header.is-solid::before { opacity: 1; }
.has-scrollstate .header.is-solid { border-bottom: none; }
.has-scrollstate .header::after {
  content: none;
}
.header.is-tucked { transform: none; }

/* The scroll progress line. A 2px read of how far down the page you are.
   On long pages it shares the header with .pindex: this line at the top,
   the section map along the bottom. scaleX only — no width, no layout. */
.progress {
  position: absolute;
  left: 0; right: 0;
  top: 0;
  height: 2px;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: var(--grad);
  pointer-events: none;
  z-index: 2;
}

/* --- 34. Split heading lines ---------------------------------------------- */
/* main.js splits display headings on their authored <br>. Each line rises out
   from behind its own mask. The padding is not decorative: overflow:hidden on
   a tight line box clips descenders and the gradient text, so the box is
   opened up and the space taken back with a negative margin. */

.display.is-split .ln {
  display: block;
  overflow: hidden;
  padding-bottom: 0.14em;
  margin-bottom: -0.14em;
}
.display.is-split .ln__i { display: block; }

/* --- 35. Card tilt -------------------------------------------------------- */
/* The project media turns to face the cursor (tactile.js) and carries a light
   that follows it across the surface. --mx / --my are written per frame by
   the pointer loop; everything else is static. */

.project { perspective: 900px; }
.project__media {
  position: relative;
  transform-style: preserve-3d;
  border-radius: var(--radius-card);
  overflow: hidden;
}
.project__media::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle at var(--mx, 50%) var(--my, 50%),
              rgb(var(--accent-rgb) / 0.20), rgb(var(--accent-rgb) / 0.05) 38%, transparent 68%);
}
.project.is-tilting .project__media::after { opacity: 1; }
.project.is-tilting .project__media { box-shadow: 0 26px 60px -30px rgb(var(--shade-rgb) / 0.85); }

/* --- 36. Surface hovers --------------------------------------------------- */
/* Small, and everywhere the eye lands while scanning. Each one is a single
   transform or colour change; none of them costs layout. */

.promise:hover .promise__word { background: var(--grad); -webkit-background-clip: text; background-clip: text; color: transparent; }
.promise::before { transform-origin: 0 50%; }
.promise:hover::before { transform: scaleX(1.9); }

.creds li:hover { border-color: rgb(var(--ink-rgb) / 0.34); transform: translateY(-2px); }
.qs li:hover { border-left-color: var(--accent); }
.bucket__grid { border-radius: var(--radius-card); }
.bucket:hover .bucket__num { transform: translateY(-2px); }

/* The accent underline on inline links wipes in from the left instead of
   simply changing colour. */
.link { background-size: 0% 1px; }
.link:hover, .link:focus-visible { background-size: 100% 1px; }

/* --- 37. Spatial experience layer ---------------------------------------- */

/* The page now has a quiet world behind it. The canvas is injected only when
   the enhancement is available; all real content remains above it. */
.atmosphere {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  opacity: 0.48;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
          mask-image: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
}

.cursor-aura {
  position: fixed;
  left: -180px;
  top: -180px;
  z-index: 1;
  width: 360px;
  aspect-ratio: 1;
  border-radius: 50%;
  pointer-events: none;
  opacity: 0;
  background: radial-gradient(circle,
    rgb(var(--accent-rgb) / 0.075), rgb(var(--accent-2-rgb) / 0.025) 38%, transparent 70%);
  mix-blend-mode: screen;
  transform-origin: 50% 50%;
}
.cursor-aura.is-on { opacity: 1; }

/* From tablet up the header is a cluster of glass chips, not one grey bar.
   The full-bleed ::before scrim stays on phones only — it would redraw the
   sausage we just took off. */
@media (min-width: 760px) {
  .header { height: calc(var(--header-h) + 16px); padding-top: 10px; }
  .header::before { content: none; }
  .has-scrollstate .header.is-solid { border-bottom: none; }
  .has-scrollstate .header::after { display: none; }
  .header__inner { height: calc(100% - 16px); }
  .main { padding-top: calc(var(--header-h) + 16px); }
}

/* Desktop row: one glass rail, one travelling pill. Every link is the same
   height so the pill lands on the word you are on, not beside it. */
@media (min-width: 1100px) {
  .header__inner { gap: 12px; }
  .header__inner > .nav { margin-left: auto; }
  .nav { gap: 12px; }
  .nav__list {
    align-items: stretch;
    gap: 2px;
    height: 44px;
    padding: 4px;
    border: 1px solid rgb(var(--accent-rgb) / 0.28);
    border-radius: 999px;
    background:
      linear-gradient(155deg, rgb(var(--accent-rgb) / 0.14), transparent 50%),
      rgba(var(--ground-rgb) / 0.55);
    -webkit-backdrop-filter: blur(8px) saturate(120%);
            backdrop-filter: blur(8px) saturate(120%);
    box-shadow:
      0 16px 40px -24px rgb(var(--shade-rgb) / 0.8),
      0 0 24px -12px rgb(var(--accent-rgb) / 0.22),
      inset 0 1px 0 rgb(var(--ink-rgb) / 0.12);
  }
  .nav__list li { display: flex; }
  .nav__link {
    display: flex;
    align-items: center;
    height: 100%;
    padding: 0 0.95em;
    border-radius: 999px;
    line-height: 1;
    letter-spacing: 0;
    -webkit-tap-highlight-color: transparent;
  }
  .nav__link:hover,
  .nav__link:focus-visible { color: var(--text); }
  .nav__link[aria-current="page"] { color: var(--accent); }
  .nav__marker {
    top: 3px;
    bottom: 3px;
    height: auto;
    border-radius: 999px;
    background: rgb(var(--accent-rgb) / 0.16);
    box-shadow: inset 0 0 0 1px rgb(var(--accent-rgb) / 0.34);
  }
  .lang {
    height: 44px;
    align-items: stretch;
    padding: 4px;
  }
  .lang a {
    min-height: 0;
    height: 100%;
  }
}

/* Hero copy sits on a very faint optical plane. The warp itself remains
   untouched and readable through it. */
.hero__inner::before {
  content: "";
  position: absolute;
  inset: -48px -64px;
  z-index: -1;
  width: min(760px, calc(100vw - (var(--gutter) * 2)));
  border-radius: 54px;
  background: radial-gradient(ellipse at 28% 50%, rgb(var(--shade-rgb) / 0.62), rgb(var(--shade-rgb) / 0.16) 58%, transparent 76%);
  filter: blur(3px);
  pointer-events: none;
}

.page-head {
  min-height: min(58vh, 620px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
}
.page-head::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: min(62vw, 760px);
  aspect-ratio: 1;
  right: -10%;
  top: 50%;
  transform: translateY(-50%);
  border-radius: 50%;
  background:
    repeating-radial-gradient(circle at 50%, transparent 0 28px, rgb(var(--accent-rgb) / 0.055) 29px 30px),
    radial-gradient(circle, rgb(var(--sky-3-rgb) / 0.34), rgb(var(--sky-2-rgb) / 0.08) 52%, transparent 72%);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 44%);
          mask-image: linear-gradient(90deg, transparent, #000 44%);
  animation: page-orbit 28s linear infinite;
}

/* Reframe repeated content as objects with edges, depth and local light. */
.promises { gap: clamp(14px, 1.8vw, 28px); }
.promise,
.stat,
.team > li,
.detail {
  position: relative;
  padding: clamp(22px, 2.5vw, 36px);
  border: 1px solid var(--rule-soft);
  border-radius: var(--radius-card);
  background:
    radial-gradient(circle at var(--light-x, 12%) var(--light-y, 8%), rgb(var(--accent-rgb) / 0.10), transparent 42%),
    linear-gradient(145deg, var(--surface), rgb(var(--ink-rgb) / 0.012));
  box-shadow: 0 24px 70px -50px rgb(var(--shade-rgb) / 0.96), inset 0 1px 0 rgb(var(--ink-rgb) / 0.04);
  overflow: hidden;
}
.promise::after,
.stat::after,
.team > li::after,
.detail::after,
.bucket__grid::after,
.handover::after,
.qs > li::after {
  content: "";
  position: absolute;
  inset: -1px;
  z-index: -1;
  pointer-events: none;
  border-radius: inherit;
  opacity: 0;
  background: radial-gradient(circle at var(--light-x, 50%) var(--light-y, 50%), rgb(var(--accent-rgb) / 0.17), transparent 38%);
}
.promise::before { margin-bottom: var(--s-6); }
.stat { border-top: 1px solid var(--rule-soft); padding-top: clamp(22px, 2.5vw, 36px); }
.team > li { min-width: 0; }

.bucket { border: 0; padding-block: clamp(16px, 2vw, 28px); }
.bucket:last-child { border-bottom: 0; }
.bucket__grid {
  position: relative;
  isolation: isolate;
  padding: clamp(26px, 4vw, 58px);
  border: 1px solid var(--rule-soft);
  background:
    radial-gradient(circle at var(--light-x, 85%) var(--light-y, 12%), rgb(var(--accent-rgb) / 0.10), transparent 36%),
    linear-gradient(135deg, rgb(var(--ink-rgb) / 0.048), rgb(var(--ink-rgb) / 0.01));
  box-shadow: var(--shadow-deep), inset 0 1px 0 rgb(var(--ink-rgb) / 0.045);
  overflow: hidden;
}
.bucket__num { position: relative; z-index: 2; }
.bucket__num::after {
  content: "";
  display: block;
  width: 1px;
  height: clamp(52px, 8vw, 110px);
  margin: 18px auto 0;
  background: linear-gradient(var(--accent), transparent);
  opacity: 0.5;
}

.handover {
  position: relative;
  isolation: isolate;
  background:
    radial-gradient(circle at var(--light-x, 12%) var(--light-y, 0%), rgb(var(--accent-rgb) / 0.11), transparent 44%),
    rgb(var(--ink-rgb) / 0.03);
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.035);
}

.qs { gap: var(--s-3); }
.qs > li {
  position: relative;
  isolation: isolate;
  padding: 16px 20px;
  border: 1px solid var(--rule-soft);
  border-left: 2px solid var(--rule);
  border-radius: 0 16px 16px 0;
  background:
    radial-gradient(circle at var(--light-x, 0%) var(--light-y, 50%), rgb(var(--accent-rgb) / 0.10), transparent 42%),
    rgb(var(--ink-rgb) / 0.018);
}
.qs--accent > li { border-image: none; border-left-color: var(--accent); }

.creds { gap: var(--s-3); }
.creds li {
  background: linear-gradient(145deg, rgb(var(--ink-rgb) / 0.045), rgb(var(--ink-rgb) / 0.012));
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.035);
}

/* Placeholder art becomes a living, deliberately abstract canvas while it
   still says exactly what asset belongs there. */
.ph {
  isolation: isolate;
  overflow: hidden;
  border-style: solid;
  border-color: rgb(var(--accent-rgb) / 0.16);
  background:
    linear-gradient(125deg, rgb(var(--ink-rgb) / 0.06), transparent 28%),
    radial-gradient(circle at 72% 28%, rgb(var(--accent-rgb) / 0.33), transparent 18%),
    radial-gradient(circle at 36% 72%, rgb(var(--accent-2-rgb) / 0.28), transparent 26%),
    repeating-linear-gradient(122deg, rgb(var(--ink-rgb) / 0.035) 0 1px, transparent 1px 18px),
    #1d1929;
  color: rgb(var(--ink-rgb) / 0.62);
  text-shadow: 0 1px 12px rgb(var(--shade-rgb) / 0.7);
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.08), inset 0 -80px 120px -70px rgb(var(--shade-rgb) / 0.8);
}
.ph::before {
  content: "";
  position: absolute;
  z-index: -1;
  width: 70%;
  aspect-ratio: 1;
  border-radius: 38% 62% 52% 48%;
  background: conic-gradient(from 40deg, transparent, rgb(var(--accent-rgb) / 0.38), rgb(var(--accent-2-rgb) / 0.08), transparent 72%);
  filter: blur(1px);
  animation: artifact-drift 18s var(--e-io) infinite alternate;
}

.project__media {
  isolation: isolate;
  box-shadow: 0 28px 80px -48px rgb(var(--shade-rgb) / 0.94);
}
.project__media::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  border-radius: inherit;
  border: 1px solid rgb(var(--ink-rgb) / 0.09);
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.07);
}

/* Lists should respond like navigation, not tables. */
.index { border-top: 0; display: grid; gap: var(--s-3); }
.index__item { border: 0; perspective: 1000px; }
.index__link {
  position: relative;
  padding: clamp(20px, 2.5vw, 34px);
  border: 1px solid var(--rule-soft);
  border-radius: 18px;
  background: linear-gradient(105deg, rgb(var(--ink-rgb) / 0.03), rgb(var(--ink-rgb) / 0.008));
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.025);
}
.index__link::after {
  content: "→";
  position: absolute;
  right: 24px;
  top: 50%;
  color: var(--accent);
  opacity: 0;
  transform: translate(-14px, -50%);
}
.index__link:hover .index__meta,
.index__link:focus-visible .index__meta { transform: translateX(-34px); }
.index__link:hover::after,
.index__link:focus-visible::after { opacity: 1; transform: translate(0, -50%); }

/* The footer closes like a substantial object, rather than a final rule. */
.footer {
  margin: clamp(12px, 2vw, 28px);
  border: 1px solid var(--rule-soft);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 4%, rgb(var(--accent-rgb) / 0.09), transparent 28%),
    linear-gradient(145deg, rgb(var(--ink-rgb) / 0.035), rgb(var(--ink-rgb) / 0.01)),
    var(--ground);
  box-shadow: var(--shadow-deep), inset 0 1px 0 rgb(var(--ink-rgb) / 0.045);
  overflow: hidden;
}

/* Opt-in soundtrack control. It remains a compact object on every route and
   exposes state in text as well as motion. */
.sound-control {
  position: fixed;
  right: clamp(16px, 2vw, 28px);
  bottom: max(clamp(16px, 2vw, 28px), env(safe-area-inset-bottom));
  z-index: 120;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  min-height: 54px;
  padding: 7px 16px 7px 8px;
  border: 1px solid rgb(var(--on-shade-rgb) / 0.13);
  border-radius: var(--radius);
  background: rgb(var(--shade-rgb) / 0.76);
  -webkit-backdrop-filter: blur(8px) saturate(115%);
          backdrop-filter: blur(8px) saturate(115%);
  box-shadow: 0 20px 54px -24px rgb(var(--shade-rgb) / 0.92), inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.08);
  color: var(--text);
  cursor: pointer;
}
.sound-control__orb {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 39px;
  height: 39px;
  border-radius: 50%;
  background: linear-gradient(145deg, rgb(var(--accent-rgb) / 0.22), rgb(var(--accent-2-rgb) / 0.08));
  border: 1px solid rgb(var(--accent-rgb) / 0.20);
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.10);
}
.sound-control__orb span {
  width: 2px;
  height: 5px;
  border-radius: 2px;
  background: var(--accent);
  transform-origin: 50% 50%;
}
.sound-control__copy { display: grid; gap: 2px; text-align: left; }
.sound-control__copy b {
  font: 600 0.67rem/1 var(--font-ui);
  letter-spacing: 0.13em;
  text-transform: uppercase;
}
.sound-control__copy small {
  font: 500 0.58rem/1 var(--font-ui);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint);
}
.sound-control.is-playing { border-color: rgb(var(--accent-rgb) / 0.34); }
.sound-control.is-playing .sound-control__orb { box-shadow: 0 0 26px rgb(var(--accent-rgb) / 0.18), inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.12); }
.sound-control.is-playing .sound-control__orb span { animation: sound-meter 820ms var(--e-io) infinite alternate; }
.sound-control.is-playing .sound-control__orb span:nth-child(2) { animation-delay: -240ms; }
.sound-control.is-playing .sound-control__orb span:nth-child(3) { animation-delay: -520ms; }
.sound-control.is-playing .sound-control__orb span:nth-child(4) { animation-delay: -110ms; }


/* Install control — balanced against Sound on the opposite edge. */
.install-control {
  position: fixed;
  left: clamp(16px, 2vw, 28px);
  bottom: max(clamp(16px, 2vw, 28px), env(safe-area-inset-bottom));
  z-index: 120;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  min-height: 54px;
  padding: 7px 17px 7px 8px;
  border: 1px solid rgb(var(--on-shade-rgb) / 0.13);
  border-radius: var(--radius);
  background: rgb(var(--shade-rgb) / 0.76);
  -webkit-backdrop-filter: blur(8px) saturate(115%);
          backdrop-filter: blur(8px) saturate(115%);
  box-shadow: 0 20px 54px -24px rgb(var(--shade-rgb) / 0.92), inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.08);
  color: var(--text);
  font: 600 0.67rem/1 var(--font-ui);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  cursor: pointer;
}
.install-control__icon {
  display: grid;
  place-items: center;
  width: 39px;
  height: 39px;
  border-radius: 50%;
  border: 1px solid rgb(var(--accent-rgb) / 0.20);
  background: linear-gradient(145deg, rgb(var(--accent-rgb) / 0.22), rgb(var(--accent-2-rgb) / 0.08));
  color: var(--accent);
  font: 400 1.25rem/1 var(--font-ui);
  box-shadow: inset 0 1px 0 rgb(var(--ink-rgb) / 0.10);
}
.install-control.is-ready {
  border-color: rgb(var(--accent-rgb) / 0.38);
  box-shadow: 0 20px 54px -24px rgb(var(--shade-rgb) / 0.92), 0 0 28px rgb(var(--accent-rgb) / 0.10), inset 0 1px 0 rgb(var(--ink-rgb) / 0.08);
}
.install-control.is-installed .install-control__icon { color: var(--shade); background: var(--grad); }
.install-help {
  position: fixed;
  left: clamp(16px, 2vw, 28px);
  bottom: calc(max(clamp(16px, 2vw, 28px), env(safe-area-inset-bottom)) + 66px);
  z-index: 121;
  width: min(310px, calc(100vw - 32px));
  padding: 14px 16px;
  border: 1px solid rgb(var(--accent-rgb) / 0.20);
  border-radius: 16px;
  background: rgb(var(--shade-rgb) / 0.92);
  -webkit-backdrop-filter: blur(8px);
          backdrop-filter: blur(8px);
  box-shadow: 0 22px 62px -28px rgb(var(--shade-rgb) / 0.96), inset 0 1px 0 rgb(var(--on-shade-rgb) / 0.05);
  color: rgb(var(--on-shade-rgb) / 0.74);
  font-size: 0.78rem;
  line-height: 1.55;
  opacity: 0;
  visibility: hidden;
  transform: translateY(8px);
}
.install-help.is-visible { opacity: 1; visibility: visible; transform: none; }

/* Surface transforms are applied only to pointer-capable devices and only
   after the JavaScript enhancement marks the element. */
.depth-surface {
  transform-style: preserve-3d;
  transform-origin: 50% 50%;
  will-change: transform;
}
.depth-surface.is-depth-active {
  transform: perspective(1100px) rotateX(var(--depth-rx, 0deg)) rotateY(var(--depth-ry, 0deg)) translateZ(8px);
  border-color: rgb(var(--accent-rgb) / 0.18);
  box-shadow: 0 34px 90px -48px rgb(var(--shade-rgb) / 0.95), inset 0 1px 0 rgb(var(--ink-rgb) / 0.07);
}
.depth-surface.is-depth-active::after { opacity: 1; }

/* --- Page transitions ----------------------------------------------------
   route.js swaps <main> in place. The page leaves the way the hero's drive
   jumps — accelerating away into perspective rather than fading — and the
   next one arrives from the other side of the same move.

   Only <main> moves. The header, the nav overlay, the footer and the grain
   are not part of the page being replaced and must not flinch, or the whole
   illusion that you stayed in one room collapses.

   perspective is on the transform itself rather than on a parent, because
   .main's parent is <body> and putting a perspective there would drag every
   fixed control into the same 3D context. */

.main {
  transform-origin: 50% 34%;
  will-change: transform, opacity, filter;
}
html.is-warping-out .main {
  transform: perspective(1400px) translateZ(-280px) scale(0.96);
  opacity: 0;
  filter: none;
  transition: transform 280ms cubic-bezier(0.55, 0, 0.85, 0.35),
              opacity 280ms ease-in;
}
html.is-warping-in .main {
  animation: page-arrive 360ms var(--e-out) both;
}
@keyframes page-arrive {
  from { transform: perspective(1400px) translateZ(160px) scale(1.02); opacity: 0; filter: none; }
  to   { transform: none; opacity: 1; filter: none; }
}

/* The View Transition API, where it exists, does the same move at the
   compositor. Naming only <main> keeps the header and the overlay out of
   the snapshot, exactly as above. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) { animation-duration: 300ms; }
  ::view-transition-new(root) { animation-duration: 420ms; }
}

@keyframes page-orbit { to { transform: translateY(-50%) rotate(360deg); } }
@keyframes artifact-drift {
  from { transform: translate3d(-20%, -14%, 0) rotate(-18deg) scale(0.88); }
  to { transform: translate3d(24%, 18%, 0) rotate(32deg) scale(1.18); }
}
@keyframes sound-meter {
  0% { transform: scaleY(0.65); }
  100% { transform: scaleY(3.2); }
}

@media (max-width: 720px) {
  .page-head:not(.page-hero) { min-height: min(52vh, 520px); }
  .page-head::before { width: 110vw; right: -52%; }
  .footer { margin: 8px; border-radius: 24px; }
  .sound-control { right: 12px; bottom: max(12px, env(safe-area-inset-bottom)); padding-right: 11px; }
  .sound-control__copy b { display: none; }
  .install-control { left: 12px; bottom: max(12px, env(safe-area-inset-bottom)); padding-right: 12px; }
  .install-control > span:last-child { max-width: 76px; line-height: 1.2; text-align: left; }
  .install-help { left: 12px; bottom: calc(max(12px, env(safe-area-inset-bottom)) + 66px); }
  .bucket__num::after { display: none; }
  .index__link::after { display: none; }
  .index__link:hover .index__meta,
  .index__link:focus-visible .index__meta { transform: none; }
}


/* --- 38. The navigation overlay ------------------------------------------ */
/* nav.js MOVES the real <nav id="site-nav"> in here rather than copying it,
   so everything below restyles the same six links the header has always had.
   With JavaScript off none of these rules apply, .has-navx is never set, and
   section 7's header row is what you get. */

/* The trigger is mobile-only again — section 7's max-width query is what
   shows it. It was forced visible at every width, which hid six labelled
   links behind one icon on a desktop with room to spare. See nav.js. */

/* The whole overlay is confined to the widths where a full-screen panel is
   the right answer. Above 760px it is display:none and the header carries its
   ordinary row of links. Keep this breakpoint in step with section 7's
   @media (max-width: 759px) block and with nav.js. */
@media (min-width: 1100px) { .navx { display: none !important; } }

.navx {
  position: fixed;
  inset: 0;
  /* Above .main and .footer (2), below .header (90) so the trigger stays
     clickable as the close control, and far below .grain (400), which is
     meant to lie over everything including this. */
  z-index: 80;
  visibility: hidden;
  opacity: 0;
}
html.navx-open .navx { visibility: visible; opacity: 1; }

.navx__sky { display: none; }

/* A fade, not a flying wall. The 3D curtain plus a canvas sky is what made
   the menu skip on a phone. */
.navx__curtain {
  position: absolute;
  inset: 0;
  background:
    radial-gradient(70% 50% at 12% 22%, rgb(var(--sky-3-rgb) / 0.42), transparent 68%),
    var(--ground);
  opacity: 0;
}
html.navx-open .navx__curtain { opacity: 1; }

/* Below the breakpoint the header's own .nav IS the panel — section 7 already
   makes it a fixed full-screen sheet, and these rules stage what is inside it
   over the curtain and starfield behind. The nav element is never moved: it is
   a row above 1100px and a panel below, which is the same element either way.

   Everything from here to the end of the staging is inside the query. Above
   it, section 7's row rules are untouched. */
@media (max-width: 1099px) {

.nav {
  z-index: 89;                 /* above .navx (80), below .header (90) */
  background-color: var(--ground);
  background-image: radial-gradient(70% 50% at 12% 22%, rgb(var(--sky-3-rgb) / 0.38), transparent 68%);
  justify-content: center;
  padding-bottom: calc(var(--gutter) + env(safe-area-inset-bottom, 0px));
}
.nav__list {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  width: min(100%, 22rem);
}

/* Resting state is present. Arrival is a short rise — transform only — so a
   stalled animation still leaves every link readable. */
.nav__list li { opacity: 1; }
body.nav-open .nav__list li {
  animation: nav-item-in 420ms var(--e-out) var(--delay, 0ms);
}

.nav__link {
  display: flex;
  align-items: center;
  min-height: 52px;
  padding: 0 2px;
  font-family: var(--font-display);
  font-size: clamp(2rem, 9vw, 3rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--text);
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}
.nav__link::before {
  content: "";
  width: 7px;
  height: 7px;
  margin-right: 0.55em;
  border-radius: 50%;
  background: rgb(var(--accent-rgb) / 0.35);
  box-shadow: 0 0 0 0 rgb(var(--accent-rgb) / 0);
  flex: none;
}
.nav__list li.is-here .nav__link::before {
  background: var(--accent);
  box-shadow: 0 0 12px rgb(var(--accent-rgb) / 0.7);
}
.nav__link::after { display: none; }
.nav__marker { display: none; }
.nav__link:hover,
.nav__link:focus-visible { color: var(--accent); }
.nav__list li.is-here .nav__link { color: var(--accent); }

.nav__email {
  display: block;
  margin-top: var(--s-7);
  font-size: 0.9375rem;
  color: var(--text-dim);
}

}  /* end @media (max-width: 1099px) — the overlay's whole staging */


/* The curtain covers the page. Filtering and scaling <main> is what made
   the overlay hitch on a phone — leave the document still. */
html.navx-open .main,
html.navx-open .footer { pointer-events: none; }
/* The two fixed controls are not part of the menu and must not float over
   the curtain that just covered their page. */
html.navx-open .sound-control,
html.navx-open .install-control,
html.navx-open .install-help { opacity: 0; pointer-events: none; }

/* --- The trigger ---------------------------------------------------------
   The mark itself, at every width. It leans and stretches towards an
   approaching cursor — the same roughly-volume-preserving stretch the
   branded cursor and the warp's stars use — and inverts when it becomes the
   close control. */

/* Mark AND word, in a pill that grows to hold both.

   It was a fixed 46x46 circle with `overflow: hidden`, built for a control
   with no text in it. Putting the word back inside that box clipped it to
   "Clo" — so the shape follows the content now: auto width, the pill radius
   section 7 already gives .nav-toggle, and the 44px minimum height this site
   holds itself to for touch targets. */
.navx-trigger {
  position: relative;
  gap: var(--s-2);
  padding: var(--s-2) var(--s-4);
  width: auto;
  min-height: 44px;
  justify-content: center;
}
@media (max-width: 1099px) {
  .navx-trigger { padding: 6px 10px; }
}
.navx-trigger:hover,
.navx-trigger:focus-visible { border-color: rgb(var(--accent-rgb) / 0.55); }
.navx-trigger__mark { display: none; }
/* Open: the control inverts — the ground fills, the mark and the word are cut
   out of it — and the mark turns to face the other way, which is what makes
   one control read as two states rather than as a button whose label
   changed. */
html.navx-open .navx-trigger {
  background: var(--grad);
  border-color: transparent;
  color: var(--shade);
}
html.navx-open .navx-trigger__mark {
  background-image: none;
  background-color: var(--shade);
  transform: rotate(180deg) scale(0.92);
}

/* --- The page index ------------------------------------------------------
   One segment per <section>, filling as you pass it and clickable to travel
   to it. It replaces the progress line rather than sitting beside it.

   The visible bar is 3px, matching the line it replaces, but each button is
   20px tall so it is not a hairline to hit. That is under the 44px this site
   holds itself to elsewhere, and it is a deliberate trade rather than an
   oversight: every section this points at is reachable by simply scrolling,
   so the index is a shortcut to something already available rather than the
   only route to it. */

.pindex {
  position: absolute;
  left: 0; right: 0;
  bottom: -1px;
  display: flex;
  gap: 2px;
  padding: 0;
  height: 20px;
  align-items: flex-end;
  pointer-events: auto;
}
.pindex__seg {
  flex: 1 1 0;
  position: relative;
  height: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
.pindex__seg::before {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: rgb(var(--accent-rgb) / 0.13);
  transition: height 200ms var(--e-out), background-color 200ms var(--e-out);
}
.pindex__seg:hover::before,
.pindex__seg:focus-visible::before { height: 6px; background: rgb(var(--accent-rgb) / 0.3); }
.pindex__seg.is-at::before { background: rgb(var(--accent-rgb) / 0.24); }
.pindex__fill {
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 3px;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left;
  transition: height 200ms var(--e-out);
}
.pindex__seg:hover .pindex__fill,
.pindex__seg:focus-visible .pindex__fill,
.pindex__seg.is-at .pindex__fill { height: 6px; }
.pindex__seg:focus-visible { outline: 2px solid var(--accent); outline-offset: -4px; }

.page-hero__pace {
  margin-top: var(--s-4);
}

/* Found-problem notes on /about/. JS fans them from a pile; without it
   they already read as a stack of slightly skewed cards. */
.qs--found li {
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.04), transparent 42%),
    var(--ground-2);
  box-shadow: 0 16px 36px -24px rgb(var(--shade-rgb) / 0.55);
}
.qs--found li:nth-child(odd) { --r: -0.8deg; transform: rotate(var(--r)); }
.qs--found li:nth-child(even) { --r: 0.7deg; transform: rotate(var(--r)); margin-left: 10px; }
.qs--found.is-live li {
  animation: found-in 720ms var(--e-soft) calc(var(--i, 0) * 80ms) both;
}

/* Ownership handover list, as cards that deal. */
.creds--deal {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(14rem, 1fr));
  gap: var(--s-3);
}
.creds--deal li {
  min-height: 4.25rem;
  display: flex;
  align-items: center;
  padding: var(--s-4) var(--s-5);
  border-radius: 16px;
  font-size: 0.875rem;
  line-height: 1.35;
  color: var(--text);
}
.creds--deal.is-live li {
  animation: deal-in 560ms var(--e-soft) calc(var(--i, 0) * 55ms) both;
}


/* --- 39. The page as a stage ---------------------------------------------
   depth.js puts every <section> on a shallow Z that answers to how hard the
   page is being scrolled, and a lean towards the cursor. The hero keeps its
   own stage and is excluded — two depth systems on one element would fight.

   perspective sits on the section rather than on a shared parent, so each
   one is its own small stage. A single perspective over the whole document
   would put the sections near the bottom of a long page at an absurd viewing
   angle, because they are thousands of pixels from the vanishing point. */

.stage-layer {
  transform: perspective(1600px)
             translateZ(var(--sz, 0px))
             rotateX(var(--sx, 0deg))
             rotateY(var(--sy, 0deg));
  transform-style: preserve-3d;
  will-change: transform;
}

/* --- 40. The ticker as a band on a cylinder ------------------------------
   depth.js places each word on the surface of a 620px cylinder and rolls the
   band with scroll momentum. The horizontal travel is unchanged — scroll.js
   still drives it, and .is-live is still what switches the CSS marquee off.

   The container needs the perspective and the track needs preserve-3d, or
   the per-word translateZ flattens to nothing. */

.ticker.is-cylinder { perspective: 900px; perspective-origin: 50% 50%; }
.ticker.is-cylinder.is-live .ticker__track {
  transform-style: preserve-3d;
  /* The roll replaces the flat band's skew rather than joining it: a skew and
     a rotation on the same strip read as a mistake, not as two effects. */
  transform: translate3d(var(--tx, 0px), 0, 0) rotateX(var(--roll, 0deg));
}
.ticker.is-cylinder .ticker__set { transform-style: preserve-3d; }
.ticker.is-cylinder .ticker__set li {
  transform-style: preserve-3d;
  backface-visibility: hidden;
  will-change: transform, opacity;
}

/* --- 41. Lit surfaces with thickness -------------------------------------
   tactile.js now computes a real surface normal and a Lambert term against
   one fixed light, and writes three values: --lit (1 at rest, above 1 turned
   towards the lamp, below turned away), and --shadow-x / --shadow-y, the
   offset that light casts.

   The point of doing it properly is that the three cues agree. Turn a card
   towards the light and it brightens, its top edge catches, and its shadow
   shortens; turn it away and all three reverse together. Before, the
   highlight sat under the cursor at a constant strength and the shadow never
   moved at all, which is why these read as flat panels with a gradient on
   them rather than as objects.

   The edge is a 1px inset highlight along the top and a darker one along the
   bottom, both scaled by --lit. That pair is what gives a panel thickness:
   a lit top edge and a shaded bottom edge is how the eye reads a raised
   surface, and it costs one box-shadow. */

.depth-surface.is-depth-active {
  box-shadow:
    /* the shadow this element's own light casts */
    var(--shadow-x, 0px) calc(var(--shadow-y, 26px) * -1) calc(58px * var(--lit, 1))
      calc(-22px * var(--lit, 1)) rgb(var(--shade-rgb) / 0.92),
    /* thickness: lit top edge, shaded bottom edge */
    inset 0 1px 0 rgb(var(--ink-rgb) / calc(0.10 * var(--lit, 1))),
    inset 0 -1px 0 rgb(var(--shade-rgb) / calc(0.34 / var(--lit, 1)));
}
/* The moving highlight, now scaled by how much light the surface is actually
   receiving rather than drawn at full strength wherever the cursor is. */
.depth-surface.is-depth-active::after {
  opacity: calc(0.55 * var(--lit, 1));
}


/* --- 42. Set pieces: home ------------------------------------------------ */

/* The buckets as three physical panels. The stack gets the perspective; each
   panel moves inside it, so the one nearest the viewer foreshortens most and
   the geometry does the work a hand-tuned scale would fake. */
.buckets--staged { perspective: 1500px; perspective-origin: 50% 46%; }
.buckets--staged .bucket {
  transform: translateZ(var(--bz, 0px));
  transform-style: preserve-3d;
  transition: transform 620ms var(--e-out), opacity 480ms var(--e-out),
              filter 480ms var(--e-out);
  will-change: transform;
}
.buckets--staged .bucket.is-lowered { opacity: 0.5; filter: saturate(0.2); }
.buckets--staged .bucket.is-raised { opacity: 1; }

/* Per-character depth on the raised panel's title. --c is the character's
   index and --chars the count, so the spread is a fraction of the word rather
   than a fixed step: a long title does not throw its last letter further than
   a short one. */
.bucket__title .ch {
  display: inline-block;
  transform: translateZ(calc(var(--chz, 0px) *
             (0.35 + 0.65 * (var(--c) / max(var(--chars, 1), 1)))));
  transition: transform 520ms var(--e-out);
  transition-delay: calc(var(--c) * 14ms);
}

/* The steps as a length of track. */
.steps--track { position: relative; perspective: 1200px; perspective-origin: 50% 40%; }
.steps--track li {
  transform: translateZ(var(--pz, 0px));
  opacity: var(--po, 1);
  transform-style: preserve-3d;
  will-change: transform, opacity;
}
/* The line between the stations, drawn as you pass. It sits under the
   counters the .steps rules already place on the left. */
.steps__rail {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 2px;
  border-radius: 2px;
  background: linear-gradient(rgb(var(--accent-rgb) / 0.9), rgb(var(--accent-2-rgb) / 0.35));
  transform: scaleY(0);
  transform-origin: top;
  pointer-events: none;
}
/* The station you are level with. A left edge rather than a background,
   because a filled row would fight the counter that is already there. */
.steps--track li.is-station { box-shadow: inset 2px 0 0 rgb(var(--accent-rgb) / 0.55); }

/* The telemetry meter. No label, no text: a bar whose length is the measured
   frame rate over 60. Information the page can show without saying anything. */
.stats__meter {
  display: block;
  height: 2px;
  margin-top: var(--s-6);
  border-radius: 2px;
  background: rgb(var(--accent-rgb) / 0.1);
  overflow: hidden;
}
.stats__meter-fill {
  display: block;
  height: 100%;
  background: var(--grad);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 520ms var(--e-out), background-color 300ms linear;
}
/* Under 50fps it says so in colour AND in length — never colour alone. */
.stats__meter.is-low .stats__meter-fill { background: linear-gradient(90deg, #FF8A80, #FFB199); }


/* --- 43. Set pieces: the other pages ------------------------------------- */

/* BRANDING — the mark, intact. One .mark filling the field, same mask as
   every other instance, so the path stays in one place. */
@media (min-width: 1100px) {
  .markfield {
    position: absolute;
    right: max(var(--gutter), calc((100% - var(--max)) / 2));
    top: auto;
    bottom: 4%;
    width: clamp(280px, 38vw, 560px);
    aspect-ratio: 1000 / 399;
    transform: none;
    pointer-events: none;
    opacity: 0.92;
    z-index: 1;
  }
}
.markfield .mark {
  width: 100%;
  height: 100%;
}
.page-head { position: relative; }

/* OWNERSHIP — the object you can take. A real button, so it focuses and
   takes a focus ring like every other control on the site. */
/* In the flow under the band's heading, not floating over the copy. It used
   to be position:absolute at the band's top-right — which, in a two-column
   grid whose right column IS the copy, meant it launched on top of the
   paragraph. See the note in pieces.js. */
.ownable {
  position: relative;
  z-index: 3;
  margin-top: clamp(20px, 3vw, 34px);
  width: 74px;
  height: 74px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid rgb(var(--accent-rgb) / 0.3);
  border-radius: 22px;
  background: rgb(var(--accent-rgb) / 0.08);
  backdrop-filter: blur(6px);
  cursor: grab;
  touch-action: none;                    /* the drag is ours, not the page's */
  will-change: transform;
  transition: border-color var(--d-fast) var(--e-out),
              box-shadow var(--d-mid) var(--e-out);
}
.ownable .mark { width: 56px; height: auto; }
.ownable:hover, .ownable:focus-visible { border-color: rgb(var(--accent-rgb) / 0.7); }
.ownable.is-held { cursor: grabbing; box-shadow: 0 24px 60px -20px rgb(var(--shade-rgb) / 0.9); }
.band--sky { position: relative; }

/* WORK — the media slots as windows. The frame is fixed and clips; only what
   is inside it moves. overflow:hidden is what makes it a window rather than
   a picture that slides off its own edges. */
.project__media.is-window { overflow: hidden; }
.project__media.is-window > * { will-change: transform; }

/* ABOUT — the two disciplines at two depths. .ln__i is main.js's own
   per-line wrapper, so this rides the split it already does. */
.staircase { perspective: 900px; perspective-origin: 50% 50%; }
.staircase .ln { transform-style: preserve-3d; }
.staircase .ln__i {
  transform: translateZ(var(--lz, 0px));
  will-change: transform;
}

/* CONTACT — fields that answer to typing. --hit is a 0..1 impulse pieces.js
   decays each frame; the field swells very slightly and its edge lights. */
.form .is-struck {
  transform: scale(calc(1 + 0.006 * var(--hit, 0)));
  border-color: rgb(var(--accent-rgb) / calc(0.25 + 0.5 * var(--hit, 0)));
  box-shadow: 0 0 0 calc(2px * var(--hit, 0)) rgb(var(--accent-rgb) / calc(0.16 * var(--hit, 0)));
}

/* 404 — the field it is lost in. Behind the copy, in front of the ground. */
.lost-field {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0.66;
  pointer-events: none;
}


/* --- 44. The service scenes ----------------------------------------------
   The three panels under "What we do" hold a small 3D scene each instead of
   a dashed placeholder. Built by pieces.js; every colour here comes from the
   accent, so they follow palette.js like everything else and are lilac on the
   home page by construction rather than by a hard-coded purple.

   The idle rotation is a keyframe (see motion.css) so these cost nothing per
   frame. --px / --py are the pointer's contribution, written by pieces.js. */

.scene {
  position: relative;
  width: 100%;
  max-width: 420px;
  margin-left: auto;
  aspect-ratio: 4 / 3;
  border: 1px solid rgb(var(--accent-rgb) / 0.14);
  border-radius: var(--radius-card);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 50% 8%, rgb(var(--accent-rgb) / 0.10), transparent 70%),
    linear-gradient(160deg, rgb(var(--sky-1-rgb) / 0.5), rgb(var(--ground-rgb) / 0.9));
  /* One perspective per scene, so each is its own small box of space. */
  perspective: 760px;
  perspective-origin: 50% 46%;
  display: grid;
  place-items: center;
}
.scene__stage {
  position: relative;
  display: grid;
  place-items: center;
  width: 62%;
  height: 62%;
  transform-style: preserve-3d;
  /* The pointer's turn composes with the keyframe's own rotation, which is
     applied to the groups inside rather than here — two transforms on one
     element would overwrite each other. */
  transform: rotateY(var(--px, 0deg)) rotateX(var(--py, 0deg));
  transition: transform 500ms var(--e-out);
}

/* --- (01) Branding: the mark extruded ---------------------------------- */
/* Each slice is a .mark, so the mask is the single data URI from section 6.
   Stacked in Z with the front faces bright and the back ones falling into
   the accent's deeper end, which is what reads as a solid object rather than
   as a stack of stickers. */

.scene__slice {
  position: absolute;
  width: 100%;
  height: auto;
  aspect-ratio: 1000 / 399;
  background-color: color-mix(in oklab,
      var(--accent) calc(100% - var(--i) * 7%), var(--accent-2));
  transform: translateZ(calc(var(--i) * -1.9px));
  opacity: calc(1 - var(--i) * 0.045);
}
/* The front face carries the light, so the object has a lit edge. */
.scene__slice:first-child {
  background-color: color-mix(in oklab, var(--accent) 70%, white);
  filter: drop-shadow(0 0 18px rgb(var(--accent-rgb) / 0.45));
}

.scene--mark .scene__stage,
.scene__group--mark { animation: scene-turn 16s var(--e-io) infinite; }

/* --- (02) Websites: a page in layers ----------------------------------- */
/* Structure, content, surface and the ground. The wireframe on each plane is
   drawn with gradients rather than child elements — four elements instead of
   forty, and it scales with the box for nothing. */

.scene__plane {
  position: absolute;
  width: 100%;
  aspect-ratio: 4 / 3;
  border: 1px solid rgb(var(--accent-rgb) / 0.7);
  border-radius: 10px;
  background:
    /* the header bar */
    linear-gradient(rgb(var(--accent-rgb) / 0.8) 0 0) no-repeat 9% 13% / 42% 8%,
    /* a block of media */
    linear-gradient(rgb(var(--accent-rgb) / 0.34) 0 0) no-repeat 9% 36% / 36% 32%,
    /* three lines of copy. Three bars, not a repeating gradient: at 130px
       across, hairlines every 9px stopped reading as text and started
       reading as moiré. */
    linear-gradient(rgb(var(--accent-rgb) / 0.6) 0 0) no-repeat 53% 38% / 38% 5%,
    linear-gradient(rgb(var(--accent-rgb) / 0.6) 0 0) no-repeat 53% 51% / 38% 5%,
    linear-gradient(rgb(var(--accent-rgb) / 0.6) 0 0) no-repeat 47% 64% / 30% 5%,
    rgb(var(--sky-1-rgb) / 0.42);
  /* 44px apart rather than 26: the planes have to be separate things you
     could count, or the stack reads as one slightly blurred rectangle. */
  transform: translateZ(calc(var(--i) * 44px - 58px));
  opacity: calc(1 - var(--i) * 0.17);
  box-shadow: 0 0 30px -10px rgb(var(--accent-rgb) / 0.5);
}
.scene--page .scene__stage,
.scene__group--page { animation: scene-assemble 11s var(--e-io) infinite; }

/* --- (03) Brand + Web: the two in one frame ---------------------------- */

.scene__group {
  position: absolute;
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}
.scene--both .scene__group--page { transform: translateZ(-84px) scale(1); }
/* Smaller than it wants to be. At 0.52 the mark filled the frame and the
   page behind it was a detail; the panel is called "Brand + Web" and both
   halves have to be legible as themselves. */
.scene--both .scene__group--mark { transform: translateZ(58px) scale(0.36); }
.scene--both .scene__stage { animation: scene-orbit 22s linear infinite; }

@media (max-width: 859px) { .scene { max-width: none; } }


/* --- 45. The rabbit hole -------------------------------------------------
   /websites/ page head. Rings travelling out of a vanishing point on an
   accelerating curve, with wireframe pages riding the same tunnel. Built by
   pieces.js; keyframes in motion.css. Purple throughout, from the accent, so
   it follows palette.js — which means it is indigo on this page, since that
   is where /websites/ sits in the family. */

/* The flat repeating-radial-gradient this supersedes. */
.page-head.has-hole::before { opacity: 0; }

.rabbit {
  position: absolute;
  z-index: -1;
  right: -8%;
  top: 50%;
  width: min(64vw, 820px);
  aspect-ratio: 1;
  transform: translateY(-50%);
  pointer-events: none;
  /* Short, so the Z travel foreshortens hard and the rings visibly rush past
     rather than drifting. A long perspective here reads as a flat target. */
  perspective: 520px;
  perspective-origin: 50% 50%;
  /* Fades into the page rather than ending on an edge: this is a hole in the
     background, not a graphic pasted onto it. */
  -webkit-mask: radial-gradient(circle at 50%, #000 42%, transparent 72%);
          mask: radial-gradient(circle at 50%, #000 42%, transparent 72%);
}
.rabbit__tunnel {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
  transform: rotateY(var(--lx, 0deg)) rotateX(var(--ly, 0deg));
  transition: transform 620ms var(--e-out);
}

.rabbit__ring,
.rabbit__page,
.rabbit__core {
  position: absolute;
  left: 50%;
  top: 50%;
  transform-style: preserve-3d;
}

.rabbit__ring {
  width: 62%;
  aspect-ratio: 1;
  margin: -31% 0 0 -31%;
  border: 1px solid rgb(var(--accent-rgb) / 0.55);
  border-radius: 50%;
  box-shadow: 0 0 24px -6px rgb(var(--accent-rgb) / 0.5);
  /* One cycle, sixteen rings, each started a sixteenth of the way in — the
     per-ring negative delay is written by pieces.js, which is the note there
     about not being clever with calc() and time. */
  animation: rabbit-fall 7s cubic-bezier(0.55, 0, 0.85, 0.35) infinite;
}

/* The website. A wireframe page drawn with gradients — no child elements —
   so it costs one box and scales with the tunnel. */
.rabbit__page {
  width: 30%;
  aspect-ratio: 4 / 3;
  margin: -11.25% 0 0 -15%;
  border: 1px solid rgb(var(--accent-rgb) / 0.85);
  border-radius: 6px;
  background:
    linear-gradient(rgb(var(--accent-rgb) / 0.75) 0 0) no-repeat 8% 13% / 44% 8%,
    linear-gradient(rgb(var(--accent-rgb) / 0.3) 0 0) no-repeat 8% 36% / 36% 34%,
    repeating-linear-gradient(rgb(var(--accent-rgb) / 0.5) 0 2px,
                              transparent 2px 10px) no-repeat 52% 36% / 40% 34%,
    rgb(var(--sky-1-rgb) / 0.55);
  box-shadow: 0 0 40px -10px rgb(var(--accent-rgb) / 0.75);
  animation: rabbit-page 7s cubic-bezier(0.55, 0, 0.85, 0.35) infinite;
}

/* The hole itself: what everything is falling into. */
.rabbit__core {
  width: 26%;
  aspect-ratio: 1;
  margin: -13% 0 0 -13%;
  border-radius: 50%;
  background: radial-gradient(circle,
      rgb(var(--accent-rgb) / 0.42), rgb(var(--accent-2-rgb) / 0.14) 44%, transparent 70%);
  transform: translateZ(-560px);
  animation: rabbit-core 4.6s var(--e-io) infinite;
}

@media (max-width: 859px) {
  /* In the document after the CTA, not behind the lede. Absolute + a large
     hole still painted through the paragraph even after padding-bottom. */
  .page-head.has-hole { padding-bottom: 0; }
  .rabbit {
    position: relative;
    z-index: 0;
    right: auto;
    left: auto;
    top: auto;
    bottom: auto;
    width: min(68vw, 280px);
    margin: var(--s-7) auto 0;
    transform: none;
    opacity: 0.55;
    -webkit-mask: radial-gradient(circle at 50% 40%, #000 36%, transparent 74%);
            mask: radial-gradient(circle at 50% 40%, #000 36%, transparent 74%);
  }
}


/* --- 46. The booklets ----------------------------------------------------
   /work/. Each project ships an <ol class="book"> of real screenshots; book.js
   binds it. Everything here is the binding — the list itself is complete
   without a line of this.

   IT IS DELIBERATELY SMALL. The single screenshot this replaced ran the full
   width of its card, about 630px on a desktop, and a browser screenshot at
   that size stops being a portfolio item and becomes wallpaper: it dominates
   the copy beside it and says less than the copy does. Capped at 430px it
   reads as an object on the page — something held, at a size that invites
   picking up rather than staring at. */

.book {
  position: relative;
  width: min(100%, 430px);
  aspect-ratio: 4 / 3;
  margin: 0;
  padding: 0;
  list-style: none;
  /* Short perspective: the leaf has to visibly swing towards the viewer as it
     comes over, and a long perspective flattens the turn into a wipe. */
  perspective: 1500px;
  perspective-origin: 20% 50%;
}
.book.is-bound { cursor: pointer; }
.book:focus-visible { outline: 2px solid var(--accent); outline-offset: 6px; border-radius: 4px; }

.book__page {
  position: absolute;
  inset: 0;
  margin: 0;
  border-radius: 4px 10px 10px 4px;   /* tight at the spine, round at the fore-edge */
  overflow: hidden;
  background: var(--ground-2);
  box-shadow: 0 18px 44px -22px rgb(var(--shade-rgb) / 0.95);
  /* The hinge. Everything about the turn is this line. */
  transform-origin: left center;
  transform-style: preserve-3d;
  will-change: transform;
}
/* Motion is the enhancement, declared where it applies, rather than a default
   that a reduced-motion block has to reach back in and cancel. If the query
   never matches, the still booklet is what the stylesheet actually says —
   which is a stronger guarantee than an override that has to be remembered
   every time a new rule is added. */
@media (prefers-reduced-motion: no-preference) {
  .book__page { transition: transform 760ms cubic-bezier(0.22, 0.68, 0.16, 1); }
  .book__edges { transition: right 420ms var(--e-out), width 420ms var(--e-out); }
}
.book__page img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;        /* a page is read from its top */
  display: block;
}
/* The reverse of the leaf: paper, not a mirrored web page. Painted on the
   page's own backface, so it appears exactly when the leaf passes side-on. */
.book__page::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  backface-visibility: hidden;
  transform: rotateY(180deg);
  background:
    linear-gradient(100deg, rgb(var(--sky-1-rgb) / 0.95), var(--ground-2) 42%, var(--ground) 100%),
    var(--ground-2);
  box-shadow: inset 22px 0 40px -26px rgb(var(--accent-rgb) / 0.45);
}
.book.is-bound .book__page.is-turned { transform: rotateY(calc(var(--turn, 172) * -1deg)); }

/* The spine: where the leaves are bound, and the shadow they cast into it. */
.book__spine {
  position: absolute;
  left: -1px; top: 0; bottom: 0;
  width: 16px;
  z-index: 400;
  pointer-events: none;
  border-radius: 4px 0 0 4px;
  background: linear-gradient(90deg,
      rgb(var(--accent-2-rgb) / 0.55), rgb(var(--accent-rgb) / 0.16) 38%, transparent 100%);
  box-shadow: 2px 0 18px -6px rgb(var(--shade-rgb) / 0.9);
}

/* The fore-edge: the pages you have not read yet, as real thickness. --left is
   written by book.js from the actual count, so the block thins as you go and
   the object tells you where you are before any number does. */
.book__edges {
  position: absolute;
  z-index: 1;
  top: 5px; bottom: 5px;
  right: calc(-2px - var(--left, 0) * 1.6px);
  width: calc(2px + var(--left, 0) * 1.6px);
  pointer-events: none;
  border-radius: 0 8px 8px 0;
  background: repeating-linear-gradient(90deg,
      rgb(var(--accent-rgb) / 0.30) 0 1px, rgb(var(--sky-2-rgb) / 0.85) 1px 1.6px);
  box-shadow: 0 16px 34px -20px rgb(var(--shade-rgb) / 0.9);
}

/* The bar under the booklet. Two real buttons and a live counter. */
.book__bar {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  width: min(100%, 430px);
  margin-top: var(--s-4);
}
.book__nav {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;          /* the touch minimum, kept */
  padding: 0;
  border: 1px solid rgb(var(--accent-rgb) / 0.28);
  border-radius: 999px;
  background: rgb(var(--accent-rgb) / 0.07);
  color: var(--text);
  font-size: 1rem;
  cursor: pointer;
  transition: border-color var(--d-fast) var(--e-out),
              background var(--d-fast) var(--e-out),
              transform var(--d-fast) var(--e-out);
}
.book__nav:hover:not(:disabled),
.book__nav:focus-visible:not(:disabled) {
  border-color: rgb(var(--accent-rgb) / 0.75);
  background: rgb(var(--accent-rgb) / 0.16);
  transform: translateY(-1px);
}
/* Disabled at the ends rather than wrapping: a booklet has a first page and a
   last one, and silently looping is how you lose track of which is which. */
.book__nav:disabled { opacity: 0.32; cursor: default; }
/* --text-dim, NOT --text-faint. The counter is a status readout — real text
   that a reader is meant to read — and --text-faint composites to 3.80:1 on
   this ground, under the 4.5:1 floor the whole site is held to. It looked
   like the right token because it is quiet, which is exactly how a contrast
   failure gets shipped. --text-dim is 7.38:1 and just as quiet. */
.book__count {
  margin: var(--s-3) 0 0;
  font: 500 var(--t-label)/1.4 var(--font-mono);
  letter-spacing: var(--track);
  color: var(--text-dim);
}

/* The rule between the arrows: one segment per page, and a contents list that
   looks like a rule. It is the progress meter and the control at once, rather
   than two elements saying the same thing. */
.book__ticks {
  display: flex;
  flex: 1;
  gap: 5px;
  align-items: center;
}
.book__tick {
  flex: 1;
  height: 22px;                 /* the hit area */
  padding: 0;
  border: 0;
  background: none;
  cursor: pointer;
  position: relative;
}
.book__tick::before {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 2px;
  margin-top: -1px;
  border-radius: 2px;
  /* 3:1 is the floor for a control's own visible bounds, and --rule at
     1.47:1 cannot carry one — the panel caught that in a neighbouring
     design and it was true here too. */
  background: rgb(var(--ink-rgb) / 0.34);
  transition: background 300ms var(--e-out), height 300ms var(--e-out);
}
.book__tick.is-read::before { background: rgb(var(--accent-rgb) / 0.45); }
.book__tick.is-at::before {
  background: var(--grad);
  height: 3px;
  margin-top: -1.5px;
  box-shadow: 0 0 10px rgb(var(--accent-rgb) / 0.6);
}
.book__tick:hover::before,
.book__tick:focus-visible::before { background: rgb(var(--accent-rgb) / 0.8); }

/* No JS: the <ol> is a plain, complete list of screenshots. */
.book:not(.is-bound) {
  aspect-ratio: auto;
  display: grid;
  gap: var(--s-4);
  perspective: none;
}
.book:not(.is-bound) .book__page { position: static; transform: none; box-shadow: none; }

@media (max-width: 559px) { .book, .book__bar { width: 100%; } }


/* --- 47. The promises, as a set ------------------------------------------
   Six cards that answer to each other. Hovering one brings it forward and
   settles the others back — the same language the home page's service panels
   use, so the site has one idea about what "picking something up" looks like
   rather than a different one per section.

   Done with :has() and no JavaScript at all. Where :has() is missing the
   siblings simply do not settle back and the hovered card still lifts, which
   is a smaller version of the same thing rather than a broken one.

   No :focus-visible twin here, deliberately, and it is worth saying why: this
   is decoration over cards that hide nothing. Every word is already on screen
   and stays on screen. Adding six tab stops to a page so that a decorative
   lift can have a keyboard equivalent would cost a keyboard visitor six
   presses to get past a paragraph — the page index in the header learned that
   lesson already. */

.promise {
  counter-increment: promise;
  /* translate and scale, NOT transform. tactile.js tilts these same cards
     through `.depth-surface.is-depth-active { transform: perspective(...)
     rotateX() rotateY() translateZ() }`, which has identical specificity to
     `.promise:hover` and sits earlier in the file — so a `transform` here
     would win and silently delete the tilt. The independent properties
     compose with it instead of replacing it, which is exactly what they are
     for. */
  transition: translate 420ms var(--e-out), scale 420ms var(--e-out),
              opacity 320ms var(--e-out), filter 320ms var(--e-out),
              border-color 320ms var(--e-out);
}

/* The number. A CSS counter, so it adds no markup and not one word of copy —
   it is the card's position in a list the reader can already see. */
.promise__word { position: relative; }
.promise::first-line { }
.promise__num {
  position: absolute;
  top: clamp(14px, 1.6vw, 22px);
  right: clamp(16px, 1.8vw, 26px);
  font: 600 clamp(1.6rem, 3.4vw, 2.6rem)/1 var(--font-display);
  letter-spacing: -0.03em;
  color: transparent;
  -webkit-text-stroke: 1px rgb(var(--accent-rgb) / 0.30);
  pointer-events: none;
  transition: -webkit-text-stroke-color 380ms var(--e-out), transform 420ms var(--e-out);
}
.promise__num::after { content: counter(promise, decimal-leading-zero); }

/* The rule at the top of the card reaches across it as you arrive. */
.promise::before { transition: width 460ms var(--e-out); }

@media (hover: hover) and (pointer: fine) {
  .promise:hover {
    translate: 0 -5px;
    border-color: rgb(var(--accent-rgb) / 0.42);
  }
  .promise:hover::before { width: 108px; }
  .promise:hover .promise__num {
    -webkit-text-stroke-color: rgb(var(--accent-rgb) / 0.85);
    transform: translateY(-2px);
  }
  /* The others settle back. 0.62 and 0.62 rather than something dramatic:
     these are sentences the visitor may still be reading, and a set that
     half-vanishes when the cursor crosses it is hostile, not responsive. */
  .promises:has(.promise:hover) .promise:not(:hover) {
    opacity: 0.62;
    filter: saturate(0.62);
    scale: 0.985;
  }
}

@media (pointer: coarse) {
  .aurora__blob, .mote, .warp-line { will-change: auto; }
}

@media (prefers-reduced-motion: reduce) {
  .atmosphere { opacity: 0.24; }
  .cursor-aura { display: none; }
  .page-head::before,
  .ph::before,
  .sound-control__orb span { animation: none !important; }
  .depth-surface.is-depth-active { transform: none; }
  /* depth.js does not initialise under reduced motion, so no section carries
     .stage-layer and the ticker never becomes a cylinder. These are here for
     a preference changed mid-visit. */
  .stage-layer { transform: none; }
  /* The set pieces keep their still, complete form: the panels are a list,
     the steps are an ordered list, the figures are the measured numbers. */
  .buckets--staged .bucket,
  .steps--track li,
  .bucket__title .ch { transform: none; transition: none; }
  /* The raised panel is still clearly the raised one — it says so with
     opacity rather than with distance, which is the same rule the nav
     overlay follows above. What goes is the travel, not the meaning. */
  .buckets--staged .bucket.is-lowered { opacity: 0.55; filter: none; }
  /* The scenes hold a still three-quarter view: a picture of the same object,
     which is what the dashed box never was. Only the turning stops. */
  .scene__stage,
  .scene__group--mark,
  .scene__group--page { animation: none !important; }
  .scene--mark .scene__stage { transform: rotateY(-26deg) rotateX(9deg); }
  .scene--page .scene__stage { transform: rotateY(-22deg) rotateX(11deg); }
  .scene--both .scene__stage { transform: rotateY(-19deg) rotateX(8deg); }
  /* The tunnel holds still: rings at fixed depths, which is a picture of a
     tunnel rather than the absence of one. */
  .rabbit__ring, .rabbit__page, .rabbit__core { animation: none !important; }
  .rabbit__ring { transform: translateZ(calc(var(--i) * -104px + 260px)); opacity: 0.5; }
  .rabbit__page { transform: translateZ(calc(var(--j) * -420px - 120px)); }
  /* The booklet still turns — it is the only way to read the other pages —
     but it does not swing. The leaf leaves and arrives, with no travel
     between: a held picture of each page rather than a missing one. */
  .book.is-still .book__page.is-turned { transform: none; opacity: 0; }
  /* The promises hold still: the set is legible without any of the settling,
     which was only ever a way of pointing at one of them. */
  .promise, .promise::before, .promise__num { transition: none; }
  .promise:hover { translate: none; }
  .promises:has(.promise:hover) .promise:not(:hover) {
    opacity: 1; filter: none; scale: 1;
  }
  .buckets--staged .bucket.is-raised { opacity: 1; }
  .steps--track li { opacity: 1; }
  .steps__rail { display: none; }
  /* The other pages' pieces do not initialise under reduced motion at all,
     so these only matter for a preference changed mid-visit. */
  .markfield__t, .staircase .ln__i { transform: none; }
  .form .is-struck { transform: none; box-shadow: none; }
  .ticker.is-cylinder.is-live .ticker__track { transform: translate3d(var(--tx, 0px), 0, 0); }
  .ticker.is-cylinder .ticker__set li { transform: none; opacity: 1; }
  /* route.js does not intercept at all under reduced motion — an ordinary
     page load is the still, complete equivalent of a transition — so these
     are belt and braces for a preference changed mid-visit. */
  html.is-warping-out .main,
  html.is-warping-in .main { transform: none; opacity: 1; filter: none; animation: none; }

  /* The nav overlay still OPENS — a menu missing under reduced motion is a
     menu missing. What goes is the travelling: the curtain does not fly in
     from -1200px, the six items do not arrive from deep perspective on a
     stagger, and lifting one no longer pushes the others back through Z.
     The lifted item is still clearly the lifted one; it says so with colour
     and opacity instead of with distance. A held picture, not a missing one. */
  .navx, .navx__curtain,
  .navx .nav__list li { transition: opacity 200ms linear !important; }
  .navx__curtain { transform: none !important; }
  .navx .nav__list li { transform: none !important; animation: none !important; }
  .navx__sky { display: none; }
  html.navx-open .main,
  html.navx-open .footer { transform: none; filter: none; }
  .navx-trigger { gap: var(--s-2); }
  .navx-trigger__mark { transition: none; }
  html.navx-open .navx-trigger__mark { transform: rotate(180deg) !important; }
}

/* --- 47. Compact windows, utilities, page arts, forced colours ----------- */

@media (max-height: 700px) {
  :root { --header-h: 58px; }
  .header__inner { gap: var(--s-3); }
}
@media (max-height: 700px) and (max-width: 1099px) {
  .nav__list { gap: 0; }
}

.sound-control {
  min-height: 44px;
  padding: 5px 12px 5px 6px;
}
.sound-control__orb { width: 34px; height: 34px; }
.install-control {
  min-height: 44px;
  padding: 5px 14px 5px 6px;
}
.install-control__icon { width: 34px; height: 34px; font-size: 1.15rem; }
body { padding-bottom: calc(64px + env(safe-area-inset-bottom, 0px)); }

.page-head.has-art::before { opacity: 0; }
/* When the current hero piece is present, drop the previous one so the two
   cannot stack in the mobile document flow — static mark vs tiled markfield
   on /branding/, rabbit tunnel vs desk on /websites/. */
.page-head:has(.markfield) .page-art--mark,
.page-head:has(.page-art--desk) .rabbit { display: none; }
.page-art {
  position: absolute;
  z-index: 0;
  right: max(var(--gutter), calc((100% - var(--max)) / 2));
  top: 50%;
  transform: translateY(-50%);
  width: min(42vw, 420px);
  pointer-events: none;
}
.page-head > *:not(.page-art):not(.markfield):not(.page-hero__sky):not(.page-hero__cue) {
  position: relative;
  z-index: 1;
}

.page-art--handover { width: min(38vw, 360px); }
.handover-stack { position: relative; height: 220px; }
.handover-card {
  position: absolute;
  width: 58%;
  height: 86px;
  border-radius: 14px;
  border: 1px solid rgb(var(--accent-rgb) / 0.28);
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.06), transparent 40%),
    rgb(var(--sky-2-rgb) / 0.72);
  box-shadow: 0 18px 40px -28px rgb(var(--shade-rgb) / 0.9);
}
.handover-card--files { left: 8%; top: 18px; transform: rotate(-8deg); }
.handover-card--keys { left: 22%; top: 62px; transform: rotate(4deg); width: 64%; }
.handover-card--accounts { left: 14%; top: 112px; transform: rotate(-2deg); }
.handover-card::after {
  content: "";
  position: absolute;
  inset: 16px 18px auto;
  height: 8px;
  border-radius: 99px;
  background: rgb(var(--accent-rgb) / 0.28);
}
.handover-mark {
  position: absolute;
  right: 6%;
  bottom: 8px;
  width: 72px;
  filter: drop-shadow(0 0 18px rgb(var(--accent-rgb) / 0.35));
}

.page-art--folio { width: min(40vw, 380px); height: 240px; }
.folio-shot {
  position: absolute;
  width: 62%;
  border-radius: 12px;
  border: 1px solid rgb(var(--accent-rgb) / 0.22);
  box-shadow: 0 22px 48px -30px rgb(var(--shade-rgb) / 0.95);
  object-fit: cover;
  aspect-ratio: 4 / 3;
}
.folio-shot--1 { left: 0; top: 18px; transform: rotate(-7deg); }
.folio-shot--2 { left: 28%; top: 48px; transform: rotate(5deg); }
.folio-shot--3 { left: 12%; top: 92px; transform: rotate(-2deg); width: 58%; }

/* ABOUT — hollow cubes, not filled bricks. Six faces, outline only,
   so the far edges stay visible through the box. Three steps: two
   disciplines, one staircase. */
.page-art--cubes {
  width: min(38vw, 340px);
  height: 240px;
  perspective: 820px;
  perspective-origin: 48% 56%;
  transform-style: preserve-3d;
}
.cubes {
  position: absolute;
  inset: 0;
  transform-style: preserve-3d;
}
.cube {
  --s: 64px;
  position: absolute;
  width: var(--s);
  height: var(--s);
  transform-style: preserve-3d;
  transform: rotateX(-28deg) rotateY(36deg);
}
.cube i {
  position: absolute;
  inset: 0;
  border: 1.5px solid rgb(var(--accent-rgb) / 0.78);
  background: transparent;
  box-shadow: none;
  backface-visibility: visible;
}
.cube i:nth-child(4),
.cube i:nth-child(5),
.cube i:nth-child(6) {
  border-color: rgb(var(--accent-rgb) / 0.34);
}
.cube i:nth-child(1) { transform: rotateY(0deg) translateZ(calc(var(--s) / 2)); }
.cube i:nth-child(2) { transform: rotateY(90deg) translateZ(calc(var(--s) / 2)); }
.cube i:nth-child(3) { transform: rotateX(90deg) translateZ(calc(var(--s) / 2)); }
.cube i:nth-child(4) { transform: rotateY(180deg) translateZ(calc(var(--s) / 2)); }
.cube i:nth-child(5) { transform: rotateY(-90deg) translateZ(calc(var(--s) / 2)); }
.cube i:nth-child(6) { transform: rotateX(-90deg) translateZ(calc(var(--s) / 2)); }
.cube--1 { left: 10%; bottom: 12%; --s: 68px; }
.cube--2 { left: 36%; bottom: 28%; --s: 68px; }
.cube--3 { left: 62%; bottom: 44%; --s: 68px; }
@media (min-width: 1100px) {
  .page-hero--object .page-art--cubes {
    right: max(var(--gutter), calc((100% - var(--max)) / 2));
    z-index: 1;
  }
}

/* Ownership / Contact — a hand offering a floating object.
   Graphite strokes, transparent ground, so the same drawing sits on
   paper and on the inverse lilac without a second asset. */
.page-art--emblem {
  width: min(44vw, 440px);
}
@media (min-width: 1100px) {
  .page-hero--object .page-art--emblem {
    right: max(var(--gutter), calc((100% - var(--max)) / 2));
    top: 54%;
    z-index: 1;
    transform: translateY(-50%);
  }
}
.page-art--emblem img {
  display: block;
  width: 100%;
  height: auto;
}

/* CONTACT — a gatehouse of the same cubes as About.
   Nine blocks, a step larger than the cube so they do not cut through
   each other: a base, a gate, two towers, a walk, a keep. */
.page-head:has(.page-art--keep) {
  overflow: hidden;
}
.page-art--keep {
  width: min(42vw, 380px);
  max-width: 100%;
  height: 320px;
  overflow: hidden;
  perspective: 820px;
  perspective-origin: 48% 62%;
  transform-style: preserve-3d;
}
.keep {
  position: absolute;
  left: 50%;
  bottom: 0;
  width: min(100%, 280px);
  height: 280px;
  margin-left: -140px;
  transform-style: preserve-3d;
}
.keep::after {
  content: "";
  position: absolute;
  left: 8%;
  right: 8%;
  bottom: 18px;
  height: 1px;
  background: linear-gradient(90deg, transparent, rgb(var(--accent-rgb) / 0.45), transparent);
}
.keep .cube {
  --s: 52px;
  --x: 0;
  --z: 0;
  left: calc(50% - (var(--s) / 2) + (var(--x) * 42px));
  top: auto;
  bottom: calc(22px + (var(--z) * 56px));
  transform: rotateX(-28deg) rotateY(36deg);
}

.page-art--mark {
  width: min(28vw, 240px);
  aspect-ratio: 1000 / 399;
}
.page-art--mark .mark { width: 100%; height: auto; opacity: 0.78; }

/* WEBSITES — a screen that opens, then someone types.
   Resting form is the finished laptop: lid up, page painted, headline
   complete. motion.css plays the opening and the typing over that. The
   rings behind it stay; this sits on them rather than replacing them. */
.page-art--desk {
  width: min(42vw, 560px);
  perspective: 920px;
  perspective-origin: 50% 88%;
  transform-style: preserve-3d;
}
@media (min-width: 1100px) {
  .page-hero--object .page-art--desk {
    right: max(var(--gutter), calc((100% - var(--max)) / 2));
    top: 56%;
    z-index: 0;
    transform: translateY(-50%);
  }
}
.page-head:has(.page-art--desk) .h-1,
.page-head:has(.page-art--desk) .lede,
.page-head:has(.page-art--desk) .hero__cta {
  max-width: min(34rem, 44%);
}
.desk {
  transform-style: preserve-3d;
  filter: drop-shadow(0 28px 48px -22px rgb(var(--shade-rgb) / 0.92));
}
.desk__lid {
  transform-origin: 50% 100%;
  transform-style: preserve-3d;
  transform: rotateX(8deg);
}
.desk__bezel {
  border-radius: 14px 14px 8px 8px;
  border: 1px solid rgb(var(--accent-rgb) / 0.28);
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.06), transparent 28%),
    #12141a;
  padding: 7px 7px 10px;
  box-shadow:
    inset 0 1px 0 rgb(var(--ink-rgb) / 0.08),
    0 0 0 1px rgb(var(--shade-rgb) / 0.35);
}
.desk__chrome {
  display: flex;
  align-items: center;
  gap: 8px;
  height: 18px;
  padding: 0 6px;
}
.desk__traffic {
  width: 28px;
  height: 6px;
  border-radius: 99px;
  background:
    radial-gradient(circle at 3px 50%, #ff6b6b 0 2.2px, transparent 2.4px),
    radial-gradient(circle at 12px 50%, #f4c15d 0 2.2px, transparent 2.4px),
    radial-gradient(circle at 21px 50%, #63d67a 0 2.2px, transparent 2.4px);
  opacity: 0.8;
  flex: 0 0 auto;
}
.desk__url {
  flex: 1;
  height: 8px;
  border-radius: 99px;
  background: rgb(var(--ink-rgb) / 0.06);
  overflow: hidden;
}
.desk__url-fill {
  display: block;
  height: 100%;
  width: 62%;
  border-radius: inherit;
  background: rgb(var(--accent-rgb) / 0.42);
}
.desk__viewport {
  position: relative;
  margin-top: 6px;
  aspect-ratio: 16 / 10;
  border-radius: 6px;
  overflow: hidden;
  background:
    radial-gradient(80% 70% at 70% 0%, rgb(var(--accent-rgb) / 0.16), transparent 62%),
    #0e1014;
}
.desk__shot {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
}
.desk__viewport:has(.desk__shot) .desk__site,
.desk__viewport:has(.desk__shot) .desk__pointer { display: none; }
.desk__site {
  position: absolute;
  inset: 10% 9% 12%;
}
.desk__nav {
  height: 7px;
  width: 46%;
  border-radius: 99px;
  background: rgb(var(--accent-rgb) / 0.55);
  margin-bottom: 14%;
}
.desk__headline {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 2.1vw, 1.35rem);
  font-weight: 650;
  letter-spacing: -0.03em;
  color: rgb(var(--on-shade-rgb) / 0.92);
  line-height: 1.15;
  white-space: nowrap;
}
.desk__typed {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  width: calc(var(--ch, 10) * 0.62em);
}
.desk__caret {
  display: inline-block;
  width: 1.5px;
  height: 0.92em;
  margin-left: 2px;
  background: var(--accent);
  vertical-align: -2px;
}
.desk__copy {
  display: grid;
  gap: 7px;
  margin-top: 12%;
}
.desk__copy span {
  display: block;
  height: 5px;
  border-radius: 99px;
  background: rgb(var(--on-shade-rgb) / 0.18);
}
.desk__copy span:nth-child(1) { width: 88%; }
.desk__copy span:nth-child(2) { width: 72%; }
.desk__copy span:nth-child(3) { width: 54%; }
.desk__btn {
  margin-top: 14%;
  width: 34%;
  height: 14px;
  border-radius: 99px;
  background: var(--grad);
}
.desk__pointer {
  position: absolute;
  left: 0;
  top: 0;
  width: 10px;
  height: 14px;
  background: rgb(var(--on-shade-rgb) / 1);
  clip-path: polygon(0 0, 100% 68%, 42% 68%, 62% 100%, 38% 100%, 22% 68%, 0 82%);
  filter: drop-shadow(0 1px 2px rgb(var(--shade-rgb) / 0.55));
}
.desk__hinge {
  height: 5px;
  margin: 0 8%;
  border-radius: 0 0 3px 3px;
  background: linear-gradient(180deg, #2a2e36, #16181b);
}
.desk__base {
  height: 14px;
  margin: 0 2%;
  border-radius: 0 0 40% 40%;
  background:
    linear-gradient(180deg, #2c3038, #1a1d22 70%, #12141a);
  box-shadow: 0 10px 18px -12px rgb(var(--shade-rgb) / 0.8);
}
.desk__keys {
  display: block;
  width: 56%;
  height: 4px;
  margin: 4px auto 0;
  border-radius: 99px;
  background:
    repeating-linear-gradient(90deg,
      rgb(var(--accent-rgb) / 0.22) 0 6px,
      transparent 6px 10px);
}

@media (max-width: 859px) {
  .page-head:has(.page-art--desk) .h-1,
  .page-head:has(.page-art--desk) .lede,
  .page-head:has(.page-art--desk) .hero__cta { max-width: none; }
  .page-art--desk {
    width: min(280px, 78vw);
    margin-left: auto;
    margin-right: auto;
    opacity: 0.92;
  }
}

@media (max-width: 859px) {
  .page-art {
    position: relative;
    right: auto;
    top: auto;
    transform: none;
    width: min(220px, 64vw);
    margin: var(--s-6) 0 0 0;
    opacity: 0.78;
  }
  .page-art--desk {
    width: min(280px, 78vw);
    margin-left: auto;
    margin-right: auto;
    opacity: 0.92;
  }
  .page-head.has-art:not(.page-hero) { min-height: 0; }
  .page-art--keep {
    width: min(220px, 70vw);
    height: 240px;
  }
  .keep {
    width: 200px;
    height: 200px;
    margin-left: -100px;
  }
  .keep .cube {
    --s: 36px;
    left: calc(50% - (var(--s) / 2) + (var(--x) * 28px));
    bottom: calc(16px + (var(--z) * 40px));
  }
}

@media (max-width: 430px) {
  .brand__word { letter-spacing: 0.12em; }
  .lang a { min-width: 32px; padding: 0 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .keep .cube {
    opacity: 1;
    transform: rotateX(-28deg) rotateY(36deg);
  }
}

@media (forced-colors: active) {
  .display, .grad, .btn--solid { color: CanvasText; background: Canvas; }
  .btn, .nav-toggle, .lang, .sound-control, .check {
    border: 1px solid CanvasText;
    forced-color-adjust: none;
  }
  .lang a[aria-current], .btn--solid {
    background: Highlight;
    color: HighlightText;
  }
  :focus-visible { outline: 3px solid Highlight; }
  .hero .display:focus,
  .hero .display:focus-visible,
  .page-hero .display:focus,
  .page-hero .display:focus-visible,
  .page-head .display:focus,
  .page-head .display:focus-visible,
  h1[tabindex="-1"]:focus,
  h1[tabindex="-1"]:focus-visible {
    outline: none;
  }
}

@supports not (transform-style: preserve-3d) {
  .stage-layer { transform: none; transform-style: flat; }
}
@media print {
  .stage-layer { transform: none; transform-style: flat; }
}

footer.footer {
  margin-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
}

/* --- 48. Studio refinement -----------------------------------------------
   The homepage hero and its inherited tokens are intentionally untouched.
   Editorial columns, fine rules and quiet surfaces carry the inner pages. */
.section, .band, .page-hero, .footer {
  --t-label: 0.875rem;
  --t-micro: 0.75rem;
  --radius-card: 16px;
}
.section { padding-block: clamp(64px, 8vw, 116px); }
.section .h-1, .band .h-1 {
  font-size: clamp(2rem, 3.8vw, 3.5rem);
  font-weight: 500;
  letter-spacing: -0.045em;
  line-height: 1.1;
  text-wrap: balance;
}
.section .h-2, .band .h-2 { letter-spacing: -0.035em; font-weight: 500; }
.section .label, .page-hero .label { letter-spacing: 0.14em; color: var(--text-dim); }
.section .micro, .footer__label { color: var(--text-dim); }
.section p, .band p { overflow-wrap: break-word; }
.band__grid > div { min-width: 0; }
.band__grid > div > p { max-width: 66ch; }
.band {
  border-radius: 16px;
  box-shadow: none;
  background: linear-gradient(120deg, rgb(var(--ink-rgb) / 0.035), transparent), var(--ground-2);
  padding-block: clamp(56px, 7vw, 100px);
}
.band--sky {
  background: linear-gradient(120deg, var(--sky-2), var(--sky-1) 65%, var(--sky-3));
  border-color: rgb(var(--accent-rgb) / 0.16);
}
.band .pull { font-weight: 450; letter-spacing: -0.04em; }
.band--sky .label, .band--sky .micro { color: rgb(var(--on-shade-rgb) / 0.72); }

/* Open layouts keep the benefits legible while the portfolio carries depth. */
.promises { gap: 36px clamp(24px, 3.5vw, 56px); }
.promise {
  padding: 26px 0 14px;
  border: 0;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  background: none;
  box-shadow: none;
  overflow: visible;
}
.promise::before, .promise::after { display: none; }
.promise__word { padding-right: 40px; font-size: clamp(1.375rem, 2vw, 1.75rem); font-weight: 500; line-height: 1.22; }
.promise__num {
  top: 30px; right: 0;
  font: 400 0.75rem/1 var(--font-mono);
  color: var(--text-dim);
  -webkit-text-stroke: 0;
  letter-spacing: 0;
}
.promise p + p { max-width: 40ch; margin-top: 18px; }
.promise:hover { translate: none; }
.promise:hover .promise__word { background: none; color: var(--text); }
.promises:has(.promise:hover) .promise:not(:hover) { opacity: 1; filter: none; scale: 1; }
.promise:hover .promise__num { transform: none; color: var(--accent); }

.bucket { padding-block: 0; }
.bucket__grid {
  border: 0;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  box-shadow: none;
  background: none;
  padding: clamp(36px, 5vw, 68px) 0;
  align-items: center;
}
.bucket:last-child .bucket__grid { border-bottom: 1px solid var(--rule); }
.bucket__grid::after, .bucket__num::after { display: none; }
.bucket__num { align-self: start; padding-top: 12px; font-family: var(--font-mono); }
.bucket__title { font-size: clamp(1.75rem, 3.6vw, 3rem); font-weight: 500; letter-spacing: -0.04em; }
.bucket__desc { max-width: 55ch; }
.buckets--staged .bucket, .bucket__title .ch { transform: none; }
.buckets--staged .bucket.is-lowered { opacity: 1; filter: none; }

.stat { border: 0; border-top: 1px solid var(--rule); border-radius: 0; background: none; box-shadow: none; padding: 32px 0; }
.stat::after { display: none; }
.stat__num { letter-spacing: -0.065em; font-weight: 400; }
.stat__label { font-size: 1rem; max-width: 35ch; }
.qs { gap: 0; }
.qs > li { padding: 18px 0 18px 20px; border: 0; border-left: 1px solid var(--rule); border-radius: 0; background: none; }
.qs > li::after { display: none; }
.qs--accent > li { border-left-color: rgb(var(--accent-rgb) / 0.5); }
.handover { border-radius: 8px; box-shadow: none; background: rgb(var(--ink-rgb) / 0.025); }
.steps--track li { transform: none; opacity: 1; }
.steps--track li.is-station { box-shadow: none; }
.steps__rail { display: none; }
.steps li { padding-block: 32px; }
.steps h3 { font-size: 1.5rem; font-weight: 500; letter-spacing: -0.025em; }

.page-head.page-hero { min-height: 0; }
.page-hero .h-1 { font-size: clamp(2.5rem, 4.8vw, 4.5rem); line-height: 1.08; letter-spacing: -0.05em; font-weight: 500; }
.page-hero .h-hero { letter-spacing: -0.055em; font-weight: 500; }
.page-hero .lede { line-height: 1.8; font-size: 1.0625rem; }
.hero .shot-rule,
.page-hero .shot-rule { display: none; }
.page-hero .hero__cta { margin-top: 36px; }
.page-hero__sky { opacity: 0.65; }
.page-hero--object .page-art--geometry {
  width: min(37vw, 500px);
  right: max(3vw, calc((100vw - 1320px) / 2));
  top: 50%;
  opacity: 1;
  transform: translateY(-50%);
  filter: none;
}
.page-art--geometry { aspect-ratio: 1; perspective: 1000px; }
.page-hero--object:has(.page-art--geometry) .h-hero { max-width: min(48rem, 57vw); }

/* Large work samples with the existing page controls beside each project. */
.projects.projects--wide { grid-template-columns: minmax(0, 1fr); gap: clamp(64px, 8vw, 112px); margin-top: 0; }
.projects--wide .project__media, .projects--wide .book__bar { max-width: none; }
.projects--wide .project__client { font-size: clamp(1.75rem, 3vw, 2.75rem); font-weight: 500; letter-spacing: -0.045em; line-height: 1.12; }
.projects--wide .project__scope { color: var(--text-dim); background: none; font-size: 0.75rem; }
.projects--wide .project__line { font-size: 1rem; line-height: 1.8; }

.detail { border: 0; border-top: 1px solid var(--rule); border-radius: 0; box-shadow: none; background: none; padding: 26px 0; }
.detail::after { display: none; }
.detail + .detail { margin-top: 12px; }
.detail a { overflow-wrap: anywhere; }
.form { gap: 28px; }
.field input, .field select, .field textarea { border-radius: 8px; box-shadow: none; }
.field textarea { min-height: 180px; }
.form .is-struck { transform: none; }
.footer { border-radius: 16px; box-shadow: none; background: var(--ground-2); }
.footer__bottom { line-height: 1.7; }
.sound-control__copy b, .sound-control__copy small { font-size: 0.75rem; }

@media (min-width: 1000px) {
  .band__grid { grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr); gap: clamp(40px, 6vw, 96px); }
  .band__grid:has(> .pull) > .display { grid-column: 1; grid-row: 1; }
  .band__grid:has(> .pull) > div { grid-column: 2; grid-row: 1 / 4; }
  .band__grid:has(> .pull) > .pull { grid-column: 1; grid-row: 2; margin-top: 24px; }
  .projects--wide .project { display: grid; grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr); column-gap: clamp(40px, 6vw, 88px); grid-template-rows: auto auto 1fr; align-items: start; }
  .projects--wide .project__media { grid-column: 1; grid-row: 1 / 4; }
  .projects--wide .project__scope { grid-column: 2; margin-top: 24px; }
  .projects--wide .project__client, .projects--wide .project__line { grid-column: 2; }
}
@media (max-width: 1099px) {
  .page-head.page-hero { min-height: 0; padding-block: 64px 36px; }
  .page-hero--object .h-hero, .page-hero--object:has(.page-art--geometry) .h-hero,
  .page-hero--object .h-1 { max-width: none; }
  .page-hero--object .page-art--geometry { position: relative; inset: auto; transform: none; width: min(340px, 70vw); margin: 24px auto 0; }
}
@media (max-width: 639px) {
  .section { padding-block: 48px; }
  .band { margin-inline: var(--gutter); border-radius: 16px; padding-block: 40px; }
  .band > .wrap { padding-inline: 0; }
  .band--inset > .wrap { padding-inline: clamp(20px, 5vw, 30px); }
  .promises { gap: 20px; }
  .promise { padding-top: 24px; }
  .page-hero .h-hero, .page-hero .h-1 { font-size: clamp(2.25rem, 9vw, 3.25rem); }
  .page-hero--object .page-art--geometry { width: min(240px, 64vw); margin: 24px 0 0; }
  .bucket__grid { gap: 24px; }
  .projects--wide .project__scope { margin-top: 28px; }
  .footer { margin-inline: var(--gutter); }
}

/* Abstract geometry echoes About's dimensional cubes and Branding's mark.
   These are lightweight geometric accents, with no raster background. */
.geometry {
  position: absolute;
  inset: 12%;
  transform-style: preserve-3d;
}
.geometry span {
  position: absolute;
  display: block;
  inset: 0;
  backface-visibility: visible;
}
/* Ownership — transparent contours with true projected depth. */
.master-key {
  position: absolute;
  inset: 0;
}
.master-key__object {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  stroke: #BA8AFF;
  filter: drop-shadow(0 0 7px rgb(160 93 242 / .2));
}
.master-key__object path { fill: none; vector-effect: non-scaling-stroke; }
html.is-inverse .master-key__object { stroke: #6C2DA8; filter: none; }
.tesseract {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
  fill: none;
  color: #BA8AFF;
  filter: drop-shadow(0 0 8px rgb(160 93 242 / 0.24));
}
.tesseract line {
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
html.is-inverse .tesseract { color: #6C2DA8; filter: none; }
html.is-inverse .detail { border-radius: 10px; box-shadow: none; padding: 24px; }
html.is-inverse .detail h2,
html.is-inverse .form .field > label,
html.is-inverse .form .fieldset > legend,
html.is-inverse .form .form__note { color: rgb(var(--on-shade-rgb) / 0.74); }
html.is-inverse .form { border-radius: 16px; box-shadow: 0 24px 64px -40px rgb(var(--shade-rgb) / 0.5); background: var(--shade); }
html.is-inverse .footer { background: var(--shade); }
@media (min-width: 1100px) {
  .page-hero--object .h-1 { max-width: min(48rem, 58vw); }
  .page-hero--object .display > .ln { white-space: normal; }
  .page-hero--object .page-art--geometry { z-index: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .geometry { transform-style: flat; }
}

/* --- 49. Inner-page composition -----------------------------------------
   Explicit columns give the type and objects their own space. The homepage
   .hero is intentionally outside these selectors. */
.page-head.page-hero--object {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  gap: 32px;
  padding-inline: max(var(--gutter), calc((100% - var(--max)) / 2 + var(--gutter)));
}
.page-head.page-hero--object > .page-hero__copy {
  width: 100%;
  min-width: 0;
  max-width: none;
  margin: 0;
  padding-inline: 0;
}
.page-head.page-hero--object .page-hero__copy .display,
.page-head.page-hero--object .page-hero__copy .hero__cta { max-width: none; }
.page-head.page-hero--object .page-hero__copy .lede { max-width: 48ch; }
.page-head.page-hero--object > .page-art,
.page-head.page-hero--object > .markfield {
  position: relative;
  inset: auto;
  transform: none;
  justify-self: center;
  width: min(100%, 340px);
  max-width: 100%;
  margin: 0;
}
.page-head.page-hero--object > .page-art--cubes { height: 240px; }
.page-head.page-hero--object > .markfield { aspect-ratio: 1000 / 399; }
.page-head.page-hero--object > .page-hero__cue { margin-top: 0; }
@media (min-width: 1100px) {
  .page-head.page-hero--object {
    grid-template-columns: minmax(0, 1.25fr) minmax(0, 0.85fr);
    column-gap: clamp(32px, 5vw, 72px);
    padding-block: 88px 104px;
  }
  .page-head.page-hero--object > .page-hero__copy { grid-area: 1 / 1; }
  .page-head.page-hero--object > .page-art,
  .page-head.page-hero--object > .markfield { grid-area: 1 / 2; width: 100%; }
  .page-head.page-hero--object .h-hero { font-size: clamp(2.75rem, 4.8vw, 4.75rem); }
}
@media (max-width: 639px) {
  .page-head.page-hero--object > .page-art { width: min(100%, 260px); }
}

/* Screenshots stay inside a quiet frame; the caption and controls sit below. */
.projects--wide .project { grid-template-rows: auto; align-items: center; }
.project__gallery, .project__copy { min-width: 0; }
.project__copy { padding-block: 28px; }
.projects--wide .project__copy .project__scope { margin-top: 0; padding: 0; letter-spacing: 0.12em; }
.projects--wide .project__copy .project__client { margin-top: 18px; }
.projects--wide .project__copy .project__line { margin-top: 24px; }
.projects--wide .project__media {
  width: 100%;
  border: 1px solid var(--rule);
  border-radius: 12px;
  background: var(--ground-2);
  box-shadow: 0 18px 44px -32px rgb(var(--shade-rgb) / 0.55);
}
.projects--wide .project__media::before,
.projects--wide .project__media::after { display: none; }
.projects--wide .book, .projects--wide .book__bar { width: 100%; }
.projects--wide .book.is-bound { overflow: hidden; perspective: none; border-radius: 11px; }
.projects--wide .book__spine, .projects--wide .book__edges,
.projects--wide .book__page::after { display: none; }
.projects--wide .book.is-bound .book__page {
  border-radius: 0;
  box-shadow: none;
  transform: translateX(12px);
  transform-style: flat;
  will-change: auto;
  opacity: 0;
  pointer-events: none;
  transition: none;
}
.projects--wide .book.is-bound .book__page.is-turned { transform: translateX(-12px); opacity: 0; }
.projects--wide .book.is-bound .book__page[aria-hidden="false"] { transform: none; opacity: 1; pointer-events: auto; }
.projects--wide .book__bar { margin-top: 16px; gap: 16px; }
.projects--wide .book__nav { flex-shrink: 0; background: none; border-color: var(--rule); }
.projects--wide .book__tick { height: 44px; }
.projects--wide .book__tick.is-at::before { box-shadow: none; background: var(--accent); }
.projects--wide .book__count { margin-top: 4px; letter-spacing: 0; font-size: 0.75rem; line-height: 1.7; }
@media (prefers-reduced-motion: no-preference) {
  .projects--wide .book.is-bound .book__page { transition: opacity 280ms ease, transform 360ms var(--e-out); }
}

/* Compact enquiry form with native radio controls and legible labels. */
.form { grid-template-columns: minmax(0, 1fr); column-gap: 20px; }
.form > * { min-width: 0; }
.form .field > label, .form .fieldset > legend {
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--text-dim);
}
.form .checks, html.is-inverse .form .checks {
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  padding: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.form .check {
  border: 1px solid var(--rule);
  border-radius: 8px;
  min-height: 52px;
  padding: 12px;
  font-size: 0.875rem;
  gap: 10px;
}
.form .check input { flex: 0 0 16px; }
html.is-inverse .form .check { border-color: rgb(var(--on-shade-rgb) / 0.18); }
html.is-inverse .form .check:has(input:checked) { border-color: rgb(var(--accent-rgb) / 0.65); }
.contact__details .detail, html.is-inverse .contact__details .detail {
  padding: 26px 0;
  border: 0;
  border-top: 1px solid var(--rule);
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--text);
}
.contact__details .detail + .detail, html.is-inverse .contact__details .detail + .detail { margin-top: 0; }
html.is-inverse .contact__details .detail :is(h2, p, a, address) { color: var(--text); }
.contact__details .detail h2 { margin-bottom: 16px; }
.contact__details .detail:first-child a { font-size: clamp(1.25rem, 2.1vw, 1.75rem); letter-spacing: -0.025em; }
@media (min-width: 1100px), (min-width: 640px) and (max-width: 859px) {
  .form { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .form > * { grid-column: 1 / -1; }
  .form > .field--half { grid-column: auto; }
}
@media (max-width: 379px) {
  .form .checks { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 859px) {
  .footer__grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 32px 24px; }
  .footer__grid > :first-child, .footer__grid > :last-child { grid-column: 1 / -1; }
  .footer__grid > * { min-width: 0; }
  .footer__grid a { overflow-wrap: anywhere; }
  .footer nav a { display: inline-flex; align-items: center; min-height: 44px; }
  .footer nav li + li { margin-top: 0; }
}
@media (max-width: 1099px) and (max-height: 700px) {
  .nav { justify-content: flex-start; padding-block: 24px; }
}

/* A compact, typographic opening for the portfolio. */
.page-head.page-hero--folio {
  min-height: 0;
  padding-block: clamp(64px, 10vh, 112px) 80px;
}
.page-hero--folio .h-1, .page-hero--folio .lede { max-width: none; }

/* --- 50. Branding: a floating identity composition ---------------------- */
.page-head.page-hero--branding { column-gap: clamp(28px, 4vw, 64px); }
.page-hero--branding .display .ln:last-child { color: #BD8DF4; }
html.is-inverse .page-hero--branding .display .ln:last-child { color: #62258D; }
.page-head.page-hero--branding > .page-art--brand { width: min(100%, 520px); aspect-ratio: 1; pointer-events: auto; }
.brand-studio { width: 100%; height: 100%; perspective: 1100px; }
.brand-studio__assembly {
  position: relative;
  width: 100%; height: 100%;
  transform: rotateX(8deg) rotateY(-9deg);
  transform-style: preserve-3d;
  transition: transform 850ms cubic-bezier(.2,.8,.2,1);
}
.brand-studio__type, .brand-studio__plate, .brand-studio__palette {
  position: absolute;
  border: 1px solid rgb(255 255 255 / .3);
  box-shadow: 0 30px 60px -35px rgb(10 6 20 / .6), inset 0 1px 0 rgb(255 255 255 / .3);
}
.brand-studio__type {
  left: 5%; top: 3%; width: 44%; height: 48%;
  padding: 5%; border-radius: 10px;
  background: #F4F0E7; color: #24202D;
  transform: rotate(-14deg) translateZ(-20px);
}
.brand-studio__type > span { display: block; font: 500 clamp(4rem, 8vw, 7.5rem)/1 var(--font-display); letter-spacing: -.09em; }
.brand-studio__type i { display: block; height: 1px; background: #24202D; opacity: .2; margin-top: 9%; width: 78%; }
.brand-studio__type i:last-child { width: 50%; }
.brand-studio__plate {
  left: 17%; top: 25%; width: 79%; height: 53%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12%; border-radius: 16px;
  background: linear-gradient(125deg, #E0C4FF, #BD8CF0 62%, #A96CE4);
  color: #29143C;
  transform: rotate(6deg) translateZ(30px);
}
.brand-studio__logo { display: block; height: 48%; width: auto; aspect-ratio: 1; color: #29143C; flex-shrink: 0; }
.brand-studio__registration { position: absolute; top: 8%; left: 6%; width: 12px; height: 12px; opacity: .45; }
.brand-studio__registration::before, .brand-studio__registration::after { content: ""; position: absolute; background: currentColor; }
.brand-studio__registration::before { top: 50%; width: 100%; height: 1px; }
.brand-studio__registration::after { left: 50%; width: 1px; height: 100%; }
.brand-studio__palette {
  left: 8%; bottom: 4%; width: 65%; height: 22%;
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 7%; padding: 4%;
  border-color: rgb(255 255 255 / .14); border-radius: 12px;
  background: #24202D;
  transform: rotate(-7deg) translateZ(65px);
}
.brand-studio__palette span { border: 1px solid rgb(255 255 255 / .16); border-radius: 5px; background: #F4F0E7; }
.brand-studio__palette span:nth-child(2) { background: #BA8AFF; }
.brand-studio__palette span:nth-child(3) { background: #37303F; }
@media (hover: hover) and (prefers-reduced-motion: no-preference) {
  .brand-studio:hover .brand-studio__assembly { transform: rotateX(0deg) rotateY(4deg); }
}
@media (prefers-reduced-motion: no-preference) {
  .brand-studio__plate { animation: brand-float 7s ease-in-out infinite; }
  .brand-studio__type { animation: brand-float 8s ease-in-out -3s infinite reverse; }
  .brand-studio__palette { animation: brand-float 6s ease-in-out -2s infinite; }
}
@keyframes brand-float { 0%, 100% { translate: 0 0; } 50% { translate: 0 -10px; } }
@media (max-width: 639px) {
  .page-head.page-hero--branding > .page-art--brand { width: min(100%, 330px); }
  .brand-studio__type > span { font-size: clamp(3.75rem, 20vw, 5.5rem); }
}

/* --- 51. Contact: colorful choices and tactile, accessible controls ------ */
html .form.form--playful {
  --form-accent: #C7A0FF;
  --form-ink: #F5F1FA;
  --form-muted: #BFBAC9;
  --form-line: rgb(245 241 250 / .17);
  padding: clamp(22px, 3vw, 36px);
  gap: 30px 20px;
  border: 1px solid var(--form-line);
  border-radius: 24px;
  background: #23232C;
  color: var(--form-ink);
  box-shadow: 0 28px 60px -40px rgb(15 10 25 / .6);
}
.form--playful:has(.check:nth-child(2) input:checked) { --form-accent: #FFB99C; }
.form--playful:has(.check:nth-child(3) input:checked) { --form-accent: #A3DBE8; }
.form--playful:has(.check:nth-child(4) input:checked) { --form-accent: #E6DC95; }
html .form.form--playful .field > label,
html .form.form--playful .fieldset > legend { color: var(--form-muted); font-size: 14px; line-height: 1.6; letter-spacing: 0; }
.form--playful .field__icon { width: 17px; height: 17px; display: inline-block; vertical-align: -.2em; margin-right: 8px; color: var(--form-accent); }
.form--playful .field__status { width: 18px; height: 18px; display: inline-block; vertical-align: -.2em; margin-left: 6px; color: #A9E5C3; opacity: 0; scale: .6; transition: opacity 180ms, scale 250ms cubic-bezier(.2,1.5,.4,1); }
.form--playful .field--ready .field__status { opacity: 1; scale: 1; }
html .form.form--playful .field--focus > label { color: var(--form-accent); }
html .form.form--playful .field input,
html .form.form--playful .field textarea {
  min-height: 54px; padding: 16px;
  background: #1B1B23; color: var(--form-ink);
  border: 1px solid var(--form-line); border-radius: 11px;
  box-shadow: inset 0 2px 4px rgb(0 0 0 / .12);
  transition: border-color 200ms, box-shadow 200ms, background 200ms;
}
html .form.form--playful .field input:hover,
html .form.form--playful .field textarea:hover { border-color: rgb(245 241 250 / .35); }
html .form.form--playful .field input:focus,
html .form.form--playful .field textarea:focus { border-color: var(--form-accent); box-shadow: 0 0 0 3px color-mix(in srgb, var(--form-accent) 16%, transparent); transform: none; }
html .form.form--playful .field textarea { min-height: 155px; }
html .form.form--playful .field input::placeholder,
html .form.form--playful .field textarea::placeholder { color: #95909F; opacity: 1; }
html .form.form--playful .field--error input,
html .form.form--playful .field--error textarea { border-color: #FFA9AA; box-shadow: 0 0 0 3px rgb(255 169 170 / .1); }
html .form.form--playful .field__error { color: #FFA9AA; }
html .form.form--playful .form__note { color: var(--form-muted); font-size: 14px; line-height: 1.8; }
html .form.form--playful .form__status { color: var(--form-accent); }
html .form.form--playful .checks { gap: 12px; grid-template-columns: repeat(2, minmax(0, 1fr)); }
html .form.form--playful .checks .check {
  --choice-color: #C7A0FF;
  display: grid; grid-template-columns: 32px minmax(0, 1fr); gap: 12px;
  min-height: 90px; padding: 18px 22px 18px 16px;
  border: 1px solid var(--form-line); border-radius: 14px;
  background: #2D2C37; color: var(--form-ink);
  box-shadow: 0 4px 0 #18181F;
  transition: transform 250ms cubic-bezier(.2,1.4,.4,1), background 220ms, border-color 180ms, box-shadow 200ms;
}
html .form.form--playful .checks .check:nth-child(2) { --choice-color: #FFB99C; }
html .form.form--playful .checks .check:nth-child(3) { --choice-color: #A3DBE8; }
html .form.form--playful .checks .check:nth-child(4) { --choice-color: #E6DC95; }
.form--playful .check__icon { width: 30px; height: 30px; color: var(--choice-color); transition: transform 350ms cubic-bezier(.2,1.4,.4,1), color 180ms; }
.form--playful .check__text { font-size: 14px; line-height: 1.4; font-weight: 500; }
.form--playful .check__tick { position: absolute; right: 7px; top: 7px; width: 14px; height: 14px; opacity: 0; scale: .3; transition: opacity 150ms, scale 250ms cubic-bezier(.2,1.5,.4,1); }
html .form.form--playful :is(.check, .budget-choice) > input {
  position: absolute; inset: 0; width: 100%; height: 100%; min-height: 0;
  margin: 0; opacity: 0; cursor: pointer; z-index: 2;
}
html .form.form--playful .checks .check:has(input:checked) { background: var(--choice-color); color: #25212D; border-color: var(--choice-color); box-shadow: 0 4px 0 color-mix(in srgb, var(--choice-color) 40%, #18181F); }
.form--playful .check:has(input:checked) .check__icon { color: #25212D; transform: rotate(-8deg) scale(1.08); }
.form--playful .check:has(input:checked) .check__tick { opacity: 1; scale: 1; }
html .form.form--playful :is(.check, .budget-choice):has(input:focus-visible) { outline: 2px solid var(--form-accent); outline-offset: 4px; }
html .form.form--playful .checks .check:active { transform: translateY(4px) scale(.98); box-shadow: 0 0 0 #18181F; }
.budget-picker { min-width: 0; }
.budget-choices { display: flex; flex-wrap: wrap; gap: 10px; }
.budget-choice {
  position: relative; flex: 1 1 118px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px;
  padding: 15px 8px; min-height: 90px;
  border: 1px solid var(--form-line); border-radius: 12px;
  background: #2D2C37; color: var(--form-ink); box-shadow: 0 3px 0 #18181F;
  cursor: pointer;
  transition: transform 220ms cubic-bezier(.2,1.4,.4,1), background 180ms, border-color 180ms, box-shadow 180ms;
}
.budget-choice__level { display: flex; align-items: flex-end; justify-content: center; gap: 3px; height: 14px; color: var(--form-accent); }
.budget-choice__level i { display: block; height: 6px; width: 4px; border-radius: 2px; background: currentColor; }
.budget-choice__level i:nth-child(2) { height: 10px; }
.budget-choice__level i:nth-child(3) { height: 14px; }
.budget-choice__price { font-size: 14px; font-weight: 500; white-space: nowrap; }
.budget-choice__price small { display: block; margin-top: 5px; font-size: 12px; font-weight: 400; text-align: center; color: var(--form-muted); }
.budget-choice:has(input:checked) { border-color: var(--form-accent); background: color-mix(in srgb, var(--form-accent) 13%, #23232C); box-shadow: 0 3px 0 color-mix(in srgb, var(--form-accent) 45%, #18181F); }
.budget-choice:active { transform: translateY(3px) scale(.98); box-shadow: none; }
.budget-skip { display: flex; align-items: center; gap: 8px; min-height: 44px; width: fit-content; color: var(--form-muted); font-size: 14px; cursor: pointer; }
.budget-skip input { width: 16px; height: 16px; margin: 0; accent-color: var(--form-accent); }
html .form.form--playful .btn--solid { background: var(--form-accent); color: #25212D; min-height: 54px; gap: 14px; border-radius: 12px; box-shadow: 0 4px 0 color-mix(in srgb, var(--form-accent) 40%, #18181F); }
html .form.form--playful .btn--solid:active { transform: translateY(4px); box-shadow: none; }
.form__send-icon { width: 20px; height: 20px; transition: transform 300ms cubic-bezier(.2,1.4,.4,1); }
.form--playful .btn:hover .form__send-icon, .form--playful .btn:focus-visible .form__send-icon { transform: translate(2px, -2px) rotate(-7deg); }
@media (hover: hover) {
  html .form.form--playful .checks .check:hover { border-color: var(--choice-color); transform: translateY(-3px); }
  html .form.form--playful .checks .check:active { transform: translateY(4px) scale(.98); }
  .form--playful .check:hover .check__icon { transform: rotate(-8deg) scale(1.08); }
  .budget-choice:hover { border-color: var(--form-accent); transform: translateY(-2px); }
  .budget-choice:active { transform: translateY(3px) scale(.98); }
}
@media (max-width: 479px) {
  html .form.form--playful .checks .check { grid-template-columns: minmax(0, 1fr); gap: 12px; padding: 16px 12px; }
  html .form.form--playful { padding-inline: 20px; }
}
@media (prefers-reduced-motion: reduce) {
  .brand-studio__assembly { transform: none; transition: none; }
  .form--playful *, .form--playful *::before, .form--playful *::after { animation: none !important; transition: none !important; }
}

/* --- 51. Reading rhythm -------------------------------------------------
   Chapter headings, coloured marginal notes and native disclosures give
   long-form copy several scales without taking it out of the document. */
.story {
  --reading-ink: var(--text);
  --reading-muted: var(--text-dim);
  --reading-rule: var(--rule);
  --reading-wash: rgb(var(--ink-rgb) / 0.035);
  --reading-accent: var(--accent);
  row-gap: 36px;
}
.band--sky .story {
  --reading-ink: #F5EFFF;
  --reading-muted: #DFD5EB;
  --reading-rule: rgb(232 210 255 / 0.22);
  --reading-wash: rgb(232 210 255 / 0.065);
  --reading-accent: #D8B2FF;
}
.story__aside { min-width: 0; }
.story__index {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-bottom: 24px;
  color: var(--reading-muted);
  font: 400 0.75rem/1 var(--font-mono);
  letter-spacing: 0.06em;
}
.story__index::after { content: ""; width: 48px; height: 1px; background: var(--reading-accent); }
.story__aside > .display { max-width: 19ch; color: var(--reading-ink); }
.story__aside > .h-1 { font-size: clamp(2.1rem, 3.5vw, 3.3rem); line-height: 1.12; }
.story__body {
  min-width: 0;
  padding-top: 34px;
  border-top: 1px solid var(--reading-rule);
  color: var(--reading-muted);
}
.story .story__body > p {
  max-width: 60ch;
  color: var(--reading-muted);
  font-size: 1.0625rem;
  line-height: 1.85;
}
.story .story__body > p + p { margin-top: 24px; }
.story .story__body > p:first-child:not(.micro) {
  color: var(--reading-ink);
  font-size: clamp(1.2rem, 1.6vw, 1.4rem);
  line-height: 1.65;
  letter-spacing: -0.015em;
}
.story .story__body > p.micro {
  margin-top: 32px;
  padding-top: 20px;
  border-top: 1px solid var(--reading-rule);
  font-size: 0.8125rem;
  line-height: 1.75;
}
.story__body > .label {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 44px;
  margin-bottom: 18px;
  color: var(--reading-ink);
  font-size: 0.875rem;
}
.story__body > .label::before { content: ""; width: 6px; height: 6px; flex: 0 0 6px; border-radius: 50%; background: var(--reading-accent); }
.story__body > p:has(> .link:only-child) { margin-top: 28px; font-size: 1rem; }
.story__body > p:has(> .link:only-child) .link { display: inline-block; padding-block: 8px; }

/* A small paper note lends the supporting sentence a different voice. */
html .pull.quote-card {
  position: relative;
  margin: 32px 0 0;
  max-width: 34ch;
  padding: clamp(24px, 3vw, 36px);
  border: 0;
  border-left: 3px solid #AF81D3;
  border-radius: 2px 18px 18px 2px;
  background: #E2CEF4;
  color: #34213D;
  box-shadow: none;
  font: italic 400 clamp(1.5rem, 2.15vw, 2rem)/1.35 Georgia, 'Times New Roman', serif;
  letter-spacing: -0.025em;
  text-wrap: pretty;
}
html .pull.quote-card p { margin: 0; max-width: none; color: #34213D; font: inherit; letter-spacing: inherit; }
.story__body > .quote-card { margin-block: 36px 0; }

/* Specifications remain native HTML: Tab to a label, then Enter or Space.
   The first item starts open. Readers can keep several explanations open. */
.spec.spec--disclosures { gap: 10px; margin-block: 30px; }
.spec.spec--disclosures > li { display: block; padding: 0; border: 0; }
.text-detail {
  border: 1px solid var(--reading-rule, var(--rule));
  border-radius: 12px;
  background: var(--reading-wash, var(--surface));
  overflow: clip;
  transition: border-color 180ms ease, background 180ms ease;
}
.text-detail[open] { border-color: var(--reading-accent, var(--accent)); }
.text-detail summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  min-height: 68px;
  padding: 18px 22px;
  list-style: none;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}
.text-detail summary::-webkit-details-marker { display: none; }
.text-detail summary::marker { content: ""; }
.spec--disclosures .text-detail summary > span {
  order: 0;
  background: none;
  color: var(--reading-ink, var(--text));
  font: 500 1rem/1.5 var(--font-ui);
  letter-spacing: -0.01em;
  text-transform: none;
  overflow-wrap: anywhere;
}
.text-detail__toggle {
  position: relative;
  display: block;
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  border-radius: 50%;
  color: #34213D;
  background: #E2CEF4;
  transition: transform 180ms ease;
}
.text-detail__toggle::before, .text-detail__toggle::after {
  content: "";
  position: absolute;
  inset: 13px 8px;
  height: 2px;
  background: currentColor;
  border-radius: 1px;
}
.text-detail__toggle::after { transform: rotate(90deg); transition: transform 180ms ease; }
.text-detail[open] .text-detail__toggle::after { transform: rotate(0deg); }
.text-detail summary:active .text-detail__toggle { transform: scale(0.88); }
.text-detail summary:focus-visible { outline: 2px solid var(--reading-accent, var(--accent)); outline-offset: -5px; border-radius: 10px; }
.text-detail__body { padding: 0 22px 24px; }
.story .text-detail__body p { color: var(--reading-muted); font-size: 1rem; line-height: 1.8; }

/* Long inventories read as rows, with enough room for full sentences. */
.creds.creds--readable {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0 36px;
  margin-top: 32px;
}
.creds.creds--readable > li {
  position: relative;
  min-width: 0;
  padding: 20px 8px 20px 26px;
  border: 0;
  border-top: 1px solid var(--reading-rule, var(--rule));
  border-radius: 0;
  background: none;
  box-shadow: none;
  color: var(--reading-muted, var(--text-dim));
  font: 400 1rem/1.65 var(--font-ui);
}
.creds--readable > li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 29px;
  width: 6px;
  height: 6px;
  border: 1px solid var(--reading-accent, var(--accent));
  transform: rotate(45deg);
}
.creds.creds--readable > li:hover { transform: none; border-color: var(--reading-rule, var(--rule)); }
.story__body .creds.creds--readable { grid-template-columns: minmax(0, 1fr); margin-block: 28px; }
.qs.qs--editorial { gap: 0; margin-block: 28px; }
.qs.qs--editorial > li {
  position: relative;
  margin: 0;
  padding: 19px 16px 19px 30px;
  border: 0;
  border-top: 1px solid var(--reading-rule, var(--rule));
  border-radius: 0;
  background: none;
  color: var(--reading-ink, var(--text));
  font-size: 1.0625rem;
  line-height: 1.65;
}
.qs.qs--editorial > li::before {
  content: "";
  position: absolute;
  top: 32px;
  left: 0;
  width: 12px;
  height: 2px;
  background: var(--reading-accent, var(--accent));
}
.qs.qs--editorial > li:last-child { border-bottom: 1px solid var(--reading-rule, var(--rule)); }
/* A body that opens with a ruled list keeps that list's own first rule,
   rather than stranding a second line above it. */
.story__body:has(> .qs.qs--editorial:first-child),
.story__body:has(> .creds.creds--readable:first-child) { padding-top: 0; border-top: 0; }
.story__body > .qs.qs--editorial:first-child,
.story__body > .creds.creds--readable:first-child { margin-top: 0; }

@media (min-width: 1000px) {
  .band__grid.story { grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr); column-gap: clamp(48px, 7vw, 112px); }
  .section > .story:has(.story__body > :nth-child(5)) > .story__aside { position: sticky; top: calc(var(--header-h) + 36px); }
}
@media (hover: hover) {
  .text-detail summary:hover { background: var(--reading-wash, var(--surface)); }
}
@media (max-width: 999px) {
  .story { row-gap: 32px; }
  .story__aside > .display { max-width: 25ch; }
  .story__body { padding-top: 28px; }
  .story__aside > .quote-card { max-width: 40ch; margin-top: 28px; }
}
@media (max-width: 639px) {
  .story__index { margin-bottom: 20px; }
  .story .story__body > p { font-size: 1rem; line-height: 1.8; }
  .story .story__body > p:first-child:not(.micro) { font-size: 1.1875rem; }
  .story .story__body > p.micro { font-size: 0.8125rem; }
  .text-detail summary { padding: 16px; min-height: 64px; gap: 12px; }
  .text-detail__body { padding: 0 16px 20px; }
  .creds.creds--readable { grid-template-columns: minmax(0, 1fr); }
}
@media (prefers-reduced-motion: reduce) {
  .text-detail,
.text-detail__toggle,
.text-detail__toggle::after { transition: none; }
}
@media print {
  .story { display: block; }
  .story__aside { position: static !important; }
  .text-detail > .text-detail__body { display: block; }
  .text-detail::details-content { content-visibility: visible; }
  .text-detail__toggle { display: none; }
}

/* Responsive image sources retain the exact gallery frame. */
.book__page picture { display: block; width: 100%; height: 100%; }
@media (min-width: 1000px) and (pointer: fine) {
  .band__grid.story--shifted { grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr); }
  .story--shifted > .story__body { margin-top: 72px; }
  .story__aside > .quote-card--break { width: calc(100% + 40px); max-width: none; margin-left: -12px; }
  .story__body > .quote-card--break { width: calc(100% + 64px); max-width: none; margin-left: -64px; }
}

@media (max-width: 1099px) {
  .header { padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px); }
  .header__inner { align-items: center; gap: 8px; }
  .brand,
  .lang,
  .nav-toggle,
  .navx-trigger {
    height: 44px;
    min-height: 44px;
    box-sizing: border-box;
  }
  .navx-trigger { gap: 0; padding-inline: 16px; }
  .page-hero__copy .lede,
  .page-hero .h-1,
  .page-hero .h-hero { max-width: none; }
  .page-head.page-hero { padding-block: 48px 28px; }
  .page-head.page-hero--object > .page-art,
  .page-head.page-hero--object > .markfield {
    justify-self: start;
    margin-inline: 0;
  }
}

.band:has(.story-deck),
.band.scroll-chapter {
  overflow: visible;
}

@media (max-width: 639px) {
  .hero { min-height: 0; padding-block: 40px 32px; }
  .hero__cta { width: 100%; }
  .hero__cta .btn { justify-content: center; }
  .page-hero__copy,
  .page-hero__copy .lede { max-width: none; }
  .footer {
    margin-inline: var(--gutter);
    border-radius: 16px;
  }
  .sound-control { right: max(12px, env(safe-area-inset-right, 0px)); }
  .install-control { left: max(12px, env(safe-area-inset-left, 0px)); right: auto; }
}

/* ==========================================================================
   Hayanezu — motion.css
   Every transition, keyframe and animation on the site lives here.
   The whole file is neutralised by the block at the bottom under
   `prefers-reduced-motion: reduce`. Nothing here carries meaning on its own.

   The hero's atmosphere is defined entirely in this file and main.css: no
   canvas, no JavaScript, nothing to boot. Everything animates transform and
   opacity only.
   ========================================================================== */

/* --- Transitions ---------------------------------------------------------- */

.nav__link::after { transition: transform var(--d-fast) var(--e-out); }

.link, .nav__link, .brand__word, .brand .mark, .lang a,
.footer a, .index__meta, .check, .nav-toggle, .view-toggle button, .word,
.field input, .field select, .field textarea, .field label {
  transition: color var(--d-fast) var(--e-out),
              background-color var(--d-fast) var(--e-out),
              border-color var(--d-fast) var(--e-out),
              box-shadow var(--d-fast) var(--e-out);
}
.brand .mark { transition: transform var(--d-mid) var(--e-soft), filter var(--d-mid) var(--e-out); }
.brand:hover .mark,
.brand:focus-visible .mark {
  transform: translateY(-1px) rotate(-4deg) scale(1.06);
  filter: drop-shadow(0 0 13px rgb(var(--accent-rgb) / 0.52));
}

.btn { transition: transform var(--d-fast) var(--e-out),
                   border-color var(--d-fast) var(--e-out),
                   box-shadow var(--d-mid) var(--e-out); }

/* visibility animates DISCRETELY — it flips at the END of its duration — so
   `visibility var(--d-mid)` delayed the panel becoming visible AND focusable
   by 380ms after it opened, while nav.js moves focus to the first item at
   220ms. The focus call landed on nothing and the keyboard was stranded on
   the trigger.

   The correct idiom is asymmetric: flip visibility immediately when opening,
   and hold it until the fade finishes when closing, which is the only thing
   the transition was ever for. */
.nav {
  transition: opacity var(--d-mid) var(--e-out),
              visibility 0s linear var(--d-mid);
}
body.nav-open .nav {
  transition: opacity var(--d-mid) var(--e-out),
              visibility 0s linear 0s;
}
.navx, .navx__curtain {
  transition: opacity var(--d-mid) var(--e-out),
              visibility 0s linear var(--d-mid);
}
html.navx-open .navx,
html.navx-open .navx__curtain {
  transition: opacity var(--d-mid) var(--e-out),
              visibility 0s linear 0s;
}

/* The index row lifts towards the viewer on hover. It is a translateZ inside
   the list's own perspective, so the row nearest the vanishing point grows
   least and the geometry does the easing for us — a plain scale() would
   treat every row identically and read as a hover state rather than depth. */
.index__link { transition: transform var(--d-mid) var(--e-soft); }
.index__link:hover, .index__link:focus-visible { transform: translateZ(34px); }

/* --- Reveal on scroll ----------------------------------------------------- */
/* `.reveal` is added by main.js; without JS the content is simply visible.
   A calm rise, in keeping with the rest: nothing here should feel urgent. */

.reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity var(--d-slow) var(--e-soft), transform var(--d-slow) var(--e-soft);
}
.reveal.is-in { opacity: 1; transform: none; }

/* --- Accent rule ---------------------------------------------------------- */

@keyframes rule-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.shot-rule { animation: rule-draw 900ms var(--e-soft) 200ms both; }
.hero .shot-rule,
.page-hero .shot-rule,
.page-head .shot-rule {
  display: none;
  animation: none;
}

/* --- Hero title warp ----------------------------------------------------- */
/* Two lines arrive from deep behind the page with a brief horizontal stretch,
   then settle crisply into the typography. The wake and bloom exist for less
   than a second: enough to say "warp", not enough to compete with the copy. */

.title-warp .warp-line { opacity: 1; filter: none; transform: none; }
.title-warp.is-ready .warp-line { opacity: 1; }
.title-warp.is-entered .warp-line {
  animation: title-warp-in 460ms cubic-bezier(0.16, 0.84, 0.18, 1) both;
}
.title-warp.is-entered .warp-line:nth-child(2) { animation-delay: 60ms; }

@keyframes title-warp-in {
  0% {
    opacity: 1;
    filter: none;
    transform: translate3d(-12px, 8px, 0);
  }
  100% {
    opacity: 1;
    filter: none;
    transform: none;
    text-shadow: none;
  }
}

.title-warp__wake,
.title-warp.is-entered .title-warp__wake {
  display: none;
  animation: none;
}
@keyframes title-wake {
  0%   { opacity: 0; transform: translate3d(-20%, 0, 0) scaleX(0.04); }
  28%  { opacity: 0.7; }
  100% { opacity: 0; transform: translate3d(30%, 0, 0) scaleX(1.18); }
}

.title-warp.is-entered .title-warp__flash {
  animation: title-flash 720ms var(--e-out) 70ms both;
}
@keyframes title-flash {
  0%, 100% { opacity: 0; transform: scale(0.72); }
  34%      { opacity: 1; transform: scale(1); }
}

/* Re-time the rule as the clean final beat of the homepage title. */
.title-warp.is-ready + .shot-rule { animation: none; transform: scaleX(0); }
.title-warp.is-entered + .shot-rule {
  animation: rule-draw 680ms var(--e-soft) 480ms both;
}

/* --- The aurora ----------------------------------------------------------- */
/* Five washes on long, mutually prime cycles, so the sky never repeats a
   composition you have already seen. Slow enough to be atmosphere rather
   than animation — you should notice it has changed, not watch it change. */

@keyframes drift-a {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(6%, 4%, 0) scale(1.12); }
}
@keyframes drift-b {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1.06); }
  50%      { transform: translate3d(-7%, 6%, 0) scale(1); }
}
@keyframes drift-c {
  0%, 100% { transform: translate3d(0, 0, 0) scale(1); }
  50%      { transform: translate3d(-5%, -6%, 0) scale(1.1); }
}

.aurora__blob--1 { animation: drift-a 31s var(--e-io) infinite; }
.aurora__blob--2 { animation: drift-b 43s var(--e-io) infinite; }
.aurora__blob--3 { animation: drift-c 37s var(--e-io) infinite; }
.aurora__blob--4 { animation: drift-a 53s var(--e-io) infinite reverse; }
.aurora__blob--5 { animation: drift-b 29s var(--e-io) infinite; }
.aurora--quiet .aurora__blob--3 { animation-duration: 51s; }

/* --- Motes ---------------------------------------------------------------- */
/* The one fast thing left. Each mote is still for most of its cycle, then
   crosses in about half a second — quick, but the size of a crumb. This is
   the speed cue the direction keeps, at the volume the reference would. */

@keyframes mote-dash {
  0%,  86%  { transform: translate3d(0, 0, 0); opacity: 0; }
  88%       { opacity: 0; }
  90%       { opacity: 1; }
  99%       { opacity: 0; }
  100%      { transform: translate3d(var(--dx, 320px), var(--dy, -40px), 0); opacity: 0; }
}
.mote { animation: mote-dash var(--dur, 9s) var(--e-io) infinite; }

/* --- Loader --------------------------------------------------------------- */

.loader { transition: opacity var(--d-mid) var(--e-out); }
.loader.is-out { opacity: 0; }

@keyframes loader-mark-in {
  from { opacity: 0; transform: scale(0.9); }
  to   { opacity: 1; transform: none; }
}
.loader__mark { animation: loader-mark-in 620ms var(--e-soft) both; }

@keyframes bloom-breathe {
  0%, 100% { transform: scale(0.94); opacity: 0.8; }
  50%      { transform: scale(1.06); opacity: 1; }
}
.loader__bloom { animation: bloom-breathe 2.4s var(--e-io) infinite; }

/* --- Ticker --------------------------------------------------------------- */
/* The track holds the same list twice; shifting it by exactly half its width
   lands the second copy where the first began, so the loop has no seam. */

@keyframes ticker-run {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.ticker__track { animation: ticker-run 52s linear infinite; }
.ticker:hover .ticker__track { animation-play-state: paused; }

/* --- The rabbit hole ------------------------------------------------------ */
/* /websites/ page head. The timing function on these is an EASE-IN — slow
   while far away, fast as it passes — because that is what falling feels
   like. A linear tunnel is a screensaver; the acceleration is the whole
   effect. See section 45 of main.css. */

@keyframes rabbit-fall {
  0%   { transform: translateZ(-1800px) rotate(0deg)  scale(0.9); opacity: 0; }
  14%  { opacity: 0.85; }
  72%  { transform: translateZ(-360px)  rotate(26deg) scale(1);   opacity: 0.6; }
  100% { transform: translateZ(500px)   rotate(52deg) scale(1.1); opacity: 0; }
}

/* The website rides the same tunnel, but holds near the middle long enough
   to be read as a page before it is pulled through. That pause is the
   "attracting" half — without it there is nothing to fall towards. */
@keyframes rabbit-page {
  0%   { transform: translateZ(-1500px) rotateZ(-6deg); opacity: 0; }
  20%  { opacity: 1; }
  58%  { transform: translateZ(-330px)  rotateZ(-1deg); opacity: 1; }
  76%  { transform: translateZ(-150px)  rotateZ(1deg);  opacity: 0.95; }
  100% { transform: translateZ(620px)   rotateZ(9deg);  opacity: 0; }
}

/* The hole breathes, so the vanishing point is alive rather than a dot. */
@keyframes rabbit-core {
  0%, 100% { opacity: 0.6; transform: translateZ(-560px) scale(0.92); }
  50%      { opacity: 1;   transform: translateZ(-560px) scale(1.12); }
}

/* --- The service scenes --------------------------------------------------- */
/* The three panels under "What we do". All of their idle motion is here, so
   it costs nothing per frame and the block at the bottom of this file stops
   it dead. Slow on purpose: these sit beside body copy, and anything quick
   next to a paragraph is something you have to look away from to read. */

/* The mark turns through +/-38 degrees and comes back. It does NOT go all the
   way round, and that is a branding decision rather than a technical one: past
   90 degrees you are looking at the back of the mask, which is the mark
   MIRRORED. Showing a company's mark in reverse for half of every cycle is the
   one thing a page selling identity work must not do. Thirty-eight degrees is
   enough to see the extrusion and read the object as solid, and the mark is
   the right way round at every frame. */
@keyframes scene-turn {
  0%, 100% { transform: rotateY(-38deg) rotateX(10deg); }
  50%      { transform: rotateY(38deg)  rotateX(4deg); }
}

/* The page draws apart into its layers and settles back into one flat page.
   The pause at the ends is the point: it is a page most of the time and a
   stack of layers briefly, not a permanently exploded diagram. */
@keyframes scene-assemble {
  0%, 18%   { transform: rotateY(-24deg) rotateX(13deg) scale(0.96); }
  46%, 62%  { transform: rotateY(-8deg)  rotateX(4deg)  scale(1); }
  100%      { transform: rotateY(-24deg) rotateX(13deg) scale(0.96); }
}

/* Both together: one slow orbit, so the mark passes in front of the page it
   is applied to and the two read as one arrangement. */
@keyframes scene-orbit {
  from { transform: rotateY(-18deg) rotateX(8deg); }
  50%  { transform: rotateY(18deg)  rotateX(-4deg); }
  to   { transform: rotateY(-18deg) rotateX(8deg); }
}

/* --- Nav panel items ------------------------------------------------------ */
/* The six links arriving from deep perspective on a stagger, below 760px.
   An animation rather than a transition, so the menu's resting state is
   "present" and this is decoration over it — see the note in main.css. */

@keyframes nav-item-in {
  from { transform: translate3d(0, 12px, 0); }
  to   { transform: translate3d(0, 0, 0); }
}

/* --- Drift view ----------------------------------------------------------- */
/* .word.is-out is gone with the effect that used it: clicking a word no
   longer throws the other thirteen 900px off-screen and teleports them home.
   The words are simulated now, so nothing about them is a transition —
   drift.js writes their transforms every frame. See the note there. */

/* ==========================================================================
   Reduced motion — the off switch.
   Under this query the site is a clean, static, fully usable page: no loader,
   no drifting sky, no motes, no reveals, no scene or Drift pointer physics.
   The mouse-head pointer itself still tracks direct input; main.js keeps the
   motion-heavy subscribers switched off.

   The aurora itself STAYS — it is a still image of a sky, and a still image
   is not motion. Only its drift stops.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
    scroll-behavior: auto !important;
  }

  .reveal { opacity: 1; transform: none; }
  .shot-rule { animation: none; transform: none; }
  .title-warp.is-ready .warp-line { opacity: 1; filter: none; transform: none; }
  .title-warp__wake, .title-warp__flash { display: none; }
  .aurora__blob { animation: none; }
  .page-hero__cue::before { animation: none; }
  .mote { display: none; }
  /* The stage keeps its depth but stops responding to the pointer — scene.js
     reads the same query and never subscribes. */
  .hero__scene { transform: none; }
  .ticker__track { animation: none; }
  .loader__mark, .loader__bloom { animation: none; }
  .desk__lid { transform: rotateX(8deg); }
  .desk__typed { width: calc(var(--ch, 10) * 0.62em); }
  .desk__caret { opacity: 0.7; }
  .desk__pointer { opacity: 0; }
  .keep .cube {
    animation: none;
    opacity: 1;
    transform: rotateX(-28deg) rotateY(36deg);
  }
  .cubes { animation: none; transform: none; }
  .page-art--emblem img { animation: none; transform: none; }

  /* Added with the interaction pass. The header still takes its ground and
     the progress line still reports position — both are information about
     where you are, not decoration — but nothing travels, rises or tilts. */
  .display.is-split .ln__i { transform: none; opacity: 1; }
  .stg { opacity: 1; transform: none; }
  .header.is-tucked { transform: none; }
  .progress { transition: none; }
  .project__media { transform: none !important; }
  .project__media::after { display: none; }
  .promise:hover::before,
  .creds li:hover,
  .bucket:hover .bucket__num { transform: none; }
}

/* Project previews. A 2px lift on hover and nothing else — the grid is the
   largest thing on the page and anything more reads as a slideshow. */
.project__media { transition: transform var(--d-mid) var(--e-out); }
.project:hover .project__media,
.project:focus-within .project__media { transform: translateY(-4px); }
@media (prefers-reduced-motion: reduce) {
  .project__media { transition: none; }
  .project:hover .project__media,
  .project:focus-within .project__media { transform: none; }
}

/* --- Header, progress, split lines, stagger -------------------------------- */

.header { transition: transform var(--d-mid) var(--e-out), border-color var(--d-mid) var(--e-out); }
.header::before, .header::after { transition: opacity var(--d-mid) var(--e-out); }
.progress { transition: transform 90ms linear; }

/* Each authored line rises from behind its own mask, one after the next.
   --l is the line index, set by main.js. */
.display.is-split .ln__i {
  transform: none;
  opacity: 1;
  transition: transform 420ms var(--e-soft), opacity 320ms var(--e-out);
  transition-delay: calc(var(--l, 0) * 40ms);
}
.display.is-split.is-lit .ln__i { transform: none; opacity: 1; }

/* Staggered children. The section fades; these travel. */
.stg {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 620ms var(--e-out), transform 620ms var(--e-soft);
  transition-delay: calc(var(--i, 0) * 62ms);
}
[data-reveal].is-in .stg { opacity: 1; transform: none; }

.reveal--group { transform: none; }
.reveal--group.is-in { transform: none; }

/* Surface hovers */
.promise::before { transition: transform var(--d-mid) var(--e-out); }
.creds li { transition: transform var(--d-fast) var(--e-out), border-color var(--d-fast) var(--e-out); }
.qs li { transition: border-left-color var(--d-mid) var(--e-out); }
.bucket__num { transition: transform var(--d-mid) var(--e-out); }
.link { transition: background-size var(--d-mid) var(--e-out), color var(--d-fast) var(--e-out); }
.project__media::after { transition: opacity var(--d-mid) var(--e-out); }
.project__media { transition: box-shadow var(--d-mid) var(--e-out); }

/* The ticker, once scroll.js has taken it over. The CSS marquee is the
   baseline and must stop, or the two would fight over the same transform. */
.ticker.is-live .ticker__track {
  animation: none;
  /* scroll.js drives --tx and --skew. The cylinder rule in main.css replaces
     the skew with a roll on the same two values. */
  transform: translate3d(var(--tx, 0px), 0, 0) skewX(var(--skew, 0deg));
}

/* --- Websites desk: lid opens, page loads, then someone types ----------- */
/* Resting form lives in main.css (lid up, headline complete). This file
   plays the sequence over it. Reduced motion at the bottom of this file
   collapses every animation to 1ms, so the still laptop is what remains. */

@keyframes desk-open {
  from { transform: rotateX(78deg) scaleY(0.18); opacity: 0.4; }
  to   { transform: rotateX(8deg) scaleY(1); opacity: 1; }
}
@keyframes desk-url {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
@keyframes desk-site {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: none; }
}
@keyframes desk-type {
  from { width: 0; }
  to   { width: calc(var(--ch, 10) * 0.62em); }
}
@keyframes desk-caret {
  0%, 46% { opacity: 1; }
  50%, 100% { opacity: 0; }
}
@keyframes desk-copy {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: none; }
}
@keyframes desk-pointer {
  0%   { opacity: 0; transform: translate(72%, 18%); }
  12%  { opacity: 1; transform: translate(64%, 16%); }
  28%  { opacity: 1; transform: translate(14%, 34%); }
  72%  { opacity: 1; transform: translate(calc(14% + var(--ch, 10) * 3.2%), 34%); }
  86%  { opacity: 1; transform: translate(22%, 72%); }
  100% { opacity: 1; transform: translate(22%, 72%); }
}
@keyframes desk-keys {
  0%, 100% { opacity: 0.35; filter: brightness(1); }
  8%, 16%, 30%, 42%, 54%, 66% { opacity: 1; filter: brightness(1.55); }
  12%, 24%, 36%, 48%, 60%, 80% { opacity: 0.4; filter: brightness(1); }
}

.desk__lid {
  animation: desk-open 1180ms var(--e-out) 80ms both;
}
.desk__url-fill {
  transform-origin: 0 50%;
  animation: desk-url 620ms var(--e-soft) 980ms both;
}
.desk__shot {
  animation: desk-site 720ms var(--e-soft) 1180ms both;
}
.desk__site {
  animation: desk-site 520ms var(--e-soft) 1180ms both;
}
.desk__typed {
  width: 0;
  animation: desk-type 1680ms steps(12, end) 1880ms both;
}
.desk__caret {
  opacity: 0;
  animation: desk-caret 1s steps(1) 1880ms infinite;
}
.desk__copy,
.desk__btn {
  animation: desk-copy 480ms var(--e-soft) 3680ms both;
}
.desk__pointer {
  opacity: 0;
  animation: desk-pointer 4.6s var(--e-soft) 1.15s both;
}
.desk__keys {
  animation: desk-keys 1.7s var(--e-io) 1.88s 1;
}

/* --- Contact keep: cubes fall into a gatehouse ------------------------- */
/* Resting pose is the isometric cube. The drop is a translate in front
   of that rotation, so the faces stay a cube on the way down. */

@keyframes keep-drop {
  from {
    opacity: 0;
    transform:
      translateY(-200px)
      rotateX(-28deg) rotateY(36deg)
      rotateZ(var(--spin, 8deg));
  }
  72% {
    opacity: 1;
    transform:
      translateY(6px)
      rotateX(-28deg) rotateY(36deg)
      rotateZ(calc(var(--spin, 8deg) * 0.12));
  }
  86% {
    transform:
      translateY(-3px)
      rotateX(-28deg) rotateY(36deg);
  }
  to {
    opacity: 1;
    transform: rotateX(-28deg) rotateY(36deg);
  }
}

.keep .cube {
  animation: keep-drop 640ms var(--e-out) calc(160ms + var(--i, 0) * 130ms) both;
}

@keyframes cubes-idle {
  from { transform: translateY(0) rotateY(-7deg); }
  50%  { transform: translateY(-8px) rotateY(7deg); }
  to   { transform: translateY(0) rotateY(-7deg); }
}
.cubes {
  animation: cubes-idle 8.5s var(--e-io) infinite;
}

@keyframes emblem-float {
  from, to { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}
.page-art--emblem img {
  animation: emblem-float 4.8s var(--e-io) infinite;
}

/* Spatial experience refinements. */
.depth-surface {
  transition: transform 560ms var(--e-soft),
              border-color var(--d-mid) var(--e-out),
              box-shadow 560ms var(--e-out);
}
.depth-surface::after { transition: opacity var(--d-mid) var(--e-out); }
.index__link::after,
.index__meta { transition: opacity var(--d-mid) var(--e-out), transform var(--d-mid) var(--e-soft); }
.sound-control { transition: transform var(--d-fast) var(--e-out), border-color var(--d-mid) var(--e-out), box-shadow var(--d-mid) var(--e-out); }
.sound-control:hover { transform: translateY(-3px); }
.install-control { transition: transform var(--d-fast) var(--e-out), border-color var(--d-mid) var(--e-out), box-shadow var(--d-mid) var(--e-out); }
.install-control:hover { transform: translateY(-3px); }
.install-help { transition: opacity var(--d-mid) var(--e-out), visibility var(--d-mid), transform var(--d-mid) var(--e-soft); }
.field input, .field select, .field textarea {
  transition: border-color var(--d-fast) var(--e-out),
              box-shadow 280ms var(--e-out),
              background-color 280ms var(--e-out),
              transform 280ms var(--e-out);
}
.checks__thumb {
  transition: transform 340ms var(--e-out), width 340ms var(--e-out),
              height 340ms var(--e-out), opacity 200ms var(--e-out);
}
.lang { transition: transform 180ms var(--e-out); }
html.is-inverse .detail,
html.is-inverse .form {
  transition: transform 280ms var(--e-out), box-shadow 280ms var(--e-out);
}
.experience-ready .depth-surface.is-depth-active,
.experience-ready [data-reveal].is-in .depth-surface.is-depth-active {
  transform: perspective(1100px) rotateX(var(--depth-rx, 0deg)) rotateY(var(--depth-ry, 0deg)) translateZ(8px);
}

@keyframes cue-pulse {
  0%, 100% { transform: scaleY(1); opacity: 0.65; }
  50% { transform: scaleY(1.22); opacity: 1; }
}
.page-hero__cue::before { animation: cue-pulse 2.6s var(--e-io) infinite; }

@keyframes found-in {
  from { opacity: 0; transform: translateY(28px) rotate(calc(var(--r, 0deg) - 10deg)); }
  to   { opacity: 1; transform: rotate(var(--r, 0deg)); }
}
@keyframes deal-in {
  from { opacity: 0; transform: translate3d(-18px, 14px, 0) rotate(-8deg); }
  to   { opacity: 1; transform: none; }
}

/* Surface finishes share the same layout, palette, content and hero artwork. */
.site-controls,
.finish-control,
.sound-control { display: none !important; }
.site-controls {
  position: fixed;
  right: max(clamp(16px, 2vw, 28px), env(safe-area-inset-right));
  bottom: max(clamp(16px, 2vw, 28px), env(safe-area-inset-bottom));
  z-index: 120;
  display: flex;
  align-items: center;
  gap: 10px;
}
.site-controls .sound-control { position: static; flex: 0 0 auto; }
.finish-control {
  display: flex;
  flex-wrap: wrap;
  min-width: 0;
  gap: 2px;
  padding: 3px;
  border: 1px solid rgb(255 255 255 / 0.2);
  border-radius: 999px;
  background: #25232C;
  box-shadow: 0 12px 32px -16px rgb(0 0 0 / 0.7), inset 0 1px 0 rgb(255 255 255 / 0.12);
}
.finish-control button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 44px;
  padding: 8px 13px;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: #E8E1EF;
  font: 500 0.875rem/1.2 var(--font-ui);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 180ms ease, color 180ms ease, transform 180ms ease;
}
.finish-control button:hover { background: #3D3448; }
.finish-control button[aria-pressed="true"] { background: #E2CEF4; color: #34213D; }
.finish-control button:active { transform: scale(0.95); }
.finish-control button:focus-visible { outline: 2px solid #F4E8FF; outline-offset: 3px; }
.finish-control__swatch { width: 16px; height: 16px; flex: 0 0 16px; border-radius: 50%; }
.finish-control__swatch--glossy {
  border: 1px solid #C5A4E2;
  background: radial-gradient(circle at 30% 22%, #FFFFFF 0 8%, #D6B3F4 22%, #8050A5 55%, #392044 85%);
  box-shadow: inset -1px -2px 2px rgb(0 0 0 / 0.3);
}
.finish-control__swatch--matte { border: 1px solid #8D6AA6; background: #AF88CE; }
html.navx-open .site-controls { visibility: hidden; pointer-events: none; }

/* Gloss: static, directional reflections across the existing surfaces. */
html[data-finish="glossy"] .grain { opacity: 0.016; }
html[data-finish="glossy"] .promises--editorial > .promise {
  background-image: linear-gradient(145deg, rgb(255 255 255 / 0.14), transparent 35%, rgb(255 255 255 / 0.035) 70%, transparent);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.25), inset 0 -1px 0 rgb(0 0 0 / 0.12), 0 22px 42px -28px rgb(0 0 0 / 0.48);
}
html[data-finish="glossy"] .pull.quote-card {
  background-image: linear-gradient(135deg, rgb(255 255 255 / 0.48), transparent 50%, rgb(255 255 255 / 0.12));
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.7), 0 20px 36px -28px rgb(0 0 0 / 0.42);
}
html[data-finish="glossy"] .text-detail {
  background-image: linear-gradient(125deg, rgb(255 255 255 / 0.07), transparent 55%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.12), 0 10px 28px -24px rgb(0 0 0 / 0.6);
}
html[data-finish="glossy"] :is(.footer, .form--playful) {
  background-image: radial-gradient(ellipse at 15% 0, rgb(201 162 255 / 0.13), transparent 55%), linear-gradient(155deg, rgb(255 255 255 / 0.065), transparent 40%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 0.18), 0 24px 48px -36px rgb(0 0 0 / 0.5);
}
html[data-finish="glossy"] .form.form--playful :is(.check, .budget-choice) {
  background-image: linear-gradient(155deg, rgb(255 255 255 / 0.13), transparent 50%);
}
html[data-finish="glossy"] :is(.finish-control, .site-controls .sound-control, .install-control) {
  background-image: linear-gradient(160deg, rgb(255 255 255 / 0.14), transparent 48%);
}

/* Matte: opaque surfaces, soft grain and a quiet edge instead of reflections. */
html[data-finish="matte"] .grain { opacity: 0.045; }
html[data-finish="matte"] .promises--editorial > .promise:nth-child(3n + 2) { background: #4A3179; }
html[data-finish="matte"] .promises--editorial > .promise:nth-child(3n) { background: #2A3878; }
html[data-finish="matte"] :is(.band:not(.band--sky), .footer, .text-detail, .pull.quote-card, .promises--editorial > .promise, .form--playful) {
  background-image: none;
  box-shadow: none;
}
html[data-finish="matte"] .band--sky { background: var(--sky-2); box-shadow: none; }
html[data-finish="matte"] :is(.brand, .nav-toggle, .lang, .sound-control, .install-control, .install-help, .finish-control) {
  background: var(--ground-2);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  box-shadow: none;
}
html[data-finish="matte"] :is(.sound-control, .install-control, .install-help, .finish-control) { background: #25232C; }
html[data-finish="matte"].is-inverse :is(.brand, .nav-toggle, .lang) { background: var(--shade); }
html[data-finish="matte"] :is(.sound-control__orb, .lang__thumb) { background: var(--accent); box-shadow: none; }
html[data-finish="matte"] .sound-control__orb span { background: var(--shade); }
html[data-finish="matte"] .form.form--playful :is(.check, .budget-choice) { background-image: none; }
@media (min-width: 1100px) {
  html[data-finish="matte"] .nav__list { background: var(--ground-2); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; }
  html[data-finish="matte"].is-inverse .nav__list { background: var(--shade); }
}
@media (max-width: 720px) {
  .site-controls { right: max(12px, env(safe-area-inset-right)); bottom: max(12px, env(safe-area-inset-bottom)); max-width: calc(100vw - 84px - env(safe-area-inset-right)); gap: 8px; }
  .finish-control button { padding-inline: 7px; gap: 6px; }
  .site-controls .sound-control { padding: 4px; min-width: 44px; min-height: 44px; }
  .site-controls .sound-control__copy { display: none; }
  .install-control { padding: 4px; min-width: 44px; min-height: 44px; }
  .install-control > span:last-child { display: none; }
  body { padding-bottom: calc(5rem + env(safe-area-inset-bottom, 0px)); }
}
@media (prefers-reduced-motion: reduce) {
  .finish-control button { transition: none; }
  .finish-control button:active { transform: none; }
}
@media (forced-colors: active) {
  .finish-control { background: Canvas; border-color: ButtonText; box-shadow: none; }
  .finish-control button { color: ButtonText; }
  .finish-control button[aria-pressed="true"] { background: Highlight; color: HighlightText; border-color: ButtonText; }
  .finish-control button:focus-visible { outline-color: Highlight; }
}
@media print { .site-controls { display: none; } }

/* ==========================================================================
   Hayanezu — poster.css
   The poster collage. Replaces editorial.css, which replaced chapters.css.

   WHY THIS EXISTS
   The deck was a slide viewer bolted onto a page. The editorial run that
   replaced it fixed the shuffling but went too quiet: a headword at 5rem, a
   paragraph at 17px thirty centimetres to its right, and a great deal of
   nothing in between. Sparse is not the same as considered.

   WHAT IT IS NOW
   Full-bleed bands, one per movement, alternating ground: near-black, bone,
   and the accent at full strength with dark type on it. Body copy set LARGE —
   the density here comes from type size, not from filling space. Numerals
   outlined rather than filled, bleeding off the band edge. An extruded frame
   stack and a couple of loose dots per band. Punchlines bold inline, key links
   underlined with a drawn wave.

   Two references drove it: a poster-collage site that alternates white / grey
   / black grounds with very large warm body copy and strikethrough jokes, and
   a black-ground studio site with an iridescent gradient sheen. The sheen here
   is a CSS gradient on a long slow transform, not a video — this site claims
   static-first and 0 third-party requests, and a 4MB loop would make both a
   lie.

   MOTION RULES, UNCHANGED
   Nothing reads scrollY. Entry rides main.js's [data-reveal] machinery via the
   .stg class, so there is one reveal system and one reduced-motion early
   return. The only scroll-linked values are two custom properties written by
   poster.js from the existing HZ.scroll subscription, both spent on
   transforms.
   ========================================================================== */

/* --- 1. Band grounds ------------------------------------------------------
   Three rooms. --p-fg and --p-dim are what everything inside a band paints
   with, so a band can change ground without a single rule below it knowing.
   The accent room reuses --shade on the accent, which is the pair the solid
   button already uses and check-contrast.js already measures at 5:1. */

.scroll-chapter .story__aside,
.scroll-chapter .story-card,
.promises--run > .promise {
  --p-bg: #14161B;
  --p-fg: #FFFFFF;
  --p-dim: rgb(255 255 255 / 0.76);
  --p-line: rgb(255 255 255 / 0.20);
  --p-hot: #A8B0F0;
  --p-sheen: 0.5;
}

.is-bone {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.78);
  --p-line: rgb(22 24 27 / 0.20);
  --p-sheen: 0.22;
}

.is-pop {
  --p-bg: var(--p-pop);
  --p-fg: var(--shade);
  --p-dim: rgb(var(--shade-rgb) / 0.82);
  --p-line: rgb(var(--shade-rgb) / 0.30);
  --p-sheen: 0;
}

/* --- 2. The chapter, as a stack of bands ----------------------------------
   The two-column split is gone. A sticky heading beside a scrolling column is
   a magazine layout; this is a poster sequence, and every part of it gets the
   full width. */

.scroll-chapter { position: relative; padding: 0; }
.scroll-chapter .wrap { max-width: none; padding: 0; }
.scroll-chapter .story { display: block; }
.scroll-chapter .story-deck,
.scroll-chapter .story-deck__viewport,
.scroll-chapter .story-deck__track {
  display: block;
  position: static;
  overflow: visible;
  min-width: 0;
  height: auto;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  transform: none;
}

/* The band itself. 100vw out of a centred column, then padded back to the
   text measure — the standard full-bleed escape, safe here because <html>
   carries overflow-x: clip so the extra cannot open a scrollbar. */
.scroll-chapter .story__aside,
.scroll-chapter .story-card {
  position: relative;
  isolation: isolate;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: clamp(52px, 7vw, 112px) max(var(--gutter), calc(50vw - 640px));
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
  background: var(--p-bg);
  color: var(--p-fg);
  /* --py and --pr are written by poster.js. */
  --py: 0;
  --pr: 0;
}

/* The iridescent veil. One wide gradient, larger than the band, moved by the
   same scroll value the numerals use — so a band lit like this shifts hue
   across its own width as it passes rather than sitting there as a static
   wash. Zero opacity in the accent room, where the ground is already the
   colour. */
.scroll-chapter .story__aside::before,
.scroll-chapter .story-card::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -40% -20%;
  pointer-events: none;
  opacity: calc(var(--p-sheen) * 0.5);
  background:
    radial-gradient(38% 60% at 18% 30%, var(--accent), transparent 70%),
    radial-gradient(42% 55% at 78% 66%, var(--accent-2, var(--accent)), transparent 72%);
  filter: blur(38px) saturate(1.3);
  transform: translate3d(0, calc(var(--py) * 1.6px), 0);
}

/* --- 3. The chapter title band -------------------------------------------- */

.scroll-chapter .story__aside {
  --p-bg: var(--p-pop);
  --p-fg: var(--shade);
  --p-dim: rgb(var(--shade-rgb) / 0.82);
  --p-line: rgb(var(--shade-rgb) / 0.30);
  --p-sheen: 0;
  display: grid;
  gap: clamp(18px, 2.4vw, 34px);
  align-content: center;
  min-height: clamp(240px, 34vh, 400px);
}

.scroll-chapter .story__index {
  display: inline-block;
  width: fit-content;
  padding: 6px 12px 5px;
  border: 2px solid currentColor;
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.24em;
  text-indent: 0.24em;
  color: var(--p-fg);
}

.scroll-chapter .story__aside > .display {
  max-width: 18ch;
  margin: 0;
  color: var(--p-fg);
  font-size: clamp(2.25rem, 6.4vw, 5rem);
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: -0.035em;
  text-wrap: balance;
}

/* --- 4. The movements ------------------------------------------------------
   Alternating rooms, and the last band of every chapter takes the accent so a
   sequence ends on colour rather than trailing off. */

.scroll-chapter .story-card:nth-child(even) {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.78);
  --p-line: rgb(22 24 27 / 0.20);
  --p-sheen: 0.22;
}
.scroll-chapter .story-card:last-child {
  --p-bg: var(--p-pop);
  --p-fg: var(--shade);
  --p-dim: rgb(var(--shade-rgb) / 0.82);
  --p-line: rgb(var(--shade-rgb) / 0.30);
  --p-sheen: 0;
}

.scroll-chapter .story-card__content {
  position: relative;
  z-index: 1;
  max-width: none;
}

/* The extruded frame. Two outlined rectangles stepped back from the content,
   the motif the reference uses behind every image. Drawn on the band's own
   pseudo-elements, so it costs no markup, and hidden on narrow screens where
   there is no room to step anything back. */
.scroll-chapter .story-card::after {
  content: "";
  position: absolute;
  z-index: 0;
  right: clamp(-30px, -1.6vw, -8px);
  bottom: clamp(-30px, -2vw, -10px);
  width: clamp(170px, 22vw, 340px);
  aspect-ratio: 3 / 2;
  background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 300 200' fill='none' stroke='%23888' stroke-width='1.4'%3E%3Crect x='60' y='6' width='233' height='150'/%3E%3Crect x='33' y='23' width='233' height='150'/%3E%3Crect x='6' y='40' width='233' height='150'/%3E%3Cpath d='M6 40 60 6M239 40 293 6M6 190 60 156M239 190 293 156'/%3E%3C/svg%3E") center / contain no-repeat;
  opacity: 0.5;
  pointer-events: none;
  transform: translate3d(0, calc(var(--py) * -0.5px), 0) rotate(calc(var(--pr) * 1deg));
}

/* --- 5. The numeral -------------------------------------------------------
   Outlined, not filled — the wireframe language the references keep returning
   to — and set to run off the top edge of its band. */

.scroll-chapter .story-card__number {
  position: absolute;
  z-index: 0;
  top: clamp(-34px, -2vw, -8px);
  right: max(var(--gutter), calc(50vw - 640px));
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(5rem, 15vw, 14rem);
  font-weight: 700;
  line-height: 0.78;
  letter-spacing: -0.06em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--p-line);
  pointer-events: none;
  user-select: none;
  will-change: transform;
  transform: translate3d(0, calc(var(--py) * 1px), 0);
}

/* The loose dots. One ring in the hot accent, one solid — the punctuation both
   references scatter through their compositions. */
.scroll-chapter .story-card__number::before,
.scroll-chapter .story-card__number::after {
  content: "";
  position: absolute;
  border-radius: 50%;
}
.scroll-chapter .story-card__number::before {
  top: 78%;
  left: -46px;
  width: 16px;
  height: 16px;
  border: 2.5px solid var(--p-hot);
}
.scroll-chapter .story-card__number::after {
  top: 96%;
  left: -22px;
  width: 8px;
  height: 8px;
  background: var(--p-fg);
  opacity: 0.7;
}

/* --- 6. The type ----------------------------------------------------------
   Large. This is the correction to the version before: the reference sets its
   running copy at something close to a heading size, and that is what makes a
   plain paragraph hold a full-bleed band on its own. */

.scroll-chapter .story-card p {
  margin: 0;
  max-width: min(40ch, 100%);
  color: var(--p-dim);
  font-size: clamp(1.1875rem, 1.9vw, 1.75rem);
  line-height: 1.48;
  letter-spacing: -0.015em;
}
.scroll-chapter .story-card p + p { margin-top: var(--s-6); }

/* The opening statement of a chapter, at poster size. */
.scroll-chapter .story-card:first-child .story-card__content > p:first-child {
  max-width: min(24ch, 100%);
  color: var(--p-fg);
  font-weight: 700;
  font-size: clamp(1.875rem, 4.6vw, 3.75rem);
  line-height: 0.98;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

/* The punchline device: a bold run inside a paragraph, in full ink rather than
   the dimmed body colour. */
.scroll-chapter .story-card strong,
.promises--run .promise strong { color: var(--p-fg); font-weight: 700; }

.scroll-chapter .story-card p.micro {
  max-width: min(52ch, 100%);
  color: var(--p-dim);
  opacity: 0.72;
  font-size: var(--t-label);
  letter-spacing: 0.14em;
  line-height: 1.7;
}

.scroll-chapter .story-card h3 {
  margin: var(--s-6) 0 var(--s-3);
  color: var(--p-fg);
  font: 700 clamp(1.25rem, 1.8vw, 1.5rem)/1.2 var(--font-display);
  letter-spacing: -0.025em;
}
.scroll-chapter .story-card__content > :first-child { margin-top: 0; }

/* --- 7. Links, with the drawn wave ---------------------------------------- */

.scroll-chapter .story-card .link,
.promises--run .promise .link {
  color: var(--p-fg);
  background: none;
  font-weight: 600;
  text-decoration: none;
  padding-bottom: 6px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='6' viewBox='0 0 24 6'%3E%3Cpath d='M0 3c2-3 4-3 6 0s4 3 6 0 4-3 6 0 4 3 6 0' fill='none' stroke='%23A8B0F0' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: 0 100%;
  background-size: 24px 6px;
  transition: background-position 320ms var(--e-out), color 200ms var(--e-out);
}
.scroll-chapter .story-card .link:hover,
.promises--run .promise .link:hover { background-position: 12px 100%; }

.scroll-chapter .story-card :focus-visible,
.promises--run :focus-visible { outline: 3px solid var(--p-fg); outline-offset: 4px; }

/* --- 8. Lists -------------------------------------------------------------
   Questions and credentials as a ruled run at body size. */

.scroll-chapter .story-card :is(.qs, .creds) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  margin: var(--s-6) 0 0;
  max-width: min(34ch, 100%);
}
.scroll-chapter .story-card :is(.qs, .creds) > li {
  position: relative;
  margin: 0;
  padding: var(--s-5) 0 var(--s-5) var(--s-7);
  border: 0;
  border-top: 1px solid var(--p-line);
  color: var(--p-fg);
  font-size: clamp(1.0625rem, 1.5vw, 1.3125rem);
  line-height: 1.4;
}
.scroll-chapter .story-card :is(.qs, .creds) > li:first-child { border-top: 0; padding-top: 0; }
.scroll-chapter .story-card :is(.qs, .creds) > li::before {
  content: "";
  position: absolute;
  left: 0;
  top: calc(var(--s-5) + 0.55em);
  width: 26px;
  height: 2px;
  background: var(--p-hot);
}
.scroll-chapter .story-card :is(.qs, .creds) > li:first-child::before { top: 0.55em; }

/* The refusals were briefly struck through, one clause each. It read as the
   promise being cancelled rather than the practice being refused, so the
   device is gone and the accent rule at the head of each line carries the
   emphasis on its own. */

/* --- 9. The promises, as poster panels ------------------------------------
   A deliberate composition on twelve columns rather than an auto grid: wide,
   narrow, narrow, wide, so the run reads as a laid-out page. An odd last panel
   takes the full width and closes the block. */

.promises.promises--run,
.promises.promises--run:has(> :last-child:nth-child(4)),
.promises.promises--run:has(> :last-child:nth-child(5)),
.promises.promises--run:has(> :last-child:nth-child(6)) {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: clamp(10px, 1.2vw, 18px);
  margin: clamp(28px, 4vw, 56px) 0 0;
  padding: 0;
  overflow: visible;
  counter-reset: promise;
}

.promises--run > .promise {
  position: relative;
  isolation: isolate;
  display: flex;
  flex-direction: column;
  gap: clamp(12px, 1.6vw, 24px);
  min-height: clamp(190px, 20vw, 280px);
  margin: 0;
  padding: clamp(26px, 3vw, 46px);
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow: hidden;
  background: var(--p-bg);
  color: var(--p-fg);
  counter-increment: promise;
  translate: none;
  scale: none;
  filter: none;
  opacity: 1;
  transition: background-color 420ms var(--e-out), color 420ms var(--e-out);
}

.promises--run > .promise:nth-child(4n + 1) { grid-column: span 7; }
.promises--run > .promise:nth-child(4n + 2) { grid-column: span 5; }
.promises--run > .promise:nth-child(4n + 3) { grid-column: span 5; }
.promises--run > .promise:nth-child(4n + 4) { grid-column: span 7; }
.promises--run > .promise:last-child:nth-child(odd) { grid-column: 1 / -1; }

/* The rooms cycle on three while the widths cycle on four, so the pattern does
   not repeat until the twelfth panel — which no list on this site reaches. */
.promises--run > .promise:nth-child(3n + 2) {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.78);
  --p-line: rgb(22 24 27 / 0.20);
}
.promises--run > .promise:nth-child(3n) {
  --p-bg: var(--p-pop);
  --p-fg: var(--shade);
  --p-dim: rgb(var(--shade-rgb) / 0.82);
  --p-line: rgb(var(--shade-rgb) / 0.30);
}

.promises--run > .promise::before { content: none; }

/* The outlined index, top right, from the counter — no markup, no copy. */
.promises--run .promise__num {
  position: absolute;
  z-index: 0;
  top: auto;   /* main.css pins it to the top; a grid row stretches its short
                  panels, so the figure is better used filling the foot. */
  bottom: clamp(-8px, -0.5vw, 0px);
  right: clamp(12px, 1.6vw, 26px);
  display: block;
  font: 700 clamp(3rem, 5.6vw, 5rem)/1 var(--font-display);
  letter-spacing: -0.05em;
  color: transparent;
  -webkit-text-stroke: 2px var(--p-line);
  opacity: 0.9;
  pointer-events: none;
  transition: -webkit-text-stroke-color 420ms var(--e-out);
}
.promises--run .promise__num::after { content: counter(promise, decimal-leading-zero); }

.promises--run .promise__word {
  position: relative;
  z-index: 1;
  margin: 0;
  color: var(--p-fg);
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 3.4vw, 3rem);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.04em;
  background: none;
  -webkit-text-fill-color: currentColor;
  /* One word, never broken: main.css sets overflow-wrap: break-word on every
     paragraph in a section, which split "Protected." before its full stop. */
  overflow-wrap: normal;
  word-break: keep-all;
  hyphens: none;
}

/* The letter shuffle. poster.js wraps each character so they can leave at
   different moments; the whole word stays in the accessibility tree because
   the spans are aria-hidden and a .visually-hidden copy carries the text. */
.promises--run .promise__word .ch {
  display: inline-block;
  transition: transform 420ms var(--e-out), color 260ms var(--e-out);
  transition-delay: calc(var(--c, 0) * 26ms);
}
.promises--run .promise__word .ch--space { width: 0.28em; }

.promises--run .promise p + p {
  position: relative;
  z-index: 1;
  margin: 0;
  max-width: min(30ch, 100%);
  color: var(--p-dim);
  font-size: clamp(1.125rem, 1.55vw, 1.4375rem);
  line-height: 1.45;
}

/* The panel answers the pointer: it flips into the accent room, the outlined
   index brightens, and the word's letters step up one after another. */
@media (hover: hover) and (pointer: fine) {
  .promises--run > .promise:hover {
    --p-bg: var(--p-pop);
    --p-fg: var(--shade);
    --p-dim: rgb(var(--shade-rgb) / 0.82);
    --p-line: rgb(var(--shade-rgb) / 0.36);
  }
  .promises--run > .promise:hover .promise__num { -webkit-text-stroke-color: rgb(var(--shade-rgb) / 0.55); }
  .promises--run > .promise:hover .promise__word .ch { transform: translateY(-0.09em); }
  .promises--run:has(.promise:hover) .promise:not(:hover) { opacity: 1; filter: none; scale: none; }
}

/* --- 10. Entry ------------------------------------------------------------
   main.js gives every band and panel .stg and adds .is-in to the section when
   it arrives. That base is a 16px rise; a poster wants to be uncovered, so the
   rise is joined by a wipe and a degree of tilt that settles out. */

.scroll-chapter .stg,
.promises--run > .promise.stg {
  clip-path: inset(0 0 100% 0);
  transform: translateY(26px) rotate(-0.5deg);
  transition: opacity 620ms var(--e-out),
              transform 760ms var(--e-soft),
              clip-path 760ms var(--e-soft);
}
.scroll-chapter.is-in .stg,
[data-reveal].is-in .promises--run > .promise.stg {
  clip-path: inset(0 0 0 0);
  transform: none;
}

/* --- 11. Narrow ----------------------------------------------------------- */

@media (max-width: 899px) {
  .scroll-chapter .story__aside,
  .scroll-chapter .story-card { padding-block: clamp(40px, 9vw, 64px); }
  .scroll-chapter .story-card::after { display: none; }
  .scroll-chapter .story-card__number {
    position: static;
    display: block;
    margin-bottom: clamp(8px, 2vw, 18px);
    font-size: clamp(3.5rem, 18vw, 6rem);
  }
  .scroll-chapter .story-card__number::before { top: 12%; left: auto; right: -4px; }
  .scroll-chapter .story-card__number::after { top: 74%; left: auto; right: -22px; }
  .scroll-chapter .story-card p { font-size: clamp(1.125rem, 4.4vw, 1.375rem); }
  .promises--run > .promise,
  .promises--run > .promise:nth-child(4n + 1),
  .promises--run > .promise:nth-child(4n + 2),
  .promises--run > .promise:nth-child(4n + 3),
  .promises--run > .promise:nth-child(4n + 4),
  .promises--run > .promise:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .promises--run > .promise { min-height: 0; }
}

/* --- 12. Reduced motion, print -------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  /* main.js's reveal early-returns here, so .stg is never applied and nothing
     needs un-hiding. What is left is the parallax, which poster.js also
     declines to start, and the two gestures that are not scroll-driven. */
  .scroll-chapter .story-card__number,
  .scroll-chapter .story-card::after,
  .scroll-chapter .story__aside::before,
  .scroll-chapter .story-card::before { transform: none; }
  .promises--run .promise__word .ch { transition: none; }
}

@media print {
  .scroll-chapter .story__aside,
  .scroll-chapter .story-card,
  .promises--run > .promise {
    width: auto;
    margin-left: 0;
    padding: 12px 0;
    background: none;
    color: #000;
    break-inside: avoid;
  }
  .scroll-chapter .story-card__number,
  .scroll-chapter .story-card::after,
  .scroll-chapter .story-card::before,
  .promises--run .promise__num { display: none; }
}

/* ==========================================================================
   13. The poster title band
   Work and Contact open on one, in place of a hero that was a heading floating
   over a gradient. Same furniture as a chapter title: the boxed index, the
   headline at poster size, the whole thing full-bleed.
   ========================================================================== */

.poster-head {
  position: relative;
  isolation: isolate;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: clamp(88px, 12vw, 180px) max(var(--gutter), calc(50vw - 640px)) clamp(52px, 7vw, 104px);
  min-height: 0;
  background: var(--p-pop);
  color: var(--shade);
  overflow: hidden;
}
/* Contact is the inverted room — its page ground is already the accent, so a
   band in the same colour would be a band you cannot see. There the title
   takes the graphite instead and the page does the shouting. */
html.is-inverse .poster-head {
  background: #14161B;
  color: #FFFFFF;
}

.poster-head .page-hero__copy,
.poster-head .wrap { max-width: none; padding: 0; }

.poster-head .label {
  display: inline-block;
  width: fit-content;
  margin: 0 0 clamp(16px, 2.2vw, 28px);
  padding: 6px 12px 5px;
  border: 2px solid currentColor;
  color: inherit;
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.24em;
  text-indent: 0.24em;
}

.poster-head .display {
  max-width: 16ch;
  margin: 0;
  color: inherit;
  font-size: clamp(2.5rem, 8vw, 6.5rem);
  font-weight: 700;
  line-height: 0.94;
  letter-spacing: -0.04em;
  text-wrap: balance;
}

.poster-head .lede {
  margin-top: clamp(20px, 2.6vw, 34px);
  max-width: min(38ch, 100%);
  color: inherit;
  opacity: 0.82;
  font-size: clamp(1.125rem, 1.7vw, 1.5rem);
  line-height: 1.45;
}

/* The hero's sky, aurora and cue belong to the gradient hero this replaces. */
.poster-head .page-hero__sky,
.poster-head .shot-rule,
.poster-head .page-hero__cue { display: none; }

/* The tesseract on Contact stays, as the band's one piece of line art —
   outlined geometry is the poster language, not a departure from it. */
.poster-head .page-art {
  position: absolute;
  z-index: -1;
  right: -4%;
  top: 50%;
  translate: 0 -50%;
  width: clamp(220px, 32vw, 460px);
  opacity: 0.28;
  color: currentColor;
}
@media (max-width: 899px) { .poster-head .page-art { display: none; } }

/* ==========================================================================
   14. Work — one band per project
   The three projects were a quiet list on one ground. Each is now a band with
   its own room, the booklet on one side and the copy on the other, sides
   swapping down the page.
   ========================================================================== */

.poster-work { padding: 0; }
.poster-work > .wrap { max-width: none; padding: 0; }
.poster-work .projects { display: block; margin: 0; counter-reset: proj; }

.poster-work .project {
  --p-bg: #14161B;
  --p-fg: #FFFFFF;
  --p-dim: rgb(255 255 255 / 0.76);
  --p-line: rgb(255 255 255 / 0.20);
  --p-hot: #A8B0F0;
  --py: 0;
  --pr: 0;
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  gap: clamp(28px, 4vw, 72px);
  align-items: center;
  width: 100vw;
  margin: 0 0 0 calc(50% - 50vw);
  padding: clamp(56px, 7vw, 112px) max(var(--gutter), calc(50vw - 640px));
  background: var(--p-bg);
  color: var(--p-fg);
  counter-increment: proj;
  overflow: hidden;
}
.poster-work .project:nth-child(even) {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.78);
  --p-line: rgb(22 24 27 / 0.20);
}
/* The booklet changes sides on alternate bands, so three projects read as a
   rhythm rather than three copies of one row. */
.poster-work .project:nth-child(even) .project__copy { order: -1; }

.poster-work .project__copy { position: relative; z-index: 1; }

.poster-work .project__scope {
  display: inline-block;
  width: fit-content;
  margin-bottom: clamp(14px, 1.8vw, 22px);
  padding: 6px 12px 5px;
  border: 2px solid currentColor;
  color: var(--p-fg);
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.24em;
  text-indent: 0.24em;
  background: none;
}

.poster-work .project__client {
  margin: 0;
  color: var(--p-fg);
  font-family: var(--font-display);
  font-size: clamp(2.25rem, 5.4vw, 4.5rem);
  font-weight: 700;
  line-height: 0.96;
  letter-spacing: -0.04em;
  overflow-wrap: normal;
  word-break: keep-all;
}

.poster-work .project__line {
  margin: clamp(16px, 2vw, 26px) 0 0;
  max-width: min(30ch, 100%);
  color: var(--p-dim);
  font-size: clamp(1.125rem, 1.6vw, 1.4375rem);
  line-height: 1.5;
}

/* The index, outlined and stepped off the top edge like a chapter numeral. */
.poster-work .project::before {
  content: counter(proj, decimal-leading-zero);
  position: absolute;
  z-index: 0;
  top: clamp(-26px, -1.6vw, -6px);
  right: max(var(--gutter), calc(50vw - 640px));
  font-family: var(--font-display);
  font-size: clamp(4.5rem, 12vw, 11rem);
  font-weight: 700;
  line-height: 0.78;
  letter-spacing: -0.06em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--p-line);
  pointer-events: none;
  transform: translate3d(0, calc(var(--py) * 1px), 0);
}

/* The booklet, framed. book.js keeps every behaviour it had; this squares the
   corner it was given and puts a rule around it so it reads as a plate on the
   band rather than a floating screenshot. */
.poster-work .project__media,
.poster-work .projects--wide .book.is-bound {
  border-radius: 0;
}
.poster-work .project__gallery {
  position: relative;
  z-index: 1;
  padding: clamp(10px, 1.2vw, 18px);
  border: 2px solid var(--p-line);
  background: rgb(var(--shade-rgb) / 0.22);
}

.poster-work .project .link { color: var(--p-fg); }

@media (max-width: 899px) {
  .poster-work .project {
    grid-template-columns: minmax(0, 1fr);
    padding-block: clamp(44px, 9vw, 72px);
  }
  .poster-work .project:nth-child(even) .project__copy { order: 0; }
  .poster-work .project::before {
    position: static;
    display: block;
    margin-bottom: clamp(6px, 1.6vw, 14px);
    font-size: clamp(3.5rem, 17vw, 6rem);
  }
}

/* ==========================================================================
   15. Contact — three panels and a band for the form
   ========================================================================== */

.poster-contact { padding: 0; }
.poster-contact > .wrap { max-width: none; padding: 0; }
.poster-contact .contact__grid { display: block; gap: 0; }

/* The three details, as poster panels on the page's own ground. */
.poster-contact .contact__details {
  background: var(--p-pop);
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(10px, 1.2vw, 18px);
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: clamp(40px, 5vw, 76px) max(var(--gutter), calc(50vw - 640px));
}
@media (max-width: 899px) {
  .poster-contact .contact__details { grid-template-columns: minmax(0, 1fr); }
}

.poster-contact .detail {
  --p-bg: #14161B;
  --p-fg: #FFFFFF;
  --p-dim: rgb(255 255 255 / 0.78);
  --p-line: rgb(255 255 255 / 0.22);
  position: relative;
  display: flex;
  flex-direction: column;
  gap: clamp(10px, 1.2vw, 16px);
  min-height: clamp(170px, 16vw, 230px);
  margin: 0;
  padding: clamp(24px, 2.8vw, 40px);
  border: 0;
  border-radius: 0;
  background: var(--p-bg);
  color: var(--p-fg);
  box-shadow: none;
  overflow: hidden;
}
.poster-contact .detail:nth-child(2) {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.80);
  --p-line: rgb(22 24 27 / 0.22);
}
.poster-contact .detail::after { content: none; }

.poster-contact .detail h2 {
  width: fit-content;
  margin: 0;
  padding: 6px 12px 5px;
  border: 2px solid currentColor;
  color: var(--p-fg);
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.24em;
  text-indent: 0.24em;
}
.poster-contact .detail p,
.poster-contact .detail .footer__addr {
  margin: 0;
  color: var(--p-dim);
  font-size: clamp(1.0625rem, 1.4vw, 1.25rem);
  line-height: 1.5;
  font-style: normal;
}
.poster-contact .detail a { color: var(--p-fg); font-size: inherit; }
.poster-contact .detail .link {
  background: none;
  text-decoration: none;
  padding-bottom: 6px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='6' viewBox='0 0 24 6'%3E%3Cpath d='M0 3c2-3 4-3 6 0s4 3 6 0 4-3 6 0 4 3 6 0' fill='none' stroke='%23A8B0F0' stroke-width='1.6'/%3E%3C/svg%3E");
  background-repeat: repeat-x;
  background-position: 0 100%;
  background-size: 24px 6px;
  transition: background-position 320ms var(--e-out);
}
.poster-contact .detail .link:hover { background-position: 12px 100%; }

/* The form sits in its own graphite band, squared off. The internals — the
   icons, the tick states, the validation — are untouched; what changes is the
   geometry, which was rounded and soft in a page that is now neither. */
.poster-contact .form {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: clamp(44px, 6vw, 88px) max(var(--gutter), calc(50vw - 640px));
  border: 0;
  border-radius: 0;
  background: #14161B;
  box-shadow: none;
}
html .poster-contact .form.form--playful { border-radius: 0; border: 0; background: #14161B; }
html .poster-contact .form.form--playful .field input,
html .poster-contact .form.form--playful .field textarea {
  border-radius: 0;
  border-width: 2px;
  background: transparent;
  box-shadow: none;
  font-size: 1.0625rem;
}
html .poster-contact .form.form--playful .field input:focus,
html .poster-contact .form.form--playful .field textarea:focus {
  border-color: var(--form-accent);
  box-shadow: 0 0 0 3px rgb(168 176 240 / 0.34);
}
html .poster-contact .form.form--playful .checks .check {
  border-radius: 0;
  border-width: 2px;
}
.poster-contact .form .fieldset > legend,
.poster-contact .form .field > label {
  text-transform: uppercase;
  letter-spacing: 0.18em;
  font-size: var(--t-label);
  font-weight: 700;
}
.poster-contact .form .btn,
.poster-contact .form button[type="submit"] {
  border-radius: 0;
  padding: 20px 34px;
  font-size: 1.0625rem;
  letter-spacing: 0.02em;
}

/* ==========================================================================
   16. The closing call to action
   Every page ends on one. It is now the loudest band on the page.
   ========================================================================== */

.poster-cta {
  --p-pop: color-mix(in srgb, var(--accent) 76%, #171526);
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding: clamp(64px, 9vw, 140px) max(var(--gutter), calc(50vw - 640px));
  border-top: 0;
  background: var(--p-pop);
  color: var(--shade);
}
html.is-inverse .poster-cta { background: #14161B; color: #FFFFFF; }
.poster-cta > .wrap { max-width: none; padding: 0; }

.poster-cta .display {
  max-width: 16ch;
  margin: 0;
  color: inherit;
  font-size: clamp(2.25rem, 6.4vw, 5rem);
  font-weight: 700;
  line-height: 0.98;
  letter-spacing: -0.04em;
}
.poster-cta .hero__cta { margin-top: clamp(26px, 3.4vw, 44px); gap: var(--s-4); }

/* On the accent the solid button has nowhere to go, so the pair inverts: the
   primary becomes the graphite block and the secondary its outline. */
.poster-cta .btn {
  border-radius: 0;
  padding: 18px 30px;
  border: 2px solid currentColor;
  color: inherit;
  background: none;
  font-weight: 700;
}
.poster-cta .btn--solid {
  background: var(--shade);
  color: var(--accent);
  border-color: var(--shade);
}
html.is-inverse .poster-cta .btn--solid { background: var(--accent); color: var(--shade); border-color: var(--accent); }
.poster-cta .btn:hover { translate: 0 -2px; }

.poster-cta .micro { margin-top: clamp(24px, 3vw, 40px); color: inherit; opacity: 0.7; }

/* ==========================================================================
   17. The common surface
   The complaint that produced this section: the rebuilt parts and the parts
   they sit between read as two different websites. They did. The bands were
   hard-edged, flat and numbered; everything around them was a soft rounded
   card with a lit gradient and a shadow.

   Rather than restyle each component, the shared primitives change once. Every
   radius goes to zero, every card surface goes flat, and every button becomes
   a rectangle with a 2px rule. That is most of the distance, and it costs
   forty lines instead of four hundred.
   ========================================================================== */

:root,
html.is-inverse {
  --radius: 0;
  --radius-card: 0;
}

.btn {
  border-radius: 0;
  border: 2px solid currentColor;
  padding: 16px 28px;
  font-weight: 700;
  letter-spacing: 0.01em;
}
.btn--solid { border-color: transparent; }

/* The lit-card treatment — a radial highlight, a 145° sheen and a 70px
   shadow — was the single loudest difference between old and new. Flat. */
:is(.promise, .stat, .team > li, .detail, .handover, .text-detail, .pull.quote-card) {
  border-radius: 0;
  box-shadow: none;
}
:is(.stat, .team > li, .handover, .text-detail) {
  background: none;
  border: 1px solid var(--rule);
}
:is(.promise, .stat, .team > li, .detail, .handover)::after { content: none; }
.bucket__grid { border-radius: 0; box-shadow: none; }
.bucket__grid::after { content: none; }

.book, .book__page, .project__media, .project__media.is-window,
.form, .field input, .field textarea, .check, .budget-choice {
  border-radius: 0;
}

/* ==========================================================================
   18. The numbering spine
   One counter per document, and every section marker draws from it. This is
   the piece that makes a page read as one system: the chapter bands, the
   plain sections and the page heads all carry the same chip in the same place
   in the same face, and the numbers run in document order whatever the page
   is made of.
   ========================================================================== */

main { counter-reset: sect; }

.section > .wrap > .label,
.band > .wrap > .label,
.page-hero__copy > .label,
.poster-head .label,
.scroll-chapter .story__index {
  counter-increment: sect;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  width: fit-content;
  margin-bottom: clamp(14px, 1.8vw, 24px);
  padding: 0;
  border: 0;
  color: var(--text-dim);
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-indent: 0;
}
.section > .wrap > .label::before,
.band > .wrap > .label::before,
.page-hero__copy > .label::before,
.poster-head .label::before,
.scroll-chapter .story__index::before {
  content: "N." counter(sect, decimal-leading-zero);
  padding: 6px 10px 5px;
  border: 2px solid currentColor;
  letter-spacing: 0.14em;
}

/* The chapter index carries no digits of its own any more — the counter is
   the single source, so a chapter cannot drift out of step with the sections
   around it. */
.scroll-chapter .story__index { color: var(--p-fg); }
.poster-head .label { color: inherit; }

/* ==========================================================================
   19. Process, as a numbered run
   Five steps that were a soft list become the clearest expression of the
   numbering system on the site.
   ========================================================================== */

.steps {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
  counter-reset: step;
  margin-top: clamp(28px, 4vw, 56px);
}
.steps > li {
  counter-increment: step;
  display: grid;
  grid-template-columns: clamp(64px, 8vw, 132px) minmax(0, 1fr);
  gap: clamp(16px, 3vw, 48px);
  align-items: start;
  margin: 0;
  padding: clamp(22px, 2.8vw, 40px) 0;
  border-top: 1px solid var(--rule);
}
.steps > li:last-child { border-bottom: 1px solid var(--rule); }
.steps > li::before {
  content: counter(step, decimal-leading-zero);
  font: 700 clamp(1.75rem, 3.4vw, 3rem)/0.9 var(--font-display);
  letter-spacing: -0.04em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--accent);
}
.steps > li > div { min-width: 0; }
.steps h3 {
  margin: 0;
  font: 700 clamp(1.25rem, 2.2vw, 1.875rem)/1.1 var(--font-display);
  letter-spacing: -0.03em;
}
.steps p {
  margin-top: var(--s-3);
  max-width: min(46ch, 100%);
  font-size: clamp(1.0625rem, 1.35vw, 1.25rem);
  line-height: 1.55;
}
.steps .steps__rail { display: none; }
@media (max-width: 599px) {
  .steps > li { grid-template-columns: minmax(0, 1fr); gap: var(--s-3); }
}

/* ==========================================================================
   20. Services, as poster panels
   Three panels on the same three-room cycle the promises use, so the two
   blocks on the home page are recognisably the same component family.
   ========================================================================== */

/* Block, not grid. As a grid the panel kept coming out at 692px inside a
   1176px track whatever was set on it; a block-level child fills its parent by
   definition and there is nothing here a grid was buying. */
.buckets { display: block; margin-top: clamp(28px, 4vw, 56px); }
.buckets > .bucket { display: block; width: auto; margin: 0 0 clamp(10px, 1.2vw, 18px); padding: 0; border: 0; }
.buckets > .bucket:last-child { margin-bottom: 0; }

.bucket__grid {
  --p-bg: #14161B;
  --p-fg: #FFFFFF;
  --p-dim: rgb(255 255 255 / 0.78);
  --p-line: rgb(255 255 255 / 0.22);
  position: relative;
  padding: clamp(26px, 3.4vw, 56px);
  border: 0;
  background: var(--p-bg);
  color: var(--p-fg);
  isolation: isolate;
}
.bucket:nth-child(2) .bucket__grid {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.80);
  --p-line: rgb(22 24 27 / 0.22);
}
.bucket:nth-child(3) .bucket__grid {
  --p-bg: var(--p-pop);
  --p-fg: var(--shade);
  --p-dim: rgb(var(--shade-rgb) / 0.84);
  --p-line: rgb(var(--shade-rgb) / 0.32);
}
.bucket__num {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--p-line);
  font: 700 clamp(1.75rem, 3vw, 2.5rem)/1 var(--font-display);
  letter-spacing: -0.04em;
}
.bucket__title {
  color: var(--p-fg);
  font: 700 clamp(1.625rem, 3vw, 2.5rem)/1.02 var(--font-display);
  letter-spacing: -0.035em;
}
.bucket__desc {
  color: var(--p-dim);
  font-size: clamp(1.0625rem, 1.45vw, 1.3125rem);
  line-height: 1.5;
  max-width: min(42ch, 100%);
}
.bucket__grid .link { color: var(--p-fg); }
.bucket:hover .bucket__num { transform: none; }

/* ==========================================================================
   21. Scale
   Everything above is set in clamp(), but a clamp only protects the sizes it
   was given. These are the guards for the widths in between: nothing may sit
   on a measure it cannot fit, and no display line may be cut mid-word.
   ========================================================================== */

.poster-head .display,
.poster-cta .display,
.scroll-chapter .story__aside > .display,
.poster-work .project__client,
.bucket__title,
.steps h3 {
  overflow-wrap: break-word;   /* only ever reached by a single word longer
                                  than the column, which is better broken than
                                  spilling off the edge */
  hyphens: manual;
}

@media (max-width: 479px) {
  .poster-head { padding-top: clamp(72px, 22vw, 110px); }
  .poster-head .display { font-size: clamp(2rem, 11vw, 2.75rem); }
  .poster-cta .display,
  .scroll-chapter .story__aside > .display { font-size: clamp(1.875rem, 9.5vw, 2.5rem); }
  .scroll-chapter .story-card:first-child .story-card__content > p:first-child {
    font-size: clamp(1.625rem, 8vw, 2.125rem);
  }
  .promises--run .promise__word { font-size: clamp(1.75rem, 10vw, 2.5rem); }
  .poster-work .project__client { font-size: clamp(1.875rem, 10vw, 2.75rem); }
}

/* The pills. --radius is a token, but the header's furniture hard-codes 999px
   rather than using it, so a page of rectangles kept a row of lozenges along
   the top. These are the eight places that do it. */
.lang,
.lang a,
.lang__thumb,
.nav__list,
.nav__link,
.nav__marker,
.book__nav,
.brand,
.install-control,
.finish-control,
.sound-control { border-radius: 0; }

/* The brief's marker sits between two full-bleed bands, so it needs the same
   inline padding they carry or it would start at the viewport edge. */
.poster-contact > .wrap > .label {
  margin: clamp(30px, 4vw, 56px) 0 clamp(14px, 1.8vw, 22px);
  padding-inline: max(var(--gutter), calc(50vw - 640px));
}

/* ==========================================================================
   22. Toning down, and the services panel rebuilt
   ========================================================================== */

/* The accent room, muted. The accent at full strength was carrying a title
   band, a closing band and a page head on every page, which is more of it
   than the palette can take at that size. A quarter of the ink mixed in keeps
   the hue and drops the glare; --shade on it still measures about 5:1, and the
   fallback is the raw accent where color-mix is unsupported. */
:root,
html.is-inverse {
  --p-pop: var(--accent);
  --p-pop: color-mix(in srgb, var(--accent) 76%, #171526);
}

/* And one less of them per chapter: a sequence ending on colour was the idea,
   but with the title band already in the accent it made two accent bands in
   every chapter. The last movement takes the bone instead. */
.scroll-chapter .story-card:last-child {
  --p-bg: #EFECE4;
  --p-fg: #16181B;
  --p-dim: rgb(22 24 27 / 0.78);
  --p-line: rgb(22 24 27 / 0.20);
  --p-sheen: 0.22;
}

/* --- Services --------------------------------------------------------------
   The panel had main.css's three-column grid underneath it: a 4rem slot for
   the number, which is not enough for "(01)" at 40px, so it broke across two
   lines. The number is now a chip in the corner drawn from a counter — the
   same figure the rest of the site uses — and the panel is two real columns.
   -------------------------------------------------------------------------- */

.buckets { counter-reset: bkt; }
.bucket { counter-increment: bkt; }

.bucket__grid {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
  gap: clamp(20px, 3vw, 56px);
  align-items: center;
  padding: clamp(62px, 6.4vw, 104px) clamp(28px, 3.4vw, 60px) clamp(30px, 3.6vw, 60px);
}

/* The digits come from the counter, so the parentheses in the markup are not
   in the way and the figure cannot disagree with its position in the list. */
.bucket__num {
  position: absolute;
  top: clamp(24px, 2.6vw, 40px);
  left: clamp(28px, 3.4vw, 60px);
  z-index: 1;
  padding: 0;
  font-size: 0;
  background: none;
  -webkit-text-fill-color: currentColor;
  color: var(--p-fg);
}
.bucket__num::before {
  content: counter(bkt, decimal-leading-zero);
  display: inline-block;
  padding: 6px 11px 5px;
  border: 2px solid currentColor;
  font: 700 var(--t-label)/1 var(--font-mono);
  letter-spacing: 0.2em;
  text-indent: 0.2em;
}
.bucket__num::after { content: none; }

.bucket__desc { margin-top: clamp(12px, 1.6vw, 20px); }
.bucket__grid > div { min-width: 0; }
.bucket__media { min-width: 0; }

@media (max-width: 899px) {
  .bucket__grid {
    grid-template-columns: minmax(0, 1fr);
    padding-top: clamp(56px, 14vw, 84px);
  }
}

/* --- The form's playful accents --------------------------------------------
   The second choice lit the form in peach, which was the one warm colour left
   on the site once the dots turned periwinkle. */
html .form.form--playful:has(.check:nth-child(2) input:checked) { --form-accent: #A8B0F0; }
html .form.form--playful .checks .check:nth-child(2) { --choice-color: #A8B0F0; }

/* ==========================================================================
   23. Rounded again, and the page heads go dark
   Two corrections. Squaring every corner was my call and it split the site in
   half instead of uniting it — some components carry radii that are not
   tokenised, so "everything sharp" was never going to be true. Everything is
   rounded instead, from one scale.

   And the page head was an accent band with the hero art laid over it at 28%
   — lilac art on a lilac ground, half of it cropped by an absolute position it
   never asked for. The band takes the graphite, the art goes back into the
   flow beside the copy at full strength, and both are legible.
   ========================================================================== */

:root,
html.is-inverse {
  --radius: 999px;
  --radius-card: 20px;
  --radius-panel: 20px;
  --radius-chip: 10px;
}

/* Undoing section 17's squaring, and the eight hard-coded pills with it. */
.btn { border-radius: var(--radius); }
.lang,
.lang a,
.lang__thumb,
.nav__list,
.nav__link,
.nav__marker,
.brand,
.install-control,
.finish-control,
.sound-control { border-radius: var(--radius); }
.book__nav { border-radius: var(--radius); }

:is(.promise, .stat, .team > li, .detail, .handover, .text-detail, .pull.quote-card),
.bucket__grid,
.book, .book__page, .project__media, .project__media.is-window,
.form, .field input, .field textarea, .check, .budget-choice {
  border-radius: var(--radius-card);
}

.promises--run > .promise,
.poster-contact .detail,
.bucket__grid { border-radius: var(--radius-panel); }
.poster-work .project__gallery { border-radius: calc(var(--radius-panel) + 6px); }
.poster-work .projects--wide .book.is-bound,
.poster-work .project__media { border-radius: var(--radius-card); }

/* The index chips, the scope chips and the section markers. */
.section > .wrap > .label::before,
.band > .wrap > .label::before,
.page-hero__copy > .label::before,
.poster-head .label::before,
.scroll-chapter .story__index::before,
.bucket__num::before,
.poster-work .project__scope,
.poster-contact .detail h2 { border-radius: var(--radius-chip); }

/* --- The page head ---------------------------------------------------------
   Graphite, two columns, art in the flow. -------------------------------- */

.poster-head,
html.is-inverse .poster-head {
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(0, 0.92fr);
  gap: clamp(24px, 4vw, 72px);
  align-items: center;
  background: #14161B;
  color: #FFFFFF;
}
.poster-head .page-hero__copy { grid-column: 1; }
.poster-head .display { color: #FFFFFF; }
.poster-head .label { color: rgb(255 255 255 / 0.82); }
.poster-head .lede { color: rgb(255 255 255 / 0.80); opacity: 1; }

/* Back into the flow at full strength. It was absolutely positioned at 28%
   opacity, which cropped it against the band's overflow and tinted it into
   the ground it was sitting on. */
.poster-head .page-art {
  position: relative;
  z-index: 0;
  grid-column: 2;
  right: auto;
  top: auto;
  translate: none;
  width: 100%;
  max-width: 520px;
  margin: 0 auto;
  opacity: 1;
}
@media (max-width: 899px) {
  .poster-head,
  html.is-inverse .poster-head { grid-template-columns: minmax(0, 1fr); }
  .poster-head .page-art { display: none; }
}

/* The services panel stretches its track. */


/* The staged services stack. pieces.js gives the three panels a perspective
   and pushes each to a different Z, so the one furthest back renders visibly
   narrower than the one in front. That reads as depth on borderless rows,
   which is what it was built for; on panels with a solid ground it reads as
   three boxes of three different widths, the last of them clipping its own
   heading. The Z travel and the focus dimming come off — the rooms already do
   the separating. */
.buckets--staged { perspective: none; perspective-origin: 50% 50%; }
.buckets--staged .bucket,
.buckets--staged .bucket.is-lowered,
.buckets--staged .bucket.is-raised {
  transform: none;
  opacity: 1;
  filter: none;
}

/* main.css caps every <p> and <li> in <main> at a 68ch measure, and opts a
   named list of components out of it. That is right for text and wrong for a
   list item that is now a panel with a ground: the cap was invisible while the
   buckets were borderless rows, and the moment they took a background it
   showed up as a panel that stops two thirds of the way across. Every list
   that became a surface joins the opt-out.

   (:where() contributes no specificity, so the original is (0,0,2) and this
   clears it comfortably.) */
main .buckets > li,
main .promises > li,
main .steps > li,
main .projects > li,
main .book > li { max-width: none; }

/* ==========================================================================
   24. Slabs, not bands — and a stack instead of a column
   Two changes that go together.

   ROUNDED. The bands were the last square things on the site, because a band
   that runs to both edges of the viewport has no corners to round. So they
   stop running to the edges: each one is now an inset slab on the page ground,
   the same radius as every panel, with a little air between them. The site has
   one shape language again, and 100vw stops fighting the scrollbar.

   STACKED. Reading a chapter was scrolling one long column. The slabs are
   sticky now, each pinned a few pixels below the one before it, so a chapter
   arrives as a deck that gathers under the chapter title and the edges of what
   you have already read stay visible at the top. Nothing is hijacked — it is
   position: sticky and the page scrolls at its own speed; a browser without
   sticky support gets the plain column back.
   ========================================================================== */

:root, html.is-inverse { --radius-slab: 28px; }

/* The wrap goes back to being a wrap. */
.scroll-chapter .wrap,
.poster-work > .wrap,
.poster-contact > .wrap,
.poster-cta > .wrap {
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Every slab: in the flow, inset, rounded. */
.scroll-chapter .story__aside,
.scroll-chapter .story-card,
.poster-work .project,
.poster-contact .contact__details,
.poster-contact .form,
.poster-head,
.poster-cta {
  width: auto;
  max-width: var(--max);
  margin-left: auto;
  margin-right: auto;
  margin-block: clamp(8px, 1vw, 14px);
  padding-inline: clamp(26px, 3.6vw, 68px);
  border-radius: var(--radius-slab);
}

.poster-head,
.poster-cta {
  width: calc(100% - 2 * var(--gutter));
  padding-block: clamp(52px, 6.4vw, 104px);
}
.poster-head { margin-top: clamp(10px, 1.4vw, 20px); }

.scroll-chapter .story__aside,
.scroll-chapter .story-card { padding-block: clamp(38px, 4.6vw, 76px); }
.poster-work .project { padding-block: clamp(40px, 5vw, 84px); }
.poster-contact .contact__details { padding-block: clamp(30px, 3.4vw, 52px); }
.poster-contact .form { padding-block: clamp(36px, 4.6vw, 72px); }

/* The numeral and the section marker were positioned against the old
   full-bleed padding, which no longer exists. */
.scroll-chapter .story-card__number,
.poster-work .project::before { right: clamp(20px, 3vw, 56px); }
.poster-contact > .wrap > .label { padding-inline: 0; }

/* --- The stack ------------------------------------------------------------
   main.js already writes --i on each staggered child, which is exactly the
   index this needs, so the offsets cost no extra JavaScript. */
@media (min-width: 900px) {
  .scroll-chapter .story__aside {
    position: sticky;
    top: calc(var(--header-h) + 12px);
    z-index: 1;
  }
  .scroll-chapter .story-card {
    position: sticky;
    top: calc(var(--header-h) + 26px + var(--i, 0) * 16px);
    z-index: 2;
    box-shadow: 0 -1px 0 rgb(var(--ink-rgb) / 0.10), 0 -24px 60px -40px rgb(var(--shade-rgb) / 0.9);
  }
  /* The last slab of a chapter releases: something has to scroll away or the
     next chapter arrives underneath a permanent lid. */
  .scroll-chapter .story-card:last-child { position: relative; top: auto; }

  .poster-work .project { position: sticky; top: calc(var(--header-h) + 20px + var(--i, 0) * 16px); }
  .poster-work .project:last-child { position: relative; top: auto; }
}

/* --- Mobile ---------------------------------------------------------------
   Compact spacing is the baseline. The mobile enhancement below restores
   stacking with an offset measured for each card's actual height. */
@media (max-width: 899px) {
  :root, html.is-inverse { --radius-slab: 20px; --radius-panel: 16px; --radius-card: 16px; }

  .scroll-chapter .story__aside,
  .scroll-chapter .story-card,
  .poster-work .project,
  .poster-contact .contact__details,
  .poster-contact .form,
  .poster-head,
  .poster-cta {
    position: relative;
    top: auto;
    padding-inline: clamp(20px, 5vw, 30px);
    margin-block: 8px;
  }
  .poster-head,
  .poster-cta { padding-block: clamp(40px, 10vw, 64px); }
  .scroll-chapter .story__aside { min-height: 0; padding-block: clamp(30px, 7vw, 44px); }
  .scroll-chapter .story-card { padding-block: clamp(28px, 7vw, 44px); }
  .poster-work .project { padding-block: clamp(32px, 8vw, 48px); }

  .poster-head .display { font-size: clamp(2rem, 9vw, 3rem); }
  .poster-cta .display,
  .scroll-chapter .story__aside > .display { font-size: clamp(1.875rem, 8vw, 2.75rem); }
  .scroll-chapter .story-card:first-child .story-card__content > p:first-child {
    font-size: clamp(1.625rem, 7vw, 2.25rem);
  }
  .poster-work .project__client { font-size: clamp(1.875rem, 8.5vw, 2.75rem); }
  .bucket__title { font-size: clamp(1.5rem, 7vw, 2rem); }

  .poster-work .project::before {
    position: static;
    display: block;
    margin-bottom: clamp(6px, 2vw, 14px);
    font-size: clamp(3rem, 16vw, 5rem);
  }
  .poster-contact .contact__details { gap: 10px; }
  .steps > li::before { font-size: clamp(1.5rem, 7vw, 2rem); }
}

/* Very narrow: the decorative layer goes entirely. It costs paint and adds
   nothing at 360px, where every pixel of width is doing real work. */
@media (max-width: 559px) {
  .scroll-chapter .story-card::after,
  .scroll-chapter .story-card__number::before,
  .scroll-chapter .story-card__number::after { display: none; }
  .promises--run .promise__num { font-size: clamp(2.5rem, 12vw, 3.5rem); }
}

/* ==========================================================================
   25. The hero art on small screens, and a pass for speed
   ========================================================================== */

/* The art was hidden below 900px because it had nowhere to sit in a single
   column. It has somewhere now: under the copy, at a size that leaves the
   headline the top of the screen. pieces.js builds every one of these
   regardless of width, so nothing new is being started — this only stops
   throwing away work already done. */
@media (max-width: 899px) {
  .poster-head .page-art {
    display: block;
    grid-column: 1;
    width: min(100%, 340px);
    margin: clamp(18px, 4vw, 30px) auto 0;
    max-width: none;
    justify-self: center;
    text-align: center;
  }
  .poster-head .page-art > svg,
  .poster-head .page-art > * { max-width: 100%; height: auto; }
}
@media (max-width: 559px) {
  .poster-head .page-art { width: min(100%, 260px); }
}

/* --- Speed ----------------------------------------------------------------
   Four changes, in order of what they cost the browser.

   1. The veil dropped its blur. `filter: blur(38px)` over a band the width of
      the page is one of the most expensive things a compositor can be asked
      for, and it was running on every band on every page. Radial gradients are
      already soft; the blur was buying almost nothing visible.

   2. Off-screen panels stop being laid out and painted. A chapter page is
      thirteen thousand pixels tall and most of it is never on screen at once;
      content-visibility lets the browser skip the work until it is close,
      and contain-intrinsic-size: auto means it remembers the real height
      afterwards so the scrollbar does not jump.

   3. The numerals gave up their permanent `will-change: transform`. It forces
      a compositor layer for the life of the page whether or not anything is
      moving; the transform promotes itself while it animates anyway.

   4. On a coarse pointer the decoration that exists to answer a mouse comes
      off entirely.
   -------------------------------------------------------------------------- */

.scroll-chapter .story__aside::before,
.scroll-chapter .story-card::before {
  filter: none;
  opacity: calc(var(--p-sheen) * 0.34);
}

.promises--run > .promise,
.buckets > .bucket,
.poster-contact .detail,
.poster-work .project {
  content-visibility: auto;
  contain-intrinsic-size: auto 320px;
}
@media (max-width: 899px) {
  .scroll-chapter .story-card {
    content-visibility: auto;
    contain-intrinsic-size: auto 420px;
  }
}

.scroll-chapter .story-card__number { will-change: auto; }

@media (pointer: coarse) {
  .scroll-chapter .story-card::after,
  .scroll-chapter .story__aside::before,
  .scroll-chapter .story-card::before { display: none; }
  .promises--run .promise__word .ch { transition: none; }
}

/* ==========================================================================
   26. The numbering spine comes out, and the last square buttons
   ========================================================================== */

/* N.001 / N.002 was borrowed from a reference that uses it as the spine of a
   whole page. Here it turned out to be a second number competing with the ones
   that carry real information — the 01/02/03 on the service panels, the
   promises and the project bands, which say where you are in a list. The
   section markers keep the label; the counter goes.

   `content: none` rather than deleting the rules above, so the chips stay one
   decision in one place if they are ever wanted back. */
.section > .wrap > .label::before,
.band > .wrap > .label::before,
.page-hero__copy > .label::before,
.poster-head .label::before,
.scroll-chapter .story__index::before { content: none; }

.section > .wrap > .label,
.band > .wrap > .label,
.page-hero__copy > .label,
.poster-head .label {
  display: block;
  gap: 0;
  counter-increment: none;
}

/* Every .story__index is empty now — the digits came out of the markup when
   the counter took over, and the counter has just gone. Three of them on the
   home page alone, and one sits in a plain .story band rather than a chapter,
   so the rule cannot be scoped to .scroll-chapter. */
/* Both forms: the bare one for the index that sits in a plain .story band,
   and the scoped one to outrank section 18's inline-flex inside a chapter. */
.story__index,
.scroll-chapter .story__index { display: none; }

/* --- The buttons that stayed square ---------------------------------------
   Written back when everything was being squared, at (0,2,0), which quietly
   outranked the (0,1,0) `.btn` rule that rounded everything else. Both are the
   primary call to action, which is a poor place to leave an inconsistency. */
.poster-cta .btn,
.poster-cta .btn--solid,
.poster-contact .form .btn,
.poster-contact .form button[type="submit"],
html .poster-contact .form.form--playful .checks .check,
html .poster-contact .form.form--playful .field input,
html .poster-contact .form.form--playful .field textarea {
  border-radius: var(--radius);
}
html .poster-contact .form.form--playful .field input,
html .poster-contact .form.form--playful .field textarea,
html .poster-contact .form.form--playful .checks .check {
  border-radius: var(--radius-card);
}

/* ==========================================================================
   27. Panels arrive from the side, alternating
   Everything entered by rising sixteen pixels, which is the same gesture the
   whole web uses and reads as nothing at all. Panels now come in from the left
   and the right by turns, with a degree of rotation that settles out — so a
   run of them assembles rather than scrolls past, and the direction tells you
   the list has changed row.

   Two safeguards. The travel is in vw and <html> carries overflow-x: clip, so
   a panel waiting off to the side cannot open a horizontal scrollbar. And the
   whole block is inside prefers-reduced-motion: no-preference — main.js
   already early-returns there and never applies .stg, but a second lock on
   the door costs nothing.
   ========================================================================== */

  .scroll-chapter .story-card.stg,
  .promises--run > .promise.stg,
  .buckets > .bucket.stg,
  .poster-work .project.stg,
  .poster-contact .detail.stg,
  .steps > li.stg {
    opacity: 0;
    clip-path: none;
    transform: translate3d(var(--in-x, 0), var(--in-y, 18px), 0) rotate(var(--in-r, 0deg));
    transition: opacity 620ms var(--e-out),
                transform 880ms var(--e-soft);
    transition-delay: calc(var(--i, 0) * 90ms);
  }

  /* Odd from the left, even from the right. nth-child rather than a sum on
     --i: the index main.js writes is a plain number and CSS has no way to
     alternate a sign from one. */
  .scroll-chapter .story-card.stg:nth-child(odd),
  .promises--run > .promise.stg:nth-child(odd),
  .buckets > .bucket.stg:nth-child(odd),
  .poster-work .project.stg:nth-child(odd),
  .poster-contact .detail.stg:nth-child(odd),
  .steps > li.stg:nth-child(odd) { --in-x: -7vw; --in-r: -1.1deg; }

  .scroll-chapter .story-card.stg:nth-child(even),
  .promises--run > .promise.stg:nth-child(even),
  .buckets > .bucket.stg:nth-child(even),
  .poster-work .project.stg:nth-child(even),
  .poster-contact .detail.stg:nth-child(even),
  .steps > li.stg:nth-child(even) { --in-x: 7vw; --in-r: 1.1deg; }

  /* The steps are a tighter run, so they travel less and lean not at all —
     six rows swinging in alternate directions is a fairground, not a list. */
  .steps > li.stg:nth-child(odd) { --in-x: -3.5vw; --in-r: 0deg; }
  .steps > li.stg:nth-child(even) { --in-x: 3.5vw; --in-r: 0deg; }

  [data-reveal].is-in .scroll-chapter .story-card.stg,
  .scroll-chapter[data-reveal].is-in .story-card.stg,
  [data-reveal].is-in .promises--run > .promise.stg,
  [data-reveal].is-in .buckets > .bucket.stg,
  [data-reveal].is-in .poster-work .project.stg,
  .poster-work[data-reveal].is-in .project.stg,
  [data-reveal].is-in .poster-contact .detail.stg,
  [data-reveal].is-in .steps > li.stg {
    opacity: 1;
    transform: none;
  }

  /* Narrower screens get a shorter throw: 7vw of a phone is nothing, but the
     rotation on a full-width slab is very visible. */
  @media (max-width: 899px) {
    .scroll-chapter .story-card.stg:nth-child(odd),
    .promises--run > .promise.stg:nth-child(odd),
    .buckets > .bucket.stg:nth-child(odd),
    .poster-work .project.stg:nth-child(odd),
    .poster-contact .detail.stg:nth-child(odd) { --in-x: -12vw; --in-r: -0.6deg; }
    .scroll-chapter .story-card.stg:nth-child(even),
    .promises--run > .promise.stg:nth-child(even),
    .buckets > .bucket.stg:nth-child(even),
    .poster-work .project.stg:nth-child(even),
    .poster-contact .detail.stg:nth-child(even) { --in-x: 12vw; --in-r: 0.6deg; }
  }

/* Withdrawn under reduced motion. main.js never applies .stg there in the
   first place, so this is the second lock rather than the first. */
@media (prefers-reduced-motion: reduce) {
  .scroll-chapter .story-card.stg,
  .promises--run > .promise.stg,
  .buckets > .bucket.stg,
  .poster-work .project.stg,
  .poster-contact .detail.stg,
  .steps > li.stg { opacity: 1; transform: none; transition: none; }
}

/* The contact details are two panels now that the address has gone, so the
   grid stops being a hard three-up and sizes itself to whatever it holds. */
.poster-contact .contact__details {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr));
}

/* ==========================================================================
   28. The hero art had no box
   Two faults, both mine, and they compounded.

   1. main.css centres the art with `transform: translateY(-50%)` against a
      `top: 50%`. My rule reset `top`, `right` and `translate` — but `translate`
      is the independent property, and this is the `transform` one. So the art
      kept being lifted by half its own height and rode up over the copy and
      the button above it.

   2. The scenes are built as absolutely positioned pieces inside a wrapper set
      to `height: 100%`. That resolved against a `.page-art` which, once it was
      in the flow rather than absolutely positioned, had no height at all — so
      the pieces laid themselves out around a box of zero height and spilled in
      every direction. A ratio gives them something to fill.
   ========================================================================== */

.poster-head .page-art {
  transform: none;
  aspect-ratio: 1 / 1;
  height: auto;
}
.poster-head .page-art > * { width: 100%; height: 100%; }

/* The tesseract is a plain SVG with its own intrinsic size and wants to keep
   it rather than be stretched to the ratio. */
.poster-head .page-art > svg {
  width: 100%;
  height: auto;
  max-width: 100%;
}

/* The word boxes the letter-split builds. poster.js wraps each word of a
   headword in a .wd so a line can only break at the spaces between them — but
   that only works if .wd is actually told not to break, and it never was. The
   JS half of that fix shipped without its CSS half, so "Visual identity" went
   on breaking after "identit" exactly as before. */
.promises--run .promise__word .wd {
  display: inline-block;
  white-space: nowrap;
}

/* ==========================================================================
   29. Tracking for Clash
   Every display size on this site was tracked between -0.035em and -0.045em,
   which was right for system-ui — SF and Segoe are drawn loose and want
   pulling in at poster sizes. Clash Display is drawn tight to begin with and
   its word space is narrow, so the same numbers closed the gaps between words
   entirely: the branding hero read as "Abrandyou canuse. Andown."

   So the tracking comes back most of the way, and a little word-spacing goes
   in to buy back the space the face does not give. Both are set here rather
   than at each rule so there is one number to turn if the face is ever
   changed again.
   ========================================================================== */

:root {
  --track-display: -0.015em;
  --track-word: 0.06em;
}

.poster-head .display,
.poster-cta .display,
.scroll-chapter .story__aside > .display,
.scroll-chapter .story-card:first-child .story-card__content > p:first-child,
.poster-work .project__client,
.promises--run .promise__word,
.bucket__title,
.steps h3,
.display,
.h-hero,
.h-1,
.h-2 {
  letter-spacing: var(--track-display);
  word-spacing: var(--track-word);
}

/* The numerals are single figures with no spaces in them, so they keep the
   tight setting that makes a large outlined number read as one shape. */
.scroll-chapter .story-card__number,
.poster-work .project::before,
.promises--run .promise__num,
.steps > li::before,
.bucket__num::before {
  letter-spacing: -0.04em;
  word-spacing: normal;
}

/* Buttons and chips are Clash Grotesk at small sizes, where the tight default
   is fine but the word gaps are still narrow. */
.btn,
.poster-work .project__scope,
.poster-contact .detail h2,
.section > .wrap > .label,
.band > .wrap > .label,
.page-hero__copy > .label,
.poster-head .label { word-spacing: 0.04em; }

/* Mobile keeps the desktop's entrances and depth, timed to the card being
   read. Native scrolling, content order and the desktop rules stay intact. */
@media (max-width: 899px) and (prefers-reduced-motion: no-preference) {
  html [data-reveal].reveal--group { opacity: 1; transform: none; }

  html [data-reveal] .stg.reveal-self {
    clip-path: none;
    transition: opacity 420ms var(--e-out), transform 620ms var(--e-soft);
    transition-delay: 0s;
  }
  html [data-reveal] .stg.reveal-self:not(.is-in):not(:focus-within) {
    opacity: 0;
    transform: translate3d(var(--in-x, 0), 20px, 0) rotate(var(--in-r, 0deg));
  }
  html [data-reveal] .stg.reveal-self:is(.is-in, :focus-within) {
    opacity: 1;
    transform: none;
  }

  .scroll-chapter .story-card::before {
    display: block;
    opacity: calc(var(--p-sheen) * 0.18);
  }

  .promises--run > .promise.is-scroll-active {
    --p-bg: var(--p-pop);
    --p-fg: var(--shade);
    --p-dim: rgb(var(--shade-rgb) / 0.82);
    --p-line: rgb(var(--shade-rgb) / 0.36);
  }
  .promises--run .promise__word .ch {
    transition: transform 420ms var(--e-out);
    transition-delay: calc(var(--c, 0) * 26ms);
  }
  .promises--run > .promise.is-scroll-active .promise__word .ch {
    transform: translateY(-0.09em);
  }
}

@media (max-width: 899px) and (min-height: 480px) and (prefers-reduced-motion: no-preference) {
  .scroll-chapter .story-card.is-mobile-stack,
  .poster-work .project.is-mobile-stack {
    content-visibility: visible;
    z-index: 2;
    box-shadow: 0 -1px 0 rgb(var(--ink-rgb) / 0.10),
                0 -20px 48px -36px rgb(var(--shade-rgb) / 0.8);
  }
  .scroll-chapter .story-card.is-mobile-stack:not(:last-child):not(:focus-within),
  .poster-work .project.is-mobile-stack:not(:last-child):not(:focus-within) {
    position: sticky;
    top: var(--mobile-stack-top, calc(var(--header-h) + 12px));
  }
}
