/* weave shared foundation. v4 BRANDCRAFT, drafted 2026-08-08 (branch brandcraft-g3).
   A hand-lettered zine from your psychiatrist's desk, stapled from colored paper.
   Warm marker ink, paper sheet grounds per section, taped white cards, riso art
   blended into the paper. Product: weave-brandcraft-redesign (DEC-001, DEC-007).

   COMPATIBILITY LAW (inherited from v3 and held): every selector present in the
   previous revision is still present, and every custom-property NAME is still
   defined. Only VALUES and component treatments change. New component classes
   are namespaced additions at the end and shadow nothing that already existed.

   SURFACE LAW (new in v4): the default surface is paper, full grammar. Any
   region under [data-surface="quiet"] re-scopes the display face back to the
   serif, silences rotation and annotations, and calms borders. Fees, medication
   FAQ body, crisis blocks, forms, and the legal triplet sit under quiet.

   LEGIBILITY FLOOR (law, Wilfred 2026-08-08): pen annotations 24px minimum and
   sparse; accent-color text 19px minimum unless on a white card; every copy
   element 4.5:1 in both themes; body 16px minimum on marketing surfaces;
   rotation never on running text, containers only, within 2.5 degrees. */

:root {
  --cloth: #FFFFFF;
  --cloth-warm: #FFFFFF;
  --cloth-card: #FFFFFF;
  --ink: #2B2320;
  --ink-2: #574B41;
  --ink-3: #6E6157;
  --hairline: #E2DACF;
  --hairline-firm: #C9BFB1;
  --fill-cool: #F3EFE8;
  --thread-sage: #587F59;
  --thread-terracotta: #C75B39;
  --thread-slate: #46545F;
  --thread-flax: #46545F;
  --thread-teal: #0F766E;
  --wa-green: #25D366;
  --thread-run: linear-gradient(90deg, var(--thread-sage) 0 45%, var(--thread-terracotta) 45% 72%, var(--thread-slate) 72%);
  --warp-line: rgb(43 35 32 / 8%);
  --shadow-soft: 3px 4px 0 rgb(43 35 32 / 12%);
  --shadow-lift: 5px 6px 0 rgb(43 35 32 / 16%);
  --paper-green: #9DB88A;
  --paper-butter: #EFC868;
  --paper-terra: #D8825F;
  --paper-sky: #8FBDB5;
  --paper-quiet: #EDF1E7;
  --marker: #C75B39;
  /* Crisis headings only. The marker terracotta measures 4.21:1 on white,
     which clears the WCAG large-text bar and misses the 4.5 body bar; on the
     one surface where someone may be reading in distress we hold the stricter
     number. Darkened along the same hue (13.8 deg vs 14.4 deg) rather than
     desaturated, so the marker family still reads as one voice. Measured
     5.01:1 on white. Reversible: restore var(--marker) to revert. */
  --crisis-accent: #B94E2E;
  --tape: rgb(252 250 244 / 62%);
  --font-display: "Kalam", "Weave Newsreader Fallback", "Comic Sans MS", cursive;
  --font-serif: "Newsreader", "Weave Newsreader Fallback", Georgia, "Times New Roman", serif;
  --font-hand: "Kalam", "Comic Sans MS", cursive;
  --font-pen: "Caveat", cursive;
  --font-ui: "Switzer", "Weave Switzer Fallback", Arial, Helvetica, sans-serif;
  --font-data: "JetBrains Mono", "Weave Mono Fallback", "SFMono-Regular", Consolas, monospace;
  /* LEGIBILITY FLOOR, raised 2026-09-03 (hard rule 41: body and labels 16px
     minimum on patient-facing surfaces, nothing under 12px anywhere). Both
     tokens were under the floor and both carry running text and functional
     labels on care pages: --text-sm at 15px sat on the nav links, the footer
     links, the fee table, the trust ribbon, the router description and the
     practical-list labels; --text-xs at 14px sat on the fee footnote. They
     converge on the floor rather than being deleted, because the COMPATIBILITY
     LAW above keeps every property NAME defined. A later scale rework may
     re-separate them, above 16px in both directions, never below. */
  --text-xs: 1rem;
  --text-sm: 1rem;
  --text-base: clamp(1.03125rem, 1rem + 0.15vw, 1.09375rem);
  --text-lede: clamp(1.15rem, 1.07rem + 0.4vw, 1.28rem);
  --text-h3: 1.5rem;
  --text-h2: clamp(2.1rem, 1.6rem + 2.2vw, 3.1rem);
  --text-h1: clamp(2.8rem, 6.8vw, 4.8rem);
  --leading-body: 1.62;
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-section: clamp(4.5rem, 10vw, 9rem);
  --radius-sm: 0.5rem;
  --radius-card: 1rem;
  --radius-outer: 1.25rem;
  --radius-inner: 0.875rem;
  --radius-pill: 999px;
  --wonky-1: 255px 15px 225px 15px / 15px 225px 15px 255px;
  --wonky-2: 15px 225px 15px 255px / 255px 15px 225px 15px;
  --wonky-3: 225px 18px 255px 15px / 18px 255px 15px 225px;
  --wonky-4: 18px 255px 18px 225px / 225px 18px 255px 18px;
  --ease-weave: cubic-bezier(0.22, 0.61, 0.36, 1);
  --ease-settle: cubic-bezier(0.34, 1.56, 0.64, 1);
  --duration-fast: 150ms;
  --duration-ui: 220ms;
  --duration-reveal: 650ms;
  --duration-light: 30s;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme]), :root:not([data-theme="light"]) {
    --cloth: #141210;
    --cloth-warm: #141210;
    --cloth-card: #1D1A17;
    --ink: #EFE9E1;
    --ink-2: #C4BAAE;
    --ink-3: #998F84;
    --hairline: #35302A;
    --hairline-firm: #48413A;
    --fill-cool: #1D1A17;
    --thread-sage: #9DC29D;
    --thread-terracotta: #E08A6B;
    --thread-slate: #93A6B3;
    --thread-flax: #93A6B3;
    --thread-teal: #76C9BF;
    --warp-line: rgb(239 233 225 / 8%);
    --shadow-soft: 3px 4px 0 rgb(0 0 0 / 45%);
    --shadow-lift: 5px 6px 0 rgb(0 0 0 / 50%);
    --paper-green: #232B1E;
    --paper-butter: #322A16;
    --paper-terra: #332018;
    --paper-sky: #1E2B29;
    --paper-quiet: #191D16;
    --marker: #E08A6B;
    /* Dark needs no darkening: the same value measures 6.61:1 on the card and
       7.13:1 on the page ground. Held equal to --marker on purpose, so the
       token carries a light-mode correction and not a second dark palette. */
    --crisis-accent: #E08A6B;
    --tape: rgb(239 233 225 / 14%);
  }
}

[data-theme="dark"] {
  --cloth: #141210;
  --cloth-warm: #141210;
  --cloth-card: #1D1A17;
  --ink: #EFE9E1;
  --ink-2: #C4BAAE;
  --ink-3: #998F84;
  --hairline: #35302A;
  --hairline-firm: #48413A;
  --fill-cool: #1D1A17;
  --thread-sage: #9DC29D;
  --thread-terracotta: #E08A6B;
  --thread-slate: #93A6B3;
  --thread-flax: #93A6B3;
  --thread-teal: #76C9BF;
  --warp-line: rgb(239 233 225 / 8%);
  --shadow-soft: 3px 4px 0 rgb(0 0 0 / 45%);
  --shadow-lift: 5px 6px 0 rgb(0 0 0 / 50%);
  --paper-green: #232B1E;
  --paper-butter: #322A16;
  --paper-terra: #332018;
  --paper-sky: #1E2B29;
  --paper-quiet: #191D16;
  --marker: #E08A6B;
  --crisis-accent: #E08A6B;
  --tape: rgb(239 233 225 / 14%);
}

