/* ===== tokens.css ===== */
/* ============================================================
   TRADES tokens.css — Paintwork Auckland + Renovate Auckland
   One studio, two temperaments. v1.0 — 2026-07-30
   Usage: <html lang="en-NZ" data-site="paint"> or data-site="reno"
   Import BEFORE components.css.
   ============================================================ */

/* ---------- Self-hosted fonts ----------
   All three families are VARIABLE, so one file per family covers the whole
   weight axis. Each is split latin / latin-ext by unicode-range: the ext file
   is only fetched when a page actually contains a macron, which every Auckland
   site needs (Ōrākei, Māngere, Te Atatū, Tāmaki Makaurau) but most pages do not.
   Fallback stacks keep a page legible if a file is missing. */

@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Fraunces";
  src: url("/assets/fonts/fraunces-latinext.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/inter-latin.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  src: url("/assets/fonts/inter-latinext.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Spline Sans Mono";
  src: url("/assets/fonts/splinesansmono-latin.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Spline Sans Mono";
  src: url("/assets/fonts/splinesansmono-latinext.woff2") format("woff2");
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Core tokens (shared, light) ---------- */
:root {
  color-scheme: light dark;

  /* Type families */
  --ff-display: "Fraunces", Georgia, "Times New Roman", serif;
  --ff-body: "Inter", system-ui, -apple-system, "Segoe UI", sans-serif;
  --ff-mono: "Spline Sans Mono", "Cascadia Code", Consolas, monospace;

  /* Type scale */
  --fs-hero: clamp(2.75rem, 1.2rem + 5.2vw, 4.75rem);
  --fs-h1: clamp(2.125rem, 1.1rem + 3vw, 3.25rem);
  --fs-h2: clamp(1.625rem, 1.1rem + 1.7vw, 2.25rem);
  --fs-h3: clamp(1.25rem, 1.05rem + 0.7vw, 1.5rem);
  --fs-stat: clamp(2.5rem, 1rem + 4.5vw, 4.25rem);
  --fs-lg: 1.1875rem;
  --fs-body: 1.0625rem;
  --fs-sm: 0.9375rem;
  --fs-mono: 0.8125rem;
  --fs-micro: 0.75rem;

  --lh-tight: 1.02;
  --lh-head: 1.12;
  --lh-body: 1.6;

  --track-head: -0.012em;
  --track-label: 0.08em;

  /* Display weight settings (Fraunces variable) */
  --display-wght: 560;
  --display-stat-wght: 300;

  /* Spacing (4px base) */
  --s-1: 4px;  --s-2: 8px;   --s-3: 12px; --s-4: 16px;
  --s-5: 24px; --s-6: 32px;  --s-7: 48px; --s-8: 64px;
  --s-9: 96px; --s-10: 128px; --s-11: 192px;

  /* Layout */
  --w-content: 1180px;
  --w-wide: 1360px;
  --measure: 66ch;
  --measure-lede: 58ch;
  --gutter: clamp(20px, 5vw, 64px);
  --grid-gap: var(--s-6);

  /* Radii */
  --r-0: 0;
  --r-1: 2px;
  --r-2: 6px;

  /* Motion */
  --t-fast: 140ms;
  --t-med: 220ms;
  --t-slow: 420ms;
  --ease-out: cubic-bezier(0.25, 1, 0.4, 1);
  --ease-inout: cubic-bezier(0.45, 0.05, 0.25, 1);

  /* Neutrals — LIGHT */
  --paper: #F6F3EC;
  --paper-raised: #FCFAF3;
  --ink: #1F1D18;
  --ink-2: #55514A;
  --ink-3: #6E6960;
  --faint: #8A857B;
  --hairline: #DCD6C8;
  --hairline-strong: #C9C2B2;

  /* Elevation — the ONE shadow in the system */
  --shadow-lift: 0 1px 0 rgb(31 29 24 / 0.06),
                 0 24px 48px -32px rgb(31 29 24 / 0.28);
}

/* ---------- Site accents — LIGHT ---------- */
html[data-site="paint"] {
  --accent: #962B20;        /* Pōhutukawa — 7.12:1 on paper */
  --accent-deep: #7D2318;   /* 8.92:1 on paper */
  --on-accent: #FFFFFF;     /* 7.89:1 on accent */
  --accent-wash: #F3E7E4;
  --sibling-accent: #2C5666;      /* reno's colour, handoff block only */
  --sibling-accent-deep: #24485A;
  --sibling-wash: #E7EDEF;
}
html[data-site="reno"] {
  --accent: #2C5666;        /* Winter Harbour — 7.21:1 on paper */
  --accent-deep: #24485A;   /* 8.82:1 on paper */
  --on-accent: #FFFFFF;     /* 7.98:1 on accent */
  --accent-wash: #E7EDEF;
  --sibling-accent: #962B20;      /* paint's colour, handoff block only */
  --sibling-accent-deep: #7D2318;
  --sibling-wash: #F3E7E4;
}

/* ---------- DARK ---------- */
@media (prefers-color-scheme: dark) {
  :root {
    --paper: #171613;
    --paper-raised: #1F1E1A;
    --ink: #ECE8DE;         /* 14.79:1 */
    --ink-2: #B3ACA0;       /* 8.03:1 */
    --ink-3: #A19B90;       /* 6.55:1 */
    --faint: #5C574E;
    --hairline: #3A3830;
    --hairline-strong: #4A473E;
    --shadow-lift: none;    /* dark elevation = surface step */
  }
  html[data-site="paint"] {
    --accent: #E58274;      /* 6.70:1 on paper */
    --accent-deep: #EF9A8E;
    --on-accent: #171613;   /* 6.70:1 on accent */
    --accent-wash: #2A2019;
    --sibling-accent: #8FB7C6;
    --sibling-accent-deep: #A9CBD8;
    --sibling-wash: #1A2228;
  }
  html[data-site="reno"] {
    --accent: #8FB7C6;      /* 8.41:1 on paper */
    --accent-deep: #A9CBD8;
    --on-accent: #171613;   /* 8.41:1 on accent */
    --accent-wash: #1A2228;
    --sibling-accent: #E58274;
    --sibling-accent-deep: #EF9A8E;
    --sibling-wash: #2A2019;
  }
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-feature-settings: "cv05" 1, "tnum" 0;
  -webkit-font-smoothing: antialiased;
}

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

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--r-1);
}

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

/* ---------- Reduced motion: mandatory ---------- */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *,
  *::before,
  *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
}

/* ===== components.css ===== */
/* ============================================================
   TRADES components.css — built ONLY on tokens.css custom props.
   Both sites use this file unmodified; data-site on <html>
   swaps the accent set. v1.0 — 2026-07-30
   ============================================================ */

/* ---------- Layout primitives ---------- */
.wrap {
  max-width: var(--w-content);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.wrap-wide { max-width: var(--w-wide); margin-inline: auto; padding-inline: var(--gutter); }

.section { padding-block: clamp(var(--s-8), 10vw, var(--s-10)); }
.section + .section { border-top: 1px solid var(--hairline); }

.grid {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: var(--grid-gap);
}
.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: 860px) {
  .grid { gap: var(--s-5); }
  .col-4, .col-5, .col-6, .col-7, .col-8 { grid-column: span 12; }
}

.prose { max-width: var(--measure); }
.lede {
  font-size: var(--fs-lg);
  color: var(--ink-2);
  max-width: var(--measure-lede);
}

/* ---------- Skip link ---------- */
.skip-link {
  position: absolute;
  left: var(--s-4);
  top: -100px;
  z-index: 100;
  background: var(--accent);
  color: var(--on-accent);
  padding: var(--s-3) var(--s-5);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  text-decoration: none;
  border-radius: var(--r-1);
  transition: top var(--t-med) var(--ease-out);
}
.skip-link:focus-visible { top: var(--s-4); }

/* ---------- Type helpers ---------- */
.display {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 72;
  letter-spacing: var(--track-head);
  line-height: var(--lh-head);
  margin: 0;
  text-wrap: balance;
}
h1.display { font-size: var(--fs-h1); }
h2.display { font-size: var(--fs-h2); }
h3.display { font-size: var(--fs-h3); }

.mono-label {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}

/* Dated-source line — under every figure, table, stat, plate */
.source-line {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  color: var(--ink-3);
  margin-top: var(--s-2);
}
.source-line::before { content: "— "; color: var(--faint); }

