/* ==========================================================================
   Uncommun Logic — site stylesheet
   Built on Brand guidelines v1.0 (9 August 2026).
   Three colours: oxblood, ink, paper. One family: Archivo. One companion:
   JetBrains Mono. One easing curve. Nothing bounces.
   ========================================================================== */

/* ---------- 01 Fonts ---------------------------------------------------- */

@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/Archivo-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Archivo';
  src: url('/assets/fonts/Archivo-SemiBold.woff2') format('woff2');
  font-weight: 600; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'Archivo Expanded';
  src: url('/assets/fonts/Archivo-ExpandedBlack.woff2') format('woff2');
  font-weight: 900; font-style: normal; font-display: swap;
}
@font-face {
  font-family: 'JetBrains Mono';
  src: url('/assets/fonts/JetBrainsMono-Regular.woff2') format('woff2');
  font-weight: 400; font-style: normal; font-display: swap;
}

/* ---------- 02 Tokens --------------------------------------------------- */

:root {
  /* palette, brand guidelines s07 */
  --ox:        #7A1220;
  --ox-deep:   #4E0B15;
  --ox-pale:   #EFDCDE;
  --ink:       #0A0A0A;
  --g70:       #57534C;
  --g40:       #9A958C;
  --g15:       #DDD8CE;
  --paper:     #F4F1EA;

  /* surface roles. Reassigned inside .on-ink. */
  --ground:    var(--paper);
  --text:      var(--ink);
  --text-2:    var(--g70);
  --rule:      var(--g15);
  --rule-soft: rgba(10, 10, 10, .09);
  --accent:    var(--ox);

  /* type */
  --display:   'Archivo Expanded', 'Archivo', system-ui, sans-serif;
  --sans:      'Archivo', system-ui, -apple-system, sans-serif;
  --mono:      'JetBrains Mono', ui-monospace, 'SFMono-Regular', monospace;

  --d1: clamp(2.25rem, 8.4vw, 6.75rem);
  --d2: clamp(2rem, 4.6vw, 3.5rem);
  --d3: clamp(1.5rem, 2.5vw, 2.125rem);
  --h1: clamp(1.125rem, 1.5vw, 1.3125rem);
  --body: 1.0625rem;
  --small: 0.875rem;
  --label: 0.6875rem;

  /* grid, brand guidelines s11 */
  --gutter: 1.5rem;
  --margin: clamp(1.25rem, 5vw, 3.5rem);
  --maxw: 82.5rem;
  --measure: 70ch;

  /* what a data panel becomes under the pointer */
  --hi: var(--ox);

  /* rhythm */
  --s1: .5rem;  --s2: 1rem;   --s3: 1.5rem;  --s4: 2.5rem;
  --s5: 4rem;   --s6: 6rem;   --s7: 9rem;

  /* motion. One curve, s10. Four durations, and which one to use is not a
     matter of taste: anything a visitor triggers themselves has to answer
     inside 250ms or it reads as lag rather than as motion. Scroll-driven and
     narrative motion is allowed to take its time. */
  --ease: cubic-bezier(.16, 1, .3, 1);
  --t-press: .12s;   /* a press answering */
  --t-ui: .2s;       /* hover, focus, toggles: anything they aim at */
  --t-fast: .28s;    /* small state changes */
  --t: .6s;          /* reveals */
  --t-slow: 1.1s;    /* the display statement arriving */

  --header-h: 4.5rem;
}

/* The oxblood surface. Used once per page at most, on the single thing that
   page most wants said. Paper on oxblood measures 9.56:1, so unlike oxblood
   on ink it carries type perfectly well. What it cannot carry is more
   oxblood, so the accent inverts to paper here. */
.on-ox {
  --ground:    var(--ox);
  --text:      var(--paper);
  --text-2:    rgba(244, 241, 234, .82);
  --rule:      rgba(244, 241, 234, .26);
  --rule-soft: rgba(244, 241, 234, .14);
  --accent:    var(--paper);
  /* the colour a panel takes when the pointer is on it */
  --hi:        var(--ink);
  color-scheme: dark;
}

/* Dark surfaces. Text becomes paper. Oxblood survives only as a solid
   graphic shape, never as text: 1.82:1 on ink. Brand guidelines s07. */
.on-ink {
  --ground:    var(--ink);
  --text:      var(--paper);
  /* .78 not .68: measured so secondary text still clears AA when the
     reinforced motif sits behind it. It also reads better on the bands. */
  --text-2:    rgba(244, 241, 234, .78);
  --rule:      rgba(244, 241, 234, .18);
  --rule-soft: rgba(244, 241, 234, .10);
  --hi:        var(--ox);
  color-scheme: dark;
}

/* ---------- 03 Reset --------------------------------------------------- */

*, *::before, *::after { box-sizing: border-box; }
html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-h) + 1rem);
}
body {
  margin: 0;
  -webkit-tap-highlight-color: rgba(122, 18, 32, .18);
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: var(--body);
  line-height: 1.62;
  font-synthesis-weight: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img, svg, video { display: block; max-width: 100%; height: auto; }
/* Author display rules beat the user-agent [hidden] rule, so restate it.
   Without this, any hidden block with a display declaration shows up. */
[hidden] { display: none !important; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
/* Removes the 300ms tap delay without disabling pinch zoom. */
a, button, .chip, .leaf, .branch, summary { touch-action: manipulation; }
a { color: inherit; }
h1, h2, h3, h4, p, ul, ol, figure, blockquote { margin: 0; }
ul, ol { padding: 0; list-style: none; }
table { border-collapse: collapse; width: 100%; }
:target { scroll-margin-top: calc(var(--header-h) + 2rem); }

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

:focus-visible {
  outline: 2px solid var(--ox);
  outline-offset: 3px;
}
.on-ink :focus-visible, .on-ox :focus-visible { outline-color: var(--paper); }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 999;
  background: var(--ink); color: var(--paper);
  padding: .75rem 1.25rem; font-family: var(--mono); font-size: var(--label);
  letter-spacing: .14em; text-transform: uppercase; text-decoration: none;
}
.skip:focus { left: 0; }

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

/* ---------- 04 Type ---------------------------------------------------- */

.d1, .d2, .d3 {
  font-family: var(--display);
  font-weight: 900;
  text-transform: uppercase;
  text-wrap: balance;
}
.d1 { font-size: var(--d1); line-height: .92; letter-spacing: -.02em; }
.d2 { font-size: var(--d2); line-height: .94; letter-spacing: -.015em; }
.d3 { font-size: var(--d3); line-height: 1;   letter-spacing: -.012em; }

.h { font-size: var(--h1); font-weight: 600; line-height: 1.3; letter-spacing: -.005em; }

.label {
  font-family: var(--mono); font-size: var(--label); font-weight: 400;
  line-height: 1; letter-spacing: .14em; text-transform: uppercase;
  color: var(--text-2);
}
.mono { font-family: var(--mono); font-variant-numeric: tabular-nums; }
.lead { font-size: clamp(1.125rem, 1.8vw, 1.375rem); line-height: 1.5; }
.small { font-size: var(--small); line-height: 1.55; color: var(--text-2); }
.measure { max-width: var(--measure); }
.measure-tight { max-width: 46ch; }

/* The substituted U carries the accent wherever colour exists. Brand s02.
   Suppressed on ink grounds where the ratio is 1.82:1 and the lockup is
   already doing the work. */
.u { color: var(--ox); }
.on-ink .u { color: inherit; }

strong, b { font-weight: 600; }
em { font-style: normal; font-weight: 600; }

/* Prose links: underlined, oxblood on paper, paper on ink. */
.prose a, .link {
  color: var(--ox);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: .22em;
  transition: color var(--t-fast) var(--ease);
}
.prose a:hover, .link:hover { color: var(--ox-deep); }
.on-ink .prose a, .on-ink .link { color: var(--paper); }
.on-ink .prose a:hover, .on-ink .link:hover { color: var(--text-2); }

.prose > * + * { margin-top: 1.15em; }
.prose h2 {
  font-family: var(--display); font-weight: 900; text-transform: uppercase;
  font-size: var(--d3); line-height: 1; letter-spacing: -.012em;
  margin-top: 2.5em; margin-bottom: .1em;
}
.prose h3 { font-size: var(--h1); font-weight: 600; margin-top: 2em; }
.prose ul { margin-left: 0; }
.prose ul li {
  position: relative; padding-left: 1.6rem; margin-top: .5em;
}
.prose ul li::before {
  content: ''; position: absolute; left: 0; top: .72em;
  width: .5rem; height: .5rem; background: var(--ox);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.prose ol { counter-reset: n; }
.prose ol li {
  counter-increment: n; position: relative; padding-left: 2.4rem; margin-top: .5em;
}
.prose ol li::before {
  content: counter(n, decimal-leading-zero);
  position: absolute; left: 0; top: .28em;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .1em;
  color: var(--ox);
}
.on-ink .prose ol li::before { color: var(--text-2); }
.prose blockquote {
  border-left: 2px solid var(--ox);
  padding-left: 1.25rem;
  font-size: clamp(1.125rem, 1.7vw, 1.3125rem); line-height: 1.45;
}
.prose table { margin: 2rem 0; font-size: var(--small); }
.prose th, .prose td {
  text-align: left; padding: .7rem .9rem; border-bottom: 1px solid var(--rule);
  vertical-align: top;
}
.prose th {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
  border-bottom: 1px solid var(--text);
}
.prose code {
  font-family: var(--mono); font-size: .9em;
  background: var(--ox-pale); padding: .1em .35em;
}
.on-ink .prose code { background: rgba(244, 241, 234, .12); }

/* ---------- 05 Layout -------------------------------------------------- */

.wrap {
  width: 100%; max-width: var(--maxw);
  margin-inline: auto; padding-inline: var(--margin);
}
.section { padding-block: clamp(4rem, 9vw, var(--s7)); }
.section-tight { padding-block: clamp(3rem, 6vw, var(--s6)); }
.surface { background: var(--ground); color: var(--text); }

.grid { display: grid; gap: var(--gutter); grid-template-columns: repeat(12, 1fr); }
.col-4  { grid-column: span 4; }
.col-5  { grid-column: span 5; }
.col-6  { grid-column: span 6; }
.col-7  { grid-column: span 7; }
.col-8  { grid-column: span 8; }
.col-12 { grid-column: span 12; }

@media (max-width: 60rem) {
  .col-4, .col-5, .col-6, .col-7, .col-8 { grid-column: span 12; }
}

.stack > * + * { margin-top: var(--s3); }
.stack-lg > * + * { margin-top: var(--s4); }

/* Section head: mono label above a display line, brand rule underneath. */
.shead { display: grid; gap: var(--s2); margin-bottom: var(--s4); }
.shead .label { display: flex; align-items: center; gap: .6rem; }
.shead .label::before {
  content: ''; width: 1.75rem; height: 1px; background: var(--ox); flex: none;
}
.on-ink .shead .label::before { background: var(--text-2); }

.hrule { height: 1px; background: var(--rule); border: 0; margin: 0; }

/* ---------- 06 Buttons ------------------------------------------------- */

.btn {
  --btn-bg: var(--ink);
  --btn-fg: var(--paper);
  position: relative; display: inline-flex; align-items: center; gap: .7rem;
  padding: 1rem 1.5rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; text-decoration: none;
  color: var(--btn-fg); background: var(--btn-bg);
  border: 1px solid var(--btn-bg);
  overflow: hidden; isolation: isolate;
  transition: color var(--t-ui) var(--ease), border-color var(--t-ui) var(--ease),
              transform var(--t-press) var(--ease);
}
.btn > span { position: relative; z-index: 1; }
.btn::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: var(--ox);
  transform: translateY(101%);
  transition: transform var(--t-ui) var(--ease);
}
.btn:hover::after, .btn:focus-visible::after { transform: translateY(0); }

/* Press feedback. Nothing in the physical world answers a push by staying
   exactly where it was. Two per cent and 120ms: felt, never noticed. */
.btn:active { transform: scale(.98); }
.btn:hover, .btn:focus-visible { color: var(--paper); border-color: var(--ox); }

.btn-accent { --btn-bg: var(--ox); }
.btn-accent::after { background: var(--ink); }
.btn-accent:hover, .btn-accent:focus-visible { border-color: var(--ink); }

.btn-ghost { --btn-bg: transparent; --btn-fg: var(--text); border-color: var(--text); }
.btn-ghost:hover, .btn-ghost:focus-visible { color: var(--paper); }
.on-ink .btn-ghost::after { background: var(--paper); }
.on-ink .btn-ghost:hover, .on-ink .btn-ghost:focus-visible {
  color: var(--ink); border-color: var(--paper);
}
/* On oxblood the ghost button fills with paper and its label becomes the
   band it is sitting on. */
.on-ox .btn-ghost { border-color: var(--paper); --btn-fg: var(--paper); }
.on-ox .btn-ghost::after { background: var(--paper); }
.on-ox .btn-ghost:hover, .on-ox .btn-ghost:focus-visible {
  color: var(--ox); border-color: var(--paper);
}

/* The gate glyph that follows every forward action. */
.btn .gate {
  position: relative; z-index: 1; width: .7rem; height: .55rem; flex: none;
  transition: transform var(--t-ui) var(--ease);
}
.btn:hover .gate { transform: translateX(.25rem); }

.cta-row { display: flex; flex-wrap: wrap; gap: var(--s2); align-items: center; }

/* ---------- 07 Header -------------------------------------------------- */

.progress {
  position: fixed; inset-inline: 0; top: 0; height: 2px; z-index: 60;
  background: transparent; pointer-events: none;
}
.progress i {
  display: block; height: 100%; width: 100%; background: var(--ox);
  transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
}

.header {
  position: fixed; inset-inline: 0; top: 0; z-index: 50;
  height: var(--header-h);
  display: flex; align-items: center;
  background: var(--paper);
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-ui) var(--ease), background var(--t-ui) var(--ease),
              transform .34s var(--ease);
}
.header.is-stuck { border-bottom-color: var(--g15); }
.header.is-hidden { transform: translateY(-100%); }
.header .wrap { display: flex; align-items: center; gap: var(--s3); }