*, *::before, *::after { box-sizing: border-box; }
html { background: var(--cloth); scroll-behavior: smooth; overflow-x: hidden; overflow-x: clip; }
body { min-width: 320px; margin: 0; background: var(--cloth); color: var(--ink-2); font-family: var(--font-ui); font-size: var(--text-base); line-height: var(--leading-body); overflow-wrap: break-word; -webkit-font-smoothing: antialiased; overflow-x: hidden; overflow-x: clip; }
body.menu-open { overflow: hidden; }
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; }
button, input, textarea, select { font: inherit; }
button { color: inherit; }
/* The UA default for <small> is 0.8125em, and it survived every floor pass in
   this file because nothing here ever named the element: line 279 sizes
   .brand small and stops there. So three care pages rendered real copy below
   the floor out of the browser's own stylesheet. Measured on contact.html
   before this rule: 13.82px at 390 and 14px at 1280, on the reply note, the
   email line and the phone line, in both themes.

   Rule 41 puts body copy on a 16px floor sitewide and spec R7 says the floor
   holds by SHARED CSS, so it has to hold for an element the author reached for
   rather than only for the classes this file happens to know. 1em, not 1rem:
   <small> inside a larger box (a lede, a card heading) should stay
   proportional to its parent, and 1rem would shrink it there. The one place a
   smaller <small> is wanted is the brand lockup, and that rule is more
   specific and still wins.

   This is the shared-CSS half only. The page-inline sub-16 classes
   (.fee-card__duration at 14px on pay and contact, figcaption.fine-print at
   14px on the homepage) are Wave 2a by lane A's disposition and are NOT
   touched here. */
small { font-size: 1em; }
h1, h2, h3, p { margin-top: 0; }
h1, h2, h3 { color: var(--ink); font-family: var(--font-display); font-weight: 700; letter-spacing: -0.01em; }
h1 { max-width: 15ch; margin-bottom: var(--space-6); font-size: var(--text-h1); line-height: 1.04; transform: rotate(-0.7deg); }
h2 { margin-bottom: var(--space-5); font-size: var(--text-h2); line-height: 1.1; transform: rotate(-0.5deg); }
h3 { margin-bottom: var(--space-3); font-size: var(--text-h3); line-height: 1.2; }
p { margin-bottom: var(--space-4); }
 /* Focus (WCAG 2.4.7, and the 2.4.8 house overlay in L31). Measured
   2026-09-03 with scripts/capture-harness/floor-probe.js across five pages at
   1280 and 390 in both themes: six control types sampled per row (button, CTA,
   nav link, footer link, input, first link) and 6 of 6 carried a 3px solid
   sage ring in every row, dark included. Nothing in this file sets
   outline:none or outline:0, so no control is left without a replacement ring.
   The values are held: 3px already exceeds the 2px floor, and widening it
   would be a change, not a fix. */
:focus-visible { outline: 3px solid var(--thread-sage); outline-offset: 4px; border-radius: var(--radius-sm); }

/* Quiet surface: the serif returns, rotation dies, the volume drops.
   This single line is what hard rule 48 asserts against: the hand-lettered and
   rotated register never carries running text, fees, crisis content, forms or
   legal text. A quiet region re-points --font-display at the serif, so the
   gate's check is "does every fee, crisis, form and legal region resolve
   --font-display to var(--font-serif)", not a survey of font names. */
[data-surface="quiet"] { --font-display: var(--font-serif); }
[data-surface="quiet"] h1, [data-surface="quiet"] h2, [data-surface="quiet"] h3 { font-weight: 500; letter-spacing: -0.02em; transform: none; }
[data-surface="quiet"] .pen, [data-surface="quiet"] .annotation { display: none; }

.skip-link { position: fixed; z-index: 300; top: var(--space-3); left: var(--space-3); padding: var(--space-3) var(--space-4); border-radius: var(--radius-pill); background: var(--ink); color: var(--cloth); transform: translateY(-160%); transition: transform var(--duration-ui) var(--ease-weave); }
.skip-link:focus-visible { transform: translateY(0); }
.shell { width: min(1184px, calc(100% - 3rem)); margin-inline: auto; }
.narrow { width: min(760px, 100%); }
.section { position: relative; padding-block: var(--space-section); }
.section-compact { padding-block: clamp(4.5rem, 7vw, 7rem); }
.section-head { max-width: 45rem; margin-bottom: var(--space-12); }
.lede { max-width: 60ch; color: var(--ink-2); font-size: var(--text-lede); }
.serif-italic { font-family: var(--font-serif); font-style: italic; }

/* Eyebrows become stamps: bordered, uppercase, faintly rotated. The sprig
   mark survives inside the stamp.

   Raised 14px to 16px, 2026-09-03. An eyebrow is a label and hard rule 41 puts
   labels on the 16px floor; the older L17 line ("micro-labels at 12px, body
   floor 14px") is the 2026-08-08 rule that rule 41 supersedes. Measured before
   the change, the smallest visible type on every care page was this stamp at
   14px, so holding it would have left the floor unmet on the page's own
   smallest text.

   Tracking drops 0.13em to 0.11em so the ABSOLUTE letter-spacing is held: it
   was 1.82px at 14px and is 1.76px at 16px. The stamp reads at the same
   density, it is simply legible.

   Leading raised 1.2 to 1.35 the same day, and it is a consequence of the
   size, not a second opinion about it. 1.2 was set when the stamp was 14px on
   one line. At 16px the label wraps at 390, and a two-line uppercase stamp at
   1.2 sets its lines 19.2px apart with a 2px border and 9px of padding around
   them: the rows touch. cognitive-gate read 236 p4_line_height failures on the
   settled baseline and every care-page one of them was this class, at 1.200 on
   16.00px type over 2 lines, on eight of the fourteen Wave 1 pages.

   1.35, not 1.5. Rule 41's 1.5 floor is for RUNNING TEXT. A bordered
   uppercase label is not running text, and 1.5 would open a visible gap
   inside a box whose padding is 5px and 4px. 1.35 clears the collision, holds
   the stamp's density, and is the value .ribbon-fact already uses in this file
   for the same kind of short tight label. The 28-character eyebrow cap is
   copy, Wave 1, and is not this.

   This change alone did NOT quiet cognitive-gate, and that turned out to be
   the more useful finding. Its leading check read every p and li over one
   line against a flat 1.5, so raising 1.200 to 1.350 moved the number and not
   the verdict: five findings before and five after on three care pages at
   390, all of them p.eyebrow. The gate held two opinions about the same
   object, because the probe already treated an eyebrow as a LABEL and not as
   running text three checks away, in rule 48's tilt exemption.

   Fable ruled on 2026-09-03 (lane C verification ruling 3): the 1.5 floor is
   a running-text rule and a label is out of its scope. cognitive-gate now
   exempts the label register from p4_line_height and prints the count and the
   reason on every run, which took that class from 236 to 208, all 28 of them
   p.eyebrow. So 1.35 is the settled value here and the gate agrees with it.
   Every other p and li is still measured against 1.5.

   Checked, not assumed: nothing else in this file sets a line-height on
   .eyebrow, .stamp or .laid-thread. .stamp declares none and inherits
   --leading-body (1.62). The only other 1.2 values in the file are on h3 and
   .button, which are a heading and a control, neither of which the leading
   check reads. */