/* ---------- Section header: keel rule + kicker + headline ---------- */
.section-head { margin-bottom: clamp(var(--s-6), 5vw, var(--s-8)); }
.section-head .kicker {
  display: block;
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 var(--s-3);
}
.section-head .kicker::before {
  content: "";
  display: block;
  width: 48px;
  border-top: 2px solid var(--accent); /* the keel rule */
  margin-bottom: var(--s-3);
}
.section-head p.intro {
  color: var(--ink-2);
  max-width: var(--measure-lede);
  margin: var(--s-4) 0 0;
}

/* ---------- Netbar / navigation (max 7 links per rulebook) ---------- */
.netbar {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--paper-raised) 88%, transparent);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--hairline);
}
.netbar-inner {
  max-width: var(--w-wide);
  margin-inline: auto;
  padding: var(--s-4) var(--gutter);
  display: flex;
  align-items: center;
  gap: var(--s-6);
}
.brand {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-decoration: none;
  color: var(--ink);
}
.brand .brand-name {
  font-family: var(--ff-mono);
  font-weight: 500;
  font-size: 1rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}
.brand .brand-name::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: var(--s-2);
  background: var(--accent);
  vertical-align: baseline;
}
.brand .brand-locale {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--ink-3);
  border-top: 1px solid var(--hairline);
  padding-top: 2px;
}
.netbar nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: var(--s-5);
}
.netbar nav a:not(.btn) {
  color: var(--ink-2);
  text-decoration: none;
  font-size: var(--fs-sm);
  font-weight: 500;
  padding: var(--s-2) 0;
  border-bottom: 2px solid transparent;
  transition: color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out);
}
.netbar nav a:not(.btn):hover,
.netbar nav a:not(.btn)[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}
@media (max-width: 860px) {
  .netbar nav a:not(.btn) { display: none; } /* build team: wire disclosure menu */
}

/* ---------- Breadcrumbs ---------- */
.breadcrumbs {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  color: var(--ink-3);
  padding-block: var(--s-4);
}
.breadcrumbs ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
}
.breadcrumbs li + li::before { content: "/"; margin-right: var(--s-2); color: var(--faint); }
.breadcrumbs a { color: var(--ink-3); text-decoration: none; }
.breadcrumbs a:hover { color: var(--accent); text-decoration: underline; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  min-height: 48px;
  padding: var(--s-3) var(--s-6);
  border-radius: var(--r-1);
  border: 1px solid transparent;
  font-family: var(--ff-body);
  font-size: var(--fs-sm);
  font-weight: 600;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              color var(--t-fast) var(--ease-out);
}
.btn-primary {
  background: var(--accent);
  color: var(--on-accent);
}
.btn-primary:hover { background: var(--accent-deep); }
.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--hairline-strong);
}
.btn-ghost:hover { border-color: var(--accent); color: var(--accent-deep); }

/* Tertiary: drawn-underline text link */
.link-draw {
  color: var(--accent-deep);
  font-weight: 600;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size var(--t-med) var(--ease-out);
  padding-bottom: 2px;
}
.link-draw:hover { background-size: 100% 1px; }
.link-draw::after { content: " →"; }

/* ---------- Cards (top-rule, not boxes) ---------- */
.card {
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-5);
  position: relative;
}
.card::before {
  /* accent tick that grows on hover — the only card motion */
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  width: 32px;
  border-top: 2px solid var(--accent);
  transition: width var(--t-med) var(--ease-out);
}
.card:hover::before { width: 100%; }
.card h3 {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 40;
  font-size: var(--fs-h3);
  margin: 0 0 var(--s-3);
}
.card p { color: var(--ink-2); font-size: var(--fs-sm); margin: 0 0 var(--s-4); }
.card .card-figure {
  font-family: var(--ff-mono);
  font-size: var(--fs-sm);
  color: var(--ink);
  font-weight: 500;
}

/* ---------- Tables (one of the 3 sanctioned boxes) ---------- */
.table-frame {
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-0);
  overflow-x: auto;
  background: var(--paper-raised);
}
table.data {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--fs-sm);
}
table.data caption {
  text-align: left;
  padding: var(--s-4) var(--s-5);
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-size: var(--fs-h3);
  border-bottom: 1px solid var(--hairline);
}
table.data th {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  text-align: left;
  color: var(--ink-3);
  padding: var(--s-3) var(--s-5);
  border-bottom: 1px solid var(--hairline-strong);
}
table.data td {
  padding: var(--s-4) var(--s-5);
  border-bottom: 1px solid var(--hairline);
  color: var(--ink-2);
  vertical-align: top;
}
table.data tr:last-child td { border-bottom: none; }
table.data td.figure {
  font-family: var(--ff-mono);
  font-weight: 500;
  color: var(--ink);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}
table.data tbody tr { transition: background-color var(--t-fast) var(--ease-out); }
table.data tbody tr:hover { background: var(--accent-wash); }

