Files
adr-sml/src/pages/about.astro
T
Pouya LajevardiandClaude Opus 5 210bc25a26 feat: build steps 7a-10 — the site is complete and reviewable at 22 pages
Steps 7a through 10 as one authorised run. Nothing deployed (D11).

7a  Lighthouse returns as `lighthouse@13.4.1` + `chrome-launcher`, NOT
    `@lhci/cli`. AGENTS.md §7's advisory attribution was wrong: the carriers
    were @lhci/cli's own `tmp` and @puppeteer/browsers' `extract-zip`, not
    Lighthouse, which audits clean. A deliberate deviation from R11's literal
    trigger, recorded with what it costs. Local gate; CI has no Chrome.

7b  OG card generator (satori + sharp) discharges R15 — 20 typed cards plus
    per-article cards; the portrait stays on / and /about/ by Q40. Insights
    plumbing: ArticleCard, Prose, the index, the article route, articleGraph,
    and /'s section 7. Card copy is constrained structurally because text in a
    JPEG cannot be grepped by check:claims: every headline IS its page's <h1>,
    enforced by `npm run og:proof`.

7c  Five drafted launch articles, draft: true / reviewedByPouya: false. An
    independent compliance audit returned 76 findings and 57 unsourced
    assertions; all blocking and should-fix applied.

8   /contact/, the intake form, and backend/intake/ (undeployed). Plain HTML
    POST to a same-origin /api/intake with a 303 redirect, so the form works
    with zero JavaScript. docs/05 records three deliberate deviations.

9   /fees/ on Q59's ruling — overtime runs from the session cap, and the
    reservation point ships adjacent to the rate. One-page PDF bio discharges
    R16; /bio/ is its source, so the circulated artefact stays inside the
    review apparatus.

10  /legal/privacy/ and /legal/terms/, written to the backend as built. Three
    of the policy's statements are derived and cannot drift.

Also: /about/'s inverse credentials band (approved at step 6); Q59 closed;
R15 and R16 discharged; and a fix to shipped copy — /practice/energy/ asserted
the absence of a regulation the source extract says must not be asserted.

Review: adversarial-reviewer, two rounds (D20/D19). Round 1 returned 16
findings including two blocking — an invisible ghost button on /fees/ at
1.00:1 that Lighthouse scored 100, and a privacy policy that named one data
processor when there are two. All 16 acted on.

Lighthouse, 22 pages, mobile: performance 99-100, accessibility 100,
best practices 100, SEO 100 on every indexable page, CLS 0.000.

AGENTS.md entry (ah) has the detail, including four of my own verification
commands that were wrong and what each of them nearly caused.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Md3GndFqWPzK78xAoebsg5
2026-08-31 10:56:54 -04:00

