/* ============================================================================
   SVRV — TOKENS.  Prepended into assets/svrv.css by build_site.py, so it is one
   authored file and zero extra requests.

   THREE TIERS, AND TWO RULES THAT MAKE THEM WORTH HAVING:
     TIER 1  PRIMITIVES   what a value IS.   The ONLY place a hex appears.
     TIER 2  SEMANTICS    what it MEANS.     The ONLY thing a rule may reference.
     TIER 3  ONE-OFFS     one component.     Named for WHY it differs.

   The count that matters is TIER 2 — the number of decisions the next editor
   faces. Twelve crimsons reached through twelve semantics is a system; the same
   twelve reached directly is debt. Drive tier 2 down; leave tier 1 alone.

   Before: 16 names a rule could reach for, three of them (--oat, --flesh, --clay)
   the SAME hex across 75 uses, plus 53 distinct raw literals in 84 places.
   After: 12 semantics, no rule holding a hex.

   CONTRAST IS DEFINED AS PAIRS, NOT COLOURS. Every --on-* semantic states the
   ground it is legible against, and build_site.py asserts the ratio. This exists
   because measuring type against the wrong ground shipped three separate AA
   failures on this build: the placeholder measured on the page ink when it sits
   on the panel, and the threshold labels measured on the page gradient when the
   threshold paints its own.
   ============================================================================ */

:root {
  /* ── TIER 1 · PRIMITIVES ─────────────────────────────────────────────────
     The crimson ladder is ONE considered thing, not nine mistakes: three
     gradients draw from it — page (1>3>8), threshold (2>3>6), plate (2>5>7). */
  --crimson-1: #4A0A0A;   /* page gradient, lightest — the warm centre        */
  --crimson-2: #3B0606;   /* threshold + plate gradients, lightest            */
  --crimson-3: #330505;   /* the mid stop shared by all three gradients       */
  --crimson-4: #2E0404;   /* the deboss: 1.03:1 on --crimson-3, reads by
                             relief alone. Not a text colour, ever.           */
  --crimson-5: #2A0404;   /* flat plate: hero plate, look, slot               */
  --crimson-6: #250404;   /* threshold gradient, darkest                      */
  --crimson-7: #1F0303;   /* plate gradient, darkest                          */
  --crimson-8: #1A0303;   /* page gradient, darkest — the deepest field       */
  --crimson-9: #140202;   /* the wordmark's own ink in the footer             */

  /* A PRIMITIVE WITH NO SEMANTIC IS NOT A BUG — that is what tier 1 is for.
     --sacramento is in the brandbook, so deleting it would lose a canon fact
     and someone would re-derive it. It has no job for a measurable reason:
     1.08:1 against --crimson-3 and 1.19:1 against --crimson-8. It physically
     cannot function as a surface distinction on Depth Crimson. Do not reach for
     it as a panel colour — that is the discovery this comment exists to spare. */
  --sacramento: #3D0C11;

  --oat:       #C9BFB2;   /* the working neutral: type, rules, marks          */
  --ivory:     #F5F1E9;   /* the bright neutral: headings, the light ground   */
  --linen:     #F2E8DE;   /* the warm neutral: glows and washes               */
  --brick:     #7d3a35;   /* light-theme secondary type — 5.93:1 on --ivory   */
  --coral:     #E86A62;   /* validation. Not in the palette by taste; it is
                             here because #A51E22 is 2.65:1 on crimson and an
                             error a person cannot read is not an error.       */
  --directive: #A51E22;   /* the directive red — decorative, never type       */
  /* light-theme primitives: crimson-3 at alpha, and the deep brick for dim type */
  --brick-deep: #5f2a22;
  --ink-a22:    rgba(51,5,5,.22);
  --ink-a34:    rgba(51,5,5,.34);

  /* ── TIER 2 · SEMANTICS ──────────────────────────────────────────────────
     Rules reference ONLY these. Fifteen COLOUR semantics — see the note at the
     foot. (Type has its own tokens below; counted separately so this number
     doesn't quietly start including them.) */

  /* grounds */
  --field: radial-gradient(125% 85% at 32% 14%,
             var(--crimson-1) 0%, var(--crimson-3) 48%, var(--crimson-8) 100%);
  --field-plate: var(--crimson-5);
  /* The panel is --crimson-3, NOT --field-plate. Two surfaces, two names: the
     modal and select menus sit on the mid stop, plates and looks on --crimson-5.
     Collapsing them would change which ground the form's type is measured
     against, which is the error this whole pass exists to stop. */
  --panel:       var(--crimson-3);
  --field-deep:  var(--crimson-8);   /* the deepest field: footer, plate ink   */
  /* type ON the light ground — the docked header inverts */
  --on-light:    var(--crimson-3);
  --on-light-2:  var(--brick);

  /* type — each states the ground it is legible against, asserted at build */
  --on-field:    var(--ivory);              /* 16.0:1 on --crimson-3          */
  --on-field-2:  var(--oat);                /*  9.9:1 on --crimson-3          */
  /* IVORY at .72, not oat. This was --tx-3 with twelve uses and is the site's
     established dim; the single oat .72 (.reg-foot) was a newcomer of mine and is
     corrected to this. Two dim values differing only in hue is how a system starts
     drifting — the inventory is what caught it, not the eye. */
  --type-dim:    rgba(245,241,233,.72);     /*  7.0:1 on --crimson-3          */

  /* lines and marks */
  --hairline:     rgba(201,191,178,.26);    /* rules, dividers, chip borders  */
  --hairline-lit: rgba(201,191,178,.5);     /* the same rule, active          */
  --measure:      rgba(201,191,178,.55);    /* the tick marks of the measure  */

  /* A FIELD EDGE IS NOT A DECORATIVE HAIRLINE. This is the one place the
     consolidation had to go the OTHER way and add a semantic. Decorative
     hairlines are exempt from WCAG 1.4.11; an input boundary is not — it needs
     3:1. --hairline is 1.71:1, so inputs cannot use it. A system that cannot
     express an accessible field edge is missing a semantic, not carrying debt. */
  --field-edge:     rgba(201,191,178,.5);   /* 3.25:1 on --crimson-3          */

  /* SUPPLEMENTARY ONLY — DO NOT MAKE THIS THE FOCUS INDICATOR.
     rest>lit is 1.71:1, and even at full opacity the state change tops out at
     3.06:1, so a border cannot signal focus at ANY alpha. The indicator is the
     :focus-visible ring (oat solid, 9.94:1 on the panel). If a future tidy
     removes that ring because this border "already shows focus", it will have
     reintroduced a failure that measures better and works worse. */
  --field-edge-lit: rgba(201,191,178,.72);  /* 5.57:1, reinforcement only     */

  /* states and marks */
  --alert:       var(--coral);              /* 5.7:1 on --crimson-3           */
  --mark-relief: var(--crimson-9);          /* the wordmark, read by relief   */

  /* TYPE SCALE — the micro/label cluster, round 1 of 3 (round 2: discrete body/display
     .92-1.35rem; round 3: the 29 clamp() curves — a different exercise, min/max/slope
     each, not a discrete step). Twelve raw values, 461 matched elements, spread
     8.96-13.12px. Consolidated to three roles, decided by two tests: does a ROLE span
     multiple sizes (drift), and does a SIZE carry multiple unrelated roles (drift).
     Two roles — STATUS and HEADING — did not survive: every member was a
     misclassification, not a drifted value, so the role disappears rather than folds.
     .cal-open turned out to be a literal <button>, not a status indicator. .cal-state
     turned out to be a <p> of explanatory prose, not a tag. .doc h2 carries
     text-transform:uppercase and .26em tracking — the house's own label idiom — so it
     was a label wearing an <h2>, never a heading rendering too small. */
  --text-label:  .8rem;    /* 361 el. Anchor: .label alone is 290 of the cluster's 461.
                              Absorbs .foot-bottom .label, .access .where, .doc h2,
                              .hero-index.
                              RAISED .68 -> .8 (10.88px -> 12.8px) 2026-08-12, with .label
                              tracking cut .3em -> .14em. This token was the site's largest
                              legibility cost and it is NOT a contrast problem: measured
                              live, .label runs 17.61:1, far above the 4.5 it needs. The
                              strain is size and tracking — 10.88px uppercase at 3.264px
                              letterspacing reads as a monogram, not a caption. Peer check:
                              The Row's smallest homepage type is 11px at normal tracking
                              and it carries no display type at all. */
  --text-action: .72rem;   /* 18 el. .cta + .piece .act + .cal-open. The card-hover
                              link and the primary button were tested for co-occurrence,
                              not assumed: minimum gap between any pair is 1623px at a
                              900px desktop viewport and 1363px at 844px mobile — both
                              exceed one full viewport at both real device heights, so
                              a visitor never sees them together and the size
                              difference was doing no perceptual work. One value. */
  --text-spec:   .8rem;    /* 52 el. .slot-brief, .ts-note, .reg-note, .piece .mat,
                              .cal-card::after (a number the visitor reads to
                              calibrate — content, not chrome), .cal-state, figcaption
                              .b, and the three fine-print disclaimers (.fine,
                              .access .also, .confirm .fallback) — same register of
                              quiet secondary reading text as a caption. */

  /* ROUND 2 — discrete body/display, .92rem-1.35rem. NOT a modulus: eight values sat
     inside a 19.6% span with no dominant anchor, which is a cluster, not a scale — a
     1.067 step here would impose structure the content doesn't have. Save the ratio
     reasoning for round 3, where the clamps actually span a display range.
     One value (1.35rem, 12 matches, .mark) turned out to be dead code, not a
     candidate — removed outright, see the commit that did it, not folded here.
     Weighted by DECISIONS not render count: .92rem had the most matches (82) but
     they are all one selector (.foot-cols .c a, repeated per page) — the same shape
     as a footer link, not a central role. .95rem is four selectors covering real
     prose in four different contexts, so it is the true centre despite fewer total
     matches. */
  --text-body:    .95rem;   /* 4 selectors: legal <p>, spec <dd>, hero-foot, reg-foot.
                               Absorbs .92(footer nav), .98(modal intro), 1.02(hero-foot
                               desktop — see the note on --text-field's neighbor below),
                               1.06(craft col p). Every fold <=10% except the single
                               1.06 instance. */

  /* --text-field IS NOT A TYPE DECISION — it is a CONSTRAINT, like --field-edge above.
     1rem sits exactly on the threshold where iOS Safari zooms the viewport on focusing
     an input under 16px. It cannot move in either direction without either triggering
     that zoom (smaller) or breaking from the form's own rhythm for no reason (larger).
     Comment exists so a future consolidation doesn't "fix" it back into --text-body
     and silently reintroduce the zoom. */
  --text-field:   1rem;     /* .field input, .field select — HELD, functional */

  --text-numeral: 1.05rem;  /* piece/row/register numerals + the manifesto signature —
                               already unified before this pass; no fold needed, only
                               centralised into a name. */

  /* ROUND 3 — the clamp() curves. Min/max consolidation only; the shared 640/1088
     band (one slope per curve, derived so every curve transitions at the same two
     widths) is the separate, later exercise. These two are pure namings — zero
     value change, each was already unified across every selector that used it. */
  --text-manifesto-caption: clamp(1.02rem,1.9vw,1.45rem);  /* .m-setup, .m-conn */
  --text-h2-util: clamp(2rem,5vw,3.4rem);  /* .edit-head h2, .truesize h2, .release h2 —
                               utility section heads (Collection intro, sizing guide,
                               release state), one register below the marketing H2
                               family. THIS is the curve the 640/1088 band was derived
                               from — it anchors the system; nothing folds into it. */

  /* NOTE for whoever designs Privacy/Terms properly: .doc h2 folding into --text-label
     means those pages currently have no structural size above 10.88px — correct for
     this type system, hard to scan for a lawyer or a buyer actually reading the page.
     Flagged, not fixed here. */

  /* ── TIER 3 · COMPONENT ONE-OFFS ─────────────────────────────────────────
     Named for WHY they differ, never as a bare override — two dim values on
     crimson with no distinguishing name is how the next person picks wrong. */

  /* THE THRESHOLD'S MICRO-LABELS. Not --type-dim, on purpose.
     The threshold's job is to EMERGE from darkness rather than to be lit, and
     the eye reads its three marks as a pattern at top, centre and bottom — not
     as integrated luminance. Measured: the three ink 0.095% of the plate, so
     lifting all of them to .72 moves absolute plate luminance by 0.000065 and
     cannot be seen as brightness. But it is 35% more inked light in a
     distributed pattern, where .65 is 10%.
     .65 is the MINIMUM that clears 4.5:1 against the threshold's own lightest
     stop, --crimson-2, at 4.58:1. It would fail on --crimson-1 at 4.32:1, and
     that ground is irrelevant here: the threshold paints an opaque gradient at
     z-index 100, so --crimson-1 is never behind these labels. The setline takes
     --type-line-threshold below, where line-against-deboss governs. */
  /* RAISED .65 -> .72 (2026-08-13). At .65 this measured 4.30:1 against the worst-case
     ground and renders at 15.2px on /register/, below the 4.5:1 body-text floor — the
     site's last live contrast failure. .72 computes 5.01:1.
     Worst case is --crimson-1 #4A0A0A, NOT #330505: the page ground is a radial gradient
     and #330505 is only its 48% mid-stop, so the lightest stop is what light-on-dark type
     has to clear. */
  --type-dim-threshold: rgba(201,191,178,.72);

  /* THE SETLINE — "Presence is built." OAT at .72, and deliberately NOT
     --type-dim, which is IVORY at .72. Same alpha, different neutral: routing the
     setline through --type-dim would have shifted the hue of the most
     art-directed line on the site while every number still looked right. The
     governing pair here is line-against-deboss at 5.72:1, not line-against-ground. */
  --type-line-threshold: rgba(201,191,178,.72);

  /* THE THRESHOLD'S CONSTRUCTION LINES — inside #intro only, three strengths
     of the same idea, which is why they are one-offs and not a --grid semantic:
     the page's actual grid draws on --hairline. */
  /* the two other gradients built from the ladder — component-scoped, so tier 3 */
  --field-threshold: radial-gradient(122% 92% at 50% 42%,
                       var(--crimson-2) 0%, var(--crimson-3) 46%, var(--crimson-6) 100%);
  --field-slot: radial-gradient(120% 90% at 30% 20%,
                  var(--crimson-2) 0%, var(--crimson-5) 60%, var(--crimson-7) 100%);
  /* the deboss reads by relief; 1.03:1 on --crimson-3 is the point, not a fault */
  --deboss: var(--crimson-4);

  /* the docked header's wash when it crosses onto the light ground */
  --header-wash: rgba(245,241,233,.9);
  /* the linen glow behind the hero plate — two strengths of one effect */
  --glow:      rgba(242,232,222,.9);
  --glow-soft: rgba(242,232,222,.85);

  --threshold-frame: rgba(201,191,178,.20);
  --threshold-rule:  rgba(201,191,178,.40);
  --threshold-tick:  rgba(201,191,178,.32);
}

