/* ===========================================================================
   MAIN. Consumes tokens.css and nothing else. No colour literal appears
   below this line except transparent and currentColor.

   Structure: a shared role layer (wrap, eyebrow, h2, lead, btn, reveal),
   then one block per section, scoped under that section's id.
   ======================================================================== */

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

/* The horizontal guard lives here and ONLY here. The root's overflow
   propagates to the viewport, so this alone stops sideways scrolling. The
   same declaration on `body` does something different and much worse: it
   makes body itself a scroll container whose scrollHeight equals its
   clientHeight, which silently kills `position: sticky` on the masthead,
   because sticky is resolved against the nearest scrollport and that box
   never scrolls. It shipped that way once. Do not put it back. */
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  overflow-x: hidden;
}
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-text);
  font-size: var(--t-body);
  line-height: var(--lh-body);
  font-synthesis-weight: none;
}

img { max-width: 100%; display: block; }

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

/* ------------------------------------------------------------ focus ---- */
:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: var(--r-1);
}
:focus:not(:focus-visible) { outline: none; }

.skip {
  position: fixed;
  top: var(--s-3);
  left: var(--s-3);
  z-index: var(--z-skip);
  padding: var(--s-3) var(--s-5);
  background: var(--accent-deep);
  color: var(--paper);
  font-family: var(--font-text);
  font-size: var(--t-small);
  font-weight: 600;
  text-decoration: none;
  transform: translateY(-160%);
}
.skip:focus { transform: none; }

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

/* ----------------------------------------------------------- roles ----- */
.wrap {
  width: 100%;
  max-width: var(--spread);
  margin-inline: auto;
  padding-inline: var(--edge);
}

.eyebrow {
  margin: 0 0 var(--s-5);
  font-size: var(--t-eyebrow);
  font-weight: 600;
  letter-spacing: var(--track-eyebrow);
  text-transform: uppercase;
  color: var(--quiet);
}

.h1, .h2, .h3 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: var(--track-display);
  color: var(--fg);
  margin: 0;
  text-wrap: balance;
}
.h1 { font-size: var(--t-display); line-height: var(--lh-display); }
.h2 { font-size: var(--t-h2); line-height: var(--lh-heading); }
.h3 { font-size: var(--t-h3); line-height: var(--lh-heading); font-weight: 700; }

/* The one accent word per page. Noto Sans JP has no true italic, and a browser
   synthesised oblique on a geometric sans looks like a rendering fault, so the
   emphasis is carried by weight and colour. <i> is kept as the element because
   it is still the correct semantics for a word set apart from its neighbours. */
.h1 i, .h2 i {
  font-style: normal;
  font-weight: 800;
  color: var(--accent);
}

.lead {
  font-size: var(--t-lead);
  line-height: 1.55;
  color: var(--fg);
  max-width: var(--measure);
  margin: var(--s-5) 0 0;
}

/* The two-tone lead: first sentence in ink, the rest in quiet, hierarchy
   inside a paragraph without a second face. ONE rule and one span per lead;
   no section gets its own version. The quiet inks in tokens.css hold 7:1 or
   better on every ground a lead is rendered on, which is what lets the quiet
   half sit on the purchase path at all. */
:is(.lead, .buy__lead) > span { color: var(--quiet); }

/* One icon style, drawn by hand: 24x24, 2px stroke, squared caps, 45/90
   angles and quarter arcs, currentColor throughout. Source of record with
   the grid rules is assets/icons/, one file per glyph; each use is inlined.
   Icons appear only where they carry information: the product cards, the
   steps, and the dashboard section. Accent-deep reads 12.76:1 on paper and
   11.70:1 on paper-2, far past the 3:1 of SC 1.4.11. */
.ic {
  display: inline-block;
  width: 24px;
  height: 24px;
  color: var(--accent);
}
.h3 .ic {
  vertical-align: -0.22em;
  margin-right: var(--s-3);
}

.copy { max-width: var(--measure); color: var(--quiet); margin: 0; }

/* a visible operator slot. It should look deliberate, not like a mistake. */
.slot {
  font-style: normal;
  color: var(--accent);
  border-bottom: 1px dotted currentColor;
  white-space: nowrap;
}

