/* AIREI — page CSS for the machine page (/ai-ffb-grading) and the proof document
   (/proof/minsawi-smart-mill). Extends base.css + shell.css; adds nothing they already carry.

   Two archetypes live here:
     · MACHINE PORTRAIT + PINNED SPEC STRIP  — .portrait · .specstrip · .frame · .outline · .flow
     · THE CIRCULATED DOCUMENT               — .doc · .facts · .mediawall · .pull

   House rules obeyed: radius stays at 2px (never a uniform 16) · green appears only inside a
   photograph, never in a painted panel · every accent is warm · motion only via .rev / [data-count]
   in motion.js · no gradient text, no glass, no glow. */

/* ── shared furniture ────────────────────────────────────────────────────────── */
.lede{font-size:clamp(18px,2vw,21px);line-height:1.55;color:var(--ink-muted);max-width:var(--measure)}
.paper .lede{color:#3D4B58}
.measure{max-width:var(--measure)}
h2{font-size:clamp(30px,4.4vw,54px)}
h3{font-size:clamp(19px,2.1vw,24px);letter-spacing:-0.0041em}
.sec-head{margin-bottom:clamp(30px,4vw,54px)}
.sec-head .eyebrow{margin-bottom:18px}
.sec-head h2{margin-bottom:18px}

.cta-row{display:flex;flex-wrap:wrap;gap:14px;margin-top:clamp(26px,3.4vw,40px)}

/* MEASURE. Mono at 11.5px with .04em tracking advances ~7.36px per character, so a note
   spanning a 1112px figure ran 151 characters per line — measured, at 1440px, on the scan
   exhibit, the MyPalm disclosures and the proof page. Comfortable body measure is 45-75 CPL
   and 90 is the outer limit for supporting text; DESIGN.md §7 licenses "mono all-caps
   eyebrows", not sixty-word paragraphs set to the full width of a photograph. 640px caps it
   at ~87 CPL, which leaves the notes that already sit inside .measure (686px) essentially
   where they were and only pulls in the full-bleed ones under figures.

   640 -> 620px, 2026-08-27, from the desktop type sweep. `.note` is the most repeated text
   component on the site: at 1280/1440/1920 it measured 82.1ch on 40+ blocks across TWELVE
   pages — ai-ffb-grading, mypalm, traceability, minsawi-smart-mill, company, careers and
   their five Malay twins — every one of them a hair over the 80ch ceiling, and it was by
   far the most repeated breach found. The cause is arithmetic, not judgement: 640px at
   13px Geist Mono is 640/7.8 = 82.05ch. 620px is 79.5ch, and with .04em tracking 74.5
   characters to a line — inside BOTH the 80ch ceiling and the 45-75 CPL band this comment
   already set. A 20px change, and it clears 40+ blocks at once. */
.note{font-family:var(--f-mono);font-size:13px;line-height:1.7;letter-spacing:.04em;
  color:var(--ink-subtle);max-width:620px}
.note a{color:var(--ink-muted);border-bottom:1px solid var(--hairline-strong)}
.paper .note{color:#6B7885}
.paper .note a{color:#3D4B58;border-bottom-color:rgba(22,32,43,.28)}

/* the source line — the single most load-bearing component on either page */
/* SENTENCE CASE, NOT A LABEL. Flipped 2026-08-27. This site already keeps two mono
   registers and `.note` (proof.css) is the second one: mono, small, muted, and set in
   sentence case at .04em because it carries PROSE. These classes had fallen on the label
   side of that line while carrying sentences — measured across the 25 pages, 86 rendered
   runs of 55 characters or more were set in tracked uppercase, the longest 407 characters,
   and they are the source lines, the section notes and the captions, i.e. the most
   load-bearing text on the page. All-caps removes word shape, which is the cue a reader
   actually uses, and it also destroys capitalisation that MEANS something here: proper
   nouns, mastheads, people's names, and product names AIREI itself capitalises. The mono
   face, the size and the colour are unchanged, so the register is intact; only the case
   and the tracking move, and tracking drops because uppercase needs it and lowercase
   does not. Nothing reflows: monospace advance is identical in both cases. */
.src-line{font-family:var(--f-mono);font-size:12.5px;letter-spacing:.02em;
  color:var(--ink-subtle);margin:0 0 10px}
.src-line a{color:var(--crude-amber);border-bottom:1px solid rgba(200,136,40,.5)}
@media (hover:hover) and (pointer:fine){.src-line a:hover{color:var(--signal-gold);
  border-bottom-color:var(--signal-gold)}}
.paper .src-line{color:#5A6874}
.paper .src-line a{color:#8A5E14;border-bottom-color:rgba(138,94,20,.5)}

/* ── machine portrait ────────────────────────────────────────────────────────── */
.portrait{padding-top:clamp(40px,6vw,84px);border-top:0}
.portrait h1{font-size:clamp(40px,7.2vw,86px);margin-bottom:22px}
.portrait .eyebrow{margin-bottom:20px}
.portrait .lede{margin-bottom:0}

/* margin-INLINE is set here on purpose. `.plate` and the bare `<figure>` in `.split`
   are <figure> elements, and this stylesheet never reset the UA default
   `figure{margin:1em 40px}` — only margin-TOP was ever overridden, so a hard 40px
   side inset survived on every plate on the site. Measured on company.html
   (Chromium, getComputedStyle, 2026-08-26): the inset is 7.2% of the text column at
   1440px and 25.0% at 360px, because 40px is fixed while the column is fluid. The
   founder portrait — the page's own hero image — shipped 256px wide inside a 350px
   text column at 390px, indented 40px past its own caption's left edge and past
   every heading, button and paragraph on the page. A designed inset is proportional;
   this one was an unreset browser default wearing a design's clothes.
   The clamp keeps the desktop rendering pixel-identical (3.2vw >= 40px at >=1250px)
   and makes the inset proportional below it: ~12.5px at 390px, holding the same
   ~7% relationship to the column that the desktop plate has. Verified across ten
   widths, 360-1440. 11 `.plate` figures on 13 pages, both languages. */
.plate{margin-top:clamp(34px,5vw,64px);margin-inline:clamp(0px,3.2vw,40px);
  border:1px solid var(--hairline-strong);
  background:var(--panel-navy);padding:10px}
.split>figure{margin-inline:clamp(0px,3.2vw,40px)}
.plate img{width:100%;height:auto}
/* Sentence case per the note on .src-line above. The one that settles it is on mypalm:
   "the plate is painted CONVEYER, the label is printed CONVEYOR" — a sentence whose whole
   point is a difference in spelling, set in a case that flattens every other word around
   the two it needs the reader to compare. */
.plate figcaption{display:flex;flex-wrap:wrap;gap:6px 22px;padding:14px 6px 4px;
  font-family:var(--f-mono);font-size:12.5px;letter-spacing:.02em;
  color:var(--ink-muted)}
.plate figcaption b{color:var(--ink);font-weight:500}
/* THE CHIP, NOT THE ROW. base.css deliberately excludes `.plate figcaption` from the
   caption measure cap because it is a wrapping flex ROW of metadata chips, and the row's
   character count is meaningless. That reasoning holds for the row and says nothing about
   a single chip — and one chip is where this broke. Measured at 1440 on the same figure in
   both languages:

       ai-ffb-grading   "Unit layout twin inclined conveyors in..."   683px, ONE line
       penggredan-ai    "Susun atur unit dua penghantar..."           998px, TWO lines

   The Malay chip is 46% longer, so it wraps — at 133.1ch, 112 characters to a line of
   12.5px all-caps mono, the widest line of text anywhere on the site. Nothing constrained
   it, so the defect appeared in one language only and was invisible in the other. 76ch is
   the caption measure base.css already uses for prose figcaptions (570px here): the Malay
   chip drops to 2 lines of 58 characters, and the longest English chip — itself 91ch on
   one line — becomes two lines of 58 rather than one of 91. Both languages now wrap the
   same way, which is the point. */
.plate figcaption>*{max-width:min(100%,76ch)}

/* ── the annotated frame ─────────────────────────────────────────────────────── */
.frame{position:relative;border:1px solid var(--hairline-strong);background:var(--deep-water);line-height:0}
.frame>img{width:100%;height:auto}
.anno{position:absolute;border:1px solid var(--signal-gold);
  box-shadow:0 0 0 1px rgba(11,21,32,.55)}
.anno span{position:absolute;top:0;left:0;transform:translateY(-100%);
  background:var(--signal-gold);color:#14202C;font-family:var(--f-mono);font-size:12px;
  font-weight:600;line-height:1;letter-spacing:.1em;padding:4px 6px}
.frame-stamp{position:absolute;right:8px;top:8px;background:rgba(11,21,32,.86);
  color:var(--ink-muted);font-family:var(--f-mono);font-size:12px;letter-spacing:.12em;
  text-transform:uppercase;padding:6px 9px;border:1px solid var(--hairline-strong);line-height:1.2}
.legend{list-style:none;margin:0;padding:18px 0 0;display:grid;gap:12px 30px;
  grid-template-columns:repeat(auto-fit,minmax(240px,1fr))}
.legend li{display:flex;gap:12px;font-family:var(--f-mono);font-size:13px;line-height:1.55;
  letter-spacing:.03em;color:var(--ink-muted)}
.legend b{color:var(--signal-gold);font-weight:600;flex:none}

/* .legend has TWO shapes wearing one class, and only one of them is a hanging indent.
   Four of the five lists are label+description — <b>01</b>, <b>FILL</b>, <b>RGB</b> — where
   `flex:none` correctly pins a short label to the left and the sentence blocks beside it.
   The fifth is a NAME plus its abbreviation, and there `flex:none` sized the <b> to
   max-content: "Malaysian Palm Oil Certification Council" is wider than its own grid
   column, so it ran 143px past the cell and printed ON TOP of the next column's text.
   Measured at 1440px on company.html and ms/syarikat.html: 10 line boxes overrunning
   their cell, 2 of them glyph-on-glyph — "Certification Council (MPMalaysian Palm Oil
   Board", "Palm Oil MMeillak Motor", "FoundaSime Darbytion". The grid cells never
   overlapped, so a box-geometry check saw nothing; only the text did.
   A name and its abbreviation are prose, not a label pair, so this variant flows inline
   and wraps inside its own cell. Scoped to the modifier so the four hanging legends —
   company/syarikat legend 2, ai-ffb-grading, ms/penggredan-ai — keep today's layout
   exactly; a global `display:block` would also have worked here but would have crossed
   the assumption fx-scan.css:435 documents about .legend li being a flex container. */
.legend--names li{display:block}
.legend--names b{margin-right:.45em}

/* ── the pinned spec strip ───────────────────────────────────────────────────── */
.rig{display:grid;gap:clamp(34px,4.6vw,64px);align-items:start}
@media (min-width:1000px){.rig{grid-template-columns:minmax(0,1fr) 372px}}

.specstrip{border:1px solid var(--hairline-strong);background:var(--panel-navy)}
@media (min-width:1000px){.specstrip{position:sticky;top:112px}}
@media (prefers-reduced-motion:reduce){.specstrip{position:static}}
.specstrip>h3{font-family:var(--f-mono);font-size:13px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--crude-amber);padding:16px 20px;
  border-bottom:1px solid var(--hairline-strong)}
.specstrip dl{margin:0;padding:4px 20px 18px}
.specstrip dt{font-family:var(--f-mono);font-size:12px;letter-spacing:.16em;text-transform:uppercase;
  color:var(--ink-muted);padding-top:16px}
.specstrip dd{margin:5px 0 0;padding-bottom:16px;border-bottom:1px solid var(--hairline);
  font-family:var(--f-mono);font-size:13px;line-height:1.5;color:var(--ink)}
.specstrip dd:last-of-type{border-bottom:0;padding-bottom:4px}
.specstrip dd.open{color:var(--crude-amber)}
/* The specification panel carried ten rows of hard operational commitments and NO source line,
   twenty pixels from a tier list that had one — so the single block a buyer would lift into a
   tender was the only unattributed thing on an evidence page. The line sits inside the panel so
   it travels with the sticky strip rather than scrolling away from what it attributes. */
.specstrip .src-line{margin:0;padding:14px 20px 16px;border-top:1px solid var(--hairline);
  line-height:1.75}

/* ── decimal outline (the four tiers) ────────────────────────────────────────── */
.outline{border-top:1px solid var(--hairline-strong)}
.outline>div{display:grid;gap:6px 26px;padding:24px 0;border-bottom:1px solid var(--hairline)}
@media (min-width:760px){.outline>div{grid-template-columns:88px minmax(0,1fr)}}
.outline .n{font-family:var(--f-mono);font-size:13px;font-weight:600;letter-spacing:.14em;
  color:var(--crude-amber);padding-top:5px}
.outline h3{margin-bottom:8px}
.outline p{margin:0;color:var(--ink-muted);max-width:60ch}

/* ── measurement notes (one line per figure, the basis behind a fold) ─────────
   REPLACES the .mx* matrix — four figures across, six dimensions down — which
   put twenty cells of apparatus in front of a reader who had come to find out
   what changed at a mill. Nothing honest was lost in the swap: every figure
   still carries Provenance / Basis / Comparator / Scope / Variance, and
   qa/note-lint.py still fails the build if one of those rows goes missing or
   prints out of order. They are one <summary> away instead of in the way.

   The System version row went with the matrix. It printed "not established"
   in all four columns — the same non-answer four times — and its substance
   survives once, in "the model build is unrecorded" and in the measurement
   basis you can ask for. qa/note-lint.py's SLOTS tuple was cut to match in
   the same pass, because a required slot that no page can satisfy is a rule
   that only ever fails.

   No background colour and no new token: .bnote sits on the page ground and
   reuses the exact type/colour pairs .mxcell and .mxhead already passed
   qa/contrast.py with. Two columns from 900px, one below it — a fold is
   readable at any width, which is the whole reason the matrix could go. */
.basis{border-top:1px solid var(--hairline-strong);margin-top:22px}
@media (min-width:900px){
  .basis{display:grid;grid-template-columns:1fr 1fr;column-gap:clamp(26px,3.4vw,52px)}
}
.bnote{border-top:1px solid var(--hairline);padding:20px 0 16px}
@media (min-width:900px){.bnote:nth-child(-n+2){border-top:0;padding-top:22px}}
.bnote .n{font-family:var(--f-mono);font-size:13px;font-weight:600;letter-spacing:.14em;
  color:var(--crude-amber);margin:0 0 7px}
.bnote h3{margin:0 0 8px;font-size:clamp(16px,1.3vw,19px);line-height:1.25}
.bnote .src-line{margin:0 0 12px}
.bline{margin:0;font-size:15.5px;line-height:1.5;color:var(--ink);max-width:52ch}
.bnote details{margin-top:14px}
.bnote summary{font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--crude-amber);cursor:pointer}
.bnote summary:focus-visible{outline:2px solid var(--signal-gold);outline-offset:3px}
/* 11px mono on one line is an 18px-tall hit area, and this summary is the ONLY way to
   reach the measurement basis behind each figure — the disclosure the page's whole
   claim-discipline rests on. Measured 2026-08-26 at 390px CSS px (is_mobile + has_touch,
   so the coarse-pointer queries actually match): 350x18, padding 0. WCAG 2.5.8 Target
   Size (Minimum, AA) asks 24x24. 8 of these across minsawi-smart-mill + ms/kajian-kes.
   Raised on `(pointer:coarse)` only, matching the footer/nav precedent in shell.css:332,
   so a mouse-driven desktop keeps today's tighter rhythm. Padding rather than a flex
   box on purpose: `display:flex` on a <summary> drops the disclosure triangle, and the
   triangle is the affordance that says this opens. */
/* Raised 28 -> 44 on 2026-08-27, together with the site-wide floor in shell.css. 28px
   cleared the AA minimum this comment cites but not the 44px of WCAG 2.5.5 / Apple's HIG,
   and because `.bnote summary` (0,1,1) outranks the new site-wide `summary` rule (0,0,1),
   this line was the reason those eight toggles stayed at 28px while every other summary
   on the site went to 44 — a floor set in two places, where the more specific one silently
   won. Keep it in ONE place: this rule is the floor for these toggles, so it moves with the
   site's. Padding stays rather than a flex box, for the reason above — the triangle. */
@media (pointer:coarse){ .bnote summary{padding:5px 0;min-height:44px} }
.bnote details dl{margin:10px 0 0;padding:0}
/* 11px FLOOR. Raised 2026-08-27. A reading floor applies to text a reader has to READ —
   prose, citations, table data, provenance. It does not apply to a one-word micro-label
   pinned to a drawing, which is read WITH the graphic and is left at 10.5px on purpose
   (fx-plant's loop numerals, the station rail, the frame stamps), nor to a superscript
   footnote marker, which is meant to be ~0.63em of its body. What was below the floor was
   none of those: it was a table of sources, a set of definition terms, two inline code
   spans and a press provenance line. */
.bnote details dt{font-family:var(--f-mono);font-size:11px;letter-spacing:.11em;
  text-transform:uppercase;color:var(--crude-amber);padding:9px 0 0;
  border-top:1px solid var(--hairline)}
/* 11.5px -> 12.5px, the `.stat .src` third pass in base.css applied here. The `dt` above
   stays at 11px: it is an uppercase LABEL and takes a label size. The `dd` is not — these
   are the four methodology notes on the Minsawi page, 74 to 97 characters each ("Our own
   IPOMC 2026 slides. The column's words: 'reportedly improved from about 17.85% to
   19.02%'"), and they are the text that says how each figure on the page was arrived at.
   This is the proof page: its whole reason to exist is these notes, and they were set
   smaller than the numbers they qualify and under the 12px floor. The 60ch measure is left
   alone — a wider glyph in the same measure means fewer characters per line, which is the
   direction that helps. */
.bnote details dd{margin:4px 0 0;padding:0 0 11px;font-family:var(--f-mono);font-size:12.5px;
  line-height:1.65;letter-spacing:.02em;color:var(--ink-muted);max-width:60ch}

/* ── the flow ────────────────────────────────────────────────────────────────── */
.flow{list-style:none;counter-reset:f;margin:0;padding:0;display:grid;gap:1px;
  background:var(--hairline);border:1px solid var(--hairline)}
.flow li{counter-increment:f;background:var(--deep-water);padding:20px 22px;
  display:flex;gap:16px;align-items:baseline}
.flow li::before{content:counter(f,decimal-leading-zero);font-family:var(--f-mono);font-size:13px;
  font-weight:600;letter-spacing:.12em;color:var(--ink-subtle);flex:none}
.flow li>span{font-size:15.5px;line-height:1.5}
.flow li:last-child>span{color:var(--ink-muted)}
/* THE ODD STEP SPANS, 2026-08-27. `.flow` paints `var(--hairline)` on the LIST and
   `var(--deep-water)` on each `li`, with `gap:1px` — so the gaps read as hairlines and any
   cell with no `li` in it reads as a lighter PAINTED BOX, not as whitespace. Two of the
   four flow lists on this site have five steps (traceability, kebolehkesanan; the other
   two have eight), so at >=720px step 05 sat alone with a 556 x 105 painted empty box
   beside it. A reader does not see "five steps in a two-column grid", they see a sixth
   card that failed to load, which is the worst thing an evidence list can look like.

   `:last-child:nth-child(odd)` fires ONLY on an odd count, so the eight-step lists are
   untouched and a list that later grows to six needs no edit here. Scoped inside the
   query because there is only one column below 720px and nothing to span. */
@media (min-width:720px){
  .flow{grid-template-columns:1fr 1fr}
  .flow>li:last-child:nth-child(odd){grid-column:1 / -1}
  /* THE CELL SPANS; THE SENTENCE MUST NOT. Measured at 1440 on traceability and
     kebolehkesanan right after the span above landed: steps 01-04 set 50.2ch in a 476px
     track and step 05 set 108.8ch across 1031px — 2.2x its siblings and 36% past the 80ch
     ceiling, so the one step a reader reaches last is the only one they have to re-find the
     left edge for. The cap is the sibling measure, not a new one: 52ch of this 15.5px face
     is ~495px against the track's 476px. The cell still spans, which is what removes the
     painted empty box; only the text stops where the column above it stops. */
  .flow>li:last-child:nth-child(odd)>span{max-width:52ch}
}

/* ── the ask-us slot ─────────────────────────────────────────────────────────── */
.slot{border:1px solid var(--crude-amber);background:rgba(200,136,40,.06);
  padding:clamp(22px,3vw,34px)}
/* IT TRAVELS, like every other narrow-column panel in this file. Measured at 1440 and 1920 on
   company.html and ms/syarikat.html: `#partners .doc` is `minmax(0,1fr) 336px`, the body ran
   1629px and the slot 637px, leaving 992px of empty right column — the largest dead column
   on the site once the sticky rails were discounted. And the thing left behind is the OFFER
   ("What we will send you", "Ask for a reference call"): a reader who scrolls into the part
   of the page that makes them want it has already scrolled past the way to ask.
   `.facts` (line 309, same `.doc`, same track) and `.specstrip` (line 158, same `.rig`) both
   already do this at the same breakpoint and the same 112px offset — this is the third panel
   of the same kind, and it was the only one still parked at the top.
   THE HEIGHT CLAIM HERE WAS WRONG, CORRECTED. It read "567-637px against a 900px viewport,
   so it never outgrows the screen" — measured on two of the eight pages this rule reaches.
   All eight at 1000/1440/1920 run 412.4-815.0px, and at that same 900px viewport 112+815=927
   already exceeds it on kebolehkesanan; on a 1000x700 laptop six of eight do. Swept the whole
   scroll in 40px steps to price it: the bottom edge stays reachable in every case (sticky
   releases as the containing block passes and the panel rides up), so nothing is unreachable
   — it is clipped for part of the scroll on pages taller than the viewport it pins in, the
   same exposure `.facts` and `.specstrip` already carry.
   Sticky changes no box and no flow, so nothing above or below it moves. */
@media (min-width:1000px){ .doc > .slot, .rig > .slot{position:sticky;top:112px} }
/* Both siblings pair the sticky with a reduced-motion opt-out (`.specstrip` line 159,
   `.facts` line 330); this one shipped without it, so a reader asking for less movement got
   a travelling panel on company/careers and a static one later on the same site. */
@media (prefers-reduced-motion:reduce){ .doc > .slot, .rig > .slot{position:static} }
.slot .eyebrow{margin-bottom:16px}
.slot h3{margin-bottom:14px}
.slot dl{margin:20px 0 0;padding:0;border-top:1px solid rgba(200,136,40,.34)}
/* Sentence case per .src-line above: every <dt> here is a DOCUMENT TITLE, up to 63
   characters, and a title is the last thing to flatten. */
.slot dt{font-family:var(--f-mono);font-size:12px;letter-spacing:.02em;line-height:1.5;
  color:var(--ink-muted);padding-top:15px}
/* max-width added 2026-08-27: `.slot dd` had none and ran the slot's full width — 81.3ch
   at every desktop width on minsawi-smart-mill and its Malay twin, wrapping to 2-3 lines.
   Same 620px cap and the same arithmetic as `.note` above (13px mono): 79.5ch. */
.slot dd{margin:5px 0 0;padding-bottom:15px;border-bottom:1px solid rgba(200,136,40,.2);
  max-width:620px;
  font-family:var(--f-mono);font-size:13px;line-height:1.5;color:var(--ink-muted)}

/* ── the circulated document ─────────────────────────────────────────────────── */
.doc{display:grid;gap:clamp(38px,5vw,72px);align-items:start}
@media (min-width:1000px){.doc{grid-template-columns:minmax(0,1fr) 336px}}
.doc>.body>*+*{margin-top:clamp(40px,5vw,76px)}
.doc h3{margin-bottom:14px}

.facts{border:1px solid var(--hairline-strong);background:var(--panel-navy)}
@media (min-width:1000px){.facts{position:sticky;top:112px}}
@media (prefers-reduced-motion:reduce){.facts{position:static}}
.facts h2{font-family:var(--f-mono);font-size:13px;font-weight:600;letter-spacing:.2em;
  text-transform:uppercase;color:var(--crude-amber);padding:16px 20px;
  border-bottom:1px solid var(--hairline-strong)}
.facts table{width:100%;border-collapse:collapse;font-family:var(--f-mono)}
.facts caption{caption-side:bottom;text-align:left;padding:0 20px 18px;
  font-family:var(--f-mono);font-size:12px;line-height:1.6;letter-spacing:.05em;color:var(--ink-muted)}
.facts th,.facts td{text-align:left;padding:13px 20px;border-bottom:1px solid var(--hairline);
  vertical-align:top}
.facts thead th{font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:var(--ink-muted);
  font-weight:600;padding-top:15px}
.facts tbody th{font-size:12px;letter-spacing:.12em;text-transform:uppercase;color:var(--ink-muted);
  font-weight:500;width:38%}
.facts tbody td{font-size:13px;color:var(--ink)}
/* The SOURCE column of the facts table: a citation, and it was the smallest type on the
   site. Sentence case for the same reason as .src-line — these are mastheads.
   11px -> 12px (2026-08-27). The note above said "it was the smallest type on the site"
   and then changed only the CASE. It was still 11px, below the 12px floor supporting text
   is normally set to, on 20 rows across careers / company / letters / kerjaya / syarikat /
   surat-rasmi / kajian-kes — and some of those cells are whole sentences, not mastheads
   ("Undated. Trial ran 1 October 2021 to 31 December 2021"). This site's argument is that
   every fact carries its source; the source column being the least legible thing on the
   page argues the opposite. 12px keeps the three-step hierarchy intact — value 13px,
   row label 12px uppercase+tracked, source 12px sentence case — so the column is still
   subordinate, it is just readable. Verified at 1:1 and 2x, 1440 and 390. */
.facts td.s{font-size:12px;letter-spacing:.02em;color:var(--ink-muted);
  width:26%}
.facts td.s a{color:var(--ink);border-bottom:1px solid var(--hairline-strong)}
@media (hover:hover) and (pointer:fine){.facts td.s a:hover{color:var(--signal-gold)}}
.facts tbody tr:last-child th,.facts tbody tr:last-child td{border-bottom:0}

/* the delta rows — before → after, hairline-composed, never a card */
.delta{grid-template-columns:repeat(auto-fit,minmax(238px,1fr))}
.delta .stat{min-width:0}
/* the delta headline is shorter than a single figure — cap it so "66 → 31" never
   overruns its column at 1440, where auto-fit gives each stat ~254px */
.delta .stat .v{font-size:clamp(33px,4.2vw,52px);overflow-wrap:break-word}
.delta .stat .u{max-width:34ch}
.delta .arrow{font-family:var(--f-mono);color:var(--ink-subtle);font-size:.46em;
  font-weight:400;vertical-align:middle;padding:0 .3em}
.delta .src-line{min-height:2.4em}

/* ── the pull quote (quoting our own most credible critic) ───────────────────── */
/* margin-inline:0 IS THE MEASURE FIX, and it is a UA default nobody wrote.
   `.pull blockquote` sets `margin:0` on the INNER element; the outer <figure> was never
   reset, so every pull quote on the site was carrying the browser's `figure{margin:1em
   40px}` — 80px of horizontal margin it did not ask for. There is no `figure{margin:0}`
   in base.css, and the only other figures that carry an inline margin (`.plate`, the bare
   `<figure>` in `.split`) get theirs DELIBERATELY from `.split>figure{margin-inline:
   clamp(0px,3.2vw,40px)}` at line 90. Measured live at 390px (is_mobile+has_touch),
   2026-08-27, before the fix: figure.pull 270px inside a 350px .measure, blockquote 248px,
   and EVERY pull quote on the site rendering at 21-25 characters per line — a return sweep
   every four words, ten of them on the longest. 80px is 23% of the column on a phone.
   Block margin is left at the UA 1em because the vertical rhythm around these figures was
   built against it; only the horizontal squeeze was unintended.

   line-height 1.16 -> 1.3. 1.16 is correct for the twelve-word sentence this component was
   sized for — traceability.html's wide instance is 2 lines at 53 cpl and reads as a poster.
   It is not correct for the instances that run 6-10 lines, where the reader is doing real
   linear reading and 40px Fraunces has long descenders sitting 6px off the ascenders below.
   The sibling case was diagnosed independently on this page's own .ltq (see the note above
   it: "at 40px that measured a 510px twelve-line wall"); this is the same defect in the
   component .ltq was split out of, and it is fixed here in leading rather than by renaming
   markup that a parallel workstream is still moving. */
.pull{margin-inline:0;border-left:2px solid var(--crude-amber);
  padding:4px 0 4px clamp(20px,3vw,34px)}
.pull blockquote{margin:0;font-family:var(--f-display);font-weight:420;
  font-size:clamp(24px,3.4vw,40px);line-height:1.3;letter-spacing:-0.0068em;color:var(--ink)}
/* Sentence case per the note on .src-line — this line carries a person's name and their
   job title, and "Head of Department, Digital Agriculture Technology (AgTech) Ecosystem"
   set in caps is 136 characters with every proper noun flattened. */
.pull figcaption{margin-top:20px;font-family:var(--f-mono);font-size:13px;line-height:1.7;
  letter-spacing:.02em;color:var(--ink-subtle)}
.pull figcaption b{color:var(--ink);font-weight:500;display:block}

/* ── media wall — named outlets with headlines, never a logo strip ───────────── */
.mediawall{list-style:none;margin:0;padding:0;display:grid;gap:1px;background:var(--hairline);
  border:1px solid var(--hairline)}
@media (min-width:640px){.mediawall{grid-template-columns:1fr 1fr}}
@media (min-width:1060px){.mediawall{grid-template-columns:1fr 1fr 1fr}}
.mediawall li{background:var(--deep-water)}
.mediawall a{display:block;padding:20px 22px;height:100%;color:var(--ink);
  transition:background var(--d2) var(--e-quad)}
.mediawall .out{font-family:var(--f-mono);font-size:12px;font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:var(--crude-amber);margin-bottom:12px;display:block}
.mediawall .hl{display:block;font-size:15px;line-height:1.4;margin-bottom:12px}
/* Sentence case per the note on .src-line. This selector is shared: on the media wall it
   is a date ("25 May 2026"), and on careers.html it is the JOB DESCRIPTION — up to 89
   characters of sentence, which is the one line a candidate reads before deciding whether
   to apply. Both read better in sentence case; only one of them was unreadable in caps. */
.mediawall .dt{font-family:var(--f-mono);font-size:12px;letter-spacing:.02em;line-height:1.55;
  color:var(--ink-muted)}
@media (hover:hover) and (pointer:fine){
  .mediawall a:hover{background:var(--panel-navy)}
  .mediawall a:hover .hl{color:var(--signal-gold)}}
@media (prefers-reduced-motion:reduce){.mediawall a{transition:none}}

/* ── the install constraint — one photo, one paragraph, asymmetric ───────────── */
.split{display:grid;gap:clamp(28px,4vw,56px);align-items:center}
@media (min-width:860px){.split{grid-template-columns:minmax(0,1.15fr) minmax(0,1fr)}
  .split.flip>:first-child{order:2}}
.split img{width:100%;height:auto;border:1px solid var(--hairline-strong)}

/* ── overflow discipline at 390px ────────────────────────────────────────────── */
@media (max-width:520px){
  .plate{padding:6px}
  .plate figcaption{gap:5px 14px;font-size:11px;letter-spacing:.02em}
  /* 9px was the smallest text on the site, and both of these are OVERLAYS — absolutely
     positioned on top of a photograph — so their size cannot reflow anything around them.
     They were shrunk to 9px to stop them overrunning the frame at 390px. Re-measured at
     390 in a real mobile context after raising them to 10.5px: the stamp renders 173px
     wide on ai-ffb-grading and 218px on ms/penggredan-ai inside a 350px frame, clearing
     both the frame and the viewport. 10.5px is legible on a phone; 9px is not.
     `.anno span` is raised with it for consistency of register, NOT on a measurement:
     no element carrying class="anno" exists in any page on this site today, so the rule
     is currently unexercised and its 390px behaviour is unverified. If annotations are
     ever added back, measure them before trusting this line. */
  .frame-stamp{font-size:10.5px;padding:4px 6px;right:5px;top:5px}
  .anno span{font-size:10.5px;padding:3px 4px;letter-spacing:.06em}
  .facts th,.facts td{padding:11px 14px}
}
/* ── the 520px valve is not enough for a 3-column table at 320px ──────────────
   Measured 2026-08-24 (headless Chrome, shipped files). The origin-record table is
   `table-layout:auto`, 3 columns, no `nowrap` anywhere, inside `.facts` whose parent
   has `overflow-x:visible` — so when it does not fit it SPILLS rather than scrolls:

       320px  traceability.html       table 333.9px vs 320px viewport  -> 11 text runs ink past the right edge
       320px  ms/kebolehkesanan.html  table 327.9px                    ->  7 text runs

   THE VIEWPORT IS THE WRONG BOUNDARY, and a first pass at 9px padding proved it: the ink
   check went green at 320px while the table still measured 303.9px inside a 280px `.facts`
   panel — fitting the SCREEN while breaking out of its own bordered card, 24.9px past the
   panel edge, visible to the eye and invisible to the check. Same family as the
   `.hero{overflow:hidden}` case base.css documents: the right question asked of the wrong box.

   The table sits at exact min-content. Measured per column, longest unbreakable word + padding:
       Certification 93.6 + 18 = 111.6   Traceability 93.6 + 18 = 111.6   Plantation 62.7 + 18 = 80.7
       sum 303.9 — which IS the table width, so every column is already as narrow as its content allows.

   That leaves padding as the only lever. `overflow-wrap:break-word` was measured and does
   NOTHING here (303.9px before and after) — it breaks a line but leaves min-content alone,
   exactly as locale-ms.css says of the same idiom. 4px fits both pages at 278px against the
   280px panel, with the 1px column hairline still giving 8px between adjacent text runs.

   Not a scroll wrapper: three narrow columns that FIT read better than three wide ones a
   phone user has to drag sideways — and the ink check has no notion of a scrollable
   ancestor, so a wrapper would have moved the text without satisfying anything. */
@media (max-width:400px){
  .facts th,.facts td{padding:11px 4px}
  .facts tbody th{width:34%}
  .specstrip dl,.specstrip>h3{padding-left:16px;padding-right:16px}
  .flow li{padding:16px 16px}
  .btn{padding:14px 18px;font-size:13px;letter-spacing:.06em}
}

/* ═══ SHARED-SHELL CURES — MOVED to shell.css ══════════════════════════════════
   C1 CONTRAST stays withdrawn: tokens.css raised --ink-ghost to #7E99B7 repo-wide
      (6.24 / 5.10 / 4.79 on Deep Water / Panel Navy / Mill Navy), which beats the
      page-scoped #808F9F this file briefly carried and which FAILED AA on Mill Navy.
      Nothing is overridden here; the shared token wins.
   C2 HEADER OVERFLOW <=900px and C3 NAV WRAPPING 901-1359px are now in
      shell.css § MASTHEAD FIT. They were cured page-scoped in THREE files — this one,
      home.css and smart-mill.css — and in none of the shared ones, which is why
      demo.html and privacy.html never received them at all.
   ══════════════════════════════════════════════════════════════════════════════ */

/* ── .doc body blocks — restore the heading rhythm ─────────────────────────────
   base.css sets h1-h4{margin:0} and the eyebrow/h2 spacing lives on .sec-head,
   which these blocks are not. Without this the eyebrow, the h2 and the first
   paragraph sat flush against each other. */
.doc .body > div > .eyebrow{margin-bottom:18px}
.doc .body > div > h2{margin-bottom:clamp(20px,2.4vw,30px)}
.doc .body > div > .measure > p:first-child{margin-top:0}
.doc .body .outline{margin-top:clamp(22px,2.6vw,34px)}
.doc .body .split{margin-top:clamp(6px,1vw,14px)}

/* facts column balance — the value column was being squeezed to ~36% and every
   two-word value wrapped to four lines */
.facts tbody th{width:33%}
.facts td.s{width:23%}

/* MOVED to shell.css, beside the [aria-current="page"] rule it belongs with. It lived here,
   in a page-family sheet, while the markup convention it styles is site-wide — so the three
   pages that use it (smart-mill, privacy, ms/kilang-pintar) do not load this file and their
   nav marker rendered --ink-muted, i.e. no "you are here" at all. See shell.css. */

/* .split lives inside the .doc grid, whose body column is ~700px at 1440 — but the
   .split breakpoint is a VIEWPORT query, so it fired two-column into 375px + 326px:
   a 300px-wide photograph and six-word lines with dead space beside them. Inside the
   document column it stays one column and the photograph takes the full measure. */
.doc .body .split{grid-template-columns:minmax(0,1fr);gap:clamp(22px,3vw,34px)}
.doc .body .split.flip>:first-child{order:0}
.doc .body .split figure{margin:0}
.doc .body .split figcaption{margin-top:12px}

/* ═══ PRINT ════════════════════════════════════════════════════════════════════
   The Minsawi page's stated job is "a document a capex committee can circulate",
   and circulating means someone prints it or saves it as a PDF. Without this the
   page prints Deep Water across every sheet, the sticky panels sit wherever the
   scroll left them, and — worst for a proof document — every source URL becomes an
   invisible underline. Kernel White ground, and the sources print as text.
   .rev is forced visible because a printed page must never depend on whether an
   IntersectionObserver got a chance to fire. */
@media print{
  /* Canonical print palette lives in base.css's own @media print :root block (the
     foundational sheet, loaded on every page, and the one with the measured page-count
     rationale on record). This file used to re-declare a SECOND, slightly different
     :root here -- #16202B/#3D4B58/#66737F vs base.css's #101820/#2C3A47/#55636F -- close
     enough neither was a contrast problem (both near-black on white), but because
     base.css loads first and this file loads after it on the two pages that use both
     (ai-ffb-grading.html, proof/minsawi-smart-mill.html), those two pages printed a
     visibly different ink colour than every other page on the site. One palette,
     declared once, so print output is identical across pages regardless of which
     stylesheet happens to load last. base.css also already sets body{background,color}
     in print -- removed the duplicate here for the same reason. */
  .rev,.rev.in{opacity:1!important;transform:none!important;transition:none!important}
  .tele,header.site,.navtoggle,.cta-row,.btn,.frame-stamp{display:none!important}
  .specstrip,.facts{position:static!important;break-inside:avoid;background:#fff;
    border:1px solid rgba(22,32,43,.42)}
  .slot{background:#fff;border:1px solid #7A520F}
  .flow li,.plate,.frame{background:#fff}
  .mediawall{background:#fff;border-color:rgba(22,32,43,.42);gap:0}
  .mediawall li{background:#fff;border:1px solid rgba(22,32,43,.22)}
  .mediawall a{color:#16202B}
  .mediawall .hl{color:#16202B}
  .rig,.doc{display:block}
  .rig>*+*,.doc>*+*{margin-top:18pt}
  section{padding:14pt 0;border-top:1px solid rgba(22,32,43,.22);break-inside:auto}
  h1,h2,h3,.eyebrow,.src-line{break-after:avoid}
  .stat,.outline>div,.mediawall li,.pull,.legend li,.plate,figure{break-inside:avoid}
  /* the table may break BETWEEN rows; a row (and the URL inside it) may not split */
  .facts{break-inside:auto}
  .facts tr,.facts th,.facts td{break-inside:avoid}
  .facts thead{display:table-header-group}
  .mediawall{grid-template-columns:1fr 1fr}
  /* a printed source that cannot be followed is not a source */
  .src-line a[href^="http"]::after,.mediawall a[href^="http"]::after,
  .facts td.s a[href^="http"]::after,.note a[href^="http"]::after,
  .pull figcaption a[href^="http"]::after{content:" — " attr(href);
    font-family:var(--f-mono);font-size:8pt;word-break:break-all;color:#55636F}
  a{color:#16202B;text-decoration:underline}
  footer{border-top:1px solid rgba(22,32,43,.42)}
  footer .cols{display:none}
  footer .legal{color:#55636F}
}

/* a grid child defaults to min-width:auto and will not shrink below its content;
   measured as a 1.15px bleed at exactly 320px. */
.doc>.body,.doc>.facts,.rig>*{min-width:0}

/* The finished frame is the one in the IMAGE FILE. It was briefly handled with CSS chips
   here instead, which was the wrong layer — CSS cannot reach og:image or a direct request
   for the asset, so anything the page needs baked in has to be baked into the file. The
   chips and this rule are retired. */

/* The <main tabindex="-1"> outline suppression has MOVED to shell.css § SKIP LINK
   TARGET. base.css gives every :focus-visible a 2px gold ring, which on <main> traced
   the entire document — measured 1280x8241px here. This file was the THIRD copy of the
   one-line cure, and demo.html/privacy.html still had none; shell.css now covers all
   seven pages. Focus still MOVES — it just does not draw a page-sized rectangle. */

/* THE ORIGIN-RECORD TABLE WAS BREAKING OUT OF ITS PANEL AT DESKTOP, not at mobile.
   Measured: .doc is a 704px + 336px grid and the table sat in the 336px sidebar while needing
   389px (columns 152/134/103). It broke out by 53.6px at 1440 and 1024, and pushed a 2px page
   scroll at 1024. An earlier pass had tightened cell padding for 320px and left this untouched,
   because the two failures are at opposite ends of the range.
   Four fixes were measured; two were clean. Tighter cells also fits, but a nine-row three-column
   provenance table crammed into a 336px sidebar is unreadable even when it technically fits — so
   the table takes the full width instead. Re-measured: fits at 1440 / 1024 / 760 / 390, no page
   scroll at any of them. */
@media (min-width:1000px){ .doc .facts{grid-column:1 / -1} }

/* ── TEAM PORTRAITS — the six the client supplied ──────────────────────────────
   The normalisation lives in the FILES, not in this rule. The six sources arrived as
   six unrelated photographs: 1507x1536 down to 333x389, backdrops running #FDFAF5 /
   #FEFEFE / #FFFFFF, and eye-lines anywhere between 13.2% and 21.7% of frame height.
   They ship as one 4:5 crop at 264x330, one eye-line at 32.0% of frame height (spread
   0.13pp across the set), faces centred to within 0.2% of frame width, and one ground
   — var(--kernel-white), because canon reserves pure white for print. So this rule
   only has to place them.

   THREE ACROSS, THEN TWO — and two across below 720px. Six divides evenly by both, so
   no row is ever left short. A four-column grid would leave a 4+2, and a row holding
   two plates under a row holding four reads as a mistake rather than as a grid.

   264px is the honest ceiling, not a design choice: see ASSETS.md § Team portraits.
   The plate is sized to the pixels that exist rather than the file being stretched to
   fill a bigger plate, which is why the grid caps well short of the 1240px wrap.
   THE CAP IS ARITHMETIC, NOT TASTE: 3 x 264 + 2 x 26 (the gap's clamp ceiling) = 844.
   It was 912 for one build, which rendered each 264px file into a 286.7px box — a 1.086x
   upscale, measured in Chrome, which is exactly the stretching the ceiling exists to
   refuse. If the gap ceiling ever changes, this number changes with it. */
/* ── THE TEAM RAIL ───────────────────────────────────────────────────────────
   A horizontal scroller rather than a grid, so six portraits at their honest
   264px use the full width instead of leaving ~330px of dead margin beside an
   844px block. The cap has not moved: the smallest source is 333px and nothing
   is upscaled — the rail just stops pretending the row must fit the viewport.

   CSS SCROLL-SNAP, NOT A JS CAROUSEL, for three reasons that each matter here:
     · it works with scripting OFF, and this site has a passing no-JS gate;
     · trackpad, touch and shift-wheel all drive it natively, and the scrollbar
       is a real affordance a custom carousel has to reinvent badly;
     · Tab moves through the figures and the browser scrolls to follow, so
       keyboard access is free rather than bolted on.
   The site rule holds: wide content scrolls INSIDE its own container and the
   page body never scrolls sideways. */
.team{display:grid;grid-auto-flow:column;grid-auto-columns:264px;
  gap:clamp(16px,2vw,26px);
  margin:clamp(26px,3.2vw,40px) 0 0;
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  scroll-padding-left:2px;
  padding-bottom:14px;
  align-items:start}
.team>figure{scroll-snap-align:start}
/* a quiet rail, not a chrome scrollbar sitting under a portrait */
.team::-webkit-scrollbar{height:6px}
.team::-webkit-scrollbar-track{background:transparent}
.team::-webkit-scrollbar-thumb{background:var(--hairline-strong);border-radius:3px}
.team:hover::-webkit-scrollbar-thumb{background:var(--ink-ghost)}
.team{scrollbar-width:thin;scrollbar-color:var(--hairline-strong) transparent}
/* a smooth snap is motion: honour the preference, keep the scrolling */
@media (prefers-reduced-motion:no-preference){.team{scroll-behavior:smooth}}
@media (max-width:719px){.team{grid-auto-columns:min(60vw,240px)}}
/* the 3-column override is superseded by the rail above */
.team figure{margin:0}
/* aspect-ratio + the token ground, so the row holds its shape before the lazy images
   land and a failed request leaves a plate rather than collapsing the row. */
.team img{width:100%;height:auto;aspect-ratio:4/5;object-fit:cover;
  background:var(--kernel-white)}
.team figcaption{margin-top:12px}
/* --f-sans DOES NOT EXIST — tokens.css defines --f-display, --f-body and --f-mono only.
   The fallback `inherit` was therefore substituted into the `font` SHORTHAND, where a bare
   CSS-wide keyword is not legal at a component position: the declaration became invalid at
   computed-value time and the browser dropped ALL of it — not just the family. So the two
   things this line was actually for, the 600 weight and the 1.25 leading, were never
   applied, and the team members' NAMES rendered at body weight and body leading — losing the
   only thing that marked them as the heading of their card.
   (An earlier draft of this note said the name became "typographically identical to the mono
   role line under them". Re-measured 2026-08-27 on both pages, that overstates it: only the
   WEIGHT matched. Name 400 / 27.2px / 17px Schibsted Grotesk vs role 400 / 16.5px / 11px
   Geist Mono — same weight, different family, size and leading.)
   Measured 2026-08-26 on company.html and ms/syarikat.html, with var(--f-body) as the control:
     as shipped   font-weight 400 · line-height 27.2px
     control      font-weight 600 · line-height 21.25px
   font-size 17px survived only because it happens to equal the inherited value. */
.team .nm{margin:0;font:600 17px/1.25 var(--f-body);letter-spacing:-.012em;
  color:var(--ink)}
/* was 12px/.10em, which broke "HEAD OF FINANCE & HUMAN RESOURCES" onto a ragged second line
   and left the six cards at two different heights. Tighter tracking plus a reserved two-line
   box levels every card whichever way a title wraps. */
.team .rl{margin:5px 0 0;font-family:var(--f-mono);font-size:11px;line-height:1.5;
  letter-spacing:.055em;text-transform:uppercase;color:var(--ink-subtle);min-height:2.7em}


/* ── DEPARTMENT COUNTS, AS TILES ─────────────────────────────────────────────
   These four sat as full-width stacked blocks: 39 words spread over 1,034px,
   which read as a long list rather than as one comparison. Four tiles across —
   and 4 divides 4, so no row is ever left with an orphan. They now sit UNDER
   the team rail: the faces introduce the company, the counts explain its shape. */
.deptcounts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));
  gap:clamp(14px,1.6vw,22px);margin-top:clamp(26px,3vw,38px);
  border-top:1px solid var(--hairline);padding-top:clamp(20px,2.4vw,30px)}
.deptcounts > div{margin:0;padding:0;border:0}
/* fallback dropped 2026-08-26. --f-display exists, so `,inherit` never fired and this line
   renders correctly — but it is the same loaded gun that went off on `.team .nm` above:
   a CSS-wide keyword inside the `font` shorthand invalidates the WHOLE declaration, weight
   and leading included, the moment the token is renamed or the sheet is loaded without
   tokens.css. Nothing here should depend on a token existing to keep its own font-weight. */
.deptcounts .n{font:400 clamp(30px,3.4vw,42px)/1 var(--f-display);
  color:var(--signal-gold);letter-spacing:-.02em}
.deptcounts h3{margin:8px 0 4px;font:600 12px/1.3 var(--f-mono);
  letter-spacing:.11em;text-transform:uppercase;color:var(--ink)}
.deptcounts p{margin:0;font-size:13.5px;line-height:1.5;color:var(--ink-muted);max-width:30ch}
@media (max-width:900px){.deptcounts{grid-template-columns:repeat(2,minmax(0,1fr))}}
@media (max-width:480px){.deptcounts{grid-template-columns:repeat(2,minmax(0,1fr));gap:16px 12px}}

/* Two brochure links measured 37px and 39px at 390 — near misses, and the brochure is the
   one asset a reader can take away from this page. Inline both, so padding-block: it grows
   the hit box without touching the line box, and "Smart Palm Oil Mill Brochure" must stay
   free to wrap inside a 265px column. */
@media (pointer:coarse){
  .slot dd a{padding-block:4px}
  .pull figcaption b a{padding-block:3px}
}

/* ── .lts — "what it settles, and what it leaves open" ────────────────────────
   Three term/definition pairs under each letter on /proof/letters. A bare <dl>
   here rendered at browser default: dt and dd on separate lines, dd indented
   40px, no rule between pairs, so the three pairs read as one paragraph with
   odd margins. This is the .slot dl treatment WITHOUT the panel — the letters
   page already has one .slot and a second amber box beside every letter would
   turn the page into a wall of panels. Two columns from 620px because the terms
   are two words and the definitions are two lines; below that the dt would be
   a 90px column of wrapped mono, which is worse than stacking. */
.lts{margin:0;padding:0;border-top:1px solid var(--hairline)}
.lts dt{margin-top:15px;font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--crude-amber)}
.lts dd{margin:5px 0 0;padding-bottom:15px;border-bottom:1px solid var(--hairline);
  font-size:14.5px;line-height:1.6;color:var(--ink-muted);max-width:62ch}
.lts dd:last-child{border-bottom:0}
@media (min-width:620px){
  .lts{display:grid;grid-template-columns:126px minmax(0,1fr);column-gap:22px}
  .lts dt{grid-column:1;margin-top:0;padding-top:16px}
  .lts dd{grid-column:2;margin-top:0;padding-top:16px;padding-bottom:16px}
  .lts dt{border-top:1px solid var(--hairline)}
  .lts dt:first-of-type,.lts dd:first-of-type{border-top:0;padding-top:15px}
  .lts dd{border-bottom:0;border-top:1px solid var(--hairline)}
  .lts dt:first-of-type{border-top:0}
}

/* ── /proof/letters + /ms/surat-rasmi — the three letter blocks ───────────────
   .pull IS NOT USABLE ON THIS PAGE, and the reason is worth writing down because
   it nearly shipped. `.pull blockquote` sets `color:var(--ink)` EXPLICITLY, so on
   a `.paper` section it overrides the inherited #16202B and renders the dark
   ground's near-white on kernel white. Measured live at 1440 before the fix:
   #F4F6F8 on #FAFAF8 = 1.04:1 against a 3.0:1 bar — an invisible pull-quote, and
   qa/contrast.py caught it on all six passes. The same pass caught five more of
   the same family on that page (.slot dt, .slot dd a, .note, .lts dt, .lts dd —
   every one a component coloured for Deep Water sitting on Kernel White). The
   cure was structural, not six overrides: these pages carry NO `.paper` section
   at all, matching proof/minsawi-smart-mill.html, which has none either. The
   light in the layout is the letters themselves — three white sheets on the dark
   ground, which is what a document should look like.

   .ltq sets NO colour, so it inherits and cannot repeat the bug on either ground.
   It is also deliberately smaller than .pull: .pull is sized for a twelve-word
   sentence, and a letter quotation runs to forty-four — at 40px that measured a
   510px twelve-line wall that outweighed the document it was quoting. */
.ltq{margin:0;padding:0 0 0 clamp(16px,1.8vw,26px);
  border-left:2px solid var(--crude-amber);
  font-family:var(--f-display);font-weight:420;
  font-size:clamp(19px,1.5vw,23px);line-height:1.36;letter-spacing:-0.002em;max-width:58ch}

/* THE LETTER, AT A SIZE WORTH PRINTING. At 411px — what .split gave it — the
   letterhead was a smudge and the signature was three pixels of ink, which is
   decoration wearing the costume of evidence. At 840 the letterhead, the subject
   line, the date and the signature block all read, and the body paragraph is the
   one thing no in-page size can carry, which is what the OPEN link under it is
   for. That link is a real, labelled affordance and not a sentence in a caption:
   the whole argument of this page is "you can check it yourself", and a reader
   should not have to guess that the picture is clickable. */
.ltdoc{margin:clamp(28px,3.4vw,44px) 0 0;max-width:840px}
.ltdoc a.sheet{display:block}
.ltdoc img{width:100%;height:auto;display:block;
  border:1px solid var(--hairline-strong);background:#fff}
.ltdoc figcaption{margin-top:12px;display:grid;gap:8px 22px;align-items:baseline}
@media (min-width:720px){.ltdoc figcaption{grid-template-columns:minmax(0,1fr) auto}}
.ltdoc .cap{font-family:var(--f-mono);font-size:12.5px;line-height:1.6;
  letter-spacing:.02em;color:var(--ink-muted);max-width:64ch}
.ltdoc .open{justify-self:start;font-family:var(--f-mono);font-size:12.5px;
  letter-spacing:.08em;text-transform:uppercase;color:var(--crude-amber);
  border-bottom:1px solid rgba(200,136,40,.5);padding-block:6px;white-space:nowrap}
@media (hover:hover) and (pointer:fine){.ltdoc .open:hover{color:var(--signal-gold)}}

/* ── .plate--screen — a SOFTWARE capture inside a plate ──────────────────────────
   Added 2026-08-27 with the two MyPalm screens on the Minsawi case study.

   THE MEASUREMENT THAT FORCED IT. A `.plate` is 1010px at 1440 and 311px at 390 —
   the inline clamp plus 10px of padding plus the wrap gutter. A photograph does not
   care: it is a scene either way. A 1600px-wide dashboard does. UI text in these
   captures is ~11px tall in the source, so it lands at ~6.9px at 1010 (legible, and
   verified at 1:1 — every nav row, tab, axis label and result box reads) and at
   ~2.1px at 311. At 311 the screen is not a small screen, it is a texture, and a
   screen too small to read is decoration.

   TWO THINGS, AND NEITHER IS A ZOOM LIBRARY.
   1. Below 900px the plate gives up its inline inset and its padding, so the capture
      gets the full column: 311 -> 390 at an iPhone width, +25%. That does not make it
      readable and is not claimed to. It is the free part.
   2. The readable part is the OPEN affordance, which is `.ltdoc`'s pattern from the
      letters page verbatim — same class, same reason written there: "a reader should
      not have to guess that the picture is clickable". The href is the 1600px file, so
      a phone gets pinch-zoom on the real capture and a desktop gets it in a tab.
   3. And the caption carries the READING in words, because a reader who never taps
      must still get what the screen says. That is mypalm.html's rule, not a new one.
   No `.plate` anywhere else changes: every declaration here is behind `--screen`. */
.plate--screen{overflow:hidden}
@media (max-width:900px){
  /* -1 * --gut, not 0. Dropping only the plate's own inset left 348px: the figure is
     inside `.wrap`, whose `padding:0 var(--gut)` is still there. Pulling back by one
     gutter on each side is what actually reaches the viewport edge — measured 390 at a
     390 client, against 311 before and 348 with margin-inline:0. */
  .plate--screen{margin-inline:calc(-1 * var(--gut));padding:0;border-inline:0}
  .plate--screen img{border-bottom:1px solid var(--hairline)}
  .plate--screen figcaption{padding-inline:var(--gut)}
}
.plate--screen figcaption{align-items:baseline}
.plate--screen .open{font-family:var(--f-mono);font-size:12.5px;letter-spacing:.08em;
  text-transform:uppercase;color:var(--crude-amber);white-space:nowrap;
  border-bottom:1px solid rgba(200,136,40,.5)}
@media (hover:hover) and (pointer:fine){.plate--screen .open:hover{color:var(--signal-gold)}}

/* ── .twice — one person, two artefacts, shown instead of asserted ───────────────
   The IOI letter is the only one of the three whose signatory also speaks on camera in
   AIREI's own film, and until now the page carried that as a SENTENCE: "the film shows
   the same person saying a compatible thing". A sentence is the weakest form a checkable
   fact can take — the reader has to accept it, then leave the page to test it.

   So the two artefacts are laid out as a matched pair under ONE name. The video's poster
   frame carries the film's own burnt-in lower third (his name, his title, his company),
   and the crop beside it is the foot of the letter reproduced below, where the same name
   is printed over an ink signature. The identity is IN THE TWO PICTURES. This layout only
   puts them at one size on one baseline so a reader sees it without being told.

   Two columns from 860px, which is `.split`'s own breakpoint, so the page has one
   two-column threshold and not two. Below it, one column with the video first: the moving
   thing is the one worth reaching first on a phone.

   Reused rather than reinvented: `.filmplayer` + `.filmnote` are base.css's video pair and
   are not restyled here beyond killing the top margin the standalone case wants; `.twicesig`
   borrows `.ltdoc img`'s border + white ground, because a paper crop and a paper sheet
   should sit on the same card. */
.twice{margin:clamp(30px,3.8vw,50px) 0 0;max-width:840px}
.twicename{margin:0;padding:0 0 16px;border-bottom:1px solid var(--hairline-strong);
  display:flex;flex-wrap:wrap;align-items:baseline;gap:2px 14px}
.twicename b{font-family:var(--f-display);font-weight:600;
  font-size:clamp(19px,1.6vw,23px);line-height:1.25;color:var(--ink)}
.twicename span{font-family:var(--f-mono);font-size:12.5px;letter-spacing:.02em;
  line-height:1.6;color:var(--ink-ghost)}
.twicegrid{display:grid;gap:clamp(26px,3.4vw,42px);align-items:start;padding-top:24px}
@media (min-width:860px){.twicegrid{grid-template-columns:minmax(0,1.18fr) minmax(0,1fr)}}
.twicemode{margin:0 0 12px;font-family:var(--f-mono);font-size:11px;letter-spacing:.16em;
  text-transform:uppercase;color:var(--crude-amber)}
/* base.css sets `.filmplayer{margin:var(--d3) 0 0}` — --d3 is a DURATION token (320ms), so
   that declaration is invalid and drops. Do not copy it; set the margin explicitly. */
.twice .filmplayer{margin:0}
.twice .filmnote{margin-top:12px}
.twicesig{margin:0}
.twicesig img{width:100%;height:auto;display:block;
  border:1px solid var(--hairline-strong);background:#fff}
/* The spoken line, at transcript scale rather than at `.ltq`'s headline scale. The letter
   quotation below is the page's pull quote and stays the largest voice on the section; this
   is the wording of a clip the reader can press play on two inches above it. */
.twicesaid{margin:16px 0 0;font-family:var(--f-display);font-weight:420;
  font-size:clamp(16px,1.25vw,18.5px);line-height:1.45;max-width:56ch}
.twicesaid+.src-line{margin-top:10px}

/* ─────────────────────────────────────────────────────────────────────────────
   THE TRACK RECORD, GIVEN SOMETHING TO LOOK AT  (2026-08-27)

   The page a buyer opens to answer "who else has AIREI done this for" ran 6,616px
   and 814 words with two images on it, and both were the AIREI logo in the header
   and the footer. Four components below, in the order they appear on the page.
   Every class name here is NEW: `.clientwall` and the `.mm` drawing classes are
   home.css's, and qa/css-collision.py exists because the last time two stylesheets
   shared a component name the later one silently restyled 24 figures. The DRAWING
   vocabulary is copied exactly (hairline + amber, mono labels, solid box, open
   bracket); only the selectors are page-local.
   ───────────────────────────────────────────────────────────────────────────── */

/* ── 1. THE FOOTPRINT  ── two territories, five sites, one baseline.
   Drawn, not photographed, and drawn in the same schematic language as the mill map
   on the home page: a solid `unitbox` for the thing that is bounded, an amber node
   for each site, an open bracket for the thing that spans. Ordering on the rail is
   the page's own 01-05, which is the order the section above reads in. */
.geomap{margin:clamp(30px,3.8vw,54px) 0 0;padding:clamp(22px,2.6vw,36px) 0 0;
  border-top:1px solid var(--hairline)}
.geomap svg{display:block;width:100%;height:auto;overflow:visible;margin:0 auto}
.geomap .gm-wide{display:none}
.geomap .gm-tall{display:block;max-width:100%}
@media (min-width:900px){
  .geomap .gm-wide{display:block;max-width:100%}
  .geomap .gm-tall{display:none}
}
.gm text{font-family:var(--f-mono);font-weight:500}
.gm .t-main{fill:var(--ink);font-weight:600;letter-spacing:.13em}
.gm .t-sub{fill:var(--ink-subtle);letter-spacing:.16em}
.gm .t-num{fill:var(--ink-subtle);font-weight:600;letter-spacing:.05em}
.gm .t-end{fill:var(--ink-muted);letter-spacing:.11em}
.gm .t-amber{fill:var(--crude-amber);font-weight:600;letter-spacing:.13em}
.gm .rail{fill:none;stroke:var(--mill-steel)}
.gm .brace{fill:none;stroke:var(--crude-amber)}
.gm .node{fill:var(--crude-amber)}
.gm .ring{fill:none;stroke:var(--hairline-strong)}
.gm .unitbox{fill:var(--panel-navy);stroke:var(--hairline-strong)}
.geomap figcaption{margin-top:clamp(16px,2vw,24px);font-family:var(--f-mono);
  font-size:12.5px;line-height:1.7;letter-spacing:.02em;color:var(--ink-muted);
  max-width:76ch}
@media print{
  .geomap .gm-wide{display:block;max-width:100%}
  .geomap .gm-tall{display:none}
  .gm .t-main{fill:#101820}
  .gm .t-sub,.gm .t-num,.gm .t-end{fill:#3C4A57}
  .gm .t-amber{fill:#7A5310}
  .gm .brace{stroke:#7A5310}
  .gm .node{fill:#7A5310}
  .gm .rail,.gm .ring{stroke:#55636F}
  .gm .unitbox{fill:#FFF;stroke:#55636F}
}

/* ── 2. THE THREE LETTERS, AS OBJECTS ──
   `.ltdoc` is the single full-width sheet on letters.html. This is its three-up
   sibling: the same white ground and hairline, at the size a document reads as a
   document rather than as a texture. 300px was chosen by rendering the scans at
   240 / 300 / 360 and looking: at 300 every letterhead, the date block, the body
   mass and the signature are all legible as what they are. */
.docrow{list-style:none;margin:clamp(28px,3.4vw,44px) 0 clamp(30px,3.8vw,52px);padding:0;
  display:grid;gap:clamp(20px,2.6vw,30px)}
@media (min-width:760px){.docrow{grid-template-columns:repeat(3,1fr)}}
.docrow li{min-width:0}
.docrow figure{margin:0}
.docrow a{display:block;text-decoration:none}
.docrow img{width:100%;height:auto;display:block;
  border:1px solid var(--hairline-strong);background:#fff}
@media (hover:hover) and (pointer:fine){
  .docrow a:hover img{border-color:var(--crude-amber)}
}
.docrow figcaption{margin-top:12px}
.docrow .who{display:block;font-family:var(--f-mono);font-size:12.5px;font-weight:600;
  letter-spacing:.06em;line-height:1.5;color:var(--ink)}
.docrow .what{display:block;margin-top:5px;font-family:var(--f-mono);font-size:12px;
  letter-spacing:.02em;line-height:1.6;color:var(--ink-muted)}
.docrow .open{display:inline-block;margin-top:9px;font-family:var(--f-mono);
  font-size:12px;letter-spacing:.08em;color:var(--ink-subtle);
  border-bottom:1px solid var(--hairline-strong)}
@media (hover:hover) and (pointer:fine){
  .docrow a:hover .open{color:var(--signal-gold);border-bottom-color:var(--signal-gold)}
}
.docrow a:focus-visible{outline:2px solid var(--signal-gold);outline-offset:4px}

/* ── 3. THE MARK WALL ──
   Two groups, marks only. Sized by ASPECT rather than by cell, so a long wordmark
   and a roundel carry the same optical weight instead of the same box: the bucket
   sets a max-height and the image never grows to fill its cell. Same five buckets
   the home page uses; a page-local class because a shared one would put two files
   in charge of one component's box. */
.wallgroup+.wallgroup{margin-top:clamp(30px,3.6vw,48px)}
.wallgroup>h3{font-family:var(--f-mono);font-size:12px;font-weight:600;
  letter-spacing:.2em;text-transform:uppercase;color:var(--crude-amber);
  margin:0 0 6px}
.wallgroup>p{margin:0;font-family:var(--f-mono);font-size:12.5px;line-height:1.7;
  letter-spacing:.02em;color:var(--ink-muted);max-width:66ch}
.markwall{list-style:none;margin:20px 0 0;padding:20px 0 0;
  border-top:1px solid var(--hairline);
  display:grid;grid-template-columns:repeat(3,1fr);gap:26px 20px;align-items:center}
@media (min-width:640px){.markwall{grid-template-columns:repeat(4,1fr)}}
@media (min-width:1000px){.markwall{grid-template-columns:repeat(6,1fr);gap:30px 22px}}
.markwall li{display:flex;align-items:center;justify-content:center;min-height:54px}
.markwall img{display:block;width:auto;height:auto;max-width:100%;
  max-height:var(--mw-h,46px);object-fit:contain}
.markwall .mw-4x{--mw-h:25px}   /* aspect >= 4.0 — a long wordmark    */
.markwall .mw-3x{--mw-h:29px}   /* 3.0 - 4.0                          */
.markwall .mw-2x{--mw-h:36px}   /* 1.6 - 3.0                          */
.markwall .mw-1x{--mw-h:43px}   /* 1.15 - 1.6                         */
.markwall .mw-sq{--mw-h:50px}   /* < 1.15 — roundel or square         */
/* A last row of one centres under the row above rather than hanging left. The image
   is capped by max-height, not by its cell, so spanning the row does not grow it. */
@media (min-width:1000px){.markwall>li:last-child:nth-child(6n+1){grid-column:1/-1}}
@media (min-width:640px) and (max-width:999px){.markwall>li:last-child:nth-child(4n+1){grid-column:1/-1}}
@media (max-width:639px){
  .markwall>li:last-child:nth-child(3n+1){grid-column:1/-1}
  .markwall img{max-height:calc(var(--mw-h,46px) * .82)}
}

/* ── THE ROSTER SITS ON PAPER, and these are the values that ground needs ──
   Measured before it moved: the client marks are the customers' own artwork, drawn for
   white letterheads and slide decks — navy IOI, navy SIPEF, black MDEC, grey Endress+Hauser.
   On --deep-water (#0B1520) they were dark-on-dark and six of the twenty-five were not
   findable by eye at all. The marks cannot be recoloured; the ground can, which is what
   index.html already does with the same wall. Everything below is the light-ground value
   for something this lane put on the page. Amber #8A5E14 and ink #3D4B58 / #6B7885 are the
   values base.css and proof.css already use on `.paper` — not new colours. */
.paper .wallgroup>h3{color:#8A5E14}
.paper .wallgroup>p{color:#3D4B58}
.paper .markwall{border-top-color:rgba(22,32,43,.18)}
/* .legend was authored for deep water: --ink-muted body over --signal-gold labels, which
   measure 1.6:1 and 1.7:1 on Kernel White. The names list is the only .legend on a paper
   ground anywhere on the site, so this is scoped to that pairing and reaches no other. */
.paper .legend li{color:#3D4B58}
.paper .legend b{color:#8A5E14}
