/* fx-plant.css — the CLOSED-LOOP RING only, since 2026-08-25.
   This file used to carry two effects. The axonometric plant drawing (`.pl-*`, and the
   `.plantfig` / `.plantnote` chrome around it) was removed from smart-mill.html and its
   Malay twin when the eight stations became photographs, and 18 rule blocks were styling
   nothing from that moment on. They are deleted here rather than left as "harmless"
   bytes: a dead rule is indistinguishable from a live one to the next person reading it,
   and the drawing they describe no longer exists to check against.
   What remains is the `.rg-*` ring on the closed-loop section, which is still live. */

/* fx-plant.css — FX-02 "the plant" and FX-03 "the loop", both on /smart-mill/.
   Page-scoped; everything global stays in tokens/base/shell.

   ══ WHY THIS IS SVG AND NOT A CANVAS ═══════════════════════════════════════
   The gauntlet variant drew the plant as a hand-rolled orthographic canvas and
   argued — correctly — that a 460 KB 3D library loses to an axonometric you
   control. That half of the call is KEPT: the projection below is the same one
   (rot -0.62, tilt 1.03, orthographic, painter's-algorithm depth sort), and no
   library ships. What is OVERTURNED is the SURFACE, and the reason is measured
   rather than asserted:

     · The demo's own stylesheet reads `.stage{display:none}
/* the disclosure is PROSE, not a caption. Set as a `.cap` it was fourteen lines
   of 10.5px uppercase mono at 390px — a wall, and unreadable as the argument it
   is. The figure keeps a two-line caption; the provenance and the three things
   the drawing adds of its own — the numbering, what the amber line means, and
   which stations get a riser — are stated in sentences, in the page's own note
   register. */
.plantnote{margin-top:18px}
.plantbox{position:relative;border:1px solid var(--hairline-strong);border-radius:2px;
  background:var(--deep-water);padding:8px 10px 4px}

.pl-side{fill:var(--panel-navy);stroke:var(--hairline-strong);stroke-width:1}
.pl-top{fill:var(--panel-navy-2);stroke:var(--hairline-strong);stroke-width:1}
.pl-side-lit{fill:var(--panel-navy-2);stroke:var(--signal-gold);stroke-width:1}
/* CONTRAST HERE IS NOT COVERED BY qa/contrast.py — IT READS `color`, NOT `fill`,
   so every colour in this SVG sits outside the gate that protects the rest of the
   site. Computed by hand instead, and then measured off the rendered pixels:
     Signal Gold on FLAT AIREI Blue          3.48:1   <- FAILS AA
     Signal Gold on AIREI Blue at 62% over
     the panel tint underneath it            5.16:1   <- passes (sampled, not modelled)
   The lit numeral is 16 SVG units, ~14px as rendered, so WCAG "large text" does
   not apply and 3.48 is a real failure, not a rounding argument. The face keeps
   AIREI Blue and gives up saturation, which is the half that was decorative.
   (Ratios are quoted without their hex literals on purpose: brand-fit.py counts
   every hex in a file as a colour CHOICE, including ones that only appear in a
   comment explaining why a colour was rejected.)
   REPORTED to the integration lane: a checker that cannot see SVG is a checker
   that reports on the wrong thing for every drawing on the site. */
.pl-top-lit{fill:var(--airei-blue);fill-opacity:.62;stroke:var(--signal-gold);stroke-width:1.6}

/* 1.7 is not a box in the row. It is a translucent PLANE over the whole row,
   dropping a riser to each station whose brochure card names remote monitoring
   via MyPalm — FOUR of the seven, not all seven. The earlier "wired down to
   every station" was an inference the brochure does not support: 1.0, 1.3 and
   1.6 carry no monitoring bullet of any kind, and drawing them a riser anyway
   put an undisclosed assertion inside the one figure the page asks to be
   checked. Counted off the page's own verbatim bullets, and off brochure p3
   directly: 1.1, 1.2, 1.4, 1.5. Flat fill + a hairline + corner ticks: an
   instrument window, and specifically NOT backdrop-filter, which DESIGN.md §5
   bans by name and qa/motion-lint.py fails the build on. */
.pl-planefill{fill:var(--mill-navy);fill-opacity:.42;stroke:var(--airei-blue-lift);
  stroke-opacity:.62;stroke-width:1.4}