a { color: var(--accent); }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  padding: 0.9rem 1.6rem;
  border-radius: var(--r-pill);
  font-family: var(--font-text);
  font-size: var(--t-small);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  border: var(--hair) solid transparent;
  cursor: pointer;
  transition: background-color var(--dur-fast) ease,
              color var(--dur-fast) ease,
              border-color var(--dur-fast) ease,
              transform var(--dur-fast) ease;
}
.btn--fill {
  background: var(--accent-fill);
  color: var(--accent-fill-fg);
}
.btn--fill:hover { transform: translateY(-1px); background: var(--fg); }
.btn--line {
  background: transparent;
  color: var(--fg);
  border-color: var(--rule-strong);
}
.btn--line:hover { border-color: var(--fg); transform: translateY(-1px); }
.btn--big { padding: 1.05rem 1.9rem; font-size: 1rem; }

/* An action whose destination has not been set yet. It keeps the weight of
   the real button, because the buying door is the loudest thing on the page
   and removing it would redraw the layout twice, but it is NOT a control:
   no href, no cursor, no hover lift, nothing in the tab order that could be
   activated to no effect. The bracket inside says why, in the same voice as
   every other unset slot on the site, and it takes the button's own colour
   so the contrast is the button's own rather than the accent on a fill.

   The bracket is not optional decoration. This rule shipped once against
   markup that had no .slot inside it, and the result was three full weight
   accent pills, indistinguishable from the live button above them, that did
   nothing at all when pressed. A dead control that looks alive is worse than
   no control. index.html carries the bracket and aria-disabled now, and
   tools/stripe-links.mjs writes both back on --unset. */
.btn--unset {
  cursor: default;
}
.btn--unset:hover { transform: none; background: var(--accent-fill); }
.btn--unset .slot { color: inherit; border-bottom-color: currentColor; }

/* the same idea in running text: a label with no destination yet */
.unset { color: var(--quiet); }

/* a plain text link that underlines from the baseline. Same grown target
   as the mast links: the text is the design, the pseudo is the touch area. */
.tlink {
  color: var(--fg);
  text-decoration: none;
  border-bottom: var(--hair) solid var(--rule-strong);
  padding-bottom: 2px;
  transition: border-color var(--dur-fast) ease, color var(--dur-fast) ease;
  position: relative;
}
.tlink::after {
  content: "";
  position: absolute;
  inset: -0.5rem 0;
}
.tlink:hover { color: var(--accent); border-color: var(--accent); }

/* ------------------------------------------------------------ texture ----
   The site's ONE depth treatment: a hairline grid drawn with two repeating
   gradients, so it costs no request and no bytes worth measuring. It is used
   in exactly two places, the ground of the system section and the mat the
   console screenshot is framed on, and it is masked to a soft field so it
   never reads as a rectangle laid over the page.

   isolation + z-index -1 keeps it above the element's own background and
   below every child, so no text is ever composited underneath it. The alpha
   is held at 0.055 in tokens.css because that is the darkest it can be while
   ink-quiet, the lightest text that ever sits on it, still measures 6.67:1
   against a grid line. `node tools/contrast.mjs` reproves that on demand. */
.tx { position: relative; isolation: isolate; }
.tx::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    repeating-linear-gradient(to right, var(--tx) 0 var(--hair), transparent var(--hair) var(--tx-pitch)),
    repeating-linear-gradient(to bottom, var(--tx) 0 var(--hair), transparent var(--hair) var(--tx-pitch));
  -webkit-mask-image: radial-gradient(120% 96% at 50% 4%, black 30%, transparent 84%);
  mask-image: radial-gradient(120% 96% at 50% 4%, black 30%, transparent 84%);
}

/* ---------------------------------------------------------- reveals ----
   Rest state is the finished state. The initial offset is only ever applied
   when the script has confirmed it is running, so with JavaScript off, or
   under reduced motion, every word below is already on the page. */
.js .reveal { opacity: 0; transform: translateY(30px); }
.js .reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity var(--dur-enter) ease, transform var(--dur-enter) var(--ease-out);
  transition-delay: calc(var(--d, 0) * var(--stagger));
}
@media (prefers-reduced-motion: reduce) {
  .js .reveal { opacity: 1; transform: none; transition: none; }
}

section { padding-block: var(--section-pad); }

/* ------------------------------------------------------------- atmos ----
   The optional warmth layer: six generated still-life bands, section
   dividers, OFF by default. The whole switch is one attribute on <body>:
   without data-atmos="on" the bands have no box, are never painted, and
   their lazy images are never fetched, so the page is the evidence recipe
   untouched. With it, they render full bleed, still, with honest alt text.
   They are photographs of nothing this business did, and the alt text on
   each one says so before it says anything else. */
