/* Design tokens — variation layer (§3). Inlined into every page's <head> by build-site.mjs
   (INLINE_STYLES token) — this exact file ships verbatim to every site, so keep this header
   short: it is public page source now, not just an authoring note. Full history of the
   2026-08-24 injection fix and the palette/type blocks added below: docs/corrections_register.md.
   Axes 3 (hero) and 4 (section order) are HTML arrangement, not CSS — not addressed here. */

:root {
  /* Palette — DEFAULT is p1's values (deep slate / amber), restated explicitly in the p1 block
     below rather than left as an implicit fallback nothing else matches — every palette is an
     equally real rule now, not four overrides plus one accidental default. */
  --ink: #1b2027;
  --ink-soft: #4a525c;
  --surface: #f7f6f3;
  --surface-alt: #ffffff;
  --line: #ddd9d2;
  --field-border: #96948F;  /* 3.03:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #c8791a;
  --accent-ink: #ffffff;
  /* Link colour. Derived from --accent but darkened for body-text contrast: the raw accent is
     tuned to carry white text on a button, not to be read as 1rem text on a light surface.
     Recomputed per palette below rather than left to inherit one palette's value. */
  --link: #9a5a11;

  /* Type — axis 2, DEFAULT matches t1 */
  --font-head: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700;
  --head-tracking: -0.02em;
  --head-transform: none;

  /* Scale */
  --step-0: 1rem;
  --step-1: 1.15rem;
  --step-2: 1.45rem;
  --step-3: 1.9rem;
  --step-4: 2.4rem;
  --space: 1rem;
  --radius: 6px;
  --measure: 68ch;

  /* CONTAINER (2026-08-26). Was hardcoded inside .wrap as min(100% - 2rem, 1120px). A token,
     because a design direction legitimately sets its own container width and a hardcoded one
     forces every direction to the portfolio default. 1120px stays the default for a site with
     no direction; direction 160 overrides it to SummitRoof's 1280px. GATE 1B now asserts that
     a direction claiming a container_max_width actually declares it. */
  --container: 1120px;
  /* Responsive gutter, adopted from the SummitRoof container (16 / 24 / 32px). */
  --container-pad: 1rem;
}

/* ============================================================
   AXIS 1 — PALETTE. Values from variation-layer.md's own table, verbatim.
   --ink-soft / --surface-alt / --accent-ink are NOT varied per palette (not in that table) —
   they stay at the :root default above for every palette. Known gap, not an oversight to miss.
   ============================================================ */