.brand { display: flex; align-items: center; text-decoration: none; flex: none; }
.brand img { height: 1.5rem; width: auto; }

.nav { display: flex; align-items: center; gap: clamp(.5rem, 1.6vw, 1.5rem); margin-left: auto; }
.nav a:not(.btn) {
  position: relative; text-decoration: none; padding: .4rem 0;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--ink); white-space: nowrap;
}
.nav a:not(.btn)::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 1px; width: 100%;
  background: currentColor; transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--t-ui) var(--ease);
}
.nav a:not(.btn):hover::after,
.nav a:not(.btn):focus-visible::after { transform: scaleX(1); }
.nav a:not(.btn)[aria-current='page'] { color: var(--ox); }
.nav a:not(.btn)[aria-current='page']::after { background: var(--ox); transform: scaleX(1); }
.nav .btn { padding: .7rem 1.1rem; }

.burger {
  display: none; margin-left: auto; width: 2.75rem; height: 2.75rem;
  align-items: center; justify-content: center;
}
.burger i {
  display: block; position: relative; width: 1.25rem; height: 1px; background: var(--ink);
  transition: background var(--t-fast) var(--ease);
}
.burger i::before, .burger i::after {
  content: ''; position: absolute; left: 0; width: 100%; height: 1px; background: var(--ink);
  transition: transform var(--t) var(--ease);
}
.burger i::before { top: -.3rem; }
.burger i::after  { top: .3rem; }
.burger[aria-expanded='true'] i { background: transparent; }
.burger[aria-expanded='true'] i::before { transform: translateY(.3rem) rotate(45deg); }
.burger[aria-expanded='true'] i::after  { transform: translateY(-.3rem) rotate(-45deg); }

.drawer {
  position: fixed; inset: 0; z-index: 45;
  background: var(--ink); color: var(--paper);
  padding: calc(var(--header-h) + 2rem) var(--margin) 2rem;
  display: grid; align-content: start; gap: .25rem;
  clip-path: inset(0 0 100% 0);
  transition: clip-path var(--t-slow) var(--ease);
  overflow-y: auto;
}
.drawer.is-open { clip-path: inset(0 0 0 0); }
/* BUG: clip-path and transform hide pixels only. A closed drawer kept ten
   links in the tab order, focused behind the clip, ring drawn then clipped
   away. visibility removes them from the tab order and the a11y tree. */
.drawer:not(.is-open) { visibility: hidden; }
.drawer { transition: clip-path var(--t-slow) var(--ease), visibility 0s linear var(--t-slow); }
.drawer.is-open { transition: clip-path var(--t-slow) var(--ease), visibility 0s; }
/* Direct children only. As a descendant selector this beat .small on the
   contact links in the foot, rendering an email address in 31px display
   type and pushing it 615px off screen. */
.drawer > a {
  font-family: var(--display); font-weight: 900; text-transform: uppercase;
  font-size: clamp(1.75rem, 8vw, 3rem); line-height: 1.06; letter-spacing: -.015em;
  text-decoration: none; padding-block: .3rem;
  opacity: 0; transform: translateY(1.2rem);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
.drawer.is-open > a { opacity: 1; transform: none; }
.drawer.is-open > a:nth-child(1) { transition-delay: .10s; }
.drawer.is-open > a:nth-child(2) { transition-delay: .16s; }
.drawer.is-open > a:nth-child(3) { transition-delay: .22s; }
.drawer.is-open > a:nth-child(4) { transition-delay: .28s; }
.drawer.is-open > a:nth-child(5) { transition-delay: .34s; }
.drawer.is-open > a:nth-child(6) { transition-delay: .40s; }
.drawer.is-open > a:nth-child(7) { transition-delay: .46s; }
.drawer > a:hover { color: var(--text-2); }
.drawer-foot { margin-top: var(--s4); display: grid; gap: .75rem; justify-items: start; }
/* An email address is one long unbreakable token. Let it break rather than
   let it decide the width of the panel. */
.drawer-foot a { overflow-wrap: anywhere; max-width: 100%; }

@media (max-width: 62rem) {
  .nav { display: none; }
  .burger { display: flex; }
}
@media (min-width: 62.01rem) {
  .drawer { display: none; }
}

body.is-locked { overflow: hidden; }

/* Everything else that gets pressed, on the same two values. Buttons carry
   their own transition; these need one adding. */
.burger, .dock-menu, .dock-cta, .lg-opt, .chip, .lg-more, .lg-chosen {
  transition: transform var(--t-press) var(--ease), color var(--t-ui) var(--ease),
              border-color var(--t-ui) var(--ease), background var(--t-ui) var(--ease);
}
.burger:active, .dock-menu:active, .dock-cta:active,
.lg-opt:active, .chip:active, .lg-more:active, .lg-chosen:active {
  transform: scale(.98);
}
/* A full-width bar scaling by 2% looks like it shrank. Half of it, and from
   the edge it is anchored to. */
.dock-menu:active, .dock-cta:active { transform: scale(.99); }

/* ---------- 07b The dock ------------------------------------------ */

/* On a phone the header hides on scroll down and the desktop nav is display:
   none, so for ten to sixteen screens there was nothing to tap and no way to
   navigate. This is fixed to the bottom, where the thumb is, and it is the
   only always-available control on the site. */
.dock { display: none; }

@media (max-width: 62rem) {
  .dock {
    position: fixed; inset-inline: 0; bottom: 0; z-index: 48;
    display: grid; grid-template-columns: auto 1fr;
    gap: 1px; background: var(--g15);
    border-top: 1px solid var(--g15);
    padding-bottom: env(safe-area-inset-bottom, 0);
  }
  .dock-menu, .dock-cta {
    min-height: 3.5rem; display: flex; align-items: center; justify-content: center;
    gap: .6rem; text-decoration: none;
    font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
    text-transform: uppercase;
  }
  .dock-menu { background: var(--paper); color: var(--ink); padding-inline: 1.2rem; }
  .dock-cta { background: var(--ox); color: var(--paper); padding-inline: 1.2rem; }
  .dock-menu span, .dock-cta span { white-space: nowrap; }
  /* The gate is sized by ".btn .gate". The dock CTA is not a .btn, so without
     this the SVG expanded to 185px and dragged the bar to 139px tall. */
  .dock .gate { width: .7rem; height: .55rem; flex: none; }
  .dock-menu i {
    position: relative; width: 1rem; height: 1px; background: currentColor;
  }
  .dock-menu i::before, .dock-menu i::after {
    content: ''; position: absolute; left: 0; width: 100%; height: 1px;
    background: currentColor;
  }
  .dock-menu i::before { top: -.28rem; }
  .dock-menu i::after { top: .28rem; }
  /* Room so the dock never covers the last line of a page. */
  body:has(.dock) { padding-bottom: 3.5rem; }
  /* The drawer covers the dock, so its own close control takes over. */
  .drawer.is-open ~ .dock { display: none; }
}

/* ---------- 08 Hero --------------------------------------------------- */

.hero {
  position: relative;
  min-height: min(100svh, 52rem);
  display: grid; align-items: end;
  padding-top: calc(var(--header-h) + 3rem);
  padding-bottom: clamp(2rem, 5vw, 4rem);
  background: var(--ink); color: var(--paper);
  overflow: hidden;
}
/* The pattern sits behind the text and never competes with it: brand s09.
   The mask clears it out of the headline block entirely. */
.hero-canvas {
  position: absolute; inset: 0; z-index: 0;
  width: 100%; height: 100%;
  mask-image: radial-gradient(125% 95% at 10% 46%,
    transparent 0%, transparent 40%, #000 82%);
  -webkit-mask-image: radial-gradient(125% 95% at 10% 46%,
    transparent 0%, transparent 40%, #000 82%);
}
.hero .wrap { position: relative; z-index: 1; }
/* Above the extruded mark, which is absolutely placed inside the same wrap. */
.hero-grid { position: relative; z-index: 1; }
.hero-grid { display: grid; gap: var(--s4); }
.hero-kicker { display: flex; align-items: center; gap: .75rem; }
/* One oxblood event per surface, brand s11. On the hero that event is the
   primary button, so this marker stays neutral. */
.hero-kicker .dot {
  width: .5rem; height: .5rem; background: var(--text-2); border-radius: 50%; flex: none;
}
/* Capped below Display 1's ceiling on purpose: at full size the statement
   pushes the primary action below the fold, and an unseen button is a
   button that does not exist. */
/* At 320px the old 2.25rem floor made "AUTOMATION" 319px wide in a 280px
   box, and overflow-x:hidden discarded the difference instead of reflowing.
   WCAG 1.4.10. */
.hero h1 { max-width: 22ch; font-size: clamp(1.875rem, 6.6vw, 5.25rem); overflow-wrap: break-word; }
.hero { grid-template-columns: minmax(0, 1fr); }
.hero-lead { max-width: 46ch; color: var(--text-2); }

/* Above 1200px the extruded mark occupies the right of the hero, so the
   headline is pulled in to keep clear of it: the two must not touch. */
@media (min-width: 75rem) {
  .hero h1 { max-width: 17ch; }
  .hero-lead { max-width: 40ch; }
}

.hero-foot {
  margin-top: var(--s4);
  display: flex; flex-wrap: wrap; gap: var(--s4) var(--s5);
  align-items: end; justify-content: space-between;
  padding-top: var(--s3); border-top: 1px solid var(--rule);
}
.hero-stats { display: flex; flex-wrap: wrap; gap: var(--s4); }
.hero-foot > .seq { flex: 1 1 100%; }
.stat { display: grid; gap: .35rem; }
.stat b {
  font-family: var(--display); font-weight: 900; font-size: clamp(1.75rem, 3.4vw, 2.75rem);
  line-height: 1; letter-spacing: -.02em;
}
.stat > span { font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2); }

.scroll-hint {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2); text-decoration: none;
}
.scroll-hint i {
  display: block; width: 1px; height: 2.5rem; background: var(--rule);
  position: relative; overflow: hidden;
}
.scroll-hint i::after {
  content: ''; position: absolute; inset-inline: 0; height: 40%;
  background: var(--paper);
  animation: railrun 2.4s var(--ease) infinite;
}
@keyframes railrun {
  0%   { transform: translateY(-100%); }
  100% { transform: translateY(250%); }
}

/* ---------- 09 Reveal engine ------------------------------------------ */

/* Line-mask reveal. The clip lives on the child so the parent keeps flow. */
[data-reveal] { --d: 0ms; }

/* Initial hidden states apply only when scripting can undo them. */

[data-reveal='mask'] > * { display: block; }
[data-reveal='mask'] .rl { display: block; overflow: hidden; }
:where(html.js) [data-reveal='mask'] .rl > span {
  display: block; transform: translateY(105%);
  transition: transform var(--t-slow) var(--ease);
  transition-delay: var(--d);
}
[data-reveal='mask'].in .rl > span { transform: translateY(0); }

:where(html.js) [data-reveal='up'] {
  opacity: 0; transform: translateY(1.75rem);
  transition: opacity var(--t) var(--ease), transform var(--t-slow) var(--ease);
  transition-delay: var(--d);
}
[data-reveal='up'].in { opacity: 1; transform: none; }

:where(html.js) [data-reveal='fade'] {
  opacity: 0; transition: opacity var(--t-slow) var(--ease); transition-delay: var(--d);
}
[data-reveal='fade'].in { opacity: 1; }

:where(html.js) [data-reveal='rule'] {
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform var(--t-slow) var(--ease); transition-delay: var(--d);
}
[data-reveal='rule'].in { transform: scaleX(1); }

:where(html.js) [data-reveal='wipe'] {
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--t-slow) var(--ease); transition-delay: var(--d);
}
[data-reveal='wipe'].in { clip-path: inset(0 0 0 0); }