.atmos { display: none; }
body[data-atmos="on"] .atmos {
  display: block;
  height: clamp(10rem, 26vh, 15rem);
}
body[data-atmos="on"] .atmos img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* ==================== mast: the header ================================== */
.mast {
  position: sticky;
  top: 0;
  z-index: var(--z-head);
  background: color-mix(in srgb, var(--paper) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: var(--hair) solid var(--rule);
}
.mast__in {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3) var(--s-4);
  min-height: 4.25rem;
}
.mast__mark {
  font-family: var(--font-display);
  font-size: 1.05rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.mast__nav {
  display: flex;
  align-items: center;
  gap: clamp(var(--s-4), 3vw, var(--s-6));
  font-size: var(--t-small);
}
.mast__nav a {
  color: var(--ink);
  text-decoration: none;
  border-bottom: var(--hair) solid transparent;
  padding-bottom: 2px;
  transition: border-color var(--dur-fast) ease;
  /* The visible link stays a text line; the TARGET is grown to the 44px
     floor by a pseudo element, so the design does not change and an older
     thumb still cannot miss. The gap tokens keep neighbours separated. */
  position: relative;
}
.mast__nav a::after {
  content: "";
  position: absolute;
  inset: -0.8rem -0.3rem;
}
.mast__nav a:hover { border-color: var(--accent); }

/* Click to call is in the header at EVERY width, phones included. It shipped
   hidden below 46em, which left a phone visitor with no tel: control between
   the hero and the contact section: 4,726px, about six screens, on a page
   whose promise is "I answer the phone". A sticky number is the conversion
   floor for a local service site and it is not the thing that gets dropped
   when the line is short. */
.mast__tel { display: inline; }

/* What gets dropped instead, measured rather than guessed. At 375px the line
   is 335px wide and holds a 162px wordmark; the buying door plus the number
   is 138px, so the two of them fit with 35px to spare and the header stays
   one row at 69px. Everything else goes.

   Written as "keep the number and the buying door" rather than as a list of
   what to hide, because the three pages carry three different navs (Work,
   Prices, Home) and an enumerated list would have quietly stopped covering
   work.html the day its first item was renamed. Nothing dropped here is the
   only route to itself: the wordmark is the way home, Prices is an anchor on
   the page you are already on, and Work is linked from the proof strip and
   from the footer. The phone was the one that had no second route. */
@media (max-width: 32em) {
  .mast__mark { font-size: 0.95rem; }
  .mast__nav { gap: var(--s-4); font-size: var(--t-micro); }
  .mast__nav a:not(.mast__tel):not([href$="buy-08"]) { display: none; }
}
/* At 320 the number and the buying door no longer both fit beside the
   wordmark. Buy is a section of a page that scrolls to it; the number is the
   business. */
@media (max-width: 21em) {
  .mast__nav a:not(.mast__tel) { display: none; }
}

/* ==================== hero-01: promise, action, one real site =========== */
#hero-01 {
  padding-top: clamp(2.5rem, 7vh, 5rem);
  padding-bottom: var(--section-pad);

  & .hero__in {
    display: grid;
    row-gap: clamp(var(--s-6), 4vw, var(--s-7));
    column-gap: clamp(var(--s-7), 7vw, var(--s-9));
    align-items: center;
  }
  @media (min-width: 62em) {
    & .hero__in { grid-template-columns: minmax(0, 1fr) auto; }
  }

  & .hero__eyebrow { margin-bottom: var(--s-4); }

  /* the operator line: a person, a place, and the promise the buyer is
     actually testing. Body size, full ink, right under the lead. */
  & .hero__op {
    max-width: var(--measure);
    margin: var(--s-4) 0 0;
  }

  & .hero__acts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4);
    margin-top: clamp(var(--s-6), 4vw, var(--s-7));
  }

  /* the price chip: quiet, one line, body sized. Quiet ink is 8.16:1 on
     paper, past the 7:1 purchase-path floor. */
  & .hero__price {
    margin: var(--s-4) 0 0;
    font-size: var(--t-body);
    color: var(--quiet);
  }

  /* the platform, cropped, in the first screen. A dark rectangle set straight
     onto warm paper reads as a hole, so it takes the same paper mat and
     hairline the whole screenshot takes further down, at a smaller gauge.

     30rem is a ceiling, not a width: the crop is 687 real pixels and this
     site does not upscale a screenshot. At 30rem it renders at 0.70 of its
     own size, and on a 375px phone at 0.49, so it is sharp at 1x and close
     to sharp at 2x. */
  & .chip {
    margin: clamp(var(--s-6), 4vw, var(--s-7)) 0 0;
    max-width: 30rem;
  }
  /* Square corners, deliberately: radius lives on pill controls and the
     device frame only. The soft shadow stays because this is a photograph
     frame, the one place the visual language grants a shadow. */
  & .chip__mat {
    display: block;
    padding: var(--s-2);
    background: var(--paper);
    border: var(--hair) solid var(--rule-strong);
    box-shadow: var(--shadow-mat);
  }
  & .chip img {
    width: 100%;
    height: auto;
  }
  & .chip figcaption {
    margin-top: var(--s-3);
    font-size: var(--t-micro);
    color: var(--quiet);
  }

  /* the device. This is the page's one signature moment: a real site,
     at a size where its own type and price are legible, scrolling itself
     on hover or keyboard focus. Without JavaScript it is a finished,
     static frame, because the movement is a CSS transition on :hover
     and :focus-visible and nothing else. */
  & .rig {
    --rig-w: clamp(16rem, 76vw, 21rem);
    --rig-h: clamp(25rem, 60vh, 34rem);
    display: block;
    width: var(--rig-w);
    margin-inline: auto;
    text-decoration: none;
    color: inherit;
  }
  & .rig__glass {
    display: block;
    position: relative;
    height: var(--rig-h);
    overflow: hidden;
    border-radius: var(--r-device);
    border: var(--hair) solid var(--rule-strong);
    background: var(--paper-2);
    box-shadow: var(--shadow-rig);
  }
  & .rig__shot {
    width: 100%;
    height: auto;
    transform: translateY(0);
    transition: transform 900ms var(--ease-out);
    will-change: transform;
  }
  & .rig:hover .rig__shot,
  & .rig:focus-visible .rig__shot {
    transform: translateY(calc(-100% + var(--rig-h)));
    transition: transform var(--dur-scroll) linear;
  }
  & .rig:focus-visible .rig__glass { outline: 2px solid var(--focus); outline-offset: 4px; }
  & .rig:focus-visible { outline: none; }

  & .rig__cap {
    display: block;
    max-width: var(--rig-w);
    margin-top: var(--s-4);
    font-size: var(--t-micro);
    color: var(--quiet);
  }
  & .rig__cap b { font-weight: 600; color: var(--ink); }
  & .rig__cap .go { white-space: nowrap; color: var(--accent); }
  & .rig:hover .rig__cap .go { text-decoration: underline; }

  @media (prefers-reduced-motion: reduce) {
    & .rig__shot, & .rig:hover .rig__shot, & .rig:focus-visible .rig__shot {
      transition: none;
      transform: translateY(0);
    }
  }
}