body[data-palette="p1"] { --ink: #1b2027; --surface: #f7f6f3; --accent: #c8791a;  --link: #9a5a11; } /* deep slate / amber */
body[data-palette="p2"] { --ink: #16241d; --surface: #f5f4ef; --accent: #b5502f;  --link: #8d3d22; } /* forest / clay */
body[data-palette="p3"] { --ink: #111a2e; --surface: #f4f6f9; --accent: #1f5fbf;  --link: #1a4e9c; } /* navy / signal blue */
body[data-palette="p4"] { --ink: #232323; --surface: #f6f3f0; --accent: #a8442c;  --link: #8a3722; } /* charcoal / rust */
body[data-palette="p5"] { --ink: #241f1a; --surface: #f8f5ef; --accent: #8a6b1f;  --link: #6d5417; } /* ironbark / ochre */
/* p6 — direction-library.md 004 "Coastal Split". The first palette taken from that library rather
   than authored here, and the first carrying roles beyond ink/surface/accent. Contrast measured
   2026-08-26: sea on foam 11.67:1, deep-green on foam 7.47:1, sea on coral 3.85:1 (AA-large, and
   the .call button is 23px/700 so that is the applicable threshold), sea on sand 7.37:1.
   Coral is 3.03:1 on foam and is therefore NEVER used for text. */
body[data-palette="p6"] {
  --ink: #093A4A;            /* sea */
  --ink-soft: #456b79;       /* 5.51:1 on foam — small note text still clears AA */
  --surface: #F4FBFA;        /* foam */
  --surface-alt: #ffffff;
  --line: #cfe2e2;
  --field-border: #8B9797;  /* 3.01:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #E66B55;         /* coral — signal only, never text */
  --accent-ink: #093A4A;     /* sea on coral, 3.85:1 */
  --link: #35594A;           /* deep green, 7.47:1 */
  --sand: #D9C7A3;
  --deep-green: #35594A;
}

/* p7 — direction-library.md 160 "Coastal Summit". Central Coast water-and-sky palette, taken from
   the operator-approved reference render (2026-08-26). Six roles beyond ink/surface/accent, because
   the direction genuinely uses them: three ocean depths carry the dark bands, gold carries rules and
   edges, coral carries action.
   CONTRAST MEASURED 2026-08-26, not eyeballed (figures recorded in the deploy log):
     body #22333B on white 13.09:1 · on sky 11.87:1
     headings #083F4F on white 11.45:1 · on sky 10.39:1
     --ink-soft #5A6E77 on white 5.34:1 · on sky 4.85:1
     --link #B5432B on white 5.52:1 · on sky 5.01:1
     white on --accent #E66B55 is 3.18:1 — AA-LARGE ONLY. Coral is therefore NEVER a ground for
       normal-size text. Everything that sits on coral in this palette is >=19px at weight 700 (the
       .call button is 23.2px/700; the CTA band's own copy is forced to 700 and >=19.2px by the
       direction stylesheet), which is the size threshold AA-large applies at.
     white on --ocean-deep 11.45:1 · on --ocean 7.43:1 · gold-bright on --ocean-deep 7.22:1
     --ocean-deep on --gold 6.23:1 (the tag/eyebrow chip) */
body[data-palette="p7"] {
  --ink: #22333B;            /* body text */
  --ink-soft: #5A6E77;       /* muted */
  --surface: #FFFFFF;
  --surface-alt: #EAF6F9;    /* sky */
  --line: #E1ECF0;
  --field-border: #878E90;  /* 3.02:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #E66B55;         /* coral — action only, never a ground for normal-size text */
  --accent-ink: #FFFFFF;
  --link: #B5432B;           /* deepened coral: the raw #C74E36 is 4.17:1 on sky and fails AA there */
  --ocean-bright: #0F7A94;
  --ocean: #0B5D73;
  --ocean-deep: #083F4F;     /* headings, dark bands, footer */
  --sky: #EAF6F9;
  --gold: #E8B93C;           /* rules, edges, chips — never text on a light ground (1.84:1) */
  --gold-bright: #F2C94C;
  --coral-dark: #D4573F;
  --coral-text: #B5432B;
}

/* p8 — direction-library.md 161 "Ipswich Precision". Base navy is the licensed Precision kit's own
   --text-color (#023750), locked by operator directive 2026-08-28; accent is Structural Teal
   (#0E7A93), chosen to sit clear of orange (Raise My House owns it on the Ipswich SERP), red,
   yellow-green and purple.
   CONTRAST MEASURED 2026-08-28 (sRGB relative luminance, not eyeballed):
     navy #023750 on white 12.61:1 (ink for body/headings, comfortably clears AA at any size)
     --ink-soft #4A6579 on white 6.12:1 (muted/secondary text)
     teal #0E7A93 on white 4.97:1 — clears AA for EVERY text size, not just large/bold. Unlike p1's
       accent (darkened separately for --link, see that block's own comment) or p7's coral (AA-large
       only), this accent needed no separate darkened --link value: the raw teal already clears
       normal-text AA on its own, so --link reuses it directly.
     white on teal (button fill, same ratio, direction of comparison does not change it) 4.97:1. */
body[data-palette="p8"] {
  --ink: #023750;
  --ink-soft: #4A6579;
  --surface: #FFFFFF;
  --surface-alt: #EEF7F8;    /* pale teal tint, for band backgrounds */
  --line: #DCE6E9;
  --field-border: #888F90;  /* 3.03:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #0E7A93;
  --accent-ink: #FFFFFF;
  --link: #0E7A93;           /* same as accent — already 4.97:1 on white, no darkening needed */
}

/* p9 — direction 162's palette, derived from the licensed Renovast kit's own scheme-05
   (css/colors/scheme-05.css), the eucalypt-green scheme, for houseraisingsunshinecoast.au.
   Chosen against the SERP: every ranking competitor on the Sunshine Coast house-raising SERP
   is blue, and it separates cleanly from site 2's deep teal (p8).

   CONTRAST CORRECTION — the kit's own primary cannot carry text at body size.
   scheme-05's --primary-color is #4F8A5B. Measured against white it is 4.10:1, which is BELOW
   the 4.5:1 WCAG AA floor for normal-size text. The kit uses it for button backgrounds under
   16px bold white type — 16px bold is NOT "large text" by WCAG (that needs 18.66px bold or
   24px normal), so the kit ships a real AA failure there and we cannot copy it verbatim.
   Resolved by splitting the tone rather than abandoning the scheme:
     --accent       #457C50  darkened eucalypt, 4.94:1 with white — carries ALL text-bearing
                             surfaces (buttons, links, the call CTA)
     --accent-bright #4F8A5B the kit's literal scheme-05 primary, kept exact, for surfaces that
                             carry NO body-size text — decorative bands, rules, icon fills,
                             large display headings (>=24px, where 3:1 applies and it passes)
   Both are genuinely the scheme; only the text-bearing one is darkened. Measured with the sRGB
   relative-luminance formula, not estimated. */
body[data-palette="p9"] {
  --ink: #234233;            /* scheme-05's own --bg-dark-1 — 11.06:1 on white */
  --ink-soft: #5A6E60;       /* 5.48:1 on white — secondary text, still AA at body size */
  --surface: #FFFFFF;
  --surface-alt: #F4F8F3;    /* scheme-05's own --bg-light, exact */
  --line: #D8E3D6;
  --field-border: #8A9189;  /* 3.01:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #457C50;
  --accent-ink: #FFFFFF;
  --accent-bright: #4F8A5B;  /* the kit's literal primary — non-text surfaces only, see above */
  --link: #457C50;
}

/* p10 — PERTH BORE WATER. Blue (water) primary, green (lawn) secondary, operator directive
   2026-08-29 for direction 163. Every value below was MEASURED with tools/build/contrast.mjs, not
   chosen by eye — the same discipline that caught direction 162 shipping a 4.10:1 accent.

   THE MEASUREMENT THAT DECIDED THE GREEN. The obvious "lawn" greens fail body text on white:
   #3E9C57 is 3.44:1 and #2F8A4C is 4.32:1 — both look perfectly healthy and both are below the
   4.5:1 AA floor. #2E7D46 is 5.07:1 and is what ships for anything text-bearing. The vivid green is
   kept EXACTLY as --accent-bright for decorative, non-text surfaces only, so the palette keeps the
   colour the brief asked for without putting it under words.

   Distinct from p8 (Ipswich navy #023750 + teal #0E7A93) and p9 (Sunshine Coast eucalypt) — the
   collision rule in assignments.md is on the combination, and this is a new palette, new type
   pairing and a different metro. */
body[data-palette="p10"] {
  --ink: #0B3C5D;            /* deep bore-water blue — 11.55:1 on white, 10.50:1 on --surface-alt */
  --ink-soft: #4A6B80;       /* 5.67:1 on white, 5.15:1 on --surface-alt — AA at body size */
  --surface: #FFFFFF;
  --surface-alt: #EFF5F9;    /* pale water tint */
  --line: #CFE1EC;           /* hairline — see the 1.4.11 note in the corrections register */
  --field-border: #838F96;  /* 3.02:1 on the field ground and on white — WCAG 1.4.11 */
  --accent: #2E7D46;         /* lawn green, 5.07:1 on white, 4.62:1 on --surface-alt */
  --accent-ink: #FFFFFF;     /* 5.07:1 on --accent */
  --accent-bright: #3E9C57;  /* 3.44:1 — NON-TEXT SURFACES ONLY, never under words */
  --link: #12557F;           /* 7.98:1 on white — blue, deliberately not the green CTA colour */
}
/* p11 — AXIAL CHARCOAL. Site 5, sydneyconcretecancerrepair.au, direction 164.
   Derived from the Axial Construct kit (templates/licensed/axial-construct/), whose own palette is
   amber #FFC631 (29 uses, the dominant accent), navy #001F3F (16), and a charcoal family
   #202C38 / #162739. Measured from the kit's css/index2.css, not eyeballed.

   CHARCOAL, NOT THE KIT'S NAVY — a deliberate departure. #001F3F is a deep navy and p10 (site 4)
   is already built on navy #0B3C5D; two remedial/trade sites in the same blue would read as one
   operator to anyone who saw both. The brief asks for dark charcoal, and the kit supplies one.

   AMBER IS A GROUND, NEVER TEXT. #FFC631 measures 1.57:1 on white — it cannot carry text and
   cannot be a link. It is the chip/step-number/card-edge colour, with --accent-ink the charcoal
   at 9.54:1 on it. This is the same shape as p6's coral, and the reason --accent-ink exists.
   WHITE ON AMBER IS 1.57:1 AND WAS MEASURED BEFORE THIS SHIPPED — the default --accent-ink of
   #ffffff would have failed every badge and step number on the site.

   THE LINK IS A DARKENED AMBER, not a third hue. #7A4E00 is the same warm family taken down until
   it clears AA on both grounds, so the site reads as charcoal + one warm accent as briefed rather
   than acquiring a blue it was never given. */
body[data-palette="p11"] {
  --ink: #1E2830;            /* charcoal — 14.99:1 on white, 13.82:1 on --surface-alt */
  --ink-soft: #4A555E;       /* 7.63:1 on white, 7.04:1 on --surface-alt — secondary text */
  --surface: #FFFFFF;
  --surface-alt: #F4F6F7;
  --line: #D5DBDF;           /* hairline — decorative rules only, 1.4.11 does not apply */
  --field-border: #8A8E91;   /* 3.05:1 on the field ground, 3.30:1 on white — WCAG 1.4.11 */
  --accent: #FFC631;         /* kit amber — GROUND ONLY, 1.57:1 on white, never text */
  --accent-ink: #1E2830;     /* charcoal on amber, 9.54:1 — NOT the #ffffff default, which is 1.57:1 */
  --link: #7A4E00;           /* darkened amber — 7.20:1 on white, 6.64:1 on --surface-alt */
}


/* p12 — "Gold Coast Tideline". balconywaterproofinggoldcoast.au (site 6), direction 165.
   Ocean blue base + warm accent, both taken from the SummitRoof kit+s own ramps (steel / ember) and
   then CORRECTED BY MEASUREMENT — tools/build/contrast.mjs, 2026-09-01, every pair measured on
   BOTH grounds, never eyeballed.

   THE SERP SAYS BLUE. Direction 162 went green precisely because every competitor on its SERP was
   blue; here the instruction is the opposite and the dig agrees — Surface Waterproofing (organic #4,
   map-pack #2) ships a split blue panel and Blutec (#2) a navy. Belonging next to them is the brief.

   TWO COLOURS FAILED AND BOTH LOOKED FINE. The kit+s --ring #EF5F1A is 3.32:1 on white — the same
   healthy-looking body-text failure directions 162 (#4F8A5B, 4.10) and 163 (#3E9C57, 3.44) each
   recorded, now three for three. And #CE420C PASSES on white at 4.76:1 but FAILS as body text on
   --surface-alt at 4.29:1 — fine on one ground, not the other, which is why every pair here is
   measured on both. --accent is therefore #B83609: passes as text on white (5.88) and tint (5.30)
   AND as a ground with white on it (5.88). One value, safe in every direction it is used. */
body[data-palette="p12"] {
  --ink: #143551;            /* steel-900 — 12.67:1 on white, 11.41:1 on --surface-alt */
  --ink-soft: #5A6B7B;       /* slate-500 — 5.49:1 on white, 4.95:1 on --surface-alt */
  --surface: #FFFFFF;
  --surface-alt: #EDF4FA;    /* steel-50 — the ocean tint */
  --line: #CBD5E1;           /* slate-200 hairline — decorative rules only, 1.4.11 does not apply */
  --field-border: #7B8B9D;   /* slate-400 — 3.49:1 on white, 3.14:1 on tint; WCAG 1.4.11 on both */
  --accent: #B83609;         /* ember-700 — text 5.88 white / 5.30 tint; ground 5.88 with white */
  --accent-ink: #FFFFFF;     /* on --accent, 5.88:1 */
  --accent-bright: #EF5F1A;  /* ember-500 — 3.32:1, DECORATIVE SURFACES ONLY, never text, ever */
  --link: #184D7C;           /* steel-700 — 8.78:1 on white, 7.91:1 on --surface-alt */
}

/* p13 — "Brisbane Slate". balconywaterproofingbrisbane.au (site 7), direction 166.
   Slate charcoal base + deep steel accent, both taken from the SAME SummitRoof ramps p12 draws on,
   and then measured on BOTH grounds with tools/build/contrast.mjs, 2026-09-02. Same kit as p12,
   deliberately the opposite end of it: p12 is steel ink with a warm ember accent, p13 is slate ink
   with a cool steel accent, so the two sites in this niche do not read as one operator.

   THE BRISBANE SERP DOES NOT SAY BLUE, WHICH IS WHY THIS IS NOT p12 AGAIN. p12's brief was "belong
   next to them" on a uniformly blue Gold Coast page 1. Brisbane's page 1 is polychrome — Megasealed
   green #009D65, Remedial Property blue #006BBD, S&S Remedial terracotta #CE6348, SealedUp indigo
   #5D4FFF (design read, 2026-09-02). With no house colour to match or avoid, the palette is chosen
   on register: the Brisbane set sells on licensing and liability, and slate over steel is a
   remedial-contractor register rather than a coastal one.

   ⚠ CORRECTED 2026-09-02 (same day). This read "licence/QBCC mentions run 34/15/8/3 across the top
   four" — case-insensitive grep counts over raw HTML, where the 8 was a lowercase `qbcc.png`
   filename repeated across one srcset, not copy. On VISIBLE COPY the four ranking pages read 10 / 3
   / 0 / 0. The claim survives on better evidence: two of the four publish a real QBCC licence number
   (15438819, 15390235), two more do nearby (15116048, 15118532), and the second term's
   People-Also-Ask block is entirely insurance-and-responsibility framed. See
   validation/balcony-waterproofing-brisbane-competitor-coverage-2026-09-02.md and
   docs/corrections_register.md, 2026-09-02.

   TWO COLOURS FAILED ON THE TINT AND BOTH PASSED ON WHITE — the same ground-dependent failure class
   p12 recorded for #CE420C, and the reason every pair here is measured twice:
     #2A6FA8 (steel-500)  5.33:1 on white, 4.49:1 on the tint. Under 4.5 by 0.01. DECORATIVE ONLY.
     #7B8B9D (slate-400)  3.49:1 on white, 2.94:1 on the tint — under WCAG 1.4.11's 3:1 for a
                          control boundary. It is p12's --field-border and it CANNOT be reused here:
                          it clears on p12's lighter #EDF4FA and fails on this darker #E7ECF2.
                          --field-border is slate-500 #5A6B7B instead (5.49 / 4.62).
   That second one is worth stating plainly: a token carried over unchanged from a sibling palette
   in the same kit still has to be re-measured, because the ground moved underneath it. */
body[data-palette="p13"] {
  --ink: #202A34;            /* slate-800 — 14.56:1 on white, 12.26:1 on --surface-alt */
  --ink-soft: #435465;       /* slate-600 — 7.79:1 on white, 6.56:1 on --surface-alt */
  --surface: #FFFFFF;
  --surface-alt: #E7ECF2;    /* slate-100 — a cool grey tint, not p12's ocean #EDF4FA */
  --line: #CBD5E1;           /* slate-200 hairline — decorative rules only, 1.4.11 does not apply */
  --field-border: #5A6B7B;   /* slate-500 — 5.49:1 on white, 4.62:1 on tint; 1.4.11 on both */
  --accent: #184D7C;         /* steel-700 — text 8.78 white / 7.39 tint; ground 8.78 with white */
  --accent-ink: #FFFFFF;     /* on --accent, 8.78:1 */
  --accent-bright: #2A6FA8;  /* steel-500 — 4.49:1 on tint, DECORATIVE SURFACES ONLY, never text */
  --link: #1E5E96;           /* steel-600 — 6.78:1 on white, 5.71:1 on --surface-alt */
}

/* p14 — "Sydney Ledger". balconywaterproofingsydney.au (site 8), direction 167.
   Near-black slate over a darkened verified green. THIRD palette off the SummitRoof ramps after p12
   and p13, and the one that has to work hardest: 165, 166 and 167 are all balcony waterproofing on
   one kit, so the layout system is shared by construction and the visual distance has to come from
   here and from t12. Measured on BOTH grounds with tools/build/contrast.mjs, 2026-09-03.

   THE SYDNEY SERP IS BLUE, WHICH IS WHY THIS IS NOT p13 AGAIN — and the instruction it produces is
   162's, not 165's. Colour read of the five page-1 organic home pages fetched in full during the
   Agent 0d run (2026-09-03, #rrggbb occurrences in served HTML):
     sydneywaterproofingservices  #1B60E0 royal + #1B98E0 sky   |  wsrg  #17A8E0 cyan + #1D4354 slate-teal
     hillswaterproofing           #0A72B6 mid blue              |  sydwaterproofingservices  #2EA3F2 + #54A5DC sky
     endeavoureng                 neutral only, #3A3A3A / #000000, no brand hue
   FOUR OF FIVE ARE BLUE AND THE FIFTH IS NEUTRAL. No warm brand, no green anywhere on page 1.
   165's brief was "the SERP is blue, belong next to them", which was right for the Gold Coast. This
   is the 162 case instead: 162 went green on the Sunshine Coast precisely BECAUSE its SERP was
   uniformly blue, and a fifth blue site in Sydney is the one thing guaranteed not to be told apart.
   p13's deep steel #184D7C is itself a blue and would land inside the SERP's own range.
   ⚠ Evidence grade, stated: page-level colour read of stored fetches, NOT an Agent 0c design SERP
   read — none exists for this niche x geo. Same grade 166 used, one grade below a real 0c pass.

   THE GREEN IS THE KIT'S OWN --success, DARKENED — the same move 162 and 163 made and for the same
   measured reason. #16A34A is the literal value in SummitRoof's :root status ramp and it is
   3.30:1 on white / 3.04:1 on tint: A FAIL for body text, and the FOURTH kit primary in a row to
   look entirely healthy and fail this check (162's #4F8A5B 4.10, 163's #3E9C57 3.44, 165's #EF5F1A
   3.32). It is kept EXACTLY as --accent-bright for non-text surfaces only. Every text-bearing green
   surface uses #136B34.

   ⚠ KNOWN PROXIMITY, RECORDED RATHER THAN LEFT TO BE NOTICED: #136B34 is in the same family as
   p10's #2E7D46 (direction 163, waterboreperth.au). Different niche, different metro, different
   state, so the ledger's collision rule is not engaged — but two mid-dark greens in one portfolio is
   a fact a reader should get from this comment rather than from a screenshot.

   THE FIELD-BORDER MEASUREMENT IS THE INTERESTING ONE, AND IT IS THE THIRD ANSWER THIS TOKEN HAS
   GIVEN. #7B8B9D (slate-400) is p12's --field-border at 3.49:1 on white / 3.14:1 on p12's tint;
   p13 recorded it FAILING at 2.94:1 on its darker #E7ECF2 and replaced it. On p14's lighter #F4F6F9
   it CLEARS at 3.22:1. It is still not taken: 3.22 is a 0.22 margin on a WCAG 1.4.11 control
   boundary, and a token that has now flipped state twice across three grounds in one kit does not
   get a third chance on a 0.22 margin. --field-border is #5A6B7B (5.49 / 5.07) instead. The
   generalisable point is p13's and it survives its own second test: a token carried over from a
   sibling palette in the same kit must be re-measured, because the ground moved underneath it. */
body[data-palette="p14"] {
  --ink: #0C1116;            /* slate-950 — 18.96:1 on white, 17.52:1 on --surface-alt */
  --ink-soft: #33414F;       /* slate-700 — 10.45:1 on white, 9.65:1 on --surface-alt */
  --surface: #FFFFFF;
  --surface-alt: #F4F6F9;    /* slate-50 — a third distinct tint, lighter than p12's #EDF4FA ocean
                                and p13's #E7ECF2 cool grey */
  --line: #CBD5E1;           /* slate-200 hairline — decorative rules only, 1.4.11 does not apply */
  --field-border: #5A6B7B;   /* slate-500 — 5.49:1 on white, 5.07:1 on tint; 1.4.11 on both */
  --accent: #136B34;         /* darkened kit --success — text 6.60 white / 6.10 tint;
                                ground 6.60 with white on it */
  --accent-ink: #FFFFFF;     /* on --accent, 6.60:1 */
  --accent-bright: #16A34A;  /* the kit's literal --success — 3.30:1 white / 3.04:1 tint.
                                DECORATIVE SURFACES ONLY, never text, ever */
  --link: #0F5C2C;           /* 8.12:1 on white, 7.50:1 on --surface-alt — AAA on both */
}

/* p15 — "Brisbane Ironbark". balconywaterproofingbrisbane.au (site 7), direction 166.
   REPLACES p13 ON THIS SITE, 2026-09-04 (operator directive: recolour 7 so it does not read as the
   same site as 6 and 8). p13 is NOT deleted — no other site holds it, but a palette that has shipped
   stays in the file, the same way a superseded direction row stays in the ledger.

   WHY p13 HAD TO GO, and it is a measurement rather than a matter of taste. p12 (site 6) is steel
   ink #143551 with a warm ember accent; p13 (site 7) was slate ink with a DEEP STEEL accent
   #184D7C — and #184D7C is p12's own `--link`. Two of the three balcony sites were therefore
   drawing from the same blue at different jobs, on a shared layout kit, in one niche. That is
   exactly the "visitor recognises two of our sites as one operator" risk the collision rule exists
   to manage, and the rule did not catch it because the rule tests the palette/type/hero/order
   COMBINATION, not whether two palettes share a hex.

   THE ACCENT IS THE LOUDEST ELEMENT ON THE PAGE, SO IT IS WHERE THE DISTANCE IS BOUGHT. The three
   balcony accents are now in three different hue families and no two are adjacent:
     p12 (site 6, Gold Coast)  #B83609  ember, orange-red
     p15 (site 7, Brisbane)    #0E5C63  petrol teal, blue-green
     p14 (site 8, Sydney)      #136B34  green
   Ink moves with it: p12 and p14 are both cool (navy-steel, near-black slate), so p15 goes WARM —
   #2B2118 espresso — which changes the header and footer ground, the single largest block of colour
   on every page, on a site whose layout it cannot change.

   BRISBANE'S SERP PERMITS THIS, WHICH IS WHY IT IS NOT A GUESS. The 0d run records a polychrome
   page 1 — Megasealed green #009D65, Remedial Property blue #006BBD, S&S Remedial terracotta
   #CE6348, SealedUp indigo #5D4FFF. There is no house colour to match and none to avoid, so the
   choice is made on register and on distance from our own siblings rather than on SERP fit. That is
   the same reasoning p13 used; only the sibling set changed.

   EVERY PAIR MEASURED WITH tools/build/contrast.mjs ON BOTH GROUNDS BEFORE IT SHIPPED, 2026-09-04
   (white / --surface-alt #F5F1EC):
     --ink          #2B2118  15.75 / 14.01
     --ink-soft     #5C4B3A   8.32 /  7.40
     --link         #0B4A50   9.95 /  8.85
     --accent       #0E5C63   7.69 /  6.84, and 7.69 as a ground with white on it
     --field-border #8A7864   4.24 /  3.77  — WCAG 1.4.11 needs 3.0; this clears it on both
     --surface on --ink       15.75 (header/footer)
   ALL PAIRS PASS. Nothing here is inherited unmeasured from a sibling palette — the mistake p13
   itself recorded when p12's `#7B8B9D` failed on p13's darker tint at 2.94.

   ⚠ `--field-border` IS DELIBERATELY NOT `#7B8B9D`. That token has now given four answers in four
   groundings across this kit (3.49 white, 3.14 p12 tint, 2.94 p13 tint, 3.22 p14 tint) and was
   refused on p14 for having only 0.22 of margin. #8A7864 is chosen instead because it is a warm
   neutral that belongs to THIS palette and clears the threshold by 0.77 on the tighter ground.

   --accent-bright is decorative only, never text: #17878F is 3.42:1 on white, which fails body. */
body[data-palette="p15"] {
  --ink: #2B2118;            /* espresso — 15.75:1 on white, 14.01:1 on --surface-alt */
  --ink-soft: #5C4B3A;       /* warm mid-brown — 8.32:1 on white, 7.40:1 on tint */
  --surface: #FFFFFF;
  --surface-alt: #F5F1EC;    /* warm paper tint */
  --line: #DDD3C7;           /* hairline, decorative rules only, 1.4.11 does not apply */
  --field-border: #8A7864;   /* warm neutral — 4.24:1 white, 3.77:1 tint; WCAG 1.4.11 on both */
  --accent: #0E5C63;         /* petrol teal — text 7.69 white / 6.84 tint; ground 7.69 with white */
  --accent-ink: #FFFFFF;     /* on --accent, 7.69:1 */
  --accent-bright: #17878F;  /* 3.42:1 — DECORATIVE SURFACES ONLY, never text, ever */
  --link: #0B4A50;           /* deep teal — 9.95:1 on white, 8.85:1 on --surface-alt */
}

/* ============================================================
   AXIS 2 — TYPE PAIRING. Font stacks/weights from variation-layer.md's table. --head-tracking
   for t3 ("wide tracking", no table value) is an implementation choice, not a sourced fact.
   ============================================================ */
body[data-type="t1"] {
  --font-head: ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}
body[data-type="t2"] {
  --font-head: Georgia, "Times New Roman", serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: normal; --head-transform: none;
}
body[data-type="t3"] {
  --font-head: system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 800; --head-tracking: 0.04em; /* "wide tracking" — implementation choice, not sourced */
  --head-transform: uppercase;
}
/* t5 — 004 specifies Manrope + Noto Sans. Both are web fonts; the no-external-request rule wins,
   so this reaches for the same register with system stacks. Documented as an approximation. */
body[data-type="t5"] {
  --font-head: "Segoe UI Variable Display", "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 800; --head-tracking: -0.025em; --head-transform: none;
}
body[data-type="t4"] {
  --font-head: "Segoe UI", system-ui, -apple-system, sans-serif;
  --font-body: Georgia, serif;
  --head-weight: 600; --head-tracking: normal; --head-transform: none;
}

/* t6 — direction 160's pairing, and the FIRST self-hosted web-font pairing in the portfolio.
   t5 above is documented as an approximation precisely because pulling Manrope + Noto Sans from a
   font CDN would break the no-external-request rule. That rule is about EXTERNAL requests, not about
   web fonts as such: a woff2 served from our own origin makes no third-party request, leaks nothing
   to a font CDN, and costs one same-origin fetch cached across every page of the site. So t6 does
   literally what t5 could only approximate.
   Both faces are SIL Open Font License 1.1, downloaded 2026-08-26 from Google Fonts as the LATIN
   SUBSET of each family's VARIABLE font — one file per family covering the whole weight axis
   (Inter 48KB, Sora 25KB; 73KB for the entire type system, cached once per visitor).
   Canonical copies live at templates/design/fonts/. A site assigned t6 must carry them at /fonts/ —
   the GATE 4 pre-check fails a build whose CSS names a font file the build output does not contain,
   so a missing font is a blocked build rather than a silent fallback to system sans. */
@font-face {
  font-family: "Sora";
  src: url("/fonts/sora-var-latin.woff2") format("woff2");
  font-weight: 100 800; 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;
}
/* Archivo — the Axial Construct kit's heading face (t10, site 5). SIL Open Font License 1.1,
   downloaded 2026-08-29 from Google Fonts as the LATIN SUBSET of the variable font: 34,928 bytes
   covering the whole 400-800 weight axis. Same rule as Sora above — a site assigned t10 must carry
   it at /fonts/ or the GATE 4 pre-check fails the build rather than falling back silently. */
@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-var-latin.woff2") format("woff2");
  font-weight: 400 800; 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;
}
/* INTER WAS DROPPED 2026-08-27 (operator directive). Body type now uses the reference render's
   own system stack, which costs no download at all; Inter was the larger of the two webfonts
   at 48KB and it was carrying body copy, where a system stack is indistinguishable at 16-19px
   on the devices this audience uses. Its @font-face block is removed rather than left dangling:
   the GATE 4 pre-check fails a build whose CSS names a font file the output does not carry, so
   an orphaned declaration would be a build failure, not dead code. */
body[data-type="t6"] {
  --font-head: "Sora", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  /* Verbatim from concreting-central-coast-claude.html, line 30. */
  --font-body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --head-weight: 700; --head-tracking: -0.025em; --head-transform: none;
}

/* t7 — direction 161's pairing, and the SECOND self-hosted web-font pairing in the portfolio
   (added 2026-08-28). Unlike t6, BOTH faces are self-hosted here — Plus Jakarta Sans for headings,
   DM Sans for body — because that is the licensed Precision kit's own pairing (its CSS names both
   as web fonts; there is no system-stack fallback to reach for on the body face the way t6 dropped
   Inter). Latin-subset variable fonts, one file per family: 27KB + 36KB, 63KB total, cached once
   per visitor. Fetched directly from Google's CDN (same source the kit's own @import pointed at)
   rather than loaded via that import, so the deployed request stays same-origin. */
@font-face {
  font-family: "Plus Jakarta Sans";
  src: url("/fonts/plus-jakarta-sans-var-latin.woff2") format("woff2");
  font-weight: 200 800; 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: "DM Sans";
  src: url("/fonts/dm-sans-var-latin.woff2") format("woff2");
  font-weight: 100 1000; 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;
}
body[data-type="t7"] {
  --font-head: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: normal; --head-transform: none;
}

/* t8 — direction 162's pairing. ONE family for both roles, which is what the Renovast kit
   actually does: custom-renovation.css sets --body-font AND --heading-font to "Poppins".
   It also @imports Inter alongside it — Inter is NEVER USED. The 14 "Inter" matches in the
   kit's style.css are all `cursor: poInter`, a mangled find-replace by the kit author, so the
   import costs the original a font download it never renders. Not carried across.

   THREE STATIC WEIGHTS, not a variable file, unlike t6/t7 — a constraint, not a preference:
   Poppins has no variable version on Google Fonts (`css2?family=Poppins:wght@300..700` returns
   `400: Font family not found`, checked at source 2026-08-28). 300/600/700 are exactly the
   weights the kit's token block renders; 23.6KB total, still under t7's 63KB. Fetched from
   Google's CDN and self-hosted, so the deployed request stays same-origin — the kit's own
   `@import url(fonts.googleapis.com...)` in custom-renovation.css is an external request §3
   forbids and GATE 1 would refuse, so it is replaced, never inherited. */
@font-face {
  font-family: "Poppins";
  src: url("/fonts/poppins-300-latin.woff2") format("woff2");
  font-weight: 300; 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: "Poppins";
  src: url("/fonts/poppins-600-latin.woff2") format("woff2");
  font-weight: 600; 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: "Poppins";
  src: url("/fonts/poppins-700-latin.woff2") format("woff2");
  font-weight: 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;
}
body[data-type="t8"] {
  --font-head: "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.025em; --head-transform: none;
}

/* t9 — Sora headings + DM Sans body (2026-08-29, direction 163). Both faces are ALREADY
   self-hosted in this file for t6 and t7 respectively, so this pairing adds no new font file and
   no new request: it is a new combination of two files the portfolio already ships. Distinct from
   t6 (Sora + a system body stack) and t7 (Plus Jakarta Sans + DM Sans). Sora's geometric, slightly
   technical display cut suits a drilling trade; DM Sans keeps the body neutral underneath it. */
body[data-type="t9"] {
  --font-head: "Sora", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}
/* t10 — the Axial Construct kit's own pairing, Archivo for headings over Inter for body.
   The kit sets Archivo + Roboto; Roboto is not in this repo and Inter is the neutral grotesque
   already here — but Inter's @font-face was REMOVED on 2026-08-27 by operator directive, body
   type now riding the system stack because a system sans is indistinguishable from Inter at body
   size on this audience's devices and costs no download. That directive stands, so t10 is ONE
   webfont: Archivo for headings, system stack for body. The kit's Roboto is the first named
   fallback, which is what most Android devices resolve to anyway. */
body[data-type="t10"] {
  --font-head: "Archivo", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --head-weight: 700; --head-tracking: -0.015em; --head-transform: none;
}


/* t11 — Sora display over the portfolio system stack. Direction 165 / site 6.
   The SummitRoof kit pairs Sora with Inter. INTER IS NOT AVAILABLE: its @font-face was removed
   portfolio-wide on 2026-08-27 by operator directive and that directive stands, so t11 is ONE
   webfont over the system stack — the same shape as t10 and for the same reason. Sora is already
   self-hosted for t6 and t9, so t11 adds NO new font file and NO new request. Distinct from t9
   (Sora + DM Sans) on the body face. */
body[data-type="t11"] {
  --font-head: "Sora", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}


/* t12 — Plus Jakarta Sans display over Archivo body. Direction 167 / site 8.
   TWO WEBFONTS, AND BOTH ARE ALREADY HERE: plus-jakarta-sans-var-latin.woff2 is self-hosted for t7
   and archivo-var-latin.woff2 for t10, so t12 adds NO new font file — only a new fonts.json entry
   naming the two that already exist.

   FIRST PAIRING IN THE PORTFOLIO WHERE ARCHIVO IS THE BODY FACE, and that is the whole point rather
   than a curiosity. 166 holds Archivo as its DISPLAY face in this same niche (balcony waterproofing,
   Brisbane). 165, 166 and 167 share one kit and therefore one layout system, so type is one of only
   two levers carrying the visual distance between them — reusing Archivo as display here would have
   handed the reader the single strongest cue that the two sites are one operator. Demoting it to
   body and putting Plus Jakarta Sans's humanist geometry on top inverts the relationship instead.

   NOT the system stack for body, unlike t10 and t11. Those two ride the system stack because the
   Inter @font-face was removed portfolio-wide on 2026-08-27 and neither kit's body face survived
   that. Here the body face is one this repo already ships, so the site gets a real pairing at no
   additional request — and on h3, where there is no photograph, the type IS the composition. */
body[data-type="t12"] {
  --font-head: "Plus Jakarta Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--surface);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: var(--step-1);
  line-height: 1.6;
  -webkit-text-size-adjust: 100%;
}

h1, h2, h3 {
  font-family: var(--font-head);
  font-weight: var(--head-weight);
  letter-spacing: var(--head-tracking);
  text-transform: var(--head-transform);
  line-height: 1.15;
  margin: 0 0 0.5em;
}

h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }

p, li { max-width: var(--measure); }

/* ANCHOR TARGETS vs A STICKY HEADER. A fragment jump scrolls the target to the very top of the
   viewport, which is underneath a sticky header — measured at 95px tall, so #quote landed 95px
   out of sight on every page that links to it. scroll-padding-top on the scrolling element is
   the fix for the whole document at once, rather than scroll-margin-top repeated on each target
   and forgotten on the next one. Zero by default; a direction with a sticky header sets the
   variable (see directions/160.css). */
html { scroll-padding-top: var(--sticky-offset, 0px); }

.wrap {
  width: 100%;
  max-width: var(--container);
  margin-inline: auto;
  padding-inline: var(--container-pad);
}
@media (min-width: 48rem) { :root { --container-pad: 1.5rem; } }
@media (min-width: 64rem) { :root { --container-pad: 2rem; } }
/* padding-BLOCK, not the `padding` shorthand. FOUND 2026-08-27 by measuring a page rather than
   reading it: this rule was `padding: calc(var(--space) * 3) 0`, which sets all four sides. Every
   template that writes <section class="section wrap"> — and most of them do — got its inline
   padding zeroed by it, because .section is declared after .wrap at the same specificity.
   Consequence, measured at 1440px on /faq/: the header, breadcrumb and hero all started their
   text at 192px and the section headings started at 160px, a 32px stagger down the page. At
   390px it was worse than cosmetic — section text sat at x=0, hard against the viewport edge
   with no gutter at all, while everything above it was inset 16px.
   A shorthand that only means to set two sides is how a container loses the other two. */
.section { padding-block: calc(var(--space) * 3); }
.section--alt { background: var(--surface-alt); }
.section > .wrap > :is(h2, h3) + p { margin-top: 0.35em; }

/* SECTION HEAD — the reference render's treatment, restored 2026-08-27 (operator directive,
   final). Eyebrow, heading, gold bar, ALL LEFT-ALIGNED, and no supporting lead paragraph.

   This replaces SummitRoof's .sr-section-head, which was centred with a 640px lead. That was
   carried for a day on an earlier directive and is now reversed: the reference render
   (concreting-central-coast-claude.html) left-aligns every section head, and the eyebrow is an
   inline-block there for the same reason it is here — it is a chip of text, not a full-width row.

   NOTHING IS DECLARED HERE. The left-aligned, inline-block, no-lead state is what the base
   stylesheet already produces; the centred version was the addition. It is removed rather than
   overridden, so there is no pair of competing rules for the next reader to reconcile. The .lead
   class and its 640px measure are gone with it — no template emits one any more. */
/* LINKS. Until 2026-08-26 there was NO global anchor rule at all, so every non-.call link on
   every page of every site rendered as a default browser blue/purple underline — including the
   brand and the whole primary nav. Palette assignment is meaningless if the most repeated
   element on the page ignores it. */
a { color: var(--link); text-decoration-color: color-mix(in srgb, var(--link) 40%, transparent); text-underline-offset: 0.15em; }
a:hover { text-decoration-color: currentColor; }
a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }

/* SITE HEADER — a real bar, not naked links on the page background. Ink ground so the tracked
   phone reads as the primary action against it, which is the whole point of the trust surface. */
header { background: var(--ink); color: var(--surface); padding-block: calc(var(--space) * 0.9); }
.header__inner {
  display: grid;
  gap: 0.65rem 1.5rem;
  grid-template-areas: "brand" "call" "nav" "note";
  align-items: center;
}
header .brand { grid-area: brand; }
header .brand a { color: var(--surface); text-decoration: none; font-family: var(--font-head); font-size: var(--step-2); }
/* FIXED 2026-08-26: this was `header > .call`, which matches nothing — the button is a child of
   .header__inner, not of <header>. grid-area and justify-self were both being dropped, so the
   phone button stretched across the full header width at every viewport below 60rem, on every
   site in the portfolio. Caught by the 390px render check, not by any gate: a stretched button
   is valid CSS and valid HTML. */
header .header__inner > .call { grid-area: call; justify-self: start; }
header nav { grid-area: nav; display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem 1.25rem; }
header nav > a, header .nav__dd > summary {
  color: var(--surface); text-decoration: none; font-family: var(--font-head);
  font-size: var(--step-0); padding-block: 0.3rem; border-bottom: 2px solid transparent;
}
header nav > a:hover, header .nav__dd > summary:hover { border-bottom-color: var(--accent); }
header .note { grid-area: note; color: color-mix(in srgb, var(--surface) 72%, transparent); margin: 0; font-size: 0.9rem; max-width: none; }

@media (min-width: 60rem) {
  .header__inner {
    grid-template-areas: "brand nav call" "note note call";
    grid-template-columns: auto 1fr auto;
  }
  header nav { justify-content: flex-start; }
}

/* MOBILE HEADER HEIGHT (2026-08-29, operator directive, portfolio-wide).
   Below 60rem the header is four stacked rows — brand, call, nav, note — and it was eating a
   quarter to nearly half of a phone viewport before any content: measured at 390x844,
   194px on centralcoastconcreting.com, 253px on houseraisingipswich.au, 372px on
   houseraisingsunshinecoast.au. On the last of those the header alone was 44% of the fold, and it
   was the largest single reason the /suburbs/ and /faq/ headings still fell outside it after the
   hero was cut by 41%.

   THREE OF THESE FOUR RULES ARE PROMOTED, NOT INVENTED. They were measured and shipped in
   directions/160.css on 2026-08-27 (224px -> 194px on that one site) and are moved here verbatim
   so every direction inherits them instead of one. That file's working also records two
   alternatives already tried and REJECTED on measurement — do not retry them without new numbers:
     - .brand and .call on ONE row made it WORSE (252px): the call button is ~221px wide and must
       stay at its AA-large size floor, leaving ~113px for the brand, which then wraps to three
       lines and the single row grows taller than the two it replaced.
     - Tightening nav padding-block to fit more links per row cut tap targets from 37px to 32px to
       buy 12px of height. Above the WCAG 2.5.8 24px floor, but paying for header height with hit
       area on a phone is the wrong trade.
   The nav row-gap is deliberately NOT zeroed (4px more) — it is the only separation between two
   rows of adjacent links, and mis-tap protection is worth more than 4px. The nav stays two rows;
   its six labels are identical on every site in the portfolio, so that count is stable.

   The fourth rule, the brand size, is new. It exists because a long brand wrapped to two lines:
   "House Raising Sunshine Coast" cost 81px where a one-line brand costs 37px. It is a clamp, not
   a nowrap — `white-space: nowrap` would send the portfolio's longest brand
   ("Roof Restoration Gosford / Central Coast", 40 characters) off the side of a 390px screen, and
   a header that overflows is worse than a header with a two-line brand. Long names still wrap;
   they just wrap later. */
@media (max-width: 59.99rem) {
  header { padding-block: 0.4rem; }
  .header__inner { gap: 0.35rem 1.5rem; }
  header .brand a { font-size: clamp(0.95rem, 3.7vw, var(--step-2)); }
  /* The service-area statement is §6's State-1 substitute for a street address, so hiding it here
     would matter if this were the only place it appeared. It is not:
     templates/partials/footer.html renders the same "Servicing ..." area line in the footer of
     every page of every site — verified across /suburbs/, /faq/, /pricing/, /contact/ and
     /privacy/ on all three live sites before this rule was generalised. What mobile does lose is
     the response-promise sentence that follows it, which is a service claim and not a §6 or §10
     disclosure; the ACL disclosure line GATE 2 checks for lives in the footer and is untouched.
     Desktop keeps both, as before. */
  header .note { display: none; }
}

/* HERO — 55/45 split-panel composition, the assigned signature move. */
/* padding-block was declared here as `calc(var(--space) * 2.5)` and was DEAD — a second `.hero`
   rule further down this same file (search "Hero — arrangement varies") sets `padding` at the same
   specificity and later in the cascade, so 2.5x never applied to any page on any site. Removed
   2026-08-29 after measuring both: computed hero geometry is byte-identical before and after, on
   every page type at 1440/1024/768/390. Two rules for one property in one file is how an edit gets
   made to the half that has no effect. */
.hero { background: var(--surface-alt); border-bottom: 1px solid var(--line); }
/* Breadcrumb sat flush against the viewport edge while every other element was inside the 1120px
   column, so the trail did not line up with the H1 beneath it. */
.crumb { padding-block: 0.75rem; font-size: 0.9rem; color: var(--ink-soft); }
/* align-items: START, not center. The copy column carries the quote form and is far taller than
   the image; centring left the image floating low with a large void above it, which read as a
   layout bug rather than a composition. Top-aligned, the image sits beside the headline. */
/* RESTRUCTURED 2026-08-26: the hero grid s two columns are now COPY and FORM, not copy and image.
   The image moved OUT of the grid to a direct child of .hero, because a hero photo is a background
   treatment in some directions (160 Coastal Summit) and a side panel in others (004 Coastal Split) —
   it cannot be both while it occupies a grid track. Directions position .hero__media themselves. */
.hero__grid { display: grid; gap: calc(var(--space) * 2); align-items: start; }
.hero__copy > :first-child { margin-top: 0; }
.hero__copy .call { margin-block: var(--space); }
.hero__bluf { font-size: var(--step-2); line-height: 1.5; }

@media (min-width: 60rem) {
  /* Copy left, quote form right. The form is the narrower half: it is a fixed set of fields, and
     giving it the wider track only stretches the inputs. The trust list sits under the copy in
     the left column while the form spans both rows — named areas rather than source order,
     because the source order is set by the 390px fold (see 1-home.html). */
  .hero__grid {
    grid-template-columns: 55fr 45fr;
    grid-template-areas: "copy form" "trust form";
    align-items: start;
  }
  .hero__grid > .hero__copy { grid-area: copy; }
  .hero__grid > .hero__form { grid-area: form; }
  .hero__grid > .trust { grid-area: trust; }
  .hero h1 { font-size: clamp(2.4rem, 3.4vw, 3.2rem); }
}

/* Constrained, never a full-height photo dump: the image is cropped to a landscape band that sits
   above the hero copy. A direction that wants it behind the copy repositions it (see 160). */
.hero__media { margin: 0 0 var(--space); }
.hero__media img { aspect-ratio: 16 / 7; object-fit: cover; max-height: 22rem; border-radius: 0; }
.hero__form > .form { max-width: none; }

/* COMPACT HERO — the /suburbs/ and /faq/ page types only (2026-08-29, operator directive after
   the defect was found on all three live sites). Those two pages are reached by clicking a nav
   tab, and the thing the visitor came for is the section BELOW the hero: the suburb list, or the
   cost answer. Measured before changing anything, at 390x844: the first content heading sat 42px
   below the fold on houseraisingipswich.au and 203px below it on houseraisingsunshinecoast.au —
   the tab landed on a title card and the answer needed a scroll. Home, service, location, pricing
   and contact keep the full hero: on those pages the hero IS the page.

   WHY THE SELECTOR CARRIES `body[data-direction]`, which looks redundant. A direction stylesheet
   is appended AFTER this file (build-site.mjs), and its hero rules are written
   `body[data-direction="160"] .hero` — specificity (0,2,1). A plain `.hero--compact` (0,1,0) or
   `body .hero--compact` (0,1,1) loses to it, silently, on exactly the site with the tallest hero.
   `body[data-direction] .hero.hero--compact` is (0,3,1): it beats the direction's own .hero rules
   regardless of file order, and a direction that genuinely wants its own compact treatment still
   overrides it by writing `body[data-direction="160"] .hero.hero--compact` — same specificity,
   later in the cascade. That escalation path is used by directions/160.css, which has to shorten
   its shoreline wedge to match. Every template emits data-direction unconditionally (it is `""`
   for a site with no direction), so the attribute is always present and this never fails to match.

   NOTHING IS HIDDEN. The BLUF is the quotable answer AI engines lift (§8) and every word of it
   still renders — it is set at the body step instead of --step-2, which is what "compact" means
   here. No clamping, no truncation, no display:none. */
body[data-direction] .hero.hero--compact {
  padding-block: calc(var(--space) * 1.25) calc(var(--space) * 1.5);
}
/* A wayfinding title, not the conversion headline — it names the page, it does not sell. */
body[data-direction] .hero.hero--compact h1 {
  font-size: clamp(1.7rem, 3.2vw, 2.3rem);
  margin-bottom: 0.35em;
}
body[data-direction] .hero.hero--compact .hero__bluf {
  font-size: var(--step-0);
  line-height: 1.55;
  margin-block: 0;
}
body[data-direction] .hero.hero--compact .call { margin-block: calc(var(--space) * 0.85) 0; }
/* And the gap BELOW it. A compact hero is a title card, and 64-100px of air between a title card
   and the content it introduces is the same defect at a smaller scale — it is section rhythm doing
   a job it was not asked to do. Halved on the viewport where it costs the most, and scoped to the
   adjacent sibling so it can only ever affect a page that declares the compact hero: section
   rhythm everywhere else on every page type is untouched. */
@media (max-width: 47.99rem) {
  body[data-direction] .hero.hero--compact + .section { padding-block-start: calc(var(--space) * 2); }
}

/* SEA-COLOURED COPY PANEL — direction 004's hero_treatment, verbatim: "a sea-coloured copy panel
   carries the local-climate BLUF." Opt-in via --panel-ink, so it activates only on a palette that
   defines one (p6 today) and every other palette keeps the plain hero it had. A design direction
   must not silently repaint five palettes it was never assigned to. */
.hero__copy { --panel-pad: 0; }
body[data-palette="p6"] .hero__copy {
  --panel-pad: calc(var(--space) * 1.75);
  background: var(--ink);
  color: var(--surface);
  padding: var(--panel-pad);
  border-radius: var(--radius);
}
body[data-palette="p6"] .hero__copy :is(h1, .hero__bluf) { color: var(--surface); }
body[data-palette="p6"] .hero__form .form label { color: var(--ink); }
body[data-palette="p6"] .hero__copy .consent { color: color-mix(in srgb, var(--surface) 78%, transparent); }
/* The quote form is no longer inside .hero__copy (see the hero restructure note above), so p6 s
   dark-panel treatment no longer inverts it. That is the behaviour the original rule wanted anyway:
   its own comment said the form controls stay on a light ground inside the dark panel. */
body[data-palette="p6"] .hero__copy .consent a { color: var(--sand); }
/* The form's own controls stay on a light ground inside the dark panel — inverting inputs as well
   makes a quote form read as decoration rather than something to fill in. */
body[data-palette="p6"] .hero__form :is(input, select, textarea) { background: #fff; color: var(--ink); }

/* SAND-TONED PRICE TABLE — 004's system_fit: "sand-toned price tables continue". */
body[data-palette="p6"] .prices caption { color: var(--ink); }
body[data-palette="p6"] .prices thead th { background: var(--sand); color: var(--ink); }
body[data-palette="p6"] .prices tbody tr:nth-child(odd) { background: color-mix(in srgb, var(--sand) 26%, transparent); }
body[data-palette="p6"] .prices th, body[data-palette="p6"] .prices td { border-bottom-color: color-mix(in srgb, var(--sand) 70%, transparent); }

/* CLIMATE-NOTE CALLOUT — 004's system_fit: "climate-note callouts ... continue". Presentation only:
   it styles a paragraph of ALREADY-SOURCED weather/drainage copy. It never licenses a new climate
   claim — §5 Pass 5 still requires a named source for anything inside it. */
.climate-note {
  border-left: 4px solid var(--accent);
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  padding: var(--space) calc(var(--space) * 1.25);
  border-radius: 0 var(--radius) var(--radius) 0;
  max-width: var(--measure);
}
body[data-palette="p6"] .climate-note { border-left-color: var(--deep-green); background: color-mix(in srgb, var(--sand) 30%, transparent); }

/* Call button — thumb-reachable, mobile-first (§3 design gate) */
.call {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 56px;
  padding: 0 1.5rem;
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-head);
  font-size: var(--step-2);
  font-weight: 700;
  text-decoration: none;
  border-radius: var(--radius);
}

.call--sticky {
  position: fixed;
  left: 1rem; right: 1rem; bottom: 1rem;
  justify-content: center;
  z-index: 50;
  box-shadow: 0 4px 20px rgb(0 0 0 / 0.25);
}
@media (min-width: 768px) { .call--sticky { display: none; } }

/* Hero — arrangement varies (axis 3), the trust surface does not */
.hero { padding: calc(var(--space) * 2) 0 calc(var(--space) * 3); }
.hero__bluf { font-size: var(--step-2); max-width: 60ch; }
.trust { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; padding: 0; margin: 1.25rem 0 0; list-style: none; }
.trust li { max-width: none; margin: 0; font-weight: 600; color: var(--ink-soft); font-size: 0.95rem; }

/* Quote form */
.form { display: grid; gap: 0.75rem; max-width: 30rem; }
/* `.form { display: grid }` is (0,1,0) and the `hidden` attribute's `display:none` lives in the UA
   stylesheet, which ANY author rule outranks. So `form.hidden = true` sets the attribute and the
   form stays on screen — the success confirmation would appear underneath a form still showing the
   visitor's own typed answers. (0,2,0) here is what actually makes the attribute work. Added
   2026-09-07 with the confirmation itself; found by reading the cascade, not after shipping it. */
.form[hidden] { display: none; }

/* Honeypot — off-screen for a sighted human, out of the accessibility tree for a screen reader
   (paired with aria-hidden + tabindex="-1" on the field itself, partials/quote-form.html).
   Positioned off-canvas rather than display:none/visibility:hidden: those are the two properties
   a bot that actually renders CSS checks for before skipping a field; a simple scraper that
   doesn't render CSS at all fills it either way. */
.hp-field { position: absolute; left: -9999px; top: -9999px; width: 1px; height: 1px; overflow: hidden; }

.form input, .form select, .form textarea {
  min-height: 48px; padding: 0.6rem 0.75rem;
  border: 1px solid var(--field-border); border-radius: var(--radius);
  font: inherit; background: var(--surface-alt); color: var(--ink);
}
/* CHECKBOXES ARE NOT TEXT FIELDS, and the rule above was catching them (fixed 2026-08-29).
   `min-height: 48px` on a bare checkbox does not make a 48px target — it makes a 13px-wide box
   stretched 48px TALL. Measured in the browser at 390px on three of the four live sites:
   13x48px, display:block on the label, checkbox and consent text stacked with no visual
   association between them. Direction 160 had already worked around it locally; the other three
   inherited the distortion, which is the tell that the workaround belonged here all along.
   The tap target is the LABEL — it wraps the input, so the whole consent sentence is clickable,
   which is a larger and more forgiving target than any 44px box. */
/* Specificity is (0,4,2) on the scoped selectors, deliberately. The direction files reach these
   controls through `body[data-direction="160"] .hero__form .form :is(input, select, textarea)` —
   (0,3,2), loading AFTER this file — and `:is()` takes the specificity of its heaviest argument,
   so a plain `.form input[type="checkbox"]` at (0,2,1) loses and the checkbox gets stretched to
   whatever tap-target height that direction sets for TEXT fields. Found twice: 13x48 across three
   sites, then 20x44 on the fourth the moment its local workaround was removed. Writing this at a
   specificity the direction layer cannot undercut is what stops the next direction reintroducing
   it silently. */
.form input[type="checkbox"], .form input[type="radio"],
body[data-direction] .form input[type="checkbox"],
body[data-direction] .form input[type="radio"],
body[data-direction] .hero__form .form input[type="checkbox"],
body[data-direction] .hero__form .form input[type="radio"] {
  min-height: 0;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  padding: 0;
  accent-color: var(--accent);
}
/* THE SUBMIT BUTTON — 2026-09-07, operator report: it renders as PLAIN TEXT on site 10's live
   home page. It was not unstyled. The rule below used to read `background: var(--ink)`, and
   direction 169's h3 hero paints `.hero { background: var(--ink) }` with the quote form inside it —
   so the button was a dark navy block on a dark navy ground with near-white text, which is
   indistinguishable from a line of white text. Nothing was broken in a way any gate could see:
   valid CSS, valid HTML, a real 56px button, invisible.

   THIS IS THE THIRD TIME THIS EXACT SHAPE HAS BEEN FIXED IN THIS FILE. `label.consent` measured
   1.06:1 on direction 163's navy panel; `.form p.consent` measured ~1.5:1 on the same; both were
   fixed by removing an assumption that the form sits on a light ground. `background: var(--ink)`
   was the same assumption in the one place it had not been removed yet.

   THE FIX IS TO MATCH `.call`, not to invent a third button colour: `--accent` on `--accent-ink`
   is the pair every palette already declares AND has measured contrast for (see the p6/p7 notes
   above, and 169's own note recording ink-on-bronze at 6.25:1 where the kit shipped 2.67:1). A
   button that borrows the CALL button's already-measured pair cannot introduce a new contrast
   defect on any of the 38 configs, which a bespoke colour here could. */
.form button {
  min-height: 56px;
  padding: 0 1.5rem;
  border: 0;
  border-radius: var(--radius);
  background: var(--accent);
  color: var(--accent-ink);
  font-family: var(--font-head);
  font-size: var(--step-2);
  font-weight: 700;
  cursor: pointer;
}

/* DISABLED STATE — the button is disabled until the Privacy Act consent box is ticked (§10).
   Set by script only, never in the markup: with JavaScript off the button ships enabled and the
   checkbox's own `required` attribute carries the same rule through native validation, so a no-JS
   visitor is never presented with a control they cannot use.

   SPECIFICITY IS DELIBERATE AND IS THE REASON FOR THE SECOND SELECTOR. Direction stylesheets style
   this button through `body[data-direction="169"] .form button` (0,2,2). A bare
   `.form button[disabled]` is (0,2,1) and would LOSE, so the disabled state would simply not appear
   on exactly the sites that have a direction — i.e. all of them. `body[data-direction]` lifts it to
   (0,3,2). Same reasoning, and the same fix, as the checkbox rules above. */
.form button[disabled],
body[data-direction] .form button[disabled],
body[data-direction] .hero__form .form button[disabled] {
  background: color-mix(in srgb, var(--ink) 12%, var(--surface-alt));
  /* --ink, NOT --ink-soft, and the difference was measured rather than eyeballed. On p17 the mixed
     ground computes to #DADCDF: --ink-soft #63606B on it is 4.44:1, which fails AA normal — and the
     usual "large text may use 3:1" escape does NOT apply, because direction 169 sets this button to
     16px, below the 18.66px bold threshold. --ink on the same ground is 11.95:1. WCAG 1.4.3 does
     exempt inactive controls, and that exemption is deliberately not being leaned on here: a
     disabled button a person cannot read is still a button they cannot read. Disabled is signalled
     by the flat ground, the inset border, the cursor and the hint line below it — not by making the
     label hard to see. */
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--field-border);
  cursor: not-allowed;
}

/* The line that says WHY the button is disabled. A disabled button is not focusable and announces
   nothing, so without this the state is a dead end for anyone who cannot see the checkbox tick.
   Hidden until the script shows it, and hidden again the moment consent is given. */
.form__hint { font-size: 0.9rem; color: inherit; opacity: 0.85; max-width: 44ch; margin: 0; }

/* SUCCESS CONFIRMATION — sits OUTSIDE the form so it survives the form being hidden on success.
   `[hidden]` is restated against `display` here because any layout rule on these classes would
   otherwise beat the attribute and ship a permanently visible success message. */
.form__hint[hidden], .form__success[hidden] { display: none; }
.form__success {
  display: grid;
  gap: 0.35rem;
  max-width: 30rem;
  padding: var(--pad-card, 1rem);
  border: 1px solid var(--line);
  border-left: 4px solid var(--accent);
  border-radius: var(--radius);
  background: var(--surface-alt);
  color: var(--ink);
}
.form__success strong { font-family: var(--font-head); font-size: var(--step-1); }
/* The "Prefer to talk?" line — secondary copy, but it still has to be legible on whatever ground
   the form sits on. --ink-soft was the same dark-on-dark bug the consent label had: on direction
   163's navy hero panel it measured about 1.5:1, and the phone link inside it 1.58:1. Inherit,
   then step back with opacity, so "secondary" is expressed as a relationship to the surrounding
   text rather than as a fixed colour that assumes a light background. 0.8 keeps it above 4.5:1
   against both a white and a navy ground given the body colours in use. */
.form p.consent { font-size: 0.9rem; color: inherit; opacity: 0.85; max-width: 44ch; }

/* PRIVACY ACT CONSENT (§10) — this is the one piece of copy on the page a person is agreeing TO,
   and it was the smallest text in the form. Set deliberately, 2026-08-29, portfolio-wide:

   - SIZE. 1rem, the same as body copy, and never shrunk below it. It was 0.85rem base and
     0.76rem inside direction 160's hero card — 12.16px measured. Consent a reader has to squint
     at is not meaningfully given, and "the card is tight" is not a reason to shrink the one
     sentence carrying a legal obligation. If a hero card cannot fit it, the card gets shorter,
     not the consent.
   - COLOUR. --ink, not --ink-soft. Measured contrast was already passing AA on all four sites
     (11.45 / 5.63 / 5.10 / 5.67) so this is not a contrast fix — it is a de-emphasis fix. The
     muted token is for secondary copy, and this is not secondary.
   - ASSOCIATION. flex row with the box pinned to the first line, so the checkbox visibly belongs
     to the sentence rather than floating above it.

   Specificity is (0,4,2) via `body[data-direction]` so it outranks the per-direction hero-card
   overrides in directions/*.css, which load AFTER this file and previously shrank it. Same
   technique and same reason as the .hero--compact block above. */
.form label.consent,
body[data-direction] .hero__form .form label.consent {
  display: flex;
  align-items: flex-start;
  gap: 0.65rem;
  font-size: 1rem;
  line-height: 1.5;
  /* Floored at 400. Direction 162 sets a 300 body weight, which is a legitimate stylistic choice
     everywhere except here — light type at 16px is the wrong call for the one sentence a person
     is agreeing to, whatever its contrast ratio measures. */
  font-weight: 400;
  /* INHERIT, not a token — corrected 2026-08-29 the same day the token was introduced.
     Setting `color: var(--ink)` assumed the form always sits on a light ground. On direction 163
     the hero paints a dark navy gradient and sets `color: #fff` on the panel, so forcing --ink put
     dark navy text on dark navy: measured 1.06:1 from rendered pixels. The previous --ink-soft was
     the same mistake one shade lighter, which is the defect the operator reported.
     Inheriting takes whatever colour the surrounding form already uses for its own labels — a value
     each direction has ALREADY chosen to suit its own panel — so the consent can never be the one
     element in the form that disagrees with its background. It also means consent reads at the
     same strength as the rest of the form, which is the point: it is not secondary copy. */
  color: inherit;
  max-width: 46ch;
  cursor: pointer;
}
/* THE LINK INSIDE THE CONSENT INHERITS TOO, and is underlined to stay identifiable without
   relying on colour. Same bug as the label, one element deeper, and it survived the label fix:
   --link is a single dark token (#12557F on p10) chosen for light page backgrounds, so on
   direction 163's dark hero panel the words "Privacy Policy" stayed dark blue on dark navy while
   the sentence around them turned white. A screenshot caught it; the pixel probe did not, because
   two words are too small a fraction of the sampled block to move the 2nd/98th percentile.
   currentColor guarantees the link can never contrast worse than the sentence containing it, and
   the underline carries the affordance that colour no longer does — which WCAG 1.4.1 wants anyway.
   This link is the reader's route to the Privacy Policy from the consent they are giving; it is
   the last link in the portfolio that should be hard to see. */
body[data-direction] .hero__form .form .consent a,
.form .consent a {
  color: currentColor;
  text-decoration: underline;
  text-underline-offset: 0.15em;
}

body[data-direction] .hero__form .form label.consent input[type="checkbox"] {
  flex: none;
  margin-block-start: 0.15em;
}

/* GHOST BUTTONS FOLLOW THEIR BAND'S TEXT COLOUR (2026-08-29).
   .btn-ghost is a transparent button defined by its border and its label, so unlike a filled
   button it has no ground of its own and inherits whatever the band behind it is painted with.
   Direction 160 already carried `body[data-direction="160"] .hero .btn-ghost { color: #fff }` —
   it had hit this and fixed it locally. 161, 162 and 163 never did, so on direction 163's navy
   hero the secondary CTA rendered in --link (#12557F) on #093654: 1.58:1, caught by the new
   rendered-pixel gate on its first run, and effectively invisible.

   Third time today a per-direction workaround turned out to be a portfolio rule wearing a local
   disguise (the others: the consent checkbox's min-height, and the consent label's colour). The
   tell is the same each time — one direction has the fix, the rest have the bug, and nothing
   in between says which is intended.

   currentColor for the border and inherit for the text means the control cannot disagree with
   the band it sits in, whichever way that band is painted. Specificity is (0,3,1), equal to
   160's own rule, and this file loads FIRST — so 160's explicit #fff still wins and nothing
   about that direction changes. */
body[data-direction] .hero .btn-ghost,
body[data-direction] .section--cta .btn-ghost {
  color: inherit;
  border-color: currentColor;
}

/* Price table — the AI-citation magnet for cost queries (§3).
   .prices-scroll is the horizontal scroller (partials/price-table.html). The min-width keeps
   the columns readable rather than letting them crush to nothing, and the overflow keeps that
   width inside the box instead of inside the page. */
.prices-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; margin: var(--space) 0; }
.prices-scroll .prices { margin: 0; }
/* Tighten the cells before reaching for the scrollbar: at 390px the three columns fit if the
   padding gives way, and a table you can read without swiping beats one you cannot. The
   wrapper above is the safety net for a table this is not enough for, not the first resort. */