/* ---------- Stat blocks ---------- */
.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: var(--grid-gap);
}
.stat {
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-4);
}
.stat .stat-value {
  font-family: var(--ff-display);
  font-weight: var(--display-stat-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 144;
  font-size: var(--fs-stat);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.stat .stat-value em {
  font-style: normal;
  color: var(--accent);
}
.stat .stat-label {
  display: block;
  margin-top: var(--s-2);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* ---------- Quote / testimonial frame ---------- */
.quote {
  border-left: 2px solid var(--accent);
  padding: var(--s-2) 0 var(--s-2) var(--s-6);
  max-width: var(--measure-lede);
}
.quote blockquote {
  margin: 0;
  font-family: var(--ff-display);
  font-weight: 400;
  font-style: italic;
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 30;
  font-size: var(--fs-h3);
  line-height: 1.45;
  color: var(--ink);
}
.quote figcaption {
  margin-top: var(--s-4);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}

/* ---------- Plates: the empty photo frames ---------- */
figure.plate { margin: 0; }
.plate-frame {
  position: relative;
  border: 1px solid var(--hairline-strong);
  background:
    /* drafting X — two hairline diagonals, the draughtsman's void */
    linear-gradient(to top right,
      transparent calc(50% - 0.5px),
      color-mix(in srgb, var(--faint) 40%, transparent) 50%,
      transparent calc(50% + 0.5px)),
    linear-gradient(to bottom right,
      transparent calc(50% - 0.5px),
      color-mix(in srgb, var(--faint) 40%, transparent) 50%,
      transparent calc(50% + 0.5px)),
    var(--accent-wash);
  border-radius: var(--r-0);
  display: grid;
  place-items: center;
  overflow: hidden;
}
.plate-frame.r-32 { aspect-ratio: 3 / 2; }
.plate-frame.r-45 { aspect-ratio: 4 / 5; }
.plate-frame.r-169 { aspect-ratio: 16 / 9; }
.plate-frame.r-11 { aspect-ratio: 1 / 1; }

.plate-frame::before {
  content: attr(data-plate);
  position: absolute;
  top: var(--s-3);
  left: var(--s-4);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  color: var(--ink-3);
}
.plate-frame::after {
  content: attr(data-spec);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  text-align: center;
  max-width: 75%;
  line-height: 1.7;
  background: var(--paper);
  padding: var(--s-2) var(--s-4);
  border: 1px solid var(--hairline);
}
/* When the real photo lands, the X, spec and wash disappear;
   frame, plate number, caption and source line remain. */
.plate-frame:has(img) { background: var(--paper-raised); }
.plate-frame:has(img)::after { display: none; }
.plate-frame img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}
figure.plate figcaption {
  margin-top: var(--s-3);
  font-size: var(--fs-sm);
  color: var(--ink-2);
}

/* Paint plates may carry a drawdown strip: place <div class="drawdown">
   immediately after .plate-frame inside the figure. Reno plates carry
   a .dim-line immediately BEFORE the frame. Hide either device on the
   other site so plates stay portable between the two codebases. */
html[data-site="reno"] figure.plate .drawdown { display: none; }
html[data-site="paint"] figure.plate .dim-line { display: none; }

/* ---------- Signature device: PAINT — the Drawdown ---------- */
.drawdown {
  height: 6px;
  background: linear-gradient(to right,
    var(--accent) 0 20%,
    color-mix(in srgb, var(--accent) 80%, var(--paper)) 20% 40%,
    color-mix(in srgb, var(--accent) 60%, var(--paper)) 40% 60%,
    color-mix(in srgb, var(--accent) 40%, var(--paper)) 60% 80%,
    color-mix(in srgb, var(--accent) 20%, var(--paper)) 80% 100%);
}
.drawdown.drawdown-hero { height: 10px; max-width: 320px; }

/* Swatch ledger */
.swatch-ledger {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: var(--s-4);
}
.swatch {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
}
.swatch .swatch-chip { height: 72px; }
.swatch .swatch-meta {
  padding: var(--s-3) var(--s-4);
  border-top: 1px solid var(--hairline);
}
.swatch .swatch-name { font-size: var(--fs-sm); font-weight: 600; color: var(--ink); }
.swatch .swatch-code {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.06em;
  color: var(--ink-3);
}

/* ---------- Signature device: RENO — the Dimension line ---------- */
.dim-line {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
  max-width: 480px;
}
.dim-line::before,
.dim-line::after {
  content: "";
  flex: 1;
  border-top: 1px solid var(--accent);
  position: relative;
}
.dim-line .tick-l,
.dim-line .tick-r {
  width: 1px;
  height: 12px;
  background: var(--accent);
  flex: none;
}
/* End ticks sit OUTSIDE the pseudo-element lines:
   markup is <span class="tick-l"></span> LABEL <span class="tick-r"></span> */
.dim-line .tick-l { order: -1; }
.dim-line .tick-r { order: 1; }

/* Section marker (crosshair bullet) */
.marker {
  display: inline-block;
  width: 14px;
  height: 14px;
  flex: none;
  border: 1px solid var(--accent);
  border-radius: 50%;
  position: relative;
}
.marker::before,
.marker::after {
  content: "";
  position: absolute;
  background: var(--accent);
}
.marker::before { left: 50%; top: -3px; bottom: -3px; width: 1px; transform: translateX(-50%); }
.marker::after { top: 50%; left: -3px; right: -3px; height: 1px; transform: translateY(-50%); }

/* Process timeline (reno) */
.timeline { list-style: none; margin: 0; padding: 0; }
.timeline li {
  display: grid;
  grid-template-columns: 14px 1fr;
  gap: var(--s-5);
  padding-block: var(--s-5);
  position: relative;
}
.timeline li:not(:last-child)::before {
  content: "";
  position: absolute;
  left: 6.5px;
  top: calc(var(--s-5) + 20px);
  bottom: calc(-1 * var(--s-2));
  border-left: 1px dashed var(--hairline-strong);
}
.timeline .marker { margin-top: 5px; }
.timeline h4 { margin: 0 0 var(--s-1); font-size: var(--fs-body); font-weight: 600; }
.timeline .timeline-span {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
}
.timeline p { margin: var(--s-1) 0 0; color: var(--ink-2); font-size: var(--fs-sm); max-width: var(--measure-lede); }

/* Proof list bullets: paint = swatch chips, reno = markers */
ul.proof-list { list-style: none; margin: var(--s-5) 0 0; padding: 0; display: grid; gap: var(--s-3); }
ul.proof-list li { display: flex; align-items: baseline; gap: var(--s-3); color: var(--ink-2); font-size: var(--fs-sm); }
html[data-site="paint"] ul.proof-list li::before {
  content: "";
  width: 10px;
  height: 10px;
  flex: none;
  background: var(--accent);
  transform: translateY(1px);
}
html[data-site="reno"] ul.proof-list li::before {
  content: "";
  width: 10px;
  height: 10px;
  flex: none;
  border: 1px solid var(--accent);
  border-radius: 50%;
  background:
    linear-gradient(var(--accent), var(--accent)) center / 1px 100% no-repeat,
    linear-gradient(var(--accent), var(--accent)) center / 100% 1px no-repeat;
  transform: translateY(1px);
}

/* ---------- Hero ---------- */
.hero { padding-block: clamp(var(--s-8), 9vw, var(--s-10)); }
.hero .grid { align-items: start; }
.hero h1 {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 144;
  font-size: var(--fs-hero);
  line-height: var(--lh-tight);
  letter-spacing: -0.015em;
  margin: var(--s-4) 0 var(--s-5);
  text-wrap: balance;
}
.hero .lede { margin: 0 0 var(--s-6); }
.hero-actions { display: flex; flex-wrap: wrap; gap: var(--s-4); align-items: center; }

/* Answer above the fold: the anchor figure */
.anchor-figure {
  margin: var(--s-7) 0 0;
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-4);
  max-width: var(--measure-lede);
}
.anchor-figure .anchor-value {
  font-family: var(--ff-mono);
  font-weight: 500;
  font-size: var(--fs-lg);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.anchor-figure .anchor-label { color: var(--ink-2); font-size: var(--fs-sm); }

/* ---------- Lead form (sanctioned box #2) ---------- */
.lead-panel {
  background: var(--paper-raised);
  border: 1px solid var(--hairline-strong);
  border-top: 3px solid var(--accent);
  box-shadow: var(--shadow-lift);
  padding: clamp(var(--s-5), 4vw, var(--s-7));
  border-radius: var(--r-0);
}
@media (max-width: 860px) { .lead-panel { border-radius: var(--r-2); } }
.lead-panel h2, .lead-panel h3 {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 40;
  font-size: var(--fs-h3);
  margin: 0 0 var(--s-2);
}
.lead-panel .lead-sub { color: var(--ink-2); font-size: var(--fs-sm); margin: 0 0 var(--s-5); }

.field { margin-bottom: var(--s-4); }
.field label {
  display: block;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
  margin-bottom: var(--s-2);
}
.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 48px;
  padding: var(--s-3) var(--s-4);
  font-family: var(--ff-body);
  font-size: var(--fs-body);
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-1);
  transition: border-color var(--t-fast) var(--ease-out);
}
.field textarea { min-height: 96px; resize: vertical; }
.field input:hover, .field select:hover, .field textarea:hover { border-color: var(--faint); }
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 0;
  border-color: var(--accent);
}
.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--s-4); }
@media (max-width: 480px) { .field-row { grid-template-columns: 1fr; } }
.lead-panel .btn { width: 100%; }
.lead-privacy {
  margin-top: var(--s-4);
  font-size: var(--fs-micro);
  color: var(--ink-3);
  text-align: center;
}

/* ---------- Cross-site handoff block ----------
   The ONE place the sibling's accent appears. */
.handoff {
  border: 1px solid var(--hairline-strong);
  border-left: 3px solid var(--sibling-accent);
  background: var(--sibling-wash);
  padding: var(--s-5) var(--s-6);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--s-4) var(--s-6);
}
.handoff .handoff-kicker {
  flex-basis: 100%;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.handoff .handoff-title {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-size: var(--fs-h3);
  margin: 0;
  flex: 1 1 320px;
}
.handoff a.handoff-link {
  color: var(--sibling-accent-deep);
  font-weight: 600;
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size var(--t-med) var(--ease-out);
  padding-bottom: 2px;
  white-space: nowrap;
}
.handoff a.handoff-link:hover { background-size: 100% 1px; }
.handoff a.handoff-link::after { content: " ↗"; }

/* ---------- Footer ---------- */
.site-footer {
  border-top: 1px solid var(--hairline-strong);
  margin-top: var(--s-9);
  padding-block: var(--s-8) var(--s-6);
  color: var(--ink-2);
  font-size: var(--fs-sm);
}
.site-footer .footer-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: var(--grid-gap);
}
@media (max-width: 860px) { .site-footer .footer-grid { grid-template-columns: 1fr; } }
.site-footer h4 {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 var(--s-3);
}
.site-footer ul { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); }
.site-footer a { color: var(--ink-2); text-decoration: none; }
.site-footer a:hover { color: var(--accent-deep); text-decoration: underline; }
.footer-studio {
  margin-top: var(--s-7);
  padding-top: var(--s-4);
  border-top: 1px solid var(--hairline);
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--s-3);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.05em;
  color: var(--ink-3);
}

/* ---------- Reveal utility (opacity + 12px rise, once) ---------- */
@keyframes rise {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: none; }
}
.reveal { animation: rise var(--t-slow) var(--ease-out) both; }
.reveal-2 { animation: rise var(--t-slow) var(--ease-out) 80ms both; }
.reveal-3 { animation: rise var(--t-slow) var(--ease-out) 160ms both; }

/* ===== extra.css ===== */
/* ============================================================
   extra.css — the build layer on top of the design system.
   Loaded AFTER tokens.css and components.css. Adds only what the
   system does not cover: mobile nav, the portfolio ring bar, FAQ,
   steps, callouts, honest-placeholder blocks, calculators, and the
   data displays (zone bars, mini charts, suburb index).
   Uses ONLY design-system tokens. No new colours, no new radii.
   ============================================================ */

/* ---------- [hidden] must actually hide ----------
   The design system sets .btn { display: inline-flex }, and an explicit
   display always beats the UA's [hidden] { display: none }. Without this
   rule every step of the qualifying brief renders at once — Back, Continue
   and Send all visible together. This is the fix, and it has to be
   !important because the competing rule is a plain class selector. */