/* ==================== offer-02: the three things ======================== */
#offer-02 {
  border-top: var(--hair) solid var(--rule);

  & .offer__grid {
    display: grid;
    gap: 0;
    margin-top: clamp(var(--s-6), 5vw, var(--s-8));
  }
  @media (min-width: 54em) {
    & .offer__grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  }

  & .card {
    padding: var(--s-6) 0;
    border-top: var(--hair) solid var(--rule);
  }
  @media (min-width: 54em) {
    & .card {
      padding: var(--s-6) clamp(var(--s-5), 2.5vw, var(--s-6));
      border-top: none;
      border-left: var(--hair) solid var(--rule);
    }
    & .card:first-child { padding-left: 0; border-left: none; }
    & .card:last-child { padding-right: 0; }
  }

  /* number, then the job that part of the system does. One line, because
     the job is the argument of this page and it should sit level with the
     ordinal rather than under it. */
  & .card__tag {
    margin: 0 0 var(--s-4);
    font-size: var(--t-micro);
    font-weight: 600;
    color: var(--quiet);
  }
  & .card__tag span {
    margin-right: var(--s-3);
    letter-spacing: 0.14em;
    color: var(--accent);
  }
  & .card__price {
    margin: var(--s-3) 0 var(--s-4);
    font-family: var(--font-display);
    font-size: var(--t-price);
    line-height: 1.15;
    color: var(--ink);
  }
  /* The counter runs on the digits alone. Tabular figures so a price on its
     way from 0 to 900 cannot change the width of the line it sits in. */
  & .tick { font-variant-numeric: tabular-nums; }
  /* Card copy sits on the purchase path, so it holds the body floor: 17px
     at 1.6, quiet ink at 8.16:1. It stopped being small print in v4. */

  & .offer__note {
    margin: clamp(var(--s-6), 4vw, var(--s-7)) 0 0;
    padding-top: var(--s-5);
    border-top: var(--hair) solid var(--rule);
    color: var(--quiet);
  }
}

