Pouya's rulings and the page are one commit, not two, because they are not separable: Q37 changed the credential label the page renders, Q39 scoped the arbitration copy, and Q35 gave Med-Arb the row that lets the footer link stand. Splitting them would produce a commit where the register says one thing and the page says another. RULINGS Q39 — ANSWERED, and my assertion was FALSE as a universal. Pouya checked rather than defended. Family arbitration in Ontario is gated: prescribed training, 14h on screening for domestic violence and power imbalances, 30h of Ontario family law for arbitrators outside the bar, 10h ongoing per two years. claims-auditor produced that counter-example from inside the repo on 2026-08-26 and it was right. The source is now IN the repo per R14 — docs/reference/ontario-family-arbitration-training.md, retrieved with its provenance — and §4 states which half it establishes: the family gate directly, the commercial half only by absence. So "commercial arbitration in Ontario requires no licence and no designation" is recorded as Pouya's stated position, unstamped. What disposes of the question is the scope exclusion: he does not do family arbitration, so it is NOT OFFERED and the gate never bears on the practice. The false universal survived in three more live places, found by grep, not recall: §4's NOT-NEGOTIABLE boundary bullet (the boundary paragraph breaching its own boundary), §9's Q33 closure row, and a comment in SiteHeader.astro. Q35 — ANSWERED, all four items, and the answer supplied a gate that was missing. Med-Arb gets an Offerings row and stays in the footer sitemap. The six subject-matter labels pass test 1. §4 gains "Subject-matter areas — the publication gate": competence to accept an appointment, AND a page that frames it as positioning without claiming history. Nothing in the nav or footer is unrowed any more. Q37 — ANSWERED. "Law and engineering" becomes "Legal training and engineering practice". A degree is not a practice; the parallel was doing the implying. Q38/R13 — the committed SVG does not close it; the walk-back went too far. It renders faithfully BECAUSE it is the raster. R13 stays open. R1 — surfaced and acknowledged; the interim licensure framing is now carried by a shipped page rather than a spec, which raises the stakes. BUILD STEP 2 Seven of docs/01's eight home sections, six new components, zero JavaScript. Section 7 (Latest insights) ships at step 7 with the collection it lists — recorded in docs/01 and in the page, not just here. Four credential slots, not three: §4's paired-disclosure condition requires the Q.Arb stage on any page that offers arbitration. No booking link (R6). The masthead tagline is suppressed on / (it duplicated the hero eyebrow). The step-1 proof sheet is deleted, and five live references to it were found by grep. WHAT THE REVIEWS FOUND — 24 findings across the two passes claims-auditor FAILED it on ten, every one implication or scope rather than fabrication, which is where D13 says the risk lives. The four that mattered: "I mediate and arbitrate" asserted a track record §4 does not hold for arbitration; the JSON-LD asserted arbitration twice and stated the stage nowhere (a crawler-only claim is still a claim); "at one published rate with preparation time included" misdescribed money against docs/07's two day rates and capped prep allowance; and "Law and engineering are not blended here" was Q37's struck parallel relocated into prose one day after Pouya struck it. It also found the Canadian Tax Foundation missing from §9 Q8 — a stale second copy of a fact that would have bitten at step 3. adversarial-reviewer found fourteen, three blocking. The first was class="section-head" on <SectionHeading> never matching — the parent-cannot- style-a-child defect for the FOURTH time, written into a diff where I had just added fresh warnings about it to two other components. Measured: 0px margin, 0px gap, headings over the card edges, with astro check and eslint both clean. I had looked at a screenshot of that section and passed over it. Fixed with a page-owned wrapper (48px, measured) and the prop is deleted from six components so it is now a build error. Also: the credential row was never "two up on a phone" and its comment said it was; PROCESS was hardcoded in the page against the reason written in site.ts; 83px of residual overflow at a 200% default font size, now 3px. Seven more I found myself first, including <Picture widths> declaring the untouched 1600px master as the <img src> fallback (254,626 B for a 476px slot, and the build log said "before: 349kB" either way), and a prop named `as` silently turning off type-checking for a whole component. VERIFICATION — run, not asserted. Full figures in AGENTS.md entry (w). npx tsc 6.0.3 · check 0/0/0 · lint clean · build clean · audit 0 1 <script> and it is JSON-LD; non-JSON-LD scripts 0; no JS bundle; identical page with script execution disabled (444 nodes, 6,578 chars) Phase 5 minifier check: no `animation` shorthand beside animation-timeline overflow 0 at 14 widths, AND every mark measured at 1.5654-1.5657 vs 1.5657 one h1, no heading skips, focus order == DOM order across 44 focusables 31 painted contrast pairs at 3 widths, 0 failures 72/72 hit-test points across 8 cards resolve to the card's link print 0 hidden, reduced-motion 0 hidden Lighthouse NOT RUN — tool unavailable until step 7 (R11) HTML validator NOT RUN, and 4 of 12 srcsets carry a duplicate 1x descriptor Opened for Pouya: Q40 (one OG image for nineteen pages), Q41 (does Q37 reach prose; may the comparative be restored; what LAT pre-hearing mediation means), Q42 (the four "also offered" processes have no row), Q43 (the process timings are published commitments with no row). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
174 lines
7.7 KiB
CSS
174 lines
7.7 KiB
CSS
/* ============================================================================
|
|
Design tokens — the single source of colour, type, space, and motion.
|
|
Spec: docs/02-design-system.md
|
|
|
|
Never write a raw hex value or a magic number in a component. If a value is
|
|
missing here, add it here.
|
|
========================================================================= */
|
|
|
|
:root {
|
|
/* --- Colour ------------------------------------------------------------
|
|
Palette carried over unchanged from the previous build (AGENTS.md D7).
|
|
Contrast ratios measured 2026-08-25 and recorded in docs/02. */
|
|
|
|
--cream: #faf7f2; /* page background */
|
|
--cream-2: #f3ede0; /* alternating section background */
|
|
--cream-3: #ebe3d1; /* cards and insets on cream */
|
|
|
|
--ink: #1a1614; /* body text; dark section backgrounds 16.81:1 */
|
|
--ink-soft: #3a322c; /* secondary text 11.75:1 */
|
|
--muted: #6e6359; /* metadata — ON CREAM ONLY (3.07:1 on ink) */
|
|
|
|
--maroon: #5a1a1c; /* primary action, dark panels 12.29:1 */
|
|
--maroon-d: #3d1112; /* hover on maroon */
|
|
--maroon-l: #7a2a2c; /* links on cream 8.95:1 */
|
|
|
|
/* GOLD IS NOT A TEXT COLOUR ON CREAM.
|
|
--gold on cream measures 2.10:1 and fails AA for body AND large text.
|
|
--gold-d measures 3.11:1 — large decorative text only, 24px+.
|
|
Both are fine on --ink (8.00) and --maroon (5.84). See docs/02. */
|
|
--gold: #c9a876; /* rules, dividers, icon strokes, on-dark text */
|
|
--gold-d: #a88858; /* large decorative display text on cream only */
|
|
--gold-l: #e2c89a; /* text: 11.09:1 on ink, 8.11:1 on maroon */
|
|
|
|
--line: rgb(26 22 20 / 0.10);
|
|
--line-2: rgb(26 22 20 / 0.06);
|
|
--line-dark: rgb(250 247 242 / 0.14);
|
|
|
|
/* Semantic aliases — prefer these in components over raw palette names. */
|
|
--bg: var(--cream);
|
|
--bg-alt: var(--cream-2);
|
|
--bg-raised: var(--cream-3);
|
|
--bg-inverse: var(--ink);
|
|
--text: var(--ink);
|
|
--text-secondary: var(--ink-soft);
|
|
--text-meta: var(--muted);
|
|
--text-inverse: var(--cream);
|
|
--text-inverse-2: var(--gold-l);
|
|
--accent: var(--maroon);
|
|
--accent-hover: var(--maroon-d);
|
|
--link: var(--maroon-l);
|
|
--rule: var(--gold);
|
|
--border: var(--line);
|
|
--focus-ring: var(--maroon);
|
|
/* docs/02: "outline: 2px solid var(--maroon); outline-offset: 3px". The
|
|
offset was written as a literal in global.css and then in two components,
|
|
which is three places to forget. */
|
|
--focus-offset: 3px;
|
|
|
|
/* --- Type -------------------------------------------------------------- */
|
|
|
|
--font-serif: 'Instrument Serif', 'Cormorant Garamond', Georgia, 'Times New Roman', serif;
|
|
--font-sans: 'Geist', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
--font-mono: 'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
|
|
/* Fluid scale, 360px → 1600px viewport. Ratio widens toward the display
|
|
end (1.25 → 1.333) so headlines scale harder than body copy.
|
|
--text-2xs is the eyebrow floor docs/02 sets at 11px. Added 2026-08-27:
|
|
SiteHeader wrote `0.6875rem` as a literal, step-1 review finding #7. */
|
|
--text-2xs: 0.6875rem; /* 11 — eyebrow */
|
|
--text-xs: 0.75rem; /* 12 — legal */
|
|
--text-sm: 0.875rem; /* 14 — meta */
|
|
--text-base: 1rem; /* 16 — body */
|
|
--text-lg: clamp(1.0625rem, 0.99rem + 0.32vw, 1.1875rem); /* 17→19 */
|
|
--text-xl: clamp(1.25rem, 1.14rem + 0.48vw, 1.5rem); /* 20→24 */
|
|
--text-2xl: clamp(1.5rem, 1.31rem + 0.81vw, 1.875rem); /* 24→30 */
|
|
--text-3xl: clamp(1.875rem, 1.55rem + 1.37vw, 2.5rem); /* 30→40 */
|
|
--text-4xl: clamp(2.25rem, 1.66rem + 2.50vw, 3.5rem); /* 36→56 */
|
|
--text-5xl: clamp(2.75rem, 1.75rem + 4.25vw, 4.75rem); /* 44→76 */
|
|
--text-6xl: clamp(3.25rem, 1.75rem + 6.35vw, 6rem); /* 52→96 */
|
|
|
|
--leading-display: 0.98;
|
|
--leading-tight: 1.15;
|
|
--leading-snug: 1.35;
|
|
--leading-body: 1.6;
|
|
--leading-relaxed: 1.75;
|
|
|
|
--tracking-display: -0.02em;
|
|
--tracking-tight: -0.01em;
|
|
--tracking-normal: 0;
|
|
--tracking-wide: 0.06em;
|
|
--tracking-eyebrow: 0.18em;
|
|
|
|
--weight-light: 300;
|
|
--weight-normal: 400;
|
|
--weight-medium: 500;
|
|
--weight-semi: 600;
|
|
|
|
/* --- Space — 8px base -------------------------------------------------- */
|
|
|
|
/* 2 — a hairline gap, below the 4px base step. It exists because the
|
|
two-line brand block needs a gap smaller than --space-1 without the header
|
|
growing; step-1 review finding #7 flagged the literal. Do not reach for it
|
|
as a general step: the 8px base starts at --space-1. */
|
|
--space-05: 2px;
|
|
--space-1: 0.25rem; /* 4 */
|
|
--space-2: 0.5rem; /* 8 */
|
|
--space-3: 0.75rem; /* 12 */
|
|
--space-4: 1rem; /* 16 */
|
|
--space-5: 1.5rem; /* 24 */
|
|
--space-6: 2rem; /* 32 */
|
|
--space-7: 3rem; /* 48 */
|
|
--space-8: 4rem; /* 64 */
|
|
--space-9: 6rem; /* 96 */
|
|
--space-10: 8rem; /* 128 */
|
|
--space-11: 10rem; /* 160 */
|
|
|
|
/* docs/02: "Section rhythm: --space-9 (96px) mobile, --space-11 (160px)
|
|
desktop." The previous curve was `6vw + 2rem`, which reaches 160px only at
|
|
a 2133px viewport — measured 128px at 1600px, 108.8px at 1280px. The upper
|
|
bound was unreachable on any real screen, so the token read as if it
|
|
delivered a rhythm it never delivered. `9vw + 1rem` hits 160px at 1600px
|
|
and still clamps to 96px on a phone. [measured 2026-08-26] */
|
|
--section-y: clamp(var(--space-9), 9vw + 1rem, var(--space-11));
|
|
|
|
/* --- Layout ------------------------------------------------------------ */
|
|
|
|
/* Sticky-header height at >= 66rem, where the header IS sticky. global.css
|
|
drives `scroll-padding-top` off this, so the skip link does not drop the
|
|
reader behind the header. If SiteHeader's padding or nav sizing changes,
|
|
re-measure and change this with it — one fact living in two files.
|
|
[measured 2026-08-26 — headless Chrome at 1024/1100/1280/1440px, with six
|
|
nav items and with a seventh injected. 81px at every one: 32 padding + 48
|
|
reserved brand block + the 1px bottom border, which is easy to forget and
|
|
is why this is measured rather than added up. The brand reserves 48px so
|
|
the height does not change when the tagline appears at 76rem] */
|
|
--header-h: 5.0625rem; /* 81 — measured, not chosen */
|
|
|
|
--width-content: 80rem; /* 1280 */
|
|
--width-wide: 90rem; /* 1440 */
|
|
--width-prose: 68ch; /* reading measure — never exceed for body copy */
|
|
--gutter: var(--space-5);
|
|
--gutter-lg: var(--space-7);
|
|
|
|
/* --- Radius, elevation, motion ----------------------------------------- */
|
|
|
|
--radius-sm: 4px;
|
|
--radius-md: 8px;
|
|
--radius-lg: 16px;
|
|
--radius-full: 999px;
|
|
|
|
--shadow-sm: 0 1px 2px rgb(26 22 20 / 0.04);
|
|
--shadow-md: 0 4px 16px rgb(26 22 20 / 0.06);
|
|
--shadow-lg: 0 12px 40px rgb(26 22 20 / 0.10);
|
|
|
|
--ease: cubic-bezier(0.2, 0.7, 0.2, 1);
|
|
--ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
--dur-fast: 150ms;
|
|
--dur-hover: 250ms;
|
|
--dur-reveal: 600ms;
|
|
|
|
--z-base: 0;
|
|
--z-sticky: 100;
|
|
--z-header: 200;
|
|
--z-overlay: 300;
|
|
--z-skip: 400;
|
|
}
|
|
|
|
@media (min-width: 48rem) {
|
|
:root { --gutter: var(--gutter-lg); }
|
|
}
|
|
|
|
/* No dark mode by design (docs/02). A single committed light identity is the
|
|
right call for a legal practice and halves the ways contrast can break. */
|