/* ── WHY FIFTEEN COLOUR SEMANTICS, AND NOT TWELVE ────────────────────────────
   Colour count only — type semantics (--text-*) are tracked where they're
   defined, above, so this number doesn't silently absorb every later family.
   The rewire itself added three that the inventory alone did not show, and each
   is a distinction a rule genuinely needs rather than a value someone liked:

     --panel       the modal sits on --crimson-3, plates on --crimson-5. Naming one
                   surface would have meant measuring the form's type against a
                   ground it does not sit on.
     --on-light    the docked header inverts to the ivory ground; without a name
                   for type on light, those rules would reach into tier 1.
     --on-light-2  the same, for secondary.

   Fifteen colour semantics against sixteen ad-hoc names is a thin win on count
   and a large one on meaning: every one of the fifteen states what it is for,
   and no rule holds a hex. The honest number is fifteen, not the flattering
   twelve.
   ──────────────────────────────────────────────────────────────────────────── */


  /* ============================================================
     SVRV &mdash; Flagship v11 &middot; "BUILT TO HOLD" &mdash; brand-canon aligned
     Concept build: Bodoni Moda (display) + Switzer (grotesk).
     Production faces: licensed PP Cirka + DM Sans.
     ============================================================ */
  @font-face{font-family:'Bodoni Moda';font-style:normal;font-weight:400 600;font-display:swap;src:url("../fonts/bodoni-normal.woff2") format("woff2");}
  @font-face{font-family:'Bodoni Moda';font-style:italic;font-weight:400 600;font-display:swap;src:url("../fonts/bodoni-italic.woff2") format("woff2");}
  @font-face{font-family:'Switzer';font-style:normal;font-weight:400;font-display:swap;src:url("../fonts/switzer-400.woff2") format("woff2");}
  @font-face{font-family:'Switzer';font-style:normal;font-weight:500;font-display:swap;src:url("../fonts/switzer-500.woff2") format("woff2");}
  /* Colour tokens live in _tokens.css, prepended here by the build. What remains
     is what is NOT colour: the easings and the type and layout measures. */
  :root{
    /* Depth Crimson &mdash; THE WORLD */
    /* the deepest ground */
    /* the one point of heat, on ivory */
    /* measure-marks + hairlines ONLY */
    /* oat edge-light for cut lines */
    --serif:'Bodoni Moda','Didot','Bodoni 72','Hoefler Text',Georgia,serif;
    --sans:'Switzer',-apple-system,BlinkMacSystemFont,'Helvetica Neue','Segoe UI',Arial,sans-serif;
    --indent:38.2vw; --edge:clamp(1.4rem,5vw,5.5rem);
    --ease:cubic-bezier(.22,1,.36,1);        /* the settle */
    --blade:cubic-bezier(.16,.84,.28,1);     /* the draw &mdash; leaves immediately, settles long */
    --kill:cubic-bezier(.85,0,.9,.35);       /* the exit &mdash; accelerates away, never rewinds */
    --cut:cubic-bezier(.05,.7,.1,1);         /* the incision &mdash; instant velocity, long decel; a blade never hesitates */
    /* semantic &mdash; flip in .light */
    }
  /* THE LIGHT THEME re-points SEMANTICS, assigned from PRIMITIVES ONLY. Never one
     semantic from another: --panel:var(--on-field) while --on-field is redefined here
     is circular and silently gives the light panel a crimson ground. */
  .light{ --on-field:var(--crimson-3); --on-field-2:var(--brick); --type-dim:var(--brick-deep);
    --hairline:var(--ink-a22); --hairline-lit:var(--ink-a34); --measure:var(--ink-a34);
    --panel:var(--ivory); --field-deep:var(--ivory);
    background:var(--ivory); color:var(--crimson-3); }

  *{box-sizing:border-box;margin:0;padding:0}
  html{-webkit-text-size-adjust:100%}
  html,body{background:var(--field) fixed;color:var(--on-field);}
  body{font-family:var(--sans);font-weight:400;line-height:1.5;overflow-x:hidden;-webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;}
  ::selection{background:var(--on-field);color:var(--field-deep);}
  a{color:inherit;text-decoration:none;} img{display:block;max-width:100%;} button{font:inherit;color:inherit;background:none;border:0;cursor:pointer;}
  :focus-visible{outline:2px solid currentColor;outline-offset:3px;}
  .skip{position:absolute;left:-9999px;top:0;z-index:200;background:var(--on-field);color:var(--field-deep);padding:.8rem 1.2rem;font-family:var(--sans);font-size:.8rem;letter-spacing:.1em;}
  .skip:focus{left:0;}

  .grain{position:fixed;inset:0;z-index:60;pointer-events:none;opacity:.07;mix-blend-mode:soft-light;
    background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='140' height='140'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");}

  /* tracking .3em -> .14em with the size raise: at 12.8px, .3em put 3.84px between every
     glyph, which is what made these read as monograms rather than captions. */
  .label{font-family:var(--sans);font-size:var(--text-label);font-weight:500;letter-spacing:.14em;text-transform:uppercase;color:var(--on-field-2);}
  .wrap{max-width:1560px;margin:0 auto;padding:0 var(--edge);}
  /* editorial offset &mdash; content set right of the golden seam */
  .indent{padding-left:var(--indent);}
  @media(max-width:820px){ :root{--indent:0} .indent{padding-left:0} }

  /* incision &mdash; a hairline that cuts in before an overline */
  .incise{position:relative;padding-top:1.5rem;width:fit-content;}
  /* THE MEASURE IS THE WIDTH OF THE LABEL. Five words, no cap, no floor.
     It used to be width:210px;max-width:60% — and 60% resolves against the label's
     BOX, not its text, so the device was keyed to `display`, not to content: 24
     shrink-wrapped labels got 60% of their text (30-126px) while 9 block labels
     overflowed the cap and all landed on 210px. The word "Entry" rendered a 30px
     stub on a piece page and a 210px rule on /request/ — same word, same size, seven
     times the length. width:fit-content makes the box the text, so width:100% below
     is literally the label's width and nothing needs remembering.
     Measured before removing the cap: the longest label is 232px at 1280 and 201px at
     390, so nothing is left unbounded that wants bounding. Exactly one label wraps
     ("FW26 - Milano, September") and there its longest line and block width are
     identical, so the rule needs no clause for wrapping. */
  .incise::before{content:"";position:absolute;top:0;left:0;height:1.5px;width:100%;
    background:var(--measure);
    transform:scaleX(0);transform-origin:left;transition:transform .6s var(--cut) .05s;}
  .incise.in::before{transform:scaleX(1);}
  /* THE MEASURE (primitive 4) &mdash; once the rule has landed, the marks tick out along it,
     left to right, in the order a measurement is actually taken. Minor mark every 30px,
     major every 150px. Every section measures before it places anything. */
  .incise::after{content:"";position:absolute;top:0;left:0;height:9px;width:100%;
    opacity:.5;pointer-events:none;
    background-image:
      repeating-linear-gradient(90deg, var(--measure) 0 1px, transparent 1px 12px),
      repeating-linear-gradient(90deg, var(--measure) 0 1px, transparent 1px 60px);
    background-size:100% 5px, 100% 9px;background-repeat:no-repeat;
    clip-path:inset(0 100% 0 0);transition:clip-path .5s var(--cut) .58s;}
  .incise.in::after{clip-path:inset(0 0 0 0);}

  /* ===== NAV ===== */
  header{position:fixed;top:0;left:0;right:0;z-index:58;padding:1.5rem var(--edge);display:flex;align-items:center;justify-content:space-between;transition:background .5s var(--ease),padding .5s var(--ease),transform .45s var(--ease);}
  header.hidden{transform:translateY(-101%);}
  header.docked:not(.onlight){background:rgba(26,3,3,.78);backdrop-filter:blur(14px);}
  header.docked{padding:1rem var(--edge);}
  .mark{color:var(--on-field-2);transition:color .4s var(--ease);}
  /* font-family, font-size, letter-spacing and text-indent removed 2026-07-31 —
     dead since the wordmark became a masked .wm span with no text-node child.
     Verified empirically: setting font-size to 4rem (vs the old 1.35rem) moved
     nothing, on .mark or on .wm. .foot-mark carries the identical leftover as a
     clamp() — flagged for round 3, not touched here. */
  .nav-r{display:flex;gap:2.4rem;align-items:center;}
  .nav-r .label{color:var(--on-field-2);transition:color .4s var(--ease);}
  .nav-r a.label{padding:.8rem 0;margin:-.8rem 0;}
  .req{position:relative;color:var(--on-field-2);transition:color .4s var(--ease);}
  .req::after{content:"";position:absolute;left:0;bottom:.45rem;height:1px;width:100%;background:currentColor;transform:scaleX(1);transform-origin:right;transition:transform .5s var(--ease);}
  .req:hover::after{transform:scaleX(0);transform-origin:left;}
  .req::before{content:"";position:absolute;left:0;bottom:.45rem;height:1.5px;width:100%;background:var(--hairline-lit);transform:scaleX(0);transform-origin:left;transition:transform .5s var(--blade) .05s;}
  .req:hover::before{transform:scaleX(1);}
  /* past the severance the header sits on oat &mdash; ink type on an oat scrim so scrolling display type never collides */
  header.docked.onlight{background:var(--header-wash);backdrop-filter:blur(14px);border-bottom:1px solid rgba(51,5,5,.12);}
  header.onlight .mark{color:var(--panel);}
  header.onlight .nav-r .label{color:var(--on-light-2);}
  header.onlight .req{color:var(--panel);}
  header.onlight .req::before{background:var(--directive);}
  /* NAV WRAPS TO A SECOND ROW ON PHONES — it does not fit on one, and it never did.
     Measured at 360: the four labels are 96+73+62+69 = 300px of text into the 264px
     left beside the wordmark. Before this rule "Atelier" was clipped at the viewport
     edge and "Request Access" sat entirely off-screen at 394-463px. It read as no
     overflow because body{overflow-x:hidden} was masking it, so every overflow check
     on this site passed while the primary CTA was invisible on a phone. Interior pages
     shipped with this; the homepage only inherited it when the navs were made to match. */
  @media(max-width:640px){
    .nav-r .sep{display:none}
    header{flex-wrap:wrap;row-gap:.7rem}
    .nav-r{gap:1.15rem;width:100%;justify-content:space-between}
  }
  /* Below ~420 the four labels still overrun the row by ~17px at .14em. The saving comes
     out of TRACKING, not size: the legibility finding was that 10.88px was too small,
     not that .14em was too tight, so shrinking the type here would undo the fix to
     solve a different problem. .06em on the nav only; .label elsewhere is untouched. */
  @media(max-width:420px){ .nav-r .label{letter-spacing:.06em} }
  /* At 320 even .06em overruns. Let the nav itself wrap rather than clip the CTA — this
     project tests 360/390/430, but "below the tested range" is not a reason to ship a
     primary action off the edge of the screen. */
  @media(max-width:340px){ .nav-r{flex-wrap:wrap;row-gap:.55rem;column-gap:1rem;justify-content:flex-start} }

  /* ===== THE THRESHOLD &mdash; BUILT, not opened. See _BUILT-LIVE.md =====
     Order of construction is doctrine: measure &rarr; structure &rarr; content &rarr; contact.
     The Depth Crimson field and the blind deboss are kept; only the VERB changed. */
  #intro{display:none;}
  .js #intro{display:block;position:fixed;inset:0;z-index:100;overflow:hidden;
    background:var(--field-threshold);}
  /* the exit: a straight edge clears the threshold. accelerates away, never rewinds. */
  #intro.done{clip-path:inset(0 0 100% 0);transition:clip-path .6s var(--kill);}
  #intro .field{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;}

  /* 1 &mdash; THE MEASURE. the rule runs to length, then the marks tick out.
     nothing is placed until the grid it sits on exists. */
  #intro .rule{position:relative;flex:none;width:min(560px,62vw);height:1px;background:var(--threshold-rule);
    transform:scaleX(0);transform-origin:left;transition:transform .62s var(--blade) .45s;}
  #intro.go .rule{transform:scaleX(1);}
  #intro .rule i{position:absolute;top:0;width:1px;height:7px;background:var(--threshold-tick);
    transform:scaleY(0);transform-origin:top;
    transition:transform .26s var(--cut);transition-delay:calc(.42s + var(--i) * .04s);}
  #intro.go .rule i{transform:scaleY(1);}
  #intro .rule i.mid{height:15px;background:var(--hairline-lit);}

  /* 2 &mdash; THE STRUCTURE. one pen travels the frame clockwise; rules meet at corners. */
  #intro .frame{position:absolute;inset:clamp(1.2rem,3.5vw,2.6rem);pointer-events:none;}
  #intro .frame i{position:absolute;background:var(--threshold-frame);}
  #intro .frame i:nth-child(1){top:0;left:0;width:100%;height:1px;transform:scaleX(0);transform-origin:left;transition:transform .3s var(--blade) .72s;}
  #intro .frame i:nth-child(2){top:0;right:0;width:1px;height:100%;transform:scaleY(0);transform-origin:top;transition:transform .3s var(--blade) .88s;}
  #intro .frame i:nth-child(3){bottom:0;right:0;width:100%;height:1px;transform:scaleX(0);transform-origin:right;transition:transform .3s var(--blade) 1.04s;}
  #intro .frame i:nth-child(4){bottom:0;left:0;width:1px;height:100%;transform:scaleY(0);transform-origin:bottom;transition:transform .3s var(--blade) 1.2s;}
  #intro.go .frame i{transform:scale(1);}

  /* 3 &mdash; THE CONTENT. the wordmark is STRUCK into the crimson &mdash; no ink, only pressure. */
  #intro .deboss{margin-top:clamp(1.5rem,3.4vw,2.6rem);
    font-family:var(--serif);font-weight:400;font-size:clamp(2.4rem,10vw,8rem);
    letter-spacing:.42em;text-indent:.42em;color:var(--deboss);line-height:1;user-select:none;
    /* more pressure: the die has to bite, or on a bright screen the field reads as empty */
    text-shadow:0 .012em 0 rgba(255,228,220,.30), 0 .025em .06em rgba(255,228,220,.14), 0 -.012em 0 rgba(0,0,0,.80), 0 -.025em .075em rgba(0,0,0,.62);
    clip-path:inset(0 100% 0 0);transition:clip-path .55s var(--cut) 1.3s;}
  #intro.go .deboss{clip-path:inset(0 0 0 0);}
  /* the type-only line sets itself, word by word. upright &mdash; no italic in the house. */
  #intro .setline{color:var(--type-line-threshold);margin-top:clamp(1.1rem,2.6vw,1.8rem);display:flex;gap:.62em;
    font-family:var(--sans);font-size:.62rem; /* held: same threshold plate as #intro .mk — not the field-label density question, a different hold for a different reason */ font-weight:500;letter-spacing:.42em;text-indent:.42em;
    text-transform:uppercase;color:var(--type-dim-threshold);}
  #intro .setline span{clip-path:inset(0 100% 0 0);
    transition:clip-path .42s var(--cut);transition-delay:calc(1.62s + var(--i) * .07s);}
  #intro.go .setline span{clip-path:inset(0 0 0 0);}
  #intro .mk{position:absolute;left:50%;transform:translateX(-50%);
    font-family:var(--sans);font-size:.56rem; /* held: same threshold plate as .setline below — judge as an image, not a diff, per the .62->.72 alpha precedent */ font-weight:500;letter-spacing:.34em;
    text-transform:uppercase;color:var(--type-dim-threshold);white-space:nowrap;
    clip-path:inset(0 100% 0 0);transition:clip-path .4s var(--cut) 2.05s;}
  #intro .mk.a{top:clamp(2.1rem,4.6vw,3.6rem);}
  #intro .mk.b{bottom:clamp(2.1rem,4.6vw,3.6rem);}
  #intro.go .mk{clip-path:inset(0 0 0 0);}

  /* 4 &mdash; CONTACT. built. the cue draws only once the construction is complete. */
  #intro .cue{position:absolute;bottom:clamp(4.4rem,8.5vw,6.6rem);left:50%;width:1px;height:34px;
    background:linear-gradient(180deg,var(--measure),transparent);
    transform:translateX(-50%) scaleY(0);transform-origin:top;transition:transform .5s var(--blade);}
  #intro.ready .cue{transform:translateX(-50%) scaleY(1);}

  /* the first gesture during construction snaps it complete &mdash; never make him wait on a timer */
  #intro.rush .rule,#intro.rush .rule i,#intro.rush .frame i,
  #intro.rush .deboss,#intro.rush .setline span,#intro.rush .mk{transition-duration:.26s;transition-delay:0s;}
  body.sealed{overflow:hidden;height:100vh;}

  /* ===== HERO ===== */
  .hero{position:relative;min-height:100svh;display:grid;align-items:end;padding-top:clamp(5.5rem,13vh,8rem);padding-bottom:clamp(4rem,9vh,6.5rem);overflow:hidden;}
  .hero-plate{position:absolute;inset:0;z-index:0;background:var(--field-plate);}
  .hero-plate img{width:100%;height:100%;object-fit:cover;object-position:64% 42%;opacity:.95;transform:scale(1.12);will-change:transform;}
  .hero-plate::after{content:"";position:absolute;inset:0;
    background:linear-gradient(180deg,rgba(26,3,3,.45) 0%,rgba(26,3,3,0) 28%,rgba(26,3,3,0) 42%,rgba(26,3,3,.88) 100%),
      linear-gradient(75deg,rgba(26,3,3,.9) 0%,rgba(45,6,6,.55) 34%,rgba(58,10,10,.06) 60%,rgba(58,10,10,0) 76%),
      radial-gradient(80% 70% at 22% 80%,rgba(26,3,3,.55),transparent 60%);}
  .hero .wrap{position:relative;z-index:2;width:100%;}
  .hero-eyebrow{margin-bottom:clamp(1.2rem,4vh,2.2rem);}
  .hero h1{font-family:var(--serif);font-weight:400;font-size:clamp(3rem,8.4vw,8.6rem);line-height:1.02;letter-spacing:-.016em;text-wrap:balance;max-width:15ch;color:var(--on-field-2);font-synthesis:none;}
  .hero h1 em{font-style:normal;}
  .hero h1 .sev{position:relative;font-style:normal;white-space:nowrap;}
  /* the strike &mdash; the word severed as it is spoken; warm hairline, no glow */
  .hero h1 .sev::after{content:"";position:absolute;left:-.01em;right:-.01em;top:53%;height:1px;background:rgba(217,176,176,.85);transform:scaleX(var(--sevcut,0));transform-origin:left;transition:transform .45s var(--cut) .9s;}
  .hero-foot{margin-top:clamp(1.8rem,5vh,3rem);display:flex;flex-wrap:wrap;gap:1.6rem 3rem;align-items:baseline;max-width:60ch;}
  .hero-foot p{color:var(--on-field-2);font-size:var(--text-body);max-width:34ch;line-height:1.55;}
  /* CTA &mdash; correspondence, not checkout: letterspaced caps on a cut underline */
  .cta{display:inline-flex;align-items:center;gap:.7rem;font-family:var(--sans);font-size:var(--text-action);font-weight:500;letter-spacing:.26em;text-transform:uppercase;color:var(--on-field);padding:.9rem 0;position:relative;transition:color .4s var(--ease);}
  .cta .arw{transition:transform .5s var(--ease);}
  .cta::after{content:"";position:absolute;left:0;bottom:.45rem;height:1px;width:100%;background:currentColor;opacity:.55;transform:scaleX(1);transform-origin:right;transition:transform .5s var(--ease);}
  .cta::before{content:"";position:absolute;left:0;bottom:.45rem;height:1.5px;width:100%;background:var(--hairline-lit);transform:scaleX(0);transform-origin:left;transition:transform .5s var(--blade) .05s;}
  .cta:hover::after{transform:scaleX(0);transform-origin:left;}
  .cta:hover::before{transform:scaleX(1);}
  .cta:hover .arw{transform:translateX(6px);}
  .light .cta::before{background:var(--directive);}
  .scrollcue{position:absolute;left:var(--edge);bottom:clamp(1rem,3vh,2rem);z-index:3;display:flex;align-items:center;gap:.8rem;color:var(--on-field-2);}
  .scrollcue .bar{width:1.5px;height:34px;background:var(--hairline-lit);opacity:.7;position:relative;overflow:hidden;}
  .scrollcue .bar::after{content:"";position:absolute;inset:0;background:var(--on-field-2);animation:drop 2.4s var(--ease) infinite;}
  @keyframes drop{0%{transform:translateY(-100%)}60%,100%{transform:translateY(100%)}}
  .hero-index{position:absolute;right:var(--edge);bottom:clamp(1rem,3vh,2rem);z-index:3;color:var(--on-field-2);font-variant-numeric:tabular-nums;letter-spacing:.2em;font-size:var(--text-label);}
  @media(max-width:640px){
    .scrollcue{display:none}
    .hero{padding-bottom:3.4rem}
    /* the figure IS the image at 390 &mdash; no push-crop, no zoom */
    .hero-plate img{object-position:48% 35%;transform:scale(1)}
    .hero-plate::after{background:linear-gradient(180deg,rgba(26,3,3,.45) 0%,rgba(26,3,3,0) 28%,rgba(26,3,3,0) 42%,rgba(26,3,3,.88) 100%),
      linear-gradient(75deg,rgba(26,3,3,.55) 0%,rgba(45,6,6,.3) 34%,rgba(58,10,10,.04) 60%,rgba(58,10,10,0) 76%)}
    /* caption-size caps drop the display tracking.
       .label's override REMOVED 2026-08-13: it existed to cut .3em down to .18em on
       phones. The base is now .14em, so this rule was setting mobile LOOSER than
       desktop — the inverse of its own stated intent. */
    .cta{letter-spacing:.2em}
    /* .nav-edit{display:none} REMOVED 2026-08-13 with the class itself — it hid the
       homepage's only content link on phones, leaving one nav item. */
    .hero{padding-top:4rem}
    .hero h1{font-size:clamp(2.5rem,9.5vw,3.2rem)}
    .hero-foot{margin-top:1.4rem;gap:1rem 1.6rem}
    /* .hero-foot p mobile override REMOVED 2026-07-31 -- the base rule now reads
       --text-body (.95rem), so this override set the identical value the base
       already provides. Verified both sides resolved before deleting: 16.32px
       desktop, 15.2px mobile, i.e. exactly .95rem == --text-body. */
    /* .access h2{font-size:clamp(2.1rem,9vw,3.4rem)} REMOVED 2026-07-31 -- a SECOND,
       separate @media(max-width:640px) block near .access's own rules also targets
       this selector with clamp(2.2rem,10vw,3.4rem), later in source order. Same
       specificity, identical condition: the later rule always wins by cascade order,
       so this one could never render at any viewport width. Verified empirically at
       390px: resolves to 39px, matching the later rule's prediction exactly, not
       this one's (35.1px). Not a fold -- a corpse, same species as round 2's
       .hero-foot p check but confirmed dead instead of confirmed live. */
  }
  @media(max-width:480px){ .facts{grid-template-columns:1fr} }

  /* ===== MANIFESTO ===== */
  .manifesto{padding-block:clamp(6rem,18vh,14rem) clamp(4rem,10vh,8rem);position:relative;}
  .manifesto .label{margin-bottom:2.8rem;display:block;}
  .manifesto p{font-family:var(--serif);font-weight:400;letter-spacing:-.01em;max-width:20ch;text-wrap:balance;color:var(--on-field-2);}
  .m-setup{font-family:var(--sans);font-size:var(--text-manifesto-caption);font-weight:500;color:var(--on-field-2);letter-spacing:.01em;margin-bottom:1.6rem;}
  /* MANIFESTO STATEMENT: ref .m-verdict 41.6/96, ratio 0.7 -> .m-cut (29.1/67.2).
     No token: one selector each. */
  .m-verdict{font-size:clamp(2.6rem,6.6vw,6rem);line-height:1.0;letter-spacing:-.018em;margin-bottom:2.4rem;}
  .m-conn{font-family:var(--sans);font-size:var(--text-manifesto-caption);font-weight:500;color:var(--on-field-2);margin-bottom:2.6rem;}
  .m-cut{font-size:clamp(1.8rem,4.8vw,4.2rem);font-style:normal;line-height:1.02;}
  .m-cut em{font-style:italic;}  /* the single italic in the house: whisper */
  /* THE MARGIN MEASURE &mdash; the left field is not dead space, it is the sheet's margin.
     A vertical rule with its marks, drawn top-down. Primitives 1 + 4, one moving part. */
  .manifesto .marginrule{position:absolute;top:clamp(6rem,18vh,14rem);bottom:clamp(4rem,10vh,8rem);
    left:calc(var(--indent) - clamp(2rem,4vw,4.5rem));width:9px;pointer-events:none;
    background-image:linear-gradient(180deg,var(--measure),var(--measure)),
      repeating-linear-gradient(180deg,var(--measure) 0 1px,transparent 1px 48px);
    background-size:1px 100%,6px 100%;background-position:0 0,1px 0;background-repeat:no-repeat;
    transform:scaleY(0);transform-origin:top;}
  .js .rv.marginrule,.js .rv.marginrule.in{clip-path:none;opacity:.4;transition:transform 1s var(--blade) .1s;}
  .js .rv.marginrule.in{transform:scaleY(1);}
  @media(max-width:820px){ .manifesto .marginrule{display:none} }
  .manifesto .sig{margin-top:3.6rem;max-width:44ch;color:var(--on-field-2);font-family:var(--sans);font-size:var(--text-numeral);line-height:1.6;}

  /* ===== THE EDIT ===== */
  .edit{padding-block:clamp(3rem,8vh,6rem) clamp(4rem,9vh,7rem);}
  .edit-head{display:flex;justify-content:space-between;align-items:flex-end;flex-wrap:wrap;gap:1rem;margin-bottom:clamp(2.5rem,6vh,4rem);}
  .edit-head h2{font-family:var(--serif);font-weight:400;font-size:var(--text-h2-util);letter-spacing:-.01em;color:var(--on-field-2);}
  .edit-head .label{color:var(--on-field-2);}
  /* the metadata column is FIXED so it aligns on a constant across every row; the name column
     is the only flexible one, so the procession's scale changes never rag the grid. */
  .piece{display:grid;grid-template-columns:4.5rem minmax(0,1fr) 15rem 7rem 6rem;align-items:center;gap:1.5rem;padding:1.7rem 0;position:relative;cursor:pointer;}
  .piece:last-child{border-bottom:1px solid var(--hairline);}
  /* THE MEASURED ROW &mdash; the collection is measured out, piece by piece. The rule and its
     marks are one element drawn by one scaleX, so a row still costs exactly one moving part. */
  .piece::before{content:"";position:absolute;left:0;top:0;height:6px;width:100%;z-index:1;
    background-image:linear-gradient(90deg,var(--hairline),var(--hairline)),
      repeating-linear-gradient(90deg,var(--hairline) 0 1px,transparent 1px 60px);
    background-size:100% 1px,100% 5px;background-position:0 0,0 1px;background-repeat:no-repeat;
    transform:scaleX(0);transform-origin:left;
    transition:transform .62s var(--blade);transition-delay:calc(var(--i,0) * 140ms);}
  .piece.in::before{transform:scaleX(1);}
  /* the procession &mdash; varied scale AND structure. a uniform grid is what killed the last
     attempt, so the accent rows get their own column rhythm, not just bigger type. */
  .piece.p-lg{padding:2.7rem 0;}
  .piece.p-lg .name{font-size:clamp(2rem,5.2vw,4rem);}
  .piece.p-md{padding:2.1rem 0;}
  .piece.p-md .name{font-size:clamp(1.7rem,4.2vw,3.1rem);}
  /* the numeral is an annotation on the measure, not a floating label &mdash; it sits at the line */
  .piece .num{align-self:start;padding-top:.55rem;}
  .piece .num{font-family:var(--serif);font-weight:500;font-size:var(--text-numeral);text-align:right;padding-right:.4rem;color:var(--on-field-2);font-variant-numeric:tabular-nums;letter-spacing:.1em;}
  .piece .name{font-family:var(--serif);font-size:clamp(1.5rem,3.4vw,2.6rem);line-height:1;color:var(--on-field-2);transition:transform .55s var(--ease),color .4s var(--ease);}
  .piece .mat{font-size:var(--text-spec);letter-spacing:.14em;text-transform:uppercase;color:var(--on-field-2);line-height:1.6;opacity:.8;transition:opacity .5s var(--ease);}
  .piece .mat{display:flex;flex-wrap:wrap;gap:0 .42em;}
  .piece .mat span{white-space:nowrap;}
  .piece .mat span+span::before{content:"\00B7";margin-right:.42em;color:inherit;opacity:.75;}
  .piece .price{font-family:var(--sans);font-size:1rem;color:var(--on-field-2);font-variant-numeric:tabular-nums;text-align:right;}
  .piece .act{justify-self:end;font-size:var(--text-action);font-weight:500;letter-spacing:.24em;text-transform:uppercase;color:var(--on-field-2);position:relative;transition:color .4s var(--ease);}
  .piece .act::after{content:"\2192";margin-left:.5rem;display:inline-block;transition:transform .5s var(--ease);}
  .piece::after{content:"";position:absolute;left:0;bottom:0;height:1.5px;width:100%;background:var(--hairline-lit);transform:scaleX(0);transform-origin:left;transition:transform .6s var(--blade);z-index:1;}
  .js .piece.rv.in{clip-path:inset(0 -6px -.22em -6px);}
  @media(hover:hover){
    .piece:hover::after{transform:scaleX(1);}
    .piece:hover .name{transform:translateX(8px);}
    .piece:hover .mat{opacity:1;color:var(--on-field-2);}
    .piece:hover .act{color:var(--on-field-2);}
    .piece:hover .act::after{transform:translateX(6px);}
  }
  .piece>span{position:relative;z-index:1;}
  @media(max-width:900px){
    /* the name gets the full width so the accent rows never wrap; price and action
       share the last line, which reads like an order sheet and gives the action a real target */
    .piece,.piece.p-lg,.piece.p-md{grid-template-columns:2.6rem minmax(0,1fr) auto;grid-template-areas:"num name name" "num mat mat" "num price act";row-gap:.5rem;column-gap:1rem;}
    .piece .num{grid-area:num}.piece .name{grid-area:name}.piece .mat{grid-area:mat}
    .piece .price{grid-area:price;text-align:left;justify-self:start}
    .piece .act{grid-area:act;justify-self:end;padding:.5rem 0 .5rem .75rem}
    /* NO HOVER ON A PHONE &mdash; the bare arrow is then the only affordance, and reads as a
       stray glyph. The word comes back where hover cannot carry the meaning. */
    .piece .act::before{content:"Request";margin-right:.15rem;}
    /* the procession must survive the stack &mdash; clamp minimums converge and flatten it otherwise */
    .piece.p-lg .name{font-size:clamp(1.95rem,7.4vw,2.9rem);}
    .piece.p-md .name{font-size:clamp(1.7rem,6vw,2.4rem);}
    .piece.p-lg{padding:2.2rem 0;} .piece.p-md{padding:1.95rem 0;}
  }

  @media(max-width:640px){ .piece .mat{letter-spacing:.1em} }

  /* ===== LOOKBOOK &mdash; asymmetric spread ===== */
  .lookbook{padding-block:clamp(2rem,6vh,5rem) clamp(5rem,13vh,10rem);}
  .lookbook > .label{display:block;margin-bottom:2.4rem;}  /* scope: must not hit .look figcaption.label */
  .looks{display:grid;grid-template-columns:1.75fr 1fr;gap:clamp(.6rem,1.6vw,1.4rem);align-items:start;}
  .look{position:relative;overflow:hidden;aspect-ratio:3/4;background:var(--field-plate);}
  .look:nth-child(1){grid-row:1/3;aspect-ratio:auto;align-self:stretch;}
  .look:nth-child(2){margin-top:clamp(3rem,10vh,7rem);}
  .look:nth-child(3){aspect-ratio:4/5;margin-top:clamp(.8rem,2.5vh,2rem);}
  /* the frame wipes (.rv); the image does NOT scale in &mdash; a thing that grows was never
     built, it inflated. one moving part per reveal. scale is kept for hover only. */
  .look img{width:100%;height:100%;object-fit:cover;transform:scale(1);transition:transform 1.2s var(--ease);}
  .look:nth-child(2) img,.look:nth-child(3) img{filter:brightness(1.22) contrast(.97);}
  @media(hover:hover){ .look.in:hover img{transform:scale(1.05);} }
  .look figcaption{position:absolute;left:0;right:0;bottom:0;padding:1rem 1.1rem;color:var(--on-field-2);background:linear-gradient(0deg,rgba(26,3,3,.75),transparent);}
  @media(max-width:700px){
    .looks{grid-template-columns:1fr 1fr;}
    .look:nth-child(1){grid-row:auto;grid-column:1/-1;aspect-ratio:16/11;}
    .look:nth-child(3){margin-top:0;aspect-ratio:3/4;}
  }

  /* ===== CAMPAIGN &mdash; full-bleed figure ===== */
  .campaign{position:relative;height:100svh;overflow:hidden;display:flex;align-items:flex-end;}
  .campaign img{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;object-position:center;transform:scale(var(--camz,1.06));will-change:transform;}
  .campaign::after{content:"";position:absolute;inset:0;background:linear-gradient(180deg,rgba(26,3,3,.55),rgba(26,3,3,0) 34%,rgba(26,3,3,.2) 62%,rgba(26,3,3,.92));}
  .campaign .wrap{position:relative;z-index:2;padding-bottom:clamp(2rem,5vh,4rem);width:100%;}
  .campaign .label{display:block;margin-bottom:1.4rem;color:var(--on-field-2);}
  .campaign h2{font-family:var(--serif);font-weight:400;font-size:clamp(2.1rem,7vw,5.6rem);line-height:1.0;letter-spacing:-.015em;color:var(--on-field-2);text-wrap:balance;max-width:15ch;}
  .campaign h2 em{font-style:normal;color:inherit;}

  /* ===== THE SEVERANCE &mdash; the line IS the cut: the oat plate rises and SEATS against the blade ===== */
  .severance{position:relative;height:34vh;overflow:hidden;}
  .severance .lightworld{position:absolute;left:0;right:0;top:50%;bottom:-6rem;background:var(--on-field);
    transform:translateY(calc((1 - var(--sev,0)) * 5rem));}
  .severance .hblade{position:absolute;left:0;right:0;top:calc(50% - 1px);height:1px;transform:scaleX(var(--sevx,0));transform-origin:left;z-index:5;transition:height .09s cubic-bezier(0,.9,.2,1),box-shadow .09s cubic-bezier(0,.9,.2,1);
    background:linear-gradient(90deg,transparent,var(--glow) 8%,var(--glow) 92%,transparent);}
  .severance .tag{position:absolute;top:calc(50% - 2.8rem);left:50%;transform:translateX(-50%) translateY(6px);opacity:0;color:var(--on-field-2);z-index:6;letter-spacing:.5em;text-indent:.5em;transition:opacity .5s var(--ease) .1s,transform .5s var(--ease) .1s;}
  .severance.seated .tag,.severance.rested .tag{opacity:1;transform:translateX(-50%) translateY(0);}
  .severance.seated .hblade{height:2px;box-shadow:0 0 26px var(--glow-soft);}
  .severance.seated .lightworld{animation:seat .14s var(--ease);}
  @keyframes seat{0%{margin-top:-3px}100%{margin-top:0}}
  @media(max-width:820px){ .severance{height:22svh} .severance .tag{top:calc(50% - 1.9rem)} }

  /* ===== CRAFT (light) ===== */
  .craft{padding:clamp(2.5rem,5vh,4rem) 0 clamp(4rem,9vh,7rem);}
  .craft .grid{display:grid;grid-template-columns:1fr;gap:clamp(3rem,7vh,5rem);align-items:center;}
  @media(min-width:900px){ .craft .grid{grid-template-columns:1fr 1fr;} }
  .craft h2{font-family:var(--serif);font-weight:400;font-size:clamp(1.7rem,5.8vw,4.5rem);line-height:1.04;letter-spacing:-.01em;color:var(--on-field);text-wrap:balance;max-width:13ch;}
  .craft .col p{color:var(--type-dim);font-size:var(--text-body);line-height:1.72;max-width:42ch;margin-top:1.6rem;}
  .craft .label{color:var(--on-field-2);display:block;margin-bottom:1.4rem;}
  @media(max-width:820px){ .craft{padding-top:2rem} }
  .detail{position:relative;aspect-ratio:4/5;overflow:hidden;background:var(--field-plate);}
  .detail img{width:100%;height:100%;object-fit:cover;object-position:center;transform:scale(1);transition:transform 1.2s var(--ease);}
  /* THE INK IS PINNED, NOT INHERITED. This caption sits on its own dark scrim, over a
     photograph — but it lives inside .craft.light, and .light remaps --on-field-2 to
     --brick (#7d3a35) for the ivory ground. The scrim stayed dark and the type went dark
     with the section, measuring 1.21:1 against the mean backdrop and 4.12:1 against its
     brightest patch — failing at every point of the image, at 17.6px where WCAG asks 4.5.
     Any text on a scrim over an image must take the dark-world ink regardless of scope. */
  .detail figcaption{position:absolute;left:0;bottom:0;right:0;padding:1.2rem 1.4rem;display:flex;justify-content:space-between;gap:1rem;background:linear-gradient(0deg,rgba(26,3,3,.88),rgba(26,3,3,.45) 46%,transparent);color:var(--oat);}
  .detail figcaption .a{font-family:var(--serif);font-weight:500;font-size:1.1rem;} /* held: folding to --text-body(.95rem) narrows the headline-to-subline ratio against .detail figcaption .b (--text-spec, .8rem) from 1.375 to 1.1875 — looked at both directly, the pairing visibly flattens. One element; not worth the cost to save a name. */
  .detail figcaption .b{font-size:var(--text-spec);letter-spacing:.16em;text-transform:uppercase;color:var(--oat);align-self:flex-end;text-align:right;}

  .facts{display:grid;grid-template-columns:1fr 1fr;gap:1px;margin-top:2.4rem;background:var(--hairline);border:1px solid var(--hairline);}
  .fact{padding:1.8rem 1.5rem;background:var(--panel);}
  .fact .k{font-family:var(--serif);font-size:clamp(1.7rem,3.6vw,2.6rem);color:var(--on-field);line-height:1;}
  .fact .k .u{font-size:.6em;}
  .fact .v{margin-top:.7rem;color:var(--on-field-2);}

  /* ===== ACCESS (light) ===== */
  .access{padding-block:clamp(4rem,10vh,8rem);text-align:center;position:relative;}
  .access .label{margin-bottom:2rem;display:inline-block;}
  .access .incise{margin-inline:auto;}
  .access .incise::before{left:50%;transform:translateX(-50%) scaleX(0);transform-origin:center;}
  .access .incise.in::before{transform:translateX(-50%) scaleX(1);}
  .access .incise::after{left:50%;transform:translateX(-50%);}
  /* H2 family: ref .access 41.6/112, step 0.8, capped below the H1 top (128) ->
     .campaign 0.8x (33.6/89.6), .craft 0.64x (27.2/72). No token: one selector each. */
  .access h2{font-family:var(--serif);font-weight:400;font-size:clamp(2.6rem,9vw,7rem);line-height:1;letter-spacing:-.015em;color:var(--on-field);text-wrap:balance;}
  .access h2 em{font-style:normal;color:var(--directive);margin-left:-.06em;}
  .access h2{max-width:18ch;margin-inline:auto;}
  .access p{margin:2.2rem auto 0;max-width:30ch;text-wrap:balance;color:var(--type-dim);line-height:1.65;}
  .access .cta{margin-top:2.4rem;color:var(--on-field);}
  @media(max-width:640px){
    .access{padding-block:4.5rem 5rem}
    .access h2{font-size:clamp(2.2rem,10vw,3.4rem)}
  }

  /* ===== FOOTER ===== */
  footer{background:var(--field-deep);border-top:1px solid var(--hairline);padding:clamp(3rem,7vh,5rem) 0 2.5rem;}
  .foot-top{display:flex;justify-content:space-between;align-items:flex-start;flex-wrap:wrap;gap:2rem;}
  /* THE BOOKEND &mdash; the same die that struck the threshold closes the document.
     The threshold is the Depth Crimson lid; this is the black interior of the box.
     No ink, only pressure. It is STRUCK in by .rv (a wipe with no opacity ramp). */

  /* THE WORDMARK IS ARTWORK, NOT TYPE.
     These were the letters S V R V set in Bodoni at .42em letter-spacing, which
     measures 5.011:1 — 22% wider than the locked 4.095:1. A mask lets the vector
     take its colour from currentColor and still carry the relief treatment, and
     aspect-ratio means we key the WIDTH only and let the height follow, which is
     the canon rule. Never set both. */
  .wm{display:block;aspect-ratio:4.0938;background:currentColor;
    -webkit-mask:url("wordmark.svg") center/contain no-repeat;
    mask:url("wordmark.svg") center/contain no-repeat;}
  .mark{display:inline-flex;align-items:center;}
  .mark .wm{width:clamp(4.6rem,6.4vw,6.1rem);}
  header.onlight .mark .wm{background:var(--panel);}
  /* the footer mark reads by relief and sheen, never by colour — the two shadows
     are the same values the typed version carried, moved to filters */
  .foot-mark .wm{width:clamp(9rem,33vw,23rem);background:var(--mark-relief);
    filter:drop-shadow(0 .012em 0 rgba(255,228,220,.20))
           drop-shadow(0 -.012em 0 rgba(0,0,0,.85));}
  .foot-mark{color:var(--mark-relief);user-select:none;
    /* font-family, font-size, letter-spacing, text-indent and line-height removed
       2026-07-31 -- identical leftover to .mark's dead properties, confirmed
       empirically in round 2: setting font-size to 1rem (vs the clamp's
       2.5rem-6.5rem range) moved nothing, on .foot-mark or its child .wm, since
       the wordmark is a masked span with no text-node child. */
    text-shadow:0 .012em 0 rgba(255,228,220,.20), 0 .025em .06em rgba(255,228,220,.10), 0 -.012em 0 rgba(0,0,0,.85), 0 -.025em .075em rgba(0,0,0,.66);}
  .foot-cols{display:flex;gap:clamp(2rem,6vw,5rem);flex-wrap:wrap;}
  .foot-cols .c{display:flex;flex-direction:column;gap:.4rem;}
  .foot-cols .c .label{color:var(--on-field-2);margin-bottom:.6rem;}
  .foot-cols .c a{color:var(--on-field-2);font-size:var(--text-body);padding:.85rem 0;transition:color .35s var(--ease);width:fit-content;}
  .foot-cols .c a:hover{color:var(--on-field-2);}
  /* the inscription is ruled before it is set &mdash; measure, then content */
  .foot-bottom{position:relative;display:flex;justify-content:space-between;flex-wrap:wrap;gap:1rem;margin-top:clamp(3rem,8vh,5rem);padding-top:1.6rem;}
  .foot-bottom::before{content:"";position:absolute;top:0;left:0;width:100%;height:1px;
    background:var(--hairline);transform:scaleX(0);transform-origin:left;
    transition:transform .7s var(--blade);}
  .foot-bottom.in::before{transform:scaleX(1);}
  .js .foot-bottom.rv{transition-delay:.22s,.22s}
  .foot-bottom .label{color:var(--on-field-2);opacity:.8;font-size:var(--text-label);}
  /* the handle is the one outward door in the inscription &mdash; it draws, like every other rule */
  .foot-bottom .ig{color:inherit;position:relative;padding:.5rem 0;}
  .foot-bottom .ig::after{content:"";position:absolute;left:0;right:0;bottom:.35rem;height:1px;
    background:currentColor;transform:scaleX(0);transform-origin:left;
    transition:transform .45s var(--blade);}
  .foot-bottom .ig:hover::after,.foot-bottom .ig:focus-visible::after{transform:scaleX(1);}
  .foot-bottom .ig::before{content:"";position:absolute;left:-.3rem;right:-.3rem;top:50%;
    transform:translateY(-50%);height:44px;}
  @media(max-width:960px){ .foot-bottom{flex-direction:column;align-items:flex-start;gap:.7rem} }

  /* ===== REQUEST MODAL ===== */
  .modal{position:fixed;inset:0;z-index:120;display:none;align-items:center;justify-content:center;padding:1.4rem;}
  .modal.open,.modal.closing{display:flex;}
  .modal .scrim{position:absolute;inset:0;background:rgba(26,3,3,.8);backdrop-filter:blur(6px);opacity:0;transition:opacity .5s var(--ease);}
  .modal.open .scrim{opacity:1;}
  .panel{position:relative;z-index:2;width:min(520px,100%);max-height:calc(100svh - 2.8rem);overflow-y:auto;background:var(--panel);border:1px solid var(--hairline);padding:clamp(2rem,5vw,3.4rem);clip-path:inset(0 0 100% 0);opacity:.001;transition:clip-path .6s var(--blade),opacity .01s linear;}
  .panel::before{content:"";position:absolute;left:0;right:0;top:0;height:2px;background:var(--hairline-lit);}
  .modal.open .panel{clip-path:inset(0 0 0 0);opacity:1;}
  /* the reverse guillotine &mdash; exits at ~60% of the entrance */
  .modal.closing .scrim{opacity:0;transition:opacity .3s var(--ease);}
  .modal.closing .panel{clip-path:inset(100% 0 0 0);opacity:0;transition:clip-path .35s var(--kill),opacity .3s var(--kill);}
  .panel .x{position:absolute;top:.9rem;right:1.1rem;font-size:1.1rem;color:var(--on-field-2);line-height:1;padding:.85rem;margin:-.4rem;} /* font-size excluded from the type scale, like .skip in round 1 — a close-button glyph is sized by hit area and icon legibility, not type hierarchy. Shares 1.1rem with .detail figcaption .a above by coincidence only; right:1.1rem on this same line is a POSITION and is unrelated to either. */
  .panel .label{display:block;margin-bottom:1rem;}
  .panel h3{font-family:var(--serif);font-weight:400;font-size:clamp(1.8rem,5vw,2.8rem);color:var(--on-field-2);line-height:1.05;}
  /* one role with .confirm-inline h2 (pages.css) — shared max already; min taken
     from .confirm-inline's 1.8rem (the chosen value: 28.8 is round, 30.4 wasn't). */
  .panel h3 em{font-style:normal;}
  .panel h3:focus{outline:none;}
  .panel > p, .panel .ask > p{color:var(--on-field-2);margin-top:1rem;max-width:36ch;line-height:1.55;font-size:var(--text-body);}
  .form{margin-top:2rem;display:flex;flex-direction:column;gap:1.5rem;}
  .field{display:flex;flex-direction:column;gap:.35rem;}
  .field label{font-size:.62rem; /* held: the conversion path — denser labels in a form may be deliberate; confirm the form was tuned as a unit before absorbing into --text-label */ font-weight:500;letter-spacing:.24em;text-transform:uppercase;color:var(--on-field-2);}
  .field select{background-image:linear-gradient(45deg,transparent 50%,var(--on-field-2) 50%),linear-gradient(135deg,var(--on-field-2) 50%,transparent 50%);background-position:calc(100% - 9px) 1.05rem,calc(100% - 4px) 1.05rem;background-size:5px 5px,5px 5px;background-repeat:no-repeat;padding-right:1.6rem;}
  .field input,.field select{background-color:transparent;border:0;border-bottom:1px solid var(--field-edge);border-radius:0;color:var(--on-field-2);font-family:var(--sans);font-size:var(--text-field);padding:.75rem 0;min-height:44px;transition:border-color .4s var(--ease);appearance:none;-webkit-appearance:none;}
  .field input:focus,.field select:focus{outline:none;border-color:var(--field-edge-lit);}
  /* The border swap alone is 2.19:1 against the unfocused rule — below the 3:1 WCAG
     2.4.11 asks of a focus indicator, i.e. effectively invisible. This adds a real ring
     on keyboard focus only, so the designed look survives for pointer users. Oat on the
     panel ground is 9.94:1. */
  .field input:focus-visible,.field select:focus-visible{outline:1px solid var(--on-field-2);
    outline-offset:3px;}
  .field select option{background:var(--panel);color:var(--on-field-2);}
  .hp{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden;}
  .field input::placeholder{color:rgba(217,176,176,.66);}
  .fields-2{display:grid;grid-template-columns:1fr 1fr;gap:1.1rem;}
  @media(max-width:480px){ .fields-2{grid-template-columns:1fr} }
  /* THE SECOND DOOR &mdash; a trade/press enquiry is not a size request.
     Same ritual, same entry; only the questions change. */
  .form.trade .field-size{display:none;}
  .form.trade .fields-2{grid-template-columns:1fr;}
  /* the quiet professional route at the close &mdash; the moment a buyer thinks "who is this?" */
  /* WHERE &mdash; stated as a coordinate, in the label voice. No address: that goes out on reply. */
  .access .where{margin-top:2.4rem;font-family:var(--sans);font-size:var(--text-label);font-weight:500;
    letter-spacing:.28em;text-transform:uppercase;color:var(--on-field-2);}
  .access .also{margin-top:1.4rem;font-family:var(--sans);font-size:var(--text-spec);letter-spacing:.02em;
    color:var(--type-dim);opacity:.9;max-width:46ch;text-wrap:pretty;}
  .lnk{font:inherit;color:var(--on-field);background:none;border:0;padding:0;cursor:pointer;
    position:relative;letter-spacing:inherit;}
  .lnk::after{content:"";position:absolute;left:0;right:0;bottom:-2px;height:1px;background:currentColor;
    transform:scaleX(0);transform-origin:left;transition:transform .45s var(--blade);}
  .lnk:hover::after,.lnk:focus-visible::after{transform:scaleX(1);}
  /* a 21px-tall inline target is untappable &mdash; extend the hit area, not the line box */
  .lnk::before{content:"";position:absolute;left:-.35rem;right:-.35rem;top:50%;
    transform:translateY(-50%);height:44px;}
  .fine{font-size:var(--text-spec);color:var(--on-field-2);opacity:.75;letter-spacing:.04em;}
  .send{margin-top:.6rem;align-self:flex-start;}
  .confirm{display:none;} .confirm .rule{width:60px;height:2px;background:var(--hairline-lit);margin:1.6rem 0;}
  .confirm p{color:var(--on-field-2);max-width:34ch;line-height:1.6;}
  .confirm .fallback{margin-top:1.1rem;font-size:var(--text-spec);color:var(--type-dim);}
  .confirm .fallback a{color:var(--on-field-2);border-bottom:1px solid var(--hairline);padding-bottom:1px;}

  /* ===== REVEAL &mdash; content is CUT in, not faded up ===== */
  .js .rv{clip-path:inset(0 100% 0 0);opacity:.001;transition:clip-path .55s var(--cut),opacity .01s linear;}
  /* the resting clip must clear descenders — line-height:1 display type overflows its box,
     and inset(0) was shearing the tails off "not performed." and "It is entry." */
  .js .rv.in{clip-path:inset(0 -6px -.22em -6px);opacity:1;}
  /* the drop &mdash; verdict lines are cut top-down: the guillotine falls on the decision */
  .js .rv.drop{clip-path:inset(0 0 100% 0);}
  .js .rv.drop.in{clip-path:inset(0 -6px -.22em -6px);}
  .js .fact.rv{transition-delay:calc(var(--i,0) * 70ms)}
  /* the row's content follows its own measure &mdash; never reveal content before the line it sits on */
  .js .piece.rv{transition-delay:calc(.18s + var(--i,0) * 140ms)}
  .js .rv.d1{transition-delay:.08s,.08s}.js .rv.d2{transition-delay:.16s,.16s}.js .rv.d3{transition-delay:.24s,.24s}.js .rv.d4{transition-delay:.32s,.32s}.js .rv.d5{transition-delay:.4s,.4s}

  /* ===== THE SET &mdash; type sets itself, word by word (Built Live, content primitive).
     The parent keeps .rv only so the existing observer still finds it; the words do the work,
     so there is never more than one moving part per reveal. */
  .js .rv.set{clip-path:none;opacity:1;transition:none;}
  .js .set > span{display:inline-block;clip-path:inset(0 100% 0 0);
    transition:clip-path .52s var(--cut);transition-delay:calc(var(--sd,.08s) + var(--w,0) * .075s);}
  .js .set.in > span{clip-path:inset(0 0 0 0);}
  @media(prefers-reduced-motion:reduce){
    .js .rv{clip-path:none;opacity:1;transition:none}
    .incise::before,.severance .hblade{transform:none}
    .incise::after{clip-path:none;transition:none}
    .js .set > span{clip-path:none;transition:none}
    .piece::before{transform:none;transition:none}
    .severance .lightworld{transform:none}
    .look img,.detail img{transform:none;transition:none}
    .scrollcue .bar::after{animation:none} .js #intro{display:none}
    /* the modal entrance is a real transition since v9 &mdash; it must be opted out of too */
    .panel,.modal .scrim{transition:none}
    .modal.open .panel,.modal.closing .panel{clip-path:none}
    .hero h1 .sev::after{transition:none}
    .severance .tag{opacity:1;transform:translateX(-50%);transition:none}
    .severance.seated .lightworld{animation:none}
    .campaign img{transform:scale(1.04)}
  }
