:root{
  /* #CC5500 is the brand orange, but it only reaches 4.04:1 on this paper, so
     it is kept for graphic marks and the text accent steps one shade darker.
     Same hue, passes AA at label sizes on both paper tones. */
  --clay-mark:#CC5500;  /* dots, rules, non-text marks */
  --clay-400:#B84B00;
  --clay-500:#A34400;   /* 5.81:1 on sand-100, 5.40:1 on sand-200 */
  --clay-600:#8F3A00;

  --sage-500:#4F6558; --sage-wash:#E9EFEA;

  /* The reference site runs a single system sans (Tailwind's default stack)
     for everything, with weight doing the work. Same here: one family, no
     webfont request at all. */
  --sys:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,
        "Helvetica Neue",Arial,sans-serif;
  --display:var(--sys);
  --body:var(--sys);

  /* One curve, three durations: the 150/200/300ms standard easing used
     throughout ionutmaxim.com. */
  --ease-out:cubic-bezier(.4,0,.2,1);
  --ease-spring:cubic-bezier(.16,1.02,.3,1);
  --t-fast:150ms; --t-mid:200ms; --t-slow:300ms;

  /* One radius scale used everywhere, rather than a different value per
     component. Softer than square, far short of a pill. */
  --r-sm:8px; --r-md:12px; --r-lg:20px;

  --margin-col:168px;   /* the marginalia column */
  --margin-gap:64px;    /* gap between it and the text column */

  /* The two halves that put a margin label, its dot, and the first line of the
     heading beside it on one invisible row. --lead-centre is half a heading's
     first line: h2 is line-height 1.1, so half of that is .55 of its own
     clamped size. --label-half is half a label's line, 12px at 1.62. A
     statement-led band leads with a slightly larger face and lands ~3px off,
     which is under a rounding error at these sizes. */
  --lead-centre:calc(.55 * clamp(1.72rem,3.5vw,2.5rem));
  --label-half:calc(12px * 1.62 / 2);

}
/* ── The palette ────────────────────────────────────────────────────────────
   Declared as a second :root so every value below arrives with the reasoning
   that produced it, rather than as a bare hex in the block above. The ten it
   replaces have been removed there, so each token is defined exactly once.
   ───────────────────────────────────────────────────────────────────────── */
:root{
  /* ── Surfaces ──
     Three states of one board, ageing. Fresh is the page, rested is a banded
     section, dried is the other side of an argument. White stops being a page
     and becomes a detail: fields, cards, hovered surfaces. */
  --sand-50:#FFFFFF;    /* was #FFFCFA — white as a detail, never the page */
  --sand-100:#FAF3E3;   /* was #FEF6F0 — paper, fresh cut. The page */
  --sand-200:#F2E8D3;   /* was #F9EDE4 — paper, rested. The tinted bands */

  /* The reference names one rule colour, #E0D1B2. This layout uses three line
     weights, so the two heavier ones continue the reference's own ramp in the
     direction it was already going, about -10,-14,-20 per step. Derived, not
     quoted. */
  --sand-300:#E0D1B2;   /* was #F0E1D5 — the rule. Every hairline */
  --sand-400:#D6C39E;   /* was #E2CDBC — field borders, the rail track */
  --sand-500:#CCB58A;   /* was #C9AE99 — the sieve dots, the mark's lead line */

  /* ── The rail ──
     Deliberately below the accent. The travelling call to action is an orange dot
     on this line, and it was once the same colour as the fill behind it and the
     beads beside it, so the one mark on the page that wants to be found was
     competing with two dozen that do not. The accent is the button's alone.
     Muted twice. The first pass took them off the accent and onto warm neutrals;
     this one halves the saturation again and lightens with it, which is what muting
     actually needs — desaturating alone walks a light warm colour toward mid-grey
     and comes out darker, not quieter. Held back from full neutral on purpose: at
     a few percent saturation these read cold against cream, and the rail should
     look like a line drawn on this paper rather than on some other.
     All three moved together so the rail stays one material. Ratios against
     paper-fresh, and the order matters rather than the numbers: the button's dot
     3.39, a passed bead 2.05, the fill 1.52, a bead still ahead 1.32, the track
     1.11. A passed bead is 1.55 from one ahead of the fill, which is the smallest
     step that still reads, and it has the scale and the halo besides. */
  --rail-fill:#CEC7B5;   /* 1.95 -> 1.52, saturation 32% -> 20% */
  --rail-mark:#B3AC97;   /* 2.55 -> 2.05, saturation 25% -> 16% */
  --rail-ahead:#DDD5C4;  /* was --sand-300 at 43% — a bead the fill has not reached */

  /* ── Ink ──
     Indigo rather than the warm near-black: cool against the wood, so the two
     never muddy. Ratios are against paper-fresh, which is what it sits on. */
  --ink:#171B34;        /* was #160B02 — 15.28:1 */
  --ink-2:#2C3050;      /* was #4A3A2E — 11.54:1 */
  --ink-3:#4E5372;      /* was #6E5B4C — 6.77:1, and 5.37:1 on dried. The
                           reference's ink-muted. Its ink-faint #7E819B is
                           3.45:1 on fresh and 2.74:1 on dried, and this token
                           carries 12px labels, so faint is not available. */

  /* ── Accent ──
     Deliberately absent. The whole clay ramp stays exactly as it is, so the
     orange you already have is the orange on the page and on the buttons.
     Re-measured against the new papers, since it was calibrated against the old
     one: clay-mark 3.90:1 (marks only, as before), clay-500 5.61 on fresh and
     5.10 on rested, clay-600 6.85. All still fit for what they carry, and no
     clay text lands on the dried paper. */

  /* One exception, and only because the paper moved underneath it: the wash was
     mixed for a pink-cream page and reads cool on wood. Same orange, 10% over
     the new paper instead of the old. */
  --clay-wash:#F5E3CC;  /* was #FBEADE */
}

*,*::before,*::after{box-sizing:border-box}
html{scroll-behavior:smooth}
body{margin:0;background:var(--sand-100);color:var(--ink);font-family:var(--body);
  font-size:18px;line-height:1.68;-webkit-font-smoothing:antialiased}
/* Their headline device: a light face with selected phrases at full weight.
   The contrast inside the sentence does the emphasis, not colour. */
h1,h2,h3{margin:0;font-family:var(--display);font-weight:300;
  letter-spacing:-0.02em;line-height:1.08}
h1 strong,h2 strong,h3 strong,.heavy{font-weight:640;letter-spacing:-0.024em}
p{margin:0 0 1.1em;max-width:60ch}
p:last-child{margin-bottom:0}
a{color:var(--clay-500)}
:focus-visible{outline:2.5px solid var(--clay-500);outline-offset:3px;border-radius:3px}

/* ── 1. Surface. Two stacked noise fields give the page the tooth of a
   ── pressed paper stock: a fine fibre grain, and a slower coarse mottle that
   ── stops the fine layer reading as digital dither. Both are inline SVG
   ── turbulence, so the whole texture costs zero requests. ── */
.surface{position:fixed;inset:0;z-index:0;pointer-events:none}

/* Coarse mottle: low frequency, few octaves, blurred. Reads as pulp. */
.surface::before{content:'';position:absolute;inset:0;opacity:.38;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='420' height='420'><filter id='m'><feTurbulence type='fractalNoise' baseFrequency='0.008' numOctaves='3' seed='7' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/><feGaussianBlur stdDeviation='1.4'/></filter><rect width='420' height='420' filter='url(%23m)' opacity='0.10'/></svg>");
  background-size:420px 420px}

/* Fine fibre: high frequency, tight. Reads as the tooth of the sheet. */
.surface::after{content:'';position:absolute;inset:0;opacity:.42;
  mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='f'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3' seed='3' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='180' height='180' filter='url(%23f)' opacity='0.05'/></svg>");
  background-size:180px 180px}

/* Panels carry a touch more tooth than the page, so they read as a heavier
   sheet laid on top rather than a flat colour swap. */
