/* ==========================================================================
   SPECIFICATIEBLAD / HET DATABLAD - LANDING PAGES
   www/css/spec-pages.css

   The 7 long-tail landing pages (NL + EN = 14 files) as data sheets: a plate
   title between two drawn rules, a four-row specification block, the argument,
   the decision the buyer actually came to make, and the evidence.

   Load order on those pages: main.css, then this file. Nothing else.
   Self-contained: its own @font-face block, its own tokens. css/spec.css is
   deliberately NOT loaded here (it sets `.wrapper { max-width: none }` and owns
   the homepage's gauge, which a four-section document has not earned).

   Deliberate difference from the homepage, recorded so the next person does not
   "fix" it: these pages carry NO section numerals. On the homepage the numerals
   are wayfinding across 4.5 viewports next to a scroll instrument. Here the
   sequence carries no information the reader needs, so a numeral would be a
   decoration wearing the system's clothes. The margin column stays, empty, as
   the document's binding margin and as the cage the homepage shares.

   Rules of the build, enforced below:
   - border-radius is 0 everywhere, no exception.
   - zero blurred box-shadow. The only box-shadow is a drawn 2px rule.
   - no transition: all.
   - three border widths only: 1px #d0d0d0 structural, 1px #e4e4e4 interior,
     2px #000000 for current, default or focused.
   - the finished state is the element's normal CSS. Nothing starts at opacity 0.
   - the #fc4c02 orange (apple-light.css / apple-bold.css) and the Lora /
     Open Sans families cannot leak back in.
   - prefers-reduced-motion is the LAST block in this file.
   ========================================================================== */


/* ==========================================================================
   1. @FONT-FACE  (self-hosted Barlow, SIL OFL, latin subset)
   Duplicated from spec.css on purpose, so this file has no @import and no
   dependency on the homepage stylesheet. Three static cuts, no latin-ext face:
   the only non-ASCII characters these pages print are Latin-1 accented letters
   and the copyright sign, all inside the latin subset in www/fonts/.
   ========================================================================== */