[hidden] { display: none !important; }

/* ---------- Mobile primary nav ----------
   The system's .netbar assumes a wide viewport. Below 860px the nav
   collapses behind a toggle. Progressive: with no JS the nav stays
   visible and simply stacks, rather than becoming unreachable. */
.nav-toggle {
  display: none;
  margin-left: auto;
  background: none;
  border: 1px solid var(--hairline-strong);
  color: var(--ink);
  padding: var(--s-2);
  border-radius: var(--r-1);
  cursor: pointer;
  line-height: 0;
}
.nav-toggle:hover { border-color: var(--accent); color: var(--accent); }

@media (max-width: 860px) {
  .js .nav-toggle { display: block; }
  .netbar-inner { gap: var(--s-4); }
  .js .netbar nav {
    display: none;
    flex-basis: 100%;
    margin-left: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding-top: var(--s-3);
  }
  .js .netbar nav[data-open] { display: flex; }
  .js .netbar nav a:not(.btn) {
    padding: var(--s-3) 0;
    border-bottom: 1px solid var(--hairline);
  }
  .js .netbar nav .btn { margin-top: var(--s-3); text-align: center; }
  /* No-JS fallback: let it wrap and stay reachable. */
  html:not(.js) .netbar nav { flex-wrap: wrap; row-gap: var(--s-3); }
}

/* ---------- Skip link ---------- */
.skip-link:focus-visible { z-index: 100; }

/* ---------- Ring bar ----------
   The portfolio's sibling-site strip. Deliberately quieter than the
   primary nav: it is a courtesy to the reader, not a call to action.
   Capped at 7 links by the rulebook (enforced in components.mjs). */
.ringbar {
  border-top: 1px solid var(--hairline);
  background: var(--paper-raised);
  padding-block: var(--s-5);
  font-size: var(--fs-sm);
}
.ringbar .ringbar-in {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--s-3) var(--s-5);
}
.ringbar-h {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.ringbar ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-5);
}
.ringbar a { color: var(--ink-2); text-decoration: none; }
.ringbar a:hover { color: var(--accent-deep); text-decoration: underline; }

/* ---------- FAQ ---------- */
.faq-list { display: grid; gap: 0; border-top: 1px solid var(--hairline); }
.faq-list details { border-bottom: 1px solid var(--hairline); }
.faq-list summary {
  cursor: pointer;
  padding: var(--s-4) var(--s-6) var(--s-4) 0;
  font-weight: 600;
  position: relative;
  list-style: none;
  transition: color var(--t-fast) var(--ease-out);
}
.faq-list summary::-webkit-details-marker { display: none; }
.faq-list summary:hover { color: var(--accent-deep); }
.faq-list summary::after {
  content: "+";
  position: absolute;
  right: 0;
  top: var(--s-4);
  font-family: var(--ff-mono);
  color: var(--ink-3);
  transition: transform var(--t-med) var(--ease-out);
}
.faq-list details[open] summary::after { transform: rotate(45deg); }
.faq-a {
  padding-bottom: var(--s-5);
  color: var(--ink-2);
  max-width: var(--measure);
}
.faq-a > :first-child { margin-top: 0; }
.faq-a > :last-child { margin-bottom: 0; }

/* ---------- Numbered steps ---------- */
.step-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--s-6);
  counter-reset: step;
}
.step-list li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s-5);
  align-items: start;
  padding-top: var(--s-5);
  border-top: 1px solid var(--hairline);
}
.step-n {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  color: var(--accent);
  letter-spacing: 0.06em;
  padding-top: 3px;
}
.step-list h3 {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-size: var(--fs-h3);
  margin: 0 0 var(--s-2);
  line-height: var(--lh-head);
}
.step-list p { margin: 0; color: var(--ink-2); max-width: var(--measure-lede); }

/* ---------- Callout ---------- */
.callout {
  border: 1px solid var(--hairline-strong);
  border-left: 3px solid var(--accent);
  background: var(--paper-raised);
  padding: var(--s-5);
  margin-block: var(--s-6);
  max-width: var(--measure);
}
.callout[data-tone="warn"] { border-left-color: var(--accent-deep); background: var(--accent-wash); }
.callout-h {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 var(--s-2);
}
.callout > :last-child { margin-bottom: 0; }
.callout p { margin: 0 0 var(--s-3); }

/* ---------- Honest placeholders ----------
   Used where real proof will go. Reads as a deliberate reservation,
   not a broken component — because saying "nothing yet" is more
   trustworthy than inventing five-star reviews. */
.proof-pending {
  border: 1px dashed var(--hairline-strong);
  padding: var(--s-5);
  color: var(--ink-3);
  font-size: var(--fs-sm);
  max-width: var(--measure);
}
.proof-pending p { margin: 0; }

/* The "who actually does the work" disclosure. Appears while the
   operator is unconfirmed, and must stay legible — not fine print. */
.disclosure {
  border-top: 1px solid var(--hairline-strong);
  border-bottom: 1px solid var(--hairline-strong);
  padding-block: var(--s-5);
  margin-block: var(--s-7);
}
.disclosure p {
  margin: 0;
  max-width: var(--measure);
  color: var(--ink-2);
  font-size: var(--fs-sm);
}
.disclosure strong { color: var(--ink); }

/* ---------- Calculators ---------- */
.calc {
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  padding: var(--s-6);
  display: grid;
  gap: var(--s-5);
}
.calc-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--s-4); }
@media (max-width: 560px) { .calc-grid { grid-template-columns: 1fr; } }
.calc-out {
  border-top: 1px solid var(--hairline-strong);
  padding-top: var(--s-5);
  display: grid;
  gap: var(--s-2);
}
.calc-out-value {
  font-family: var(--ff-display);
  font-weight: var(--display-stat-wght);
  font-size: var(--fs-stat);
  line-height: var(--lh-tight);
  font-variant-numeric: tabular-nums;
  letter-spacing: var(--track-head);
}
.calc-out-label { color: var(--ink-2); font-size: var(--fs-sm); max-width: var(--measure-lede); }
.calc-working {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  color: var(--ink-3);
  border-left: 1px solid var(--hairline-strong);
  padding-left: var(--s-4);
  display: grid;
  gap: var(--s-1);
}
.calc-working b { font-weight: 500; color: var(--ink-2); }
.calc noscript p { color: var(--accent-deep); }

/* ---------- The qualifying brief ----------
   Layered on the design system's .lead-panel. With no JS every step is
   visible and the form is a plain long form that posts — the [data-js]
   attribute (set by the script) is what enables the stepped behaviour. */
.brief-step { border: 0; margin: 0; padding: 0; }
.brief-step + .brief-step { margin-top: var(--s-5); }
.lead-panel[data-js] .brief-step + .brief-step { margin-top: 0; }

.brief-nav { display: flex; gap: var(--s-3); margin-top: var(--s-5); }
/* The system sets .lead-panel .btn to 100%; the nav needs them side by side. */
.brief-nav .btn { width: auto; flex: 1 1 auto; }

.field-note {
  margin: var(--s-2) 0 0;
  font-size: var(--fs-sm);
  color: var(--ink-2);
  border-left: 2px solid var(--hairline-strong);
  padding-left: var(--s-3);
}
.field-note[data-tone="warn"] { border-left-color: var(--accent); color: var(--ink); }
.field-note a { color: var(--accent-deep); }

.field .opt {
  font-family: var(--ff-body);
  text-transform: none;
  letter-spacing: 0;
  color: var(--faint);
}
.field [aria-invalid="true"] { border-color: var(--accent); }

.brief-blocked {
  margin-top: var(--s-5);
  border: 1px solid var(--accent);
  background: var(--accent-wash);
  padding: var(--s-5);
  font-size: var(--fs-sm);
}
.brief-blocked p { margin: 0; }
.brief-blocked a { color: var(--accent-deep); }

/* ---------- Zone / share bars ----------
   A stacked hairline bar. Used for Unitary Plan zone mix and dwelling
   mix. A <span> used as a bar needs display:block or width is ignored. */
.share-bar {
  display: flex;
  height: 10px;
  border: 1px solid var(--hairline-strong);
  overflow: hidden;
  margin-block: var(--s-3) var(--s-2);
}
.share-bar span { display: block; height: 100%; }
.share-bar span:nth-child(1) { background: var(--accent); }
.share-bar span:nth-child(2) { background: color-mix(in srgb, var(--accent) 62%, var(--paper)); }
.share-bar span:nth-child(3) { background: color-mix(in srgb, var(--accent) 40%, var(--paper)); }
.share-bar span:nth-child(4) { background: color-mix(in srgb, var(--accent) 24%, var(--paper)); }
.share-bar span:nth-child(5) { background: color-mix(in srgb, var(--accent) 14%, var(--paper)); }
.share-bar span:nth-child(n + 6) { background: var(--hairline-strong); }

