feat: build step 3 — /about/, minus its memberships; close Q40–Q43
Build and deploy / build-and-deploy (push) Failing after 6s
Build and deploy / build-and-deploy (push) Failing after 6s
Applies Pouya's rulings on Q42, Q41(a)(b)(c), Q43 and Q40, then builds `/about/` — six of docs/01's seven items. `/about/` ships WITHOUT a memberships group. R10 is a prohibition on shipping a page that lists memberships before they are re-confirmed; the re-confirmation is a fact only Pouya holds and was not obtained. The first version published all four and disclosed the gap in five places instead; both review agents rejected that. Q44 carries the question. Rulings: - Q42 — ENE, dispute-system design and pre-dispute technical advisory rowed; settlement counsel struck as a partisan role. The strike exposed a hole in the offering test, which now states the prior question it was missing. - Q41(a) — Q37 reaches prose, and prose is held to a higher bar. The sentence is now one constant, ASYMMETRY_LINE, because two hand-typed copies had already diverged inside one session. - Q41(b) — not restored; the implication turned out to be in three places, two of which survived the sweep that closed it. - Q41(c) — verified against the LAT's own Rules and extracted into docs/reference/lat-case-conference.md. Rule 2.4 makes "Pre-Hearing Conference" the Tribunal's own term for a case conference; the Rules contain zero occurrences of `mediat` in 66,593 characters. - Q43 — the timings are service commitments; PROCESS_FRAMING renders adjacent to them, not in a lede above. - Q40 — bundled to step 7 as R15, blocking cutover. Four review passes, 43 findings, nine of them defects in their own predecessors' fixes. The worst was mine: the false universal Q39 struck reached a public page. Also fixed a portrait ladder that upscaled 1.93x at 1024/DPR2 on BOTH pages — the shipped home page included — because its 960 ceiling was derived from the layout range where the image is narrowest. Verified: check/lint/build/audit clean; 0 upscaling across 11 device profiles; 0 overflow and 0 over-wide elements at 13 widths; 0 contrast failures across 127 and 88 painted pairs; 0 print failures against white paper; reveal 0 hidden under reduced-motion and print; zero JavaScript. Lighthouse NOT RUN — tool unavailable until step 7 (R11). HTML validator NOT RUN. Opens Q44 (memberships), Q45 (PDF bio), Q46 (offering-test gating; the glossary standard), Q47 (jobTitle without worksFor). Adds R15. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0148NztQskLKKApP5SzAA78e
This commit is contained in:
co-authored by
Claude Opus 5
parent
165d259f5c
commit
c576b9a85f
@@ -0,0 +1,971 @@
|
||||
---
|
||||
/**
|
||||
* `/about/` — Biography and credentials. Build step 3 (docs/01 §Build order):
|
||||
* "the credential spine everything else references."
|
||||
*
|
||||
* JOB (docs/01 §`/about/`): "be the page an appointing body or opposing counsel
|
||||
* reads before agreeing to an appointment. This page carries the verifiable
|
||||
* record."
|
||||
*
|
||||
* SECTIONS, against docs/01's seven-item outline:
|
||||
* 1 Portrait, name, designation line → the hero
|
||||
* 2 Narrative biography, 400–600 words → §Background
|
||||
* 3 Credentials, structured → §Credentials
|
||||
* 4 The credentialing arc → §The arc
|
||||
* 5 Languages and cross-cultural → §Language
|
||||
* 6 Speaking and publications → OMITTED, per the spec itself
|
||||
* 7 Person JSON-LD + PDF bio → JSON-LD ships; the PDF does not
|
||||
*
|
||||
* ITEM 6 IS OMITTED ON THE SPEC'S OWN INSTRUCTION, not by oversight: "Omit the
|
||||
* section entirely until there is something in it. An empty 'Speaking' heading
|
||||
* is worse than no heading." Nothing to list.
|
||||
*
|
||||
* ITEM 7'S PDF IS NOT SHIPPED, and the omission is stated rather than silent —
|
||||
* AGENTS.md Q45. No such file exists, and a link to a missing file on the page
|
||||
* an appointing body reads is worse than its absence. It is also not a
|
||||
* formatting job: a one-page bio is a credential document circulated DETACHED
|
||||
* from the site, where no build and no reviewer ever re-checks it. Two
|
||||
* decisions there are Pouya's.
|
||||
*
|
||||
* THE PARENT/CHILD SCOPE TRAP, because this page uses <SectionHeading> four
|
||||
* times. A parent CANNOT style a child component's root element — the rule
|
||||
* compiles against the parent's cid and silently never matches. Every heading
|
||||
* below is wrapped in a page-owned <div class="section-head">. Not defensive
|
||||
* boilerplate: it is the fourth-instance defect CLAUDE.md records, and the
|
||||
* components have had their `class` props deleted so passing one is a build
|
||||
* error rather than a silent no-op.
|
||||
*
|
||||
* R10 / Q44 — THE MEMBERSHIPS GROUP IS NOT ON THIS PAGE. R10 is written as a
|
||||
* prohibition — re-confirm *before* any page listing memberships ships — and
|
||||
* `/about/` is the page it names. The re-confirmation is a fact only Pouya holds
|
||||
* and was not obtained, so the group is withheld and a `TODO(pouya)` sits on
|
||||
* CREDENTIAL_GROUPS below with the exact question. §4 is NOT re-stamped:
|
||||
* nothing was re-checked. Q44.
|
||||
*
|
||||
* A first version of this page published all four and disclosed the gap instead.
|
||||
* Both review agents rejected that; the reasoning is on CREDENTIAL_GROUPS.
|
||||
*/
|
||||
import { Picture, getImage } from 'astro:assets';
|
||||
import BaseLayout from '../layouts/BaseLayout.astro';
|
||||
import ContactBand from '../components/ContactBand.astro';
|
||||
import Eyebrow from '../components/Eyebrow.astro';
|
||||
import Pill from '../components/Pill.astro';
|
||||
import SectionHeading from '../components/SectionHeading.astro';
|
||||
import portrait from '../assets/pouya-lajevardi.jpg';
|
||||
import ogDefault from '../assets/og-portrait.jpg';
|
||||
import { aboutGraph } from '../data/schema';
|
||||
import {
|
||||
ASYMMETRY_LINE,
|
||||
CREDENTIALS,
|
||||
PORTRAIT,
|
||||
ROLE,
|
||||
SITE,
|
||||
} from '../data/site';
|
||||
|
||||
/**
|
||||
* `image` ON THE Person NODE — docs/04 lists it, and this page is where
|
||||
* PERSON_ID (`/about/#person`) actually resolves.
|
||||
*
|
||||
* AN EARLIER VERSION OF THIS PAGE OMITTED IT and argued at length that it could
|
||||
* not be supplied: "SEO.astro computes that URL internally and does not expose
|
||||
* it." That reasoning talked itself into the wrong answer — the URL does not
|
||||
* have to come from SEO.astro. `/` derives it in six lines with `getImage()`,
|
||||
* and the same six lines work here. The result was two documents asserting the
|
||||
* same `@id` with different property sets, which is worse than either choice
|
||||
* made deliberately.
|
||||
*
|
||||
* EXACTLY the transform SEO.astro applies to the same source (jpeg, 1200x630),
|
||||
* so Astro's asset cache returns the same hashed file rather than emitting a
|
||||
* second copy for the crawler. JPEG on purpose: link-preview and structured-data
|
||||
* consumers are not browsers and several still do not decode WebP, let alone
|
||||
* AVIF.
|
||||
*
|
||||
* The withdrawn reasoning follows, because it is a good example of a comment
|
||||
* arguing for a defect.
|
||||
*
|
||||
* NO `getImage()` CALL FOR THE JSON-LD IMAGE, unlike `/`.
|
||||
*
|
||||
* `/` generates the 1200x630 jpeg so the Person node can carry an absolute
|
||||
* `image` URL, and it works because that page renders the ProfessionalService
|
||||
* node too. Here the Person node is the whole graph, and SEO.astro already emits
|
||||
* exactly the same transform of exactly the same source as `og:image`. Calling
|
||||
* `getImage()` again would return the same cached asset — so this is not about
|
||||
* duplicate files, it is about a second place that has to be kept in step with
|
||||
* SEO.astro's transform. It is passed the URL by the layout instead.
|
||||
*
|
||||
* Except it cannot be: `SEO.astro` computes that URL internally and does not
|
||||
* expose it. So the node ships WITHOUT `image` on this page and WITH it on `/`,
|
||||
* which is a real inconsistency in a field docs/04 lists for the Person node.
|
||||
* Both resolve to the same @id, so a crawler joining the two documents gets the
|
||||
* image either way — but that is a hope about crawler behaviour, not a fact.
|
||||
* Recorded rather than papered over; the fix is for SEO.astro to expose the URL
|
||||
* it already computes, which is a component change and not a page change.
|
||||
*/
|
||||
const ldImage = await getImage({
|
||||
src: ogDefault,
|
||||
format: 'jpeg',
|
||||
width: 1200,
|
||||
height: 630,
|
||||
});
|
||||
const graph = aboutGraph(new URL(ldImage.src, Astro.site).href);
|
||||
|
||||
/**
|
||||
* The designation line — docs/01 item 1. Assembled from constants so it cannot
|
||||
* drift from §4, and ordered held-first.
|
||||
*
|
||||
* Q.Arb IS NOT IN IT, deliberately. It is not held (§4: "Describe as newly
|
||||
* commenced, never as held or nearing completion"), and a designation line is
|
||||
* precisely a list of things held. The arc section states the stage plainly,
|
||||
* which is what §4's paired-disclosure condition requires — this page offers
|
||||
* arbitration, so the stage appears on this page and not only in the footer.
|
||||
*/
|
||||
const designationLine = [
|
||||
'Mediator',
|
||||
CREDENTIALS.designations[0],
|
||||
CREDENTIALS.education[0],
|
||||
];
|
||||
|
||||
/**
|
||||
* The credentialing arc — docs/01 item 4, and docs/03: "the credentialing
|
||||
* pathway from Q.Med through Q.Arb to C.Med-Arb is stated openly as in
|
||||
* progress. The brief treats that arc as part of the story rather than
|
||||
* something to obscure."
|
||||
*
|
||||
* `state` is the load-bearing column. "Commenced August 2026" is §4's exact
|
||||
* wording and the ONLY permitted wording — docs/03: not "in progress", because
|
||||
* the weaker form drifts toward "nearly complete", which §4 Forbidden bars
|
||||
* outright.
|
||||
*/
|
||||
/*
|
||||
* FIVE CLAIMS CAME OUT OF THIS BLOCK, and the first was the worst thing in the
|
||||
* step-3 diff. BOTH review agents found it independently, which is the strongest
|
||||
* signal this loop produces.
|
||||
*
|
||||
* 1. ⚠️ "arbitral appointments are not gated behind it, which is why I accept
|
||||
* them now" — **the false universal Q39 struck, on a public page.**
|
||||
* Unscoped ("arbitral", not commercial), asserted as flat fact in the first
|
||||
* person, and it publishes a proposition of Ontario law that §4 holds only
|
||||
* in scoped form and deliberately does NOT stamp `[verified]`. Family
|
||||
* arbitration is an arbitral appointment and it IS gated
|
||||
* (`docs/reference/ontario-family-arbitration-training.md`). Q39 swept
|
||||
* three instances of this universal on 2026-08-27; this was the fourth and
|
||||
* the first outside a comment. §4 requires the STAGE be stated — never the
|
||||
* register's gating rationale. Deleted rather than rescoped: this page has
|
||||
* no business carrying the argument at all.
|
||||
* 2. "on the same institutional pathway" and
|
||||
* 3. "Three designations on one institutional pathway" (the section lede) —
|
||||
* §4 attaches ADRIC / ADRIO to **Q.Med only**. Neither the Q.Arb row nor
|
||||
* the C.Med-Arb row names a body.
|
||||
* 4. "The senior hybrid designation" — a ranking claim about a third party's
|
||||
* credential structure, with no row and no source.
|
||||
* 5. The expansions — "Qualified Mediator", "Qualified Arbitrator",
|
||||
* "Chartered Mediator-Arbitrator". Flagged as being in §11 Glossary but
|
||||
* not in §4 Verified.
|
||||
*
|
||||
* ⚠️ ITEM 5 WAS REMOVED AND IS NOW RESTORED, AND IT IS THE ONE PLACE THIS
|
||||
* SESSION WENT AGAINST A REVIEW FINDING. The reason is a SECOND finding, from
|
||||
* the next audit pass, and it is a consistency point rather than a claim point:
|
||||
* this page also publishes "Provincial Offences Act", "Statutory Accident
|
||||
* Benefits Schedule" (as SABS) and "the ADR Institute of Canada and the ADR
|
||||
* Institute of Ontario" — every one of them a §11 Glossary expansion, on exactly
|
||||
* the ground the designation names were struck. *"One standard or the other."*
|
||||
*
|
||||
* The standard chosen is: **§11 Glossary is the source for DEFINITIONAL
|
||||
* expansions** — what an abbreviation stands for — while §4 Verified remains the
|
||||
* only source for claims ABOUT POUYA. Expanding `Q.Med` says nothing about him;
|
||||
* "he holds it" is the claim, and that has a row. The alternative standard would
|
||||
* have required stripping POA, SABS and the institute names from the prose and
|
||||
* `recognizedBy` from the JSON-LD, which makes the page materially worse for a
|
||||
* reader who does not already know the acronyms, in exchange for no reduction in
|
||||
* risk. **Q46 asks Pouya to ratify that standard** and it is the only thing
|
||||
* holding it up; if he declines, all four classes come out together.
|
||||
*
|
||||
* Sourcing them externally was tried first and failed: `adric.ca/designations/`
|
||||
* redirects to `/designations-cee/` and its HTML contains **zero** occurrences
|
||||
* of "Q.Med", "Qualified Mediator" or "Chartered Mediator" in 114,985 bytes —
|
||||
* navigation only, body assembled client-side. So R14 cannot be met from the
|
||||
* obvious URL, which is why this rests on §11 and on Q46 rather than on a
|
||||
* committed extract.
|
||||
*/
|
||||
const ARC = [
|
||||
{
|
||||
name: 'Q.Med',
|
||||
state: 'Held',
|
||||
/* NOT "the designation I mediate under". That imported a PERMISSION framing
|
||||
onto what §4 records as a voluntary credential, in a register that says
|
||||
no designation is required to be appointed as a mediator — the
|
||||
credential-as-licence slip §4 says produced a wrong answer twice. */
|
||||
body:
|
||||
'Qualified Mediator, held through the ADR Institute of Canada and the ' +
|
||||
'ADR Institute of Ontario. The designation I hold as a mediator today.',
|
||||
},
|
||||
{
|
||||
name: 'Q.Arb',
|
||||
state: 'Commenced August 2026',
|
||||
body:
|
||||
'Qualified Arbitrator. Newly commenced — not held, and not nearing ' +
|
||||
'completion.',
|
||||
},
|
||||
{
|
||||
name: 'C.Med-Arb',
|
||||
state: 'The endpoint',
|
||||
body:
|
||||
'Chartered Mediator-Arbitrator. The designation this practice is built ' +
|
||||
'toward.',
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* The structured credentials — docs/01 item 3: "designations, education,
|
||||
* certifications, memberships. Every line from AGENTS.md §4 Verified."
|
||||
*
|
||||
* LANGUAGES ARE NOT A GROUP HERE, and that is a heading decision rather than an
|
||||
* omission: docs/01 item 5 gives them a section of their own, and having both
|
||||
* an h3 "Languages" group and an h2 "Language" section would put the same two
|
||||
* facts in the accessibility tree twice under near-identical names. The section
|
||||
* wins because it carries the cross-cultural half, which a list cannot.
|
||||
*
|
||||
* NOT PRESENT, AND EACH IS A §4 DIRECTIVE RATHER THAN A GAP:
|
||||
* - The Law Society. Listing it implies licensure, which D13 bars. §4:
|
||||
* "Excluded deliberately, not by oversight."
|
||||
* - OCNI. Not current (§4), so it is not published.
|
||||
* - Any licence status, in either direction. §4 records it `[unestablished]`.
|
||||
*
|
||||
* TODO(pouya): Are ADRIC, ADRIO, the three OBA sections (Construction &
|
||||
* Infrastructure, ADR, Civil Litigation) and the Canadian Tax Foundation all
|
||||
* current TODAY, and in which month does each renew? — AGENTS.md Q44.
|
||||
*
|
||||
* ⚠️ MEMBERSHIPS ARE DELIBERATELY NOT RENDERED, AND THIS IS A REVERSAL.
|
||||
*
|
||||
* The first version of this page published all four on §4's 2026-08-26 stamp and
|
||||
* disclosed the outstanding re-confirmation in a note, in this comment, in
|
||||
* `schema.ts`, in §9 Q44 and on the cutover checklist. Both review agents
|
||||
* rejected that, and they are right. §12 **R10** is written as a PROHIBITION —
|
||||
* *"Re-confirm at each renewal, **and before any page listing memberships
|
||||
* ships** — `/about/` at build step 3 is the first one that will"* — and
|
||||
* documenting a prohibition is not discharging it. `CLAUDE.md` gives the
|
||||
* procedure for a fact you do not have, and it is this one: leave
|
||||
* `TODO(pouya)`, log the question, let the gap be visible. *"A build that fails
|
||||
* on an unanswered question is a correct build."*
|
||||
*
|
||||
* The alternative was to ship them and call it disclosed. It was taken once and
|
||||
* is recorded here as the decision it was, not as an oversight — and it came
|
||||
* with a second defect on top: the note asserted *"Memberships are renewed
|
||||
* annually and are listed as current"*, which (a) warranted currency the
|
||||
* register cannot vouch for and (b) widened §4, which records yearly renewal for
|
||||
* the **OBA sections and the CTF only** and says nothing about ADRIC or ADRIO.
|
||||
*
|
||||
* OCNI is the precedent and it is in §4: a membership lapsed, quietly, and the
|
||||
* register now reads "not current, do not publish". Nothing tells you when.
|
||||
*
|
||||
* The other three groups ship. Restoring this one is one array entry, the moment
|
||||
* Q44 closes — and re-stamp §4 and `CREDENTIALS.memberships` that day.
|
||||
*/
|
||||
const CREDENTIAL_GROUPS = [
|
||||
{ title: 'Designations', items: CREDENTIALS.designations },
|
||||
{ title: 'Education', items: CREDENTIALS.education },
|
||||
{ title: 'Certifications', items: CREDENTIALS.certifications },
|
||||
];
|
||||
---
|
||||
|
||||
<BaseLayout
|
||||
title="About · Pouya Lajevardi · Mediator, Q.Med · Toronto"
|
||||
description="Pouya Lajevardi, JD, Q.Med — a Toronto mediator who also practises as a machine-learning and infrastructure engineer. Credentials, background, designations."
|
||||
ogType="profile"
|
||||
imageAlt={PORTRAIT.alt}
|
||||
jsonLd={graph}
|
||||
>
|
||||
{/* ---- 1. Hero: portrait, name, designation line --------------------- */}
|
||||
<section class="hero">
|
||||
<div class="wrap hero-inner">
|
||||
<div class="hero-copy">
|
||||
<Eyebrow dot>About</Eyebrow>
|
||||
|
||||
{
|
||||
/* THE H1 IS THE NAME, not a headline, and that is docs/01 item 1
|
||||
("Portrait, name, designation line") agreeing with the search intent
|
||||
it records for this page (`"Pouya Lajevardi"`, `Pouya Lajevardi
|
||||
mediator`). The masthead carries the name as a brand mark; a bio page
|
||||
needs it as the document's subject. */
|
||||
}
|
||||
<h1 class="display hero-h">{SITE.name}</h1>
|
||||
|
||||
{
|
||||
/* EACH SEPARATOR IS INSIDE THE SPAN IT PRECEDES, not a sibling of it.
|
||||
As siblings the flex container wrapped between them, leaving an
|
||||
orphaned "·" at the end of line 1 at 390px. The NON-BREAKING SPACE
|
||||
after the glyph is what keeps it attached — an earlier version used
|
||||
`white-space: nowrap` on the whole item instead, which fixed the
|
||||
orphan and broke reflow at a 200% default font size. */
|
||||
}
|
||||
<p class="designation">
|
||||
{
|
||||
designationLine.map((part, i) => (
|
||||
<span class="designation-part">
|
||||
{i > 0 && (
|
||||
<span class="sep" aria-hidden="true">
|
||||
{'·\u00A0'}
|
||||
</span>
|
||||
)}
|
||||
{part}
|
||||
</span>
|
||||
))
|
||||
}
|
||||
</p>
|
||||
|
||||
{
|
||||
/* THE ROLE LINE, and it is the single highest-risk sentence on this
|
||||
page. Both strings come from `ROLE` in src/data/site.ts rather than
|
||||
being typed here, for the reason that file gives: "these are the two
|
||||
where the wording IS the compliance."
|
||||
|
||||
D13: the approved phrasing is "active litigation exposure", NEVER
|
||||
"practice" in this context. The boutique is never named (D16). The
|
||||
matter types are §4 verbatim and must not be extended without a row.
|
||||
|
||||
EXPLICITLY INTERIM — AGENTS.md R1, surfaced again 2026-08-28
|
||||
precisely because this page is where the framing now does its
|
||||
heaviest work. */
|
||||
}
|
||||
<p class="hero-lede">
|
||||
I am {ROLE.title} at {ROLE.at}, with {ROLE.litigationLine} across{' '}
|
||||
{ROLE.litigationAreas.slice(0, -1).join(', ')} and{' '}
|
||||
{ROLE.litigationAreas.at(-1)}. I mediate commercial disputes and I
|
||||
accept arbitration appointments in commercial matters; the Q.Arb
|
||||
pathway commenced in August 2026. I also work as a machine-learning
|
||||
and infrastructure engineer.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* `widths` + `sizes` rather than `densities`, because the portrait is
|
||||
fluid and a density ladder would size it from one assumed CSS width.
|
||||
`width` and `height` are passed ALONGSIDE `widths` — without them Astro
|
||||
declares the untouched 1600px master as the <img src> fallback, which
|
||||
is the defect `/`'s comment records at 254,626 bytes.
|
||||
|
||||
⚠️ THIS COMMENT PREVIOUSLY MADE FOUR CLAIMS AND THREE WERE MEASURABLY
|
||||
FALSE. Recorded rather than quietly replaced, because the false ones
|
||||
were the confident ones.
|
||||
|
||||
(a) "Same ladder as `/`'s hero and the same reasoning" — true, and
|
||||
that was the problem: `/`'s reasoning derived a 960 ceiling from
|
||||
the TWO-COLUMN layout, which only engages at 66rem. Below 66rem
|
||||
the hero is one column and the portrait is the full content
|
||||
width. Measured: 592px at a 640 viewport, 672 at 768, 804 at 900,
|
||||
928 at 1024 — needing 1184-1856 device px at DPR 2 against a 960
|
||||
ceiling. **1.40x upscale at 768/DPR2, 1.93x at 1024/DPR2**, on
|
||||
this page and on `/`. At 768/DPR1 a 760w file exists and is not
|
||||
chosen, so part of the loss was purely a wrong `sizes` (52vw
|
||||
declared against an ~88vw slot). Fixed two ways: `.hero-portrait`
|
||||
is capped at 30rem below 66rem so the widest real slot is 480 CSS
|
||||
px, which makes 960 exactly right for DPR 2; and a 1440 rung
|
||||
covers DPR 3, which the ≥66rem range had also been missing
|
||||
(429px x 3 = 1287 against 960).
|
||||
|
||||
AND THE 1440 RUNG OVERSHOT, SO 1080 EXISTS TO CORRECT IT. Adding 1440
|
||||
for DPR 3 removed a 1.07x upscale at 390/DPR3 and replaced it with a
|
||||
**48,799 B fetch where the old one was 21,526 B** — +27 KB on a phone,
|
||||
to fix a 7% softness nobody can see. A browser takes the smallest
|
||||
candidate at or above what it needs, and with no rung between 960 and
|
||||
1440 the only choices were "slightly soft" or "+27 KB". 1080 makes
|
||||
1026 (390 x DPR 3) exact and cheap. This was a defect in the fix for
|
||||
the defect above, found by measuring the fix rather than the source.
|
||||
|
||||
AND 1080 ALONE MISSED THE TWO LARGEST CURRENT PHONES, WHICH
|
||||
MAKES THIS THE THIRD ITERATION OF THIS LADDER. 1080 was tuned to
|
||||
390 CSS px x DPR 3 (= 1026), and `sizes` resolves to
|
||||
`calc(100vw - 3rem)` up to 528px, so every phone wider than 390
|
||||
overshoots to the next rung: iPhone 14 Plus (428@3, needs 1140)
|
||||
and 15/16 Pro Max (430@3, needs 1146) both took **1440 —
|
||||
48,799 B**, against 27,594 for the device the rung was tuned
|
||||
for. +21,205 B, 13% of page weight. A 1200 rung closes it at
|
||||
1.05x. Measured after: no rung more than 1.06x oversized on the
|
||||
phone axis, and still no upscaling anywhere.
|
||||
(b) "The LCP element on this page is the <h1>" — **false.**
|
||||
`PerformanceObserver` at 1280x900: LCP element is
|
||||
`IMG.portrait-img`, size 229,679; the <h1> box is 51,484, 4.5x
|
||||
smaller. So the portrait IS the LCP element at desktop widths.
|
||||
(c) "two words of 96px serif" — **false.** `.hero-h` sets
|
||||
`--text-5xl`, which computes to **76px**. 96px is `--text-6xl`,
|
||||
which is what `/` uses.
|
||||
(d) "above the fold at every width" — **false.** Portrait top vs
|
||||
viewport height: 782 vs 568 at 320, 752 vs 640 at 360 — entirely
|
||||
below the fold at both, i.e. **0 visible px** at the two widths
|
||||
`docs/02` names explicitly. 120px visible at 390x844.
|
||||
|
||||
SO WHY IS IT STILL `eager` AND NOT `fetchpriority="high"`? Because (b)
|
||||
and (d) pull in opposite directions and the split is real. Re-measured
|
||||
AFTER the cap, since the cap changes the element's size and therefore
|
||||
the LCP candidate (`PerformanceObserver`, cache cleared per sample):
|
||||
|
||||
390x844 LCP = P.hero-lede 93,411
|
||||
768x1024 LCP = IMG.portrait-img 168,161
|
||||
1280x900 LCP = IMG.portrait-img 229,679
|
||||
|
||||
So the portrait is the LCP element from **768px up** — not "~1056px
|
||||
up", which is what this comment said before the cap was measured — and
|
||||
at phone widths LCP is the hero lede, a font-dependent text paint the
|
||||
preloaded Geist already covers. `loading` and `fetchpriority` cannot be
|
||||
conditioned on viewport. `eager` serves the tablet-and-desktop LCP;
|
||||
`fetchpriority="high"` is withheld because at 320-360, where the image
|
||||
is entirely off-screen, it would outrank that text paint. For
|
||||
reference, `/` differs at 768 (LCP = H1.display, 135,289) because its
|
||||
headline is a four-line sentence rather than a two-word name. */
|
||||
}
|
||||
<div class="hero-portrait">
|
||||
<Picture
|
||||
src={portrait}
|
||||
width={960}
|
||||
height={960}
|
||||
widths={[380, 480, 640, 760, 960, 1080, 1200, 1440]}
|
||||
sizes="(min-width: 80rem) 429px, (min-width: 66rem) 33vw, (min-width: 33rem) 480px, calc(100vw - 3rem)"
|
||||
formats={['avif', 'webp']}
|
||||
fallbackFormat="jpeg"
|
||||
alt={PORTRAIT.alt}
|
||||
loading="eager"
|
||||
decoding="sync"
|
||||
class="portrait-img"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 2. Narrative biography ---------------------------------------- */}
|
||||
<section class="section bio reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading eyebrow="Background" level={2}>
|
||||
<span slot="heading">Two directions, one file.</span>
|
||||
</SectionHeading>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* 400–600 WORDS, docs/03: "Tell the three tracks as one arc, not three
|
||||
lists." Measured, not estimated — see the word-count assertion in the
|
||||
verify step of this session's Change Log entry.
|
||||
|
||||
Q41(a) IS APPLIED THROUGHOUT AND THIS IS THE FIRST PAGE WRITTEN UNDER
|
||||
IT. Pouya's ruling, 2026-08-27: the implication test reaches prose, and
|
||||
prose is held to a HIGHER bar — "state the asymmetry explicitly rather
|
||||
than relying on a parallel construction to carry it." So the fourth
|
||||
paragraph names which half is training and which is work, in as many
|
||||
words. Avoiding the noun pair "law and engineering" is not sufficient
|
||||
on its own: a reader can supply the missing symmetry from silence, and
|
||||
for the legal half the missing half is a licence.
|
||||
|
||||
EVERY CLAIM TRACES TO §4 Verified: the JD, the boutique role, active
|
||||
litigation exposure and its four matter types, Q.Med, multiple
|
||||
completed sole mediations, arbitration appointments (§4 Offerings,
|
||||
scoped to commercial), the Q.Arb pathway commenced August 2026,
|
||||
C.Med-Arb as the goal, engineering practice, SML Company Ltd, Farsi,
|
||||
Iranian-Canadian. Nothing here asserts or implies licensure. */
|
||||
}
|
||||
<div class="prose bio-prose">
|
||||
<p>
|
||||
I came to dispute resolution from two directions, and I still work in
|
||||
both.
|
||||
</p>
|
||||
<p>
|
||||
The first is law. I hold a JD from Bond University, and I am{' '}
|
||||
{ROLE.title} at {ROLE.at}. That role gives me {ROLE.litigationLine} — personal
|
||||
injury, construction, regulatory matters under the Provincial Offences Act,
|
||||
and accident benefits under the SABS. What that exposure is actually worth
|
||||
in a mediation is unglamorous: I have seen how these files get built. Which
|
||||
productions turn out to be thin. Where expert reports talk past each other
|
||||
rather than disagree. Which issues resolve once someone puts the documents
|
||||
in order, and which ones never will.
|
||||
</p>
|
||||
<p>
|
||||
The second is engineering. I work as a machine-learning and
|
||||
infrastructure engineer. That is current practice, not a former career
|
||||
and not an interest: I read code, model documentation, deployment
|
||||
topology, and the operational records that show what a system did
|
||||
rather than what a specification said it would do.
|
||||
</p>
|
||||
{
|
||||
/* FROM A CONSTANT — ASYMMETRY_LINE in src/data/site.ts. It was typed
|
||||
here and separately on `/`, and the two copies had already diverged
|
||||
(full stops here, a comma there) inside the session that wrote both.
|
||||
Q41(a) makes this the sentence responsible for foreclosing the
|
||||
licence implication, so it is the worst string on the site to let
|
||||
drift. */
|
||||
}
|
||||
<p>{ASYMMETRY_LINE}</p>
|
||||
<p>
|
||||
Mediation is where they meet. I hold the Q.Med designation through the
|
||||
ADR Institute of Canada and the ADR Institute of Ontario, and I have
|
||||
completed multiple sole mediations. I accept arbitration appointments
|
||||
in commercial matters — as sole arbitrator, as a party-appointed
|
||||
arbitrator, and in co-arbitration. Where a matter turns on a technical
|
||||
question, I read the technical material myself.
|
||||
</p>
|
||||
<p>
|
||||
My Q.Arb pathway commenced in August 2026, and C.Med-Arb is the
|
||||
designation I am working toward. I state the stage openly because an
|
||||
appointing body will establish it anyway, and because a reader can do
|
||||
more with the fact than with a hedge. I would rather say where I am on
|
||||
the arc than leave it to be inferred.
|
||||
</p>
|
||||
{
|
||||
/* BOTH ADDITIONS TO THIS SENTENCE CAME BACK OUT. §4 verifies exactly
|
||||
one relation — *"Operator of SML Company Ltd. alongside the
|
||||
practice"* — and that is now all it says.
|
||||
|
||||
"It is not a law firm and does not hold itself out as one" — a
|
||||
negative REGULATORY statement with no row, attached to the one
|
||||
§4 row carrying an express caution against being read together
|
||||
with the licence row *"into an implication that neither row
|
||||
makes."* Added to be helpful; it touches exactly what §4 says
|
||||
not to touch.
|
||||
"the company through which the engineering work is done" — a
|
||||
corporate-structure claim. §4 verifies operation alongside the
|
||||
practice, the jurisdiction of incorporation and the place of
|
||||
business — not which work runs through which vehicle. */
|
||||
}
|
||||
<p>I run SML Company Ltd alongside both.</p>
|
||||
<p>
|
||||
I have also completed the Kompass Arbitration Certificate Program and
|
||||
the Stitt Feld Handy negotiation and ADR workshop sequence. Neither is
|
||||
a designation, and I name them precisely for that reason: process
|
||||
training is the easiest thing in this field to assert loosely, so it
|
||||
is worth stating exactly what it was.
|
||||
</p>
|
||||
{
|
||||
/* THE NEUTRALITY LINE. It is a disclaimer and it earns its place:
|
||||
docs/03 requires the equivalent on `/for-parties/`, and this is the
|
||||
page an appointing body reads. It also states the negative of the
|
||||
implication §4 Forbidden bars — "acts for clients", "represents
|
||||
parties" — which is a stronger position than merely never asserting
|
||||
it. Q42's reasoning is the same reasoning: Pouya struck settlement
|
||||
counsel because a partisan role "undercuts the brand's central
|
||||
claim". This sentence is that claim, stated.
|
||||
|
||||
The family-law exclusion is NOT here. Pouya scoped it to
|
||||
`/practice/shareholder/` — "One sentence, not a section" — and
|
||||
widening it to this page is his call, not an implementer's. */
|
||||
}
|
||||
{
|
||||
/* THIS SENTENCE HAS NOW BEEN WRONG IN BOTH DIRECTIONS, WHICH IS WHY
|
||||
THE THIRD VERSION AVOIDS THE AXIS ALTOGETHER.
|
||||
|
||||
"I do not give legal advice" — flagged because "do not" describes
|
||||
an ELECTION, and an election implies the entitlement to choose.
|
||||
"I cannot give legal advice" — flagged on the next pass because
|
||||
"cannot" is a DENIAL of entitlement, and §4 on licence status
|
||||
is explicit: *"Do not assert it, do not deny it, do not infer
|
||||
it from anything else here."*
|
||||
|
||||
Both readings are correct and they point in opposite directions,
|
||||
because both sentences make a claim about CAPACITY. So this one does
|
||||
not: it states the ROLE and its consequence for the reader, which is
|
||||
the form `docs/03` actually sanctions on `/for-parties/` (*"the
|
||||
mediator is not your lawyer"* — role, not capacity) and the only one
|
||||
that asserts nothing and denies nothing. The underlying question is
|
||||
R1's. */
|
||||
}
|
||||
<p>
|
||||
I act as a neutral. I do not act for a party in a matter I take, and
|
||||
each party should have their own legal advice.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 4. The credentialing arc -------------------------------------- */}
|
||||
{
|
||||
/* SECTION 4 BEFORE SECTION 3, and the reorder is deliberate. docs/01 lists
|
||||
credentials (item 3) then the arc (item 4). The arc is the part a reader
|
||||
is likely to have a question about — it is the thing this practice is
|
||||
candid about that others are not — and burying it under a scannable list
|
||||
of things already held reads as a footnote to them. §4's paired-disclosure
|
||||
condition also wants the stage stated where the offering is made, and the
|
||||
offering is made in the narrative directly above. The list follows. */
|
||||
}
|
||||
<section class="section section-inverse arc-section reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading
|
||||
eyebrow="The arc"
|
||||
level={2}
|
||||
lede="Three designations. Two of them are ahead of me, and saying so is the point."
|
||||
>
|
||||
<span slot="heading">Where the credentials sit.</span>
|
||||
</SectionHeading>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* `role="list"` RESTORED, AND THE REASON I REMOVED IT WAS WRONG ABOUT
|
||||
ARIA. The comment here claimed that on an <ol> the role "re-announces
|
||||
an ordered list as an unordered one". It does not: **both <ul> and <ol>
|
||||
map to the `list` role**, so `role="list"` on an <ol> is a no-op for
|
||||
ordering, not a downgrade. What it is actually for is the WebKit
|
||||
heuristic that strips list semantics from a list with
|
||||
`list-style-type: none` — and `.arc` sets exactly that.
|
||||
|
||||
It also left the two <ol>s on this two-page site DISAGREEING, with
|
||||
`/`'s `.process-strip` keeping the role. That is the state that gets
|
||||
copied seventeen times.
|
||||
|
||||
Not verified here: whether WebKit's heuristic covers <ol> as well as
|
||||
<ul>. There is no Safari instrument in this environment, so the role
|
||||
stays on the precautionary side, which costs nothing. Chrome's AX tree
|
||||
exposes `.arc` as `list` with three `listitem` children either way. */
|
||||
}
|
||||
<ol class="arc" role="list">
|
||||
{
|
||||
ARC.map((stage) => (
|
||||
<li class="arc-item">
|
||||
<h3 class="arc-name">{stage.name}</h3>
|
||||
<p class="arc-state">
|
||||
<Pill>{stage.state}</Pill>
|
||||
</p>
|
||||
<p class="arc-body">{stage.body}</p>
|
||||
</li>
|
||||
))
|
||||
}
|
||||
</ol>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 3. Credentials, structured ------------------------------------ */}
|
||||
<section class="section section-alt creds reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading eyebrow="Credentials" level={2}>
|
||||
<span slot="heading">The verifiable record.</span>
|
||||
</SectionHeading>
|
||||
</div>
|
||||
|
||||
<div class="cred-grid">
|
||||
{
|
||||
CREDENTIAL_GROUPS.map((group) => (
|
||||
<div class="cred-group">
|
||||
<h3 class="cred-title">{group.title}</h3>
|
||||
<ul class="cred-items" role="list">
|
||||
{group.items.map((item) => (
|
||||
<li>{item}</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
|
||||
{
|
||||
/* THIS NOTE IS GONE, AND IT CARRIED THREE SEPARATE DEFECTS. It read:
|
||||
"Memberships are renewed annually and are listed as current. Nothing
|
||||
above asserts a licence to practise law, in either direction."
|
||||
|
||||
(a) "renewed annually" WIDENED §4, which records yearly renewal for
|
||||
the OBA sections and the CTF only and says nothing about ADRIC
|
||||
or ADRIO. The widened form had already propagated to four places.
|
||||
(b) "listed as current" was an affirmative public WARRANTY of
|
||||
currency stacked on top of an undischarged R10 — the reminder
|
||||
whose entire purpose is that no such warranty be made without a
|
||||
re-confirmation. The memberships group is now off the page
|
||||
(Q44), so the sentence has nothing left to warrant either.
|
||||
(c) "Nothing above asserts a licence to practise law, in either
|
||||
direction" READS AS A DENIAL. §4 on licence status: "Do not
|
||||
assert it, do not deny it, do not infer it from anything else
|
||||
here." It was also the only sentence on the site that raised
|
||||
licensure at all, on the page where R1 says the D13 framing is
|
||||
already doing its heaviest work — and no spec asked for it.
|
||||
|
||||
Both review agents flagged (c) independently and escalated it to
|
||||
Pouya rather than rewriting it. That is the right destination: R1. */
|
||||
}
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- 5. Language and cross-cultural practice ----------------------- */}
|
||||
<section class="section language reveal">
|
||||
<div class="wrap">
|
||||
<div class="section-head">
|
||||
<SectionHeading eyebrow="Language" level={2}>
|
||||
<span slot="heading">English and Farsi, without an interpreter.</span>
|
||||
</SectionHeading>
|
||||
</div>
|
||||
|
||||
{
|
||||
/* §4 verifies "Bilingual English and Farsi" and "Iranian-Canadian;
|
||||
cross-cultural fluency with diaspora business communities".
|
||||
|
||||
NO QUANTITY AND NO COMPARATIVE. An earlier draft opened "many of the
|
||||
disputes I am best placed to take", which carries a count I do not
|
||||
have and the token "best" — which §4 Forbidden bars as a superlative
|
||||
and which a forbidden-terms sweep would flag on sight. Rewritten to a
|
||||
claim about the work: some disputes are not separable from the
|
||||
relationship, and this is what working in the parties' own language
|
||||
changes. Nothing about other neutrals — Q41(b). */
|
||||
}
|
||||
<div class="prose">
|
||||
<p>
|
||||
I mediate in English and in Farsi. I am Iranian-Canadian, and some
|
||||
commercial disputes are not separable from the relationship between
|
||||
the parties — family-held companies and diaspora businesses in
|
||||
particular, where the commercial disagreement and a much longer
|
||||
history arrive together.
|
||||
</p>
|
||||
<p>
|
||||
Working in the parties' own language, with no interpreter in the room,
|
||||
changes what gets said and how early it gets said. It removes a layer
|
||||
between a party and their own account of events.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* ---- Contact band --------------------------------------------------- */}
|
||||
<ContactBand />
|
||||
</BaseLayout>
|
||||
|
||||
<style>
|
||||
/* --- 1. Hero -------------------------------------------------------- */
|
||||
|
||||
.hero {
|
||||
padding-block: var(--space-8) var(--space-9);
|
||||
}
|
||||
.hero-inner {
|
||||
display: grid;
|
||||
gap: var(--space-7);
|
||||
align-items: center;
|
||||
}
|
||||
.hero-copy {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-5);
|
||||
}
|
||||
.hero-h {
|
||||
/* --text-5xl, not --text-6xl. `/`'s headline is a sentence and needs the
|
||||
display ceiling; this is a two-word name, and at 96px it sets 15
|
||||
characters across a line that then has nothing to balance against. */
|
||||
font-size: var(--text-5xl);
|
||||
/* `anywhere`, NOT `break-word`. The type scale is rem-based, so at a 200%
|
||||
DEFAULT FONT SIZE this heading computes to 88px and "Lajevardi" — one
|
||||
unbreakable 9-character word — is wider than the 224px content box at a
|
||||
320px viewport. `break-word` permits a break at layout time but does NOT
|
||||
reduce min-content size, so it would not have helped; `anywhere` does.
|
||||
It has no effect at any normal size: a word only breaks when it cannot
|
||||
fit. Breaking a name mid-word is ugly and it is better than a reader at
|
||||
200% zoom losing the page. WCAG 1.4.4 / 1.4.10. */
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
.designation {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
/* THE GAP CARRIES THE SEPARATOR'S SPACING, not a margin on .sep. The
|
||||
separator is aria-hidden, so its box must not be what a sighted reader
|
||||
depends on for rhythm while a screen-reader user gets nothing — with
|
||||
`gap` the spacing survives the element being ignored. */
|
||||
gap: var(--space-1) var(--space-3);
|
||||
align-items: baseline;
|
||||
font-family: var(--font-mono);
|
||||
font-size: var(--text-sm);
|
||||
letter-spacing: var(--tracking-tight);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
/* NO `white-space: nowrap` — IT WAS HERE AND IT BROKE REFLOW. Gluing the whole
|
||||
item together made "Q.Med (ADRIC / ADRIO)" unbreakable, and at a 200%
|
||||
DEFAULT FONT SIZE that pushed this page to 108px of overflow at 320px
|
||||
against `/`'s accepted 63. The separator does not need the whole item to be
|
||||
unbreakable — it only needs to stay attached to the FIRST word, which the
|
||||
non-breaking space in the markup does. WCAG 1.4.10. */
|
||||
.designation-part {
|
||||
display: inline;
|
||||
}
|
||||
.designation .sep {
|
||||
/* NOT `var(--rule)`. Gold `#c9a876` on cream measures **2.10:1** — the one
|
||||
hard constraint in `docs/02` and `tokens.css`, which say in terms that
|
||||
gold is never a text colour on cream. An in-browser audit of all 100
|
||||
text-bearing elements on this page returned exactly two failures and both
|
||||
were this span. `aria-hidden` does not dispose of it: these separators are
|
||||
the only thing dividing three credential items, and at 2.10:1 they are
|
||||
invisible, so the line reads as a run-on. That is a legibility failure
|
||||
before it is a rule breach. `--text-meta` measures 5.47:1 on cream and
|
||||
still recedes from the 11.75:1 text beside it. */
|
||||
color: var(--text-meta);
|
||||
}
|
||||
.hero-lede {
|
||||
max-inline-size: var(--width-prose);
|
||||
font-size: var(--text-lg);
|
||||
line-height: var(--leading-relaxed);
|
||||
color: var(--text-secondary);
|
||||
}
|
||||
/* `<Picture>` emits an <img> wrapped in a <picture>, and the <picture> is the
|
||||
box the grid sizes — the `class` prop lands on the <img>, which is the
|
||||
defect InfinityMark.astro records for its own flex sizing.
|
||||
|
||||
THIS COMMENT CLAIMED "the <picture> WRAPPER carries no cid, so it needs
|
||||
`:global()`". **That is false.** Read from the built HTML: the emitted markup
|
||||
is `<picture data-astro-cid-ta2fbyqs="true">` — Astro DOES propagate the
|
||||
page's scope attribute to both elements for `astro:assets` components (it
|
||||
does not for ordinary user components, which is the real rule CLAUDE.md
|
||||
records). Decisive corroboration in the shipped CSS: InfinityMark's BARE
|
||||
`picture` selector compiles to `picture[data-astro-cid-usztftas]` and
|
||||
demonstrably works. So `:global()` was unnecessary and merely broader than
|
||||
intended — it would also have matched a <picture> inside any child
|
||||
component placed here. Plain selector, correct comment.
|
||||
|
||||
4/5 rather than 1/1 — the master is square, and 4/5 is the crop `/` uses.
|
||||
One portrait treatment across the site rather than two. */
|
||||
.hero-portrait {
|
||||
aspect-ratio: 4 / 5;
|
||||
overflow: hidden;
|
||||
border-radius: var(--radius-lg);
|
||||
background: var(--bg-raised);
|
||||
/* THE CAP IS THE UPSCALE FIX, not a style preference — see the <Picture>
|
||||
comment. Uncapped, this slot ran to 928 CSS px at a 1024px viewport, which
|
||||
is 1856 device px at DPR 2 against a 960w ceiling. `margin-inline: auto`
|
||||
because a 480px box in a 928px column would otherwise sit hard against
|
||||
the inline start. */
|
||||
max-inline-size: 30rem;
|
||||
margin-inline: auto;
|
||||
}
|
||||
.hero-portrait picture {
|
||||
display: block;
|
||||
block-size: 100%;
|
||||
}
|
||||
.portrait-img {
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
object-fit: cover;
|
||||
/* Above centre: the head sits in the upper half of a square crop. */
|
||||
object-position: 50% 22%;
|
||||
}
|
||||
|
||||
@media (min-width: 66rem) {
|
||||
.hero-portrait {
|
||||
/* Released above 66rem: the grid track is already 390-476px, so the cap
|
||||
is inert — and leaving it in place would silently become the constraint
|
||||
if the track ever widened. The track governs here, not this number. */
|
||||
max-inline-size: none;
|
||||
}
|
||||
.hero-inner {
|
||||
/* 1fr / 0.62fr — the portrait is smaller than `/`'s 0.72 because this
|
||||
hero's copy block is a name plus two short lines and the picture would
|
||||
otherwise dominate a page whose subject is the text. */
|
||||
grid-template-columns: 1fr 0.62fr;
|
||||
gap: var(--space-8);
|
||||
}
|
||||
}
|
||||
|
||||
/* --- 2. Background --------------------------------------------------- */
|
||||
|
||||
/* NO `.section-head` RULE — it moved to `global.css`, where `.prose` lives.
|
||||
It was byte-identical in both pages, and every one of the seventeen
|
||||
remaining pages needs it for the same reason (a parent cannot style a child
|
||||
component's root, so the wrapper must be page-owned). */
|
||||
/* NO `> p + p` RULE HERE. It was the only paragraph-spacing rule in this
|
||||
file and it is now redundant: global.css owns `.prose` paragraph spacing as
|
||||
of 2026-08-28, which is what stopped §Language below from rendering its two
|
||||
paragraphs as one block. Two rules setting the same property to the same
|
||||
value is one rule that will eventually disagree. */
|
||||
.bio-prose {
|
||||
font-size: var(--text-lg);
|
||||
line-height: var(--leading-relaxed);
|
||||
}
|
||||
/* NO `.bio-prose i` RULE. It styled a statute-name italic that the bio no
|
||||
longer uses: `Geist` ships NO italic face (every Geist `@font-face` is
|
||||
`font-style: normal`), so the `<i>` rendered as SYNTHETIC OBLIQUE, and the
|
||||
serif italic that would have set it properly is no longer preloaded on this
|
||||
page. "Provincial Offences Act" is set in roman. If a statute name ever
|
||||
needs italics here, load a face for it first. */
|
||||
|
||||
/* --- 4. The arc ------------------------------------------------------ */
|
||||
|
||||
.arc {
|
||||
display: grid;
|
||||
/* `min(18rem, 100%)` rather than a bare 18rem floor: a bare floor cannot
|
||||
shrink below itself and overflows at a large default font size. The
|
||||
credential row on `/` is the measured instance of that mistake. */
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(18rem, 100%), 1fr));
|
||||
gap: var(--space-6);
|
||||
/* NO `padding: 0` OR `list-style: none` HERE — `global.css`'s
|
||||
`ul[role='list'], ol[role='list']` reset already supplies both, and this
|
||||
block was re-implementing it by hand. Two rules for one job, and the
|
||||
hand-written copy is the one that drifts. `margin: 0` also comes from the
|
||||
global `* { margin: 0 }` reset. */
|
||||
}
|
||||
.arc-item {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
padding-block-start: var(--space-4);
|
||||
border-block-start: 1px solid var(--line-dark);
|
||||
}
|
||||
/* <h3>, not <p>. These are the headings of the three arc items and they set
|
||||
at --text-2xl serif, so marking them up as paragraphs was the fake-heading
|
||||
pattern: a screen-reader user got no heading navigation for the one section
|
||||
on this page a reader is most likely to jump to. `ProcessStep` on `/` uses
|
||||
<h3> for exactly this shape. Outline stays h1 -> h2 -> h3 with no skips. */
|
||||
.arc-name {
|
||||
font-family: var(--font-serif);
|
||||
font-size: var(--text-2xl);
|
||||
line-height: var(--leading-tight);
|
||||
}
|
||||
.arc-state {
|
||||
margin: 0;
|
||||
}
|
||||
.arc-body {
|
||||
margin: 0;
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-body);
|
||||
/* NOT --text-secondary. On an inverse ground `--ink-soft` measures ~1.4:1
|
||||
against `--ink` — the inherited `--text-inverse` (cream, 16.81:1) is what
|
||||
carries body copy here, so the colour is deliberately left alone rather
|
||||
than set to a token that is correct only on cream. */
|
||||
}
|
||||
|
||||
/* --- 3. Credentials -------------------------------------------------- */
|
||||
|
||||
.cred-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
|
||||
gap: var(--space-7) var(--space-6);
|
||||
}
|
||||
/* THESE ARE HEADINGS AND THEY WERE DRESSED AS EYEBROWS. The previous rule set
|
||||
11px / Geist Mono / 0.18em / uppercase / --text-meta, which is `docs/02`'s
|
||||
eyebrow specification exactly — and `docs/02` says in terms: "An eyebrow is
|
||||
not a heading and never carries the <h*>." `Eyebrow.astro` restates it.
|
||||
|
||||
The measurable consequence was worse than the rule breach: at 11px these
|
||||
<h3>s were SMALLER than the 12px eyebrow above them and 5px smaller than
|
||||
the 16px list items they head, so "MEMBERSHIPS" was the least legible text
|
||||
on the page an appointing body reads.
|
||||
|
||||
Resolved by keeping the <h3> — these genuinely are the headings for their
|
||||
lists, and the heading navigation is worth more than the styling — and
|
||||
dropping the eyebrow treatment. The gold rule stays: gold is sanctioned for
|
||||
dividers, and a 1px border is not text. */
|
||||
.cred-title {
|
||||
font-size: var(--text-base);
|
||||
font-weight: var(--weight-medium);
|
||||
letter-spacing: var(--tracking-tight);
|
||||
color: var(--text-secondary);
|
||||
padding-block-end: var(--space-3);
|
||||
border-block-end: 1px solid var(--rule);
|
||||
}
|
||||
.cred-items {
|
||||
margin: var(--space-4) 0 0;
|
||||
padding: 0;
|
||||
list-style: none;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--space-3);
|
||||
font-size: var(--text-base);
|
||||
line-height: var(--leading-snug);
|
||||
}
|
||||
/* NO `.cred-note` RULE. The note it styled was removed — three defects in one
|
||||
sentence, recorded in the markup above — and the rule went with it rather
|
||||
than shipping as dead CSS to every visitor. Noted so the next reader does
|
||||
not re-add a note to fill a rule that no longer exists. */
|
||||
|
||||
/* NO CONTACT-BAND RULES HERE. `.contact-inner`, `.contact-h`, `.contact-body`
|
||||
and `.contact-action` moved to `ContactBand.astro` with the markup they
|
||||
style. They were left behind after the extraction — dead CSS shipping to
|
||||
every visitor, and worse, the **46ch / 52ch divergence the extraction
|
||||
existed to end was still sitting on disk in both pages**, so the next reader
|
||||
would have found two different values and no rendered difference. Deleted
|
||||
2026-08-28. */
|
||||
</style>
|
||||
Reference in New Issue
Block a user