.eyebrow, .laid-thread { display: inline-block; position: relative; margin-bottom: var(--space-5); padding: 5px 12px 4px; border: 2px solid currentColor; border-radius: 4px 9px 5px 10px; color: var(--ink); font-size: 1rem; font-weight: 700; letter-spacing: 0.11em; line-height: 1.35; text-transform: uppercase; transform: rotate(-1deg); opacity: 0.92; font-variant-numeric: tabular-nums lining-nums; }
.eyebrow:nth-of-type(even), .laid-thread:nth-of-type(even) { transform: rotate(1deg); }
[data-surface="quiet"] .eyebrow, [data-surface="quiet"] .laid-thread { transform: none; border-color: var(--hairline-firm); color: var(--ink-2); }
.thread-underline, .eyebrow--threaded { display: inline-block; }
.eyebrow::before, .thread-underline::before, .eyebrow--threaded::before, .laid-thread::before { content: ""; display: inline-block; width: 1.2em; height: 1.2em; margin-right: 0.45em; vertical-align: -0.25em; background: url("/img/sprig.svg") no-repeat center / contain; }
.eyebrow::after, .thread-underline::after, .eyebrow--threaded::after, .laid-thread::after { content: none; }
.nav-link[aria-current="page"] { color: var(--thread-sage); box-shadow: inset 0 -2px 0 var(--thread-sage); }
.eyebrow--teal { color: var(--thread-teal); }

/* The stitched divider keeps its job with a hand-pulled look. */
.stitched-divider { position: relative; height: 1px; margin: 0; border: 0; background: var(--hairline); }
.stitched-divider::before { content: ""; position: absolute; top: -1px; left: max(1.5rem, calc((100vw - 1184px) / 2)); width: 56px; height: 3px; background: var(--thread-run); transform: rotate(-0.4deg); }

.site-header, .nav { position: fixed; z-index: 100; top: var(--space-4); right: 0; left: 0; pointer-events: none; }
.nav-pill, .nav__inner { display: flex; align-items: center; justify-content: space-between; width: min(1120px, calc(100% - 2rem)); min-height: 64px; margin-inline: auto; padding: 0.45rem 0.5rem 0.45rem 1.3rem; border: 2px solid var(--ink); border-radius: var(--wonky-3); background: var(--cloth); box-shadow: var(--shadow-soft); pointer-events: auto; }
.brand, .nav__logo { display: inline-flex; align-items: center; min-height: 44px; gap: 0.65rem; color: var(--ink); font-family: var(--font-hand); font-size: 1.05rem; font-weight: 700; letter-spacing: 0.02em; text-decoration: none; }
/* The nav identity sub-line is a label, 14px to 16px (rule 41). It is hidden
   below 1024px, so the only width that can feel it is the full pill. */