.pl-planetick{fill:none;stroke:var(--airei-blue-lift);stroke-opacity:.9;stroke-width:2}
.pl-planelab{font-family:var(--f-mono);font-size:13.5px;letter-spacing:.14em;
  fill:var(--ink-subtle);text-anchor:start}

/* ─── the small-screen key ────────────────────────────────────────────────
   The drawing carries labels at ~12.5 user units against a 1259.1-unit viewBox.
   Below 900px the box renders under ~420px wide and those labels land at ~4px —
   ink that cannot be read is not information. So the NAMES go and the NUMBERS
   are enlarged, and the rail directly beneath is the number→name key, which is
   the convention a real plant drawing uses.

   THIS BLOCK MUST STAY BELOW THE BASE RULES IT OVERRIDES, and that is not a
   style preference — it is the bug this comment replaced. It sat ABOVE
   `.pl-num` and `.pl-planelab` until 2026-08-24 and enlarged NOTHING: a media
   query adds no specificity, so at equal specificity the LATER rule won on
   source order and the numerals kept `font-size:16px`. Measured at a 390px
   viewport before the move: `.pl-num` computed 16px → 5.00px of rendered ink,
   `.pl-planelab` 13.5px → a 33.78 x 5.00px smear. Only `.pl-lab{display:none}`
   ever took effect, because nothing later redeclares `display` — and that one
   survivor is exactly what made a dead rule look like a working one.
   Measured after the move, same viewport: `.pl-num` 44px → 15.00px of ink. */
@media (max-width:900px){
  /* the plane keeps its NUMBER and loses its name — "1.7  DATA ROOM" at 40px
     would run clean across the roof of 1.2. The rail underneath is the key. */
  .pl-planename{display:none}
  /* 40/34, not 44/40. Sized by measurement at BOTH ends of the band, not at one:
     at 360px the numeral renders 13px of ink (the base 16px rendered 5px — the
     defect this block exists to fix), and at 899px, where the same user units
     render 3x larger, 44 spilled visibly off the roof of every volume. A
     point-in-polygon check of each numeral's ink box against its own `.pl-top`
     face is in the scratchpad note for this lane; 16px sits fully on the roof at
     desktop, which is the shape being preserved. */
  .pl-num{font-size:40px}
  .pl-planelab{font-size:34px}
}

/* Hover / current highlight. `fill` and `stroke` are NOT on the site's allowed
   transition-property list (qa/motion-allow.json), and widening that list to
   make a hover look nicer is the exact failure mode the harness exists to stop.
   So the lit state is a SECOND copy of the same faces at opacity 0, and opacity
   is what transitions — inside the 100-320ms interaction band. */
.pl-st:hover .pl-planelab,
.pl-st.is-current .pl-planelab{fill:var(--signal-gold)}
@media (prefers-reduced-motion:reduce){
}

.plantlegend{display:flex;flex-wrap:wrap;gap:6px 22px;margin:14px 0 0;padding:0;
  list-style:none;font-family:var(--f-mono);font-size:10.5px;letter-spacing:.12em;
  text-transform:uppercase;color:var(--ink-subtle)}
.plantlegend li{display:flex;align-items:center;gap:9px}
.plantlegend i{width:22px;height:0;border-top:2px solid var(--ink-subtle);
  display:inline-block;flex:none}
/* THE SWATCH CARRIES THE COLOUR; THE TEXT STAYS INK.
   Colouring the whole row put Crude Amber at 72% opacity behind 10.5px type —
   3.72:1 on Deep Water, and qa/contrast.py failed it on all six passes.
   Dimming a key to say "this one is weaker evidence" was the wrong instrument
   anyway: the DASH already says it, in the legend and in the drawing, and it
   says it at full contrast. */
.plantlegend .k-flow i{border-top-color:var(--crude-amber)}
.plantlegend .k-tele i{border-top-color:var(--airei-blue-lift);border-top-style:dashed}

/* ─── FX-03 · the loop ─────────────────────────────────────────────────── */
.loopgrid{display:grid;gap:clamp(26px,3.6vw,48px);grid-template-columns:minmax(0,1fr);
  align-items:center;margin-top:clamp(26px,3.4vw,44px)}
@media (min-width:900px){.loopgrid{grid-template-columns:minmax(0,.78fr) minmax(0,1.22fr)}
  /* left-aligned in its own column at desktop: centred, the ring floated 85px
     right of the replay button and the caption beneath it and the column read
     as two things. Centred is still right when it is the only thing in a
     single-column layout. */
  .ring{margin:0}}
