feat: build step 3 — /about/, minus its memberships; close Q40–Q43
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:
Pouya Lajevardi
2026-08-28 12:10:41 -04:00
co-authored by Claude Opus 5
parent 165d259f5c
commit c576b9a85f
17 changed files with 2603 additions and 147 deletions
+971
View File
@@ -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, 400600 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>
{
/* 400600 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>