.brand small, .nav__logo span { display: block; color: var(--ink-2); font-family: var(--font-ui); font-size: 1rem; font-weight: 600; letter-spacing: 0.06em; }
.brand-mark { width: 28px; height: 28px; color: var(--thread-sage); }
.nav-links, .nav__links { display: flex; align-items: center; gap: 0.35rem; margin: 0; padding: 0; list-style: none; }
.nav-link, .nav__links a { display: inline-flex; position: relative; align-items: center; min-height: 44px; padding: 0.5rem 0.75rem; border: 2px solid transparent; border-radius: 4px 9px 5px 10px; color: var(--ink-2); font-size: var(--text-sm); font-weight: 600; letter-spacing: 0.04em; text-decoration: none; }
.nav-link::before { content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit; background: var(--fill-cool); opacity: 0; transform: scale(0.94); transition: opacity var(--duration-ui) var(--ease-weave), transform var(--duration-ui) var(--ease-weave); }
.nav-link:hover::before { opacity: 1; transform: scale(1); }
.nav-link:hover { color: var(--ink); border-color: var(--hairline-firm); }
.nav-link[aria-current="page"]::after { right: 0.75rem; bottom: 0.2rem; left: 0.75rem; width: auto; }
.nav-cta, .nav__cta { margin-left: var(--space-2); }
.menu-button, .nav__toggle { display: none; position: relative; width: 48px; height: 48px; border: 2px solid var(--hairline-firm); border-radius: 50%; background: var(--fill-cool); cursor: pointer; }
.menu-button span, .nav__toggle span { position: absolute; left: 13px; width: 20px; height: 2px; background: var(--ink); transition: transform 320ms var(--ease-weave), top 320ms var(--ease-weave), opacity var(--duration-fast) var(--ease-weave); }
.menu-button span:nth-child(1), .nav__toggle span:nth-child(1) { top: 16px; }
.menu-button span:nth-child(2), .nav__toggle span:nth-child(2) { top: 22px; }
.menu-button span:nth-child(3), .nav__toggle span:nth-child(3) { top: 28px; }
.menu-button[aria-expanded="true"] span:nth-child(1), .nav__toggle[aria-expanded="true"] span:nth-child(1) { top: 22px; transform: rotate(45deg); }
.menu-button[aria-expanded="true"] span:nth-child(2), .nav__toggle[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.menu-button[aria-expanded="true"] span:nth-child(3), .nav__toggle[aria-expanded="true"] span:nth-child(3) { top: 22px; transform: rotate(-45deg); }

/* Buttons: hand-drawn cards. The primary is a white card with a marker label
   inside a wonky ink border; ink on white measures 12.9:1 light. In dark the
   card token deepens and the ink token lightens with it. */
.button-row, .btn-group { display: flex; flex-wrap: wrap; gap: var(--space-4); align-items: center; }
.button, .btn { display: inline-flex; align-items: center; justify-content: center; min-height: 52px; padding: 0.7rem 0.7rem 0.6rem 1.5rem; border: 2.5px solid var(--ink); border-radius: var(--wonky-1); font-family: var(--font-hand); font-size: 1.25rem; font-weight: 700; line-height: 1.2; text-decoration: none; cursor: pointer; transition: transform var(--duration-ui) var(--ease-settle), border-radius var(--duration-ui) var(--ease-weave), background-color var(--duration-ui) var(--ease-weave), box-shadow var(--duration-ui) var(--ease-weave); }
.button .icon-chip, .btn .icon-chip { display: grid; place-items: center; width: 36px; height: 36px; margin-left: 0.8rem; border-radius: 50%; background: var(--fill-cool); transition: transform var(--duration-ui) var(--ease-weave); }
.button:hover .icon-chip, .btn:hover .icon-chip { transform: translateX(3px) rotate(6deg); }
.button:hover, .btn:hover { border-radius: var(--wonky-2); transform: rotate(-0.6deg); }
.button:active, .btn:active { transform: scale(0.98); }
.button-primary, .btn--primary { background: var(--cloth-card); color: var(--ink); box-shadow: var(--shadow-lift); }
.button-primary:hover, .btn--primary:hover { box-shadow: var(--shadow-soft); }
.button-secondary, .btn--secondary { border-color: var(--hairline-firm); background: transparent; color: var(--ink); }
.button-secondary:hover, .btn--secondary:hover { border-color: var(--thread-sage); color: var(--thread-sage); }
.button-secondary .icon-chip, .btn--secondary .icon-chip { background: var(--fill-cool); }
.button-whatsapp, .btn--whatsapp { border-color: #14532D; background: var(--wa-green); color: #102515; box-shadow: var(--shadow-lift); }
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) .button-whatsapp, :root:not([data-theme="light"]) .btn--whatsapp { border-color: #9DE2B8; }
}
[data-theme="dark"] .button-whatsapp, [data-theme="dark"] .btn--whatsapp { border-color: #9DE2B8; }
[data-surface="quiet"] .button, [data-surface="quiet"] .btn { font-family: var(--font-ui); font-size: 1rem; font-weight: 600; border-width: 2px; border-radius: var(--radius-pill); transform: none; }
[data-surface="quiet"] .button:hover, [data-surface="quiet"] .btn:hover { border-radius: var(--radius-pill); transform: none; }

.double-bezel { padding: 6px; border: 2px solid var(--ink); border-radius: var(--wonky-2); background: var(--cloth-warm); box-shadow: var(--shadow-soft); }
.double-bezel > .bezel-inner { height: 100%; border: 1px solid var(--hairline-firm); border-radius: var(--radius-inner); background: var(--cloth-card); }

/* Art plate, promoted from learn.css (DEC-030): transparent and white-ground
   pieces float on colored paper under multiply; the taped white plate is L22's
   answer, now a site component. Fade-only under reveal: the plate never takes
   a transform (it is an ancestor of blended art). */
.art-plate { position: relative; width: min(100%, 24rem); margin-inline: auto; padding: var(--space-5); border: 2.5px solid var(--ink); border-radius: var(--wonky-3); background: #FFFFFF; box-shadow: var(--shadow-lift); }
.art-plate > img { width: 100%; transform: rotate(-1.4deg); }
.art-plate--alt { border-radius: var(--wonky-4); }
.art-plate--alt > img { transform: rotate(1.3deg); }
html.reveal-ready:not(.reveal-complete) .art-plate.reveal,
html.reveal-ready:not(.reveal-complete) .art-plate.reveal.in { transform: none; }
[data-surface="quiet"] .double-bezel { border: 1px solid var(--hairline-firm); border-radius: var(--radius-outer); box-shadow: none; }
[data-surface="quiet"] .double-bezel > .bezel-inner { border: 1px solid var(--hairline); border-radius: var(--radius-inner); }
/* The fee frame keeps the pasted-card ink border inside quiet (DEC-030): the
   honesty artifact is still a made thing; quiet drops rotation and noise, not
   the hand. Specificity matches the quiet bezel soften above. */
[data-surface="quiet"] .fee-frame { border: 2.5px solid var(--ink); border-radius: var(--wonky-2); box-shadow: var(--shadow-lift); }
.card { border: 2.5px solid var(--ink); border-radius: var(--wonky-1); background: var(--cloth-card); box-shadow: var(--shadow-soft); }
.card:nth-of-type(even) { border-radius: var(--wonky-2); }
[data-surface="quiet"] .card { border: 1px solid var(--hairline-firm); border-radius: var(--radius-card); box-shadow: none; }
.liftable { transition: transform 300ms var(--ease-settle), box-shadow 300ms var(--ease-weave); }
.liftable:hover { transform: rotate(0deg) translateY(-2px); box-shadow: var(--shadow-lift); }

/* The fee table stays the honesty artifact: quiet by force, whatever surface
   its page declares. Tabular numerals, daylight, zero decoration. */
/* Fee surfaces re-set to the quiet Brandcraft register (DEC-030): the honesty
   artifact is a pasted white card, not the old double-bezel chrome. Zero
   rotation by quiet law; the wonky border and offset-solid shadow carry the
   hand feel; numerals stay tabular daylight. */
.fee-frame { --font-display: var(--font-serif); border: 2.5px solid var(--ink); border-radius: var(--wonky-2); background: var(--cloth-card); box-shadow: var(--shadow-lift); padding: var(--space-2); }
.fee-frame .bezel-inner { overflow: hidden; background: var(--cloth-card); border: 0; border-radius: calc(var(--radius-inner) - 2px); }
.fee-table, .pricing-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); font-variant-numeric: tabular-nums lining-nums; }
.fee-table th, .fee-table td, .pricing-table th, .pricing-table td { padding: var(--space-4) var(--space-5); border-bottom: 1px solid var(--hairline); text-align: left; }
/* Money surface: the column heads are labels on the honesty artifact. 14 to 16. */
.fee-table th, .pricing-table th { color: var(--ink); font-size: 1rem; font-weight: 600; letter-spacing: 0.01em; text-transform: none; border-bottom: 2px solid var(--ink); }
.fee-table td:last-child, .fee-table th:last-child { text-align: right; }
.fee-table tbody tr { transition: background-color var(--duration-ui) var(--ease-weave); }
.fee-table tbody tr:hover { background: var(--fill-cool); }
.fee-footnote, .pricing-note { padding: var(--space-4) var(--space-5); color: var(--ink-2); font-size: var(--text-xs); }

/* Trust strip legacy grid stays defined for any page not yet on the ribbon. */
.trust-strip { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink); }
.trust-item { position: relative; padding: 1.4rem 1.25rem 1.35rem; }
.trust-item + .trust-item { border-left: 1px dashed var(--hairline-firm); }
.trust-item::before { content: ""; position: absolute; top: -2px; left: 1.25rem; width: 24px; height: 3px; background: var(--thread-sage); }
.trust-item:nth-child(2)::before { background: var(--thread-terracotta); }
.trust-item:nth-child(3)::before { background: var(--thread-slate); }
.trust-item:nth-child(4)::before { background: var(--thread-teal); }
.trust-item strong { display: block; color: var(--ink); font-size: var(--text-sm); }
.trust-item span { color: var(--ink-2); font-size: 1rem; }

/* Crisis support: structure locked (ledger law 2), rendered quiet always. */
.crisis-block, .crisis-box { --font-display: var(--font-serif); display: grid; grid-template-columns: minmax(0, 3fr) minmax(14rem, 2fr); gap: clamp(1.5rem, 5vw, 4rem); align-items: center; padding: clamp(1.5rem, 4vw, 2.5rem); border: 1px solid var(--hairline-firm); border-radius: var(--radius-card); background: var(--cloth-card); box-shadow: none; transform: none; }
.crisis-block h2, .crisis-block h3, .crisis-box h2, .crisis-box h3 { color: var(--crisis-accent); font-family: var(--font-serif); font-weight: 500; transform: none; }
.crisis-block .eyebrow, .crisis-box .eyebrow { display: block; transform: none; border-color: var(--hairline-firm); color: var(--ink-2); width: fit-content; }
.crisis-block__title { display: inline-block; position: relative; padding-bottom: var(--space-2); }
/* The rule belongs to the heading it sits under, so it takes the heading's
   colour. Left on the lighter marker it read as a mismatched second tone at
   2px directly beneath a 50px heading. */
.crisis-block__title::after { content: ""; position: absolute; right: 0; bottom: 0; left: 0; height: 2px; background: linear-gradient(90deg, var(--crisis-accent) 0 58%, var(--thread-flax) 58%); }
.crisis-block ol { margin: var(--space-5) 0 0; padding-left: 1.3rem; }
.crisis-block li + li { margin-top: var(--space-2); }
.crisis-block__art { width: min(100%, 18rem); max-height: 23rem; margin-inline: auto; object-fit: contain; }

.care-bridge { display: grid; grid-template-columns: minmax(0, 7fr) minmax(16rem, 5fr); gap: clamp(1.5rem, 5vw, 4rem); align-items: end; padding: clamp(1.75rem, 4vw, 3rem); border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink); }
.care-bridge__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); justify-content: flex-end; }
.safe-care { padding: var(--space-6); border: 1px solid var(--hairline-firm); border-radius: var(--radius-card); background: var(--cloth-card); }