@font-face {
  font-family: Barlow;
  src: url(/fonts/barlow-400.woff2) format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: Barlow;
  src: url(/fonts/barlow-500.woff2) format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: Barlow;
  src: url(/fonts/barlow-800.woff2) format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

/* Metric-matched fallback, so the swap does not shift the layout. Measured,
   not guessed: Barlow 400 sets the same sample 5.23% narrower than Helvetica
   Neue (4874.3px vs 5143.3px at 100px), and its own ascent and descent are
   100% and 20% of the em. The overrides compound with size-adjust, so they are
   divided by it: 100/0.9477 and 20/0.9477. */
@font-face {
  font-family: 'Barlow Fallback';
  src: local('Helvetica Neue'), local('Arial');
  size-adjust: 94.77%;
  ascent-override: 105.5%;
  descent-override: 21.1%;
  line-gap-override: 0%;
}


/* ==========================================================================
   2. TOKENS  (same values as css/spec.css section 2)
   Only the roles these pages actually use are declared.
   ========================================================================== */

:root {
  /* -- families ------------------------------------------------------ */
  --font-sans: Barlow, 'Barlow Fallback', system-ui, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, monospace;

  /* -- type scale. Every clamp middle term carries a rem component, so
        200% zoom holds. ------------------------------------------------ */
  --t-plate:    clamp(2rem, 1.5rem + 2.5vw, 3.5rem);        /* 32 -> 56px  */
  --t-h2:       clamp(2rem, 1.833rem + 0.833vw, 2.5rem);    /* 32 -> 40px  */
  --t-h3:       1.75rem;                                    /* 28px        */
  --t-lead:     clamp(1.375rem, 1.25rem + 0.625vw, 1.75rem);/* 22 -> 28px  */
  --t-body:     1.125rem;                                   /* 18px        */
  --t-caption:  0.875rem;                                   /* 14px        */
  --t-anno:     0.8125rem;                                  /* 13px mono   */
  --t-wordmark: 1.375rem;                                   /* 22px        */

  /* -- colour -------------------------------------------------------- */
  --surface:     #ffffff;
  --surface-100: #f5f5f5;
  --surface-200: #f1f1f1;
  --ink:         #000000;
  --ink-strong:  #121212;
  --ink-600:     #414141;
  --slate:       #6b6d76;   /* 5.15:1 on white. Every small grey is this.  */
  --slate-invert:#a9abb3;   /* 6.6:1 on #252525. The same grey, on the dark
                               ground. Slate itself reads at 2.3:1 there, so
                               the hue is kept and only the lightness moves. */
  --line:        #d0d0d0;   /* every structural 1px rule                 */
  --line-soft:   #e4e4e4;   /* rules inside tables and lists             */
  --graphite:    #252525;
  --signal:      #00c14e;   /* used exactly once, on one 8x8px square  */
  --closer-ground: var(--graphite);

  /* #8d8d8d is NOT USED on any light ground anywhere in this file.
     3.32:1, illegal below 18px. The omission is a decision, recorded here. */

  /* -- grid and space ------------------------------------------------ */
  --page-width: 1400px;
  --gauge-w: 96px;
  --wf-h: 24px;          /* the ruler lying down, <1024px only */
  --gutter: 12px;           /* >=768px: 24px ; >=1280px: 40px */
  --margin-col: 0px;        /* >=768px: 56px ; >=1024px: 96px */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 20px;
  --space-6: 24px;
  --space-8: 32px;
  --space-12: 48px;

  /* -- motion. Two easing characters with assigned jobs. There is no third
        here: these pages have one load beat and one press. -------------- */
  --ease-struct: cubic-bezier(0.215, 0.61, 0.355, 1); /* structure      */
  --ease-load:   cubic-bezier(0.16, 1, 0.3, 1);       /* the load beat  */
  --ease-spring: linear(0, 0.32 8%, 0.79 20%, 1.03 30%, 1.01 46%, 1);

  /* -- motion, durations. Four steps plus the press, one job each, so the
        same kind of action takes the same time on every page of the site.
        Small element, short step. Full-bleed rule, long step. --------- */
  --dur-press: 90ms;  /* the press itself, read as instant               */
  --dur-1:    150ms;  /* feedback on a small element: colour, underline  */
  --dur-2:    250ms;  /* a state change: a rule taking or losing weight  */
  --dur-3:    400ms;  /* one staggered member of a group of rules        */
  --dur-4:    620ms;  /* a rule drawing its own full length              */
  --stagger:   60ms;  /* the step between members of one group of rules  */

  /* -- the gauge reading. 1:1 with scroll, written by js/spec.js. With no JS
        at all this stays 0, which is the correct picture of "you are at the
        top of the document". ------------------------------------------- */
  --p: 0;

  /* -- kill the old accent. apple-light.css declares --accent: #fc4c02 and
        apple-bold.css declares --blue: #fc4c02. Neither file is linked on
        these pages, but if one is ever pulled in again the orange resolves
        to ink instead of leaking into the page. ------------------------ */
  --accent: var(--ink-strong);
  --blue:   var(--ink-strong);
}


/* ==========================================================================
   3. MAIN.CSS NEUTRALISERS AND BASE
   main.css stays linked (it is the normalize layer and the resume-page styles)
   and is never reformatted. These rules load later with equal or higher
   specificity and cancel only the parts that can reach this markup. Every
   selector below answers a specific declaration in main.css; the comment says
   which one.
   ========================================================================== */

/* main.css: html { background:#fff; scroll-behavior:smooth } */
html {
  background: var(--surface);
  scrollbar-gutter: stable;
  -webkit-text-size-adjust: 100%;
}

/* main.css: body { font-family:"Lora",...serif; color:#333; font-size:16px;
   line-height:1.6 }. Equal specificity, later in the cascade, so this wins. */
body {
  margin: 0;
  background: var(--surface);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0;
  color: var(--ink-strong);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* main.css sets radius at (0,2,0) and (0,1,0) on a handful of selectors.
   Radius 0 everywhere, no exception, no carve-out. */
*,
*::before,
*::after {
  border-radius: 0;
}

/* main.css (normalize): h1 { font-size:2em; margin:0.67em 0 } */
h1, h2, h3, h4, p, ul, ol, dl, dd, figure {
  margin: 0;
}

/* main.css: h2 { font-weight:600 !important } and
   h3 { padding-bottom:1.5rem !important; padding-top:1.5rem !important }.
   The neutraliser has to carry !important too, because the original does. */
h2 { font-weight: 500 !important; }
h3 { padding: 0 !important; }

/* main.css: p { font-size:1.125rem } and li { font-size:1.125rem }.
   Same value, restated from the token so a token change moves both. */
p, li { font-size: inherit; }

ul, ol { padding: 0; list-style: none; }

img, svg { display: block; max-width: 100%; height: auto; }

/* Browser surfaces the page did not draw still carry the design.
   main.css: ::selection { background:rgba(51,51,51,0.8); color:#fff }. */
::selection {
  background: var(--ink);
  color: var(--surface);
  text-shadow: none;
}

::-moz-selection {
  background: var(--ink);
  color: var(--surface);
  text-shadow: none;
}

/* The caret and the accent colour for any control the page grows later. */
:root { accent-color: var(--ink); caret-color: var(--ink); }

/* Long Dutch compounds in the big type must never push a scrollbar. */
h1, h2, h3, .plate, .pf__claim, .dt__case {
  overflow-wrap: anywhere;
  min-width: 0;
}


/* ==========================================================================
   4. TYPE ROLES
   ========================================================================== */

/* plate, the page topic. Not his name: the topic is what was searched for. */
.plate {
  font-family: var(--font-sans);
  font-size: var(--t-plate);
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink-strong);
}

.h2 {
  font-size: var(--t-h2);
  font-weight: 500;
  line-height: 1.06;
  letter-spacing: -0.02em;
  color: var(--ink-strong);
}

.lead {
  font-size: var(--t-lead);
  font-weight: 500;
  line-height: 1.28;
  letter-spacing: -0.02em;
  color: var(--ink-strong);
}

.prose {
  font-size: var(--t-body);
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: 0;
  color: var(--ink-strong);
}

.prose + .prose { margin-block-start: var(--space-4); }

.caption {
  font-size: var(--t-caption);
  font-weight: 400;
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: var(--slate);
}

/* anno, the mono annotation. Used for specification labels, column heads and
   route strings: it labels a thing, it is never used for reading. */
.anno {
  font-family: var(--font-mono);
  font-size: var(--t-anno);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--slate);
  font-variant-numeric: tabular-nums;
}

/* wordmark, one of only two uppercase roles on the page. */
.wordmark {
  font-size: var(--t-wordmark);
  font-weight: 800;
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--ink);
  white-space: nowrap;
}

/* Bold inside running copy is always the 800 cut, never synthetic. */
b, strong {
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--ink-strong);
}

/* Below 480px the 18px body steps to 16px; everything else is already fluid. */
@media (max-width: 479px) {
  :root { --t-body: 1rem; }
}


/* ==========================================================================
   5. BAND GRID
   Full-bleed shell, 12 columns capped at --page-width, margin column added as
   inner padding. Same cage as the homepage, so a visitor moving between them
   sees content start at the same x.
   ========================================================================== */

.band {
  position: relative;
  width: 100%;
}