/* Word reveal. Each word rises out of its own clip, staggered. Used on the
   one display statement per page, never on body copy: it is expensive to
   read a paragraph that arrives a word at a time. */
:where(html.js) [data-reveal='words'] .wd { display: inline-block; overflow: hidden; vertical-align: bottom; }
:where(html.js) [data-reveal='words'] .wd > i {
  display: inline-block; font-style: inherit;
  transform: translateY(105%);
  transition: transform 1s var(--ease);
}
[data-reveal='words'].in .wd > i { transform: none; }


/* An opt-in third dimension for section statements: each word stands up out
   of the page. Not used on the hero, where it would sit in front of the
   largest contentful paint. */
:where(html.js) [data-reveal='words'][data-3d] { perspective: 44rem; }
:where(html.js) [data-reveal='words'][data-3d] .wd { overflow: visible; }
:where(html.js) [data-reveal='words'][data-3d] .wd > i {
  opacity: 0;
  transform: rotateX(-84deg) translateY(.25em);
  transform-origin: 50% 100%;
  transition: transform 1.1s var(--ease), opacity .55s var(--ease);
}
[data-reveal='words'][data-3d].in .wd > i { opacity: 1; transform: none; }

/* A phrase inside a statement, kept whole and underscored once the line has
   landed. Written as <i data-hl> so that a visitor without scripting reads the
   same sentence, undecorated and un-italic. The rule is the brand's, drawn
   left to right on the shared curve, and it waits for the words rather than
   racing them. */
[data-hl] { font-style: normal; }
.wd.is-hl { position: relative; }
:where(html.js) .wd.is-hl::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: .02em;
  height: .075em; background: currentColor;
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .75s var(--ease);
}
[data-reveal='words'].in .wd.is-hl::after { transform: scaleX(1); transition-delay: .8s; }

/* Stagger: children animate in sequence. Delay set in CSS, not markup. */
:where(html.js) [data-stagger] > * {
  opacity: 0; transform: translateY(1.25rem);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
[data-stagger].in > * { opacity: 1; transform: none; }
[data-stagger].in > :nth-child(1) { transition-delay: .00s; }
[data-stagger].in > :nth-child(2) { transition-delay: .07s; }
[data-stagger].in > :nth-child(3) { transition-delay: .14s; }
[data-stagger].in > :nth-child(4) { transition-delay: .21s; }
[data-stagger].in > :nth-child(5) { transition-delay: .28s; }
[data-stagger].in > :nth-child(6) { transition-delay: .35s; }
[data-stagger].in > :nth-child(7) { transition-delay: .42s; }
[data-stagger].in > :nth-child(8) { transition-delay: .49s; }
[data-stagger].in > :nth-child(9) { transition-delay: .56s; }
[data-stagger].in > :nth-child(10) { transition-delay: .63s; }
[data-stagger].in > :nth-child(n+11) { transition-delay: .7s; }

/* ---------- 10 Intro (name device) ----------------------------------- */

/* Hidden unless scripting is available: a no-JS visitor must never meet a
   fixed overlay that nothing can dismiss. */
.intro { display: none; }
html.js:not([data-intro-skip]) .intro {
  position: fixed; inset: 0; z-index: 100;
  background: var(--ink); color: var(--paper);
  display: grid; place-items: center;
  transition: clip-path 1s var(--ease);
  clip-path: inset(0 0 0 0);
  cursor: pointer;
}
.intro.done { clip-path: inset(0 0 100% 0); pointer-events: none; }
.intro-skip {
  position: absolute; bottom: 2rem; right: var(--margin);
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: rgba(244, 241, 234, .5);
}
html.intro-lock, html.intro-lock body { overflow: hidden; }

/* The name device. UNCOMMON is spelled correctly, the O leaves the word and
   becomes the ring of the mark, the U drops into the slot. Brand s02. */
.iv {
  display: flex; align-items: center; gap: .28em;
  font-family: var(--display); font-weight: 900; text-transform: uppercase;
  font-size: clamp(1.75rem, 7.2vw, 5rem); line-height: 1; letter-spacing: -.02em;
  position: relative;
}
.iv-word {
  display: inline-flex; align-items: baseline; opacity: 0;
  transition: opacity .4s var(--ease);
}
.iv-slot { position: relative; display: inline-block; }
.iv-o {
  display: inline-block;
  transition: transform .9s var(--ease), opacity .7s var(--ease);
}
.iv-u {
  position: absolute; left: 0; top: 0; color: var(--ox);
  opacity: 0; transform: translateY(-.5em);
  transition: transform .8s var(--ease), opacity .5s var(--ease);
}
.iv-mark {
  display: inline-flex; align-items: center; height: .72em; margin-left: .18em;
}
.iv-mark svg { height: 100%; width: auto; overflow: visible; }
.iv-tri {
  opacity: 0; transform: translateX(-1.4em);
  transition: transform .8s var(--ease), opacity .5s var(--ease);
}
.iv-ring {
  opacity: 0; transform: scale(.4);
  transform-origin: center;
  transition: transform .8s var(--ease), opacity .5s var(--ease);
}
.iv-rule {
  position: absolute; left: 0; right: 0; bottom: -1.1em; height: 2px;
  background: var(--paper);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .9s var(--ease);
}

/* ---------- 10c The gate device, reused --------------------------- */

/* The intro's closing beat, turned into a component: the triangle sweeps in,
   the ring lands in the slot the O left, the rule arrives last. Placed
   between major sections so the page keeps repeating the brand mechanism
   instead of decorating itself with something else. */
/* A flexed rule plus a fixed-size mark, rather than one stretched SVG: a
   stretched viewBox would distort the triangle and the ring, and the ring
   being a true circle is the whole point of it. */
.gate-rule {
  display: flex; align-items: center; gap: .85rem;
  width: 100%;
  /* No margin of its own: it sits between two sections that already carry
     generous padding, and adding to that left a void rather than a rhythm. */
  margin-block: 0;
}
.gate-rule .gr-line {
  flex: 1 1 auto; display: block; height: 1px; background: var(--rule);
}
.gate-rule .gr-mark {
  flex: none; width: 3.5rem; height: 1.5rem; color: var(--text);
  overflow: visible;
}
.gate-rule .gr-ring { stroke: var(--ox); }
.on-ink .gate-rule .gr-ring { stroke: var(--text-2); }

/* One gate walks the rule, forever, slowly. The track spans the rule and is
   what moves; the glyph is pinned to its leading edge and rides along, so a
   single transform of 100% carries it exactly one rule-width. The rule clips,
   which both hides the exit and stops the travelling track from reaching the
   document and producing sideways scroll. */
.gate-rule { position: relative; overflow: hidden; overflow: clip; }
.gr-track {
  position: absolute; left: 0; right: 4.4rem; top: 50%;
  height: 0; pointer-events: none;
  animation: gr-travel 19s cubic-bezier(.45, 0, .55, 1) infinite;
}
.gr-track::before {
  content: '';
  position: absolute; left: 0; top: -.22rem;
  width: .44rem; height: .44rem;
  background: var(--ox);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.on-ink .gr-track::before { background: var(--paper); }
@keyframes gr-travel {
  0%   { transform: translateX(0);    opacity: 0; }
  7%   { opacity: 1; }
  90%  { opacity: 1; }
  100% { transform: translateX(100%); opacity: 0; }
}

/* The footer rule carries the same traveller, so every page has one quiet
   thing still moving at the bottom of it. */
.footer .gate-rule { margin-bottom: var(--s4); }

.gate-rule .gr-line {
  transform: scaleX(0); transform-origin: 0 50%;
}
.gate-rule .gr-tri {
  opacity: 0; transform: translateX(-2.5rem);
}
.gate-rule .gr-ring {
  opacity: 0; transform: scale(.35);
  transform-origin: center;
  transform-box: fill-box;
}
:where(html.js) .gate-rule.in .gr-line {
  transform: scaleX(1);
  transition: transform 1.2s var(--ease);
}
:where(html.js) .gate-rule.in .gr-tri {
  opacity: 1; transform: none;
  transition: opacity .5s var(--ease) .32s, transform .9s var(--ease) .32s;
}
:where(html.js) .gate-rule.in .gr-ring {
  opacity: 1; transform: none;
  transition: opacity .4s var(--ease) .56s, transform .8s var(--ease) .56s;
}
:where(html:not(.js)) .gate-rule .gr-line { transform: none; }
:where(html:not(.js)) .gate-rule .gr-tri,
:where(html:not(.js)) .gate-rule .gr-ring { opacity: 1; transform: none; }

/* Section heads get the same gesture in miniature: the rule draws, then the
   ring lands after the label, the way the mark follows the wordmark. */
:where(html.js) [data-reveal='head'] .label::before {
  transform: scaleX(0); transform-origin: 0 50%;
}
[data-reveal='head'] .label::before { transition: transform .9s var(--ease); }
[data-reveal='head'].in .label::before { transform: scaleX(1); }

[data-reveal='head'] .label::after {
  content: ''; width: .5rem; height: .5rem; flex: none;
  border: 1px solid var(--ox); border-radius: 50%;
  margin-left: .1rem;
}
.on-ink [data-reveal='head'] .label::after { border-color: var(--text-2); }
:where(html.js) [data-reveal='head'] .label::after {
  opacity: 0; transform: scale(.3);
  transition: opacity .45s var(--ease) .5s, transform .75s var(--ease) .5s;
}
[data-reveal='head'].in .label::after { opacity: 1; transform: none; }

/* ---------- 10b Cross-document page transitions --------------------- */

@view-transition { navigation: auto; }

/* The new page wipes up from the bottom, which is the intro's exit gesture
   run backwards. Chrome and Edge honour this; everywhere else the default
   cross-fade applies and nothing is lost. */
@media (prefers-reduced-motion: no-preference) {
  ::view-transition-old(root) {
    animation: vt-out .4s cubic-bezier(.16, 1, .3, 1) both;
  }
  ::view-transition-new(root) {
    animation: vt-in .62s cubic-bezier(.16, 1, .3, 1) both;
  }
  @keyframes vt-out {
    to { opacity: 0; transform: translateY(-1.2%); }
  }
  @keyframes vt-in {
    from { clip-path: inset(100% 0 0 0); }
    to { clip-path: inset(0 0 0 0); }
  }
}

/* ---------- 11 Cards ------------------------------------------------- */

.cards { display: grid; gap: 1px; background: var(--rule); }
.cards-3 { grid-template-columns: repeat(3, 1fr); }
.cards-4 { grid-template-columns: repeat(4, 1fr); }
.cards-2 { grid-template-columns: repeat(2, 1fr); }
@media (max-width: 68rem) { .cards-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 56rem) {
  .cards-3, .cards-4, .cards-2 { grid-template-columns: 1fr; }
}

.card {
  background: var(--ground);
  padding: clamp(1.5rem, 2.6vw, 2.25rem);
  display: grid; gap: var(--s2); align-content: start;
  position: relative; isolation: isolate;
  transition: background var(--t) var(--ease);
}
.card > * { position: relative; z-index: 1; }
.card .num {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em; color: var(--ox);
}
.on-ink .card .num { color: var(--text-2); }
.card p { color: var(--text-2); }
.card img.picto { width: 2.25rem; height: 2.25rem; }

a.card { text-decoration: none; }
.card-go {
  margin-top: .4rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--ox);
  display: inline-flex; align-items: center; gap: .45rem;
}
.card-go::after {
  content: ''; width: .55rem; height: .45rem; flex: none;
  background: var(--ox);
  clip-path: polygon(0 0, 100% 50%, 0 100%);
  transition: transform var(--t) var(--ease);
}
a.card:hover .card-go::after,
a.card:focus-visible .card-go::after { transform: translateX(.3rem); }
.on-ink .card-go { color: var(--paper); }
.on-ink .card-go::after { background: var(--paper); }
.card { transition: background var(--t) var(--ease), transform var(--t) var(--ease); }
.card:hover, .card:focus-within { transform: translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .card:hover { transform: none; } }
a.card::after {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: var(--ox-pale); opacity: 0;
  transition: opacity var(--t) var(--ease);
}
a.card:hover::after, a.card:focus-visible::after { opacity: 1; }
.on-ink a.card::after { background: rgba(244, 241, 234, .06); }

/* ---------- 12 Process scrub ---------------------------------------- */

.scrub { position: relative; }
/* A sticky progress rail. It sits on an opaque band so it reads as chrome
   rather than as a stray line crossing the text underneath it. */
.scrub-rail {
  position: sticky; top: var(--header-h); z-index: 3;
  padding-block: 1.25rem; background: var(--ground);
  margin-bottom: var(--s3);
}
.scrub-rail i {
  display: block; height: 1px; background: var(--rule); position: relative;
}
.scrub-rail i::after {
  content: ''; position: absolute; inset: 0; background: var(--ox);
  transform: scaleX(var(--p, 0)); transform-origin: 0 50%;
}
.on-ink .scrub-rail i::after { background: var(--paper); }

.step {
  display: grid; grid-template-columns: 6rem 1fr; gap: var(--s3) var(--s4);
  padding-block: clamp(2rem, 5vw, 3.5rem);
  border-top: 1px solid var(--rule);
  align-items: start;
}
.step:last-child { border-bottom: 1px solid var(--rule); }
.step-n {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.5rem, 5vw, 4rem); line-height: .85; letter-spacing: -.03em;
  color: var(--text);
  transition: color var(--t-slow) var(--ease), clip-path .8s var(--ease);
}
/* The numeral is printed downwards as the rail reaches it, rather than fading
   up like everything else on the site. Four steps, four numbers, one gesture
   that belongs to this page and to nowhere else. */