/* ==================== platform-03: the software, photographed ===========
   A landscape screenshot of a dark console framed on a light mat. The mat
   is the only reason this needs any styling at all: a dark rectangle set
   straight onto warm paper reads as a hole, and a hairline plus a little
   air turns it into a photograph of something.                            */
#platform-03 {
  background: var(--paper-2);
  border-top: var(--hair) solid var(--rule);

  /* what the login shows, in the buyer's nouns, glyph beside each. Quiet
     ink holds 7.48:1 on paper-2; the glyphs read 11.70:1. */
  & .plat__keys {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: var(--s-3) var(--s-6);
    margin: var(--s-5) 0 0;
    padding: 0;
  }
  & .plat__keys li {
    display: inline-flex;
    align-items: center;
    gap: var(--s-2);
    font-size: var(--t-small);
    font-weight: 600;
    color: var(--quiet);
  }

  & .shot {
    margin: clamp(var(--s-6), 5vw, var(--s-8)) 0 0;
    max-width: 58rem;
  }
  /* Square corners, like the chip in the hero: radius belongs to pills and
     the device frame. The mat's soft shadow is the photograph-frame
     exception and stays. */
  & .shot__mat {
    padding: clamp(var(--s-3), 1.4vw, var(--s-5));
    background: var(--paper);
    border: var(--hair) solid var(--rule-strong);
    box-shadow: var(--shadow-mat);
  }
  /* width and height are on the element, so the box is reserved before the
     bytes arrive and nothing below it moves when they do. */
  & .shot img {
    width: 100%;
    height: auto;
    border: var(--hair) solid var(--rule);
  }
  /* Two phone screens of the client dashboard, side by side in the mat.
     Portrait screenshots at natural phone proportions; capped so a pair of
     390-point screens never balloons past believable size on a wide desk. */
  & .shot__pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: clamp(var(--s-3), 1.4vw, var(--s-5));
    max-width: 46rem;
    margin-inline: auto;
  }
  & figcaption {
    margin-top: var(--s-4);
    max-width: var(--measure);
    font-size: var(--t-micro);
    color: var(--quiet);
  }

  /* On a phone the screenshots take the full viewport width and stack: two
     phone screens side by side at 170px each would be unreadable, and a
     phone screenshot read ON a phone at its own size is the most honest
     rendering this figure can have. */
  @media (max-width: 47.99em) {
    & .shot {
      max-width: none;
      margin-inline: calc(var(--edge) * -1);
    }
    & .shot__mat {
      padding: var(--s-2);
      border-inline: 0;
    }
    & .shot__pair {
      grid-template-columns: 1fr;
      max-width: 24rem;
    }
    & figcaption { padding-inline: var(--edge); }
  }
}

/* ==================== system-04: the argument, drawn ====================
   Three inputs, one trunk, one login, one phone ringing.

   The whole diagram is sized so it renders at roughly 1:1 at every width
   this site is read at, which is the only way a 12px annotation stays a
   12px annotation. The viewBox is 340 wide and the figure is capped at
   24rem, so the scale runs from 0.99 at a 375px phone to 1.13 on a desk.
   A wide landscape diagram would have had to shrink to 0.46 on that phone
   and its labels with it.                                                */