.ringwrap{margin:0}
.ring{display:block;width:100%;max-width:420px;margin:0 auto}
.rg-track{fill:none;stroke:var(--hairline-strong);stroke-width:1.5}
.rg-arc{fill:none;stroke:var(--airei-blue-lift);stroke-width:3.5;stroke-linecap:butt}
.rg-ret{fill:none;stroke:var(--crude-amber);stroke-width:3.5;stroke-linecap:butt}
.rg-head{fill:var(--airei-blue-lift)}
.rg-head-ret{fill:var(--crude-amber)}
.rg-node{fill:var(--panel-navy);stroke:var(--hairline-strong);stroke-width:1.5}
.rg-n4 .rg-node{stroke:var(--signal-gold)}
/* authored LIT — the resolved state. The script removes the ink and puts it
   back; nothing here starts hidden, so no-JS and reduced-motion both land on
   the same finished drawing.
   The ring around a node is the SAME colour as the leg that LEAVES it, so gold
   is not spent four times over: three blue, one amber. (This comment read
   "arrives at it" until 2026-08-24 and described a drawing that does not exist:
   the leg arriving at node 4 is the blue arc, and the leg arriving at node 1 is
   the amber return, so under "arrives" node 4 would ring blue and node 1 amber
   — the exact inverse of every one of the four rings as drawn. The DRAWING was
   right and the sentence was wrong; the sentence is what changed.) A first pass rang
   all four in Signal Gold and the actuator — the one node the section is about —
   became the least distinguishable thing in the drawing. */
.rg-lit{fill:none;stroke:var(--airei-blue-lift);stroke-width:2;opacity:1}
.rg-n4 .rg-lit{stroke:var(--crude-amber)}
.rg-num{font-family:var(--f-mono);font-size:17px;font-weight:600;fill:var(--ink-muted);
  text-anchor:middle;dominant-baseline:central}
.rg-n4 .rg-num{fill:var(--signal-gold)}
.rg-core{font-family:var(--f-mono);font-size:10.5px;letter-spacing:.2em;
  fill:var(--ink-ghost);text-anchor:middle}
.rg-act{font-family:var(--f-mono);font-size:11.5px;letter-spacing:.13em;
  fill:var(--crude-amber);text-anchor:middle}

/* the steps: a vertical ledger, NOT four equal cards.
   DESIGN.md §8 lists "the three-icon rounded-square feature grid" as an AI tell
   and the same shape one column wider is the same tell; a numbered rule down the
   left is also simply the right register for a SEQUENCE, which four side-by-side
   boxes actively fight. */
.loop{list-style:none;margin:0;padding:0;display:block}
.loop li{position:relative;border:0;border-left:2px solid var(--hairline);border-radius:0;
  background:transparent;padding:13px 0 15px 20px;margin:0}
.loop li+li{margin-top:2px}
.loop .n{font-family:var(--f-mono);font-size:10.5px;font-weight:600;letter-spacing:.18em;
  text-transform:uppercase;color:var(--crude-amber)}
.loop h3{font-family:var(--f-body);font-weight:700;font-size:17px;letter-spacing:-0.0017em;
  line-height:1.3;margin:5px 0 0;color:var(--ink)}
.loop p{margin:7px 0 0;font-size:15px;line-height:1.55;color:var(--ink-muted);max-width:52ch}
.loop li:last-child{border-left-color:var(--crude-amber)}
.loop li:last-child .n,.loop li:last-child h3{color:var(--signal-gold)}

/* A sentence, not a label ("and the next reading starts the loop again"), so sentence case
   per .src-line in proof.css, and up to the 11px floor. */
/* 11px -> 12.5px, third pass (see `.stat .src`, base.css). The note above calls it a
   sentence and then set it at the label size; 11px was never a floor for reading, it was
   one rung below one. */
.ret-m{margin:16px 0 0;padding-left:20px;font-family:var(--f-mono);font-size:12.5px;
  letter-spacing:.02em;line-height:1.55;color:var(--crude-amber)}

/* ─── the replay controls ──────────────────────────────────────────────────
   A control with no script behind it is a dead button, so it does not exist
   until the script that runs it has finished wiring itself up. */