.site-footer { padding-block: var(--space-16) var(--space-8); border-top: 2px solid var(--ink); background: var(--cloth-warm); }
/* Footer columns. The five nav tracks were repeat(5, minmax(7rem, 1fr)), and
   the nav lists still carried the user-agent list box: 40px of padding and a
   disc marker. At 1024 that left 78px of text width per column, so 15 of the
   24 links broke across two and three lines while their bullets stayed on the
   first line, next to a fragment. Measured on services, medication-faq and
   learn at 1440/1280/1024/900/800/768/390.

   Two changes, both reversible. The lists lose the user-agent box, which is
   what a nav list wants and what the homepage had already done for itself
   locally. The track floor rises to the width five tracks actually get at the
   full shell, and auto-fit lets the row reflow to four, three or two columns
   instead of crushing every column to a fragment. Labels are frozen copy, so
   the longest of them still wraps at some widths; without the marker that is
   an ordinary two-line label rather than an orphaned bullet. */
.footer-grid { display: grid; grid-template-columns: minmax(14rem, 1.7fr) repeat(auto-fit, minmax(9.5rem, 1fr)); gap: var(--space-8); }
.footer-grid h2 { margin-bottom: var(--space-3); font-family: var(--font-ui); font-size: var(--text-sm); font-weight: 600; letter-spacing: 0; transform: none; }
/* Footer targets (hard rule 42), fixed 2026-09-03. The anchors were 32px tall
   and the rows touched, which is the residual the 08-22 audit recorded and
   nothing since had measured: 24 of 43 rendered controls on an area page were
   under 44 by 44, and most of them were these.

   Two changes. The anchor becomes a full-width flex box, so the hit area is
   the whole column row rather than the width of the label, and the label still
   wraps normally inside it (an inline-flex anchor sizes to max-content and
   would have pushed long labels out of a narrow column). The list becomes a
   grid with an 8px gap, which is the second half of rule 42: adjacent targets
   are separated, not stacked flush.

   Cost, measured: the footer grows. That is the price of the rule and it is
   paid in the one region of the page designed to be scanned slowly. */
.footer-grid nav ul { display: grid; gap: var(--space-2); margin: 0; padding: 0; list-style: none; }
.footer-grid nav a { display: flex; align-items: center; min-height: 44px; color: var(--ink-2); font-size: var(--text-sm); }
.footer-locations { display: grid; grid-template-columns: 2fr 1fr; gap: var(--space-8); margin-top: var(--space-12); padding-top: var(--space-6); border-top: 1px solid var(--hairline); font-size: var(--text-sm); }
.footer-locations ul { padding-left: 1.2rem; }
.footer-locations li + li { margin-top: var(--space-2); }

/* Rule 41's measure, in the two footer lines that are sentences.
   p.footer__legal sits in the 2fr track of .footer-locations, which is 768px
   at 1280, and at the footer's smaller type that renders 83.3ch. It was the
   ONLY p4_measure_over_75 finding on the six generated area previews, and it
   fired on every one of the fourteen Wave 1 pages in the settled baseline,
   because it is one shared partial. The promise line in .footer__brand is the
   same kind of sentence in a track that widens the same way (lane C finding 4,
   2026-09-03).

   The cap goes on the PARAGRAPH, not on the column. Narrowing the track would
   move the location list, the crisis line and the area link run with it, and
   those are lists and a link run, not prose: their line lengths are set by the
   addresses and the link labels, and shortening the track only makes them wrap
   more. One rule, on the two elements that are actually sentences.

   70ch, not the 68ch care.css uses for body prose, because this is the smaller
   footer face and 70ch of it is a shorter physical line than 68ch of body
   copy. Both sit inside rule 41's band and well inside WCAG 1.4.8's 80.
   care.css deliberately scopes its own measure rule to main so that this line
   is capped once, here, in the file the shared partial actually travels
   with.

   :first-of-type picks the promise and leaves the WhatsApp line alone. That
   second paragraph is one link, it is already inline-flex at 44px from the
   :only-child target rule below, and a measure on a control is meaningless. */
.footer__legal,
.footer__brand > p:first-of-type { max-width: 70ch; }

/* Rule 42, part two: the links that are not in a nav list.
   A link that is the only ELEMENT in its paragraph is a standalone control,
   not a word in a sentence, and the WCAG 2.5.8 inline exception does not cover
   it. Measured at 19 to 27px tall before this: the footer WhatsApp line, the
   footer brand, the crisis block's "all emergency numbers" link, and the
   reviews strip's "read more".

   :only-child ignores text nodes, which is deliberate and worth stating
   because it is easy to misread. It matches an anchor that is the only child
   ELEMENT even when prose surrounds it, so it also picks up the footer crisis
   line ("If there is immediate danger, call 112. Crisis support"). That is the
   right outcome there: one short line, on the crisis path, where the full
   target is worth having. It does NOT pick up the postal address's "get
   directions", because that li also carries a strong and a br. The one thing
   to watch when adding a rule here: inline-flex makes a link atomic, so it
   cannot break across lines. Keep it off long link text inside long
   paragraphs. */
.site-footer p > a:only-child,
.crisis-block p > a:only-child,
.crisis-box p > a:only-child,
.voices__more > a:only-child {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}
.footer__brand .brand { min-height: 44px; }

/* Links that sit in running text. Vertical padding on an INLINE box grows the
   hit area without growing the line box, so a target can be raised without
   touching the paragraph's rhythm. How far it is raised depends on whether the
   link is really in a sentence, and the first draft of this rule got that
   wrong in a way the probe caught: applying the full treatment to every one of
   them took the footer from 1676px to 2399px at 390, because .footer-locations
   li is a wrapped postal address, not a link row.

   .footer-areas is a LINK RUN, eleven area links separated by middots. It is
   navigation typeset as a sentence, so the inline exception does not really
   describe it and the house 44px floor applies in full. Because consecutive
   lines both carry links, the line-height has to rise with the padding or two
   targets on adjacent lines overlap.

   .footer__crisis is one short line ending in one link, on the crisis path.
   Full 44px, and no line-height change is needed because there is no second
   line to collide with.

   The rest are single links inside real sentences (the postal address's "get
   directions", a helpline row). WCAG 2.5.5 AAA and 2.5.8 both carve out a
   target "in a sentence or block of text", and forcing 44px here would extend
   each link's hit box over the prose lines above and below it, so that
   clicking a word of the address opens the map. They take a smaller lift
   instead: 19px to roughly 35px, which clears the 24px AA floor of 2.5.8 and
   leaves the paragraph honest. Recorded as a deliberate exception, with the
   number, rather than left unmeasured. */
/* Order matters here and cost one measurement to notice. .footer-areas is an
   li INSIDE .footer-locations, so `.footer-areas a` and `.footer-locations a`
   tie at (0,2,0) and the later rule wins. Written the other way round, the
   link run silently inherited the smaller in-sentence padding and measured
   36px instead of 44. General first, specific second. */
.footer-locations a,
.crisis-lines a,
.crisis-tier-1 a { padding-block: 0.5rem; text-underline-offset: 3px; }
.footer-areas { line-height: 2.75; }
/* The crisis line's link is already inline-flex at 44px from the :only-child
   rule above; padding it as well took it to 51.5px, which is a taller footer
   line for nothing. Left out on purpose. */