.band__inner {
  max-width: calc(var(--page-width) + var(--margin-col));
  margin-inline: auto;
  padding-inline: calc(var(--gutter) + var(--margin-col)) var(--gutter);
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  column-gap: var(--space-4);
  row-gap: var(--space-4);
}

/* Two full-bleed ground switches on the page. Exactly two, never three.
   A ground switch carries its own block padding: the section rhythm above is a
   margin, and a margin sits outside the painted area, so without this the grey
   would start high above its heading and stop flush against its last rule. */
.band--tint { background: var(--surface-100); }
.band--invert { background: var(--closer-ground); }

.band--tint > .band__inner,
.band--invert > .band__inner { padding-block: 72px; }

/* A grounded band does not also need a hairline: the ground change is already
   the separation, and drawing both is the same job done twice. Removing it also
   makes the band's block padding read as one value top and bottom. */
.band--tint > .band__inner > .band__rule,
.band--invert > .band__inner > .band__rule { display: none; }

/* The rhythm above a grounded band is now partly inside it, so the margin above
   drops by the padding it gained. The five values stay distinct and uneven. */
.band--02.band--tint { margin-block-start: 24px; }
.band--04.band--invert { margin-block-start: 80px; }

.band--invert,
.band--invert .h2,
.band--invert .prose,
.band--invert .lead { color: var(--surface); }

.band--invert .anno,
.band--invert .caption { color: var(--slate-invert); }

.band--invert :where(a, button, [role="button"], [tabindex]):focus-visible {
  outline-color: var(--surface);
}

/* Section rhythm. Four distinct values, deliberately uneven, and deliberately
   shorter than the homepage's: this document is a quarter of its length, so
   the homepage's 192px closer gap would read as a missing section. */
.band--00 { margin-block-start: 0; }
.band--01 { margin-block-start: 96px; }
.band--02 { margin-block-start: 72px; }
.band--03 { margin-block-start: 112px; }
.band--04 { margin-block-start: 128px; }

/* The band rule is a real element, as on the homepage: 1px at rest. These
   pages have no current-section state, so it never goes to 2px. */
.band__rule {
  grid-column: 1 / -1;
  height: 1px;
  background: var(--line);
  margin-block-end: var(--space-6);
  clip-path: inset(0);
  transition:
    height var(--dur-2) var(--ease-struct),
    background-color var(--dur-2) linear,
    clip-path var(--dur-4) var(--ease-struct);
}

/* Integer pixels, never scaleY: a scaled hairline resamples. */
.band.is-current > .band__inner > .band__rule {
  height: 2px;
  background: var(--ink);
}

/* BEAT B, the rule draw. The from-state lives behind .js, which the script adds
   only after confirming prefers-reduced-motion is false. Without .js the rule is
   simply full width. */
.js .band:not(.is-ruled) > .band__inner > .band__rule { clip-path: inset(0 100% 0 0); }


/* ==========================================================================
   5b. THE GAUGE  (de meetlat)
   The margin column is reserved so this can stand in it. One fixed element,
   four children, nothing focusable, aria-hidden, pointer-events none.
   Ported unchanged from css/spec.css: same four parts, same three widths,
   same --p, written 1:1 with scroll by js/spec.js. These are 3400px and
   4800px documents and they carried no position marker at all.
   ========================================================================== */

.gauge {
  display: none;
  position: fixed;
  inset-block: 0;
  left: 0;
  width: var(--gauge-w);
  pointer-events: none;
  z-index: 2;
}

/* The gauge is fixed, so it runs over the one inverted band. The rail and the
   ticks need nothing: #d0d0d0 and #e4e4e4 read on white and on #252525 alike.
   The two solid marks do need a flip, and it cannot be mix-blend-mode: a
   position:fixed element establishes its own stacking context, so a child
   blends against that context and never against the page. js/spec.js sets
   html.on-invert while the closing band is current, and this one token flips. */
:root          { --gauge-ink: var(--ink); --gauge-ground: var(--surface); }
html.on-invert { --gauge-ink: #ffffff; --gauge-ground: var(--closer-ground); }

.gauge__rail,
.gauge__ticks,
.gauge__fill,
.gauge__cursor { position: absolute; }

.gauge__rail {
  left: 40px;
  width: 1px;
  inset-block: 0;
  background: var(--line);
}

.gauge__ticks {
  left: 41px;
  width: 4px;
  inset-block: 0;
  background: repeating-linear-gradient(
    to bottom,
    var(--line-soft) 0 1px,
    transparent 1px 8px
  );
}

/* The one scaling transform in the build: a 2px solid bar whose only edge is
   horizontal, so there is no hairline to resample. */
.gauge__fill {
  left: 39px;
  width: 2px;
  inset-block: 0;
  background: var(--gauge-ink);
  transform-origin: top;
  transform: scaleY(var(--p));
}

.gauge__cursor {
  left: 32px;
  top: 0;
  width: 16px;
  height: 16px;
  background: var(--gauge-ink);
  translate: 0 calc((100dvh - 16px) * var(--p));
}


/* ==========================================================================
   6. NAMEPLATE ROW
   44px, full bleed, 1px bottom rule. No motion. Same class vocabulary as the
   homepage on purpose: a visitor moving between the two sees one row, not two
   dialects of one row. The only difference is that the wordmark is a link
   here, because a search visitor landed mid-site and needs a route home.
   ========================================================================== */

.np {
  border-block-end: 1px solid var(--line);
}

.np > .band__inner {
  align-items: center;
  row-gap: var(--space-2);
  /* Pinned, not min-height. The row is 44px by design, and leaving it free
     lets the font swap change its height and push the whole document down.
     Above 768px the content is a 32px photo and one line of 14px text, so
     44px is never tight. */
  height: 44px;
}

.np__left {
  grid-column: 1 / 8;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
  min-width: 0;
}

.np__right {
  grid-column: 8 / -1;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2);
  min-width: 0;
}