@media (max-width: 30rem) {
  .prices :is(th, td) { padding: 0.6rem 0.4rem; font-size: 0.95rem; }
}
.prices { width: 100%; border-collapse: collapse; margin: var(--space) 0; }
.prices caption { text-align: left; font-weight: 700; padding-bottom: 0.5rem; }
.prices th, .prices td { text-align: left; padding: 0.7rem 0.5rem; border-bottom: 1px solid var(--line); }
.prices td:last-child { white-space: nowrap; font-variant-numeric: tabular-nums; }
/* Dark header row, promoted from direction 160 on 2026-08-29 (base component pass). --ink with
   --surface text rather than --accent: --accent is not guaranteed to carry white at 4.5:1 across
   palettes (p9's literal primary measures 4.10:1 and is decoration-only), while --ink is the token
   that already has to. GATE 1B measures the rendered result either way. */
.prices { background: var(--surface); border-radius: var(--radius-lg); overflow: hidden; }
.prices thead th { background: var(--ink); color: var(--surface); padding: 0.9rem 1rem; font-size: 0.95rem; }
.prices tbody tr:nth-child(even) { background: var(--surface-alt); }

/* `overflow-wrap: anywhere` added 2026-09-20, housekeeping item 108. A .note carries a bare source
   URL on every location page ("Source: https://… — confirm current requirements with …") and on the
   FAQ, and a URL is one unbreakable word wherever the browser finds no break opportunity. Site 1's
   Wamberal page overflowed a 390px viewport by 48px on a 98-character council URL, while two pages
   carrying a LONGER 104-character URL passed — the difference is where the breaks fall, not the
   length, which is why this is a layout rule and not a copy rule.
   It is strictly protective: it changes nothing that already fits, and cannot alter a passing
   layout. ⚠ It reaches a live site only at that site's next deploy. */