.footer-areas a { padding-block: 0.8rem; text-underline-offset: 3px; }
/* Rule 42, part three: the address block's action link, corrected 2026-09-04
   on Fable's review of the seven live Wave 1a pages (F1).

   The comment two rules up reasoned that "Get directions" is a link inside a
   sentence and took the smaller lift, 19px to 36px. The measurement disagrees
   with the reasoning. The link sits after a line break, at the end of the
   address block, and it is the only control in that li: it reads and behaves
   as a standalone action, not as a word someone might click mid-sentence. The
   WCAG 2.5.8 inline exception does not describe it, so the house 44px floor
   applies in full. Measured at 390 on all seven Wave 1a pages: 100.1 x 36px
   before, 100.1 x 44px after.

   The selector is the narrowest one that reaches only this link. Scanned over
   the served tree: 107 pages carry .footer-locations and 105 of them hold
   exactly one anchor inside an li that is not .footer-areas, the maps link.
   The area link run keeps its own rule above, and the two location lines
   carry no links at all, so no inline text link near it moves and no
   line-height changes.

   min-height with border-box counts the 0.5rem padding already on it, so the
   box goes to 44 rather than to 52. */
.footer-locations li:not(.footer-areas) > a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

.reveal { opacity: 1; transform: none; }
html.reveal-ready:not(.reveal-complete) .reveal { opacity: 0; transform: translateY(24px); transition: opacity var(--duration-reveal) var(--ease-weave), transform var(--duration-reveal) var(--ease-weave); }
html.reveal-ready:not(.reveal-complete) .reveal.in { opacity: 1; transform: translateY(0); }
/* Reduced motion (hard rule 40, ledger L30). Rewritten 2026-09-03. Two things
   were wrong with the previous one-liner and both were measured, not guessed.

   It set transition-duration to 1ms on every element instead of removing the
   transition, so under prefers-reduced-motion EVERY element computed as
   carrying a live 1ms transition on all properties: 519 of 519 elements on the
   homepage, 445 of 449 on an area page, 6334 of 6340 on a study guide
   (floor-probe.js, 2026-09-03). A suppressed animation is not an absent one,
   and a rule that leaves one on every node is not honouring the preference,
   it is racing it.

   And it left the hover transforms in place. With the duration at 1ms the
   pasted-card settle and the CTA wobble no longer animated, they JUMPED. An
   instantaneous displacement is still motion to the person the rule protects.

   NEUTRALISED: every transition, every animation, and every transform that is
   a CHANGE of state (the pasted-card settle, the button wobble and press, the
   icon-chip nudge, the router arrow slide, the liftable hover, the nav pill's
   fill scale).

   DELIBERATELY KEPT, because neutralising them would be a bug and not a fix:
     static rotation, which is decoration and does not move (the pasted card
       still sits at its angle, the h1 still leans);
     positional transforms, which do a job (translateY parks the skip link
       off-screen; translateX centres the tape on its card; scaleX draws the
       router underline, which with no transition simply appears and is the
       only hover affordance that row has);
     the scribble underline, whose resting state is already drawn, so it is
       present at rest exactly as before.

   The scroll-entry reveals themselves are NOT removed here: content is forced
   visible, which is what the preference asks for. Whether care pages keep
   reveals at all is Wilfred's open fork R-11. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    scroll-behavior: auto !important;
    transition: none !important;
    animation: none !important;
  }
  .reveal,
  html.reveal-ready:not(.reveal-complete) .reveal { opacity: 1; transform: none; }
  .draw path { stroke-dasharray: none !important; stroke-dashoffset: 0 !important; }
  .pasted:hover { transform: rotate(var(--rot, -1.1deg)); }
  .pasted:nth-of-type(even):hover { transform: rotate(1.1deg); }
  [data-surface="quiet"] .pasted:hover { transform: none; }
  .button:hover, .btn:hover,
  .button:active, .btn:active { transform: none; }
  .button:hover .icon-chip, .btn:hover .icon-chip { transform: none; }
  .liftable:hover { transform: none; }
  .nav-link::before { transform: scale(1); }
  .router-row:hover .router-row__arrow,
  .router-row:focus-visible .router-row__arrow { transform: none; }
}

@media (max-width: 1023px) {
  .brand small, .nav__logo span { display: none; }
}

/* Tablet footer. Below the full shell the brand block and five nav columns
   cannot share a row without pushing the nav tracks back under 9.5rem, so the
   brand takes its own row and the nav columns get the whole width. Without
   this the reflow drops one column into the brand's slot with the rest of the
   row empty beside it. */
@media (max-width: 1180px) and (min-width: 768px) {
  .footer-grid { grid-template-columns: repeat(auto-fit, minmax(9.5rem, 1fr)); }
  .footer__brand { grid-column: 1 / -1; }
}

@media (max-width: 767px) {
  .shell { width: min(100% - 2rem, 680px); }
  .site-header, .nav { top: 0.65rem; }
  .nav-pill, .nav__inner { width: calc(100% - 1rem); min-height: 58px; padding-left: var(--space-4); }
  .js .menu-button, .js .nav__toggle { display: block; z-index: 2; }
  .js .nav-links, .js .nav__links { position: fixed; inset: 0; z-index: 1; display: flex; flex-direction: column; align-items: stretch; justify-content: center; gap: 0.35rem; padding: 7rem 2rem 3rem; background: var(--cloth); opacity: 0; visibility: hidden; transition: opacity 260ms var(--ease-weave), visibility 260ms var(--ease-weave); }
  .js .nav-links[data-open="true"], .js .nav__links[data-open="true"] { opacity: 1; visibility: visible; }
  .js .nav-link, .js .nav__links a { justify-content: center; min-height: 52px; font-size: 1.25rem; }
  .trust-strip { grid-template-columns: 1fr 1fr; }
  .trust-item:nth-child(3) { border-left: 0; }
  .trust-item:nth-child(n + 3) { border-top: 1px dashed var(--hairline-firm); }
  .crisis-block, .crisis-box { grid-template-columns: 1fr; }
  .crisis-block__art { grid-row: 1; width: min(56%, 14rem); max-height: 17rem; }
  .care-bridge { grid-template-columns: 1fr; }
  .care-bridge__actions { justify-content: flex-start; }
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer__brand { grid-column: 1 / -1; }
  .footer-locations { grid-template-columns: 1fr; }
}

/* Riso art blend. Transform lives on the img itself, never a wrapper: an
   ancestor transform isolates the blend and the white ground returns (case
   law, brandcraft concept build). Dark keeps the white plate treatment. */
img[src^="/img/themed/"], img[src="/img/homepage-hero.webp"] { mix-blend-mode: multiply; }

/* Dark ground, general rule. Multiply against a near-black ground erases the
   art, and the carve-out had been written per path: /img/themed/ plus one
   filename. Every route that put art anywhere else had to notice the problem
   and solve it again locally, which is the latent class DEC-026 recorded
   after /img/homepage.png needed its own carve-out.

   The blend is therefore neutralised for every image in dark, not for a list
   of paths. Two properties of this rule matter:

   It paints nothing. No background, no padding, no radius. A page that
   already mounts its art on its own white plate cannot be double-plated by
   it, which is why the plate below stays enumerated per art set: a plate is
   an aesthetic decision about one set of drawings, a blend is a correctness
   one about all of them.

   Its weight is deliberate, and measured rather than assumed. img[src] under
   the theme selector outranks a page-local class rule that turns multiply on,
   which is the shape every such rule in this tree has. Under [data-theme] it
   ties with a page rule that also names the img, and source order hands the
   page the win; under prefers-color-scheme the :root:not(...) prefix makes it
   one step heavier and it takes that tie instead. That asymmetry is inherited
   from the plate rules below, not introduced here, and nothing live depends
   on it: no page in this tree declares multiply inside a dark selector.

   Measured 2026-08-09 across 87 pages and 305 images in both dark paths: zero
   resolved to multiply, and this rule changed none of them. It closes the
   class for what comes next rather than fixing anything visible today, so it
   was proven by planting the defect it exists for, not by a green run. */
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) img[src] { mix-blend-mode: normal; } }
[data-theme="dark"] img[src] { mix-blend-mode: normal; }