.share-key { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--s-2); font-size: var(--fs-sm); }
.share-key li { display: grid; grid-template-columns: 10px 1fr auto; gap: var(--s-3); align-items: baseline; }
.share-key i { display: block; height: 10px; width: 10px; margin-top: 5px; }
.share-key li:nth-child(1) i { background: var(--accent); }
.share-key li:nth-child(2) i { background: color-mix(in srgb, var(--accent) 62%, var(--paper)); }
.share-key li:nth-child(3) i { background: color-mix(in srgb, var(--accent) 40%, var(--paper)); }
.share-key li:nth-child(4) i { background: color-mix(in srgb, var(--accent) 24%, var(--paper)); }
.share-key li:nth-child(5) i { background: color-mix(in srgb, var(--accent) 14%, var(--paper)); }
.share-key li:nth-child(n + 6) i { background: var(--hairline-strong); }
.share-key .k-val { font-family: var(--ff-mono); font-size: var(--fs-mono); color: var(--ink-2); }

/* ---------- Mini bar chart (12-month / monthly series) ---------- */
.mini-chart { display: flex; align-items: flex-end; gap: 2px; height: 76px; margin-block: var(--s-4) var(--s-2); }
.mini-chart span {
  display: block;
  flex: 1;
  min-width: 3px;
  background: color-mix(in srgb, var(--accent) 40%, var(--paper));
  border-top: 1px solid var(--accent);
}
.mini-chart span[data-peak] { background: var(--accent); }
.mini-axis {
  display: flex;
  justify-content: space-between;
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  color: var(--ink-3);
  letter-spacing: 0.04em;
}

/* ---------- Suburb index ---------- */
.index-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  columns: 4 14rem;
  column-gap: var(--s-6);
}
.index-grid li { break-inside: avoid; padding: var(--s-1) 0; font-size: var(--fs-sm); }
.index-grid a { color: var(--ink); text-decoration: none; }
.index-grid a:hover { color: var(--accent-deep); text-decoration: underline; }
.index-grid .idx-meta { color: var(--ink-3); font-family: var(--ff-mono); font-size: var(--fs-micro); }

.alpha-jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s-2);
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  margin-block: var(--s-5);
}
.alpha-jump a {
  border: 1px solid var(--hairline-strong);
  padding: 2px var(--s-2);
  color: var(--ink-2);
  text-decoration: none;
}
.alpha-jump a:hover { border-color: var(--accent); color: var(--accent-deep); }

/* ---------- Card grid ---------- */
.card-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); gap: var(--s-5); }

/* ---------- Prose defaults ---------- */
.prose { max-width: var(--measure); }
.prose > :first-child { margin-top: 0; }
.prose h3 {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-size: var(--fs-h3);
  line-height: var(--lh-head);
  margin: var(--s-7) 0 var(--s-3);
}
.prose p { margin: 0 0 var(--s-4); color: var(--ink-2); }
.prose ul, .prose ol { margin: 0 0 var(--s-5); padding-left: var(--s-5); color: var(--ink-2); }
.prose li { margin-bottom: var(--s-2); }
.prose a { color: var(--accent-deep); text-underline-offset: 2px; }
.prose strong { color: var(--ink); font-weight: 600; }

/* Tabular numerals wherever a figure appears inline in prose. */
.num, .figure, td.figure { font-variant-numeric: tabular-nums; }

/* ---------- Utility ---------- */
.stack-6 { display: grid; gap: var(--s-6); }
.stack-5 { display: grid; gap: var(--s-5); }
.tight { margin-top: 0; }
.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* Grid children default to min-width:auto, so a wide table inside a
   grid column forces the whole page to scroll sideways on mobile. */
.grid > * { min-width: 0; }

/* ============================================================ LCP guard ==== */
/* `.reveal` runs `rise`, which animates from opacity:0 over 420ms. Wherever that
   wrapper contains the page's <h1> — both home heroes, and every reno suburb
   page — the Largest Contentful Paint element is invisible for those 420ms, so
   the animation is directly buying a worse LCP on the pages search sends people to.

   Worse than slow: it is fragile. The design contract says content must never
   depend on animation to be visible, and an element parked at opacity:0 waiting
   on an animation that (for any reason) never runs is exactly that failure.

   So where a reveal wrapper holds the h1, keep the motion and drop the fade. The
   headline paints immediately at full opacity and still settles into place.
   :has() is progressive — where it is unsupported nothing matches and the
   behaviour is simply what it was before, never broken. */
@keyframes rise-nofade {
  from { transform: translateY(12px); }
  to   { transform: none; }
}
.reveal:has(h1),
.reveal-2:has(h1),
.reveal-3:has(h1) {
  animation-name: rise-nofade;
}

/* ===== depth.css ===== */
/* ============================================================
   TRADES depth.css — the dimensional layer. v1.0 — 2026-07-30
   Loads AFTER tokens.css, components.css and extra.css.

   Doctrine:
   · Depth here means architectural drawing and real materials —
     a plate stack, a dimension line that extends itself, a
     photograph drifting a few millimetres behind its caption
     apparatus. Nothing spins, tilts, glows or floats.
   · CSS scroll-driven animations (animation-timeline) are the
     ONLY motion engine. They run off the main thread, cost
     transform/opacity/clip only, and need zero JavaScript.
   · Every scroll effect lives inside
       @supports (animation-timeline: scroll()) { … }
     Outside that block each class is either inert or a purely
     static composition, so an unsupporting browser renders a
     complete, intentional page — never a blank or broken one.
   · No element in this file starts at opacity:0 outside the
     @supports block. Inside it, the only opacity animation
     (.fx-rise) uses an ENTRY range, which by geometry always
     reaches 100% — even for the last element on the page,
     because maximum scroll puts its bottom edge at the
     viewport bottom, which IS entry 100%.
   · prefers-reduced-motion: the global 1ms rule in tokens.css
     does NOT neutralise scroll-driven animations (progress-based
     timelines ignore duration), so this file carries its own
     kill block at the end. Do not remove it.
   · Tokens only. No new hex values, no new radii, no new fonts.
     The few lengths that tune the effects are file-local custom
     props declared below, derived from nothing brand-level —
     they are physics, not identity, so they do not belong in
     tokens.css.
   ============================================================ */

:root {
  /* Effect physics — local to this layer */
  --fx-drift: 24px;      /* parallax travel inside a plate frame  */
  --fx-rise: 18px;       /* settle distance for scroll reveals    */
  --fx-exit: 20px;       /* hero exit drift                       */
  --fx-folio-drift: 36px;/* ghost numeral travel                  */
}

/* ============================================================
   PART 1 — STATIC COMPOSITIONS
   These carry the page even where animation-timeline is
   unsupported and where reduced-motion is on. They are the
   fallback state, designed first.
   ============================================================ */

/* ---------- 1.1 The plate stack ----------
   A photograph presented as the top sheet of a stack of plates:
   one offset understack frame behind the real frame. Physical
   depth with zero shadow, zero blur, zero motion — an object on
   a desk, not a card in an app.
   Markup: add .plate-stack to figure.plate.
   Cost: two positioned pseudo-boxes, painted once. */
.plate-stack { position: relative; }
.plate-stack .plate-frame { position: relative; z-index: 1; }
.plate-stack::before {
  content: "";
  position: absolute;
  z-index: 0;
  top: calc(-1 * var(--s-3));
  right: calc(-1 * var(--s-3));
  width: 60%;
  height: 55%;
  border: 1px solid var(--hairline-strong);
  background: var(--accent-wash);
}
/* Keep the understack inside the column on small screens */
@media (max-width: 860px) {
  .plate-stack::before { right: 0; top: calc(-1 * var(--s-2)); }
}

/* ---------- 1.2 Plate number chip over photographs ----------
   components.css renders the mono plate number (data-plate)
   directly on the frame. Over the accent-wash empty state that
   is legible; over a real photograph it is not guaranteed. When
   an image is present the number sits on a paper chip — the
   catalogue tag on a printed plate. ink-3 on paper = 4.92:1 (AA). */
.plate-frame:has(img)::before {
  background: var(--paper);
  padding: 2px var(--s-2);
  border: 1px solid var(--hairline);
  z-index: 2;
}