.np__photo {
  width: 32px;
  height: 32px;
  object-fit: cover;
  flex: 0 0 auto;
}

.np__mark { line-height: 1; min-width: 0; }

.np__mark a { color: inherit; }

/* The 20px hairline between the wordmark and the role subtitle. */
.np__hair {
  width: 1px;
  height: 20px;
  background: var(--line);
  flex: 0 0 auto;
}

.np__role {
  font-size: var(--t-caption);
  line-height: 1.4;
  letter-spacing: -0.02em;
  color: var(--slate);
  min-width: 0;
}

.np__social {
  display: flex;
  align-items: center;
  gap: 0;
}

.np__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  color: var(--ink-strong);
  transition: color var(--dur-1) linear;
}

/* Monochrome, in currentColor. The inline SVGs carry a fill attribute;
   CSS beats a presentation attribute. */
.np__icon svg { width: 18px; height: 18px; }
.np__icon svg path,
.np__icon svg rect,
.np__icon svg circle,
.np__icon svg polygon { fill: currentColor; }


/* ==========================================================================
   6b. AVAILABILITY STRIP
   44px, #f1f1f1, 1px bottom rule. No motion. Ported unchanged from
   css/spec.css so a visitor moving between the homepage and a landing page
   sees one strip, not two dialects of one strip.

   The strip tint is NOT a third full-bleed ground switch: it is a narrower,
   slightly cooler step than the paper tint, chosen so a 44px strip reads as a
   rule with a ground and never as a section. The Two Grounds Rule still holds.

   This carries the only green on the page, once, on one 8x8px square, and
   never on text.
   ========================================================================== */

.avail {
  background: var(--surface-200);
  border-block-end: 1px solid var(--line);
}

.avail > .band__inner {
  align-items: center;
  min-height: 44px;
}

.avail__line {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-size: 1rem;
  line-height: 1.4;
  color: var(--ink-strong);
}

.avail__dot {
  width: 8px;
  height: 8px;
  background: var(--signal);
  flex: 0 0 auto;
}


/* ==========================================================================
   7. TITLE BLOCK  (the first viewport)
   Plate title between two drawn rules, then the specification block, then the
   argument. Measurements before the argument: that is the whole thesis.
   ========================================================================== */

.band--00 > .band__inner { padding-block-start: var(--space-8); }

.title__head { grid-column: 1 / 11; }

/* The two rules that draw open on load. 2px, ink, integer height: never a
   scaled hairline. */
.plate__rule {
  display: block;
  height: 2px;
  background: var(--ink);
}

.title__head .plate { margin-block: var(--space-4); }

/* 12px, not 8px: at line-height 1 the 56px descenders sit close to the
   closing rule. */
.title__head .plate__rule--close { margin-block-start: var(--space-3); }

/* BEAT A, the single load beat. CSS only, no JS, no from-state held: the
   keyframe has a from and no to, so the finished state is the element's own
   CSS. Top rule opens from the left, bottom rule from the right. */
/* The finished state is a real shape, not `none`.
   clip-path only interpolates between two shapes of the same kind: an
   `inset()` paired with `none` is a DISCRETE transition, so the rule used to
   sit invisible for half the duration and then pop to full width. Declaring
   the finished state as inset(0) — which clips nothing — turns the same
   two rules into an actual draw. */
.plate__rule { clip-path: inset(0); }

@media (prefers-reduced-motion: no-preference) {
  .plate__rule { animation: rule-draw-lr var(--dur-4) var(--ease-load); }
  .plate__rule--close { animation: rule-draw-rl var(--dur-4) var(--ease-load) 120ms; }
}

@keyframes rule-draw-lr { from { clip-path: inset(0 100% 0 0); } }
@keyframes rule-draw-rl { from { clip-path: inset(0 0 0 100%); } }

.title__role {
  grid-column: 1 / 11;
  margin-block-start: var(--space-3);
  color: var(--slate);
}


/* Section headings are direct grid items of the band. Stated once. */
.band__inner > .h2 { grid-column: 1 / 10; }
.band__inner > .prose,
.band__inner > .lead { grid-column: 1 / 8; }


/* ==========================================================================
   8. SPECIFICATION BLOCK
   Four ruled rows. Mono uppercase label in columns 1 to 3, fact in 4 to 12.
   A definition list, because that is what it is.
   ========================================================================== */

.spec {
  grid-column: 1 / -1;
  margin-block-start: var(--space-6);
}

.spec__row {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column: 1 / -1;
  align-items: baseline;
  column-gap: var(--space-4);
  padding-block: var(--space-4);
  border-block-start: 1px solid var(--line);
}

.spec__row:last-child { border-block-end: 1px solid var(--line); }

.spec__label {
  grid-column: 1 / 4;
  padding-block-start: 0.25em;
}

.spec__value {
  grid-column: 4 / 12;
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink-strong);
  font-variant-numeric: tabular-nums;
  max-width: 68ch;
}


/* ==========================================================================
   9. ARGUMENT COLUMN
   One measure, capped. The primary button closes it.
   ========================================================================== */

.arg {
  grid-column: 1 / 9;
  margin-block-start: var(--space-8);
}

.arg .lead { max-width: 57ch; }
.arg .prose { max-width: 57ch; }
.arg .btn { margin-block-start: var(--space-6); }

.arg__note {
  margin-block-start: var(--space-3);
  max-width: 44ch;
}