#system-04 {
  background: var(--paper);
  border-top: var(--hair) solid var(--rule);
  border-bottom: var(--hair) solid var(--rule);

  & .system__in {
    display: grid;
    gap: clamp(var(--s-7), 6vw, var(--s-8));
    align-items: center;
  }
  /* 24rem is a track width, not a max-width on the figure. An `auto` track
     asked the SVG for a max-content width, got the 300px it happened to lay
     out at, and quietly shrank every label in the diagram by 22 percent. */
  @media (min-width: 58em) {
    & .system__in { grid-template-columns: minmax(0, 1fr) 24rem; }
  }
  & .system__copy .copy { color: var(--quiet); }
  & .system__fig {
    justify-self: center;
    width: 100%;
    max-width: 24rem;
  }
  & .dia { display: block; width: 100%; height: auto; }

  & .dia__nodes rect { fill: var(--paper); stroke: var(--rule-strong); stroke-width: 1; }
  & .dia__hub { fill: var(--paper); stroke: var(--accent); stroke-width: 2; }
  & .dia__out { fill: var(--accent-fill); }

  /* Every size below is in viewBox units, and the viewBox is 340 wide against
     a box that is 335px on a 375px phone and 384px on a desk. That is a scale
     of 0.99 to 1.13, so these ARE the rendered pixel sizes give or take a
     tenth, which is the entire reason the diagram is drawn portrait. */
  & .dia__no text {
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.14em;
    fill: var(--accent);
  }
  & .dia__name text {
    font-size: 15px;
    font-weight: 700;
    letter-spacing: -0.01em;
    fill: var(--ink);
  }
  & .dia__edge text { font-size: 13px; font-weight: 500; fill: var(--ink-quiet); }
  & .dia__hubname { font-size: 14px; font-weight: 700; fill: var(--ink); text-anchor: middle; }
  & .dia__hubsub { font-size: 12.5px; font-weight: 500; fill: var(--ink-quiet); text-anchor: middle; }
  & .dia__outname { font-size: 14px; font-weight: 700; fill: var(--accent-fill-fg); text-anchor: middle; }

  /* The traces carry the argument, so they are the accent and not a rule.
     Every path declares pathLength="1", which turns "draw the line" into a
     dashoffset from 1 to 0 with no measuring in JavaScript at all. */
  & .dia__trace path {
    stroke: var(--accent);
    stroke-width: 1.5;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: 1;
  }
  /* Armed only once the head gate has confirmed a script is running. With
     scripts off this rule never applies and the diagram is simply finished. */
  .js & .dia__trace path { stroke-dashoffset: 1; }
  .js & .reveal.is-in .dia__trace path {
    stroke-dashoffset: 0;
    transition: stroke-dashoffset var(--dur-draw) var(--ease-out);
    transition-delay: calc(var(--d, 0) * var(--stagger));
  }
  @media (prefers-reduced-motion: reduce) {
    .js & .dia__trace path { stroke-dashoffset: 0; transition: none; }
  }
}

/* ==================== steps-05: how it goes ============================= */
#steps-05 {
  background: var(--paper-2);

  & .steps {
    list-style: none;
    margin: clamp(var(--s-6), 5vw, var(--s-8)) 0 0;
    padding: 0;
    display: grid;
    gap: var(--s-6);
    counter-reset: step;
  }
  /* Four beats, not three, since the fourth is the one that recurs. Two up
     at tablet and four across on a desk; at 54em, four columns would give
     each step about 11rem and break "Your domain, your name, your phone
     number" over six lines. */
  @media (min-width: 40em) {
    & .steps { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: clamp(var(--s-6), 4vw, var(--s-7)); }
  }
  @media (min-width: 62em) {
    & .steps { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: clamp(var(--s-5), 2.6vw, var(--s-7)); }
  }
  & .steps li {
    counter-increment: step;
    padding-top: var(--s-5);
    border-top: var(--hair) solid var(--rule-strong);
  }
  & .steps li::before {
    content: counter(step, decimal-leading-zero);
    display: block;
    margin-bottom: var(--s-4);
    font-size: var(--t-micro);
    font-weight: 600;
    letter-spacing: 0.14em;
    color: var(--accent);
  }
  /* Step copy holds the 17px body floor too; quiet ink is 7.48:1 on this
     ground. Small print stopped being small in v4. */
  & .steps p { margin: var(--s-3) 0 0; color: var(--quiet); }
}

/* ==================== proof-06: a strip, not a section ================== */
#proof-06 {
  padding-block: clamp(var(--s-7), 8vh, var(--s-8));
  border-top: var(--hair) solid var(--rule);
  border-bottom: var(--hair) solid var(--rule);

  & p {
    margin: 0;
    max-width: 44rem;
    font-family: var(--font-display);
    font-size: clamp(1.35rem, 2.6vw, 1.9rem);
    line-height: 1.35;
    color: var(--ink);
  }
  & a { white-space: nowrap; }
}