/* ---------- 1.3 The caption apparatus ----------
   Caption + dated source line arranged like a monograph plate
   listing: a hairline, then caption left and source right on
   desktop. Markup: wrap figcaption + .source-line in
   <div class="plate-meta">. Degrades to a stacked column. */
.plate-meta {
  border-top: 1px solid var(--hairline);
  margin-top: var(--s-3);
  padding-top: var(--s-3);
}
.plate-meta figcaption { margin-top: 0; }
@media (min-width: 861px) {
  .plate-meta {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: var(--s-5);
  }
  .plate-meta .source-line { margin-top: 0; text-align: right; flex: none; max-width: 45%; }
}

/* ---------- 1.4 The anchor monument ----------
   The single sourced number promoted from a footnote-weight
   block to the most important object on the page: a full-width
   band under the hero, keel-ruled, with the figure set in the
   system's giant-numeral voice (Fraunces 300, opsz 144).
   Static composition — no motion required to work. */
.anchor-monument {
  border-top: 2px solid var(--accent);
  border-bottom: 1px solid var(--hairline);
  margin-top: clamp(var(--s-7), 6vw, var(--s-9));
  padding-block: clamp(var(--s-6), 5vw, var(--s-8));
  display: grid;
  grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--grid-gap);
  align-items: start;
}
@media (max-width: 860px) { .anchor-monument { grid-template-columns: 1fr; } }
.anchor-monument .monument-value {
  font-family: var(--ff-display);
  font-weight: var(--display-stat-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 144;
  font-size: clamp(3.25rem, 1.4rem + 6.4vw, 6rem);
  line-height: 0.95;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
  margin: 0;
}
.anchor-monument .monument-kicker {
  display: block;
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
  margin-bottom: var(--s-3);
}
.anchor-monument .monument-note { color: var(--ink-2); font-size: var(--fs-sm); margin: 0; max-width: var(--measure-lede); }
.anchor-monument .monument-note a { color: var(--accent-deep); }
/* The dimension underline that (with support) extends itself */
.anchor-monument .monument-rule {
  height: 1px;
  background: var(--accent);
  margin-top: var(--s-4);
  max-width: 420px;
}

/* ---------- 1.5 Ghost folio numerals ----------
   Oversized section numerals (data-folio="02") behind section
   headers — the monograph's chapter folio. --faint at reduced
   alpha, decorative, aria-irrelevant (empty alt-text form of
   attr() where supported; the numeral duplicates the visible
   section order so it carries no unique information).
   Static by default; drifts a few px under Part 2. */
.fx-folio { position: relative; }
.fx-folio > .section-head,
.fx-folio > * { position: relative; z-index: 1; }
.fx-folio::before {
  content: attr(data-folio);
  position: absolute;
  z-index: 0;
  top: calc(-1 * var(--s-6));
  right: 0;
  font-family: var(--ff-display);
  font-weight: var(--display-stat-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 144;
  font-size: clamp(6rem, 3rem + 12vw, 13rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: color-mix(in srgb, var(--faint) 26%, transparent);
  pointer-events: none;
  user-select: none;
}
@supports (content: attr(data-folio) / "") {
  .fx-folio::before { content: attr(data-folio) / ""; } /* silent to AT */
}

/* ---------- 1.6 Raised band ----------
   One neutral rhythm device: a full-bleed section on
   --paper-raised between hairlines. It breaks the single-column
   plateau without touching the accent-wash prohibition (the
   band is a neutral surface step, exactly how dark mode already
   expresses elevation). Use at most twice per page. */
.band-raised {
  background: var(--paper-raised);
  border-top: 1px solid var(--hairline);
  border-bottom: 1px solid var(--hairline);
}
.band-raised + .section { border-top: 0; } /* avoid a doubled rule */

/* ---------- 1.7 The grand handoff ----------
   The cross-site recommendation promoted from a footer-adjacent
   strip to a considered introduction: sibling keel, display-size
   title, one sentence of judgement, one link. Still the only
   place the sibling accent appears. Static. */
.handoff-grand {
  border-top: 2px solid var(--sibling-accent);
  border-bottom: 1px solid var(--hairline-strong);
  background: var(--sibling-wash);
  padding: clamp(var(--s-6), 6vw, var(--s-8)) 0;
}
.handoff-grand .handoff-kicker {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
  margin: 0 0 var(--s-3);
}
.handoff-grand .handoff-title {
  font-family: var(--ff-display);
  font-weight: var(--display-wght);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 72;
  font-size: var(--fs-h2);
  line-height: var(--lh-head);
  margin: 0 0 var(--s-4);
  max-width: 24ch;
  text-wrap: balance;
}
.handoff-grand p { color: var(--ink-2); max-width: var(--measure-lede); margin: 0 0 var(--s-5); }
.handoff-grand a.handoff-link {
  color: var(--sibling-accent-deep);
  font-weight: 600;
  font-size: var(--fs-lg);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0% 1px;
  transition: background-size var(--t-med) var(--ease-out);
  padding-bottom: 2px;
}
.handoff-grand a.handoff-link:hover { background-size: 100% 1px; }
.handoff-grand a.handoff-link::after { content: " ↗"; }

/* ============================================================
   PART 2 — SCROLL-DRIVEN MOTION
   Everything below exists only where the browser supports
   scroll timelines. Each animation is transform/opacity/clip
   only, runs on the compositor, and maps deterministically to
   scroll position (no timers, no rAF, no listeners).
   ============================================================ */
@supports (animation-timeline: scroll()) {

  /* ---- 2.1 Page progress keel (.fx-progress) ----
     A 2px accent hairline across the very top of the viewport
     that extends with reading progress — the dimension line
     measuring the document itself. display:none outside this
     block, so unsupporting browsers never see a dead strip.
     Cost: one 2px compositor layer, scaleX only. */
  .fx-progress {
    display: block;
    position: fixed;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: var(--accent);
    transform-origin: 0 50%;
    z-index: 60;
    pointer-events: none;
    animation: fx-scalex linear both;
    animation-timeline: scroll(root block);
  }

  /* ---- 2.2 Settle reveal (.fx-rise) ----
     The scroll-time sibling of components.css .reveal: sections
     settle 18px into place as they enter. ENTRY range only —
     entry 100% is always reachable (see header note), so the
     end state is guaranteed visible by pure CSS geometry.
     NEVER apply above the fold (hero keeps .reveal) and never
     together with .reveal on the same element — the animation
     shorthands would fight. */
  .fx-rise {
    animation: fx-rise linear both;
    animation-timeline: view(block);
    animation-range: entry 5% entry 55%;
  }

  /* ---- 2.3 Plate parallax (.fx-parallax on figure.plate) ----
     The photograph drifts a few millimetres slower than its
     frame and caption apparatus — the one true parallax in the
     system, confined inside the plate's overflow:hidden frame.
     The img is oversized by 2×drift so coverage never breaks.
     Cost: translate3d on an already-composited image layer. */
  .fx-parallax .plate-frame img {
    height: calc(100% + (2 * var(--fx-drift)));
    top: calc(-1 * var(--fx-drift));
    animation: fx-drift linear both;
    animation-timeline: view(block);
    animation-range: cover 0% cover 100%;
  }

  /* ---- 2.4 Keel draw (.fx-keel on .section-head) ----
     The section keel rule draws itself left→right as the header
     enters — sanctioned by DESIGN-SYSTEM §4 ("the keel rule may
     draw in"). Fallback: the keel is simply there. */
  .fx-keel .kicker::before {
    transform-origin: left center;
    animation: fx-scalex linear both;
    animation-timeline: view(block);
    animation-range: entry 10% entry 50%;
  }

  /* ---- 2.5 Dimension line extends (.fx-dim on .dim-line) ----
     RENO signature. The two measuring lines grow outward from
     the label toward their end ticks as the element enters.
     Fallback: the finished dimension line. */
  .fx-dim.dim-line::before,
  .fx-dim .dim-line::before {
    transform-origin: right center;
    animation: fx-scalex linear both;
    animation-timeline: view(block);
    animation-range: entry 0% entry 60%;
  }
  .fx-dim.dim-line::after,
  .fx-dim .dim-line::after {
    transform-origin: left center;
    animation: fx-scalex linear both;
    animation-timeline: view(block);
    animation-range: entry 0% entry 60%;
  }

  /* ---- 2.6 Drawdown paints in (.fx-paint on .drawdown) ----
     PAINT signature. The drawdown strip is pulled across like a
     drawdown card — clip-path inset from the right recedes as
     the strip enters. clip on a 6–10px strip is a trivial paint.
     Fallback: the finished drawdown. */
  .fx-paint {
    animation: fx-paint linear both;
    animation-timeline: view(block);
    animation-range: entry 0% entry 70%;
  }

  /* ---- 2.7 Hero exit drift (.fx-exit-drift) ----
     As the reader scrolls away, the hero plate lifts slightly
     faster than the text column — two sheets of paper
     separating. EXIT range only; at rest the transform is none,
     so the unsupported/reduced state is exactly the layout. */
  .fx-exit-drift {
    animation: fx-exit linear both;
    animation-timeline: view(block);
    animation-range: exit 0% exit 100%;
  }

  /* ---- 2.8 Ghost folio drift ----
     The chapter numeral moves against the scroll a little
     slower than the text in front of it — background sheet vs
     foreground sheet. Decorative element only; ±36px. */
  .fx-folio::before {
    animation: fx-folio linear both;
    animation-timeline: view(block);
    animation-range: cover 0% cover 100%;
  }

  /* ---- 2.9 Monument rule extends ----
     The 1px accent rule under the anchor monument's numeral
     extends across as the monument enters — the site measuring
     its own headline figure. */
  .anchor-monument .monument-rule {
    transform-origin: left center;
    animation: fx-scalex linear both;
    animation-timeline: view(block);
    animation-range: entry 0% entry 80%;
  }

  /* ---- Keyframes (shared) ---- */
  @keyframes fx-scalex {
    from { transform: scaleX(0); }
    to   { transform: scaleX(1); }
  }
  @keyframes fx-rise {
    from { opacity: 0; transform: translateY(var(--fx-rise)); }
    to   { opacity: 1; transform: none; }
  }
  @keyframes fx-drift {
    from { transform: translate3d(0, calc(-1 * var(--fx-drift)), 0); }
    to   { transform: translate3d(0, var(--fx-drift), 0); }
  }
  @keyframes fx-paint {
    from { clip-path: inset(0 100% 0 0); }
    to   { clip-path: inset(0 0 0 0); }
  }
  @keyframes fx-exit {
    from { transform: none; }
    to   { transform: translateY(calc(-1 * var(--fx-exit))); }
  }
  @keyframes fx-folio {
    from { transform: translateY(var(--fx-folio-drift)); }
    to   { transform: translateY(calc(-1 * var(--fx-folio-drift))); }
  }
}

/* Outside @supports: the progress keel must not exist at all. */
.fx-progress { display: none; }
@supports (animation-timeline: scroll()) { .fx-progress { display: block; } }

/* ============================================================
   PART 3 — REDUCED MOTION KILL BLOCK (do not remove)
   Scroll-driven animations ignore animation-duration, so the
   1ms rule in tokens.css does not stop them. This block does.
   Every effect's base state is the complete, finished layout,
   so switching them off simply ships the finished page.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .fx-progress { display: none !important; }
  .fx-rise,
  .fx-exit-drift,
  .fx-paint,
  .fx-folio::before,
  .fx-parallax .plate-frame img,
  .fx-keel .kicker::before,
  .fx-dim.dim-line::before,
  .fx-dim.dim-line::after,
  .fx-dim .dim-line::before,
  .fx-dim .dim-line::after,
  .anchor-monument .monument-rule {
    animation: none !important;
  }
  /* Parallax img reverts to exact-fit so no oversize crop shift */
  .fx-parallax .plate-frame img { height: 100%; top: 0; }
}

/* ===== inner.css ===== */
/* ============================================================
   TRADES inner.css — the inner-page layer. v1.0 — 2026-08-03
   Loads AFTER tokens.css, components.css, extra.css AND depth.css.

   What this layer is:
   The home pages carry the composition — monument, folios, plates,
   raised bands, scroll motion. The other 577 pages carry none of it.
   This layer gives the inner pages their own devices, designed for
   the constraint that makes inner pages different: 492 of them are
   suburb pages with NO photograph of their own subject, generated
   from data, landed on cold from Google.

   The devices:
     .hero-inner   the inner-page hero grid (asymmetric, like home)
     .spec-card    a drafting title block — the suburb as an object
     .posline      the distribution scale — where THIS page's figure
                   sits between Auckland's lowest and highest
     .section-crest  the one crescendo section on a long data page
     .table-frame.frame-major  the page's central table, promoted
     .inst / .inst-head / .calc-out readout  the calculator as an
                   instrument rather than a form

   Same three guarantees as depth.css, enforced by construction:
   1. Zero runtime dependencies. Pure CSS; the only motion engine is
      animation-timeline inside @supports (animation-timeline: scroll()).
   2. Complete without support. Every class below is a finished static
      composition first. Nothing in this file starts at opacity:0 —
      the two scroll effects here animate transform only, and their
      base state is the finished layout.
   3. Reduced motion = finished page. The global 1ms rule does NOT
      stop scroll-driven animations, so this file carries its own
      kill block at the end. Never add a scroll effect without
      registering it there.

   Colour: tokens only. No new hex values. Every text-on-surface pair
   in this file already has its ratio stated in DESIGN-SYSTEM §1
   (ink / ink-2 / ink-3 / accent on paper and paper-raised). The only
   new non-text surfaces are accent↔paper mixes at ≤40%, which carry
   no text — same contract as the share bars in extra.css.
   ============================================================ */

/* ============================================================
   PART 1 — STATIC COMPOSITIONS
   ============================================================ */

/* ---------- 1.1 Inner-page hero (.hero-inner) ----------
   The suburb/cost/tool hero as a 7/5 asymmetric grid — the house
   move from the home pages, at a slightly smaller register. The
   left column carries kicker, signature device, H1, lede; the
   right column carries an OBJECT: a spec-card + posline on suburb
   pages, a plate on cost/tool pages.
   Markup: <section class="hero hero-inner"><div class="wrap grid">
             <div class="col-7">…</div><div class="col-5">…</div>
           </div></section>
   Fallback: it IS static. Collapses to one column under 860px via
   the existing .grid rules. Cost: zero — layout only. */
.hero-inner { padding-block: clamp(var(--s-7), 7vw, var(--s-9)); }
.hero-inner h1 {
  /* Inner pages use the H1 size, not the home hero size — the
     hierarchy between the front door and the rooms is deliberate. */
  font-size: var(--fs-h1);
  font-variation-settings: "SOFT" 0, "WONK" 0, "opsz" 96;
}
.hero-inner .lede { margin-bottom: 0; }
/* On mobile the aside object follows the lede rather than
   interrupting it — .grid already stacks; just add breathing room. */
@media (max-width: 860px) {
  .hero-inner .col-5 { margin-top: var(--s-6); }
}

/* ---------- 1.2 The spec card (.spec-card) ----------
   A drafting TITLE BLOCK for the page's subject: mono labels, mono
   values, hairline-ruled rows under a 2px accent keel. This is how
   a suburb becomes an object without a photograph — the same move
   an architect's sheet makes in its bottom-right corner.
   NOT a box (boxes stay reserved for plates/lead panel/tables):
   it is keel + hairlines, the system's structural language.
   Markup:
     <div class="spec-card">
       <p class="spec-title">Ponsonby — specification</p>
       <dl>
         <div><dt>Local board</dt><dd>Waitematā</dd></div>
         <div><dt>Character overlay</dt><dd>Yes — ~47.4% of area</dd></div>
         …
       </dl>
       <p class="source-line">…</p>
     </div>
   Fallback: static. Cost: zero. Contrast: dt ink-3 (4.92:1 AA at
   its 12px mono size is NOT enough — so dt uses --fs-micro but
   ink-3 which is AA for all sizes per DESIGN-SYSTEM §1.2); dd ink
   (15.19:1). */
.spec-card { border-top: 2px solid var(--accent); padding-top: var(--s-4); }
.spec-card .spec-title {
  font-family: var(--ff-mono);
  font-size: var(--fs-mono);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 var(--s-3);
}
.spec-card dl { margin: 0; }
.spec-card dl > div {
  display: grid;
  grid-template-columns: minmax(11ch, 38%) 1fr;
  gap: var(--s-4);
  padding-block: var(--s-3);
  border-bottom: 1px solid var(--hairline);
  align-items: baseline;
}
.spec-card dl > div:last-child { border-bottom: 1px solid var(--hairline-strong); }
.spec-card dt {
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  font-weight: 500;
  letter-spacing: var(--track-label);
  text-transform: uppercase;
  color: var(--ink-3);
}
.spec-card dd {
  margin: 0;
  font-family: var(--ff-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  text-align: right;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere; /* long values can never push the column */
}
.spec-card dd a { color: var(--accent-deep); }
.spec-card .source-line { margin-top: var(--s-3); }
/* Very narrow screens: labels above values, both left-aligned. */
@media (max-width: 400px) {
  .spec-card dl > div { grid-template-columns: 1fr; gap: var(--s-1); }
  .spec-card dd { text-align: left; }
}

/* ---------- 1.3 The position line (.posline) ----------
   The anti-clone device. Every suburb page shows the same KIND of
   figure; this shows where THIS suburb's figure sits in Auckland's
   distribution — a drafting scale with an accent marker that is
   genuinely somewhere different on all 246 pages. Also reused as a
   calculator readout dial (payback vs horizon).
   Markup (positions emitted at build time as custom props):
     <div class="posline" style="--pos:63.4%; --mid:50.9%">
       <p class="posline-read">$892/wk — 21st of 246 suburbs</p>
       <div class="posline-track" role="img" aria-label="…the same
            information in a sentence…">
         <span class="posline-fill"></span>
         <span class="posline-tick posline-tick-mid"></span>
         <span class="posline-tick posline-tick-pos"></span>
       </div>
       <div class="posline-scale"><span>min</span><span>mid</span><span>max</span></div>
       <p class="source-line">…</p>
     </div>
   No text is attached to the marker, so no marker position can
   cause overflow; the read-line above and the scale row below are
   normal flow. The track carries role="img" + aria-label so AT
   gets the sentence, not three unlabeled spans.
   Fallback: fully static (fill at rest = full width var(--pos)).
   Cost: four painted rectangles. The fill is a non-text accent mix
   (24%), same contract as extra.css share bars. */
.posline { max-width: var(--measure-lede); }
.posline .posline-read {
  font-family: var(--ff-mono);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
  margin: 0 0 var(--s-3);
}
.posline .posline-read strong { color: var(--accent-deep); font-weight: 500; }
.posline-track {
  position: relative;
  height: 14px;
  border: 1px solid var(--hairline-strong);
  background: var(--paper-raised);
  overflow: hidden;
}
.posline-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--pos, 50%);
  background: color-mix(in srgb, var(--accent) 24%, var(--paper));
}
.posline-tick { position: absolute; top: 0; bottom: 0; }
.posline-tick-mid {
  left: var(--mid, 50%);
  width: 1px;
  background: var(--faint);
}
.posline-tick-pos {
  left: var(--pos, 50%);
  width: 2px;
  margin-left: -1px; /* centre the 2px marker on its position */
  background: var(--accent);
}
.posline-scale {
  display: flex;
  justify-content: space-between;
  gap: var(--s-3);
  margin-top: var(--s-2);
  font-family: var(--ff-mono);
  font-size: var(--fs-micro);
  letter-spacing: 0.04em;
  color: var(--ink-3);
}
.posline-scale span { min-width: 0; }
.posline-scale span:nth-child(2) { text-align: center; }
.posline-scale span:last-child { text-align: right; }

/* ---------- 1.4 The crescendo section (.section-crest) ----------
   Long data pages plateau because every section head weighs the
   same. Exactly ONE section per page — the one the page exists
   for — gets the crest: headline promoted a full size step, a
   longer keel, deeper padding. On the cost page that is the labour
   model; on a guide it is the finding; on a suburb page nothing
   gets it (the monument under the hero is the suburb's crest).
   Markup: add .section-crest to the <section> (helper: crest:true).
   Fallback: static. Cost: zero. */
.section-crest { padding-block: clamp(var(--s-9), 12vw, var(--s-11)); }
.section-crest .section-head h2 { font-size: var(--fs-h1); }
.section-crest .section-head .kicker::before { width: 96px; }
.section-crest .section-head { margin-bottom: clamp(var(--s-7), 6vw, var(--s-9)); }

/* ---------- 1.5 The major table (.table-frame.frame-major) ----------
   Tables are already one of the three sanctioned boxes. The ONE
   table a page is built around additionally carries the accent
   keel on its top edge — the same 3px signal the lead panel uses,
   so "this object is the point" reads consistently system-wide.
   At most one per page. Fallback: static. Cost: zero. */
.table-frame.frame-major { border-top: 3px solid var(--accent); }
.table-frame.frame-major table.data caption { padding-block: var(--s-5); }

/* ---------- 1.6 The instrument (.inst on form.calc) ----------
   A calculator is the site doing arithmetic in front of you, and it
   should read like a measuring instrument: a numbered mono header
   plate, inputs as the controls, and a READOUT — not a form with a
   paragraph at the end.
   Markup:
     <form class="calc inst">
       <div class="inst-head">
         <span class="inst-no">INSTRUMENT 01</span>
         <span class="inst-title">Landlord repaint return</span>
       </div>
       …existing .calc-grid fields…
       <div class="calc-out">…existing output…</div>
     </form>
   The readout: .calc-out steps DOWN to the page surface (--paper)
   inside the raised calc box — an inset window, the inverse of
   elevation, which is exactly what a display cut into an instrument
   panel is. Its value keeps the giant-numeral voice from extra.css.
   Fallback: static. Cost: zero. */
.calc.inst { border-top: 3px solid var(--accent); }
.inst-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--s-4);
  border-bottom: 1px solid var(--hairline-strong);
  padding-bottom: var(--s-3);
  font-family: var(--ff-mono);
  letter-spacing: var(--track-label);
  text-transform: uppercase;
}
.inst-head .inst-no { font-size: var(--fs-micro); color: var(--accent); font-weight: 500; }
.inst-head .inst-title { font-size: var(--fs-micro); color: var(--ink-3); text-align: right; }
.calc.inst .calc-out {
  background: var(--paper);
  border: 1px solid var(--hairline);
  border-top: 1px solid var(--hairline-strong);
  padding: var(--s-5);
}
.calc.inst .calc-out-value { color: var(--ink); }
/* The readout's own measuring rule — extends on entry where
   supported (2.3), full-width at rest. Same device as the anchor
   monument's rule, so the two read as one family. */