.note { color: var(--ink-soft); font-size: 0.9rem; overflow-wrap: anywhere; }

/* Services dropdown (2026-08-26). <details>/<summary>, so it works with no JS and is
   keyboard-operable and screen-reader-announced by the browser itself. On narrow screens it stays
   in flow and pushes the rest of the nav down — a fixed overlay on a 375px viewport covers the
   phone number, and the phone number is the product (§3 design gate). */
.nav__dd { display: inline-block; position: relative; }
.nav__dd > summary {
  cursor: pointer; list-style: none; padding: 0.35rem 0;
  display: inline-flex; align-items: center; gap: 0.3rem;
}
.nav__dd > summary::-webkit-details-marker { display: none; }
.nav__dd > summary::after {
  content: ""; width: 0.45em; height: 0.45em; border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-0.1em);
}
.nav__dd[open] > summary::after { transform: rotate(-135deg) translateY(-0.1em); }
.nav__dd > summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.nav__dd-list { list-style: none; margin: 0.4rem 0 0; padding: 0; }
.nav__dd-list li { margin: 0; }
.nav__dd-list a { display: block; padding: 0.45rem 0; }

/* An open dropdown takes its own row rather than sitting beside the nav links it pushed aside.
   Below 48rem the panel stays IN FLOW deliberately (see the note on this component above: a
   fixed overlay on a 375px viewport covers the tracked phone number, and the phone number is
   the product) — but in flow it was a flex item sharing a line with "Home", which read as two
   overlapping menus rather than one open one. `nav` is a wrap-enabled flex container, so a
   full basis when open is all it takes. */
.nav__dd[open] { flex-basis: 100%; }

@media (min-width: 48rem) {
  /* Desktop only: float the panel so it does not shove the page around on hover-capable screens. */
  .nav__dd[open] { flex-basis: auto; }
  .nav__dd-list {
    position: absolute; top: 100%; left: 0; z-index: 20; min-width: 15rem;
    /* FIXED 2026-08-27: this was `background: var(--bg)`, and --bg is not defined in tokens.css,
       in any palette block, or anywhere else in the portfolio. It resolved to nothing, so the
       floating panel had NO BACKGROUND — the page content ran straight through the open menu on
       every site that did not separately override it. A transparent floating layer is not a
       styling nit; it makes the menu unreadable over a photograph. */
    background: var(--surface-alt);
    border: 1px solid var(--line);
    border-radius: 8px;
    padding: 0.5rem 0.9rem;
    box-shadow: 0 12px 28px rgb(0 0 0 / 22%);
  }
}

/* Illustrative imagery. Never captioned as our own work (§6 State 1) — the alt text carries
   "illustrative example" and no figcaption element is used anywhere. */
.hero__media, .section__media { display: block; margin: var(--space) 0; }
.hero__media img, .section__media img {
  width: 100%; height: auto; border-radius: 8px; display: block;
}

/* FOOTER. Full-bleed element, wrapped inner content — same shape as the header, and for the same
   reason: `class="wrap"` used to sit on <footer> itself, so any footer background stopped at the
   content column and left the page surface showing down both sides. Fixed 2026-08-26.
   Column layout and spacing adopted from the SummitRoof reference system (2fr 1fr 1fr, 64px gap,
   two columns at 900px, one at 560px; 80px top / 32px bottom) — see the extraction table in
   docs/corrections_register.md. */
footer { border-top: 1px solid var(--line); padding-block: 5rem 2rem; }
.footer__inner { display: grid; gap: 2.5rem; }
@media (min-width: 35rem) { .footer__inner { grid-template-columns: 1fr 1fr; gap: 2.5rem; } }
@media (min-width: 56.25rem) { .footer__inner { grid-template-columns: 2fr 1fr 1fr; gap: 4rem; } }
.footer__col > :first-child { margin-top: 0; }
.footer__brand { font-size: var(--step-2); margin-bottom: 0.4em; }
.footer__col h3 { font-size: 0.82rem; text-transform: uppercase; letter-spacing: 0.08em; margin-bottom: 0.9rem; }
.footer__phone { font-size: var(--step-2); font-family: var(--font-head); font-weight: 700; margin: 0.5rem 0; }
.footer__list { list-style: none; padding: 0; margin: 0; }
.footer__list li { margin-bottom: 0.55rem; max-width: none; }

/* The trailing legal block. The rule above it separates it from the columns — which only works
   because the disclosure is now the LAST thing in the footer. It used to be the FIRST, which
   rendered an empty band and a stray horizontal rule above nothing at all. */
.disclosure { font-weight: 600; margin-top: 2.5rem; padding-top: 1.5rem; border-top: 1px solid var(--line); }
.disclosure p { font-size: 0.87rem; max-width: 80ch; margin: 0 0 0.5rem; }

/* Clearance for the sticky mobile call bar, which is fixed to the bottom edge below 768px and
   would otherwise sit on top of the ABN line. Paired with .call--sticky's own media query. */
@media (max-width: 47.99rem) { footer { padding-bottom: 6rem; } }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

/* ============================================================================================
   BASE COMPONENT LAYER — promoted from direction 160, 2026-08-29 (operator doctrine).
   ============================================================================================

   THE DOCTRINE, so this block is not re-litigated: site 1's component pattern IS the portfolio
   base. Direction files supply palette, type pairing, hero treatment and imagery only, and depart
   from the base only where a site's SERP dig says that niche genuinely looks different. The design
   target is a good local tradie's own site — plain, dense, specific — not a template demo.

   WHY THIS EXISTS AT ALL. Before this block, the builder emitted a whole family of class names that
   tokens.css styled ZERO rules for: .svc*, .steps/.step*, .wp*, .why__*, .services, .suburbs,
   .chips, .eyebrow, .area__*, .hero__ctas. Direction 160 had grown 154 selectors implementing them;
   161/162/163 had 43-71 and re-invented or simply omitted each one. Measured consequences, all
   found in a single day:
     · .wp badge chips had 0 rules in the base AND 0 in direction 163, so site 4 shipped its
       Ground / Depth / Roster / Scope badges completely unstyled;
     · the consent checkbox's min-height fix existed only in 160 while three sites rendered a
       13x48px distortion;
     · .btn-ghost's dark-hero colour fix existed only in 160 while site 4 shipped a 1.58:1 CTA.
   Three instances of one shape: ONE DIRECTION HAS THE FIX, THE REST HAVE THE BUG, and nothing in
   between says which was intended. A base that styles nothing guarantees that shape recurs.

   PALETTE-NEUTRAL BY CONSTRUCTION. Everything below uses only portfolio tokens — --ink, --ink-soft,
   --surface, --surface-alt, --line, --accent, --link, --space, --radius. Direction 160's own rules
   reach for --ocean-deep, --gold and a literal #E1ECF0, which are p6/p7 palette values; promoting
   those verbatim would have made every site look like site 1, which is the opposite of the
   doctrine. The SHAPE is promoted; the COLOUR stays per-palette.

   SPECIFICITY IS DELIBERATELY LOW — plain class selectors, no body[data-direction] prefix. The
   direction stylesheets load after this file and every rule in them is at least (0,2,x), so any
   direction that wants to depart still wins by simply existing. This is a floor, not a ceiling.
   The two exceptions elsewhere in this file that DO out-specify directions (.hero--compact, the
   consent block) are there because they encode a compliance or legibility requirement a direction
   must not be able to undo by accident. Component shape is not in that category. */

/* Layout tokens the components need. These lived only in direction 160 (--pad-card, --gap-grid,
   --radius-lg/md, --shadow-*), which is why nothing else could use its components. They are
   spacing, radii and elevation — neutral, not palette — so they belong here. 160 redefines all of
   them inside its own block and therefore does not change. 161/162/163 already define their own
   --shadow-sm/md and 163 its own --gap-grid; those continue to win. */
:root {
  --pad-card: 24px;
  --gap-grid: 24px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 0.06), 0 2px 8px rgb(0 0 0 / 0.05);
  --shadow-md: 0 4px 12px rgb(0 0 0 / 0.08), 0 8px 24px rgb(0 0 0 / 0.06);
  --shadow-lg: 0 12px 32px rgb(0 0 0 / 0.10), 0 24px 64px rgb(0 0 0 / 0.08);
}

/* --- 1. PHOTO SERVICE CARDS -----------------------------------------------------------------
   .svc-grid > .svc > .svc__link > (.svc__media, .svc__body > .svc__title/.svc__text/.svc__more).
   .svc__media and .svc__body are SPANs; they only blockify because .svc__link is a flex column —
   direction 162 learned that the hard way and its note is worth keeping in mind before changing
   the display value here. */