:where(html.js) .step-n { color: var(--rule); clip-path: inset(0 0 100% 0); }
.step.in .step-n { color: var(--text); clip-path: inset(0 0 0 0); }

/* The facts under each step arrive after its numeral, left to right, so the
   eye reads the number then the terms. */
:where(html.js) .step-meta span {
  opacity: 0; transform: translateX(-.5rem);
  transition: opacity var(--t) var(--ease), transform var(--t) var(--ease);
}
.step.in .step-meta span { opacity: 1; transform: none; }
.step.in .step-meta span:nth-child(1) { transition-delay: .34s; }
.step.in .step-meta span:nth-child(2) { transition-delay: .42s; }
.step.in .step-meta span:nth-child(3) { transition-delay: .5s; }
.step-body { display: grid; gap: var(--s2); max-width: 58ch; }
.step-meta {
  display: flex; flex-wrap: wrap; gap: 1.25rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
  padding-top: .5rem;
}
.step-meta b { color: var(--text); font-weight: 400; }
@media (max-width: 48rem) {
  .step { grid-template-columns: 1fr; gap: var(--s2); }
}

/* ---------- 14 Marquee --------------------------------------------- */

.marquee {
  overflow: hidden; border-block: 1px solid var(--rule);
  padding-block: 1.1rem;
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}
.marquee-track {
  display: flex; gap: 3rem; width: max-content;
  animation: slide 42s linear infinite;
}
.marquee:hover .marquee-track { animation-play-state: paused; }
.marquee span {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2); white-space: nowrap;
  display: flex; align-items: center; gap: 3rem;
}
.marquee span::after {
  content: ''; width: .32rem; height: .32rem; background: var(--ox); flex: none;
  clip-path: polygon(0 0, 100% 50%, 0 100%);
}
.on-ink .marquee span::after { background: var(--text-2); }
@keyframes slide {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

/* ---------- 15 Pull quote / statement ------------------------------ */

.statement {
  background: var(--ground); color: var(--text);
  padding-block: clamp(4rem, 9vw, 8rem);
  position: relative; overflow: hidden;
}
.statement .wrap { position: relative; z-index: 1; }

/* Big dark bands keep a whisper of the pattern at rest and bring it forward
   on hover, rather than switching from nothing to something. */
/* Every full-width dark band carries the pattern at rest and brings it
   forward on hover. Scoped to section-level veils so a card sitting inside
   a dark band does not stack a second copy on top of the first. */
/* A single tile-width of travel, so the loop is seamless, over seventy
   seconds, which is about six pixels a second. It should read as the surface
   being alive rather than as something moving. Transform only, so it stays on
   the compositor, and the layer is oversized so no edge is ever exposed. */
/* The drifting layer is deliberately larger than its box so no edge is ever
   exposed mid-travel, which means the box has to clip it. Without this the
   overflow reached the document and produced 183px of sideways scroll. */
.statement.veil,
.section.on-ink.veil { overflow: hidden; overflow: clip; }
.statement.veil::before,
.section.on-ink.veil::before {
  opacity: .3;
  inset: -12%;
  transform: none;
  animation: motif-drift 70s linear infinite;
}
/* The drift carries the pointer offset inside its own keyframes. The two
   effects would otherwise fight: an animation beats a transition, so the
   pointer lean applied to the same pseudo-element was being discarded on
   exactly the panels where it matters most. Both live here now, and because
   --vx and --vy are read at each frame the field follows the pointer directly
   rather than trailing it. */
@keyframes motif-drift {
  from { transform: translate3d(calc(var(--vx) * 16px), calc(var(--vy) * 16px), 0); }
  to   { transform: translate3d(calc(var(--tile) * -1 + var(--vx) * 16px),
                                calc(var(--vy) * 16px), 0); }
}
.statement.veil:hover::before,
.statement.veil:focus-within::before,
.section.on-ink.veil:hover::before,
.section.on-ink.veil:focus-within::before { opacity: .6; }
.statement q { quotes: none; }

/* ---------- 16 Numbers / ROI ---------------------------------------- */

/* auto-fit, not four fixed tracks: with two children the old rule left two
   empty cells showing the section background, and squeezed the labels into
   one-word columns. */
.figures {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(auto-fit, minmax(10.5rem, 1fr));
  /* Fills the column beside the statement rather than floating at the top of
     it: two figures 160px tall next to a 600px headline read as an
     afterthought. The numbers still sit at the top of their own cells. */
  height: 100%;
}
.figure {
  background: var(--ground); padding: clamp(1.25rem, 2.4vw, 2rem);
  display: grid; gap: .5rem; align-content: start;
  transition: background var(--t-ui) var(--ease), color var(--t-ui) var(--ease);
}
/* The panel you are pointing at takes the other colour: oxblood on a dark
   band, ink on the oxblood one. It replaces the second copy of the motif that
   used to live here, which was a pattern fighting the pattern behind it. */
@media (hover: hover) and (pointer: fine) {
  .figure:hover { background: var(--hi); color: var(--paper); }
  .figure:hover > span, .figure:hover small { color: rgba(244, 241, 234, .82); }
}
.figure b {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2rem, 4.4vw, 3.25rem); line-height: .95; letter-spacing: -.025em;
}
.figure > span { font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2); }
.figure small { font-size: var(--small); color: var(--text-2); line-height: 1.4; }

/* The price band reads as a ceiling, so it is built as one: the rule is drawn
   across the top of each figure and the numeral rises until it meets it and
   stops. Nothing overshoots, which is the point of the rule it is hitting. */
.on-ox .figure { position: relative; overflow: hidden; }
.on-ox .figure::before {
  content: ''; position: absolute; inset-inline: 0; top: 0; height: 2px;
  background: var(--paper);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .8s var(--ease);
}
:where(html.js) .on-ox .figure b { display: block; transform: translateY(115%); }
.on-ox .figure b { transition: transform .9s var(--ease) .25s; }
.on-ox .figures.in .figure::before { transform: scaleX(1); }
.on-ox .figures.in .figure b { transform: none; }
.on-ox .figures.in .figure:nth-child(2)::before { transition-delay: .14s; }
.on-ox .figures.in .figure:nth-child(2) b { transition-delay: .39s; }
/* The label under a rising numeral waits for it. */
:where(html.js) .on-ox .figure > span { opacity: 0; transition: opacity var(--t) var(--ease) .6s; }
.on-ox .figures.in .figure > span { opacity: 1; }

/* ---------- 17 Solutions catalogue ---------------------------------- */

.filters {
  display: flex; flex-wrap: wrap; gap: .5rem; align-items: center;
  padding-block: var(--s3);
}
.chip {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase;
  padding: .55rem .85rem; border: 1px solid var(--rule); color: var(--text-2);
  transition: color var(--t-fast) var(--ease), border-color var(--t-fast) var(--ease),
              background var(--t-fast) var(--ease);
}
.chip:hover { color: var(--text); border-color: var(--text); }
.chip[aria-pressed='true'] {
  background: var(--ink); border-color: var(--ink); color: var(--paper);
}
.chip.chip-all[aria-pressed='true'] { background: var(--ox); border-color: var(--ox); }

.sol-meta {
  display: flex; flex-wrap: wrap; gap: 1.5rem; align-items: baseline;
  padding-block: var(--s2); border-top: 1px solid var(--rule);
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
}
.sol-meta b {
  font-family: var(--display); font-weight: 900; font-size: 1.5rem;
  letter-spacing: -.02em; color: var(--text);
}

/* ---------- 16b The number --------------------------------------- */

/* The site used to demonstrate one invoice being read. It was the wrong
   argument: a visitor does not need to watch a robot type, they need to know
   what the hour is worth. This is the same mechanism turned on the visitor's
   own figures. Two published sources, three inputs they control, and every
   step of the arithmetic printed underneath. Nothing here is an image. */

.calc { --p: 0; display: grid; gap: clamp(1.25rem, 3vw, 2rem); }
@media (min-width: 62rem) {
  /* Stretch, not start: the two boxes are a pair and a short one beside a
     tall one left a void under the figure. */
  .calc { grid-template-columns: minmax(0, 1.02fr) minmax(0, 1fr); align-items: stretch; }
}

/* ---- the result ---- */

.calc-out {
  border: 1px solid var(--ox);
  padding: clamp(1.1rem, 3vw, 2rem);
  display: grid; gap: .8rem; align-content: start;
}
.calc-out .label { color: var(--ox); }
.on-ink .calc-out { border-color: var(--rule); }
.on-ink .calc-out .label { color: var(--text-2); }

.calc-figure {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.25rem, 8.4vw, 4.5rem); line-height: 1;
  letter-spacing: -.035em;
  display: flex; align-items: center; min-height: 1.1em;
}
.calc-sub {
  font-family: var(--mono); font-size: var(--small); color: var(--text-2);
  line-height: 1.7;
}
.calc-sub b { color: var(--text); font-weight: 400; }

/* The ring reads the payback, not the money: full circle at one month. */
.calc-ring { display: flex; align-items: center; gap: .9rem; }
.calc-ring svg { width: 3rem; height: 3rem; flex: none; color: var(--ox); }
.on-ink .calc-ring svg { color: var(--text); }
.calc-arc { transition: stroke-dashoffset .8s var(--ease); }
.calc-ring p { font-family: var(--mono); font-size: var(--label);
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-2); }

/* ---- the odometer ---- */

/* One ten-sided drum per digit, turned on X. The cell clips, so only the face
   at the front is legible and its neighbours are caught mid-turn at the top
   and bottom edges, which is what makes it read as a solid object rather than
   as text being replaced.

   The drum is pushed back by exactly its own radius, so the front face lands
   at z = 0 and the perspective does not enlarge it past the dollar sign
   standing beside it. Radius for a ten-sided prism of side h is
   h / (2 tan 18deg) = 1.539h, and here h is one em.

   It always rolls forward: from 9 the drum climbs to 10 rather than winding
   back to 0. */