.calc.inst .inst-rule {
  height: 1px;
  background: var(--accent);
  max-width: 320px;
  margin-top: var(--s-3);
}

/* ---------- 1.7 Suburb hero device slot ----------
   On PAINT suburb pages the hero drawdown sits under the kicker at
   hero width; on RENO the dimension line carries the suburb's own
   label ("PONSONBY · 2 STATISTICAL AREAS"). Both devices already
   exist — this only sizes them for the inner hero. */
.hero-inner .drawdown { max-width: 220px; margin-bottom: var(--s-4); }
.hero-inner .dim-line { margin-bottom: var(--s-4); }

/* ============================================================
   PART 2 — SCROLL-DRIVEN MOTION
   Only where scroll timelines exist. Transform only — nothing in
   this layer animates opacity, so no content can ever be stranded
   invisible by this file even in a buggy engine.
   ============================================================ */
@supports (animation-timeline: scroll()) {

  /* ---- 2.1 The posline measures itself ----
     The fill draws from the left edge to the suburb's position as
     the track enters — the scale taking its reading. scaleX on a
     14px strip; base state (and reduced-motion state) is the
     finished reading. */
  .posline-fill {
    transform-origin: left center;
    animation: fx-scalex linear both; /* keyframes from depth.css */
    animation-timeline: view(block);
    animation-range: entry 0% entry 70%;
  }

  /* ---- 2.2 The marker seats itself ----
     The 2px position marker drops in (scaleY from the top edge)
     just after the fill reaches it. Transform only. */
  .posline-tick-pos {
    transform-origin: center top;
    animation: fx-scaley linear both;
    animation-timeline: view(block);
    animation-range: entry 30% entry 80%;
  }

  /* ---- 2.3 The instrument rule extends ----
     Same move as the anchor monument's rule (depth.css 2.9). */
  .calc.inst .inst-rule {
    transform-origin: left center;
    animation: fx-scalex linear both;
    animation-timeline: view(block);
    animation-range: entry 0% entry 80%;
  }

  @keyframes fx-scaley {
    from { transform: scaleY(0); }
    to   { transform: scaleY(1); }
  }
}

/* ============================================================
   PART 3 — REDUCED MOTION KILL BLOCK (do not remove)
   Scroll-driven animations ignore the 1ms global rule; this block
   is what actually stops them. Every base state above is the
   finished composition, so this simply ships the finished page.
   ============================================================ */
@media (prefers-reduced-motion: reduce) {
  .posline-fill,
  .posline-tick-pos,
  .calc.inst .inst-rule {
    animation: none !important;
  }
}