/* ==========================================================================
   10. DECISION LIST  (the signature)
   The real question a buyer of this topic has to decide, answered per row.
   Three fixed columns that never move: the case, the pick, the reason.

   The recommendation is reported by WEIGHT, never by colour: the usual answer
   carries a 2px ink rule instead of a 1px hairline, and its pick is set in the
   800 cut. A mono marker names that state in words, so the meaning does not
   live in the line width alone.
   ========================================================================== */

.dt {
  grid-column: 1 / -1;
  margin-block-start: var(--space-6);
}

.dt__head {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column: 1 / -1;
  column-gap: var(--space-4);
  padding-block-start: var(--space-2);
  padding-block-end: var(--space-2);
}

.dt__head span:nth-child(1) { grid-column: 1 / 5; }
.dt__head span:nth-child(2) { grid-column: 5 / 8; }
.dt__head span:nth-child(3) { grid-column: 8 / -1; }

.dt__row {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column: 1 / -1;
  align-items: baseline;
  column-gap: var(--space-4);
  padding-block: var(--space-5);
  border-block-start: 1px solid var(--line);
}

.dt__row:last-child { border-block-end: 1px solid var(--line); }

.dt__row--default {
  border-block-start-width: 2px;
  border-block-start-color: var(--ink);
}

.dt__case {
  grid-column: 1 / 5;
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink-strong);
}

.dt__pick {
  grid-column: 5 / 8;
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: -0.01em;
  color: var(--ink-strong);
}

.dt__row--default .dt__pick {
  font-weight: 800;
  color: var(--ink);
}

.dt__mark {
  display: block;
  margin-block-start: var(--space-1);
}

.dt__why {
  grid-column: 8 / -1;
  font-size: var(--t-caption);
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--slate);
}


/* BEAT C, the decision table's rules.
   This is the one block on the page where the reader has to compare rows
   against each other, so its rules draw in reading order when the band is
   reached: same mechanic, same 60ms step and same easing as the homepage's
   ledger, capped at 640ms end to end. Attention arrives at the top row and
   walks down, which is the order the table is meant to be read in.

   The rules are pseudo-elements, because a border cannot be clipped. The
   borders themselves stay declared and go transparent, so every row keeps
   the exact height it had before this beat existed. No content moves: only
   the hairlines draw, which is the whole motion vocabulary of this sheet. */
.dt__row {
  position: relative;
  border-block-start-color: transparent;
}

.dt__row--default { border-block-start-color: transparent; }
.dt__row:last-child { border-block-end-color: transparent; }

.dt__row::before,
.dt__row:last-child::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  height: 1px;
  background: var(--line);
  clip-path: inset(0);
  transition: clip-path var(--dur-3) var(--ease-struct);
}

.dt__row::before { inset-block-start: -1px; }
.dt__row:last-child::after { inset-block-end: -1px; }

.dt__row--default::before {
  height: 2px;
  inset-block-start: -2px;
  background: var(--ink);
}

/* Reading order, one --stagger apart. A row's closing rule draws with its
   own row. Five rows is the longest table on the site: 4 steps plus
   --dur-3 is 640ms end to end, which is inside the 800ms a group of
   siblings may take before the tail starts to drag. */
.dt__row:nth-child(2)::before, .dt__row:nth-child(2)::after { transition-delay: var(--stagger); }
.dt__row:nth-child(3)::before, .dt__row:nth-child(3)::after { transition-delay: calc(var(--stagger) * 2); }
.dt__row:nth-child(4)::before, .dt__row:nth-child(4)::after { transition-delay: calc(var(--stagger) * 3); }
.dt__row:nth-child(5)::before, .dt__row:nth-child(5)::after { transition-delay: calc(var(--stagger) * 4); }

/* The held from-state, behind the same .js capability gate as every other
   beat in this file. Drop the class and the table is simply ruled. */
.js .band:not(.is-ruled) .dt__row::before,
.js .band:not(.is-ruled) .dt__row:last-child::after {
  clip-path: inset(0 100% 0 0);
}


/* ==========================================================================
   11. PROOF ROWS
   Fixed columns that never move, only their values change: the claim, the
   measurement or the rule it answers to, and the reference.
   ========================================================================== */

.pf {
  grid-column: 1 / -1;
  margin-block-start: var(--space-6);
}

.pf__head {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column: 1 / -1;
  column-gap: var(--space-4);
  padding-block-end: var(--space-2);
}

.pf__head span:nth-child(1) { grid-column: 1 / 6; }
.pf__head span:nth-child(2) { grid-column: 6 / 11; }
.pf__head span:nth-child(3) { grid-column: 11 / -1; text-align: right; }

.pf__row {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  grid-column: 1 / -1;
  align-items: baseline;
  column-gap: var(--space-4);
  padding-block: var(--space-5);
  border-block-start: 1px solid var(--line);
}

.pf__row:last-child { border-block-end: 1px solid var(--line); }

.pf__claim {
  grid-column: 1 / 6;
  font-size: var(--t-h3);
  font-weight: 500;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--ink-strong);
  font-variant-numeric: tabular-nums;
}

.pf__detail {
  grid-column: 6 / 11;
  font-size: var(--t-caption);
  font-weight: 400;
  line-height: 1.45;
  letter-spacing: -0.02em;
  color: var(--slate);
}

.pf__ref {
  grid-column: 11 / -1;
  text-align: right;
}

.pf__ref a {
  display: inline-block;
  padding-block: 5px;
}


/* ==========================================================================
   12. RELATED INDEX
   The homepage's index row, unchanged: the whole row is one anchor, and its
   rule doubles in weight on hover or focus.
   ========================================================================== */

.idx { grid-column: 1 / -1; margin-block-start: var(--space-6); }

.idx__row {
  position: relative;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: 56px;
  padding-block: var(--space-4);
  color: var(--ink-strong);
  text-decoration: none;
}