.tinted{position:relative}
.tinted::after{content:'';position:absolute;inset:0;pointer-events:none;
  border-radius:inherit;opacity:.42;mix-blend-mode:multiply;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='180' height='180'><filter id='p'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' seed='11' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='180' height='180' filter='url(%23p)' opacity='0.06'/></svg>")}

@media (prefers-reduced-motion: no-preference){}

.doc{max-width:1140px;margin:0 auto;padding:0 26px}

/* ── 2. The rail. One annotation system: the marginalia sit to its left and
   ── double as the section markers, so nothing is labelled twice. ── */
.spine{display:none}
@media(min-width:1180px){
  /* Doubled: 64px of air each side of the rail. Everything downstream (grid
     gaps, dot offset, rail position) derives from this one number. */
  :root{--margin-gap:128px}
  /* left is set in JS from the real column edge: 50vw includes the scrollbar
     but the centred container does not, so vw math drifts by half a scrollbar. */
  /* Under the masthead (z-30). At rest the bar has no ground, so nothing is
     hidden by that; once the bar docks and gains one, it clips the head of the
     rule and the line reads as running out from beneath it. */
  /* --spine-top is the measured masthead height, set in JS: hardcoding it would
     leave a sliver or a gap the moment font metrics differ. Starting the rule at
     the bar's lower edge also means the progress fill maps to the length the
     reader can actually see. */
  .spine{display:block;position:fixed;top:var(--spine-top,0px);bottom:0;width:1px;
    z-index:20;pointer-events:none;left:-100px}
  .spine .track{position:absolute;inset:0;background:var(--sand-400);opacity:.85}

  /* The beads are drawn inside the rule, not as pseudo-elements of the margins.
     They marked a section's place on the rail and were positioned from the
     margin's own box, which put a 13px circle in one layer and a 1px rule in a
     fixed one: the two agree exactly in CSS and round independently on screen, so
     the bead read as sitting beside the line rather than on it, and whether it
     drew above or below depended on a z-index race between two unrelated
     subtrees. As a child of the rail there is nothing to align and nothing to
     race: left:50% of a 1px parent is the rule's centre by construction, and a
     later sibling of the track paints over it. JS gives them their y, taken from
     the label whose row they belong to. */
  .spine .bead{position:absolute;left:50%;top:-99px;width:13px;height:13px;
    box-sizing:border-box;border-radius:50%;
    transform:translate(-50%,-50%);
    background:var(--sand-100);border:2px solid var(--sand-400);
    /* Slow on purpose. The bead is reporting that the rule has reached it, and a
       200ms flip made that read as a click rather than an arrival. */
    transition:background 820ms var(--ease-out),
               border-color 820ms var(--ease-out),
               transform 560ms var(--ease-spring)}
  .spine .bead[data-lit="true"]{background:var(--clay-mark);border-color:var(--clay-mark);
    transform:translate(-50%,-50%) scale(1.2)}
  /* scaleY rather than height: compositor-only, no layout on every scroll frame. */
  .spine .fill{position:absolute;left:0;top:0;width:1px;height:100%;
    background:var(--clay-mark);transform:scaleY(0);transform-origin:top;
    transition:transform 90ms linear}


}

/* Marginalia: right-aligned against the rail, with a marker that is part of the
   block itself, so it can never drift out of alignment with its own text. */
.margin{font-size:13px;line-height:1.62;color:var(--ink-3)}
@media(min-width:920px){
  .margin{position:sticky;top:104px;align-self:start;text-align:right;
    padding-right:2px;padding-top:calc(var(--lead-centre) - var(--label-half));
    transition:color var(--t-mid) var(--ease-out)}
  .margin em{border-top:1px solid var(--sand-400)}
}
@media(min-width:1180px){
  /* Above the rail: the dot marks the rule, so the rule must not cross it. */
  .margin{position:sticky;z-index:21}
}
.margin b{display:block;font-family:var(--body);font-size:11px;font-weight:500;
  text-transform:uppercase;letter-spacing:2.4px;
  color:var(--ink-3);margin-bottom:7px;transition:color var(--t-mid) var(--ease-out)}
.margin[data-on="true"] b{color:var(--clay-500)}
.margin em{display:block;font-style:normal;margin-top:14px;padding-top:13px;
  border-top:1px solid var(--sand-400);color:var(--ink-3)}

/* The closing section's own button is the ending on every page and at every
   width. The disc that used to cap the rail is gone: it was the rail's ending
   before the travelling button existed, and once the ride superseded it on the
   home page it survived on the others as a dot stuck to the line with nowhere to
   have come from. */

/* ── The mark. An open ring, one point of focus at its centre, one line out
   through the gap. The gap is the whole idea, so nothing may close it: no
   background plate, no containing circle. Two tones, and it holds at 16px. ── */
.mark{display:block;width:26px;height:26px;flex:none}
.mark__ring{fill:none;stroke:var(--ink);stroke-width:3.1;stroke-linecap:round;
  transition:stroke var(--t-slow) var(--ease-out)}
.mark__lead{fill:none;stroke:var(--sand-500);stroke-width:2.2;stroke-linecap:round;
  transition:stroke var(--t-slow) var(--ease-out),transform var(--t-slow) var(--ease-out)}
.mark__core{fill:var(--clay-mark)}
/* The lead extends on hover: the flow moves, the focus does not. */
/* Hovering the mark turns its opening from the right round to the bottom, and the
   line it points down carries a pulse away with it. The gap is the whole idea of
   this mark, so moving it is the one gesture available that says something rather
   than just lighting up.
   transform-box:view-box, not the default border-box: on an SVG element the origin
   is otherwise measured from the element's own bounding box, and the ring's box is
   not the mark's centre. This is the same trap that put the intro's core 7 units
   off centre. */
.mark__ring,.mark__lead{transform-box:view-box;transform-origin:16px 16px;
  transition:transform 620ms var(--ease-spring)}
a:hover .mark__ring{transform:rotate(90deg)}
/* The lead turns with the gap, and its nudge goes with it: translateX after the
   rotation runs along the new direction, so it reaches further down rather than
   further right. */
a:hover .mark__lead{stroke:var(--clay-400);transform:rotate(90deg) translateX(1.5px)}

/* The pulse. A short comet of the mark's own clay, travelling the length of the
   rule once per hover, brightest at its leading edge so it reads as sent rather
   than as a band sliding past.
   It starts at the logo, which is where the rule starts, so it needs clipping at
   that end: the clip is a 1px box the length of the rail, and the pulse begins its
   run entirely inside it and above the cut. Without it the comet's tail hangs over
   the mark before the run begins, and the line appears to carry on above the logo,
   which is the one thing the rail must never look like. The clip is 1px wide and
   the pulse is 1px wide, so nothing is lost sideways, and the beads stay outside
   it because they are 13px and would be sliced. */
.spine .pulseclip{position:absolute;inset:0;width:1px;overflow:hidden;
  pointer-events:none}
.spine .pulse{position:absolute;left:0;top:0;width:1px;height:96px;
  background:linear-gradient(180deg,transparent 0%,var(--clay-mark) 100%);
  opacity:0;pointer-events:none}
.spine[data-pulse="true"] .pulse{animation:railpulse 1150ms var(--ease-out) 1}
@keyframes railpulse{
  0%{transform:translateY(-96px);opacity:1}
  100%{transform:translateY(100vh);opacity:1}
}

@media (prefers-reduced-motion: reduce){
  a:hover .mark__ring{transform:none}
  a:hover .mark__lead{transform:none}
  .spine[data-pulse="true"] .pulse{animation:none}
}

/* ── First-load animation ──
   The stage is only ever built on a first visit, and only for a reader who has
   not asked for less motion. Everything the animation brings in itself starts
   hidden here, in CSS, so nothing is visible for a frame before the timeline
   takes hold. The h1 needs no entry: .rise already masks it until data-ready. */
.intro{display:none}
html[data-intro="running"] .intro{display:grid;place-items:center;
  position:fixed;inset:0;z-index:90;background:var(--sand-100)}
.intro__mark{width:min(46vw,232px);height:auto;overflow:visible}

html[data-intro="running"] .top .name,
html[data-intro="running"] .top nav,
html[data-intro="running"] .open .margin,
html[data-intro="running"] .open .deck,
html[data-intro="running"] .principle,
html[data-intro="running"] .hero-cta,
html[data-intro="running"] .act-note,
html[data-intro="running"] .stats,
html[data-intro="running"] .spine{opacity:0}

/* ── Masthead ──
   No ground of its own: it sits on the page like the first band, and so it does
   not travel. A transparent bar that follows the reader is a bar the page
   scrolls straight through, so dropping the background means dropping the
   sticky with it, along with the hairline that only existed to separate the two.
   Still position:relative rather than static, because the mobile menu is
   absolutely positioned against it, and it still needs a z-index: main carries
   z-2, so without one the page paints over the header and the open menu panel
   renders behind the hero. The row uses .doc, so the header's inner edges align
   with every band by construction and it inherits the same responsive gutter
   instead of repeating 26px and 1140px. */
.top{position:relative;z-index:30;padding-top:20px;padding-bottom:20px}

/* Docked: past the hero the bar leaves the flow and waits just above the
   viewport, dropping in when the reader scrolls back up and lifting away when
   they carry on down. It only ever docks while it is already off-screen, so the
   switch out of flow is never seen.
   Leaving the flow would otherwise pull the whole page up by the bar's height,
   so main takes that height back as padding: the fixed bar contributes nothing
   to layout, main's padding contributes exactly what it used to, and the
   document height and every scroll offset stay where they were.
   Docked it does need a ground. It is over the text now, not beside it: the page
   colour rather than a new one, thin enough to read as the same paper and blurred
   so the type crossing under it never competes with the type on it. Blur only,
   no saturate: saturating would quietly re-tint a palette whose ratios were
   measured. */
.top[data-dock="true"]{position:fixed;top:0;left:0;right:0;
  background:color-mix(in srgb,var(--sand-100) 78%,transparent);
  backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
  border-bottom:1px solid var(--sand-300);
  transform:translateY(-100%);
  transition:transform 380ms var(--ease-out)}
.top[data-dock="true"][data-reveal="true"]{transform:none}
.top[data-dock="true"] ~ main{padding-top:var(--bar-h,0px)}
@media (prefers-reduced-motion: reduce){
  .top[data-dock="true"]{transition:none}
}
/* The bar owns its height, the row owns its alignment. Vertical padding cannot
   live on .top__row: .doc sets `padding:0 20px` further down the sheet, and the
   shorthand would zero it. */
.top__row{display:flex;justify-content:space-between;align-items:center;gap:22px}

.top .name{display:flex;align-items:center;gap:10px;
  font-family:var(--display);font-size:19px;font-weight:600;letter-spacing:-0.015em}
.top .name .mark{width:24px;height:24px}
/* Above the rail breakpoint the bar adopts the same three columns as every
   band, so nothing here is positioned by eye: the logotype right-aligns where
   every margin label ends, the mark centres in the gutter the rail runs down,
   and the nav ends where the text column ends. The mark caps the rule from
   inside an opaque bar, which is why it needs no plate behind it: this is the
   page ground, not a hole cut in a band. */
@media(min-width:1180px){
  /* Generous above, so the mark is not crowded against the top of the screen. */
  .top{padding-top:38px;padding-bottom:24px}
  .top__row{display:grid;gap:0;align-items:center;
    grid-template-columns:var(--margin-col) var(--margin-gap) minmax(0,1fr)}
  /* One link across two cells: same tab stop, same accessible name, both halves
     on the grid. The inner columns repeat the outer two, so they cannot drift. */
  .top .name{grid-column:1 / span 2;display:grid;gap:0;align-items:center;
    grid-template-columns:var(--margin-col) var(--margin-gap)}
  /* grid-row is not optional: the mark is placed in column 2, so sparse
     auto-placement would push a column-1 sibling onto a second row. */
  .top .name span{grid-row:1;grid-column:1;justify-self:end;text-align:right}
  .top .name .mark{grid-row:1;grid-column:2;justify-self:center;width:30px;height:30px}
  /* Left, on the text column's own edge: the menu starts where every headline
     and paragraph below it starts. */
  .top nav{grid-column:3;justify-self:start}
}

/* The nav is reference, not action: the rail disc is the only thing on a wide
   screen asking to be clicked. So the nav joins the tracked-label register the
   whole site uses for its meta layer (.margin b, .verdict .k, .stair .k) rather
   than sitting at body size, and the current page lights clay exactly the way
   an active margin label does. Sizes come from the shared label rule further
   down, so this never drifts from the rest of the system. */
.top nav{display:flex;gap:30px}
.top nav a{position:relative;font-family:var(--body);font-size:11px;font-weight:500;
  text-transform:uppercase;letter-spacing:2.4px;color:var(--ink-3);
  text-decoration:none;transition:color var(--t-mid) var(--ease-out)}
/* A 44px hit area without touching the layout. Vertical padding would have done
   it too, but the links are flex items and so blockified: the padding would grow
   the row, make the masthead taller, and drag the underline below with it. An
   inset pseudo-element belongs to the link for hit-testing and is invisible to
   layout, so the bar keeps its height and the rule keeps its place. Horizontally
   0, so the 30px gap between links stays a gap and no two targets overlap.
   Desktop only: the stacked mobile rows are already 52px and adjacent, where
   bleeding 12px past each edge would hand clicks to the neighbour. */
@media(min-width:761px){
  .top nav a::before{content:'';position:absolute;inset:-12px 0}
}

/* right:2px, not 0: tracked type carries a trailing letter-space the rule
   would otherwise sit under. */
.top nav a::after{content:'';position:absolute;left:0;right:2px;bottom:-6px;height:1.5px;
  background:var(--clay-mark);transform:scaleX(0);transform-origin:left;
  transition:transform var(--t-mid) var(--ease-out)}
.top nav a:hover{color:var(--clay-500)}
.top nav a[aria-current="page"]{color:var(--clay-500)}
.top nav a:hover::after,
.top nav a[aria-current="page"]::after{transform:scaleX(1)}
.top nav a:focus-visible{outline:2px solid var(--clay-600);outline-offset:6px;
  border-radius:2px}

/* ── Hero ──
   The bloom used to live inside .open, which is only as wide as the text
   column, so overflow:hidden cut it into a visible rectangle. It now sits in a
   full-bleed band and is masked to fade out, so it has no edge at all. */
.heroband{position:relative;overflow:hidden;isolation:isolate}
.heroband>.doc{position:relative;z-index:2}
.open{position:relative;padding:104px 0 96px}
@media(max-width:760px){.open{padding:64px 0 58px}}
.bloom{position:absolute;inset:-30% -12% -40% -12%;z-index:0;pointer-events:none;
  -webkit-mask-image:radial-gradient(120% 96% at 58% 38%,#000 34%,transparent 80%);
          mask-image:radial-gradient(120% 96% at 58% 38%,#000 34%,transparent 80%)}
.bloom i{position:absolute;display:block;border-radius:50%;filter:blur(70px);opacity:.55}
.bloom i:nth-child(1){width:52vw;height:52vw;max-width:680px;max-height:680px;left:38%;top:-18%;
  background:radial-gradient(circle,#F0D9C6,transparent 68%);animation:drift1 26s var(--ease-out) infinite alternate}
.bloom i:nth-child(2){width:40vw;height:40vw;max-width:520px;max-height:520px;left:58%;top:26%;
  background:radial-gradient(circle,#E7DFCB,transparent 66%);animation:drift2 34s var(--ease-out) infinite alternate}
.bloom i:nth-child(3){width:30vw;height:30vw;max-width:400px;max-height:400px;left:30%;top:52%;
  background:radial-gradient(circle,#DCE6DD,transparent 66%);animation:drift3 30s var(--ease-out) infinite alternate}
@keyframes drift1{to{transform:translate3d(-7%,6%,0) scale(1.12)}}
@keyframes drift2{to{transform:translate3d(6%,-8%,0) scale(1.08)}}
@keyframes drift3{to{transform:translate3d(-5%,-6%,0) scale(1.15)}}

/* ── 3. Pointer light. The paper catches a warm highlight where you look. ── */
.lamp{position:absolute;inset:0;z-index:1;pointer-events:none;opacity:0;
  transition:opacity 900ms var(--ease-out);
  background:radial-gradient(420px circle at var(--mx,60%) var(--my,40%),
    rgba(196,99,60,.10),transparent 62%)}
.heroband[data-lamp="true"] .lamp{opacity:1}

/* ── One content column for the entire page. Hero, bands and closing section
   ── all start at the same left edge; only the margin notes sit outside it. ── */
.open .inner{display:grid;gap:22px}
@media(min-width:920px){
  .open .inner{grid-template-columns:var(--margin-col) minmax(0,1fr);
    gap:var(--margin-gap);align-items:start}
}
/* The hero's own row. Its heading is far bigger than a section's, so the centre
   of its first line is nowhere near where --lead-centre puts a section's: .rise
   sets a 1.4 line, which places the ink centre .7 of the font size down. Scoped
   to the hero, and the dot follows because it reads the same variable. */
.open .inner{--lead-centre:calc(.7 * clamp(2.7rem,6.6vw,4.7rem))}
@media(min-width:920px){
  .open .inner>.margin{padding-top:calc(var(--lead-centre) - var(--label-half))}
}
.close{display:grid;gap:22px}
@media(min-width:920px){
  .close{grid-template-columns:var(--margin-col) minmax(0,1fr);
    gap:var(--margin-gap);align-items:start}
}

/* ── 7. The sieve. A pinned scene: everything you could build, narrowed by
   ── scroll to the one thing that decides it. ── */
.band--scene{padding:0;align-items:start}
.scene{position:relative;height:300vh}
.pin{position:sticky;top:0;height:100vh;display:flex;flex-direction:column;
  align-items:center;justify-content:center;gap:26px}
.pin svg{width:100%;height:auto;display:block;overflow:visible}
.scene .d{fill:var(--sand-500)}
.scene .d.final{fill:var(--clay-mark)}
.scene .halo{fill:none;stroke:var(--clay-mark);stroke-width:1;opacity:0;
  transform-box:fill-box;transform-origin:center}
/* Twice, then done. This was an infinite loop, which put permanent motion on a
   section the reader has arrived at to read: the scene holds its answer from 0.86
   to the end of the scroll on purpose, and a ring pulsing under it forever is the
   opposite of holding. Nothing else on the page has idle motion -- the travelling
   button stops the frame it settles -- and this was the exception. Two pulses
   announce the answer and hand the moment to the dot, which stays. */
.scene .halo.on{animation:ping 3.2s var(--ease-out) 2}
@keyframes ping{0%{opacity:.55;transform:scale(.4)}70%{opacity:0;transform:scale(1.35)}100%{opacity:0;transform:scale(1.35)}}

/* One caption at a time, crossfading with the stage. */
.caption{position:relative;height:104px;width:100%;text-align:center}
.caption span{position:absolute;inset:0;display:flex;flex-direction:column;
  align-items:center;gap:6px;opacity:0;transform:translateY(8px);
  transition:opacity 420ms var(--ease-out),transform 520ms var(--ease-out)}
.caption span[data-on="true"]{opacity:1;transform:none}
.caption b{font-family:var(--display);font-size:clamp(1.25rem,2.4vw,1.75rem);
  font-weight:600;letter-spacing:-0.02em}
.caption i{font-style:normal;font-size:15px;color:var(--ink-3);max-width:44ch;line-height:1.55}
.caption span[data-key="true"] b{color:var(--clay-500)}

.ticks{display:flex;gap:14px;align-items:center}
/* Dots, not bars: the rail, the wordmark and the field above all mark position
   with a disc, so the stage marks speak the same language. The fill grows from
   the centre, the way the surviving dot itself does. */
.ticks i{display:block;width:9px;height:9px;border-radius:50%;
  background:var(--sand-400);position:relative}
.ticks i::after{content:'';position:absolute;inset:0;border-radius:50%;
  background:var(--clay-500);transform:scale(0);
  transition:transform 260ms var(--ease-out)}
.ticks i[data-fill="true"]::after{transform:scale(1)}
.counter{font-family:var(--display);font-size:13px;font-weight:600;color:var(--ink-3);
  min-width:112px;text-align:right;font-variant-numeric:tabular-nums}

@media(max-width:919px){
  .scene{height:280vh}
  .caption{height:120px}
}

/* ── 8. Deliverable glyphs. Line art, drawn on reveal. No tiles. ── */
.glyph{width:26px;height:26px;flex:none;color:var(--clay-500);align-self:start;margin-top:4px}
.glyph path,.glyph rect,.glyph circle,.glyph line{fill:none;stroke:currentColor;
  stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round;
  stroke-dasharray:var(--len,90);stroke-dashoffset:var(--len,90);
  transition:stroke-dashoffset 1100ms var(--ease-out)}
.asset[data-in="true"] .glyph path,.asset[data-in="true"] .glyph rect,
.asset[data-in="true"] .glyph circle,.asset[data-in="true"] .glyph line{stroke-dashoffset:0}

/* ── 4. Variable-weight entrance. The headline sets itself. ── */
.open h1{font-size:clamp(2.7rem,6.6vw,4.7rem);line-height:.95;letter-spacing:-0.032em;
  max-width:none;margin-bottom:34px}
/* Each line is its own masked block, so its box has to contain its own glyphs.
   The stack's deepest face needs 1.33em for that (81 up, 19 down per 100), and
   any tighter line-height drops the descenders outside the box where
   overflow:hidden cuts them: the old .04em of padding was covering 3px of a
   14px overhang, and could not be widened because that padding is the mask the
   entrance slides behind. So the box keeps a full natural line and the leading
   comes off the bottom margin instead. 1.33 - 0.38 = the 0.95em step above,
   and the mask stays tight against the text it hides. */
.rise{display:block;overflow:hidden;line-height:1.4;margin-bottom:-.45em}
.rise strong{font-weight:640}
/* Hand-set lines only earn their keep where they actually fit. Below that the
   headline reflows as ordinary text and skips the mask entirely. */
@media(max-width:760px){
  /* Reflowed as ordinary text: no mask, so the h1's own leading governs again. */
  .rise{display:inline;overflow:visible;padding:0;margin:0;line-height:inherit}
  .rise>span{display:inline;transform:none}
}
.rise>span{display:inline-block;transform:translateY(105%);
  transition:transform 760ms var(--ease-spring)}
body[data-ready="true"] .rise>span{transform:translateY(0)}

.open .deck{font-size:clamp(1.12rem,2vw,1.32rem);line-height:1.58;color:var(--ink-2);
  max-width:41ch;margin-bottom:40px}
.open .deck b{font-weight:600;color:var(--ink)}

/* ── The single call to action. One per page, so it can afford presence. ── */
.act{position:relative;display:inline-flex;align-items:center;gap:16px;
  padding:20px 24px 20px 34px;border-radius:var(--r-md);min-height:64px;
  font-family:var(--body);font-size:17.5px;font-weight:600;letter-spacing:-0.005em;
  color:#fff;text-decoration:none;overflow:hidden;isolation:isolate;
  /* Top stop is darker than clay-400: at that lightness white text fell to
     4.04:1. This floor keeps every band of the gradient above AA. */
  background:linear-gradient(180deg,#EA650F 0%,#DF5A06 52%,#CF4F00 100%);
  /* A lit top edge and a warm cast beneath: the button sits on the paper. */
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22),
             inset 0 -1px 0 rgba(0,0,0,.14),
             0 1px 2px rgba(93,41,18,.20),
             0 10px 26px -8px rgba(93,41,18,.42);
  transition:transform 420ms var(--ease-spring),box-shadow 420ms var(--ease-out),
             filter 300ms var(--ease-out)}
.act:hover{color:#fff;filter:saturate(1.06) brightness(1.03);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28),
             inset 0 -1px 0 rgba(0,0,0,.14),
             0 2px 4px rgba(93,41,18,.22),
             0 20px 44px -12px rgba(93,41,18,.52)}
.act:active{transform:translateY(1px) scale(.994)}

/* A slow sheen crosses the face on hover. */
.act::before{content:'';position:absolute;inset:0;z-index:-1;pointer-events:none;
  background:linear-gradient(105deg,transparent 32%,rgba(255,255,255,.20) 48%,transparent 64%);
  transform:translateX(-120%);transition:transform 900ms var(--ease-out)}
.act:hover::before{transform:translateX(120%)}

/* The arrow rides in its own chip, which opens as you approach. */
.act .chip{display:grid;place-items:center;width:34px;height:34px;border-radius:50%;
  background:rgba(255,255,255,.16);flex:none;
  transition:background 320ms var(--ease-out),transform 420ms var(--ease-spring)}
.act:hover .chip{background:rgba(255,255,255,.26);transform:translateX(3px)}
.act svg{transition:transform 420ms var(--ease-spring)}
.act:hover svg{transform:translateX(2px)}
.act:focus-visible{outline:2.5px solid var(--clay-600);outline-offset:4px}

.act-note{font-size:15px;color:var(--ink-3);margin-top:18px}

/* ── Hero principle line. A statement of method, not a tagline: small, quiet,
   set apart by a rule rather than by weight or colour. ── */
.principle{display:flex;align-items:center;gap:11px;margin:32px 0 0;
  font-family:var(--display);font-size:14.5px;font-weight:500;letter-spacing:.01em;
  color:var(--ink-2)}
.principle::before{content:'';flex:none;width:26px;height:1px;background:var(--clay-mark)}
.principle span{font-weight:400;color:var(--ink-3)}

.hero-cta{margin:34px 0 0}

/* ── Stat row. Three plain numbers, hairline-separated. ── */
.stats{display:grid;gap:0;border-top:1px solid var(--sand-300);
  border-bottom:1px solid var(--sand-300);margin-top:56px}
@media(min-width:720px){.stats{grid-template-columns:repeat(3,1fr)}}
.stat{padding:22px 0}
@media(min-width:720px){
  .stat{padding:24px 28px;border-left:1px solid var(--sand-300)}
  .stat:first-child{padding-left:0;border-left:0}
}
@media(max-width:719px){.stat + .stat{border-top:1px solid var(--sand-300)}}
.stat b{display:block;font-family:var(--display);font-weight:550;
  font-size:clamp(1.5rem,3vw,2rem);letter-spacing:-0.024em;margin-bottom:4px}
.stat span{font-size:14.5px;color:var(--ink-3)}

/* ── Home proof cards. The kill line is the load-bearing part, so it gets the
   rule and the accent label; the app name stays plain. ── */
.proofs{display:grid;gap:18px;margin-top:30px}
@media(min-width:860px){.proofs{grid-template-columns:repeat(3,1fr);gap:22px}}
.proof{display:flex;flex-direction:column;padding:22px 24px;background:var(--sand-50);
  border:1px solid var(--sand-300);border-radius:var(--r-md)}
.proof h3{font-size:1.05rem;font-weight:640;line-height:1.25;margin:0 0 8px}
.proof p{margin:0;color:var(--ink-2);font-size:.97rem}
.proof .kill{margin-top:auto;padding-top:14px;border-top:1px solid var(--sand-300)}
.proof p.kill{margin-top:16px}
@media(min-width:860px){.proof p.kill{margin-top:auto}}
.proof .kill b{display:block;font-size:11px;text-transform:uppercase;letter-spacing:2.2px;
  font-weight:600;color:var(--clay-500);margin-bottom:5px}

/* ── Case-study screens. Line drawings in the same idiom as the deliverable
   glyphs, so proof shots read as part of the page rather than pasted onto it.
   A real screenshot can replace the <svg> with an <img> and needs no new CSS. ── */
.shots{display:grid;gap:24px;margin-top:32px}
@media(min-width:700px){.shots{grid-template-columns:repeat(3,1fr);gap:22px}}
.shot{margin:0}
.shot .screen,.shot img{display:block;width:100%;height:auto}
.shot img{border-radius:var(--r-md);border:1px solid var(--sand-300)}
.shot figcaption{margin-top:14px;font-size:13px;line-height:1.55;color:var(--ink-3)}
@media(max-width:699px){
  /* One screen at a time on a phone, at a size worth looking at. */
  .shot .screen,.shot img{max-width:300px;margin-inline:auto}
  .shot figcaption{max-width:300px;margin-inline:auto}
}
.screen{overflow:visible}
.screen .fr{fill:var(--sand-50);stroke:var(--sand-400);stroke-width:1.5}
.screen text{font-family:var(--body);fill:var(--ink)}
.screen .t{font-size:21px;font-weight:640;letter-spacing:-0.02em}
.screen .s{font-size:13.5px;fill:var(--ink-3)}
.screen .mid{text-anchor:middle}
.screen .d{font-size:11.5px;font-weight:600;letter-spacing:2.2px;fill:var(--ink-3)}
.screen .pill{fill:none;stroke:var(--sand-400);stroke-width:1.2}
.screen .pill.on{fill:var(--clay-wash);stroke:var(--clay-mark)}
.screen .p{font-size:14.5px;text-anchor:middle}
.screen .card{fill:none;stroke:var(--sand-400);stroke-width:1.2}
.screen .rule{stroke:var(--sand-400);stroke-width:1.5;fill:none;stroke-linecap:round}
.screen .btn{fill:var(--clay-500)}
.screen .btnt{font-size:15.5px;font-weight:600;fill:var(--sand-50);text-anchor:middle}
.screen .ring{fill:var(--clay-wash);stroke:none}
.screen .tick{stroke:var(--clay-mark);stroke-width:2.6;fill:none;
  stroke-linecap:round;stroke-linejoin:round}

/* ── Session quotes. What someone said, and the moment they said it. The
   attribution earns the quote; without it a quote is just a claim. ── */
.quotes{display:grid;gap:18px;margin-top:30px}
@media(min-width:820px){.quotes{grid-template-columns:repeat(2,1fr);gap:22px}}
.quote{margin:0;padding:24px 26px;background:var(--sand-50);
  border:1px solid var(--sand-300);border-radius:var(--r-md)}
.quote p{margin:0;font-family:var(--display);font-size:1.14rem;line-height:1.44;
  letter-spacing:-0.012em;color:var(--ink);text-wrap:pretty}
.quote footer{margin-top:15px;padding-top:13px;border-top:1px solid var(--sand-300);
  font-size:12.5px;line-height:1.5;color:var(--ink-3)}

/* ── Bands ── */
.band{display:grid;grid-template-columns:1fr;gap:22px;padding:80px 0}
@media(min-width:920px){.band{grid-template-columns:var(--margin-col) minmax(0,1fr);
  gap:var(--margin-gap);padding:104px 0}}
/* Sections read as panels resting on the page rather than full-width stripes.
   Inset is kept small so the text column never shifts at any width. */
.tinted{position:relative;background:var(--sand-200);border-radius:var(--r-lg);
  margin-inline:20px}
@media(max-width:760px){.tinted{margin-inline:10px;border-radius:var(--r-md)}}


h2{font-size:clamp(1.72rem,3.5vw,2.5rem);line-height:1.1;max-width:19ch;margin-bottom:26px}
.lede{font-size:1.06rem;color:var(--ink-2)}
/* Emphasis, not colour, carries meaning: bold marks the claim a reader would
   repeat, and takes the text up to full ink rather than tinting it. */
.lede strong{font-weight:640;color:var(--ink)}

/* ── Steps ── */
.steps{display:grid;gap:36px}
@media(min-width:840px){.steps{grid-template-columns:repeat(3,1fr);gap:40px}}
.step{position:relative;padding:20px 16px 18px;margin:0 -16px;border-radius:var(--r-md);
  transition:background var(--t-mid) var(--ease-out),transform var(--t-mid) var(--ease-out)}
.step::before{content:'';position:absolute;top:0;left:16px;right:16px;height:2px;
  background:var(--sand-400);transform:scaleX(0);transform-origin:left;
  transition:transform 800ms var(--ease-out)}
.step[data-in="true"]::before{transform:scaleX(1)}
.step:hover{background:var(--sand-50);transform:translateY(-3px)}
.tinted .step:hover{background:var(--sand-100)}
.step .n{display:block;font-family:var(--display);font-size:13px;font-weight:600;
  color:var(--clay-500);margin-bottom:12px}
.step h3{font-size:1.18rem;font-weight:600;margin-bottom:10px;line-height:1.22}
.step p{font-size:.97rem;color:var(--ink-2);margin:0}

/* ── 5. Deliverables that open. Named things you can look inside. ── */
.assets{margin-top:6px}
.asset{border-top:1px solid var(--sand-300)}
.asset:last-child{border-bottom:1px solid var(--sand-300)}
.asset button{all:unset;display:grid;grid-template-columns:26px 1fr 26px;gap:16px;align-items:start;
  width:100%;box-sizing:border-box;cursor:pointer;padding:28px 18px;margin:0 -18px;
  width:calc(100% + 36px);border-radius:var(--r-md);
  transition:background var(--t-mid) var(--ease-out)}
@media(min-width:780px){.asset button{grid-template-columns:26px 224px minmax(0,1fr) 26px;gap:14px 22px}}
.asset button:hover{background:var(--clay-wash)}
.asset button:focus-visible{outline:2.5px solid var(--clay-500);outline-offset:-2px}
.asset .nm{font-family:var(--display);font-size:1.28rem;font-weight:600;letter-spacing:-0.018em;
  transition:transform var(--t-mid) var(--ease-spring)}
.asset button:hover .nm{transform:translateX(6px)}
.asset .sm{color:var(--ink-2);font-size:1.02rem}
@media(max-width:779px){.asset .sm{display:none}}
.asset .sign{position:relative;width:20px;height:20px;justify-self:end;margin-top:6px}
.asset .sign::before,.asset .sign::after{content:'';position:absolute;background:var(--clay-500);
  border-radius:1px;transition:transform var(--t-mid) var(--ease-spring)}
.asset .sign::before{left:0;right:0;top:9px;height:2px}
.asset .sign::after{top:0;bottom:0;left:9px;width:2px}
.asset[data-open="true"] .sign::after{transform:scaleY(0)}
.asset[data-open="true"] .sign::before{transform:rotate(180deg)}
/* 0fr → 1fr: height animates without measuring anything. */
.asset .more{display:grid;grid-template-rows:0fr;
  transition:grid-template-rows 420ms var(--ease-out)}
.asset[data-open="true"] .more{grid-template-rows:1fr}
.asset .more>div{overflow:hidden}
.asset .more p{padding:0 0 28px;color:var(--ink-2);font-size:1rem;max-width:58ch}
@media(min-width:780px){.asset .more p{padding-left:280px}}

/* ── 6. The statement reads itself as you scroll. ── */
.statement{font-family:var(--display);font-size:clamp(1.7rem,4vw,2.75rem);line-height:1.14;
  letter-spacing:-0.028em;font-weight:300;max-width:22ch;margin:0 0 26px}
.statement w.key{font-weight:640}
/* Unlit words sit at --ink-3, which still clears AA. The effect is a deepening,
   not a reveal, so nothing is ever below contrast while you read it. */
.statement w{display:inline-block;color:var(--ink-3);
  transition:color 320ms var(--ease-out)}
.statement w[data-lit="true"]{color:var(--ink)}
.statement w.key[data-lit="true"]{color:var(--clay-500)}

.rev{opacity:0;transform:translateY(18px);
  transition:opacity var(--t-slow) var(--ease-out),transform var(--t-slow) var(--ease-out)}
.rev[data-in="true"]{opacity:1;transform:none}

.close{padding:104px 0 118px}
@media(max-width:760px){.close{padding:72px 0 84px}}
.close h2{max-width:20ch;margin-bottom:20px}
.colo{padding:22px 0 44px;border-top:1px solid var(--sand-300);display:flex;
  justify-content:space-between;gap:16px;font-size:13px;color:var(--ink-3);flex-wrap:wrap}

@media (prefers-reduced-motion: reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{animation-duration:.001ms !important;transition-duration:.001ms !important}
  .rev{opacity:1;transform:none}
  .rise>span{transform:none}
  .bloom i{animation:none}
  .lamp{display:none}
  .statement w{color:var(--ink)}
}

/* ══════════════════════════════════════════════════════════════════════
   Components introduced when the system went site-wide
   ══════════════════════════════════════════════════════════════════════ */

.skip-link{position:absolute;left:16px;top:-100px;z-index:100;background:var(--clay-500);
  color:#fff;padding:12px 20px;border-radius:var(--r-sm);font-weight:600;
  text-decoration:none;transition:top var(--t-slow) var(--ease-out)}
.skip-link:focus{top:16px;color:#fff}

.top .name{font-family:var(--display);font-weight:640;font-size:17px;
  letter-spacing:-0.02em;color:var(--ink);text-decoration:none}
/* ── The wordmark's separator ──
   A drawn dot rather than a full stop. A period is a glyph: it sits on the baseline,
   at whatever weight and size the face decides, and it read as punctuation between two
   words rather than as a mark holding them apart. This is a circle at the optical
   centre of the line, sized and spaced deliberately.
   The words are laid out with inline-flex and a gap rather than by putting spaces in
   the markup, so the air either side of the dot is one number that does not change
   with the font's word-space. That is also why the anchor carries an aria-label: a
   whitespace-only text node between flex items is dropped, so without it the name
   reads "one flowfirst". */
.name > span{display:inline-flex;align-items:center;gap:.42em}
.name em{flex:none;width:.29em;height:.29em;border-radius:50%;
  background:var(--clay-500);font-style:normal}

/* Mobile nav: a real menu button rather than a wrapping row of links. */
.navtoggle{display:none}
@media(max-width:760px){
  .top{padding-top:14px;padding-bottom:14px}
  .top__row{flex-wrap:nowrap}
  .navtoggle{display:grid;place-content:center;gap:5px;width:44px;height:44px;
    margin-right:-8px;border:0;background:none;cursor:pointer;padding:0}
  .navtoggle span{display:block;width:20px;height:1.5px;background:var(--ink);
    transition:transform var(--t-slow) var(--ease-out),opacity var(--t-slow) var(--ease-out)}
  .navtoggle[aria-expanded="true"] span:first-child{transform:translateY(3.25px) rotate(45deg)}
  .navtoggle[aria-expanded="true"] span:last-child{transform:translateY(-3.25px) rotate(-45deg)}
  /* 0fr only collapses the first grid row, and there are four links, so the
     menu sat open. max-height collapses the whole box. */
  /* The panel hangs off .top, which is full width now, so its gutter is set to
     match .doc at this breakpoint rather than guessed. */
  /* visibility, not just max-height. Clipping a box with overflow:hidden hides it
     but leaves everything inside it focusable, so tabbing from the logo went
     through four invisible links and scrolled the clipped panel to chase them.
     visibility:hidden takes the whole subtree out of the tab order and off the
     screen reader, which is what a collapsed menu should be; aria-expanded on the
     button is what says it can be opened. Switched with a delay equal to the
     collapse so it stays visible for the length of the animation, and back
     instantly on the way open. */
  .top nav{position:absolute;left:0;right:0;top:100%;display:flex;
    flex-direction:column;gap:0;background:var(--sand-100);
    border-bottom:1px solid transparent;padding:0 20px;
    max-height:0;overflow:hidden;visibility:hidden;
    transition:max-height 320ms var(--ease-out),
               padding 320ms var(--ease-out),
               border-color 320ms var(--ease-out),
               visibility 0s linear 320ms}
  .top[data-open="true"] nav{max-height:70vh;padding:6px 20px 18px;
    border-bottom-color:var(--sand-300);visibility:visible;
    transition:max-height 320ms var(--ease-out),
               padding 320ms var(--ease-out),
               border-color 320ms var(--ease-out),
               visibility 0s linear 0s}
  .top nav a{min-height:52px;display:flex;align-items:center;
    border-bottom:1px solid var(--sand-300)}
  .top nav a:last-child{border-bottom:0}
  /* No room for an underline in a stacked list, so colour carries the state. */
  .top nav a::after{display:none}
}

/* Doubts */
.doubts{display:grid;gap:18px}
.doubt{padding:22px 24px;background:var(--sand-50);border:1px solid var(--sand-300);
  border-radius:var(--r-md)}
@media(min-width:800px){.doubt{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1.05fr);
  gap:28px;align-items:start}}
.doubt .q{margin:0;font-size:1.02rem;color:var(--ink);font-weight:500}
.doubt .a{margin:8px 0 0;color:var(--ink-2)}
@media(min-width:800px){.doubt .a{margin:0}}

/* Three-up */
/* Three or more claims stack as hairline rows, the same anatomy as the pricing
   stairs: the title is the row's left-hand accent, the body sits beside it.
   Columns are kept for the places that hold exactly two things. */
.rows{display:grid;margin-top:14px}
.rows > div{padding:34px 0;border-top:1px solid var(--sand-300)}
.rows > div:last-child{border-bottom:1px solid var(--sand-300)}
@media(min-width:820px){
  .rows > div{display:grid;grid-template-columns:280px minmax(0,1fr);column-gap:64px;
    padding:44px 0}
}
.rows h3{font-size:1.18rem;font-weight:640;line-height:1.4;letter-spacing:-.01em;
  margin:0 0 10px}
@media(min-width:820px){.rows h3{margin-bottom:0}}
.rows p{color:var(--ink-2);font-size:.98rem;line-height:1.65;margin:0}

/* Fit lists */
.fit{display:grid;gap:18px}
@media(min-width:820px){.fit{grid-template-columns:repeat(2,1fr);gap:24px}}
.fit__col{padding:24px;border:1px solid var(--sand-300);border-radius:var(--r-md);
  background:var(--sand-50)}
.fit__col.no{background:transparent}
.fit__title{font-size:12px;font-weight:600;text-transform:uppercase;letter-spacing:1.8px;
  margin:0 0 16px;color:var(--clay-500)}
.fit__title.no{color:var(--ink-3)}
.checklist{list-style:none;margin:0;padding:0;display:grid;gap:12px}
.checklist li{position:relative;padding-left:26px;color:var(--ink-2);margin:0;max-width:none}
.checklist li::before{content:'';position:absolute;left:2px;top:.55em;width:9px;height:9px;
  border-radius:50%;background:var(--clay-mark)}
.checklist.cross li::before{background:none;border:1.5px solid var(--sand-500);
  width:8px;height:8px;top:.6em}

/* Pricing stairs. One step per row with the number as the row's left-hand
   object, the way slowclarity set its steps: the price does the work its ghost
   numerals did, except here the big figure is the information itself. Hairlines
   and vertical room instead of cards, like everything else on the site. */
.stairs{display:grid;margin-top:14px}
.stair{padding:38px 0;border-top:1px solid var(--sand-300)}
.stair:last-child{border-bottom:1px solid var(--sand-300)}
/* The two-column row belongs to the priced staircase only: the case study's
   timeline uses the same bones with nothing to put in a left column. */
@media(min-width:900px){
  .stairs--price .stair{display:grid;grid-template-columns:280px minmax(0,1fr);
    column-gap:64px;padding:52px 0}
  .stairs--price .stair .price{grid-column:1;grid-row:1/span 3;align-self:start}
  .stairs--price .stair .k,.stairs--price .stair h3,.stairs--price .stair p{grid-column:2}
}
.stair .k{font-size:11px;text-transform:uppercase;letter-spacing:2.4px;font-weight:500;
  color:var(--clay-500);margin:0 0 14px}
.stair h3{font-size:clamp(1.4rem,2vw,1.7rem);font-weight:640;margin-bottom:14px;
  letter-spacing:-.015em}
/* The step is the accent and the number is its ghost: still the row's left-hand
   object at display scale, the way slowclarity set its numerals, but in the quiet
   ink so the eye lands on what the step is before what it costs. */
.stair .price{font-size:clamp(1.9rem,2.6vw,2.35rem);font-weight:300;
  letter-spacing:-.02em;color:var(--ink-3);margin:0 0 18px;line-height:1.05;
  white-space:nowrap}
.stair .price span{display:block;font-size:11px;text-transform:uppercase;
  letter-spacing:2.4px;font-weight:500;color:var(--ink-2);margin:12px 0 0;
  font-family:var(--mono)}
@media(min-width:900px){.stairs--price .stair .price{margin-bottom:0}}
.stair p{font-size:.98rem;color:var(--ink-2);margin:0;line-height:1.65}

/* Probe lists */
.probe{list-style:none;margin:22px 0 0;padding:0 0 0 22px;display:grid;gap:16px;
  border-left:2px solid var(--sand-400)}
.probe li{margin:0;color:var(--ink-2);max-width:62ch}
.probe strong{display:block;color:var(--ink);font-weight:640;margin-bottom:2px}

/* Verdicts */
.verdicts{display:grid;gap:14px;margin-top:24px}
@media(min-width:760px){.verdicts{grid-template-columns:repeat(3,1fr)}}
.verdict{padding:20px;border:1px solid var(--sand-300);border-radius:var(--r-md);
  background:var(--sand-50)}
.verdict .k{font-size:11px;text-transform:uppercase;letter-spacing:2.4px;font-weight:600;
  margin:0 0 10px}
.verdict.go .k{color:var(--clay-500)}
.verdict.adjust .k{color:#7A5A1B}
.verdict.stop .k{color:var(--ink-3)}
.verdict p{font-size:.94rem;color:var(--ink-2);margin:0}

/* Case notes */
.case{display:grid;gap:22px;margin-top:26px}
@media(min-width:820px){.case{grid-template-columns:repeat(2,1fr)}
  .case .case__block:first-child{grid-column:1 / -1}}
.case__block .case__k{font-size:11px;text-transform:uppercase;letter-spacing:2.2px;font-weight:600;
  color:var(--ink-3);margin:0 0 8px}
.case__block.change .case__k{color:var(--clay-500)}
.case__block.kill .case__k{color:#7A5A1B}
.case__block p{color:var(--ink-2);margin:0;font-size:.97rem}

/* FAQ */
.faq{border-top:1px solid var(--sand-300);margin-top:8px}
.faq details{border-bottom:1px solid var(--sand-300)}
.faq summary{display:flex;align-items:center;justify-content:space-between;gap:18px;
  min-height:64px;padding:16px 0;cursor:pointer;list-style:none;
  font-size:1.05rem;font-weight:500;color:var(--ink)}
.faq summary::-webkit-details-marker{display:none}
.faq summary:hover{color:var(--clay-500)}
.faq summary i{position:relative;flex:none;width:14px;height:14px}
.faq summary i::before,.faq summary i::after{content:'';position:absolute;background:var(--clay-500);
  transition:transform var(--t-slow) var(--ease-out)}
.faq summary i::before{left:0;right:0;top:6px;height:1.5px}
.faq summary i::after{top:0;bottom:0;left:6px;width:1.5px}
.faq details[open] summary i::after{transform:scaleY(0)}
.faq details>div{padding:0 0 20px}
.faq details p{color:var(--ink-2);max-width:62ch}

/* Quiet inline link with arrow */
.quiet{display:inline-flex;align-items:center;gap:8px;font-weight:600;font-size:.98rem;
  text-decoration:none;color:var(--clay-500)}
.quiet svg{transition:transform var(--t-slow) var(--ease-out)}
.quiet:hover svg{transform:translateX(3px)}

/* Start page */
/* The start page's two-column grid and its white card are gone: the section they
   held is one column with one button now, and a box around an explanation was the
   thing being explained away. */
.field{margin-bottom:20px}
.field__label{display:block;font-size:14.5px;font-weight:600;margin-bottom:8px}
.req{color:var(--clay-500)}
.field__hint{display:block;font-size:14px;color:var(--ink-3);margin-bottom:10px}
.input,.textarea{width:100%;min-height:52px;padding:14px;font-family:var(--body);
  /* sand-50, not sand-100. Under the old palette those two were #FFFCFA and
     #FEF6F0 and a field on either was indistinguishable, so this said sand-100 and
     nobody noticed. The promoted palette makes sand-50 pure white and sand-100 the
     warm page, which left a field the same colour as the paper behind it with only
     a 1px border to say otherwise -- and the palette's own note reserves white for
     exactly this: fields, cards, hovered surfaces. Found by promoting; the sample
     only ever covered the home page, which has no form on it. */
  font-size:16px;color:var(--ink);background:var(--sand-50);
  border:1px solid var(--sand-400);border-radius:var(--r-sm);
  transition:border-color var(--t-slow) var(--ease-out),box-shadow var(--t-slow) var(--ease-out)}
.input:focus,.textarea:focus{outline:none;border-color:var(--clay-500);
  box-shadow:0 0 0 3px rgba(204,85,0,.16)}
.textarea{min-height:118px;resize:vertical;line-height:1.6}
.field__error{display:none;margin:8px 0 0;font-size:14px;font-weight:500;color:#A32014}
.field[data-invalid="true"] .input,.field[data-invalid="true"] .textarea{border-color:#A32014}
.field[data-invalid="true"] .field__error{display:block}
.form-status{display:none;padding:22px;border-radius:var(--r-md);background:var(--clay-wash);
  border:1px solid var(--sand-400)}
.form-status[data-visible="true"]{display:block}
.form-status h3{font-size:1.1rem;font-weight:640;margin-bottom:8px}
.form-status p{color:var(--ink-2);font-size:.97rem;margin:0}
.fineprint{font-size:13.5px;color:var(--ink-3);margin-top:16px}
.act--block{width:100%;justify-content:center;padding-left:26px;padding-right:26px}

/* Footer */
.colo{position:relative;z-index:2;display:flex;justify-content:space-between;gap:16px;
  flex-wrap:wrap;max-width:1140px;margin:0 auto;padding:24px 26px 44px;
  font-size:13.5px;color:var(--ink-3);border-top:1px solid var(--sand-300)}
.colo a{color:var(--ink-3);text-decoration:none}
.colo a:hover{color:var(--clay-500)}

/* Everything above the texture layers. The rail is deliberately excluded: it
   must keep position:fixed and its own z-index.
   main takes no z-index of its own on purpose. With one it becomes a stacking
   context, and then nothing inside it can rise above the rail at z-20, which is
   why the rule used to draw straight through the marginalia dots and the foot
   disc. It is positioned and later in the DOM than .surface, so it still sits
   above the texture. (.act carries isolation:isolate, so its sheen at z-index:-1
   stays contained either way.) */
main{position:relative}
.colo{position:relative;z-index:2}

/* ── Mobile refinements ────────────────────────────────────────────────
   11px tracked labels are legible on a desktop monitor and not on a phone;
   tap targets under 44px fail on touch. Both are fixed at the source rather
   than per component. */
.margin b,.verdict .k,.stair .k,.case__block .case__k,.fit__title,.caption i,
.top nav a{font-size:12px}
@media(max-width:760px){
  .margin b,.verdict .k,.stair .k,.case__block .case__k,.fit__title,
  .top nav a{font-size:12.5px;
    letter-spacing:2px}
  body{font-size:17px}
  .margin{font-size:14px;margin-bottom:4px}
  .band{padding:56px 0}
  .doc{padding:0 20px}
  .colo{padding:20px 20px 40px}
}

/* Tap targets. Scoped below the rail breakpoint, or this re-shows the
   masthead wordmark that the rail rule deliberately hides. */
@media(max-width:1179px){
  .top .name{display:inline-flex;align-items:center;min-height:44px}
}
.quiet{min-height:44px}
.faq summary{min-height:56px}

/* Marginalia reads as a section label on small screens, not a right rail. */
@media(max-width:919px){
  .margin{display:flex;flex-wrap:wrap;align-items:baseline;gap:0 10px;
    padding-bottom:14px;border-bottom:1px solid var(--sand-300);margin-bottom:22px}
  .margin b{margin-bottom:0}
  .margin em{margin-top:0;padding-top:0;border-top:0;flex-basis:100%;
    color:var(--ink-3);opacity:.9}
}

/* The narrowest phones still in use are 320px wide. Two things do not fit there
   on their own: the tick row under the figure wants 302px of the 281px going, and
   the button's label plus its chip land exactly on the available width, so it
   wraps to two lines and takes 35px of height with it. */
@media(max-width:380px){
  .ticks i{width:28px}
  .counter{min-width:84px}
  .act{padding:18px 22px;gap:12px}
}

/* On a phone the whole hero is measured against one requirement: the button has
   to be in the first view on a 667px screen, the shortest one still in real use.
   Every number below is spent on that. */
@media(max-width:520px){
  .open h1{font-size:clamp(2.15rem,10vw,2.9rem);line-height:1.04}
  .open{padding-top:44px}
  .open .margin{margin-bottom:16px}
  .open .deck{margin-bottom:30px}
  .principle{margin-top:24px}
  .hero-cta{margin-top:26px}
  .stats{margin-top:38px}
  .stat b{font-size:1.5rem}
}

/* ═══════════════════════════════════════════════════════════════════════════
   REFINEMENTS
   ───────────────────────────────────────────────────────────────────────────
   Everything below was built and reviewed as a separate override sheet against
   the home page before being adopted for the whole site, which is why it reads
   as a layer: it restates a handful of the rules above rather than editing them
   in place. That is deliberate and worth keeping. Each block says what the base
   rule did and why it changed, and several of them only make sense as a
   correction -- the deliverable rows, the doubts and the steps are all rules
   whose original is still the sensible default for a section that has not been
   reworked. Read top to bottom, the sheet is the design followed by its
   revisions; folding these into the definitions above would lose that.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Signals ───────────────────────────────────────────────────────────────
   The reference reserves three colours for the three outcomes and nothing else:
   sage for go, ochre for adjust, clay for stop. Today go borrows the accent,
   which means the accent has to mean both "this is a link" and "this is a yes".
   Colour only, and three lines to delete if you disagree. */
.verdict.go .k{color:#4E6349}          /* 5.93:1 on fresh */
.verdict.adjust .k{color:#7E5714}      /* the reference's #8F6417 is 4.31:1 on a
                                          rested band, so the label is a step
                                          darker at 5.29:1 */
.verdict.stop .k{color:#8C3A24}        /* 6.92:1 */
.case__block.kill .case__k{color:#7E5714}

/* Form errors are the stop colour: darker than the accent, so an error and a
   link never read as the same thing. */
.field__error{color:#8C3A24}
.field[data-invalid="true"] .input,
.field[data-invalid="true"] .textarea{border-color:#8C3A24}

/* ── The third paper ───────────────────────────────────────────────────────
   Dried is reserved for the other side of an argument: what this isn't, what not
   to do. The only place on this page that qualifies is the column of reasons it
   might not be for you, which already carries its own padding, so this is a
   background and a border and nothing else. Its text is ink-3 and ink-2, both
   of which clear AA on this surface. */
.fit__col.no{background:#E7D9BE;border-color:#D6C39E}

/* ── The rail ──────────────────────────────────────────────────────────────
   White track, warm fill. Against wood, white reads as light rather than as a
   colour, which is the one thing the reference reserves it for, and it gives the
   fill a ground to advance against rather than a wood one it would disappear into.
   The fill was the accent orange and is not any more: see --rail-fill.
   It advances on a curve now instead of a straight line. The reference's single
   easing is described as fast out, long settle, which is exactly what a fill
   chasing the scroll should do; 90ms was too short for any curve to read, so the
   duration goes to the reference's 180. Each scroll frame retargets the
   transition, so the effect is a fill that catches up smoothly rather than one
   that steps. */
@media(min-width:1180px){
  .spine .track{background:var(--sand-50);opacity:1}
  .spine .fill{background:var(--rail-fill);
    transition:transform 180ms cubic-bezier(.2,.7,.3,1)}

  /* Making this read correctly took three goes, so it is worth writing down why.
     The dot is painted above the rail and its centre agrees with the rail's to
     0.00 in every measurement, and it still looked like a bead sitting beside the
     line rather than on it. Two reasons, neither of them the alignment:
       1. It was a ring with a cream hole, and cream against a white track is
          1.11:1, so the interruption existed and was invisible.
       2. A 1px rule and a 13px circle rasterise independently. Even snapped to
          the same whole pixel they can land on neighbouring device pixels at
          fractional display scaling, which is exactly the kind of 1px error the
          eye is best at.
     So the dot no longer relies on being pixel-perfect. It is filled, and it
     carries an opaque halo of the paper behind it, which clears the rule for 4px
     all round. The line is now unmistakably interrupted whichever way either of
     them rounds. */
  /* Filled rather than a ring: the hole was the page cream and the track is
     white, 1.11:1 apart, so the interruption existed and was invisible. The halo
     is the paper it sits on, which clears the rule for 4px all round.
     The bead is a child of the rail now, so it cannot fall behind the line or
     round off its centre, and one halo colour serves every band: it is the page
     paper, and the rail crosses the tinted panels rather than sitting inside
     them. */
  /* One colour per state, and no ring. The bead was two-tone in both states -- a
     2px border in one value around a centre in another -- and once the lit centre
     came off the accent while the border did not, a passed bead read as an orange
     ring around an olive core inside a paper halo. Three colours on a 13px dot,
     repeated down the page, which is more construction than a section marker needs
     and reads as an object rather than a mark.
     So it is a flat disc: one value, and the halo, which is not a third colour but
     the page's own paper doing the one job the dot cannot do without -- breaking a
     1px rule cleanly whichever way the two rasterise.
     Smaller with it. Dropping the border makes the whole 13px solid where only the
     inner 9px was before, so a plain 13px disc would have weighed more than the
     ring it replaced; 10px keeps it lighter than what it replaces rather than
     heavier. */
  .spine .bead{width:10px;height:10px;border:0;
    background:var(--rail-ahead);
    box-shadow:0 0 0 4px var(--sand-100)}
  /* A deepening rather than a change of colour, which is how the statement's words
     light too: the bead stays the same material and simply darkens once the fill
     has passed it. It keeps its paper halo, and that is what makes it read as an
     interruption in the line — not the contrast between the two, which is slight
     on purpose. */
  .spine .bead[data-lit="true"]{background:var(--rail-mark)}
}

/* ── The hover pulse ──
   Muting the fill and the beads left the pulse as the loudest thing on the rail:
   full-strength clay at 3.90 against paper, where the call to action's dot is 3.39.
   The one mark meant to be found was being out-shouted by a decoration on the line
   it rides.
   Its hue stays — it is the logomark's own clay travelling down the rule it points
   along, and that is the whole idea of the gesture — so the weight comes down
   instead. The keyframes are redefined rather than the element's opacity set,
   because the animation pins opacity at both ends and would simply overrule it.
   At 0.60 the comet peaks at 2.13 over the bare track and 3.05 over the fill,
   both under the dot, and still clearly a highlight against the 1.95 fill. */
@keyframes railpulse{
  0%{transform:translateY(-96px);opacity:.6}
  100%{transform:translateY(100vh);opacity:.6}
}

/* The docked masthead needs nothing here: style.css now mixes it from
   --sand-100, so it follows the paper wherever the paper goes. */
@media(max-width:760px){
  .top nav{background:var(--sand-100)}
}


/* ═════════════════════════════════════════════════════════════════════════════
   Design changes, sample only
   ═════════════════════════════════════════════════════════════════════════════ */

/* A legible handwriting face, vendored like the rest, for the quotes only. These
   are the one place on the page where the words are someone else's, said out
   loud, so a hand is doing something no weight or size could. Everything else
   stays typeset: the margin notes are the site's own voice, not a quotation.
   Caveat's x-height is small for its point size, so it is set well up from the
   size it replaces. */
@font-face{font-family:'Quote Hand';src:url('../fonts/caveat-var.woff2') format('woff2-variations');
  font-weight:400 700;font-style:normal;font-display:swap}

.doubt .q,.quote p{font-family:'Quote Hand','Segoe Script',cursive;
  font-weight:600;font-size:1.62rem;line-height:1.32;letter-spacing:.006em;
  color:var(--ink)}
@media(max-width:520px){
  .doubt .q,.quote p{font-size:1.48rem}
}

/* Doubts and steps get the same treatment: room, not boxes.
   The doubts were still boxes, and the box was the problem. Each one is a two
   column grid -- the reader's objection on the left, the reply on the right -- and
   the reply is hidden until hovered, so at rest a bordered white card sat there
   with one half filled and one half blank. Half-empty air inside a drawn box reads
   as something failing to load. The same air on the page's own paper, between
   hairlines, reads as a wide margin, which is what it is.
   So the card goes and the three become rows in a list: no fill, no border, no
   corner, one hairline between each, in the same language as the three-up above
   them. The quote can then start at the text column's own left edge instead of
   28px inside a box, which lines it up with every other paragraph in the section. */
.doubts{gap:0;border-top:1px solid var(--sand-300)}
.doubt{padding:30px 0;background:none;border:0;border-radius:0;
  border-bottom:1px solid var(--sand-300)}
@media(min-width:800px){
  /* A shade more room for the objection than the answer: it is set in the
     handwriting face at 26px against 18px of body copy, so an even split wrapped
     it to two tight lines while leaving the reply's column short. */
  .doubt{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr);gap:40px}
}
/* Stacked, the reply sat 8px under the objection, which is close spacing for two
   things set in different faces at 26px and 18px. The two columns above do not need
   it: there the gap between them is doing this job. */
@media(max-width:799px){
  .doubt .a{margin-top:14px}
}
/* One variable for the gutter, because the track below has to reach across it. Set
   as the gap as well as read by the reach, so the two cannot drift apart: the first
   attempt hard-coded 40px from style.css and missed by 4px, which is exactly what
   this section widened it to. */
.steps{--step-gap:44px;gap:var(--step-gap)}

/* ── The objection first, the answer on hover ──────────────────────────────
   Quoting what the reader is thinking lands harder when they read it alone for a
   moment, so the answer is the reply to a hover rather than something already
   sitting there.
   Scoped to pointers that can hover rather than to a width: a touch screen of any
   size keeps the answer, which is what a phone needs, and so does a small laptop
   window, which a width query would have wrongly hidden it on.
   The answer keeps its space, so the card cannot jump and nothing reflows, and it
   is only made transparent, never display:none, so it stays in the accessibility
   tree and is still read out.
   The card carries a tabindex purely so there is something for :focus-within to
   fire on: without it the reveal answered the cursor and nothing else, and a
   keyboard user could never read a single answer. Tab through the three and they
   open one at a time. */
@media (hover:hover) and (pointer:fine){
  .doubt .a{opacity:0;transform:translateX(-6px);
    transition:opacity var(--t-slow) var(--ease-out),
               transform var(--t-slow) var(--ease-out)}
  .doubt:hover .a,
  .doubt:focus-within .a{opacity:1;transform:none}
  /* The focus stop has to look like one, or tabbing lands somewhere invisible.
     :focus:not(:focus-visible) rather than a bare :focus to switch it off. Both
     selectors carry the same weight, so the plain one written second was beating
     the ring in the cascade and the keyboard stop had no outline at all -- the
     exact thing these two lines exist to prevent. */
  .doubt:focus-visible{outline:2px solid var(--clay-600);outline-offset:3px}
  .doubt:focus:not(:focus-visible){outline:none}
  /* Something has to answer the cursor. It used to be the wood shadow every card
     on the page uses, which is no longer available to a row that is not a card, and
     would be the wrong gesture anyway: a shadow lifts an object, and this is a line
     of text. The rule under the row deepens instead -- the row it belongs to is
     what the cursor is on, so that is the thing to acknowledge. */
  .doubt{transition:border-color var(--t-mid) var(--ease-out)}
  .doubt:hover{border-bottom-color:var(--sand-500)}
}
@media (hover:hover) and (pointer:fine) and (prefers-reduced-motion:reduce){
  .doubt .a{transition:none;transform:none}
}

/* ── The deliverable rows ──────────────────────────────────────────────────
   Two problems. The hover was the accent wash while every other card on the page
   hovers to white, so this one row looked like a different kind of object. And
   the opened text was pushed 280px right, into a narrow ragged column under the
   summary rather than under its own title.
   Both fixed: hover matches the cards, and the body sits under the name at the
   same left edge, which is where the system puts body copy everywhere else. */
/* One hover for every card: move to white with the wood-coloured shadow, and
   hold the text colour so nothing flickers as the cursor crosses it. Inside a
   tinted band the steps were hovering to page cream instead of white. */
.step:hover,
.tinted .step:hover{background:var(--sand-50);
  box-shadow:0 6px 22px -12px rgba(74,58,26,.26)}

/* The deliverable row is the surface, not its header. That header is 18px wider
   than the row and carries a 12px radius, so hovering it drew a rounded white
   card overhanging the row while the text it had just opened sat outside that
   card, on the band, orphaned. The surface is painted behind the whole row now,
   square and flush, so the body is on the same ground as the name that opened
   it, and an open row stays lifted whether the cursor is on it or not. */
.asset{position:relative;isolation:isolate}
/* z-index:-1 inside an isolated row, not z-index:0 with positioned children.
   The header button carries all:unset in style.css, which resets position and
   outranks any `.asset > *` rule on specificity, so the button stayed
   unpositioned and this surface painted straight over its name, glyph and
   summary. The minus sign survived only because it sets its own position.
   Isolating the row puts the surface behind its in-flow content without needing
   the content positioned at all. */
.asset::before{content:'';position:absolute;inset:0 -18px;z-index:-1;
  pointer-events:none;background:transparent;
  transition:background var(--t-hover) var(--ease)}
.asset:hover::before,
.asset[data-open="true"]::before{background:var(--sand-50)}
.asset button{border-radius:0}
.asset button:hover{background:transparent}
.asset button:hover .nm{transform:translateX(4px)}

@media(min-width:780px){
  /* Aligned with the summary above it, which is the column the original 280px was
     aiming at and missing by 14. Written as the grid that produces it rather than
     as the total, so it cannot drift from the header: glyph, gap, name, gap. */
  .asset .more p{padding-left:calc(26px + 22px + 224px + 22px);
    padding-right:26px;max-width:62ch}
}
@media(max-width:779px){
  /* No summary column down here, so the body follows the name instead. */
  .asset .more p{padding-left:calc(26px + 16px)}
}
.asset .more p{padding-bottom:30px}

/* ── The steps, marked ─────────────────────────────────────────────────────
   "Step one" in 13px was the only thing distinguishing them. A numeral carries
   it now: large, light, in the accent, with the words kept as the label. The
   count comes from a CSS counter, so the markup stays as it is. */
/* ── The method as a timeline ───────────────────────────────────────────────
   Three columns of prose with a numeral on each read as three parallel facts,
   which is the one thing these are not: they happen in an order, and the first
   can end the project before the other two exist. Nothing in the layout said so.
   The section becomes the page's own rail laid on its side. Each step's rule
   extends across the gutter to meet its neighbour, so what was three separate
   hairlines over three unequal columns is now one continuous track, and each step
   drops a station on it. Same construction as the spine: a flat disc in the muted
   rail tone with a halo of the paper behind it, which is what lets a 10px dot
   interrupt a 1px line cleanly whichever way the two rasterise.
   It draws rather than appears. Each segment already scaled in from the left when
   its column revealed, and that is left alone -- three segments that meet, drawn
   one after another, read as a single line being drawn across the section. The
   station follows its own segment by 260ms, so the line arrives first and the stop
   lands on it. */
.steps{counter-reset:step}
.step{counter-increment:step}

.step::before{height:1px;background:var(--rail-fill)}
@media(min-width:840px){
  /* The segment stops at its own column's edge, so it has to cover the gutter to
     reach the next one. The last one stops there, or the track runs off the side
     of the section with nothing to join. */
  .step::before{right:calc(16px - var(--step-gap))}
  .step:last-child::before{right:16px}
}

.step::after{content:'';position:absolute;top:0;left:16px;
  width:10px;height:10px;border-radius:50%;box-sizing:border-box;
  background:var(--rail-mark);box-shadow:0 0 0 4px var(--sand-100);
  transform:translate(-50%,-50%) scale(0);
  transition:transform 520ms var(--ease-spring) 260ms}
.step[data-in="true"]::after{transform:translate(-50%,-50%) scale(1)}
/* The band is untinted today; this keeps the halo honest if it ever is not. */
.tinted .step::after{box-shadow:0 0 0 4px var(--sand-200)}

/* The numeral hangs under its own station, and is larger for it: it is the thing
   carrying the sequence now that the track has somewhere to put it. Left at the
   accent deliberately -- this section is not the rail, and the numerals are the
   one flourish in it. Note that they are a CSS counter and so invisible to a
   screen reader, which is why the "Step one" beside them stays: that span is the
   only accessible name the step has. */
.step .n{position:relative;min-height:56px;padding-left:66px;
  display:flex;align-items:center}
.step .n::before{content:counter(step);position:absolute;left:0;top:50%;
  transform:translateY(-50%);
  font-family:var(--display);font-size:54px;font-weight:200;line-height:1;
  letter-spacing:-.04em;color:var(--clay-mark)}
@media(min-width:820px){
  .step{padding-top:34px}
}
@media (prefers-reduced-motion:reduce){
  .step::after{transition:none;transform:translate(-50%,-50%) scale(1)}
}


/* ── The call to action rides the rail ─────────────────────────────────────
   Driven by assets/js/ride.js, which sets the geometry every frame.
   Home page only: the ride is the hero's button compacted, so it needs one to start
   from, and shell() ships the script to a page by asking its markup for a hero
   button rather than by keeping a list of slugs. This is only the look: a dot on the rule that grows into the disc
   the foot of the rail used to carry, and finally into the closing section's own
   button, which it then hands over to. */
/* width, height, border-radius and transform are all set per frame by the script,
   so nothing here may transition them: a CSS transition on top of a spring is two
   integrators fighting over the same number. Only the fade in and out is CSS. */
.ride{position:fixed;left:0;top:0;z-index:45;will-change:transform,width,height;
  display:grid;grid-auto-flow:column;place-items:center;gap:0;
  box-sizing:border-box;overflow:hidden;white-space:nowrap;text-decoration:none;
  color:#fff;font-family:var(--body);font-size:17.5px;font-weight:600;
  letter-spacing:-0.005em;
  background:linear-gradient(180deg,#EA650F 0%,#DF5A06 52%,#CF4F00 100%);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.22),
             0 6px 18px -6px rgba(93,41,18,.5);
  opacity:0;pointer-events:none;
  transition:opacity 260ms var(--ease-out)}
.ride[data-in="true"]{opacity:1;pointer-events:auto}
.ride:hover{filter:saturate(1.06) brightness(1.03)}
.ride:focus-visible{outline:2.5px solid var(--clay-600);outline-offset:4px}

/* No transitions on the label or the chip. Their width, opacity and margins are
   written every frame from the shape's actual width, so they cannot arrive on a
   schedule of their own while the outline is still opening. Two clocks on one
   movement is most of what makes an animation read as synthetic. */
.ride__label{max-width:0;opacity:0;overflow:hidden}
.ride__chip{display:grid;place-items:center;flex:none;
  width:34px;height:34px;border-radius:50%;opacity:0}
.ride[data-form="pill"] .ride__chip{background:rgba(255,255,255,.26)}

/* Every rule here is gated on html[data-ride], which ride.js sets only once it has
   decided it is really going to run. That matters more than it looks.
   The ride needs a hero button to be the first form of, and only the home page has
   one; and style.css already hides .close .act above this width because the disc at
   the foot of the rail is the call to action there. So a page with no ride, given
   these rules ungated, would have its foot disc hidden by the first rule and its
   closing button hidden by style.css and be left with no call to action at all.
   Gated, a page without a ride keeps the foot disc exactly as it always had it. */
@media(min-width:1180px){

  /* Both real buttons wait at opacity 0 for the ride to arrive on top of them. The
     hero's is the object's first form: once the reader leaves the hero it has become
     the dot on the rail, so it must not still be sitting there. It comes back when
     they scroll back up to it. The closing one is hidden by the stylesheet at this
     width, because the foot disc used to be the only call to action down there. */
  html[data-ride] .hero-cta .act,
  html[data-ride] .close .act{display:inline-flex;opacity:0;
    transition:opacity 240ms var(--ease-out)}
  html[data-ride] .hero-cta[data-handed="true"] .act,
  html[data-ride] .close[data-handed="true"] .act{opacity:1}
  /* Nothing to click while it is standing in for the ride. */
  html[data-ride] .hero-cta:not([data-handed="true"]) .act,
  html[data-ride] .close:not([data-handed="true"]) .act{pointer-events:none}
}

/* ═══════════════════════════════════════════════════════════════════════════
   FROM THE DESIGN SYSTEM (v1.0)
   ───────────────────────────────────────────────────────────────────────────
   Adopted from the One Flow First design system doc: the typefaces and their
   settings, the paper grain, the 4px space scale, the logotype's weight split,
   and the motion rules. What is not adopted, and why, is in the README — the doc
   was derived from an older build of this site and several of its statements
   contradict decisions since made and measured here.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Typefaces ──
   IBM Plex Sans and IBM Plex Mono, a sans-only pairing. Already vendored for an
   earlier experiment, so this costs no third-party request and no tracking; the
   four files come to 126KB and are all served from here.
   The variable sans covers 100–700, which is what the scale below needs: display
   is set at 200 and 300, weights that would have meant two more files as static
   cuts. Mono is two static cuts because it is only ever used at 11–12px in two
   weights, where a variable axis would be paying for range nothing uses.
   The old system stack stays behind each as the fallback, so a failed font
   request degrades to what the site was last week rather than to Times. */
@font-face{font-family:'Plex Sans';src:url('../fonts/plex-sans-var.woff2') format('woff2-variations');
  font-weight:100 700;font-style:normal;font-display:swap}
@font-face{font-family:'Plex Sans';src:url('../fonts/plex-sans-var-italic.woff2') format('woff2-variations');
  font-weight:100 700;font-style:italic;font-display:swap}
@font-face{font-family:'Plex Mono';src:url('../fonts/plex-mono-500.woff2') format('woff2');
  font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:'Plex Mono';src:url('../fonts/plex-mono-600.woff2') format('woff2');
  font-weight:600;font-style:normal;font-display:swap}

:root{
  --sys:'Plex Sans',ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,
        "Helvetica Neue",Arial,sans-serif;
  --mono:'Plex Mono',ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;

  /* ── Motion ──
     One easing for everything, which is the doc's point and a fair one: the
     consistency is what reads as smooth, more than any single curve does. Fast
     out, long settle.
     Four durations, each with a job: colour, hover, height, first arrival. The
     rail's fill was already written at 180ms on this exact curve before the doc
     was read, which is some evidence the numbers are right. */
  --ease-out:cubic-bezier(.2,.7,.3,1);
  --t-fast:120ms;    /* colour */
  --t-mid:180ms;     /* hover */
  --t-slow:340ms;    /* anything that changes height */
  --t-arrive:520ms;  /* a block's one and only entrance */

  /* ── Space, 4px base ──
     Named so the rhythm the doc specifies can be written as itself: 104 above a
     section header, 44 below its rule, 28 between a heading and its body. */
  --s-xs:4px; --s-sm:8px; --s-md:16px; --s-lg:28px;
  --s-xl:44px; --s-2xl:72px; --s-3xl:104px;
}

/* ── The paper grain ──
   Three repeating hairline weaves crossed at 0°, 90° and 37°, at a little over
   1% opacity. The doc's rule for it is the useful part: it is felt rather than
   seen, it must not survive a screenshot at 50% zoom, and if you can describe it
   it is too strong.
   On body, and left to scroll with the page, because it is the paper the page is
   printed on — fixing it would slide the type over a stationary texture, which is
   the one thing that would give it away.
   The doc pairs the weaves with two soft radial washes. Those are not adopted:
   the hero already carries .bloom doing that job, and a second light source at
   90% white in the same corner reads as two washes rather than one page.
   Tinted bands, cards and fields all paint their own background, so the grain
   stops at their edges by construction, which is the doc's "never behind a card"
   without needing a rule to enforce it. */
body{
  background-image:
    repeating-linear-gradient(0deg,  rgba(23,27,52,.016) 0 1px, rgba(23,27,52,0) 1px 3px),
    repeating-linear-gradient(90deg, rgba(23,27,52,.013) 0 1px, rgba(23,27,52,0) 1px 4px),
    repeating-linear-gradient(37deg, rgba(120,92,40,.012) 0 1px, rgba(120,92,40,0) 1px 5px);
}

/* ── The type scale ──
   The doc's weights and tracking, which are lighter and tighter than what was
   here: display at 200 where it was 300, and tracking from -.02em out to -.03em
   at the largest size. Plex at 200 is a genuinely thin face and only works
   because the sizes are large — nothing below 34px is set at 200 anywhere.
   The emphasis rule is untouched because it was already the site's own: every
   heading is a light opening clause and one bold closing clause, and the promise
   sits in the weight change rather than in a colour. */
h1{font-weight:200;letter-spacing:-.03em;line-height:1.06}
h2{font-weight:300;letter-spacing:-.025em;line-height:1.12;margin-bottom:var(--s-lg)}
h3{font-weight:500;letter-spacing:-.015em;line-height:1.25}
.deck,.lede{letter-spacing:-.005em}

/* Eyebrows and readouts move to mono. The doc reserves it for section ordinals,
   uppercase micro-labels and anything that reads as a measurement, always 11–12px
   at .14em tracking — which is what every one of these already was in the sans,
   with the tracking doing mono's job by hand. */
.margin b,.step .n,.case__block .case__k,.verdict .k,.stair .k,
.counter,.top nav a{font-family:var(--mono);letter-spacing:.14em}
.margin b,.top nav a{font-size:11px}
.step .n,.case__block .case__k{font-size:12px}

/* ── The logotype ──
   The doc splits the wordmark by weight instead of setting it evenly: "one flow"
   light, the dot in terracotta, "first" semibold. The dot was already the accent
   here; the weight split is new, and it is what makes the mark say which half of
   it is the name. */
.name i{font-style:normal;font-weight:300}
.name b{font-weight:600}

/* ── Press is felt ──
   .985, which the doc calls barely visible and entirely noticeable. Buttons and
   the rail disc only: a link inside a sentence has nothing to scale. */
.act:active,.railcta:active,.ride:active{transform:scale(.985)}
.act,.railcta{transition:transform var(--t-fast) var(--ease-out),
  background var(--t-mid) var(--ease-out),box-shadow var(--t-mid) var(--ease-out)}

/* Arrivals: 10px rather than 18, on the arrival duration, and staggered 70ms
   within a group by site.js as each group crosses. */
.rev{transform:translateY(10px);
  transition:opacity var(--t-arrive) var(--ease-out),
             transform var(--t-arrive) var(--ease-out)}

/* Focus: 2px accent at 3px offset, everywhere. It was 6px on the nav and 3px on
   the objections, which is two answers to one question. */
.top nav a:focus-visible,.act:focus-visible,.asset button:focus-visible,
.doubt:focus-visible,.railcta:focus-visible,.ride:focus-visible{
  outline:2px solid var(--clay-600);outline-offset:3px}

@media (prefers-reduced-motion:reduce){
  .act:active,.railcta:active,.ride:active{transform:none}
}

/* ── The button loses its gradient ──
   Two things pointed at the same fix. The design system's don't-list rules out
   gradients outright, and the gradient was also the last contrast failure on the
   site: white at 17.5px/600 needs 4.5:1, and the top stop #EA650F gave 3.30:1, so
   the label was under AA across the upper third of every primary button. The note
   beside it claimed the top stop was chosen to keep every band above AA, which was
   simply wrong — measured 3.30, 3.75 and 4.40 down the three stops, so only the
   bottom one passed.
   Flat --clay-400, 5.19:1 against white. It is the site's own ramp one step down
   from --clay-mark rather than the doc's #B2461F: the instruction was to keep this
   terracotta, and this keeps it.
   The inset highlight goes with the gradient. It existed to make a lit top edge
   read against the darkening face, and on a flat colour it is a grey line. The
   warm cast underneath stays, because the doc allows a shadow on hover and on
   floating things, and the ride is both. */
.act,.ride{background:var(--clay-400)}
.act{box-shadow:0 1px 2px rgba(93,41,18,.20)}
.act:hover{filter:none;background:var(--clay-500);
  box-shadow:0 2px 6px rgba(93,41,18,.22)}
.ride{box-shadow:0 6px 18px -6px rgba(93,41,18,.5)}

/* ── A second way out of the hero ──
   Borrowed from slowclarity.com, which pairs its one call to action with "Not sure
   yet? Start here" pointing at its own qualification section. The gap it fills is
   real here: this page had exactly one path, straight to the form, and a reader who
   is not ready had nothing to do but leave. The Fit section already answers them, and
   nothing routed to it.
   Set quieter and smaller than .quiet is elsewhere, and on its own line under the
   note, because it must not compete with the button it sits beneath: it is the exit
   for someone the button did not convince, not a second offer. */
.quiet--inline{display:inline-flex;margin-top:10px;font-size:.92rem;font-weight:500;
  color:var(--ink-3);gap:6px}
.quiet--inline:hover{color:var(--clay-500)}
@media(min-width:560px){
  .act-note .quiet--inline{margin-left:2px}
}

/* ── The intake ──
   Eleven questions, one per screen once site.js has them, and one long form if it
   never arrives. The markup is the long form; nothing here creates a second copy.
   Borrowed from slowclarity.com, which puts a guided intake where most sites put a
   booking link. The reasoning is worth restating: for a service whose product is a
   straight answer, a form that makes the reader think is a better front door than
   one that takes their calendar. These are not its questions -- they are the ones
   this engagement actually turns on, the assumption and the appetite for a no. */
.intake__lead{margin:0 0 26px;color:var(--ink-2);font-size:1rem;line-height:1.7;
  max-width:52ch}
.intake__steps{list-style:none;margin:0;padding:0;display:grid;gap:var(--s-lg)}
.qstep{margin:0}
/* The step is hidden with [hidden], so nothing here needs to know how many there
   are, and the un-paginated form is simply every step visible at once. */
.qstep[hidden]{display:none}

/* A line above the question that says what kind of question it is. Three of the
   eleven carry one; the rest do not need telling. */
.qstep__frame{margin:0 0 12px;font-family:var(--mono);font-size:11px;
  letter-spacing:.14em;text-transform:uppercase;color:var(--clay-500)}
.qstep__opt{margin-left:10px;font-family:var(--mono);font-size:10px;
  letter-spacing:.12em;text-transform:uppercase;font-weight:500;
  color:var(--ink-3);vertical-align:1px}

/* The question itself carries the weight a label does not usually get, because on
   its own screen it is the only thing being asked. */
.qstep > .field__label,.qstep .qfield legend{display:block;font-family:var(--display);
  font-size:1.32rem;font-weight:500;line-height:1.28;letter-spacing:-.012em;
  color:var(--ink);margin-bottom:8px;padding:0}
.qstep > .field__hint{display:block;margin-bottom:14px;color:var(--ink-3);
  font-size:.95rem;line-height:1.6;max-width:46ch}
.qstep .textarea{min-height:104px}
.qstep .field__error{display:none}
.qstep[data-invalid="true"] .field__error{display:block}

/* The choice question. A row of real radios, each a full-width target, because
   four short options are quicker to read than a select is to open. */
.qfield{border:0;margin:0;padding:0}
.pick{display:flex;align-items:center;gap:12px;min-height:52px;padding:0 14px;
  border:1px solid var(--sand-300);border-radius:var(--r-sm);
  background:var(--sand-50);cursor:pointer;
  transition:border-color var(--t-mid) var(--ease-out)}
.pick + .pick{margin-top:8px}
.pick:hover{border-color:var(--sand-500)}
.pick input{accent-color:var(--clay-400);width:18px;height:18px;flex:none}
.pick span{font-size:1rem;color:var(--ink-2)}
.pick:has(input:checked){border-color:var(--clay-400)}
.pick:has(input:checked) span{color:var(--ink)}
.pick:focus-within{outline:2px solid var(--clay-600);outline-offset:3px}

/* Back and the count sit above the button, not beside it: the button is the one
   thing on the step that should look like the way forward. */
.intake__bar{display:flex;align-items:center;justify-content:space-between;
  gap:16px;margin:0 0 16px;min-height:44px}
.intake__back{background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--body);font-size:.94rem;font-weight:500;color:var(--ink-3)}
.intake__back:hover{color:var(--clay-500)}
.intake__back[hidden]{display:none}
.intake__count{margin:0;font-family:var(--mono);font-size:11px;letter-spacing:.14em;
  text-transform:uppercase;color:var(--ink-3)}

/* ── The brief the reader keeps ──
   There is no server behind this, so the end of the form is the brief itself,
   readable and copyable, with the plain statement that nothing has been sent. */
#brief{margin-top:14px;font-family:var(--mono);font-size:13px;line-height:1.7;
  background:var(--sand-50);white-space:pre;resize:vertical}
.briefacts{display:grid;gap:12px;margin-top:18px;justify-items:start}
.briefacts .quiet{background:none;border:0;padding:0;cursor:pointer;
  font-family:var(--body)}
@media(min-width:520px){
  .briefacts{grid-auto-flow:column;align-items:center;
    grid-template-columns:auto auto;justify-content:start;gap:20px}
}
.form-status .act--block{width:auto}

/* ── The intake page ──
   The point of this page is that there is nothing on it. The same eleven questions
   inside a card in the middle of start.html read as a contact form that would not
   end, because they were surrounded by a masthead, a nav, a rail, a margin note, a
   checklist, a closing section and a footer, and every one of those said "there is
   more of this below". Alone on a page, one question at a time, the same eleven
   read as a conversation. That is the whole change; the questions did not move. */
.bare{min-height:100vh;display:flex;flex-direction:column}

/* A rule at the very top, and the only ambient indicator on the site: it reports
   how far through the reader is and nothing else. Accent here, where there is no
   rail for it to compete with and progress is worth being able to see. */
.intakeprog{position:fixed;top:0;left:0;right:0;height:2px;z-index:60;
  background:var(--clay-400);transform:scaleX(0);transform-origin:left;
  transition:transform var(--t-slow) var(--ease-out)}

.baretop{display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:26px 20px;max-width:760px;width:100%;margin:0 auto;box-sizing:border-box}
@media(min-width:620px){.baretop{padding:34px 40px}}
/* Exit, not Back: Back is the button inside the form that moves one question, and
   two controls a centimetre apart both saying back is how a reader loses their place. */
.exit{display:inline-flex;align-items:center;gap:8px;min-height:44px;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);text-decoration:none;
  transition:color var(--t-fast) var(--ease-out)}
.exit:hover{color:var(--clay-500)}
.exit span{font-size:16px;line-height:1}

.intakepage{flex:1;display:flex;align-items:center;justify-content:center;
  padding:20px 20px 72px;box-sizing:border-box}
@media(min-width:620px){.intakepage{padding:32px 40px 96px}}
.intakepage > *{width:100%;max-width:660px}
.intakepage .intake{max-width:660px}

/* The question, alone on a screen, gets the size a heading gets. This is the only
   place the interface type scale and the display scale meet. */
.intakepage .qstep > .field__label,
.intakepage .qstep .qfield legend{font-size:clamp(1.5rem,3.4vw,2.05rem);
  font-weight:300;line-height:1.18;letter-spacing:-.022em;margin-bottom:14px}
.intakepage .qstep > .field__hint,
.intakepage .qstep__hint{font-size:1rem;margin-bottom:22px;max-width:44ch}
/* The contact step asks a question like every other step, but its two fields carry
   their own labels, so the question has to be a heading rather than a label. It was
   the one step with nothing set at question size, which made the end of the form look
   like a different form. */
.intakepage .qstep__q{font-size:clamp(1.5rem,3.4vw,2.05rem);font-weight:300;
  line-height:1.18;letter-spacing:-.022em;margin:0 0 10px}
.qstep__hint{display:block;color:var(--ink-3);line-height:1.6}
.intakepage .qstep .textarea{min-height:132px;font-size:17px;line-height:1.6}
.intakepage .intake__steps{gap:0}

/* The welcome. It is a step like any other so that with scripting off it is simply
   the paragraph above the questions, and so Back out of question one returns here
   rather than to nothing. */
.qstep--open h1{font-size:clamp(1.9rem,4.6vw,2.9rem);font-weight:200;
  letter-spacing:-.03em;line-height:1.1;margin-bottom:22px}
.qstep--open .lede{max-width:48ch}
.qstep--open .lede + .lede{margin-top:16px}

.intakepage .intake__bar{margin:30px 0 0;order:2}
.intakepage .intake{display:flex;flex-direction:column}
.intakepage .intake__steps{order:0}
.intakepage .intake > button[type="submit"]{order:1;margin-top:30px;width:auto;
  align-self:start}
.intakepage .fineprint{order:3;margin-top:22px}
@media(max-width:519px){
  .intakepage .intake > button[type="submit"]{width:100%}
}

/* The brief, when it arrives, is the only thing on the page. */
.intakepage .form-status{display:none}
.intakepage .form-status[data-visible="true"]{display:block}
.intakepage .form-status h3{font-size:clamp(1.6rem,3.6vw,2.2rem);font-weight:300;
  letter-spacing:-.025em;line-height:1.16;margin-bottom:16px}
.intakepage .form-status > div > p{color:var(--ink-2);font-size:1rem;line-height:1.7;
  max-width:56ch;margin-bottom:24px}

/* ── The takeover ──
   Fixed over everything, opaque, and its own scroll container. The grain is on body
   and body is behind this, so the overlay repeats it rather than showing through:
   it has to look like the same paper, not like a sheet laid on top of it. */
.takeover[data-modal="true"]{position:fixed;inset:0;z-index:100;overflow-y:auto;
  overscroll-behavior:contain;
  background-color:var(--sand-100);
  background-image:
    repeating-linear-gradient(0deg,  rgba(23,27,52,.016) 0 1px, rgba(23,27,52,0) 1px 3px),
    repeating-linear-gradient(90deg, rgba(23,27,52,.013) 0 1px, rgba(23,27,52,0) 1px 4px),
    repeating-linear-gradient(37deg, rgba(120,92,40,.012) 0 1px, rgba(120,92,40,0) 1px 5px);
  display:flex;flex-direction:column}
.takeover[hidden]{display:none}
/* Un-promoted, it is a section: separated from the page above it by a rule, every
   question visible, and no way for it to cover anything. */
.takeover:not([data-modal="true"]){border-top:1px solid var(--sand-300);
  margin-top:var(--s-2xl);padding-top:var(--s-xl)}
.takeover:not([data-modal="true"]) .takeover__top .exit,
.takeover:not([data-modal="true"]) .intakeprog,
.takeover:not([data-modal="true"]) .intake__bar{display:none}
.takeover:not([data-modal="true"]) .takeover__body{display:block}
/* No animation on the way in beyond the paper arriving: a modal that slides is a
   modal you wait for, and the first question should already be readable. */
.takeover__top{display:flex;align-items:center;justify-content:space-between;gap:20px;
  padding:22px 20px;max-width:760px;width:100%;margin:0 auto;box-sizing:border-box;
  flex:none}
@media(min-width:620px){.takeover__top{padding:30px 40px}}
.takeover__top .name{font-family:var(--display);font-size:17px;font-weight:600;
  letter-spacing:-.02em;color:var(--ink);display:flex;align-items:center;gap:10px}
.takeover__top .name .mark{width:24px;height:24px}
.takeover__body{flex:1}

/* Close, not Back: Back is the control inside the form that moves one question, and
   two things a centimetre apart both meaning backwards is how a reader loses
   their place. */
.exit{display:inline-flex;align-items:center;gap:8px;min-height:44px;padding:0;
  background:none;border:0;cursor:pointer;
  font-family:var(--mono);font-size:11px;letter-spacing:.14em;text-transform:uppercase;
  color:var(--ink-3);text-decoration:none;
  transition:color var(--t-fast) var(--ease-out)}
.exit:hover{color:var(--clay-500)}
.exit span{font-size:16px;line-height:1}

/* The rule at the top of the overlay, and the only ambient indicator on the site:
   it reports how far through the reader is and nothing else. */
.takeover[data-modal="true"] .intakeprog{position:absolute;top:0;left:0;right:0;height:2px;
  background:var(--clay-400);transform:scaleX(0);transform-origin:left;
  transition:transform var(--t-slow) var(--ease-out)}

/* Nothing behind the overlay is reachable, including by a rail that is position:fixed
   and would otherwise paint straight through it. */
html[data-over="true"] .spine,
html[data-over="true"] .ride,
html[data-over="true"] .top{display:none}

/* A numbered variant of the checklist, for the one place on the site that describes a
   sequence in prose rather than in columns. The dot says "and also"; a numeral says
   "and then", which is the whole difference on a page whose problem was that it
   described a call and handed over a form. */
.checklist--ord{counter-reset:ck}
.checklist--ord li{counter-increment:ck;padding-left:34px;max-width:60ch}
.checklist--ord li::before{content:counter(ck);left:0;top:0;
  width:auto;height:auto;border-radius:0;background:none;
  font-family:var(--mono);font-size:11px;font-weight:600;letter-spacing:.14em;
  color:var(--clay-500);line-height:1.8}
.checklist--ord li b{font-weight:600;color:var(--ink)}

/* ── The intake, loosened ──
   Measured against slowclarity's intake, which is where this pattern came from and
   which reads as more relaxed than the first pass here did. The differences were
   all quantifiable: its question is 48px against our 33; its field is invisible --
   transparent, no border, 24px text sitting on the page -- against our white box
   with a 1px border and 17px text; its gaps run 32/16/63/100 down the screen where
   ours ran 12/14/22/30; and its controls are a plain text Back and a modest pill,
   against our full-strength 74px block. Tightness was the sum of those numbers.
   The identity stays ours: paper, terracotta, Plex, the mono eyebrows. Only the
   rhythm changes. Everything here is scoped to .intakepage, so the page-embedded
   fallback form and the brief panel keep their boxed fields. */
.intakepage > *{max-width:720px}
.intakepage .qstep__frame{margin-bottom:26px}
.intakepage .qstep > .field__label,
.intakepage .qstep .qfield legend{font-size:clamp(1.9rem,3.6vw,3rem);
  font-weight:300;line-height:1.22;letter-spacing:-.025em;margin-bottom:16px}
.intakepage .qstep__q{font-size:clamp(1.9rem,3.6vw,3rem);line-height:1.22;
  letter-spacing:-.025em;margin-bottom:16px}
.intakepage .qstep > .field__hint,
.intakepage .qstep__hint{font-size:1.06rem;font-weight:300;line-height:1.6;
  margin-bottom:52px;max-width:52ch}
/* A step whose question has no hint still needs the air the hint would have kept. */
.intakepage .qstep > .field__label{margin-bottom:16px}
.intakepage .qstep > .field__label:has(+ textarea){margin-bottom:52px}

/* The field disappears. No box, no fill: 22px of light Plex sitting on the paper
   with one hairline underneath, which darkens to the accent when the field is
   awake. The box was the single biggest source of tightness -- it framed every
   answer as a form control, where the point of the page is that it reads as a
   conversation. */
.intakepage .qstep .textarea,
.intakepage .qstep .input{background:none;border:0;border-radius:0;
  border-bottom:1px solid var(--sand-400);
  padding:10px 0 14px;min-height:0;
  font-size:22px;font-weight:300;line-height:1.55;color:var(--ink);
  transition:border-color var(--t-mid) var(--ease-out)}
.intakepage .qstep .textarea:focus,
.intakepage .qstep .input:focus{outline:none;box-shadow:none;
  border-bottom-color:var(--clay-500)}
.intakepage .qstep .textarea::placeholder,
.intakepage .qstep .input::placeholder{color:var(--ink-3);opacity:.6;font-weight:300}
.intakepage .qstep .field{margin-bottom:34px}
.intakepage .qstep .field .field__label{font-family:var(--mono);font-size:11px;
  font-weight:600;letter-spacing:.14em;text-transform:uppercase;color:var(--ink-3);
  margin-bottom:2px}

/* The choices lose their boxes for the same reason the field did. */
.intakepage .pick{background:none;border:0;border-bottom:1px solid var(--sand-300);
  border-radius:0;padding:18px 2px;min-height:56px}
.intakepage .pick + .pick{margin-top:0}
.intakepage .pick:hover{border-bottom-color:var(--sand-500)}
.intakepage .pick:has(input:checked){border-bottom-color:var(--clay-400)}
.intakepage .pick span{font-size:1.12rem;font-weight:300}

/* Controls on one quiet row, a long way below the field: Back on the left with the
   count beside it, the action on the right. The submit keeps the accent -- it is
   still the one thing on the screen that moves the reader forward -- but at pill
   proportions rather than the closing section's full block. */
.intakepage .intake{display:grid;grid-template-columns:1fr auto;align-items:center;
  column-gap:24px}
.intakepage .intake__steps{grid-column:1 / -1;order:0}
.intakepage .intake__kbd{grid-column:1 / -1;order:1;margin:14px 0 0;
  font-family:var(--mono);font-size:10.5px;letter-spacing:.13em;
  text-transform:uppercase;color:var(--ink-3);opacity:.7}
.intakepage .intake__kbd[hidden]{display:none}
.intakepage .intake__bar{grid-column:1;order:2;margin:64px 0 0;
  display:flex;justify-content:flex-start;gap:26px}
.intakepage .intake > button[type="submit"]{grid-column:2;order:3;margin:64px 0 0;
  justify-self:end;align-self:center;width:auto;
  min-height:52px;padding:14px 26px;border-radius:999px;font-size:16px}
.intakepage .fineprint{grid-column:1 / -1;order:4;margin-top:26px}
@media(max-width:559px){
  .intakepage .intake{grid-template-columns:1fr}
  .intakepage .intake__bar,
  .intakepage .intake > button[type="submit"]{grid-column:1;justify-self:stretch;
    margin-top:34px}
  .intakepage .intake__bar{margin-top:44px}
}
/* The chord does not exist on a touch screen. */
@media (hover:none){
  .intakepage .intake__kbd{display:none}
}

/* ── The step arrives ──
   Questions used to flip: one display toggle, no motion at all, which read as a
   form paging rather than a conversation moving on. A 300ms rise on whichever step
   becomes visible -- restarted by the display change itself, so no script keeps
   time. Scoped to the promoted overlay: the no-script fallback shows every step at
   once and has nothing to arrive. */
@keyframes stepin{from{opacity:0;transform:translateY(12px)}}
.takeover[data-modal="true"] .qstep{animation:stepin 300ms var(--ease-out)}
.takeover[data-modal="true"] .form-status[data-visible="true"] > *{
  animation:stepin 340ms var(--ease-out)}
@media (prefers-reduced-motion:reduce){
  .takeover[data-modal="true"] .qstep,
  .takeover[data-modal="true"] .form-status[data-visible="true"] > *{animation:none}
}

/* ── The sticky call to action, phones only ──
   The design system specifies it -- "appears after the first screen, on mobile
   only" -- and the flow needs it: on a phone there is no rail and no travelling
   button, so a reader in the middle of the page had no way forward except the
   menu. One pill, the same words as every other primary action, replying to
   scroll position rather than idling. */
.stickycta{display:none}
@media(max-width:1179px){
  .stickycta{position:fixed;left:50%;bottom:calc(14px + env(safe-area-inset-bottom));
    z-index:50;display:inline-flex;align-items:center;justify-content:center;
    min-height:52px;padding:14px 26px;border-radius:999px;
    background:var(--clay-400);color:#fff;text-decoration:none;
    font-family:var(--body);font-size:15.5px;font-weight:600;white-space:nowrap;
    box-shadow:0 10px 26px -10px rgba(93,41,18,.55);
    transform:translate(-50%,calc(100% + 20px + env(safe-area-inset-bottom)));
    transition:transform var(--t-slow) var(--ease-out)}
  .stickycta[data-on="true"]{transform:translate(-50%,0)}
  .stickycta:active{transform:translate(-50%,0) scale(.985)}
}
html[data-over="true"] .stickycta{display:none}
@media (prefers-reduced-motion:reduce){
  .stickycta{transition:none}
}

/* ── The reply ──
   What the asker says between questions, keyed in site.js to what the reader just
   did: answered, skipped, or chose. Set in the handwriting face because that face
   is reserved for words a person says out loud -- the reader's own objections use
   it already -- and this is the other half of that conversation. Quiet ink, not
   the accent: it is a voice, not a control. */
.qstep__reply{margin:0 0 26px;font-family:'Quote Hand','Segoe Script',cursive;
  font-weight:600;font-size:1.5rem;line-height:1.35;letter-spacing:.006em;
  color:var(--ink-2);max-width:30ch}

/* ── Focus on a filled button ──
   The sitewide ring is 2px clay-600 at 3px offset, and on paper that is right; on
   a control that is already solid accent it read as a hard dark rim pressed
   against the pill. Same construction as the rail's beads instead: a halo of the
   paper, then the ring. The gap is what makes it read as focus rather than as a
   border the button always had. */
.act:focus-visible,.ride:focus-visible,.stickycta:focus-visible{outline:none;
  box-shadow:0 0 0 3px var(--sand-100),0 0 0 5px var(--clay-500),
             0 1px 2px rgba(93,41,18,.20)}
/* The dialog container takes focus when it opens; it is not a thing to draw a ring
   around, the way in is announced rather than outlined. */
.takeover:focus{outline:none}

/* Deliberate blanks: slots for the details that must not ship missing (the
   photo, the name, the write-ups), marked so they read as a plan rather than an
   accident. Dashed because nothing else on the site is: the eye finds every open
   item in one scan, and the style has an end date. */
.blank{border:1.5px dashed var(--sand-500);border-radius:var(--r-md);
  padding:20px 24px;margin-top:22px}
.blank b{display:block;font-family:var(--mono);font-size:11px;text-transform:uppercase;
  letter-spacing:2.4px;font-weight:500;color:var(--clay-500);margin-bottom:10px}
.blank p{color:var(--ink-3);font-size:.95rem;line-height:1.6;margin:0;max-width:none}
.blankrow{display:flex;gap:22px;flex-wrap:wrap;margin-top:28px;align-items:stretch}
.blankrow .blank{margin-top:0;flex:1 1 260px}
.blank--portrait{flex:0 0 200px;aspect-ratio:4/5;display:flex;flex-direction:column;
  justify-content:center;text-align:center}