.odo { display: inline-flex; align-items: center; }
.odo-c { display: inline-block; }
.odo-d {
  position: relative; display: inline-block;
  width: 1ch; height: 1em;
  overflow: hidden;
  perspective: 9em;
}
.odo-r {
  position: absolute; inset: 0;
  transform-style: preserve-3d;
  transform: translateZ(-1.539em) rotateX(calc(var(--n, 0) * 36deg));
  /* Short on purpose. At a second the digits are unreadable soup for the whole
     drag, and a number nobody can read while they are changing it is worse
     than no animation. */
  transition: transform .45s var(--ease);
}
.odo-r > i {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  font-style: normal; backface-visibility: hidden;
}
.odo-r > i:nth-child(1)  { transform: rotateX(0deg)    translateZ(1.539em); }
.odo-r > i:nth-child(2)  { transform: rotateX(-36deg)  translateZ(1.539em); }
.odo-r > i:nth-child(3)  { transform: rotateX(-72deg)  translateZ(1.539em); }
.odo-r > i:nth-child(4)  { transform: rotateX(-108deg) translateZ(1.539em); }
.odo-r > i:nth-child(5)  { transform: rotateX(-144deg) translateZ(1.539em); }
.odo-r > i:nth-child(6)  { transform: rotateX(-180deg) translateZ(1.539em); }
.odo-r > i:nth-child(7)  { transform: rotateX(-216deg) translateZ(1.539em); }
.odo-r > i:nth-child(8)  { transform: rotateX(-252deg) translateZ(1.539em); }
.odo-r > i:nth-child(9)  { transform: rotateX(-288deg) translateZ(1.539em); }
.odo-r > i:nth-child(10) { transform: rotateX(-324deg) translateZ(1.539em); }

/* ---- the three inputs ---- */

.calc-in {
  display: grid; gap: 1px; background: var(--rule);
  border: 1px solid var(--rule);
}
/* Without scripting the sliders would move and change nothing, which is worse
   than not offering them. The result, the working and the sources are all
   static text and stay. */
html:not(.js) .calc-in { display: none; }
.calc-row {
  background: var(--ground); padding: clamp(.8rem, 2vw, 1.1rem);
  display: grid; gap: .35rem;
}
.calc-row .k {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2);
}
.calc-row .v {
  font-family: var(--display); font-weight: 900; font-size: 1.125rem;
  letter-spacing: -.02em; color: var(--text); white-space: nowrap;
}
.calc-row .n { font-size: var(--small); color: var(--text-2); line-height: 1.5; }

/* A native range: it already knows about keyboards, screen readers and
   fingers. Only the two parts a browser lets us touch are restyled, and the
   thumb is the mark rather than a circle. */
.calc-range {
  -webkit-appearance: none; appearance: none;
  width: 100%; height: 2.75rem; margin: 0;
  background: transparent; cursor: ew-resize;
}
.calc-range::-webkit-slider-runnable-track {
  height: 1px; background: var(--rule);
}
.calc-range::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none;
  width: 1.6rem; height: 1.15rem; margin-top: -.575rem;
  background: var(--ox); border: 0;
  clip-path: polygon(0 0, 100% 50%, 0 100%, 21% 50%);
}
.calc-range::-moz-range-track { height: 1px; background: var(--rule); }
.calc-range::-moz-range-thumb {
  width: 1.6rem; height: 1.15rem; border: 0; border-radius: 0;
  background: var(--ox);
  clip-path: polygon(0 0, 100% 50%, 0 100%, 21% 50%);
}
.on-ink .calc-range::-webkit-slider-thumb { background: var(--paper); }
.on-ink .calc-range::-moz-range-thumb { background: var(--paper); }
.calc-range:focus-visible { outline: 2px solid var(--ox); outline-offset: 2px; }

/* ---- the working, assembled by scrolling ---- */

/* --p comes from the scroll position of the block. Each term carries its own
   index and appears when the scroll passes it, so the sum builds left to
   right as it enters the screen and reads as arithmetic being done. */
.calc-work {
  grid-column: 1 / -1;
  border-top: 1px solid var(--rule); padding-top: 1rem;
  font-family: var(--mono); font-size: clamp(.6875rem, 1.9vw, .8125rem);
  display: flex; flex-wrap: wrap; align-items: baseline; gap: .15rem .55rem;
  line-height: 2.1; color: var(--text-2);
}
.calc-work .tm { display: inline-block; }
:where(html.js) .calc-work .tm {
  --i: 0;
  --q: max(0, min((var(--p) - var(--i) * .07) * 9, 1));
  opacity: var(--q);
  transform: translateY(calc((1 - var(--q)) * .5em));
}
.calc-work .tm:nth-child(2)  { --i: 1; }
.calc-work .tm:nth-child(3)  { --i: 2; }
.calc-work .tm:nth-child(4)  { --i: 3; }
.calc-work .tm:nth-child(5)  { --i: 4; }
.calc-work .tm:nth-child(6)  { --i: 5; }
.calc-work .tm:nth-child(7)  { --i: 6; }
.calc-work .tm:nth-child(8)  { --i: 7; }
.calc-work .tm:nth-child(9)  { --i: 8; }
.calc-work .tm:nth-child(10) { --i: 9; }
.calc-work .tm:nth-child(11) { --i: 10; }
.calc-work .tm:nth-child(12) { --i: 11; }
.calc-work .tm-v { color: var(--text); }
.calc-work .tm-r { color: var(--ox); }
.on-ink .calc-work .tm-r { color: var(--text); }

/* ---- where the figures come from ---- */

.calc-src {
  grid-column: 1 / -1;
  display: grid; gap: .7rem;
  font-size: var(--small); color: var(--text-2); line-height: 1.6;
}
/* Two columns once there is room: four short notes in one narrow column left
   half the block empty and pushed the last one well below the fold. */
@media (min-width: 62rem) {
  .calc-src { grid-template-columns: 1fr 1fr; gap: 1rem 2.5rem; }
}
.calc-src p { max-width: 62ch; }
.calc-src .tag {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ox); margin-right: .55rem;
  white-space: nowrap;
}
.on-ink .calc-src .tag { color: var(--text); }
.calc-src a { color: inherit; }

@media (max-width: 22.5rem) {
  .calc-figure { font-size: clamp(1.75rem, 11vw, 2.5rem); }
}

/* ---------- 16c The mark, extruded ------------------------------- */

/* Seven triangle plates and five rings on separate planes, turned by the
   scroll. It is the logo rather than a decoration, it costs one transform per
   frame, and it is not shown on phones: there is no pointer to answer and no
   room to spare. */
.mark3d { display: none; }
@media (min-width: 75rem) {
  .mark3d {
    --p: 0; --mx: 0; --my: 0;
    display: block; position: absolute; z-index: 0;
    right: -1.5rem; top: 50%; width: 18rem; height: 18rem;
    margin-top: -6rem;
    perspective: 62rem; pointer-events: none;
  }
  .m3 {
    position: absolute; inset: 0; transform-style: preserve-3d;
    transform:
      rotateX(calc((-6 + var(--my) * 9) * 1deg))
      rotateY(calc((-26 + var(--p) * 46 + var(--mx) * 18) * 1deg));
    transition: transform .34s var(--ease);
  }
  .m3-tri, .m3-ring { position: absolute; inset: 0; transform-style: preserve-3d; }
  .m3-tri > i, .m3-ring > i { position: absolute; display: block; }
  .m3-tri > i {
    left: 4%; top: 50%; width: 60%; height: 42%; margin-top: -21%;
    background: var(--paper);
    clip-path: polygon(0 0, 100% 50%, 0 100%, 19% 50%);
    transform: translateZ(var(--z, 0));
    opacity: var(--o, 1);
  }
  .m3-tri > i:nth-child(1) { --z: -72px; --o: .07; }
  .m3-tri > i:nth-child(2) { --z: -60px; --o: .09; }
  .m3-tri > i:nth-child(3) { --z: -48px; --o: .12; }
  .m3-tri > i:nth-child(4) { --z: -36px; --o: .16; }
  .m3-tri > i:nth-child(5) { --z: -24px; --o: .22; }
  .m3-tri > i:nth-child(6) { --z: -12px; --o: .34; }
  .m3-tri > i:nth-child(7) { --z: 0px;   --o: 1; }
  .m3-ring > i {
    right: 8%; top: 50%; width: 19%; height: 19%; margin-top: -9.5%;
    border: .62rem solid var(--ox); border-radius: 50%;
    background: none;
    transform: translateZ(var(--z, 0));
    opacity: var(--o, 1);
  }
  .m3-ring > i:nth-child(1) { --z: -48px; --o: .3; }
  .m3-ring > i:nth-child(2) { --z: -36px; --o: .45; }
  .m3-ring > i:nth-child(3) { --z: -24px; --o: .6; }
  .m3-ring > i:nth-child(4) { --z: -12px; --o: .8; }
  .m3-ring > i:nth-child(5) { --z: 0px;   --o: 1; }
}

/* ---------- 16d The gate on the scroll rail ---------------------- */

/* The mark rides the whole document on a hairline at the right edge, and
   inverts itself against whatever it is passing over: difference against
   paper reads black, against ink it reads paper. One element, no second
   colour scheme to maintain. */
.srail { display: none; }
@media (min-width: 62rem) {
  /* It used to invert itself with mix-blend-mode: difference, which is exact
     against ink and against paper and produces mint green against oxblood.
     Script tells it what it is passing over instead, so the mark only ever
     holds two of the three brand colours. */
  .srail {
    display: block;
    position: fixed; top: 0; bottom: 0; right: 1.4rem; width: 1px;
    z-index: 46; pointer-events: none;
    background: var(--g15);
    transition: background var(--t-ui) var(--ease);
  }
  .srail[data-on='dark'] { background: rgba(244, 241, 234, .22); }
  .srail > i {
    position: absolute; left: 0; top: 0; width: 1px;
    height: calc(var(--p, 0) * 100%);
    background: var(--ox);
  }
  .srail[data-on='dark'] > i { background: rgba(244, 241, 234, .5); }
  .srail-mark {
    position: absolute; left: 50%; top: calc(var(--p, 0) * 100%);
    width: 1.9rem; height: .82rem; margin-left: -.95rem; margin-top: -.41rem;
    color: var(--ink);
    transition: color var(--t-ui) var(--ease);
  }
  .srail[data-on='dark'] .srail-mark { color: var(--paper); }
  .srail-mark svg { width: 100%; height: 100%; overflow: visible; }
  .srail-tri { transform-box: fill-box; transform-origin: 50% 50%;
    transform: rotate(calc(var(--p, 0) * 360deg)); }
  .srail-ring { stroke: var(--ox); }
  .srail[data-on='dark'] .srail-ring { stroke: var(--paper); }
  /* At the foot of the document the ring fills: the gate has fired. It is a
     two-pixel reward for reading to the end, and it is the only state this
     rail has other than where it is. */
  .srail-ring { transition: fill var(--t) var(--ease); fill: transparent; }
  .srail[data-end] .srail-ring { fill: var(--ox); }
  .srail[data-end][data-on='dark'] .srail-ring { fill: var(--paper); }
}
@media print { .srail { display: none; } }

/* ---------- 16e Tilt -------------------------------------------- */

/* Four degrees, on a fine pointer only, and the transform is written by
   script so nothing here needs an inline style. */
:where(html.js) [data-tilt] { transition: transform .45s var(--ease); }
/* Tilt survives in one place: a photograph you can look slightly around. On a
   card or a figure it was decoration applied by the yard. */

/* ---------- 17 The gate ladder ----------------------------------- */

/* Three questions, one open at a time, answers collapsing to a single line.
   Sized so that on a 390px screen the current question and the top of the
   results are on the same screen: the tree it replaces put its answer 998px
   below the fold, which is why every tap felt broken. */

.ladder { display: grid; gap: var(--s3); }

.lg-steps { display: grid; gap: 1px; background: var(--rule); }
.lg-step { background: var(--ground); }

.lg-ask {
  display: flex; align-items: center; gap: .7rem;
  padding: 1rem .1rem .35rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text);
}
.lg-ask.is-waiting { color: var(--g40); padding-block: 1rem; }

.lg-gate { width: 1.3rem; height: .95rem; flex: none; }
.lg-gate .lg-tri { fill: var(--g40); transition: fill var(--t) var(--ease); }
.lg-gate .lg-ring { stroke: var(--g40); transition: stroke var(--t) var(--ease); }
/* The answer inverts the gate: the ring takes the accent, which is the whole
   device of the brand used as a state indicator. */
.lg-gate.is-on .lg-tri { fill: var(--text); }
.lg-gate.is-on .lg-ring { stroke: var(--ox); }
.on-ink .lg-gate.is-on .lg-ring { stroke: var(--paper); }

.lg-options {
  display: grid; gap: .5rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
  padding-bottom: 1rem;
}
.lg-opt {
  text-align: left; display: grid; gap: .15rem; align-content: center;
  min-height: 3.5rem; padding: .8rem .9rem;
  border: 1px solid var(--rule);
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.lg-opt:hover, .lg-opt:focus-visible { border-color: var(--text); background: var(--ox-pale); }
.lg-opt-l { font-weight: 600; font-size: 1rem; line-height: 1.25; }
.lg-opt-h {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-2);
}