/* ==================== reach-07: phone first, then four fields =========== */
#reach-07 {
  & .reach__in {
    display: grid;
    gap: clamp(var(--s-7), 6vw, var(--s-9));
    align-items: start;
  }
  @media (min-width: 58em) {
    & .reach__in { grid-template-columns: minmax(0, 0.95fr) minmax(0, 1fr); }
  }

  & .reach__tel {
    display: inline-block;
    margin-top: var(--s-6);
    font-family: var(--font-display);
    font-size: clamp(1.6rem, 3.4vw, 2.3rem);
    color: var(--accent);
    text-decoration: none;
    border-bottom: 2px solid transparent;
    transition: border-color var(--dur-fast) ease;
  }
  & .reach__tel:hover { border-color: var(--accent); }

  & form { display: grid; gap: var(--s-5); }
  & form > .btn { justify-self: start; }
  & .field { display: grid; gap: var(--s-2); }
  & label { font-size: var(--t-small); font-weight: 600; color: var(--ink); }
  & input, & textarea, & select {
    width: 100%;
    padding: 0.8rem 0.9rem;
    font: inherit;
    font-size: var(--t-small);
    color: var(--ink);
    background: var(--paper);
    border: var(--hair) solid var(--rule-strong);
    transition: border-color var(--dur-fast) ease;
  }
  & textarea { min-height: 6.5rem; resize: vertical; }
  & input:hover, & textarea:hover { border-color: var(--ink); }
  & .err {
    font-size: var(--t-micro);
    color: var(--accent);
    font-weight: 600;
  }
  & [aria-invalid="true"] { border-color: var(--accent); border-width: 2px; }

  & .summary {
    padding: var(--s-4) var(--s-5);
    border: 2px solid var(--accent);
    font-size: var(--t-small);
  }
  & .summary ul { margin: var(--s-2) 0 0; padding-left: 1.1rem; }
  & .summary[hidden] { display: none; }

  & .pot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

  & .note { font-size: var(--t-micro); color: var(--quiet); margin: 0; }
  /* The draft only exists when the script does. Saying otherwise with
     scripts off would be a claim about storage that is not true. */
  html:not(.js) & .draft { display: none; }
  & .nojs { display: none; }
  html:not(.js) & .nojs {
    display: block;
    padding: var(--s-4) var(--s-5);
    border: var(--hair) solid var(--rule-strong);
    font-size: var(--t-small);
  }
}

/* ==================== buy-08: the loud door ============================= */
#buy-08 {
  background: var(--bg);
  color: var(--fg);

  & .buy__head { max-width: 40rem; }
  & .buy__head .h2 { color: var(--fg); }
  /* The door has to say the same thing the argument said two screens up, or
     the section that takes the money contradicts the section that made the
     case. */
  & .buy__lead {
    margin: var(--s-5) 0 0;
    font-size: var(--t-lead);
    line-height: 1.55;
    color: var(--fg);
  }

  & .buy__list {
    list-style: none;
    margin: clamp(var(--s-6), 5vw, var(--s-8)) 0 0;
    padding: 0;
  }
  & .buy__row {
    display: grid;
    gap: var(--s-4);
    align-items: center;
    padding: var(--s-6) 0;
    border-top: var(--hair) solid var(--rule);
  }
  & .buy__row:last-child { border-bottom: var(--hair) solid var(--rule); }
  @media (min-width: 48em) {
    & .buy__row {
      grid-template-columns: minmax(0, 1fr) auto auto;
      gap: var(--s-6);
    }
  }
  & .buy__name {
    font-family: var(--font-display);
    font-size: var(--t-h3);
    font-weight: 600;
    margin: 0;
  }
  /* Everything in the buying door is purchase path: body sized, and
     paper-quiet was retuned to 7.13:1 on the board for exactly this. */
  & .buy__price { margin: 0; color: var(--quiet); }
  & .buy__price .slot { color: var(--accent); }
  & .buy__terms {
    margin: clamp(var(--s-6), 4vw, var(--s-7)) 0 0;
    max-width: 40rem;
    color: var(--quiet);
  }

  /* the hero's two actions again, proof beside them, closing the page the
     way it opened. */
  & .buy__again {
    margin: clamp(var(--s-6), 4vw, var(--s-7)) 0 0;
    padding-top: var(--s-6);
    border-top: var(--hair) solid var(--rule);
  }
  & .buy__proof { margin: 0; color: var(--fg); }
  & .buy__acts {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--s-4);
    margin-top: var(--s-5);
  }
}