@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) img[src^="/img/themed/"], :root:not([data-theme="light"]) img[src="/img/homepage-hero.webp"] { mix-blend-mode: normal; background: #FFFFFF; border-radius: var(--radius-card); padding: 4%; } }
[data-theme="dark"] img[src^="/img/themed/"], [data-theme="dark"] img[src="/img/homepage-hero.webp"] { mix-blend-mode: normal; background: #FFFFFF; border-radius: var(--radius-card); padding: 4%; }

.theme-toggle { display: inline-flex; align-items: center; justify-content: center; width: 44px; height: 44px; border: 2px solid var(--hairline-firm); border-radius: 50%; background: transparent; color: var(--ink-2); cursor: pointer; }
.theme-toggle:hover { color: var(--ink); border-color: var(--ink); }

/* ==========================================================================
   LOOK 02 COMPONENTS (v3 additions, kept defined; treatments recalibrated)
   ========================================================================== */

/* The warp field retires visually under paper; the selector stays defined. */
.warp-field { position: relative; isolation: isolate; }
.warp-field::before { content: none; }

.router { border-top: 2px solid var(--ink); }
.router-row { display: grid; grid-template-columns: minmax(0, 4fr) minmax(0, 6fr) auto; gap: var(--space-6); align-items: baseline; min-height: 64px; padding: var(--space-5) 0; border-bottom: 1px dashed var(--hairline-firm); color: var(--ink); text-decoration: none; }
.router-row__title { display: inline-block; position: relative; font-family: var(--font-hand); font-size: clamp(1.2rem, 1.6vw, 1.45rem); font-weight: 700; line-height: 1.25; }
.router-row__title::after { content: ""; position: absolute; right: 0; bottom: -3px; left: 0; height: 3px; border-radius: 2px; background: var(--marker); transform: scaleX(0) rotate(-0.5deg); transform-origin: left center; transition: transform var(--duration-fast) var(--ease-weave); }
.router-row__desc { display: block; color: var(--ink-2); font-size: var(--text-sm); line-height: 1.45; }
.router-row__arrow { flex: 0 0 auto; align-self: center; color: var(--ink-2); transition: transform var(--duration-fast) var(--ease-weave), color var(--duration-fast) var(--ease-weave); }
.router-row:hover .router-row__title::after, .router-row:focus-visible .router-row__title::after { transform: scaleX(1) rotate(-0.5deg); }
.router-row:hover .router-row__arrow, .router-row:focus-visible .router-row__arrow { color: var(--ink); transform: translateX(3px); }

.thread-ribbon { display: flex; position: relative; flex-wrap: wrap; align-items: center; column-gap: clamp(1rem, 2.2vw, 1.75rem); row-gap: 0.35rem; margin: 0; padding: var(--space-4) 0; border-top: 2px solid var(--ink); border-bottom: 2px solid var(--ink); list-style: none; font-variant-numeric: tabular-nums lining-nums; }
.thread-ribbon::before { content: ""; position: absolute; top: -2px; left: 0; width: 56px; height: 3px; background: var(--thread-run); }
.ribbon-fact { display: flex; align-items: center; margin: 0; color: var(--ink); font-size: var(--text-sm); font-weight: 600; line-height: 1.35; }
.ribbon-fact + .ribbon-fact::before { content: ""; flex: none; width: 20px; height: 3px; margin-right: clamp(1rem, 2.2vw, 1.75rem); background: var(--thread-run); }

.crisis-tier-1 { margin-top: var(--space-5); padding: var(--space-5) var(--space-6); border: 1.5px solid var(--hairline-firm); border-radius: var(--radius-sm); background: var(--cloth-card); }
.crisis-tier-1 h3 { margin-bottom: var(--space-2); color: var(--crisis-accent); font-family: var(--font-ui); font-size: var(--text-h3); font-weight: 600; letter-spacing: -0.01em; transform: none; }
.crisis-tier-1 p { margin-bottom: 0; color: var(--ink); font-variant-numeric: tabular-nums lining-nums; }
.crisis-tier { margin-top: var(--space-6); }
/* Crisis path: a label someone may be reading in distress. 14 to 16 (rule 41,
   rule 50). */
.crisis-tier h3 { margin-bottom: var(--space-3); color: var(--ink-2); font-family: var(--font-ui); font-size: 1rem; font-weight: 600; letter-spacing: 0.12em; line-height: 1.3; text-transform: uppercase; transform: none; }
.crisis-lines { margin: 0; padding: 0; list-style: none; border-top: 1px solid var(--hairline); }
.crisis-lines li { margin: 0; padding: var(--space-3) 0; border-bottom: 1px solid var(--hairline); color: var(--ink-2); font-variant-numeric: tabular-nums lining-nums; }
.crisis-lines strong { color: var(--ink); font-weight: 600; }

@media (max-width: 1023px) {
  .router-row { grid-template-columns: minmax(0, 5fr) minmax(0, 5fr) auto; gap: var(--space-5); }
}

@media (max-width: 767px) {
  .router-row { grid-template-columns: minmax(0, 1fr) auto; gap: 0 var(--space-4); align-items: center; padding: var(--space-4) 0; }
  .router-row__title { grid-column: 1; margin-bottom: 0.2rem; }
  .router-row__desc { grid-column: 1; }
  .router-row__arrow { grid-column: 2; grid-row: 1 / span 2; }
  .thread-ribbon { flex-direction: column; align-items: stretch; row-gap: 0; padding: 0; }
  .ribbon-fact { padding: 0.8rem 0; }
  .ribbon-fact + .ribbon-fact { border-top: 1px dashed var(--hairline-firm); }
  .ribbon-fact + .ribbon-fact::before { content: none; }
}

/* ==========================================================================
   BRANDCRAFT PRIMITIVES (v4 additions, 2026-08-08)
   Namespaced. Nothing here shadows an existing class. The paper sheets,
   tape, stamps, pen and marker voices, torn edges, and the settle hover.
   ========================================================================== */

/* Paper sheets: section grounds. The torn edge is the sheet's FIRST child,
   its fill the sheet ABOVE, and the sheet carries no top padding (seam law:
   spacing lives on the inner wrap). */
.sheet-green { background: var(--paper-green); }
.sheet-butter { background: var(--paper-butter); }
.sheet-terra { background: var(--paper-terra); }
.sheet-sky { background: var(--paper-sky); }
.sheet-quiet { background: var(--paper-quiet); }
.sheet-white { background: var(--cloth); }
.sheet-green, .sheet-butter, .sheet-terra, .sheet-sky, .sheet-quiet { padding-top: 0; }
.sheet-green .lede, .sheet-butter .lede, .sheet-terra .lede, .sheet-sky .lede { color: var(--ink); }
/* Legibility floor on paper: prose sitting directly on a colored sheet runs
   full ink (ink-2 measures under 4.5:1 on every paper stock). White cards
   inside keep their own softer hierarchy. */
.sheet-green, .sheet-butter, .sheet-terra, .sheet-sky { color: var(--ink); }
.sheet-green .router-row__desc, .sheet-green .router-row__arrow,
.sheet-terra .fine-print, .sheet-butter .fine-print, .sheet-sky .fine-print { color: var(--ink); }
.torn { display: block; width: 100%; height: 30px; margin-bottom: -1px; }
.torn path { stroke: none; }

/* Paper tooth: one fixed tiled-noise layer, 4%. Cheap, print-safe, and it
   dies under forced-colors. */
.paper-tooth::after { content: ""; position: fixed; inset: 0; pointer-events: none; z-index: 60; opacity: 0.04; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E"); }
@media (forced-colors: active) { .paper-tooth::after { content: none; } }

/* Pasted cards: the wonky card plus tape and the settle hover. Rotation
   lives on the container; running text inside stays level with the card. */
.pasted { position: relative; padding: var(--space-6); transform: rotate(var(--rot, -1.1deg)); transition: transform 350ms var(--ease-settle); }
.pasted:nth-of-type(even) { --rot: 1.1deg; }
.pasted:hover { transform: rotate(0deg); }
.tape { position: absolute; width: 92px; height: 27px; top: -13px; left: 50%; background: var(--tape); border-left: 1px dashed rgb(43 35 32 / 12%); border-right: 1px dashed rgb(43 35 32 / 12%); box-shadow: 0 1px 2px rgb(43 35 32 / 12%); transform: translateX(-50%) rotate(-2deg); pointer-events: none; }
.tape--tl { left: 14%; transform: rotate(-40deg); }
.tape--tr { left: auto; right: 7%; transform: rotate(42deg); }
[data-surface="quiet"] .pasted { transform: none; }
[data-surface="quiet"] .pasted:hover { transform: none; }

/* Stamps: practical facts as rubber stamps. Tabular numerals for data. */
/* The stamp is the eyebrow's twin and moves with it (rule 41, same reasoning
   and the same held absolute tracking). */
.stamp { display: inline-block; padding: 5px 12px 4px; border: 2px solid var(--ink); border-radius: 4px 9px 5px 10px; color: var(--ink); font-size: 1rem; font-weight: 700; letter-spacing: 0.11em; text-transform: uppercase; opacity: 0.9; transform: rotate(-1deg); font-variant-numeric: tabular-nums lining-nums; }
.stamp--alt { transform: rotate(1.2deg); }
.stamp--marker { color: var(--marker); border-color: var(--marker); }
.stamp-wall { display: flex; flex-wrap: wrap; gap: var(--space-3) var(--space-4); }
[data-surface="quiet"] .stamp { transform: none; opacity: 1; }

/* The two hand voices. Marker for display, pen for annotations. The pen
   floor is 24px by law; the class enforces it. */
.hand { font-family: var(--font-hand); font-weight: 700; }
.pen, .annotation { font-family: var(--font-pen); font-size: max(1.5rem, 24px); font-weight: 500; line-height: 1.3; color: var(--ink); }
.pen--marker { color: var(--marker); }
.pen--marker, .annotation--tilt { display: inline-block; transform: rotate(-1.4deg); }

/* The scribble underline. Draw-on once under no-preference; resting state
   is drawn (dashoffset 0) so reduced motion always sees it. */
.scribbled { position: relative; white-space: nowrap; }
.scribbled svg { position: absolute; left: -4%; bottom: -0.18em; width: 108%; height: 0.32em; overflow: visible; pointer-events: none; }
.scribbled path { fill: none; stroke: var(--marker); stroke-width: 5.5; stroke-linecap: round; stroke-dashoffset: 0; }
@media (prefers-reduced-motion: no-preference) {
  .draw path { stroke-dasharray: 340; stroke-dashoffset: 340; animation: bc-draw 750ms var(--ease-weave) 350ms forwards; }
  @keyframes bc-draw { to { stroke-dashoffset: 0; } }
}

/* Stitch line: the thread running between pen numbers and card headers. */
.stitch { flex: 1; height: 8px; }
.stitch path { stroke: var(--marker); stroke-width: 2; stroke-dasharray: 7 6; fill: none; opacity: 0.75; }

/* Note card: ruled paper for the handwritten note moments. */
.note-card { background: repeating-linear-gradient(transparent, transparent 42px, rgb(43 35 32 / 12%) 42px, rgb(43 35 32 / 12%) 43px), var(--cloth-card); }
.note-card .pen { font-size: max(1.75rem, 28px); line-height: 43px; }

/* Peeking illustration: the step-card image that rises over the card top,
   reading as a pasted print. Blend stays on the img (stacking-context law). */
.peek { position: relative; width: 74%; margin: -58px auto 10px; }
.peek img { transform: rotate(-1.6deg); }
.pasted:nth-of-type(even) .peek img { transform: rotate(1.4deg); }

@media (max-width: 767px) {
  .pasted { --rot: -0.5deg; }
  .pasted:nth-of-type(even) { --rot: 0.5deg; }
  .tape { width: 76px; }
  .peek { margin-top: -44px; }
  /* Release the nowrap. The h1 clamp floor is 44.8px and the marker phrase
     cannot break, so in a 343px shell it is amputated by the clip on html
     and body instead of wrapping. inline-block ships with it, not as taste:
     an absolutely positioned child of a WRAPPED inline gets a degenerate
     containing block, which collapsed this underline svg to width 0 and
     painted its stroke at raw viewBox scale, 104px past the viewport on five
     learn pages. Measured by scripts/capture-harness/overflow-probe.js. */
  .scribbled { white-space: normal; display: inline-block; max-width: 100%; }
  .scribbled svg { left: 0; width: 100%; }
}

/* ---------------------------------------------------------------- quiet door
   The email alternative on /contact, for people who reach for contact and do
   not send. Added 2026-08-30 with js/quiet-door.js.

   Uses the existing token set only: no new colour is introduced, and there is
   no one-sided tinted box anywhere in here. Structure is a hairline and type,
   which is the house rule. */

.form-grid { display: grid; gap: 0.9rem; }
.form-grid label {
  display: block;
  font-family: var(--font-ui);
  font-size: 1rem;
  font-weight: 600;
  margin-bottom: 0.35rem;
}
.form-grid input[type="email"],
.form-grid input[type="text"],
.form-grid input[type="tel"] {
  width: 100%;
  font-family: var(--font-ui);
  font-size: 1rem;
  padding: 0.7rem 0.85rem;
  color: var(--ink);
  background: transparent;
  border: 1px solid var(--hairline-firm);
  border-radius: var(--radius-sm);
}
.form-grid input:focus-visible {
  outline: 2px solid var(--thread-sage);
  outline-offset: 2px;
  border-color: var(--thread-sage);
}
.form-grid button[disabled] { opacity: 0.55; cursor: progress; }

.quiet-consent {
  font-family: var(--font-ui);
  /* The four SPDI facts at the point of collection (rule 52). 13.76px to 16px:
     a consent notice nobody can read is not a notice. */
  font-size: 1rem;
  line-height: 1.55;
  color: var(--ink-2);
  margin: 0;
}
.quiet-consent strong { color: var(--ink); font-weight: 600; }

/* The status line occupies no space until it says something, so the form does
   not jump when a message appears. */
.quiet-status {
  /* The form's text error, read beside the field (rule 44). 14.4px to 16px. */
  font-family: var(--font-ui);
  font-size: 1rem;
  margin: 0;
  min-height: 1.5em;
}
.quiet-status[data-state="ok"]    { color: var(--thread-sage); font-weight: 600; }
.quiet-status[data-state="error"] { color: var(--thread-run); font-weight: 600; }
.quiet-status[data-state="busy"]  { color: var(--ink-3); }