.lg-chosen {
  width: 100%; text-align: left;
  display: grid; grid-template-columns: auto 1fr auto; gap: .7rem;
  align-items: center; padding: .9rem .1rem; min-height: 3rem;
}
.lg-chosen .lg-q {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
}
.lg-chosen .lg-a { font-weight: 600; grid-column: 2; font-size: 1rem; }
.lg-chosen .lg-change {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--ox);
}
.on-ink .lg-chosen .lg-change { color: var(--paper); }
@media (max-width: 34rem) {
  .lg-chosen { grid-template-columns: auto 1fr; }
  .lg-chosen .lg-a { grid-column: 2; }
  .lg-chosen .lg-change { grid-column: 2; }
}

/* ---- the hand-off ---- */

/* Answering a question rebuilds the step, so these fire on insertion without
   any script. The options wipe out to the right and the answer is printed as
   a line with a rule drawn under it: the point is that the answer went
   somewhere rather than that the page redrew. Clip-path, so nothing fades and
   nothing moves the layout. */
@media (prefers-reduced-motion: no-preference) {
  html.js .lg-options .lg-opt { animation: lg-wipe .44s var(--ease) both; }
  html.js .lg-options .lg-opt:nth-child(1) { animation-delay: 0s; }
  html.js .lg-options .lg-opt:nth-child(2) { animation-delay: .045s; }
  html.js .lg-options .lg-opt:nth-child(3) { animation-delay: .09s; }
  html.js .lg-options .lg-opt:nth-child(4) { animation-delay: .135s; }
  html.js .lg-options .lg-opt:nth-child(5) { animation-delay: .18s; }
  html.js .lg-options .lg-opt:nth-child(n+6) { animation-delay: .225s; }

  /* Only the answer that just changed replays. Three lines redrawing on every
     tap would be noise. */
  html.js .lg-chosen.is-new .lg-a { animation: lg-print .5s var(--ease) both; }
  html.js .lg-chosen.is-new::after { animation: lg-draw .55s var(--ease) .1s both; }
}
@keyframes lg-wipe {
  from { clip-path: inset(0 100% 0 0); }
  to   { clip-path: inset(0 0 0 0); }
}
@keyframes lg-print {
  from { clip-path: inset(100% 0 0 0); transform: translateY(.35em); }
  to   { clip-path: inset(0 0 0 0); transform: none; }
}
@keyframes lg-draw {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}
.lg-chosen { position: relative; }
.lg-chosen::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: var(--ox); transform: scaleX(0); transform-origin: 0 50%;
}
.on-ink .lg-chosen::after { background: var(--paper); }

/* ---- the count and the escapes ---- */

.lg-bar {
  position: relative;
  display: flex; flex-wrap: wrap; align-items: center; gap: .75rem 1rem;
  padding-block: .75rem; border-top: 1px solid var(--text);
}
/* Three answers in, and the bar draws itself a line. It is the only thing on
   the page that says finished, and it costs one pseudo-element. */
.lg-bar::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--ox);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform .7s var(--ease);
}
.ladder[data-done] .lg-bar::after { transform: scaleX(1); }
.lg-bar b {
  font-family: var(--display); font-weight: 900; font-size: 1.5rem;
  letter-spacing: -.02em; line-height: 1;
}
.lg-bar .lg-esc {
  margin-left: auto; display: flex; gap: .5rem; flex-wrap: wrap;
}
.lg-search {
  font: inherit; font-size: 1rem;
  background: transparent; color: var(--text);
  border: 1px solid var(--rule); border-radius: 0;
  padding: .7rem .8rem; min-height: 2.75rem; width: min(16rem, 100%);
}
.lg-search:focus-visible { border-color: var(--ox); }

/* ---- results ---- */

.lg-results { display: grid; gap: .4rem; }
.lg-item {
  border: 1px solid var(--rule);
  opacity: 0; transform: translateY(.6rem);
  transition: opacity .5s var(--ease), transform .6s var(--ease);
}
.lg-results.in .lg-item { opacity: 1; transform: none; }
.lg-results.in .lg-item:nth-child(1) { transition-delay: .04s; }
.lg-results.in .lg-item:nth-child(2) { transition-delay: .09s; }
.lg-results.in .lg-item:nth-child(3) { transition-delay: .14s; }
.lg-results.in .lg-item:nth-child(4) { transition-delay: .19s; }
.lg-results.in .lg-item:nth-child(n+5) { transition-delay: .22s; }

.lg-item summary {
  display: grid; grid-template-columns: 1fr auto auto; gap: .9rem;
  align-items: center; cursor: pointer;
  padding: .85rem .9rem; min-height: 3.25rem;
  list-style: none;
}
.lg-item summary::-webkit-details-marker { display: none; }
.lg-item summary:focus-visible { outline: 2px solid var(--ox); outline-offset: 2px; }
.lg-it { font-weight: 600; font-size: .9375rem; line-height: 1.25; }
/* The hours figure is the whole value proposition. The tree hid it on mobile;
   here it is on every row at every width. */
.lg-ih {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .06em;
  color: var(--text-2); white-space: nowrap;
}
.lg-ih b {
  font-family: var(--display); font-weight: 900; font-size: 1.125rem;
  letter-spacing: -.02em; color: var(--text);
}
.lg-ib {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .08em;
  text-transform: uppercase; color: var(--text-2); white-space: nowrap;
}
@media (max-width: 30rem) {
  .lg-item summary { grid-template-columns: 1fr auto; }
  .lg-ib { display: none; }
}
.lg-item[open] { border-color: var(--text); }
.lg-body {
  padding: 0 .9rem 1rem; display: grid; gap: .6rem;
  font-size: var(--small); color: var(--text-2); line-height: 1.55;
}
.lg-full { font-weight: 600; color: var(--text); font-size: .9375rem; }
.lg-tools, .lg-est {
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .04em;
  line-height: 1.5;
}
.lg-est { padding-top: .5rem; border-top: 1px solid var(--rule); }

.lg-more {
  margin-top: .4rem; padding: .9rem; min-height: 3rem;
  border: 1px solid var(--text);
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase;
}
.lg-more:hover { background: var(--ink); color: var(--paper); }
.lg-none { font-size: var(--small); color: var(--text-2); padding-block: .75rem; }

.fallback-list { margin-top: var(--s4); display: grid; gap: var(--s4); }
.fallback-family h3 {
  font-size: var(--h1); font-weight: 600;
  border-bottom: 1px solid var(--text); padding-bottom: .5rem;
  display: flex; gap: .75rem; align-items: baseline;
}
.fallback-family h3 .mono { font-size: var(--label); color: var(--text-2); letter-spacing: .12em; }
.fallback-family ul { display: grid; gap: .75rem; margin-top: .9rem; }
.fallback-family li {
  padding-bottom: .75rem; border-bottom: 1px solid var(--rule);
  font-size: var(--small); line-height: 1.5;
}
.fallback-family li .mono { font-size: .625rem; letter-spacing: .08em; color: var(--text-2); }

@media (prefers-reduced-motion: reduce) {
  .lg-item { opacity: 1 !important; transform: none !important; }
}

.panel {
  position: fixed; right: 0; top: 0; bottom: 0; z-index: 55;
  width: min(28rem, 100%);
  background: var(--ink); color: var(--paper);
  padding: calc(var(--header-h) + 1.5rem) 1.75rem 2rem;
  transform: translateX(101%);
  transition: transform var(--t-slow) var(--ease);
  overflow-y: auto;
  border-left: 1px solid rgba(244, 241, 234, .2);
}
.panel.is-open { transform: none; }
/* Same defect: the close button was tabbable at x=1799 in a 1440 viewport. */
.panel:not(.is-open) { visibility: hidden; }
.panel { transition: transform var(--t-slow) var(--ease), visibility 0s linear var(--t-slow); }
.panel.is-open { transition: transform var(--t-slow) var(--ease), visibility 0s; }
.panel-close {
  position: absolute; top: calc(var(--header-h) + .25rem); right: 1.5rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: rgba(244, 241, 234, .6);
}
.panel-close:hover { color: var(--paper); }
.panel .pcode { font-family: var(--mono); font-size: var(--label); letter-spacing: .14em; color: rgba(244, 241, 234, .6); }
.panel h3 { font-size: clamp(1.25rem, 2vw, 1.625rem); font-weight: 600; line-height: 1.2; margin-top: .75rem; }
.panel .pd { color: rgba(244, 241, 234, .72); margin-top: .9rem; }
.panel .pgrid {
  display: grid; grid-template-columns: 1fr 1fr; gap: 1px;
  background: rgba(244, 241, 234, .2); margin-top: 1.5rem;
}
.panel .pgrid div { background: var(--ink); padding: .9rem; display: grid; gap: .3rem; }
.panel .pgrid b { font-family: var(--display); font-weight: 900; font-size: 1.75rem; line-height: 1; letter-spacing: -.02em; }
.panel .pgrid span { font-family: var(--mono); font-size: .625rem; letter-spacing: .12em; text-transform: uppercase; color: rgba(244, 241, 234, .6); }
.panel .ptags { display: flex; flex-wrap: wrap; gap: .35rem; margin-top: 1.25rem; }
.panel .ptag {
  font-family: var(--mono); font-size: .625rem; letter-spacing: .1em; text-transform: uppercase;
  border: 1px solid rgba(244, 241, 234, .28); padding: .3rem .5rem; color: rgba(244, 241, 234, .8);
}
.panel .ptools {
  margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid rgba(244, 241, 234, .2);
  font-family: var(--mono); font-size: .6875rem; letter-spacing: .06em; color: rgba(244, 241, 234, .7);
}
.panel .pcta { margin-top: 1.75rem; }

.scrim {
  position: fixed; inset: 0; z-index: 54; background: rgba(10, 10, 10, .5);
  opacity: 0; pointer-events: none; transition: opacity var(--t) var(--ease);
}
.scrim.is-on { opacity: 1; pointer-events: auto; }

/* ---------- 18 Founders --------------------------------------------- */

.people { display: grid; gap: var(--s5); }
.person {
  display: grid; grid-template-columns: 12rem minmax(0, 1fr);
  gap: var(--s4);
  align-items: start;
  padding-block: clamp(2rem, 4vw, 3rem);
  border-top: 1px solid var(--rule);
}
.people > .person:last-child { border-bottom: 1px solid var(--rule); }
/* Portrait beside the name rather than above it, so two founders fit in
   about one screen instead of 1.74. */
@media (max-width: 56rem) {
  .person { grid-template-columns: 5.5rem minmax(0, 1fr); gap: var(--s3); align-items: start; }
  .portrait { max-width: 5.5rem; }
  .portrait figcaption { display: none; }
  .person-body h2, .person-body h3 { font-size: 1.375rem; }
  .person { padding-block: 1.25rem; }
}

.portrait {
  position: relative; aspect-ratio: 1 / 1; background: var(--ink);
  overflow: hidden; width: 100%; max-width: 12rem;
}
/* Held in ink monochrome by default and released to colour on hover. It is
   the brand register, and it is also what lets a low-resolution source sit
   next to a high-resolution one without the difference shouting. */
.portrait img {
  width: 100%; height: 100%; object-fit: cover; object-position: 50% 28%;
  filter: grayscale(1) contrast(1.12) brightness(1.02);
  transform: scale(1.02);
  transition: filter .8s var(--ease), transform 1.2s var(--ease);
}
.person:hover .portrait img,
.person:focus-within .portrait img { filter: none; transform: scale(1.06); }
@media (prefers-reduced-motion: reduce) {
  .portrait img { transition: none; transform: none; }
  .person:hover .portrait img { transform: none; }
}
.portrait-fallback {
  position: absolute; inset: 0; display: grid; place-items: center;
  background: var(--ink);
}
.portrait-fallback svg { width: 46%; height: auto; }
.portrait figcaption {
  position: absolute; inset-inline: 0; bottom: 0;
  padding: .5rem .6rem; background: var(--ink); color: var(--paper);
  font-family: var(--mono); font-size: .625rem; letter-spacing: .12em;
  text-transform: uppercase;
}
.portrait-note {
  margin-top: .6rem; font-family: var(--mono); font-size: .625rem;
  letter-spacing: .12em; text-transform: uppercase; color: var(--text-2);
}
.person-body { display: grid; gap: var(--s3); }
.person-body h2, .person-body h3 {
  font-size: var(--d3); font-family: var(--display); font-weight: 900;
  text-transform: uppercase; line-height: 1; letter-spacing: -.015em;
}
.person-role { font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--ox); }
.cvlist { display: grid; gap: 0; border-top: 1px solid var(--rule); }
.cvlist li {
  display: grid; grid-template-columns: 9rem 1fr; gap: 1rem;
  padding-block: .8rem; border-bottom: 1px solid var(--rule);
  font-size: var(--small);
}
.cvlist .when { font-family: var(--mono); font-size: var(--label); letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-2); padding-top: .18rem; }
.cvlist .what b { display: block; font-weight: 600; font-size: .9375rem; }
.cvlist .what span { color: var(--text-2); }
@media (max-width: 40rem) {
  .cvlist li { grid-template-columns: 1fr; gap: .2rem; }
}