/* ==================== colophon: short, operational ====================== */
.colophon {
  border-top: var(--hair) solid var(--rule);
  padding-block: clamp(var(--s-7), 7vh, var(--s-8));
  font-size: var(--t-small);

  & .colophon__in {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--s-5) var(--s-6);
  }
  & nav { display: flex; flex-wrap: wrap; gap: var(--s-5); }
  & a {
    color: var(--ink);
    text-decoration: none;
    border-bottom: var(--hair) solid var(--rule-strong);
    /* grown target, same device as the mast links: 44px reachable, text
       unchanged */
    position: relative;
  }
  & a::after { content: ""; position: absolute; inset: -0.8rem -0.3rem; }
  & a:hover { color: var(--accent); border-color: var(--accent); }
  & .quiet { color: var(--quiet); font-size: var(--t-micro); }
  & .quiet a { color: var(--quiet); border-bottom-color: var(--rule); }
  & .meter { margin: var(--s-6) 0 0; color: var(--quiet); font-size: var(--t-micro); }
}

/* ==================== banner: interior pages ============================ */
.banner {
  padding-top: clamp(3rem, 8vh, 5.5rem);
  padding-bottom: clamp(2.5rem, 6vh, 4rem);
  border-bottom: var(--hair) solid var(--rule);
}
.crumbs { font-size: var(--t-micro); color: var(--quiet); margin: 0 0 var(--s-5); }
.crumbs a { color: var(--quiet); }

/* ==================== work index ======================================== */
.shelf { margin-top: clamp(var(--s-6), 5vw, var(--s-8)); }
.shelf__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-4);
  padding-bottom: var(--s-3);
  border-bottom: var(--hair) solid var(--rule-strong);
}
.shelf__head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--t-h3);
  font-weight: 600;
}
.shelf__count { font-size: var(--t-micro); color: var(--quiet); }
.shelf ol { list-style: none; margin: 0; padding: 0; }
.shelf li { border-bottom: var(--hair) solid var(--rule); }
.row {
  display: grid;
  gap: var(--s-1) var(--s-5);
  align-items: baseline;
  padding: var(--s-5) 0;
  text-decoration: none;
  color: var(--ink);
  transition: color var(--dur-fast) ease, padding-left var(--dur-fast) ease;
}
@media (min-width: 44em) {
  .row { grid-template-columns: minmax(0, 15rem) minmax(0, 1fr) auto; }
}
.row:hover { color: var(--accent); padding-left: var(--s-3); }
.row__name { font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; }
.row__what { color: var(--quiet); font-size: var(--t-small); }
.row:hover .row__what { color: inherit; }
.row__go { font-size: var(--t-micro); color: var(--quiet); white-space: nowrap; }
.row:hover .row__go { color: inherit; }

/* ==================== 404 =============================================== */
.lost { padding-block: clamp(5rem, 16vh, 9rem); }
.lost .h1 { max-width: 18ch; }
.lost__acts { display: flex; flex-wrap: wrap; gap: var(--s-4); margin-top: var(--s-7); }

/* ---------------------------------------------------- stagger steps ----
   Written as attributes rather than inline style attributes, so style-src
   in _headers can stay 'self' with no 'unsafe-inline' anywhere on the site. */
[data-d="0"] { --d: 0; }
[data-d="1"] { --d: 1; }
[data-d="2"] { --d: 2; }
[data-d="3"] { --d: 3; }
[data-d="4"] { --d: 4; }

.mt-4 { margin: var(--s-4) 0 var(--s-2); }
.mt-7 { margin-top: var(--s-7); }

#slip-outcome pre {
  margin: var(--s-4) 0 0;
  padding: var(--s-4);
  background: var(--paper-2);
  font-family: var(--font-text);
  font-size: var(--t-micro);
  line-height: 1.6;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
#slip-outcome pre:empty { display: none; }
#slip-outcome .btn { margin-top: var(--s-4); }

/* ---------------------------------------------------------------- the name --
   CARVERPOINT, set the way the logo sets it: one word, two tones, the second
   half carrying the accent. The wordmark is type, not an image file, so it
   stays crisp at every size, inverts on the dark band without a second asset,
   and costs no bytes. .wm-b takes the accent from the token, which is the
   whole reason the palette can be changed in one place. */
.wm-a { color: inherit; }
.wm-b { color: var(--brand-orange); }