.svc-grid { display: grid; gap: var(--gap-grid); grid-template-columns: 1fr; list-style: none; padding: 0; margin: 2rem 0 0; }
@media (min-width: 37.5rem) { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 56.25rem) { .svc-grid { grid-template-columns: repeat(3, 1fr); } }
.svc {
  max-width: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-top: 4px solid var(--accent);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.svc__link { display: flex; flex-direction: column; height: 100%; color: inherit; text-decoration: none; }
.svc__media { display: block; min-width: 0; }
.svc__media img { display: block; width: 100%; height: auto; aspect-ratio: 16 / 10; object-fit: cover; }
/* A card with no image in the pack keeps the same height discipline WITHOUT borrowing another
   service's photograph — a tinted band stands in for the picture rather than a picture of
   something else. That is a §6/§5 rule, not a styling preference: captioning one job as another
   is the same failure as a fabricated price, wearing a photo. */
/* TEXT-ONLY CARDS — a grid where NO card has an image (2026-09-07). The band above is what an
   imageless card wears when its SIBLINGS have photographs; with no such sibling it stands in for
   nothing, and site 10 shipped seven identical grey boxes live. `.svc--textonly` is emitted by
   buildServiceCards instead of `.svc--noimage` in that case, so this needs no rule of its own to
   suppress the band — it simply never matches the ::before selector. The accent stays visible as
   the card's existing 4px top border, so a text-only card still reads as a card. The one extra
   declaration is breathing room the band used to provide. */
.svc--textonly .svc__body { padding-top: calc(var(--pad-card) * 1.15); }

.svc--noimage .svc__link::before {
  content: "";
  display: block;
  aspect-ratio: 16 / 10;
  border-bottom: 4px solid var(--accent);
  background: linear-gradient(160deg, var(--surface-alt), color-mix(in srgb, var(--ink) 12%, var(--surface-alt)));
}
.svc__body { display: flex; flex-direction: column; flex: 1; padding: var(--pad-card); }
.svc__title { font-family: var(--font-head); font-size: 1.13rem; font-weight: 700; color: var(--ink); margin-bottom: 0.35em; display: block; }
.svc__text { color: var(--ink-soft); font-size: 0.97rem; flex: 1; }
.svc__more { margin-top: 0.9rem; font-weight: 700; color: var(--link); display: block; }
.svc__link:hover .svc__more { text-decoration: underline; }

/* Group label — a heading INSIDE the card grid, separating money services from structural
   adjacents. It is a grid item like the cards are, so without `grid-column: 1 / -1` it silently
   consumes one card cell and staggers everything after it. That is precisely what site 4 shipped:
   three labels, three lost cells, a grid that looked broken for a reason nothing named.
   Styled only in direction 162 before this. role="presentation" in the markup keeps it out of the
   accessibility tree — it is a visual grouping, and the cards below it already say what they are. */
.svc-group-label {
  grid-column: 1 / -1;
  max-width: none;
  margin: 0.5rem 0 0;
  font-family: var(--font-head);
  font-size: 0.82rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.svc-group-label:first-child { margin-top: 0; }

/* --- 2. ICON-BADGE ROW (why-points) ----------------------------------------------------------
   .wp > .wp__chip + .wp__body(.wp__title + .wp__text). The chip carries a 2-6 character label —
   "1:1", "$", "REC", "CC", "QBCC", "Ground" — and is aria-hidden, so it is decoration beside the
   title that actually names the point. Sized as a square so a one-character label and a six-
   character one do not produce two different row heights. */
/* --- 1B. THE WHY PANEL'S GRID AND MEDIA — ADDED 2026-09-03 AFTER A MEASURED OVERFLOW -----------
   ⚠ `.why__grid` AND `.why__media` HAD NO RULE ANYWHERE, IN THE BASE OR IN ANY DIRECTION, AND THE
   RESULT WAS A HORIZONTAL PAGE OVERFLOW ON EVERY SITE THAT SHIPS A WHY IMAGE.
   `<picture class="why__media">` defaults to display:inline and its `<img width="1200">` had
   nothing constraining it: the base's own image rule is scoped `.hero__media img, .section__media
   img` and does not match `.why__media img`, and this stylesheet declares NO global
   `img { max-width: 100% }`. So the image laid out at its intrinsic 1200px on every viewport.

   MEASURED, NOT INFERRED — `node tools/build/render-check.mjs <domain> --container 1280px`,
   2026-09-03, the first time that tool has ever been run on these three sites:
     1024px  horizontal overflow 208px :: PICTURE.why__media | IMG
      768px  horizontal overflow 456px :: PICTURE.why__media | IMG
      390px  horizontal overflow 826px :: PICTURE.why__media | IMG
   IDENTICAL on balconywaterproofinggoldcoast.au, balconywaterproofingbrisbane.au and
   balconywaterproofingsydney.au. It is a base defect, not a direction's choice, which is why the
   fix belongs here and not in a direction file — fixing it in one direction would have left the
   other two broken AND made the third differ from them.

   MEASURED AT SOURCE from the licensed kit rather than invented —
   C:\DRE-kits\summitroof-2.6\summitroof\assets\css\style.css:311-314:
     .sr-whyus .sr-container{display:grid;grid-template-columns:1fr 1fr;gap:64px;align-items:center}
     .sr-whyus__media{border-radius:var(--radius-xl);overflow:hidden;box-shadow:var(--shadow-lg);aspect-ratio:5/4}
     .sr-whyus__media img{width:100%;height:100%;object-fit:cover}
     @media(max-width:900px){.sr-whyus .sr-container{grid-template-columns:1fr;gap:40px}}
   and from its :root — `--radius-xl:24px`, `--shadow-lg:0 24px 48px rgba(12,17,22,.14)`.

   LITERALS FOR RADIUS AND SHADOW, for the reason 166 and 167 both already record: this stylesheet
   stops at `--radius-lg: 16px` and has no `--radius-xl`, and its own `--shadow-lg` is a different
   two-layer value than the kit's. `var(--radius-xl)` would resolve to nothing.

   THE 900px COLLAPSE IS THE KIT'S OWN BREAKPOINT, kept because it is what stops the two-column
   panel becoming two unreadable slivers on a tablet — which is the width band render-check was
   widened to cover on 2026-08-28 after the Precision-kit mid-width gap. */
.why__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: center; }
@media (max-width: 900px) { .why__grid { grid-template-columns: 1fr; gap: 40px; } }
.why__media {
  display: block;
  border-radius: 24px;
  overflow: hidden;
  box-shadow: 0 24px 48px rgba(12, 17, 22, 0.14);
  aspect-ratio: 5 / 4;
  margin: 0;
}
.why__media img { width: 100%; height: 100%; object-fit: cover; display: block; }

.why__points { display: grid; gap: 1.1rem; list-style: none; padding: 0; margin: 1.5rem 0 0; }
.wp { display: flex; gap: 0.9rem; max-width: none; align-items: flex-start; }
.wp__chip {
  flex: none;
  display: grid;
  place-items: center;
  min-width: 44px;
  height: 44px;
  padding: 0 0.5rem;
  border-radius: 10px;
  background: var(--accent);
  color: var(--accent-ink, #fff);
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 0.9rem;
  line-height: 1;
}
.wp__body { display: block; min-width: 0; }
.wp__title { display: block; font-family: var(--font-head); color: var(--ink); font-size: 1.02rem; margin-bottom: 0.2em; }
.wp__text { color: var(--ink-soft); font-size: 0.95rem; }

/* --- 3. NUMBERED STEP CARDS ------------------------------------------------------------------
   The number is a CSS counter, not content: it is presentational, it must not be read out twice by
   a screen reader alongside a step title that already says what the step is, and renumbering a
   list must never mean editing content-tokens.json. */
.steps { display: grid; gap: var(--gap-grid); grid-template-columns: 1fr; list-style: none; padding: 0; margin: 2rem 0 0; counter-reset: step; }
@media (min-width: 37.5rem) { .steps { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 56.25rem) { .steps { grid-template-columns: repeat(4, 1fr); } }
.step {
  counter-increment: step;
  max-width: none;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  padding: var(--pad-card);
}
.step::before {
  content: counter(step);
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  margin-bottom: 0.9rem;
  border-radius: 50%;
  background: var(--accent);
  color: var(--accent-ink, #fff);
  font-family: var(--font-head);
  font-weight: 800;
  font-size: 1.25rem;
}
.step__title { display: block; font-family: var(--font-head); color: var(--ink); font-size: 1.08rem; margin-bottom: 0.3em; }
.step__text { color: var(--ink-soft); font-size: 0.95rem; }

/* --- 4. EYEBROW LABEL ------------------------------------------------------------------------
   A small-caps label above a heading. --link rather than --accent: on several palettes --accent is
   a non-text-safe brightness (p9's #4F8A5B measures 4.10:1 and is kept for decoration only), and
   an eyebrow is text. */
.eyebrow {
  display: inline-block;
  margin: 0 0 0.7rem;
  font-family: var(--font-head);
  font-size: 0.78rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--link);
  max-width: none;
}

/* --- 5. PRICE TABLE, DARK HEADER ROW — folded into the .prices block further up this file
   rather than added here, so the table has ONE definition. Two blocks styling one component in
   one file is how a rule gets changed in the place that is not winning. */

/* --- 6. SUBURB CHIPS -------------------------------------------------------------------------- */
.chips { display: flex; flex-wrap: wrap; gap: 10px; margin: 20px 0; padding: 0; list-style: none; }
.chips li { max-width: none; margin: 0; }
.chips :is(span, a) {
  display: inline-flex;
  align-items: center;
  padding: 8px 16px;
  border-radius: 999px;
  background: var(--surface);
  border: 1px solid var(--field-border);
  color: var(--ink);
  font-size: 0.92rem;
  text-decoration: none;
}
.chips a:hover { background: var(--surface-alt); }

/* --- 7. TRUST STATEMENTS — already based (see the .trust rules further up this file). Kept as a
   numbered placeholder so this list matches the approved component table rather than silently
   skipping 7; the original rules were extended in place instead of duplicated here. */

/* --- 8. HERO CTA PAIR -------------------------------------------------------------------------
   Emitted by four templates and, before this, styled in exactly one direction. Wraps rather than
   shrinking: a phone number that has to be squinted at is worse than one on its own line. */
.hero__ctas { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; margin-block: calc(var(--space) * 1.1) 0; }

/* --- 9. CTA BAND ------------------------------------------------------------------------------ */
.cta__actions { display: flex; flex-wrap: wrap; gap: 0.75rem; align-items: center; justify-content: center; margin-top: 1.25rem; }

/* --- 10. SERVICE-AREA LAYOUT ------------------------------------------------------------------
   Two columns where there is room, copy above media when there is not. .area__media currently has
   no content on any site — the Google embed it used to hold was removed on 2026-08-29 as a State-1
   defect (see 1-home.html) — and it stays laid out here so the SVG service-area map drops into a
   slot that already works rather than arriving with its own layout. */
.area__grid { display: grid; gap: var(--gap-grid); grid-template-columns: 1fr; align-items: start; }
@media (min-width: 56.25rem) { .area__grid { grid-template-columns: 1.1fr 1fr; } }
.area__copy p { max-width: 56ch; }
.area__media { min-width: 0; }


/* --- 10a. SERVICE-AREA MAP -------------------------------------------------------------------
   Base-layer component (30 Aug 2026). Fills the .area__media slot the Google embed left empty.
   COLOUR IS DELIBERATELY NOT ACCENT-BASED. Every mark is --ink or --ink-soft on the section's own
   ground, because those two are the tokens every direction already measures for contrast, and
   because an accent is not safe to assume: direction 164's amber is 1.57:1 on white and would fail
   1.4.11 as a dot. Primary areas differ by SIZE, not hue, which also survives a colour-blind
   reader. No new tokens — the requirement was per-site palette only. */
.area-map { margin: 0; }
.area-map__svg { display: block; width: 100%; height: auto; overflow: visible; }
/* The outline is CONTEXT, not a boundary — deliberately faint, and never the thing a reader reads
   first. Fill uses the ink at low alpha rather than a surface token so it works on either ground. */
.area-map__region { fill: color-mix(in srgb, var(--ink) 7%, transparent); stroke: var(--ink-soft); stroke-width: 3; }
.area-map__dot { fill: var(--ink); }
.area-map__dot--primary { fill: var(--ink); }
.area-map__leader { stroke: var(--ink-soft); stroke-width: 2; }
/* 15px is above the 1.4.3 small-text floor and is measured as small text (4.5:1), never claimed as
   large text to buy the easier 3:1 threshold. */
/* font-size is in SVG USER UNITS, set by area-map.mjs to land near 15px after the viewBox scale.
   Overriding it here in px would undo that — see the RENDER_SCALE comment in area-map.mjs. */
.area-map__label { fill: var(--ink); font-weight: 600; }
.area-map__caption, .area-map__unmapped { color: var(--ink-soft); font-size: var(--step-0); margin-top: 0.5rem; }

@media (prefers-reduced-motion: no-preference) { .area-map__svg { transition: none; } }


/* --- 10b. SERVICE-AREA MAP: LABELS ARE A WIDE-CONTAINER LUXURY ---------------------------------
   Checked at 390px, not only at 1440px, and that is what produced this block. SVG text scales with
   the viewBox: the suburb labels are sized to read at the ~556px column a 1440px desktop gives
   them, and on a 390px phone the same map renders them at 10.3px with the longest name clipped off
   the edge. Twenty-five of them, unreadable.

   The switch is a CONTAINER query, not a viewport one, because the viewport is the wrong thing to
   ask. .area__grid is single-column below 56.25rem, so the map is WIDER at 768px (~700px, labels at
   ~21px) than it is at 900px, where the two-column grid first hands it a ~400px slot and the labels
   drop to ~12px. A viewport breakpoint would have shown labels at exactly the width they stop being
   readable. The container query keys off the slot the map actually gets, so it is right at every
   width including ones nobody thought to test.

   460px is the threshold because the label is 30 user units in a 1000-unit viewBox: 30 x (460/1000)
   = 13.8px rendered, which is the floor worth showing. Below it the dots and the region stay as
   context and the list below carries the names. */
.area__media { container-type: inline-size; }

.area-map__label, .area-map__leader { display: none; }
.area-map__list {
  list-style: none; margin: 0.5rem 0 0; padding: 0;
  display: flex; flex-wrap: wrap; gap: 0.25rem 0.75rem;
  color: var(--ink); font-size: var(--step-0);
}
.area-map__list li::after { content: "·"; margin-left: 0.75rem; color: var(--ink-soft); }
.area-map__list li:last-child::after { content: ""; margin-left: 0; }

/* A DENSE MAP NEVER GETS LABELS, AT ANY WIDTH. area-map.mjs measures how far the worst label had
   to slide from its own dot and stamps .area-map--dense past a quarter of the map height. Width is
   not the variable there — the points are simply too close together for a label to sit beside the
   thing it names — so no container is ever wide enough and the list carries the names instead. */
@container (min-width: 460px) {
  .area-map:not(.area-map--dense) .area-map__label { display: block; }
  .area-map:not(.area-map--dense) .area-map__leader { display: block; }
  .area-map:not(.area-map--dense) .area-map__list { display: none; }
}

/* --- 11. SERVICES / SUBURBS SECTION WRAPPERS -------------------------------------------------- */
.services, .suburbs { display: block; }

/* p16 — direction 168 "Newcastle Sandstone". Site 9, dental implants x Newcastle.
   TEAL AND SAGE ARE EXCLUDED BY OPERATOR DIRECTIVE (4 Sep 2026), which rules out the Fertilys
   kit's own accents outright: its --theme-color3 is #005252 (teal) and --theme-color4 is #87c03d
   (sage-green). This palette is therefore NOT taken from the kit, unlike p13/p15 from SummitRoof.
   The kit supplies the LAYOUT SYSTEM only; the colour is chosen against it.

   WHY BURGUNDY AND NOT ANOTHER BLUE. The portfolio's cool half is crowded — p3 navy/signal blue,
   p13 slate/steel #184D7C, p15 petrol teal, p14's green. A seventh cool palette would read as the
   same operator to anyone who saw two of these sites. Burgundy is the first warm-dark accent in the
   portfolio and is at maximum distance from every live row.

   AND IT SUITS AN AHPRA SITE, which is the real constraint. A regulated health advertisement may
   not read as promotional (GATE 2A bans urgency and inducement language), so the palette carries
   the restraint the copy is forbidden from abandoning: warm sandstone ground, near-black ink,
   one deep accent used sparingly. No yellow — the kit's #ffd15b is a promotional colour and would
   fight the compliance posture on every page.

   CONTRAST MEASURED BEFORE SHIPPING, not asserted (the site-8 precedent, where two inherited values
   failed on a sibling palette). All six pairs pass WCAG 1.4.3 at 4.5:1 for normal text:
     ink #16181C on surface  16.06:1     accent on surface        7.35:1
     link #7A2833 on surface  8.71:1     white on accent          8.14:1
     white on ink            17.77:1     accent on white          8.14:1
   Nothing in this palette relies on the 3:1 large-text or boundary allowance. */
body[data-palette="p16"] {
  --ink: #16181C;
  --surface: #F6F3EE;
  --accent: #8C2F39;
  --link: #7A2833;
}

/* t13 — Archivo display over DM Sans body. Direction 168 / site 9.
   ADDS NO FONT FILE AND NO REQUEST: archivo-var-latin.woff2 is already self-hosted for t10 and
   dm-sans-var-latin.woff2 for t9. Same precedent as t12, which paired two faces this repo already
   shipped rather than introducing one.

   THE KIT'S OWN PAIRING CANNOT BE USED. Fertilys sets "GT Walsheim Pro" for body and "Work Sans"
   for headings. GT Walsheim Pro is a commercial licence this repo does not hold, and Work Sans has
   no file here — so copying the kit's type would mean either a licence we do not have or an
   external request the no-external-request rule forbids. This is the pairing chosen against that
   constraint, not a preference.

   ARCHIVO AS DISPLAY, NOT BODY — the inverse of t12. t12 demoted Archivo to body specifically
   because 166 held it as display in the same niche and metro. Site 9 is a different niche in a
   different metro with no sibling, so that constraint does not apply and Archivo's grotesque
   authority is usable where it works best. DM Sans underneath is a humanist geometric that reads
   calm at body size, which is what a health page needs to do. */
body[data-type="t13"] {
  --font-head: "Archivo", "Segoe UI Variable Display", "Segoe UI", system-ui, sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.015em; --head-transform: none;
}

/* p17 — direction 169 "Illawarra Bronze". Site 10, family law x Wollongong NSW.
   TAKEN FROM THE ABOGADA KIT AND THEN MEASURED, which is the only reason it does not ship the
   kit's own values unchanged. Envato Elements, estate subscription (vault/sops/account-map.md §16).

   THE INK IS THE KIT'S, LITERALLY. --theme-color4 / --heading-color = rgba(20,31,42,1) = #141F2A,
   css/style.css:40,56. It reads as navy at a glance and is not one: its channel spread is
   20/31/42, a 22-point blue lift over red, where the SERP's actual navy — Kells' #1F2A44, the only
   competitor brand colour extractable from markup — runs 31/42/68, a 37-point lift. #141F2A is a
   near-neutral cool charcoal. It sits OUTSIDE the range four page-1 competitors occupy rather than
   inside it, which is the p14 test applied to a different SERP.

   THE DISTANCE IS BOUGHT ON THE ACCENT, per the p15 doctrine — it is the loudest element on the
   page. Bronze #CB935D is the kit's --theme-color1 and is unoccupied on this SERP: the nearest
   competitor value is Kells' gold #F0B434, a bright saturated yellow, and the other warm accents
   are peach (Hulse #EB916A) and orange (Nikolovski). Nobody here uses a muted metallic tan.

   ⚠ AND THE KIT'S BRONZE FAILS EVERY TEXT THRESHOLD, INCLUDING ITS OWN BUTTON. Measured with
   tools/build/contrast.mjs, 2026-09-05, on white and on the kit's own #F5F5F5 tint:
     #CB935D on white              2.67:1   FAIL body, FAIL large, FAIL 1.4.11 non-text
     #CB935D on #F5F5F5            2.45:1   FAIL everything
     white on #CB935D              2.67:1   FAIL — and this is what the kit ships on its CTA
                                            (.theme-btn, css/style.css:3270-3284: bronze ground,
                                            white uppercase 16px). The kit's primary button is an
                                            accessibility failure as delivered.
     #141F2A on #CB935D            6.25:1   PASS
   So the bronze stays, at its exact kit value, and the BUTTON TEXT FLIPS TO INK. That is the
   highest-ratio fix available and it keeps the kit's actual colour on the page's loudest element,
   rather than replacing the colour to rescue the text. It is the FIFTH kit primary in a row to
   look healthy and fail (162's 4.10, 163's 3.44, 165's 3.32, 167's 3.30, now 2.67 — the worst yet).

   TEXT-BEARING BRONZE IS A SEPARATE TOKEN. --accent-text #8A5A24 is the kit hue darkened until it
   clears body text on both grounds: 5.88:1 white, 5.40:1 tint. Links use it. --accent is never
   text, on any ground, at any size.

   THE KIT'S BODY GREY ALSO FAILS ON THE KIT'S OWN TINT. --paragraph #75727B (style.css:58) is
   4.72:1 on white — a pass with 0.22 to spare — and 4.33:1 on #F5F5F5, a fail. The kit pairs a
   body colour with an alternate section ground it cannot legally sit on. --ink-soft #63606B keeps
   the cool-violet cast and clears both: 6.15 / 5.64.

   --field-border #7A7681 is 4.43 white / 4.07 tint against WCAG 1.4.11's 3.0 — 1.07 of margin on
   the worse ground. #8C8892 was measured first and refused at 3.47/3.18: p14 and p15 both refused
   a boundary token holding 0.22 of margin, and 0.18 is not an improvement on that precedent.

   --sand #F0E4D6 is a warm bronze-tinted band for the price table, measured on all three text
   tokens it has to carry: ink 13.32, ink-soft 4.91, accent-text 4.70. */
body[data-palette="p17"] {
  --ink: #141F2A;            /* kit --theme-color4, literal — 16.68:1 white, 15.30:1 on tint */
  --ink-soft: #63606B;       /* kit --paragraph darkened — 6.15:1 white, 5.64:1 tint */
  --surface: #FFFFFF;        /* kit --main-bg */
  --surface-alt: #F5F5F5;    /* kit --bg-color5 */
  --sand: #F0E4D6;           /* warm band for the price table — ink 13.32, ink-soft 4.91 */
  --line: #E4E0DA;           /* hairline, decorative rules only, 1.4.11 does not apply */
  --field-border: #7A7681;   /* 4.43:1 white, 4.07:1 tint; WCAG 1.4.11 needs 3.0 */
  --accent: #CB935D;         /* kit --theme-color1, literal — GROUND ONLY, NEVER TEXT (2.67:1) */
  --accent-ink: #141F2A;     /* ink on bronze, 6.25:1 — the kit ships white here at 2.67:1 */
  --accent-text: #8A5A24;    /* darkened bronze for text — 5.88:1 white, 5.40:1 tint */
  --link: #8A5A24;           /* same value; a bronze link is the kit's own idiom, made legible */
}

/* t14 — Playfair Display display over Mulish body. Direction 169 / site 10.
   THE KIT'S OWN PAIRING, TAKEN LITERALLY. css/style.css:35-36 declares
   --font-title: "Playfair Display", serif and --font-body: "Mulish", sans-serif. Unlike Fertilys
   (t13), whose GT Walsheim Pro is a licence this repo does not hold, both of these are SIL OFL 1.1
   and can be self-hosted — so this is the first direction where the kit's type is used rather than
   approximated or replaced.

   TWO NEW FILES, AND THAT IS THE COST. Neither family was already self-hosted here, so t14 adds
   playfair-display-var-latin.woff2 (38KB) and mulish-var-latin.woff2 (30KB) — latin subset of each
   family's variable font, fetched directly from the Google Fonts CSS2 API so the served request
   stays same-origin. Same method as t7. t12 and t13 both added zero files by recombining existing
   ones; this one cannot, and 68KB is the price of the kit's actual voice.

   FIRST REAL SERIF DISPLAY FACE IN THE PORTFOLIO. t2 is Georgia — a system serif, no file. Every
   self-hosted pairing before this is grotesque over grotesque. On a SERP where the rank-2 firm runs
   a black-and-white grotesque and the rank-5 firm runs a stone-grey serif, a high-contrast
   Didone-adjacent serif is the axis that separates us from the grotesques without landing on
   Seacliff's stone.

   HEAD WEIGHT 700 IS OURS, NOT THE KIT'S. The kit sets h1 700 but h2 400 (style.css:151-167) — a
   48px serif at regular weight. That is a real editorial look and it is not one this engine's
   templates can carry, because the same rule renders service-card titles and FAQ questions where
   400 at 26px loses the hierarchy. 700 throughout, recorded as a departure rather than implied. */
body[data-type="t14"] {
  --font-head: "Playfair Display", ui-serif, Georgia, "Times New Roman", serif;
  --font-body: "Mulish", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p18 — direction 175 / site 15 houseunderpinningbrisbane.au. THE ACTO KIT'S OWN COLOURS, with the
   warm ones confined to the dark grounds they can be read on. Rulings: validation/
   underpinning-brisbane-direction-rulings-2026-09-21.md (ruling 1 and amendment 1a). Every pair
   below measured with tools/build/contrast.mjs on 2026-09-21; flat pairs only, and the rendered
   page is tested by render-check.mjs, not by these numbers.

   THE LEAD IS NAVY, NOT ORANGE. The kit's own primary #fd571d is 3.20:1 against white, so the
   kit's white-on-orange button cannot ship. --accent is therefore the navy, which carries white
   text at 13.06:1 and is readable as text on white (13.06) and on the tint (11.97). Everything the
   base paints with --accent (buttons, links, focus rings on a light ground) is legible by default.

   THE WARM COLOURS ARE NOT --accent, AND THAT IS DELIBERATE. --accent-bright (#fd571d) and
   --accent-warm (#fc9a36) exist only for direction 175's dark bands, where 175.css applies them:
     #fd571d on ink #0c0d24 ........ 5.97:1   (ONLY on ink: on navy it is 4.08, on white 3.20)
     #fc9a36 on navy #192d66 ....... 6.10:1   #fc9a36 on ink ........ 8.93:1   (NEVER on white: 2.14)
     ink on #fd571d ................ 5.97:1   ink on #fc9a36 ........ 8.93:1   (button text on either)
   #9dc638 and #e72636 are excluded outright and appear nowhere. No token below is white on orange. */
body[data-palette="p18"] {
  --ink: #0C0D24;            /* kit ink — 19.11:1 white, 17.52:1 on the tint; header and hero ground */
  --ink-soft: #5D5D66;       /* kit body colour — 6.52:1 white, 5.97:1 on the tint */
  --surface: #FFFFFF;
  --surface-alt: #F3F5FA;    /* cool paper tint */
  --line: #DBE0EC;           /* hairline, decorative rules only, 1.4.11 does not apply */
  --field-border: #767B93;   /* 4.18:1 white, 3.83:1 tint — WCAG 1.4.11 needs 3.0 */
  --accent: #192D66;         /* kit deep navy — 13.06:1 as text on white; carries white at 13.06:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 13.06:1 */
  --link: #192D66;           /* the lead colour as the link colour, 13.06:1 white, 11.97:1 tint */
  --deep: #192D66;           /* kit navy, named for the dark bands 175.css paints with it */
  --accent-bright: #FD571D;  /* kit primary — ON INK #0C0D24 ONLY, never navy, never white */
  --accent-warm: #FC9A36;    /* kit amber — ON NAVY OR INK ONLY, never white */
}

/* t15 — Playfair Display display over DM Sans body. Direction 175 / site 15.
   THE KIT SHIPS NO FONT. It declares 'Ubuntu' seven times and carries no @font-face, no file and no
   font request, so it renders in the browser's generic sans-serif; nothing is overridden here
   (operator ruling 2026-09-21). Both faces are SIL OFL 1.1, latin-subset variable fonts, already in
   templates/design/fonts/ — t15 adds no file. DM Sans is declared above for t7 and t9.

   ⚠ THE PLAYFAIR DISPLAY @font-face IS DECLARED IN directions/175.css, NOT HERE. No @font-face for
   Playfair Display exists in this file, though t14's block above says the face is self-hosted: the
   file is copied into a t14 build's public/fonts/ and nothing refers to it (checked in site 10's
   built HTML, 2026-09-21: seven @font-face rules, none for Playfair or Mulish). Adding one here
   would change site 10's rendering on its next build, which is not this change's to decide.
   HEAD WEIGHT 700 as t14, for the same reason. */
body[data-type="t15"] {
  --font-head: "Playfair Display", ui-serif, Georgia, "Times New Roman", serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p19 — direction 176 / site 16 houseunderpinningsydney.au. THE BUILDA KIT'S OWN NEUTRALS, with its
   orange confined to the dark grounds it can be read on (operator ruling (b), 2026-09-21: "neutral-led,
   orange accent-only on dark grounds — same shape as site 15's ruling"). Every pair measured with
   tools/build/contrast.mjs on 2026-09-21; flat pairs only — the rendered page is tested by
   render-check.mjs, not by these numbers. Record: validation/underpinning-sydney-kit-measurement-2026-09-21.md.

   THE LEAD IS INK, NOT ORANGE. The kit's own primary #FF6600 is 2.94:1 against white, so the kit's
   white-on-orange button cannot ship. --accent is the kit's own title ink #0C0A0A, which carries white
   text at 19.75:1 and is readable as text on white (19.75) and on the cream tint (18.35). Everything the
   base paints with --accent (buttons, links, focus rings on a light ground) is therefore legible by default.
   THE KIT'S SLATE #23343E IS NOT USED AS THE LEAD: it sits inside the Sydney SERP's navy family
   (ΔE ≈ 5 from the rank-2 competitor's #1d2e40) and 5.8 from the live Sydney concrete-cancer ink.

   THE ORANGE IS NOT --accent, AND THAT IS DELIBERATE. --accent-bright (#FF6600) exists only for
   direction 176's dark bands, where 176.css applies it:
     #FF6600 on ink #0C0A0A ........ 6.73:1   on #171717 ........ 6.11:1   (NEVER on white: 2.94)
     ink on #FF6600 ................ 6.73:1   (button text on orange; white on orange DOES NOT EXIST)
   THE KIT'S AMBER #F0A538 IS NOT DEFINED HERE AT ALL. It is ΔE 10.7 from site 15's amber and 18.7 from the
   live Sydney concrete-cancer amber; withholding it leaves orange as the only warm value (ruling permits
   amber, does not require it). #209E2E green, #E2B93B, #27AE60 and #EB5757 are excluded outright.
   Ink-soft #555555: 7.46 white, 6.93 cream. --field-border #6F675D: 5.56 white, 5.17 cream (a control
   boundary, needs 3.0 under WCAG 1.4.11; taken to 4.5 on the operator's ruling that every shipped pair
   meets it). The kit's own #968D81 (3.27) and #B3B3B3 (2.10) are refused. */
body[data-palette="p19"] {
  --ink: #0C0A0A;            /* kit title ink — 19.75:1 white, 18.35:1 on the cream; header and hero ground */
  --ink-soft: #555555;       /* kit body colour — 7.46:1 white, 6.93:1 cream */
  --surface: #FFFFFF;
  --surface-alt: #FFF5EB;    /* the kit's warm cream --smoke-color3 */
  --line: #ECE5DB;           /* hairline, decorative rules only, 1.4.11 does not apply */
  --field-border: #6F675D;   /* 5.56:1 white, 5.17:1 cream */
  --accent: #0C0A0A;         /* the lead colour is INK: white text on it 19.75:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 19.75:1 */
  --link: #0C0A0A;           /* 19.75:1 white, 18.35:1 cream. Underlined by the base rule, so colour is not the only cue */
  --deep: #171717;           /* kit --black-color2, the CTA band's ground: 17.93:1 white */
  --accent-bright: #FF6600;  /* kit primary — ON INK #0C0A0A OR #171717 ONLY (6.73 / 6.11), never white */
}

/* t16 — Outfit display over the portfolio system stack. Direction 176 / site 16.
   The Builda kit pairs Outfit (headings) with Inter (body). INTER IS NOT AVAILABLE: its @font-face was
   removed portfolio-wide on 2026-08-27 by operator directive and that directive stands, so t16 is ONE
   webfont over the system stack — the same shape as t10 and t11 and for the same reason. Outfit is the
   kit's own display face, taken literally. It is SIL OFL 1.1, the latin subset of the variable font
   (outfit-var-latin.woff2, 32,292 bytes, fetched 2026-09-21), and it is a NEW file. Its @font-face is
   declared in directions/176.css, not here, for the reason the t15 note above gives for Playfair: a
   declaration in this shared file names a font that a build for any other pairing does not copy.
   Distinct from every live pairing in the niche (t15) and the metro (t10, t12). */
body[data-type="t16"] {
  --font-head: "Outfit", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p20 — direction 174 / site 17 houseunderpinningmelbourne.au. A PLUM LEAD, ENGINE-AUTHORED. The Roadly kit's own
   palette (vermilion #E53925 with navy #0F1E36) is NOT used: the red is ΔE 4.6 from Buildfix's red (Melbourne SERP
   rank 1) and 14.6 from site 15's orange, and the navy is ΔE 7.9 from site 15's ink, so no recolouring of either left a
   clear palette. Operator ruling 2026-09-22: replace it wholesale by a plum lead, #6A2C70. This is a departure from
   the 21 Sep direction that kit palettes are measured, not chosen, and the ruling is its authority. Record:
   validation/underpinning-melbourne-kit-measurement-2026-09-22.md (§5, §7, §9). Every pair below is flat-pair
   arithmetic (tools/build/contrast.mjs is the shipped-pair audit); the rendered page belongs to render-check.mjs.

   PLUM IS THE LEAD ON LIGHT GROUNDS ONLY: headings, links, buttons. It is ΔE >= 27.4 from every live accent
   (nearest: site 15's navy #192D66) and 28.9 from the nearest Melbourne SERP colour (Buildfix's navy #2C2D53); no live
   hex has a hue between 270 and 330 degrees. White on plum 9.51:1; plum on white 9.51, on the tint 8.59.
   ⚠ PLUM ON A DARK GROUND IS 2.01:1 (on #0C0D24), SO IT IS NEVER TEXT, A RULE OR AN ICON THERE, AND IT IS NEVER A
   DARK SURFACE (operator ruling 2026-09-22: "plum is the accent lead only — never the dark background surface").
   On the dark bands the primary button is WHITE with ink text (19.11:1); headings and links are white or a light tint.

   THE DARK GROUND IS SITE 15's INK, #0C0D24, ON THE OPERATOR'S RULING — THE SAME HEX (ΔE 0, same niche). Reported as
   a residual, not resolved: the ledger compares labels, and a plum lead over a navy-black ground does not read as
   site 15's navy-led page, but the value itself is shared. White on it 19.11:1.
   The kit's near-black #1A1A1A is not used: ΔE 6.4 from site 16's ink #0C0A0A and 1.5 from its #171717.
   ⚠ THE LIGHT TINT IS A NEAR-WHITE AND IS ONLY ΔE 2.2 FROM SITE 15's #F3F5FA: at this lightness no palette
   separates on the tint, so the separation is carried by the lead (plum against navy), not by the paper.
   Body #616161 is the kit's own: 6.19:1 white, 5.59 on the tint. --field-border #736879: 5.27 white, 4.76 tint
   (taken to 4.5 as sites 15 and 16 were). --line is decorative (WCAG 1.4.11 does not apply). */
body[data-palette="p20"] {
  --ink: #0C0D24;            /* site 15's ink, on the operator's ruling — 19.11:1 white; the header and closing-band ground */
  --ink-soft: #616161;       /* kit body colour — 6.19:1 white, 5.59:1 on the tint */
  --surface: #FFFFFF;
  --surface-alt: #F6F2F7;    /* a faint plum-tinted paper — ENGINE-AUTHORED, near-white */
  --line: #E4DDE6;           /* hairline, decorative rules only */
  --field-border: #736879;   /* 5.27:1 white, 4.76:1 tint */
  --accent: #6A2C70;         /* the plum lead — white text on it 9.51:1; text on white 9.51, on the tint 8.59 */
  --accent-ink: #FFFFFF;     /* on --accent, 9.51:1 */
  --link: #6A2C70;           /* the lead as the link colour on light grounds; underlined by the base rule */
  --deep: #0C0D24;           /* the dark ground is the ink — plum is never a dark surface */
}

/* t17 — Space Grotesk display over DM Sans body. Direction 174 / site 17. Both are the Roadly kit's own faces,
   taken literally (the kit ships neither file and imports both from Google Fonts, which is not used). Both are SIL
   OFL 1.1, latin-subset VARIABLE fonts, self-hosted: space-grotesk-var-latin.woff2 is a NEW file (22,288 bytes,
   fetched 2026-09-22), dm-sans-var-latin.woff2 is already in templates/design/fonts/ for t7, t9, t13 and t15. DM Sans's
   @font-face is declared above for t7 and t9. Space Grotesk's @font-face is declared in directions/174.css, NOT here,
   for the reason the t15 note gives for Playfair: a declaration in this shared file names a font that a build for any
   other pairing does not copy. DM Sans as the body face is shared with site 15 (t15), which the operator ruled is not
   a collision axis (Rule 1 compares the whole four-tuple). Display weight 700 (Space Grotesk's variable range is 300-700).
   Distinct from every live pairing in the niche (t15, t16) and the metro (none live). */
body[data-type="t17"] {
  --font-head: "Space Grotesk", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p21 — direction 178 / site 18 underpinningwollongong.au. A MOSS-OLIVE LEAD, ENGINE-AUTHORED. The Buildnow kit's own lead
   (orange #F45B1E, white text on it 3.30:1) is NOT used: it is ΔE 3.7 from site 15's #EF5F1A (same niche) and 13.7 from Mainmark's
   #FB7B33 accent (Wollongong SERP rank 2), and site 16 already ships orange in the niche. The Wollongong page 1 reads blue
   (Geotech Built #3BB9FF, Mainmark #0072BC, Affordable #013474, Knobel #27419A), yellow (Billcorp #FFF100) and default black-and-white
   (Burrell), so a moss-olive lead is ΔE 56.5+ from every SERP colour and ΔE 19.0 or more from every live palette (the nearest is
   site 3's eucalypt green, 19.0). White on the lead 7.53:1; moss on the paper 7.02:1. THE LEAD IS FOR LIGHT GROUNDS ONLY: moss on the ink is 2.18:1. */
body[data-palette="p21"] {
  --ink: #1C2117;            /* green-black; white on it 16.42:1. The header and the closing band. ΔE 4.7 from site 12's #16241D (different niche and metro) */
  --ink-soft: #5C6672;       /* the kit's own --text-3 — 5.84:1 white, 5.43:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F1F3E4;    /* a faint olive-tinted paper — ENGINE-AUTHORED; the kit's #F8F7F0 is ΔE 3.6 from site 16's cream, so it is not used */
  --line: #DDE0CB;           /* hairline, decorative rules only */
  --field-border: #6F765F;   /* 4.74:1 white, ≥4.2:1 on the paper */
  --accent: #4A5A2A;         /* the moss lead — white text on it 7.53:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 7.53:1 */
  --link: #4A5A2A;           /* the lead as the link colour on light grounds; underlined by the base rule */
  --deep: #1C2117;           /* the dark ground is the ink — moss is never a dark surface */
}

/* t18 — Unbounded display over the portfolio system stack. Direction 178 / site 18. Unbounded is the Buildnow kit's own display face
   (main.css: h1-h6 `font-family: "Unbounded"`), taken literally; the kit imports it from Google Fonts, which is not used. SIL OFL 1.1,
   latin-subset VARIABLE font (wght 200-900 requested as 300-800), self-hosted: unbounded-var-latin.woff2 is a NEW file (50,904 bytes,
   fetched 2026-09-24). The kit's body face Barlow is static-only (nine weights) and is not taken; body is the system stack, as t16.
   @font-face lives in directions/178.css for the reason the t17 note gives. Unbounded is a WIDE face: heading sizes in 178.css are
   set below the kit's. Distinct from every live pairing in the niche (t15, t16, t17) and the metro (t14). */
body[data-type="t18"] {
  --font-head: "Unbounded", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --head-weight: 600; --head-tracking: 0; --head-transform: none;
}

/* p22 — direction 177 / site 19 underpinningnewcastle.au. A DEEP TEAL LEAD, ENGINE-AUTHORED, over a wine-black ink. The BuildGo kit's own lead
   (yellow #FFBF43; dark text on it 9.69:1, a rare pass) is NOT used: it is ΔE 3.8 from p11's #FFC631 (site 5) and the two top Newcastle page-1
   sites carry yellow or orange accents (Precision #fcd012, Newcastle House Levelling #ffa400, read by extraction, not seen). The Newcastle
   page 1 otherwise reads blue (Mainmark #0072BC, Resinject #3858E9 / #003388, Beveridge #003399, Billcorp #003388, Newcastle Foundation Repairs
   #5572B0), with red accents. The teal is ΔE 24.8 from the nearest of those and ΔE 5.4 from p15's #0E5C63 (site 7, Brisbane balcony
   waterproofing: a different niche and metro), which is the RESIDUAL; every other live lead is 16.4 or more away. THE INK #481026 was chosen as
   the dark ground furthest from every live ink and deep value in the palette file (ΔE 20.4 from the nearest, p18's #0C0D24; white on it 15.24:1) under
   two limits set by this file: white text at 15:1 or better, and a modest channel spread so it stays an ink. ⚠ ITS NEAREST LIVE LEAD IS p16's
   #8C2F39 at ΔE 16.7 (site 9, dentalimplantsnewcastle.au, the SAME metro): a wine-black beside site 9's burgundy, reported. White on the lead 7.91:1;
   teal on the paper 7.34:1. THE LEAD IS FOR LIGHT GROUNDS ONLY: teal on the ink is 1.93:1. */
body[data-palette="p22"] {
  --ink: #481026;            /* wine-black; white on it 15.24:1. The header and the closing band */
  --ink-soft: #57505C;       /* 7.76:1 white, 7.20:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F4F7F6;    /* a faint teal-tinted paper — ENGINE-AUTHORED (the kit's #F8F7F0 is ΔE 3.1 from it and is not used) */
  --line: #D6E0DE;           /* hairline, decorative rules only */
  --field-border: #5F7472;   /* 4.97:1 white, 4.61:1 on the paper */
  --accent: #0F5B57;         /* the teal lead — white text on it 7.91:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 7.91:1 */
  --link: #0F5B57;           /* the lead as the link colour on light grounds; underlined by the base rule */
  --deep: #481026;           /* the dark ground is the ink — teal is never a dark surface */
}

/* t19 — Instrument Sans display over DM Sans body. Direction 177 / site 19. Both are the BuildGo kit's own faces (its style.css sets
   --heading-font "Instrument Sans" and --body-font "DM Sans" and imports both from Google Fonts, which is not used). Both are SIL OFL 1.1,
   latin-subset VARIABLE fonts, self-hosted: instrument-sans-var-latin.woff2 is a NEW file (30,092 bytes, fetched 2026-09-25, wght 400-700
   requested), dm-sans-var-latin.woff2 is already in templates/design/fonts/ for t7, t9, t13, t15 and t17. Instrument Sans's @font-face is
   declared in directions/177.css, NOT here, for the reason the t17 note gives. DM Sans as the body face is shared with t15 and t17 (Rule 1
   compares the whole four-tuple). Display weight 600 (the kit sets 500; 600 reads at the sizes 177.css uses). Distinct from every live pairing
   in the niche (t15, t16, t17, t18) and the metro (t14). */
body[data-type="t19"] {
  --font-head: "Instrument Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 600; --head-tracking: -0.01em; --head-transform: none;
}

/* p23 — direction 179 / site 20 houseraisinggoldcoast.au. THE KIT'S OWN LEAD, ACID LIME #E1E31D, over an engine-authored aubergine-black ink. The Archik kit
   (winsfolio; certificate E2ZBVS6JUF) sets black text on #E1E31D (15.21:1); with the ink below it is 11.38:1. THE LEAD IS KEPT because, unlike the kits before it,
   it is CLEAR OF THE PORTFOLIO: ΔE 15.6 from the nearest live lead (p11's #FFC631, site 5) and 30 or more from every other. RESIDUAL, reported: ΔE 8.1 from
   #bcce41, the lime accent of one Gold Coast page-1 operator, read by EXTRACTION, not seen. THE INK #381048 is the dark ground furthest from every live ink and deep
   value (ΔE 14.5 from the nearest, p22's #481026; p18's deep #192D66 is 14.6), searched over 22,931 candidates at white text 15:1 or better; the kit's own neutral
   #222222 is ΔE 0.3 from a live ink and is NOT used. ⚠ ITS NEAREST LIVE LEAD is p20's plum #6A2C70 at ΔE 11.7 (site 17, Melbourne underpinning; another niche and metro).
   LIME IS NEVER TEXT, A LINK, A RULE OR A FOCUS RING ON A LIGHT GROUND: it is 1.38:1 on white. On light grounds the mark is the INK; lime is a button ground (ink text,
   11.38:1) and a mark on the dark bands (11.38:1 on ink). Paper #F7F7ED is ENGINE-AUTHORED (the kit's white and #f5f5f5 are not used). */
body[data-palette="p23"] {
  --ink: #381048;            /* aubergine-black; white on it 15.72:1. The header and the closing band */
  --ink-soft: #5A4A66;       /* 8.06:1 white, 7.42:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F7F7ED;    /* a faint lime-tinted paper — ENGINE-AUTHORED; ink on it 14.48:1 */
  --line: #DDDDCC;           /* hairline, decorative rules only */
  --field-border: #6E6478;   /* 5.59:1 white, 5.15:1 on the paper */
  --accent: #E1E31D;         /* the kit's lime: a button ground and a dark-band mark. NEVER text on light */
  --accent-ink: #381048;     /* on --accent, 11.38:1 */
  --link: #381048;           /* links on light grounds are the ink, underlined by the base rule */
  --deep: #381048;           /* the dark ground is the ink */
}

/* t20 — Epilogue for display and body. Direction 179 / site 20. Epilogue is the Archik kit's own and only face (main.css imports it from Google Fonts, which is
   not used). SIL OFL 1.1, latin-subset VARIABLE font (wght 400-800), self-hosted: epilogue-var-latin.woff2 is a NEW file (35,700 bytes, fetched 2026-09-25).
   Its @font-face is declared in directions/179.css, NOT here, for the reason the t17 note gives. Distinct from every live pairing in the niche (t7, t8) and the
   metro (t11). */
body[data-type="t20"] {
  --font-head: "Epilogue", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Epilogue", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}

/* p24 — direction 180 / site 21 newcastleasbestosremoval.au. A DEEP UMBER LEAD, ENGINE-AUTHORED, over a chestnut-black ink. The Consto kit's own lead (yellow
   #FEED01 on #0B0B0B; black on it is 16.24:1, a pass) is NOT used: yellow is the construction-trade default, it is ΔE 5.4 from p23's lime (site 20) and 13.4 from p11's
   #FFC631 (site 5), and the Newcastle page-1 sites already read yellow or orange on the top two (#fcd012, #ffa400, read by extraction for site 19, not seen). A
   hazard-yellow on an asbestos page would also read as warning tape on a marketing site that removes nothing. ΔE throughout is CIEDE2000, the method sites 19 and 20
   used (a CIE76 sweep found the candidates; every figure here was re-measured in CIEDE2000). The umber is ΔE 15.4 from the nearest live lead (p4's rust #A8442C,
   site 4, Central Coast demolition: another metro and niche), 17.7 from p16's burgundy #8C2F39 (site 9, dentalimplantsnewcastle.au: the SAME metro, another niche)
   and 17.8 from p2's #B5502F; ⚠ THE RESIDUAL IS THE WARM-BROWN FAMILY (p2, p4, p16 read reddish where this reads chestnut). THE INK #461600 is the dark ground
   furthest from every live ink under white text 15:1 or better and a chroma under 32 (searched 0-88 per channel in steps of 2 by CIE76): ΔE 14.9 from p15's #2B2118
   (site 11), 16.3 from p22's #481026 (site 19, the SAME metro); white on it 15.27:1. ⚠ IT IS ITS OWN LEAD'S DARK SISTER, so the two are one hue family by intent:
   the lead is for light grounds only (umber on the ink is 1.71:1). White on the lead 8.95:1; lead on white 8.95:1, on the paper 8.09:1. Paper #F6F3EF is
   ENGINE-AUTHORED (the kit's #F2F3F5 and #F9F9F9 are cool greys and are not used). */
body[data-palette="p24"] {
  --ink: #461600;            /* chestnut-black; white on it 15.27:1. The header and the closing band */
  --ink-soft: #5C4E45;       /* 7.98:1 white, 7.22:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F6F3EF;    /* a faint warm paper — ENGINE-AUTHORED; ink on it 13.81:1 */
  --line: #E0D8D0;           /* hairline, decorative rules only */
  --field-border: #7A6A5E;   /* 5.18:1 white, 4.69:1 on the paper */
  --accent: #684024;         /* the umber lead — white text on it 8.95:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 8.95:1 */
  --link: #684024;           /* the lead as the link colour on light grounds (8.95:1 white, 8.09:1 paper); underlined by the base rule */
  --deep: #461600;           /* the dark ground is the ink — umber is never a dark surface */
}

/* t21 — Nunito Sans for display and body. Direction 180 / site 21. Nunito Sans stands in for the Consto kit's Museo Sans (MuseoSans-300/700/900 ship inside the kit
   as .woff2/.ttf, but Museo Sans is a commercial family and the Envato item licence was not read as covering its redistribution as a web font, so NO kit font file is
   used). Nunito Sans is the nearest open humanist: rounded terminals, a heavy 800. SIL OFL 1.1, latin-subset VARIABLE font (wght 400-800), self-hosted:
   nunito-sans-var-latin.woff2 is a NEW file (31,076 bytes, fetched 2026-09-29). Its @font-face is declared in directions/180.css, NOT here, for the reason the t17 note
   gives. Distinct from every live pairing in the niche (none yet) and the metro (t13 Archivo + DM Sans, t19 Instrument Sans + DM Sans). */
body[data-type="t21"] {
  --font-head: "Nunito Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Nunito Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 800; --head-tracking: -0.01em; --head-transform: none;
}

/* p25 — direction 181 / site 22 asbestosremovalcentralcoastnsw.au. A DEEP INDIGO LEAD, ENGINE-AUTHORED, over a violet-black ink. The Sanera kit's own colours (cyan #44D6FE,
   lime #9BCB3B) are NOT used: they are the cleaning-trade look and cyan is the kit's default. A CIE76-then-CIEDE2000 sweep of sRGB for a lead with white text at 7.5:1 or
   better and chroma 28 or more, furthest from every live lead (p1-p24 accents), found the indigo family; #4B3FA6 is a restrained member of it (white on it 8.20:1),
   ΔE 12.6 from the nearest live lead (p18's navy #192D66, site 15, Brisbane; the nearest Central Coast lead is p3's blue #1F5FBF, site 2). THE INK #2A2140 is ΔE 8.8 from the
   nearest live ink (p18's #0C0D24): ⚠ INKS ARE DARK AND CLOSE BY NATURE; the lead is the distinct axis. White on ink 15.11:1. The lead is for light grounds only (indigo on the
   ink is 1.84:1). Paper #F5F4FA is ENGINE-AUTHORED (ink on it 13.82:1, lead on it 7.50:1). */
body[data-palette="p25"] {
  --ink: #2A2140;            /* violet-black; white on it 15.11:1. The header and the closing band */
  --ink-soft: #4F4866;       /* 8.57:1 white, 7.83:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F5F4FA;    /* a faint cool paper — ENGINE-AUTHORED; ink on it 13.82:1 */
  --line: #DDDAE8;           /* hairline, decorative rules only */
  --field-border: #746C8C;   /* 4.92:1 white, 4.50:1 on the paper */
  --accent: #4B3FA6;         /* the indigo lead — white text on it 8.20:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 8.20:1 */
  --link: #4B3FA6;           /* the lead as the link colour on light grounds (8.20:1 white, 7.50:1 paper); underlined by the base rule */
  --deep: #2A2140;           /* the dark ground is the ink — indigo is never a dark surface */
}

/* t22 — Rubik for display and body. Direction 181 / site 22. Rubik is the Sanera kit's own heading face (--global--font-heading, loaded there from Google Fonts); no kit
   font FILE is used. SIL OFL 1.1, latin-subset VARIABLE font (wght 400-800), self-hosted: rubik-var-latin.woff2 is a NEW file (35,348 bytes, fetched 2026-09-29). Its
   @font-face is declared in directions/181.css, NOT here, for the reason the t17 note gives. Distinct from every live pairing (none uses a rounded-geometric grotesque). */
body[data-type="t22"] {
  --font-head: "Rubik", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Rubik", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p26 — direction 182 / site 23 sydneyasbestosremoval.au. A RASPBERRY LEAD, ENGINE-AUTHORED, over a plum-black ink. The Wastex kit's own colours (lime #93BD33, green #0D4F2B,
   maroon #4F0709) are NOT used: they are a waste-and-recycling look, and the kit's green sits beside p14's green (site 12, balcony waterproofing Sydney) in the same metro. A sweep
   of sRGB for a lead with white text at 7.5:1 or better and chroma 28 or more, furthest from every live lead (p1-p25 accents, CIEDE2000), found only near-blacks once the
   indigo (p25) was taken; a restrained raspberry was chosen by hand and measured. #9A2262: white on it 7.56:1, ΔE 12.7 from the nearest live lead (p20's plum #6A2C70, site 17,
   Melbourne; about 12 from p16's burgundy #8C2F39, site 13, Newcastle). THE INK #2A1024 is ΔE 9.2 from the nearest live ink (p22's #481026): ⚠ INKS ARE DARK AND CLOSE BY NATURE; the
   lead is the distinct axis. White on ink 17.53:1. The lead is for light grounds only (raspberry on the ink is 2.32:1). Paper #FBF6F8 is ENGINE-AUTHORED (ink on it 16.39:1, lead on it 7.07:1). */
body[data-palette="p26"] {
  --ink: #2A1024;            /* plum-black; white on it 17.53:1. The header and the closing band */
  --ink-soft: #5A4552;       /* 8.72:1 white, 8.16:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #FBF6F8;    /* a faint warm paper — ENGINE-AUTHORED; ink on it 16.39:1 */
  --line: #E6D9E0;           /* hairline, decorative rules only */
  --field-border: #8A7482;   /* 4.28:1 white, 4.01:1 on the paper (over the 3:1 non-text floor) */
  --accent: #9A2262;         /* the raspberry lead — white text on it 7.56:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 7.56:1 */
  --link: #9A2262;           /* the lead as the link colour on light grounds (7.56:1 white, 7.07:1 paper); underlined by the base rule */
  --deep: #2A1024;           /* the dark ground is the ink — raspberry is never a dark surface */
}

/* t23 — Inter for display and body. Direction 182 / site 23. Inter is the Wastex kit's own body and heading face (--body-font-family and --heading-font-family, loaded there from
   Google Fonts); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE font, already self-hosted here as inter-var-latin.woff2 (48,256 bytes, since 26 Aug) though no
   pairing used it until now. Its @font-face is declared in directions/182.css, NOT here, for the reason the t17 note gives. */
body[data-type="t23"] {
  --font-head: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.015em; --head-transform: none;
}

/* p27 — direction 183 / site 24 asbestosremovalwollongong.au. A DARK BRONZE LEAD, HAND-PICKED, over a warm near-black ink. The Cleanify kit's own colours (green #42990E, orange #FD8001, yellow #F2D701)
   are NOT used: a cleaning-services look, and orange and yellow are the trade's default hazard colours. A sweep of sRGB (white text at 7.5:1 or better, chroma 28 or more, furthest from the 25
   live leads p1-p26 bar the two dark-band inks, CIEDE2000) returned only near-blacks again (best #3C3000, ΔE 15.3, white 13:1), so #5A4800 (chroma 40, white 8.89:1) was HAND-PICKED and
   measured: ΔE 13.9 from the nearest live lead (p5's ironbark ochre #8A6B1F, site 5, Central Coast). It is not the raspberry (p26, site 23), umber (p24, site 21) or indigo (p25, site 22) of the
   other asbestos sites. THE INK #1F1806 was not measured against the live inks: INKS ARE DARK AND CLOSE BY NATURE; the lead is the distinct axis. The lead is for light grounds only (bronze on the
   ink is 1.98:1). Paper #FAF8F1 is ENGINE-AUTHORED (ink on it 16.59:1, lead on it 8.37:1). */
body[data-palette="p27"] {
  --ink: #1F1806;            /* warm near-black; white on it 17.62:1. The header and the closing band */
  --ink-soft: #4A4432;       /* 9.70:1 white, 9.13:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #FAF8F1;    /* a faint warm paper — ENGINE-AUTHORED; ink on it 16.59:1 */
  --line: #E4DFC9;           /* hairline, decorative rules only */
  --field-border: #857C5F;   /* 4.16:1 white, 3.92:1 on the paper (over the 3:1 non-text floor) */
  --accent: #5A4800;         /* the dark bronze lead — white text on it 8.89:1 */
  --accent-ink: #FFFFFF;     /* on --accent, 8.89:1 */
  --link: #5A4800;           /* the lead as the link colour on light grounds (8.89:1 white, 8.37:1 paper); underlined by the base rule */
  --deep: #1F1806;           /* the dark ground is the ink — bronze is never a dark surface */
}

/* t24 — Manrope for display and body. Direction 183 / site 24. Manrope is the Cleanify kit's own body and heading face (--body-font-family and --heading-font-family, loaded there from Google
   Fonts); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE font (wght 400-800), self-hosted here as manrope-var-latin.woff2 (24,836 bytes, fetched 2026-09-29 from fonts.gstatic.com).
   Its @font-face is declared in directions/183.css, NOT here, for the reason the t17 note gives. */
body[data-type="t24"] {
  --font-head: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.015em; --head-transform: none;
}

/* p28 — direction 184 / site 25 asbestosremovalcanberraact.au. A DEEP SPRUCE GREEN LEAD, HAND-PICKED from the licensed Labout kit's own theme hue (#37AA67, white text on it 3.0:1, so not used as sold),
   over a petrol-black ink. A sweep of sRGB (white text at 6.5:1 or better, HSL grid, furthest from the 27 live leads p1-p27, CIEDE2000) put near-blacks and maroons furthest away and the deep greens
   and petrols next; #1C4A2E (chroma 45, white 10.15:1) is the kit's own hue and measured ΔE 11.9 from the nearest live lead. It is not the raspberry (p26, site 23), umber (p24, site 21), indigo
   (p25, site 22) or bronze (p27, site 24) of the other asbestos sites. THE INK #0E1C22 and the paper #F1F6F3 are ENGINE-AUTHORED; INKS ARE DARK AND CLOSE BY NATURE, the lead is the distinct axis.
   The lead is for light grounds only. */
body[data-palette="p28"] {
  --ink: #0E1C22;            /* petrol-black; white on it about 17.4:1. The header and the closing band */
  --ink-soft: #3B4F55;       /* body-soft text; about 8:1 on white */
  --surface: #FFFFFF;
  --surface-alt: #F1F6F3;    /* a faint green-grey paper — ENGINE-AUTHORED */
  --line: #D3DFD8;           /* hairline, decorative rules only */
  --field-border: #6A8275;   /* over the 3:1 non-text floor on white and on the paper */
  --accent: #1C4A2E;         /* the deep spruce lead — white text on it 10.15:1 */
  --accent-ink: #FFFFFF;
  --link: #1C4A2E;           /* the lead as the link colour on light grounds; underlined by the base rule */
  --deep: #0E1C22;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t25 — Afacad for display, Inter for body. Direction 184 / site 25. Both are the Labout kit's own faces (--title-font, --text-font, loaded there from Google Fonts); no kit font FILE is used.
   SIL OFL 1.1, latin-subset VARIABLE fonts self-hosted here (afacad-var-latin.woff2 20,748 bytes wght 400-700, fetched 2026-09-29 from fonts.gstatic.com; inter-var-latin.woff2 already shipped for t23).
   Its @font-face is declared in directions/184.css, NOT here, for the reason the t17 note gives. */
body[data-type="t25"] {
  --font-head: "Afacad", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Inter", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p29 — direction 185 / site 26 concretecancerrepairgoldcoast.au. A BURNT SIENNA LEAD, HAND-PICKED from the licensed Kotar kit's own theme hue (#F68A0A, white text on it 2.45:1, so not used as sold),
   over a warm near-black ink. A sweep of sRGB (white text at 6.5:1 or better, HSL grid, furthest from the 28 live leads p1-p28, CIEDE2000) put near-blacks, maroons and violets furthest away; in the kit's own
   orange family the furthest is #8E4D0B (white 6.53:1), measured ΔE 11.1 from the nearest live lead (p24's umber, site 21, Newcastle: another city). It is the portfolio's only burnt sienna. THE INK #1A1612
   and the paper #F8F4EF are ENGINE-AUTHORED; INKS ARE DARK AND CLOSE BY NATURE, the lead is the distinct axis. The lead is for light grounds only. */
body[data-palette="p29"] {
  --ink: #1A1612;            /* warm near-black; white on it about 17.99:1. The header and the closing band */
  --ink-soft: #4D4339;       /* body-soft text; about 9.64:1 on white */
  --surface: #FFFFFF;
  --surface-alt: #F8F4EF;    /* a faint warm paper — ENGINE-AUTHORED */
  --line: #E3DACF;           /* hairline, decorative rules only */
  --field-border: #8A7A68;   /* over the 3:1 non-text floor on white (4.15) and on the paper (3.79) */
  --accent: #8E4D0B;         /* the burnt sienna lead — white text on it 6.53:1 */
  --accent-ink: #FFFFFF;
  --link: #8E4D0B;           /* the lead as the link colour on light grounds (5.96:1 on the paper); underlined by the base rule */
  --deep: #1A1612;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t26 — Titillium Web for display, Archivo for body. Direction 185 / site 26. Both are the Kotar kit's own faces (--title-font, --body-font, loaded there from Google Fonts); no kit font FILE is used.
   SIL OFL 1.1. Titillium Web is STATIC (weights 600 and 700, latin subset, fetched 2026-10-01 from fonts.gstatic.com v19); Archivo is already self-hosted for t10 (its @font-face is above).
   The Titillium Web @font-face is declared in directions/185.css, NOT here, for the reason the t17 note gives. */
body[data-type="t26"] {
  --font-head: "Titillium Web", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: 0; --head-transform: none;
}

/* p30 — direction 186 / site 27 concretecancerrepairbrisbane.au. AN OXBLOOD LEAD, HAND-PICKED from the licensed Construz kit’s own theme hue (#EA5501, white text on it 3.62:1, so not used as sold),
   over the kit’s own near-black title colour. A sweep of sRGB (white text at 6.5:1 or better, HSL grid, furthest from the 29 live leads p1-p29, CIEDE2000) put near-blacks, maroons and violets furthest away; in the kit’s
   own orange-red family #6B1E0E (white 11.56:1) measured ΔE 11.7 from the nearest live lead (p24’s umber, site 21, Newcastle: another city). THE INK #15161C is the kit’s --title-color; the paper #FAF5F2 is ENGINE-AUTHORED.
   INKS ARE DARK AND CLOSE BY NATURE, the lead is the distinct axis. The lead is for light grounds only. */
body[data-palette="p30"] {
  --ink: #15161C;            /* the kit’s title colour, a cool near-black; white on it about 18.05:1. The header and the closing band */
  --ink-soft: #484A55;       /* body-soft text; about 8.80:1 on white */
  --surface: #FFFFFF;
  --surface-alt: #FAF5F2;    /* a faint warm paper — ENGINE-AUTHORED */
  --line: #E6DCD6;           /* hairline, decorative rules only */
  --field-border: #85746E;   /* over the 3:1 non-text floor on white (4.45) and on the paper (4.11) */
  --accent: #6B1E0E;         /* the oxblood lead — white text on it 11.56:1 */
  --accent-ink: #FFFFFF;
  --link: #6B1E0E;           /* the lead as the link colour on light grounds (10.68:1 on the paper); underlined by the base rule */
  --deep: #15161C;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* p31 — direction 187 / site 28 concretecancerrepairmelbourne.au. A DEEP PETROL LEAD, HAND-PICKED by rotating the licensed Binter kit’s own navy (#00245A, the colour its headings use) toward teal, because the navy itself is ΔE 3.3 from
   p18 (site 15) and the kit’s orange #F26522 fails white text (3.15:1). A sweep of sRGB (white text at 6.5:1 or better, HSL grid, furthest from the 30 live leads p1-p30, CIEDE2000) put near-blacks, plums and violets furthest away;
   #193643 (white 12.73:1) measured ΔE 12.9 from the nearest live lead and is clear of the Melbourne sibling (p20, a purple). THE INK #101A22 and the paper #F3F6F8 are ENGINE-AUTHORED; INKS ARE DARK AND CLOSE BY NATURE,
   the lead is the distinct axis (it is ΔE 9.9 from the ink, both dark: its job is the link and button colour on light grounds). The lead is for light grounds only. */
body[data-palette="p31"] {
  --ink: #101A22;            /* a blue-black; white on it about 17.60:1. The header and the closing band */
  --ink-soft: #3D4C57;       /* body-soft text; about 8.86:1 on white */
  --surface: #FFFFFF;
  --surface-alt: #F3F6F8;    /* a faint cool paper — ENGINE-AUTHORED */
  --line: #D9E2E7;           /* hairline, decorative rules only */
  --field-border: #6A8592;   /* over the 3:1 non-text floor on white (3.90) and on the paper (3.59) */
  --accent: #193643;         /* the petrol lead — white text on it 12.73:1 */
  --accent-ink: #FFFFFF;
  --link: #193643;           /* the lead as the link colour on light grounds (11.73:1 on the paper); underlined by the base rule */
  --deep: #101A22;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t27 — Roboto for display and body. Direction 187 / site 28. Roboto is the Binter kit’s own and only face (body font-family, headings weight 700); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE font
   self-hosted here (roboto-var-latin.woff2 43,136 bytes wght 400-900, fetched 2026-10-01 from fonts.gstatic.com). Its @font-face is declared in directions/187.css, NOT here, for the reason the t17 note gives. */
body[data-type="t27"] {
  --font-head: "Roboto", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Roboto", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p32 — direction 188 / site 36 poolremovaladelaide.au. A DEEP LAGOON-BLUE LEAD, HAND-PICKED. The licensed Antek kit's own colours are a yellow (#EDB509, white text on it fails) and a charcoal (#222222), neither used.
   The nearest live leads by CIEDE2000 are p13 (ΔE 9.7), p15 (9.9) and p8 (10.0): a blue-teal beside those is the residual, below the 10-13 range of recent picks, said so. White on the lead 7.06:1. THE INK #0F1E26 and the paper #F2F6F7
   are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p32"] {
  --ink: #0F1E26;            /* a blue-black; white on it 17.02:1. The header and the closing band */
  --ink-soft: #43555F;       /* body-soft text; 7.77:1 on white, 7.14:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F2F6F7;    /* a faint cool paper — ENGINE-AUTHORED */
  --line: #D7E2E5;           /* hairline, decorative rules only */
  --field-border: #6A8794;   /* over the 3:1 non-text floor on white (3.81) and on the paper (3.51) */
  --accent: #1F5F7A;         /* the lagoon lead — white text on it 7.06:1 */
  --accent-ink: #FFFFFF;
  --link: #1F5F7A;           /* the lead as the link colour on light grounds (6.49:1 on the paper); underlined by the base rule */
  --deep: #0F1E26;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t28 — Barlow for display and body. Direction 188 / site 36. Barlow is the Antek kit's own and only face (font-family: Barlow); no kit font FILE is used. SIL OFL 1.1, latin-subset STATIC weights 400, 600 and 700
   (Barlow has static files on Google Fonts; the 7cH... files fetched 2026-10-02 from fonts.gstatic.com, 22,196 + 22,772 + 22,788 bytes) self-hosted here. Their @font-face is declared in directions/188.css, NOT here, for the reason the t17 note gives. */
body[data-type="t28"] {
  --font-head: "Barlow", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Barlow", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p33 — direction 189 / site 31 gosfordretainingwalls.au. A DUSKY VIOLET-GREY LEAD, HAND-PICKED. The licensed B Construction kit's own colours are a bright blue (#1196CC) over a navy (#202c45) in its default skin set, and a yellow in its meta badge; none used.
   The nearest live leads by CIEDE2000 are p20 (ΔE 12.2), p25 (15.9) and p18 (16.2): inside the 10 to 13 range of recent picks. White on the lead 7.91:1. THE INK #1B1626 and the paper #F5F3F8
   are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p33"] {
  --ink: #1B1626;            /* a violet-black; white on it 17.66:1. The header and the closing band */
  --ink-soft: #4C4658;       /* body-soft text; 9.04:1 on white, 8.20:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F5F3F8;    /* a faint cool paper — ENGINE-AUTHORED */
  --line: #DDD8E6;           /* hairline, decorative rules only */
  --field-border: #7E7490;   /* over the 3:1 non-text floor on white (4.39) and on the paper (3.98) */
  --accent: #5A4B6B;         /* the dusky violet lead — white text on it 7.91:1 */
  --accent-ink: #FFFFFF;
  --link: #5A4B6B;           /* the lead as the link colour on light grounds (7.18:1 on the paper); underlined by the base rule */
  --deep: #1B1626;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t29 — Montserrat for display, Open Sans for body. Direction 189 / site 31. Both are the B Construction kit's own faces (its style-main.css @imports Open Sans and Montserrat from Google Fonts; the kit's body is Open Sans, its headings Montserrat); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE fonts (Montserrat wght 400-800, Open Sans wght 400-700) self-hosted here. Their @font-face is declared in directions/189.css, NOT here, for the reason the t17 note gives. */
body[data-type="t29"] {
  --font-head: "Montserrat", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Open Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p34 — direction 190 / site 29 balconywaterproofingmelbourne.au. A MULBERRY LEAD, HAND-PICKED. The licensed Tilepro kit's own colours are an orange (#F94A29) over a charcoal (#202020), with a deep green (#0E2207) in places; none used.
   The nearest live leads by CIEDE2000 are p26 (ΔE 11.4), p33 (11.6) and p16 (12.5): inside the 10 to 13 range of recent picks. White on the lead 7.45:1. THE INK #1F1419 and the paper #F8F4F6
   are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p34"] {
  --ink: #1F1419;            /* a mulberry-black; white on it 17.91:1. The header and the closing band */
  --ink-soft: #54474D;       /* body-soft text; 8.80:1 on white, 8.08:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F8F4F6;    /* a faint warm paper — ENGINE-AUTHORED */
  --line: #E3D9DE;           /* hairline, decorative rules only */
  --field-border: #85737B;   /* over the 3:1 non-text floor on white (4.43) and on the paper (4.07) */
  --accent: #76475A;         /* the mulberry lead — white text on it 7.45:1 */
  --accent-ink: #FFFFFF;
  --link: #76475A;           /* the lead as the link colour on light grounds (6.83:1 on the paper); underlined by the base rule */
  --deep: #1F1419;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t30 — Oswald for display, Raleway for body. Direction 190 / site 29. Both are the Tilepro kit's own faces (its style.css @imports Oswald and Raleway from Google Fonts; --title-font Oswald, --text-font Raleway); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE fonts (Oswald wght 400-700, Raleway wght 400-700, as served) self-hosted here. Their @font-face is declared in directions/190.css, NOT here, for the reason the t17 note gives. */
body[data-type="t30"] {
  --font-head: "Oswald", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Raleway", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 600; --head-tracking: 0.005em; --head-transform: none;
}

/* p35 — direction 191 / site 34 bathroomrenovationsnewcastle.au. AN UMBER LEAD, HAND-PICKED. The licensed Renovate kit's own colours are a yellow (#F4BC16) over a charcoal (#25282A); white text on the yellow fails, neither used.
   The nearest live leads by CIEDE2000 are p24 (ΔE 11.1) and p27 (11.2): inside the 10 to 13 range of recent picks. White on the lead 8.08:1. THE INK #221C13 and the paper #F6F3EE are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p35"] {
  --ink: #221C13;            /* an umber-black; white on it 16.89:1. The header and the closing band */
  --ink-soft: #554B3F;       /* body-soft text; 8.52:1 on white, 7.70:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F6F3EE;    /* a faint warm paper — ENGINE-AUTHORED */
  --line: #E2DCD0;           /* hairline, decorative rules only */
  --field-border: #7A6E5D;   /* over the 3:1 non-text floor on white (4.98) and on the paper (4.50) */
  --accent: #5C4E37;         /* the umber lead — white text on it 8.08:1 */
  --accent-ink: #FFFFFF;
  --link: #5C4E37;           /* the lead as the link colour on light grounds (7.30:1 on the paper); underlined by the base rule */
  --deep: #221C13;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t31 — Raleway alone, for display and body. Direction 191 / site 34. Raleway is the Renovate kit's only face (every page links Raleway 100-900 from Google Fonts); no kit font FILE is used. SIL OFL 1.1, the latin-subset VARIABLE font (wght 400-700 as served), self-hosted for t30 and reused. Its @font-face is declared in directions/191.css, NOT here, for the reason the t17 note gives. */
body[data-type="t31"] {
  --font-head: "Raleway", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Raleway", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p36 — direction 192 / site 37 centralcoastsubfloorventilation.au. A SLATE LEAD, HAND-PICKED. The licensed Airslv kit's own colours are a coral red (#F5545A) and a blue (#005CFF/#1E6DFB) over a near-black (#13121D); white text on the red fails, neither used.
   The nearest live leads by CIEDE2000 are p31 (ΔE 9.7) and p32 (9.9): a little under the 10 to 13 range of recent picks, the crowded space leaving little room. White on the lead 8.36:1. THE INK #161C20 and the paper #F2F5F6 are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p36"] {
  --ink: #161C20;            /* a slate-black; white on it 17.20:1. The header and the closing band */
  --ink-soft: #424D55;       /* body-soft text; 8.66:1 on white, 7.91:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F2F5F6;    /* a faint cool paper — ENGINE-AUTHORED */
  --line: #DCE2E5;           /* hairline, decorative rules only */
  --field-border: #67737C;   /* over the 3:1 non-text floor on white (4.86) and on the paper (4.44) */
  --accent: #40505A;         /* the slate lead — white text on it 8.36:1 */
  --accent-ink: #FFFFFF;
  --link: #40505A;           /* the lead as the link colour on light grounds (7.63:1 on the paper); underlined by the base rule */
  --deep: #161C20;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t32 — Manrope for headings over Kumbh Sans for body. Direction 192 / site 37. These are the Airslv kit's own two faces (--airslv-font Manrope, --airslv-font-two Kumbh Sans, loaded by the kit from Google Fonts); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE fonts, self-hosted (manrope-var-latin.woff2 already shipped for t24; kumbh-sans-var-latin.woff2 new). Their @font-face is declared in directions/192.css, NOT here, for the reason the t17 note gives. */
body[data-type="t32"] {
  --font-head: "Manrope", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Kumbh Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p37 — direction 193 / site 38 gosfordroofrestoration.au. AN OXBLOOD BROWN LEAD, HAND-PICKED. The licensed Roofie kit's own colours are a red (#FF4138, white on it 3.3:1) and an orange (#FC9D21, white on it 2.0:1) over browns (#18120B, #050504); neither red nor orange is used.
   The nearest live leads by CIEDE2000 are p24 (ΔE 10.6) and p16 (10.7): inside the 10 to 13 range of recent picks. White on the lead 9.59:1. THE INK #1E1514 and the paper #F7F3F1 are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p37"] {
  --ink: #1E1514;            /* a warm black; white on it 17.91:1. The header and the closing band */
  --ink-soft: #5A4A47;       /* body-soft text; 8.38:1 on white, 7.60:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F7F3F1;    /* a faint warm paper — ENGINE-AUTHORED */
  --line: #E4DBD8;           /* hairline, decorative rules only */
  --field-border: #857370;   /* over the 3:1 non-text floor on white (4.48) and on the paper (4.07) */
  --accent: #633A36;         /* the oxblood lead — white text on it 9.59:1 */
  --accent-ink: #FFFFFF;
  --link: #633A36;           /* the lead as the link colour on light grounds (8.70:1 on the paper); underlined by the base rule */
  --deep: #1E1514;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t33 — Catamaran for headings over DM Sans for body. Direction 193 / site 38. These are the Roofie kit's own two main faces (--roofie-catamaran-font, --roofie-dmsans-font, loaded by the kit from Google Fonts); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE fonts, self-hosted (dm-sans-var-latin.woff2 already shipped for t7, t9, t13 and t15; catamaran-var-latin.woff2 new). Catamaran's @font-face is declared in directions/193.css, NOT here, for the reason the t17 note gives; DM Sans's is declared once above. */
body[data-type="t33"] {
  --font-head: "Catamaran", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.005em; --head-transform: none;
}

/* p38 — direction 194 / site 30 newcastleretainingwalls.au. A STONE KHAKI LEAD, HAND-PICKED. The licensed Bricks kit's own colour is a yellow (#FFC104) over a slate (#2A2F35); white text on the yellow fails, neither used.
   The nearest live leads by CIEDE2000 are p35 (ΔE 10.7, the Newcastle bathroom site) and p21 (11.2): inside the 10 to 13 range of recent picks. White on the lead 5.63:1. THE INK #1C1B14 and the paper #F4F3EC are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p38"] {
  --ink: #1C1B14;            /* an olive-black; white on it 17.27:1. The header and the closing band */
  --ink-soft: #55513D;       /* body-soft text; 7.98:1 on white, 7.18:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F4F3EC;    /* a faint stone paper — ENGINE-AUTHORED */
  --line: #E0DDCF;           /* hairline, decorative rules only */
  --field-border: #8A8670;   /* over the 3:1 non-text floor on white (3.67) and on the paper (3.30) */
  --accent: #6E6846;         /* the khaki lead — white text on it 5.63:1 */
  --accent-ink: #FFFFFF;
  --link: #6E6846;           /* the lead as the link colour on light grounds (5.06:1 on the paper); underlined by the base rule */
  --deep: #1C1B14;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t34 — Open Sans alone, for display and body. Direction 194 / site 30. Open Sans is the Bricks kit's body face (its heading face, PT Sans, is not taken: no file ships); no kit font FILE is used. SIL OFL 1.1, the latin-subset VARIABLE font already self-hosted for t29 and reused. Its @font-face is declared once above (t29). */
body[data-type="t34"] {
  --font-head: "Open Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Open Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.01em; --head-transform: none;
}

/* p39 — direction 195 / site 32 bathroomrenovationsipswich.au. A DEEP FERN-GREEN LEAD, HAND-PICKED. The licensed Xpat kit's own colour is a yellow (#FFEA00) over a near-black (#1F1C0C); white text on the yellow fails, neither used.
   The nearest live lead by CIEDE2000 is p9 (ΔE 10.0); every other live lead is farther: inside the 10 to 13 range of recent picks (a sweep over hue, saturation and lightness against p1 to p38, white text kept at 5.5 or more). White on the lead 5.51:1.
   THE INK #10231D and the paper #F1F6F3 are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p39"] {
  --ink: #10231D;            /* a green-black; white on it 16.40:1. The header and the closing band */
  --ink-soft: #3F5650;       /* body-soft text; 7.90:1 on white, 7.23:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F1F6F3;    /* a faint green-white paper — ENGINE-AUTHORED */
  --line: #D5E2DC;           /* hairline, decorative rules only */
  --field-border: #738A82;   /* over the 3:1 non-text floor on white (3.69) and on the paper (3.38) */
  --accent: #197663;         /* the fern lead — white text on it 5.51:1 */
  --accent-ink: #FFFFFF;
  --link: #197663;           /* the lead as the link colour on light grounds (5.04:1 on the paper); underlined by the base rule */
  --deep: #10231D;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t35 — Poppins 700 for headings over DM Sans for body. Direction 195 / site 32. Poppins is the Xpat kit's own text face (no kit font file is used); DM Sans is the body face already shipped for t7. SIL OFL 1.1, self-hosted. */
body[data-type="t35"] {
  --font-head: "Poppins", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.02em; --head-transform: none;
}

/* p40 — direction 196 / site 33 bathroomrenovationsgeelong.au. A DUSK-BLUE LEAD, HAND-PICKED. The licensed Arcodo kit's own colour is a yellow (#FDC830) over a near-black (#111212); white text on the yellow fails, neither used.
   The nearest live lead by CIEDE2000 is p3 (ΔE 9.8, a little under the 10 to 13 range of recent picks; a sweep over hue 150 to 235, saturation up to 0.6 and lightness 0.2 to 0.45 against p1 to p39, white text kept at 5.5 or more, found nothing farther in a natural hue; the farther candidates were saturated indigos). White on the lead 6.76:1.
   THE INK #14182B and the paper #F2F4F9 are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p40"] {
  --ink: #14182B;            /* a blue-black; white on it 17.57:1. The header and the closing band */
  --ink-soft: #454B66;       /* body-soft text; 8.57:1 on white, 7.78:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F2F4F9;    /* a faint blue-white paper — ENGINE-AUTHORED */
  --line: #D9DEEC;           /* hairline, decorative rules only */
  --field-border: #767E9C;   /* over the 3:1 non-text floor on white (4.01) and on the paper (3.65) */
  --accent: #4D588F;         /* the dusk-blue lead — white text on it 6.76:1 */
  --accent-ink: #FFFFFF;
  --link: #4D588F;           /* the lead as the link colour on light grounds (6.14:1 on the paper); underlined by the base rule */
  --deep: #14182B;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t36 — DM Sans alone, headings 700. Direction 196 / site 33. DM Sans is the Arcodo kit's own body face (no kit font file is used) and is already shipped for t7; the kit's heading face, Albert Sans, is not self-hosted. SIL OFL 1.1, self-hosted. */
body[data-type="t36"] {
  --font-head: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "DM Sans", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 700; --head-tracking: -0.015em; --head-transform: none;
}

/* p41 — direction 197 / site 35 poolrenovationsunshinecoast.au. A DEEP TEAL LEAD, HAND-PICKED. The licensed Pizi kit's own colour is a blue (#0152A3) over a near-black (#1F1F1F) with grey text (#8B8B8B, which fails on white); the blue is 4.7 from p13 and sits in the crowded blue band, so it is not used.
   The nearest live lead by CIEDE2000 is p39 (ΔE 8.2): a little under the 10 to 13 range of recent picks; a sweep over every hue, saturation 0.3 to 0.75 and lightness 0.24 to 0.42 against p1 to p40, white text kept at 5.5 or more, found no farther natural-hue lead except a magenta and a plum, which read as the wrong trade. White on the lead 5.55:1.
   THE INK #10282A and the paper #F1F7F7 are ENGINE-AUTHORED. The lead is for light grounds only. */
body[data-palette="p41"] {
  --ink: #10282A;            /* a teal-black; white on it 15.5:1. The header and the closing band */
  --ink-soft: #3F5557;       /* body-soft text; 7.6:1 on white, 6.9:1 on the paper */
  --surface: #FFFFFF;
  --surface-alt: #F1F7F7;    /* a faint teal-white paper — ENGINE-AUTHORED */
  --line: #D5E4E4;           /* hairline, decorative rules only */
  --field-border: #6E8E8E;   /* over the 3:1 non-text floor on white (3.6) and on the paper (3.3) */
  --accent: #267373;         /* the deep teal lead — white text on it 5.55:1 */
  --accent-ink: #FFFFFF;
  --link: #267373;           /* the lead as the link colour on light grounds (5.1:1 on the paper); underlined by the base rule */
  --deep: #10282A;           /* the dark ground is the ink — the lead is never a dark surface */
}

/* t37 — Oswald for display, Archivo for body. Direction 197 / site 35. Both are the Pizi kit's own faces (its style.css @imports Oswald and Archivo from Google Fonts); no kit font FILE is used. SIL OFL 1.1, latin-subset VARIABLE fonts, both already self-hosted (oswald-var-latin.woff2 shipped for t30, archivo-var-latin.woff2 for t10). */
body[data-type="t37"] {
  --font-head: "Oswald", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-body: "Archivo", ui-sans-serif, system-ui, -apple-system, "Segoe UI", sans-serif;
  --head-weight: 600; --head-tracking: 0.005em; --head-transform: none;
}

/* Sourced share table on the suburbs index (site 20, 25 Sep 2026). Deliberately not .prices, which the price-table gates match on. */
.area-shares-scroll { overflow-x: auto; margin: 1.25rem 0; }
.area-shares { border-collapse: collapse; width: 100%; min-width: 22rem; }
.area-shares caption { text-align: left; font-weight: 700; padding-bottom: .5rem; }
.area-shares th, .area-shares td { text-align: left; padding: .5rem .75rem; border-bottom: 1px solid currentColor; }
/* The frames: one column on a phone, one row of three from 37.5rem, cropped to the service cards' 16:10 (operator, 26 Sep 2026). */
.suburbs-frames { display: grid; gap: var(--gap-grid); grid-template-columns: 1fr; margin-top: 1.5rem; }
@media (min-width: 37.5rem) { .suburbs-frames { grid-template-columns: repeat(3, 1fr); } }
.suburbs-frames > .section__media { margin: 0; min-width: 0; }
.suburbs-frames > .section__media img { aspect-ratio: 16 / 10; object-fit: cover; }

/* YouTube click-to-load facade (operator ruling 26 Sep 2026; tools/build/lib/video.mjs). Before play: a button over the site's own
   thumbnail, no request to YouTube. On press, the inline script swaps in a youtube-nocookie.com iframe of the same box. */
.video-facade { margin: 1.5rem 0; }
.video-facade__play, .video-facade__frame { display: block; width: 100%; aspect-ratio: 16 / 9; border: 0; border-radius: 8px; }
.video-facade__play { position: relative; cursor: pointer; font: inherit; background: var(--ink) center / cover no-repeat; color: #FFFFFF; text-align: left; padding: 0; overflow: hidden; }
.video-facade__play::after { content: ""; position: absolute; inset: 0; background: linear-gradient(transparent 45%, rgb(0 0 0 / 0.72)); }
.video-facade__icon { position: absolute; z-index: 1; top: 50%; left: 50%; width: 72px; height: 72px; margin: -36px 0 0 -36px; border-radius: 50%; background: rgb(0 0 0 / 0.72); }
.video-facade__icon::before { content: ""; position: absolute; top: 50%; left: 54%; transform: translate(-50%, -50%); border-style: solid; border-width: 13px 0 13px 22px; border-color: transparent transparent transparent #FFFFFF; }
.video-facade__title { position: absolute; z-index: 1; left: 1rem; right: 1rem; bottom: .9rem; font-weight: 700; font-size: 1.05rem; line-height: 1.3; }
.video-facade__play:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }
.video-facade__note { font-size: .85rem; margin-top: .5rem; color: var(--ink-soft); }

/* Threshold checker (operator decision 26 Sep 2026; tools/build/lib/threshold-checker.mjs). The table is the content and reads without
   JavaScript; the script only marks rows .tc--on (applies at the value typed) and .tc--off (does not). */
.tc__head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: .5rem 1rem; }
.tc__head h2 { margin: 0; }
.tc__copy { font: inherit; font-size: .85rem; font-weight: 600; padding: .4rem .75rem; border: 1px solid var(--line); border-radius: 6px; background: var(--surface); color: var(--ink); cursor: pointer; white-space: nowrap; }
.tc__copy:hover, .tc__copy:focus-visible { border-color: var(--ink); }
.tc__controls { margin: 1rem 0; }
.tc__controls label { display: block; font-weight: 600; margin-bottom: .35rem; }
.tc__controls input { font: inherit; width: 100%; max-width: 18rem; padding: .55rem .7rem; border: 1px solid var(--field-border, var(--line)); border-radius: 6px; background: var(--surface); color: var(--ink); }
.tc__out { margin: .5rem 0 0; font-weight: 600; }
.tc__scroll { overflow-x: auto; margin: 1rem 0; }
.tc__table { border-collapse: collapse; width: 100%; min-width: 34rem; }
.tc__table caption { text-align: left; font-weight: 700; padding-bottom: .5rem; }
.tc__table th, .tc__table td { text-align: left; vertical-align: top; padding: .55rem .7rem; border-bottom: 1px solid var(--line); }
.tc__when { white-space: nowrap; font-weight: 600; }
.tc__src { font-size: .85rem; overflow-wrap: anywhere; }
.tc__flag { display: block; margin-top: .35rem; font-size: .85rem; font-style: italic; }
.tc__table tr.tc--on td { background: color-mix(in srgb, var(--ink) 9%, transparent); }
.tc__table tr.tc--on td:first-child { box-shadow: inset 4px 0 0 var(--ink); }
.tc__table tr.tc--off td { color: var(--ink-soft); } /* not opacity: small text must keep 4.5:1 */
.tc__send button { font: inherit; font-weight: 600; padding: .5rem .9rem; border: 1px solid var(--ink); border-radius: 6px; background: var(--surface); color: var(--ink); cursor: pointer; margin-right: .5rem; }
/* Row -> service page link inside each checker row, and the one link back to the checker on every service page (26 Sep 2026). */
.tc__svc { display: block; margin-top: .35rem; font-size: .85rem; }
/* ANSWER BOX (site 24, 29 Sep 2026): three radio questions above the checklist and a result panel built from the rows that apply. Hidden until the script runs. */
.tc__answer { margin: 1.25rem 0; padding: 1rem 1.1rem; border: 1px solid var(--line); border-radius: var(--radius, 8px); background: var(--surface); }
.tc__answer h3 { margin: 0 0 .35rem; }
.tc__qs { display: grid; gap: 1rem; margin: 1rem 0; grid-template-columns: 1fr; }
@media (min-width: 48rem) { .tc__qs { grid-template-columns: repeat(3, 1fr); } }
.tc__q { border: 0; margin: 0; padding: 0; min-width: 0; }
.tc__q legend { font-weight: 700; padding: 0; margin-bottom: .4rem; }
.tc__opt { display: flex; gap: .55rem; align-items: flex-start; padding: .5rem .6rem; margin-bottom: .35rem; border: 1px solid var(--field-border, var(--line)); border-radius: 6px; cursor: pointer; min-height: 44px; }
.tc__opt input { margin-top: .3rem; flex: none; inline-size: 1.05rem; block-size: 1.05rem; accent-color: var(--accent); }
.tc__opt:has(input:checked) { border-color: var(--ink); background: color-mix(in srgb, var(--ink) 7%, transparent); }
.tc__opt:has(input:focus-visible) { outline: 2px solid var(--ink); outline-offset: 2px; }
.tc__result { margin: .5rem 0 0; padding: .75rem 0 0; border-top: 1px solid var(--line); }
.tc__result h4 { margin: 1rem 0 .35rem; }
.tc__result ul { margin: 0 0 .5rem; padding-left: 1.1rem; }
.tc__result li { margin-bottom: .6rem; }
.tc__rsrc { display: block; font-size: .85rem; overflow-wrap: anywhere; }
.tc__count { margin: 0 0 .5rem; }
.tc__ansbtns { display: flex; flex-wrap: wrap; gap: .5rem; margin: .75rem 0 0; }
.tc__ansbtns button { font: inherit; font-weight: 600; padding: .5rem .9rem; border: 1px solid var(--ink); border-radius: 6px; background: var(--surface); color: var(--ink); cursor: pointer; min-height: 44px; }
.tc__ansbtns button:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }
.tc-back { margin-block: 0 calc(var(--space) * 2); }
/* 29 Sep 2026 (site 24): the checker link is the last line of the section above it, but sat a full section padding (80px at 390, 120px at 1440) below that section's last paragraph. Pull it up to about a line and a half. Written at body[data-direction] weight because every direction sets its own .section padding at that weight. */
body[data-direction] .section:has(+ .tc-back) { padding-block-end: calc(var(--space) * 1.5); }