/* ---------- 19 Tech stack ------------------------------------------- */

.stack-grid {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
}
.stack-cell {
  background: var(--ground); padding: 1.25rem;
  display: grid; gap: .5rem; align-content: start; min-height: 9rem;
}
.stack-cell .k { font-family: var(--mono); font-size: .625rem; letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2); }
.stack-cell b { font-size: 1.0625rem; font-weight: 600; line-height: 1.2; }
.stack-cell p { font-size: var(--small); color: var(--text-2); line-height: 1.45; }

/* ---------- 19b The live specimen -------------------------------- */

.spec {
  display: grid; gap: 1px; background: var(--rule);
  grid-template-columns: repeat(3, 1fr);
}
@media (max-width: 62rem) { .spec { grid-template-columns: repeat(2, 1fr); } }
/* Two columns all the way down, not one. Six numbers one per row was 1.49
   screens of a phone for six numbers. */
@media (max-width: 38rem) {
  .spec { grid-template-columns: repeat(2, 1fr); }
  .spec-cell { padding: .85rem .8rem; }
  .spec-cell b { font-size: clamp(1.35rem, 7vw, 1.9rem); }
  /* The explanatory notes matter least on the smallest screen. */
  .spec-cell small { display: none; }
}
.spec-cell {
  position: relative; overflow: hidden;
  background: var(--ground); padding: clamp(1rem, 2.2vw, 1.6rem);
  display: grid; gap: .4rem; align-content: start;
  transition: background var(--t-ui) var(--ease), color var(--t-ui) var(--ease);
}
@media (hover: hover) and (pointer: fine) {
  .spec-cell:hover { background: var(--hi); color: var(--paper); }
  .spec-cell:hover > span, .spec-cell:hover small { color: rgba(244, 241, 234, .86); }
}
/* One pass of a rule across the cell as its figure lands: the panel argues
   that these were measured, so the arrival should look like a measurement and
   not like a number appearing. Runs once, per cell, never in a loop. */
.spec-cell::after {
  content: ''; position: absolute; left: 0; top: 0; bottom: 0; width: 1px;
  background: var(--ox); opacity: 0;
}
.on-ink .spec-cell::after { background: var(--paper); }
@media (prefers-reduced-motion: no-preference) {
  .spec-cell.is-measured::after { animation: spec-pass .75s var(--ease) both; }
}
@keyframes spec-pass {
  from { transform: translateX(0); opacity: .9; }
  to   { transform: translateX(calc(var(--w, 20rem) * 1)); opacity: 0; }
}
.spec-cell b {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.75rem, 3.6vw, 2.75rem); line-height: 1; letter-spacing: -.025em;
  font-variant-numeric: tabular-nums;
}
.spec-cell > span {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2);
}
.spec-cell small { font-size: var(--small); color: var(--text-2); line-height: 1.45; }

/* Until the browser has reported, the panel says so rather than showing
   zeros that would read as a claim. */
#specimen:not([data-live]) .spec-cell b { color: var(--text-2); }
#specimen[data-unsupported] .spec-cell small { opacity: .6; }

/* ---------- 20 Contact block ------------------------------------- */

.contact-list { display: grid; gap: 0; border-top: 1px solid var(--rule); }
.contact-list li {
  display: grid; grid-template-columns: 8rem 1fr; gap: 1rem;
  padding-block: 1rem; border-bottom: 1px solid var(--rule); align-items: baseline;
}
.contact-list dt, .contact-list .k {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
}
.contact-list a { text-decoration: none; font-weight: 600; overflow-wrap: anywhere; }
.contact-list a:hover { color: var(--ox); }
@media (max-width: 40rem) {
  .contact-list li { grid-template-columns: 1fr; gap: .25rem; }
}

/* ---------- 21 Brief builder ---------------------------------------- */

.brief { display: grid; gap: var(--s3); }
.brief fieldset { border: 0; padding: 0; margin: 0; display: grid; gap: .75rem; }
.brief legend {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2); padding: 0; margin-bottom: .25rem;
}
.brief label.field { display: grid; gap: .4rem; font-size: var(--small); }
/* 16px, below which iOS zooms the page on focus and throws the layout. */
.brief input[type='text'], .brief input[type='number'], .brief textarea, .brief select {
  font: inherit; font-size: 1rem;
  background: transparent; color: var(--text);
  border: 1px solid var(--rule); padding: .8rem .9rem; width: 100%;
  border-radius: 0; min-height: 3rem;
  transition: border-color var(--t-fast) var(--ease);
}
.brief textarea { resize: vertical; min-height: 7rem; line-height: 1.5; }
.brief [aria-invalid='true'] { border-color: var(--ox); border-width: 2px; }
.brief .row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s2); }
@media (max-width: 44rem) { .brief .row { grid-template-columns: 1fr; } }
.brief .hint { font-size: var(--small); color: var(--text-2); line-height: 1.5; }

/* Full-width rows, not 16px boxes. The checkbox was 16x16, under the 24px
   WCAG minimum and far under the 44px platform guidance. */
.brief .checks { display: grid; gap: .4rem; }
.brief .checks label {
  display: flex; align-items: center; gap: .8rem;
  min-height: 3rem; padding: .6rem .9rem;
  border: 1px solid var(--rule);
  font-size: .9375rem; cursor: pointer;
  transition: border-color var(--t-fast) var(--ease), background var(--t-fast) var(--ease);
}
.brief .checks label:hover { border-color: var(--text); }
.brief .checks label:has(:checked) { border-color: var(--ox); background: var(--ox-pale); }
.brief input[type='checkbox'] {
  width: 1.5rem; height: 1.5rem; accent-color: var(--ox); flex: none; margin: 0;
}
@media (min-width: 44rem) {
  .brief .checks { grid-template-columns: 1fr 1fr; }
}

/* ---- readiness ---- */

/* The button used to look identical whether or not it could do anything, and
   only said so after being pressed. It now carries the state: outline while
   the brief is not sendable, filled the moment it is. The oxblood rises from
   the bottom edge, which is the same gesture the hover fill uses, spent on
   something that means more than hover. */
.brief-send .btn {
  --btn-bg: transparent; --btn-fg: var(--text);
  border-color: var(--g40);
}
.brief-send .btn::after { background: var(--ox); }
.brief-send[data-ready] .btn { --btn-fg: var(--paper); border-color: var(--ox); }
.brief-send[data-ready] .btn::after { transform: translateY(0); }
.brief-send .btn .gate { transition: transform var(--t-ui) var(--ease); }
.brief-send[data-ready] .btn .gate { transform: translateX(.25rem); }
.brief-send { display: grid; gap: .7rem; }
.brief-ready {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
  display: flex; align-items: center; gap: .5rem; min-height: 1.2em;
}
.brief-ready .gate { width: .8rem; height: .6rem; flex: none; color: var(--g40);
  transition: color var(--t-ui) var(--ease), transform var(--t) var(--ease); }
.brief-send[data-ready] .brief-ready { color: var(--text); }
.brief-send[data-ready] .brief-ready .gate { color: var(--ox); transform: translateX(.2rem); }

/* ---- the live figure, beside the inputs ---- */

.est-live {
  border: 1px solid var(--ox);
  padding: clamp(1rem, 2.4vw, 1.5rem);
  display: grid; gap: .6rem;
  position: sticky; top: calc(var(--header-h) + 1rem);
}
.est-live .label { color: var(--ox); }
.est-row { display: flex; align-items: center; gap: 1rem; }
.est-ring { width: 3.25rem; height: 3.25rem; flex: none; color: var(--ox); }
.est-arc { transition: stroke-dashoffset .42s var(--ease); }
.est-live output {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(2.5rem, 7vw, 3.5rem); line-height: 1;
  letter-spacing: -.03em; font-variant-numeric: tabular-nums;
}
@media (max-width: 62rem) {
  .est-live { position: static; }
}
@media (prefers-reduced-motion: reduce) {
  .est-arc { transition: none; }
}

/* ---------- 22 Notes ---------------------------------------------- */

.notes-list { display: grid; gap: 0; border-top: 1px solid var(--text); }
.note-row {
  display: grid; grid-template-columns: 8rem 1fr auto; gap: var(--s3);
  padding-block: clamp(1.25rem, 2.5vw, 2rem);
  border-bottom: 1px solid var(--rule);
  text-decoration: none; align-items: baseline;
  transition: padding-inline var(--t) var(--ease);
}
.note-row:hover { padding-inline: .75rem; background: var(--ox-pale); }
.note-row .when { font-family: var(--mono); font-size: var(--label); letter-spacing: .1em;
  text-transform: uppercase; color: var(--text-2); }
.note-row h2 { font-size: clamp(1.125rem, 2vw, 1.5rem); font-weight: 600; line-height: 1.25; }
.note-row p { font-size: var(--small); color: var(--text-2); margin-top: .4rem; max-width: 58ch; }
.note-row .go { font-family: var(--mono); font-size: var(--label); letter-spacing: .14em; color: var(--ox); }
@media (max-width: 48rem) {
  .note-row { grid-template-columns: 1fr; gap: .5rem; }
  .note-row .go { display: none; }
}

.article-head { display: grid; gap: var(--s3); max-width: 46ch; }
.article-meta {
  display: flex; flex-wrap: wrap; gap: 1.25rem;
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
  padding-top: var(--s2); border-top: 1px solid var(--rule);
}

/* ---------- 23 Footer -------------------------------------------- */

.footer {
  background: var(--ink); color: var(--paper);
  padding-block: clamp(3rem, 6vw, 5rem) 2rem;
}
.footer-grid {
  display: grid; gap: var(--s4);
  grid-template-columns: minmax(0, 1.3fr) repeat(2, minmax(0, 1fr));
}
@media (max-width: 62rem) { .footer-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 40rem) { .footer-grid { grid-template-columns: 1fr; } }
.footer h2 {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: rgba(244, 241, 234, .55); margin-bottom: var(--s2);
}
.footer ul { display: grid; gap: .35rem; }
.footer a { text-decoration: none; font-size: var(--small); color: rgba(244, 241, 234, .9); overflow-wrap: anywhere; }
.footer a:hover { color: var(--paper); text-decoration: underline; text-underline-offset: .2em; }
.footer .sig {
  font-family: var(--display); font-weight: 900; text-transform: uppercase;
  font-size: clamp(1.125rem, 2vw, 1.5rem); line-height: 1.05; letter-spacing: -.015em;
  max-width: 20ch;
}
.footer-foot {
  margin-top: var(--s5); padding-top: var(--s2);
  border-top: 1px solid rgba(244, 241, 234, .18);
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4); justify-content: space-between;
  font-family: var(--mono); font-size: .625rem; letter-spacing: .1em;
  text-transform: uppercase; color: rgba(244, 241, 234, .55);
}
.footer-brand img { height: 1.75rem; width: auto; margin-bottom: var(--s2); }

/* ---------- 22b The three-step sequence -------------------------- */

/* Three numbered steps on one line, joined by a rule that draws itself as
   the block arrives. One idea, read left to right, no scrolling required. */
.seq {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--gutter);
  position: relative;
  padding-top: 2.5rem;
}
.seq::before {
  content: ''; position: absolute; top: .55rem; left: 0; right: 0;
  height: 1px; background: var(--rule);
}
.seq::after {
  content: ''; position: absolute; top: .55rem; left: 0; right: 0;
  height: 1px; background: var(--ox);
  transform: scaleX(0); transform-origin: 0 50%;
  transition: transform 1.4s var(--ease) .2s;
}
.on-ink .seq::after { background: var(--paper); }
.seq.in::after { transform: scaleX(1); }