.idx__row::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  height: 1px;
  background: var(--line);
  transition:
    height var(--dur-1) var(--ease-struct),
    background-color var(--dur-1) linear;
}

.idx__row:last-child::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  height: 1px;
  background: var(--line);
}

.idx__label {
  font-size: var(--t-h3);
  font-weight: 500;
  line-height: 1.06;
  letter-spacing: -0.02em;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line);
  text-underline-offset: 0.18em;
  transition:
    text-decoration-color var(--dur-1) linear,
    text-decoration-thickness var(--dur-1) linear;
  min-width: 0;
}

.idx__route {
  flex: 0 0 auto;
  text-align: right;
}

.idx__row:focus-within::before,
.idx__row:focus-visible::before { height: 2px; background: var(--ink); }

.idx__row:focus-within .idx__label,
.idx__row:focus-visible .idx__label {
  text-decoration-thickness: 2px;
  text-decoration-color: var(--ink);
}

@media (hover: hover) and (pointer: fine) {
  .idx__row:hover::before { height: 2px; background: var(--ink); }
  .idx__row:hover .idx__label {
    text-decoration-thickness: 2px;
    text-decoration-color: var(--ink);
  }
}

.idx__row:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }


/* ==========================================================================
   13. CLOSER AND FOOTER
   One inverted band, then the sheet's revision line.
   ========================================================================== */

.closer__copy { grid-column: 1 / 8; }
.closer__copy .lead { margin-block-start: var(--space-3); max-width: 46ch; }
.closer__copy .btn { margin-block-start: var(--space-6); }

.sig {
  grid-column: 1 / -1;
  margin-block-start: var(--space-8);
  padding-block-start: var(--space-4);
  border-block-start: 1px solid var(--slate);
}

.foot > .band__inner { padding-block: var(--space-8); }

.foot__lines { grid-column: 1 / -1; }
.foot__line + .foot__line { margin-block-start: var(--space-2); }


/* ==========================================================================
   14. COMPONENTS AND STATE MATRICES
   Nine states exist. loading/pending, error, empty and success are not
   applicable on a static page with no fetch and no form, so they are
   deliberately not built. Recorded here rather than silently skipped.
   ========================================================================== */

/* -- 14.1 Prose link -------------------------------------------------------
   rest: 1px #d0d0d0 underline. hover or focus: 2px #000000, 150ms linear.
   A non-colour affordance on every link.
   :where() keeps this at one-type-selector specificity, so every control rule
   below wins over it without an !important anywhere. */
:where(main, .np, .foot, .closer) a {
  color: inherit;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line);
  text-underline-offset: 0.18em;
  transition:
    text-decoration-color var(--dur-1) linear,
    text-decoration-thickness var(--dur-1) linear;
}

:where(main, .np, .foot, .closer) a:focus-visible,
:where(main, .np, .foot, .closer) a:active {
  text-decoration-thickness: 2px;
  text-decoration-color: var(--ink);
}

@media (hover: hover) and (pointer: fine) {
  :where(main, .np, .foot, .closer) a:hover {
    text-decoration-thickness: 2px;
    text-decoration-color: var(--ink);
  }
}

:where(.band--invert) a { text-decoration-color: var(--slate); }

@media (hover: hover) and (pointer: fine) {
  :where(.band--invert) a:hover { text-decoration-color: var(--surface); }
}

/* Controls are not prose links. */
.skip,
.btn,
.lang,
.np__icon,
.np__mark a,
.idx__row { text-decoration: none; }

/* Every focusable thing gets the same ring. Stated once. */
a:focus-visible,
button:focus-visible,
[tabindex]:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}

/* -- 14.2 Button, primary --------------------------------------------------
   rest: #000000 ground, #ffffff label, Barlow 500 18px, radius 0,
   min-height 44px, padding 0 24px, no border, no shadow.
   hover (fine pointers only): #252525, --dur-1.
   active: scale(0.98) at --dur-press; release on the linear() spring over
   --dur-2.
   focus-visible: 2px ink outline, offset 2px.
   disabled: not applicable, a mailto: is never disabled.
   Label width is identical in every state. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 var(--space-6);
  border: 0;
  background: var(--ink);
  color: var(--surface);
  font-family: var(--font-sans);
  font-size: var(--t-body);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0;
  text-align: center;
  -webkit-tap-highlight-color: transparent;
  transition:
    background-color var(--dur-1) var(--ease-struct),
    color var(--dur-1) linear,
    transform var(--dur-2) var(--ease-spring);
}

@media (hover: hover) and (pointer: fine) {
  .btn:hover { background: var(--graphite); color: var(--surface); }
}

.btn:active {
  transform: scale(0.98);
  transition:
    background-color var(--dur-1) var(--ease-struct),
    color var(--dur-1) linear,
    transform var(--dur-press) var(--ease-struct);
}

/* -- Button, inverted, used in the one graphite band only ---------------- */
.btn--invert {
  background: var(--surface);
  color: var(--ink);
}

@media (hover: hover) and (pointer: fine) {
  .btn--invert:hover { background: var(--surface-200); color: var(--ink); }
}

.btn--invert:focus-visible {
  outline: 2px solid var(--surface);
  outline-offset: 2px;
}

/* -- 14.3 Language link --------------------------------------------------
   rest: 16px #121212, no underline, 44x44 hit area from padding.
   active page: inset 0 -2px 0 #000000 plus aria-current="page". That is the
   only box-shadow on the page and it is a rule, not a blur. */
.lang {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  min-height: 44px;
  font-size: 1rem;
  font-weight: 500;
  line-height: 1.2;
  color: var(--ink-strong);
  transition:
    box-shadow var(--dur-1) linear,
    text-decoration-color var(--dur-1) linear,
    text-decoration-thickness var(--dur-1) linear;
}