956 lines
48 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
/**
* `/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 → REMOVED 2026-08-29, see below
* 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 4 IS GONE, AND IT WAS DELETED RATHER THAN REWRITTEN. Pouya, 2026-08-29:
* *"Two held designations, no journey… An arc invites 'where are you on it';
* two designations don't."* Q.Arb is held and C.Med-Arb is off the site
* entirely, so the section had no subject left — three pills reading Held,
* Held, and nothing. What it used to carry now sits in item 3, which is a list
* of held things and was always the right shape for it. **Do not restore it
* from docs/01's seven-item outline**; that item is struck there too.
*
* 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.
* **Q45 CLOSED 2026-08-28 — deferred by Pouya to build step 9, alongside
* `/fees/`, and tracked as AGENTS.md §12 R16.** His reasoning: it is a derived
* artefact, so building it before this page and the fee card are final means
* building it twice. No such file exists yet, 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 travel with R16 and are NOT settled by the
* deferral — generated-at-build vs authored once, and whether it carries
* anything the site does not.
*
* This paragraph also comes out at step 9 (R16), which now lists this file.
* *(It pointed at Q45 after Q45 closed; `adversarial-reviewer` found that
* `grep -rn R16 src` returned nothing at all.)*
*
* 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 SHIPS, AND IT CARRIES NO CURRENCY
* WARRANTY. Q44 closed 2026-08-28: Pouya re-confirmed all four as current, so
* R10's prohibition is discharged and the group renders. Two conditions came
* with that ruling and both are load-bearing on this page:
*
* 1. **Nothing here promises the memberships stay current.** The struck
* sentence ("Memberships are renewed annually and are listed as current")
* stays struck and nothing replaces it. His words: *"List the memberships;
* promise nothing about their future state."* The list is a snapshot, and
* only §4's stamp says when it was taken.
* 2. He declined renewal-date tracking, so **R10 no longer fires on a date —
* it fires on an event**: re-confirm before any cutover or major
* republish. That is why R10 stays live with the group shipped.
*
* The page held all three positions in three days — published-with-a-disclosure
* (rejected by both review agents), withheld-behind-a-TODO (correct while R10
* was undischarged), now published-with-no-warranty. The middle state was not a
* detour; it is what "a build that fails on an unanswered question is a correct
* build" looks like from the inside.
*/
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 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,
DESIGNATIONS_HELD_LINE,
PORTRAIT,
PRACTICE_AREAS,
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 BIOGRAPHY ENUMERATES THE PRACTICE AREAS IN PROSE, which means it is the
one place on the site that names them without rendering `PRACTICE_AREAS`.
Card labels ("Insurance, SABS & LAT") do not read as prose, and a joined list
of them in a paragraph was worse than the duplication. So the count is
asserted instead: add a seventh area and this throws, which is the prompt to
rewrite the sentence. Same mechanism as the ground-alternation check in
`practice/[slug].astro`. */
/* `: number`, NOT the inferred literal. `PRACTICE_AREAS` is `as const`, so
`.length` is the literal type `6`; with `AREAS_NAMED_IN_BIO` also literal `6`,
adding a seventh area makes the comparison `7 !== 6` — non-overlapping
literals — and `astro check` fails first with `ts(2367) This comparison
appears to be unintentional`, which reads like lint noise. Both deploy paths
run `npm run check` BEFORE the build, so the implementer would never see the
message below, and the message is the whole point of the guard. Widening the
left side keeps the comparison live at runtime. Measured by
`adversarial-reviewer` 2026-08-30. */
const AREAS_NAMED_IN_BIO: number = 6;
if (PRACTICE_AREAS.length !== AREAS_NAMED_IN_BIO) {
throw new Error(
`/about/'s biography names ${AREAS_NAMED_IN_BIO} practice areas in prose, ` +
`but PRACTICE_AREAS now has ${PRACTICE_AREAS.length}. Rewrite the ` +
`"I accept appointments in six areas" paragraph, then update this count.`,
);
}
/**
* The designation line — docs/01 item 1. Assembled from constants so it cannot
* drift from §4.
*
* BOTH DESIGNATIONS, because a designation line is a list of things held and
* as of 2026-08-29 Q.Arb is one of them. It was excluded while it was a stage.
* The issuing bodies repeat across the two entries; that is what the strings in
* `CREDENTIALS.designations` say, and spelling them once across a joined pair
* would be this file re-typing §4 rather than rendering it.
*/
const designationLine = [
'Mediator',
...CREDENTIALS.designations,
CREDENTIALS.education[0],
];
/**
* 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. **It is the precedent** —
* a membership lapsed quietly and the register now reads "not current, do
* not publish". Nothing told anyone when.
* - Any licence status, in either direction. §4 records it `[unestablished]`.
*
* ⚠️ MEMBERSHIPS RENDER, AND THE PAGE SAYS NOTHING ABOUT THEIR FUTURE STATE.
* That second clause is the whole ruling, so it is written here beside the
* array rather than in a change log nobody reads at edit time.
*
* **Q44 closed 2026-08-28.** Pouya re-confirmed all four as current — ADRIC,
* ADRIO, the three OBA sections, and the Canadian Tax Foundation — which
* discharges R10's prohibition and puts the group back on the page. §4 is
* re-stamped `[verified 2026-08-28 — Pouya]`.
*
* **DO NOT ADD A CURRENCY SENTENCE.** Not "renewed annually", not "current as
* of", not "listed as current", not a stamp date in the markup. His ruling is
* explicit: *"List the memberships; promise nothing about their future state.
* The list is a snapshot, and only §4's stamp says when it was taken."* The
* struck sentence is quoted in the comment further down this file with the
* three defects it carried; the second of those is now the live one.
*
* **WHY THE ABSENCE OF A WARRANTY IS THE HONEST FORM AND NOT AN EVASION.**
* Pouya declined renewal-date tracking. Without renewal months there is no date
* on which anyone could re-check, so any sentence asserting continued currency
* would be asserting something nothing in this repo can support — which is the
* OCNI shape exactly: §4 carries OCNI as lapsed and unpublishable, and that was
* found roughly a year late. R10 therefore fires on an **event** now (before any
* cutover or major republish), not on a date. That is recorded in §12 R10 with
* this reasoning attached, because a stamp with no trigger behind it goes stale
* silently.
*
* "Canadian Tax Foundation" ships WITHOUT a "(CTF)" abbreviation, unlike ADRIC
* and ADRIO. Pouya's ruling wrote "(CTF)" when listing what to confirm, but the
* abbreviation appears nowhere else on this site — ADRIC and ADRIO earn their
* parentheses because "Q.Med (ADRIC / ADRIO)" uses them in the Designations
* group two entries above. An unused abbreviation is noise, so it is omitted;
* one word to reverse if he wants it.
*
* `memberOf` IS EMITTED FROM THIS PAGE'S JSON-LD (Q53), AND FROM A DIFFERENT
* ARRAY. `src/data/schema.ts` builds it from `MEMBERSHIP_ORGS`, not from the
* `CREDENTIALS.memberships` this group renders: the graph names the bodies, the
* page also names the OBA's three sections. **Only their length is enforced, by
* a compile-time assertion — content parity is manual.** So editing this list
* means editing that one. They are the same §4 row seen twice.
*/
const CREDENTIAL_GROUPS = [
{ title: 'Designations', items: CREDENTIALS.designations },
{ title: 'Education', items: CREDENTIALS.education },
{ title: 'Certifications', items: CREDENTIALS.certifications },
{ title: 'Memberships', items: CREDENTIALS.memberships },
];
---
<BaseLayout
title="About · Pouya Lajevardi · Mediator, Q.Med, Q.Arb · Toronto"
description="Pouya Lajevardi, JD, Q.Med, Q.Arb — a Toronto mediator who also practises as a machine-learning and infrastructure engineer. Credentials and background."
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.
THE MEDIATION HALF CARRIES NO SCOPE, AND THE ASYMMETRY IS
DELIBERATE — Q56, ruled 2026-08-30. Arbitration is scoped commercial
because of a legal gate (Q39: family arbitration in Ontario requires
prescribed training). Mediation has no such gate and §4's row is
unscoped. Do not restore "commercial" to the mediation half to make
the two read as a pair. */
}
<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. I accept arbitration
appointments in commercial matters. 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), Q.Arb, 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>
{
/* A SECOND PARAGRAPH HERE WAS CANDOUR ABOUT AN INCOMPLETE CREDENTIAL
— "I would rather say where I am on the arc". Q.Arb is held; do not
write another. `check:claims` q-arb-as-a-stage catches the form. */
}
<p>
Mediation is where they meet. {DESIGNATIONS_HELD_LINE}, 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>
{
/* 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. */
}
{
/* §4 VERBATIM: "Operator of SML Company Ltd. **alongside the
practice**." This read "alongside both", where "both" resolved to the
law track and the engineering track — a concurrency claim §4 does not
make, flagged by `claims-auditor` 2026-08-28. Two neighbouring
additions were deleted from this section for the same reason (see
below), and the wording had propagated from docs/03, now corrected
too. NOT a corporate-structure claim either — see schema.ts on why
`worksFor` is withheld. */
}
<p>I run SML Company Ltd alongside the practice.</p>
{
/* ⚠️ NO SCOPE CLAIM AND NO COVERAGE CLAIM. §4 has no row for the
subject matter of his ADR work, and `/practice/insurance/` ships
"Disputes between an insured person and an insurer" — an
individual-versus-insurer SABS dispute is not commercial, so this
paragraph must not declare the six areas a commercial class.
What Q35 grants is the frame used here: an area may be named where
he can competently accept an appointment, framed as positioning
rather than claimed history. "I accept appointments in" is that
frame; "the subject matter runs across" is not, because §Background
is where a reader defaults to reading history. */
}
<p>
I accept appointments in six areas: construction and infrastructure;
technology, AI and data; energy and the grid; insurance and accident
benefits; shareholder and family-business disputes; and cross-border
matters. What those have in common is a record somebody has to read
closely, and a dispute that turns on what is actually in it.
</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, and it is
the only form that asserts nothing and denies nothing. The underlying
question is R1's.
AN EARLIER VERSION OF THIS COMMENT CITED `docs/03`'s
`/for-parties/` directive as the sanctioned example — *"the mediator
is not your lawyer" — role, not capacity*. That was wrong twice:
"not your lawyer" PRESUPPOSES lawyer status, which §4 Forbidden bars
of Pouya and D13 bars by implication; and the half of that sentence
this comment did not quote was "cannot give you legal advice", which
is the denial the comment itself says was struck twelve lines above.
`docs/03` has since been corrected. Do not re-import an example from
a spec without reading the whole sentence it sits in. */
}
<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>
{/* ---- 3b. The one-page PDF ------------------------------------------- */}
{
/* ✅ **R16 / Q45 DISCHARGED — build step 9.** `docs/01` §`/about/` item 7 has
carried a pending note since step 3: the PDF did not exist, and a link to a
file that does not exist is a broken link on the page an appointing body
reads. It exists now, it is committed, and this is the link.
**`/bio/` is the source and the PDF is a rendering of it** — so every line
of the document circulated with an appointment proposal is on a page that
`check:claims`, the adversarial review and the cutover claims pass all see.
That was R16's actual objection: *"a PDF circulated with an appointment
proposal is read once, by the reader who matters most, and never seen by a
reviewer again."*
It carries NOTHING the site does not — R16's second open sub-decision, and
the answer that avoids the §4 question it flagged. No matter list, no
referees, no figure that is not on `/fees/`. */
}
<section class="section bio-download reveal">
<div class="wrap">
<p class="download-line">
<a href="/pouya-lajevardi-bio.pdf" download>
Download a one-page PDF of this record
</a>
<span class="download-note">
— designations, education, memberships, the processes offered and the
rates, on one sheet. The same page is at <a href="/bio/">/bio/</a>.
</span>
</p>
</div>
</section>
{/* ---- 3. Credentials, structured ------------------------------------ */}
{
/* ⚠️ `section-inverse`, NOT `section-alt` — approved by Pouya at build step
6 and applied at step 7b. The arc section struck on 2026-08-29 was this
page's only dark band, so removing it left `/about/` with four cream
sections and the accent contact band, and the alternating rhythm
`docs/02` sets went with it.
Exactly ONE rule had to change — `.cred-title`. The measured ratios are on
that rule below, which is where a future editor changing a colour will be
looking. Everything else inherits cream from `.section-inverse`. */
}
<section class="section section-inverse 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. **THIS IS NOW THE OPERATIVE DEFECT.** Q44 closed and
the group is back on the page, so the sentence has something to
warrant again — and it still must not return. Pouya, 2026-08-28:
*"NO CURRENCY WARRANTY on the page. The sentence you struck
stays struck, and nothing may replace it."* He declined renewal
tracking, which is exactly why the warranty cannot be made:
there is no date behind it. R10 fires on an event instead.
(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. */
/* --- 3b. The one-page PDF ------------------------------------------- */
/* A quiet band between the bio and the credentials, not a call to action: the
reader an appointing body sends here is looking for the record, and a
download button styled like the contact CTA would compete with it. */
.bio-download {
padding-block: var(--space-7);
border-block: 1px solid var(--border);
}
.download-line {
max-inline-size: var(--width-prose);
font-size: var(--text-base);
line-height: var(--leading-body);
}
.download-note {
color: var(--text-secondary);
}
/* --- 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);
/* THE ONE COLOUR THAT HAD TO MOVE WITH THE BAND. This was
`--text-secondary`, which is `--ink-soft` — **1.43:1** on the ink ground
this section now has, i.e. worse than the gold-on-cream 2.10:1 this
project treats as the defect that must never ship. `--text-inverse-2` is
gold-l: 11.09:1 on ink (docs/02). The list items below inherit cream from
`.section-inverse` at 16.81:1 and are untouched.
The gold border is a 1px divider, which tokens.css sanctions gold for on
any ground, and gold on ink measures 8.00:1 regardless. */
color: var(--text-inverse-2);
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>