.seq-step { position: relative; display: grid; gap: .6rem; align-content: start; }
.seq-step::before {
  content: ''; position: absolute; top: -2.5rem; left: 0;
  width: .6rem; height: .6rem; background: var(--ground);
  border: 1px solid var(--ox); border-radius: 50%;
  transform: translateY(.25rem);
}
.on-ink .seq-step::before { border-color: var(--paper); }
.seq-step b {
  font-family: var(--display); font-weight: 900;
  font-size: clamp(1.75rem, 3.2vw, 2.75rem); line-height: 1; letter-spacing: -.02em;
}
.seq-step .k {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .14em;
  text-transform: uppercase; color: var(--text-2);
}
.seq-step p { font-size: var(--small); color: var(--text-2); line-height: 1.5; max-width: 34ch; }
@media (max-width: 52rem) {
  .seq { grid-template-columns: 1fr; gap: var(--s3); padding-top: 0; }
  .seq::before, .seq::after { display: none; }
  .seq-step { border-top: 1px solid var(--rule); padding-top: 1.1rem; }
  .seq-step::before { display: none; }
}

/* ---------- 23b The motif veil ------------------------------------ */

/* The brand pattern surfaces behind the text on hover, then retreats.
   Brand s09: the pattern always sits behind type and never competes with
   it, which is why it tops out well under half opacity and why it scales
   down into place rather than moving. */
.veil { position: relative; isolation: isolate; --tile: 26rem; --vx: 0; --vy: 0; }
.veil::before {
  content: '';
  position: absolute; inset: 0; z-index: -1;
  background-image: url('/assets/brand/motif-light-muted.svg');
  background-size: var(--tile) auto;
  background-repeat: repeat;
  background-position: center;
  opacity: 0;
  /* The field leans towards the pointer. Two custom properties on the same
     element as the pseudo, so the recalculation is scoped to it and no child
     is touched. Transform only: the tiling never repaints. */
  transform: translate3d(calc(var(--vx) * 14px), calc(var(--vy) * 14px), 0) scale(1.09);
  transition: opacity .7s var(--ease), transform .55s var(--ease);
  pointer-events: none;
}
.veil:hover::before,
.veil:focus-within::before {
  opacity: .38;
  transform: translate3d(calc(var(--vx) * 14px), calc(var(--vy) * 14px), 0) scale(1);
}

/* Dark surfaces get their own artwork rather than the same file at a higher
   opacity: the muted dark motif is painted in near-blacks and stays invisible
   on ink however far you push it. The strong variant swaps those for full
   oxblood and a low-luminance neutral, so it reads clearly while paper text
   over it still measures 8.73:1. */
.on-ink .veil::before,
.veil.on-ink::before { background-image: url('/assets/brand/motif-dark-strong.svg'); }
.on-ink .veil:hover::before,
.on-ink .veil:focus-within::before { opacity: .55; }

/* Bigger surfaces get a bigger tile so the motif does not read as noise. */
.veil-lg { --tile: 40rem; }

@media (prefers-reduced-motion: reduce) {
  .veil::before { transition: none; transform: none !important; }
}
@media (hover: none), (pointer: coarse) {
  /* No hover and no pointer to lean towards, so show a whisper of it
     permanently and hold it still. */
  .veil::before { opacity: .26; transform: none; }
  .on-ink .veil::before { opacity: .34; }
  .statement.veil::before,
  .section.on-ink.veil::before { opacity: .4; }
}

/* ---------- 24 Misc ---------------------------------------------- */

.callout {
  background: var(--ox-pale); color: var(--ink);
  padding: clamp(1.25rem, 2.6vw, 2rem);
  display: grid; gap: var(--s2);
  border-left: 2px solid var(--ox);
}
.callout .label { color: var(--ox-deep); }
.callout-spaced { margin-top: var(--s4); }

.note-under { margin-top: var(--s2); }
.cards-stacked { margin-top: 1px; }
.footer-legal-head { margin-top: var(--s3); }


/* Legal document header block, borrowed from the brand guidelines. */
.doc-meta { border-top: 1px solid var(--text); }
.doc-meta dl { margin: 0; display: grid; }
.doc-meta dl > div {
  display: grid; grid-template-columns: 9rem 1fr; gap: 1rem;
  padding-block: .6rem; border-bottom: 1px solid var(--rule);
}
.doc-meta dt {
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
}
.doc-meta dd { margin: 0; font-size: var(--small); }
@media (max-width: 40rem) {
  .doc-meta dl > div { grid-template-columns: 1fr; gap: .15rem; }
}

/* Checkbox rows in the brief builder. */
.brief .row label:has(input[type='checkbox']) {
  display: flex; align-items: center; gap: .55rem;
  font-size: var(--small); padding: .35rem 0;
}
.brief input[type='checkbox'] {
  width: 1rem; height: 1rem; accent-color: var(--ox); flex: none; margin: 0;
}
.brief output#bEst, .brief output#bHoursOut, .brief output#bPeopleOut { font-variant-numeric: tabular-nums; }
.brief output#bHoursOut, .brief output#bPeopleOut {
  font-family: var(--mono); font-size: var(--small); font-weight: 400;
  letter-spacing: .06em; color: var(--ox);
}

/* 404 */
.oops { min-height: 70svh; display: grid; align-content: center; }

.breadcrumb {
  padding-top: calc(var(--header-h) + 2rem);
  font-family: var(--mono); font-size: var(--label); letter-spacing: .12em;
  text-transform: uppercase; color: var(--text-2);
}
.breadcrumb a { text-decoration: none; }
.breadcrumb a:hover { color: var(--ox); }
.breadcrumb span { opacity: .5; margin-inline: .4rem; }

.page-head { padding-block: var(--s4) var(--s5); }
.page-head.first { padding-top: var(--s3); }

/* Interior pages carry a display line, not a cover statement. Display 1 at
   full size belongs to the landing hero only. */
.page-head .d1, .oops .d1 { font-size: clamp(2.25rem, 5.8vw, 4.5rem); }

/* ---------- 24b Mobile and touch --------------------------------- */

/* Notched phones: keep fixed chrome and page edges clear of the rounded
   corners and the home indicator. */
@supports (padding: env(safe-area-inset-left)) {
  .wrap {
    padding-left: max(var(--margin), env(safe-area-inset-left));
    padding-right: max(var(--margin), env(safe-area-inset-right));
  }
  .drawer {
    padding-left: max(var(--margin), env(safe-area-inset-left));
    padding-right: max(var(--margin), env(safe-area-inset-right));
    padding-bottom: max(2rem, env(safe-area-inset-bottom));
  }
  .footer { padding-bottom: max(2rem, env(safe-area-inset-bottom)); }
}

/* Anything tapped clears 44px. Keyed on a coarse pointer OR a narrow
   viewport, because pointer detection is unreliable on hybrid devices and a
   narrow screen is touched often enough that guessing wrong costs more than
   the padding. */
@media (pointer: coarse), (max-width: 46rem) {
  .btn { padding: 1.05rem 1.4rem; min-height: 3rem; }
  .chip { padding: .85rem 1rem; min-height: 2.75rem; display: inline-flex; align-items: center; }
  .lg-opt { min-height: 3.75rem; }
  .lg-item summary { min-height: 3.5rem; }
  .lg-chosen { min-height: 3.25rem; }
  .lg-more { min-height: 3.25rem; }
  .drawer > a { padding-block: .55rem; }
  .footer a { display: inline-block; padding-block: .6rem; }
  .contact-list a { display: inline-block; padding-block: .6rem; }
  .drawer-foot a { display: inline-block; padding-block: .7rem; }
  .brand { padding-block: .6rem; }
  .breadcrumb a { display: inline-block; padding-block: .8rem; }
  .calc-range { height: 3rem; }
  /* 16px or iOS zooms the page on focus and throws the layout. */
  .brief input, .brief textarea, .brief select, .lg-search { font-size: 1rem; }
}

/* Scrolling containers must not drag the page behind them. */
.drawer { overscroll-behavior: contain; -webkit-overflow-scrolling: touch; }

@media (max-width: 46rem) {
  /* A 26rem tile on a 390px screen shows about one repeat, so the pattern
     reads as scattered marks rather than as a pattern. */
  .veil { --tile: 11rem; }
  .veil-lg { --tile: 14rem; }
  .statement.veil::before,
  .section.on-ink.veil::before { opacity: .2; }
  .veil::before { opacity: .2; }

  /* One clear action per screen beats two half-width ones. */
  .cta-row .btn { width: 100%; justify-content: space-between; }
  .cta-row { gap: .75rem; }

  .hero { min-height: auto; padding-bottom: 2.5rem; }
  .page-head { padding-block: var(--s2) var(--s3); }
  .page-head .d1 { font-size: clamp(1.75rem, 8.5vw, 2.5rem); }
  .page-head .grid { gap: var(--s2); }
  .gate-rule { margin-block: 0; }
  .prose table { font-size: .8125rem; }
  .section { padding-block: clamp(2.5rem, 8vw, 4rem); }
  .section-tight { padding-block: clamp(2rem, 6vw, 3rem); }
}

/* Short landscape phones: never let the hero eat the whole viewport. */
@media (max-height: 30rem) and (orientation: landscape) {
  .hero { min-height: auto; padding-top: calc(var(--header-h) + 1.5rem); }
}

/* 320px, the WCAG 1.4.10 test width. */
@media (max-width: 22.5rem) {
  .lg-bar { gap: .5rem; }
  .lg-esc { margin-left: 0; width: 100%; }
  .lg-search { width: 100%; }
}

/* ---------- 25 Reduced motion ----------------------------------- */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    transition-delay: 0ms !important;
  }
  [data-reveal], [data-stagger] > * { opacity: 1 !important; transform: none !important; }
  [data-reveal='mask'] .rl > span { transform: none !important; }
  [data-reveal='wipe'] { clip-path: none !important; }
  [data-reveal='rule'] { transform: none !important; }
  .gate-rule .gr-line { transform: none !important; }
  .gr-track { animation: none !important; display: none; }
  .statement.veil::before,
  .section.on-ink.veil::before { animation: none !important; inset: 0; }
  .gate-rule .gr-tri, .gate-rule .gr-ring { opacity: 1 !important; transform: none !important; }
  [data-reveal='head'] .label::before { transform: none !important; }
  [data-reveal='head'] .label::after { opacity: 1 !important; transform: none !important; }
  .hero-canvas { display: none; }
  .reticle { display: none; }
  .marquee-track { animation: none; }
  .intro { display: none; }
  /* The drum, the extruded mark and the tilt all stop being motion and
     become layout: show the value, show one plate, level everything. */
  .odo-d { overflow: visible; perspective: none; width: auto; }
  .odo-r { transition: none !important; transform: none !important;
    position: static; transform-style: flat; }
  .odo-r > i { position: static; transform: none !important; }
  .odo-r > i:not(.is-shown) { display: none; }
  .m3 { transition: none !important; transform: none !important; }
  .m3-tri > i:not(:nth-child(7)), .m3-ring > i:not(:nth-child(5)) { display: none; }
  .m3-tri > i, .m3-ring > i { transform: none !important; opacity: 1 !important; }
  [data-tilt] { transform: none !important; }
  /* Belt and braces for the two clip-based reveals: if the reveal class never
     lands, the numeral and the facts must still be readable. */
  .step-n { clip-path: none !important; }
  /* The price band: the rule is simply there, the numeral is simply up. */
  .on-ox .figure::before { transform: scaleX(1) !important; }
  .on-ox .figure b { transform: none !important; }
  .on-ox .figure > span { opacity: 1 !important; }
  .wd.is-hl::after { transform: scaleX(1) !important; }
  .step-meta span { opacity: 1 !important; transform: none !important; }
  .lg-opt, .lg-chosen .lg-a, .lg-chosen::after,
  .spec-cell::after { animation: none !important; clip-path: none !important; }
  .lg-chosen::after { transform: scaleX(1) !important; }
  .calc-work .tm { opacity: 1 !important; transform: none !important; }
  .srail-tri { transform: none !important; }
  [data-reveal='words'][data-3d] .wd > i { opacity: 1 !important; transform: none !important; }
}

/* ---------- 26 Print -------------------------------------------- */

@media print {
  .header, .drawer, .progress, .footer, .reticle, .hero-canvas,
  .marquee, .scroll-hint, .panel, .scrim { display: none !important; }
  body { background: #fff; color: #000; font-size: 11pt; }
  .hero, .statement, .on-ink, .footer { background: #fff !important; color: #000 !important; }
  a[href^='http']::after { content: ' (' attr(href) ')'; font-size: 9pt; }
}