.lang[aria-current="page"] { box-shadow: inset 0 -2px 0 var(--ink); }

@media (hover: hover) and (pointer: fine) {
  .lang:hover {
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--ink);
    text-underline-offset: 0.18em;
  }
  .np__icon:hover { color: var(--ink); }
}

/* -- 14.4 Skip link ----------------------------------------------------- */
.skip {
  position: absolute;
  inset-block-start: var(--space-4);
  inset-inline-start: var(--space-4);
  z-index: 3;
  padding: var(--space-3) var(--space-4);
  background: var(--surface);
  color: var(--ink-strong);
  font-size: var(--t-body);
  clip-path: inset(50%);
}

.skip:focus,
.skip:focus-visible { clip-path: none; }

/* -- 14.5 Utilities ----------------------------------------------------- */

/* The column key. Real text in the DOM at every width, so the value a screen
   reader reads always arrives with the column it belongs to. Above 768px the
   visible column head carries it, so the key is clipped; below 768px the head
   is gone and the key takes its place. */
.dt__key,
.vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}


/* ==========================================================================
   15. RESPONSIVE
   The grid does not become a different design; the three fixed columns of the
   decision list and the proof rows stack, and the sheet keeps its rules.
   ========================================================================== */

@media (min-width: 768px) {
  :root { --gutter: 24px; --margin-col: 56px; }
}

@media (min-width: 1024px) {
  :root { --margin-col: 96px; }

  /* The instrument, in the margin column it measures. */
  .gauge { display: block; }
}

@media (min-width: 1280px) {
  :root { --gutter: 40px; }
}

/* --------------------------------------------------------------------------
   DE DUIMLAT  (the thumb rule)

   A 24px strip on its own opaque ground, with the 1px rail as its top edge, so
   content that scrolls under it ends on a hairline of the sheet's own
   vocabulary and not on a cut. It is read, never touched: pointer-events stays
   none, nothing in it is focusable, and there is no tap-to-seek, because that
   is a scrollbar and the platform has one. With no JS --p stays 0: rail, ticks
   and the square parked at the left, no fill, which is the true picture of
   "top of the document".
   -------------------------------------------------------------------------- */
@media (max-width: 1023px) {
  .gauge {
    display: block;
    inset-block: auto 0;
    inset-inline: 0;
    width: auto;
    /* The home indicator sits under the bar on an iPhone. The ground grows to
       cover it; the marks stay in the top 24px, inside the thumb arc. env()
       resolves to 0px on every other device. */
    height: calc(var(--wf-h) + env(safe-area-inset-bottom, 0px));
    background: var(--gauge-ground);
    container-type: inline-size;
  }

  .gauge__rail {
    inset-block: 0 auto;
    inset-inline: 0;
    width: auto;
    height: 1px;
  }

  .gauge__ticks {
    inset-block: 1px auto;
    inset-inline: 0;
    width: auto;
    height: 4px;
    background: repeating-linear-gradient(
      to right,
      var(--line-soft) 0 1px,
      transparent 1px 8px
    );
  }

  .gauge__fill {
    inset-block: 0 auto;
    inset-inline: 0;
    width: auto;
    height: 2px;
    transform-origin: left center;
    transform: scaleX(var(--p));
  }

  /* The square walks right by translate, not by left: animating left dirties
     layout every changed frame. A raw percentage resolves against the square's
     own 16px box and 100dvw counts a scrollbar it cannot see, so the bar
     declares itself a size container and the square reads cqi. */
  .gauge__cursor {
    inset-block: 0 auto;
    right: auto;
    left: 0;
    translate: calc((100cqi - 16px) * var(--p)) 0;
  }

  /* It never covers content. The reservation is in the first layout, so it
     costs 24px of document height and no layout shift. */
  body { padding-block-end: calc(var(--wf-h) + env(safe-area-inset-bottom, 0px)); }
}

/* ---- Below 1024px the nameplate's role line wraps, so the 44px pin is
   released. The pin only has to hold where the font swap can move the page,
   which is the desktop layout. ------------------------------------------- */
@media (min-width: 768px) and (max-width: 1023px) {
  .np > .band__inner {
    height: auto;
    min-height: 44px;
    padding-block: var(--space-2);
  }
}

/* ---- Below 768px every three-column row stacks. The labels stay: a stacked
   row without its column head is three sentences with no idea which is which.
   ------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .title__head,
  .title__role { grid-column: 1 / -1; }

  .arg { grid-column: 1 / -1; }

  .spec__row,
  .dt__row,
  .pf__row {
    display: block;
    padding-block: var(--space-4);
  }

  .spec__label,
  .spec__value,
  .dt__case,
  .dt__pick,
  .dt__why,
  .pf__claim,
  .pf__detail,
  .pf__ref { max-width: none; }

  .spec__value { margin-block-start: var(--space-1); }

  .dt__head,
  .pf__head { display: none; }

  /* The column head comes out of hiding, because the row is now on its own. */
  .dt__key {
    position: static;
    width: auto;
    height: auto;
    margin: 0 0 var(--space-1);
    clip-path: none;
    display: block;
    margin-block-start: var(--space-3);
  }

  .pf__ref {
    text-align: left;
    margin-block-start: var(--space-3);
  }

  .closer__copy { grid-column: 1 / -1; }

  .idx__row {
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-1);
  }

  .idx__route { text-align: left; }

  /* SC 2.5.8: a standalone link under 24px that is not part of a sentence run
     needs a 44px target. Vertical padding on an inline box paints and
     hit-tests but does not enter line layout, so this costs 0px of document
     height and 0 layout shift. The footer links are exempt: they sit inside
     running sentences, and padding them would make their line boxes overlap so
     the later link steals the earlier one's taps. */
  .pf__ref a { display: inline-block; padding-block: 14px; }

  /* The section rhythm compresses, but stays uneven. */
  .band--01 { margin-block-start: 64px; }
  .band--02 { margin-block-start: 48px; }
  .band--03 { margin-block-start: 72px; }
  .band--04 { margin-block-start: 88px; }

  .band--02.band--tint { margin-block-start: 16px; }
  .band--04.band--invert { margin-block-start: 56px; }

  .band--tint > .band__inner,
  .band--invert > .band__inner { padding-block: var(--space-12); }
}