.fx-replay{display:none}
/* A control the reader is asked to press. 11px floor; the coarse-pointer rule below
   already takes it to 12px with a 44px target. */
.fx-js .fx-replay{display:inline-flex;align-items:center;gap:9px;
  font-family:var(--f-mono);font-size:11px;letter-spacing:.12em;text-transform:uppercase;
  background:transparent;color:var(--airei-blue-lift);border:1px solid var(--airei-blue);
  border-radius:2px;padding:9px 14px;cursor:pointer;margin-top:14px;
  transition:background var(--d2) var(--e-quad),color var(--d2) var(--e-quad),
             border-color var(--d2) var(--e-quad)}
@media (hover:hover) and (pointer:fine){
  .fx-js .fx-replay:hover{background:var(--airei-blue);color:var(--kernel-white);
    border-color:var(--airei-blue)}}
.fx-js .fx-replay:focus-visible{outline:2px solid var(--signal-gold);outline-offset:2px}
/* Under reduced motion the script hides the control with [hidden] — there is
   nothing for it to replay. That needed a rule: an explicit `display` on a
   class beats the UA sheet's `[hidden]{display:none}`, so the button stayed on
   screen and reduced-motion shipped a button that did nothing. Higher
   specificity, not !important. */
.fx-js .fx-replay[hidden]{display:none}
@media (prefers-reduced-motion:reduce){.fx-js .fx-replay{transition:none}}

/* ─── print ────────────────────────────────────────────────────────────────
   base.css inverts the whole palette to ink-on-paper for print, so the volumes
   come through as an outlined line drawing, which is what an axonometric wants
   to be on a sheet. Two things are removed rather than inverted: the ground grid
   (grey hatching a monochrome office printer turns to mud) and the lit overlay
   (a hover state that a script may have left switched on when the sheet was
   sent — it has no meaning on paper). */
@media print{
  .plantbox{border:1px solid rgba(16,24,32,.28);background:#fff}
  .fx-replay{display:none !important}
  .plantfig,.ringwrap,.loop li{break-inside:avoid;page-break-inside:avoid}
  .pl-top-lit,.pl-side-lit{display:none}
}

/* ── LOOP STEP ICONS ──────────────────────────────────────────────────────────────
   One drawn icon per step, animating inside its own SVG with SMIL — no JavaScript, so it
   keeps working with scripting off (it simply rests at a frame) and there is no observer to
   wire. Each is drawn from its own step: a sensor trace that pulses, a forecast running dashed
   ahead of the last real reading, a branch resolving to one correction, and a valve turning.
   The number moves into the same row as the icon so the step reads as one object. */
.loop li .n{display:flex;align-items:center;gap:14px;margin:0 0 12px}
.loop .lnum{display:inline-grid;place-items:center;width:24px;height:24px;flex:none;
  border:1px solid var(--hairline-strong);border-radius:50%;
  font:600 11.5px/1 var(--f-mono);color:var(--ink-ghost)}
/* The icon is the ANCHOR of the step, not a bullet beside the number — at 34px it read as
   decoration. Boxed, at 52px, on the panel ground, it is the first thing the eye lands on and
   the number becomes the small print it should be. */
.loop .li{width:32px;height:32px;flex:none;color:var(--airei-blue-lift)}
.loop .icb{display:inline-grid;place-items:center;width:52px;height:52px;flex:none;
  border:1px solid var(--hairline);background:var(--panel-navy)}
.loop li h3{margin:0 0 6px}
/* Reduced motion stops the drawing dead — SMIL ignores the media query, so the elements are
   hidden and the icon rests as a static line drawing, which is what it is underneath. */
@media (prefers-reduced-motion:reduce){
  .loop .li animate,.loop .li animateTransform,.loop .li animateMotion{display:none}
  .loop .li .fc{stroke-dashoffset:0}
}

/* CONTROL LABELS ON A PHONE. "Run the cycle again" is a real button — the only way to
   replay the diagram — and its label is set at 10.5px mono with .14em tracking, which is
   the site's fine-print register borrowed for a control. Measured at 390 in a real mobile
   context: 178x34. The tap floor is handled with the rest of the controls; this is the
   READING half of the same problem. 12px on a phone only — the desktop rhythm, where the
   button sits beside a 1112px diagram, is unchanged. */
@media (pointer:coarse) and (max-width:640px){
  .fx-js .fx-replay{font-size:12px;min-height:44px}
}