/* ---- The nameplate on a phone -------------------------------------------
   Ported from css/spec.css, where these rules were measured rather than
   guessed, so both documents wear one nameplate instead of two dialects.

   display: contents promotes the photo, the wordmark and the role line to
   items of the nameplate's own flex line, so the role sentence takes a line of
   its own instead of wrapping three times inside a narrow track. Nothing is
   shrunk to make it fit: the five hit boxes keep 44 x 44, and 220px of them
   plus the photo plus the wordmark need about 352px of line, so flex-wrap
   decides it per device with no breakpoint to pick.

   Before this, the 22px nowrap wordmark overflowed its seven-column track and
   ran under the social icons at 390px. Seen in a screenshot, not in a
   computed style.
   -------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .np > .band__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    height: auto;
    min-height: 0;
    row-gap: 2px;
    column-gap: var(--space-2);
    /* 10px at the top, because the hit boxes reach 10px above their own row
       and the top row is the top of the document. */
    padding-block: 10px 6px;
  }

  .np__left { display: contents; }
  .np__photo { width: 24px; height: 24px; }
  .np .wordmark { font-size: 1rem; }
  .np__hair { display: none; }

  .np__role {
    order: 1;
    flex: 1 0 100%;
    font-size: 0.8125rem;
    line-height: 1.4;
  }

  .np__right {
    margin-inline-start: auto;
    gap: 0;
  }

  /* The negative block margin lets the boxes overflow their own 24px row
     instead of setting it. They overhang into the role line, which holds no
     link, and never past the nameplate rule. */
  .np__icon,
  .np .lang { margin-block: -10px; }

  /* Each social anchor is an inline-flex box inside its own list item, so the
     item's line box carries the inherited strut. A flex item has none. */
  .np__social > li { display: flex; }

  /* The current-language mark is an inset 2px rule at the bottom of the 44px
     box. That box now reaches 10px past its own row, so the rule would land in
     the middle of the role sentence and read as a strikethrough. Same 2px of
     ink, put on the glyphs instead, where it cannot move when the box does. */
  .np .lang[aria-current="page"] {
    box-shadow: none;
    text-decoration: underline;
    text-decoration-thickness: 2px;
    text-decoration-color: var(--ink);
    text-underline-offset: 0.18em;
  }
}

/* Below 377px the right-hand group no longer shares the top row: it wraps, so
   the wrap is made explicit at exactly the width where it already happens. */
@media (max-width: 376px) {
  .np > .band__inner { padding-block: 4px; }
  .np__right { flex: 0 0 100%; justify-content: flex-end; }
}


/* ==========================================================================
   16. PRINT
   The sheet prints as a sheet: no inverted ground, no photo, no controls.
   ========================================================================== */

@media print {
  .avail,
  .np__social,
  .lang,
  .np__photo,
  .btn,
  .skip,
  .idx { display: none; }

  .band--invert { background: none; }

  .band--invert,
  .band--invert .h2,
  .band--invert .prose,
  .band--invert .lead { color: var(--ink-strong); }

  .band--01, .band--02, .band--03, .band--04 { margin-block-start: 24px; }

  a { text-decoration-color: var(--slate); }

  /* Held from-states have no meaning on paper: a band the reader never
     scrolled to would print with its hairlines missing. */
  .plate__rule,
  .plate__rule--close,
  .band__rule,
  .dt__row::before,
  .dt__row::after {
    animation: none;
    clip-path: none;
  }
}


/* ==========================================================================
   17. REDUCED MOTION  (last block in this file, on purpose)
   Explicit rather than a blanket wildcard: the wildcard would also cancel the
   1ms floor it is trying to set. main.css declares html { scroll-behavior:
   smooth }, so that is named here too.
   ========================================================================== */

@media (prefers-reduced-motion: reduce) {
  /* Removed: every rule that draws its own length, and the press. Nothing
     on this page translates a layer, zooms or parallaxes, so these are the
     whole of the movement. */
  .plate__rule,
  .plate__rule--close,
  .band__rule,
  .dt__row::before,
  .dt__row::after {
    animation: none;
    clip-path: none;
  }

  .band__rule { height: 1px; }
  .band.is-current > .band__inner > .band__rule { height: 2px; }

  .btn:active { transform: none; }

  /* The backstop, so anything added later is neutralised without being
     named here first. 0.01ms rather than 0s, because a transitionend
     listener still has to fire. */
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0ms !important;
    scroll-behavior: auto !important;
  }

  /* Kept on purpose, at the short step: colour and line weight on the
     controls the visitor is pointing at. Neither displaces anything, so
     neither is a vestibular trigger, and a control that reports itself by
     fading is easier to follow than one that snaps. This is the soft-fade
     half of the preference, not an exception to it. The band rules are
     deliberately NOT in this list: they track scroll rather than answer a
     pointer, so under reduce they snap. */
  :where(main, .np, .foot, .closer) a,
  .idx__row::before,
  .idx__label,
  .lang,
  .np__icon,
  .btn {
    transition-duration: var(--dur-1) !important;
  }
}
