/* ═══════════════════════════════════════════════════════════════════════════
   AMPACITIES · Interlock (PLC testing tool) · library/plc-testing/css/plc.css
   PLC-2 · the page shell. Page-scoped, `.plc-*` only. Touches no shared sheet.

   ── WHERE THIS SITS IN THE CASCADE ─────────────────────────────────────────
   /shared/_shared.css  →  /shared/site-chrome.css  →  /shared/calc-grouped.css
   →  /shared/glass-skin.css  →  THIS FILE  →  the page's own <style> (nothing).
   The tool is a standard calc-page card: `.vd-stage > .vd-suite.suite-wide >
   section.vd.plc-tool`. That buys the ivory editorial band, the near-black slab
   (#1a1a1e in BOTH themes — calc-grouped.css:58), the site chrome and the day/
   night toggle for free, and it is the shell PLC-4's calc-save/doc-card wiring
   expects.

   ── THE TOKEN TRAP, AND WHY EVERY --plc-* VALUE BELOW IS A LITERAL ─────────
   `--ink` is redeclared THREE times on the way down: ivory #faf9f5 on :root
   (night), near-black #141413 on [data-theme="day"], and #181a1f again inside
   `.vd` (calc-grouped.css:51). A drafting canvas that says `color: var(--ink)`
   therefore paints near-black on a near-black ground on the DEFAULT (day) page.
   The spike could get away with `--plc-ground: var(--bg-deepest)` because it was
   night-only and standalone; here that resolves to #e8e6dc and the whole ink
   ramp collapses to 1.19–2.50:1.

   So: the canvas pins the NIGHT ramp as literals, in both themes, deliberately.
   A ladder drawing is a dark drafting surface the way `.vd` itself is — the site
   already ships "fixed-dark panel inside a light page" as its house pattern.

   Contrast, recomputed with tests/unit/landing-contrast.test.mjs's own formula
   against the two grounds this file actually paints on
   (#262523 = canvas · #1a1a1e = the .vd slab):
     ivory  #faf9f5 → 14.54 / 16.47     soft   #d5d3cb → 10.22 / 11.57
     mute   #a09d94 →  5.65 /  6.40     copper #e08a66 →  5.83 /  6.61
     clay   #d97757 →  4.91 /  5.56     clay-sm #eb9d7e →  7.04 /  7.98
     fail   #ff5b50 →  5.01 /  5.67     pass   #93a877 →  5.91 /  6.70
   All AA-small (>= 4.5). The DAY clay ramp (#b0512f = 2.96:1, #cc6a47 = 4.17:1)
   is absent by construction and must never be carried onto this canvas.
   (The spike's own header block quoted 17.50/7.02 — those are the ratios against
   #141413, not #262523. Corrected here.)

   ── FOUR EXCLUSIVE COLOUR CHANNELS, AND ONLY FOUR ──────────────────────────
     copper  #e08a66   the active drop target / the armed tool
     ivory   #faf9f5   selection
     fail    #ff5b50   validation error
     voltage #8ab4e8   power flow — §3c-ii, PLC-3. RESERVED SINCE PLC-0 AND
                       UNUSED UNTIL NOW. It is the one channel that appears only
                       while a simulation is attached: with no trace, nothing
                       carries data-power and the canvas is byte-identical to
                       the authoring state, which is why adding it moves no
                       design-matrix baseline.
   No glow, no neon, no gradients (DESIGN-LANGUAGE.md §9). Validation is shape-
   coded as well as colour-coded (dash + ▲) so it survives grayscale, and power
   is shape-coded too — see §3c-ii, where the reason is measured rather than
   stylistic.

   ── FONTS ──────────────────────────────────────────────────────────────────
   No @font-face here. Poppins / Lora / JetBrains Mono are self-hosted and
   declared once in site-chrome.css:19-37 from /assets/landing/fonts/; linking
   that sheet is the entire cost. JetBrains Mono is TWO STATIC INSTANCES on
   purpose — Chromium's print-to-PDF embedder silently drops variable fonts.

   glass-skin.css:155 forces `font-family: var(--ff-sf) !important` on `.vd` and
   on every `input`/`select`/`button` inside it. Ordinary descendants merely
   INHERIT that, so a plain `.plc-tag { font-family: … }` wins outright. The form
   controls are the exception: `.vd-stage .vd button` is specificity (0,2,1), so a
   page-scoped `.plc-tool .plc-btn` at (0,2,0) loses even carrying !important —
   measured in the browser, not assumed. §2a is the one block in this file that
   reaches into the shared sheet's own scope to win at (0,3,0). It is the only
   coupling to glass-skin here; if that sheet ever drops the !important, §2a
   becomes redundant rather than wrong.

   That is also the whole of glass-skin's reach into this page: every other
   !important rule in it is scoped to `.dd` / `.field` / `.pj-fld` / `.vd-status`
   / `.tb-cell`, none of which this page uses.

   ── EVERY LEAF CLASS IS NAMESPACED, AND HERE IS WHY ────────────────────────
   `.btn` belonging to site-chrome is the famous one, but it is not the only one.
   `_shared.css:174` defines a GLOBAL `.warn` — a serif-italic callout with a
   copper left border and 8px/14px padding. A strip chip written as
   `.plc-tool .plc-strip .warn` out-specifies it only on the properties it
   actually declares; this file declared `color`, so the chip silently arrived
   wearing Instrument Serif italic inside a bordered box. Caught in a screenshot,
   not in review.

   Bare `.chip` `.nm` `.sc` `.k` `.l` `.num` `.t` are all live in shared/*.css
   too. So every leaf class this page owns carries the `plc-` prefix —
   `.plc-warn` `.plc-ok` `.plc-bad` `.plc-chip` `.plc-nm` `.plc-sc` `.plc-lb`
   `.plc-k` `.plc-l`. Scoping protects the properties you remember to declare;
   naming protects the ones you don't.

   ── HORIZONTAL OVERFLOW AT 375px ───────────────────────────────────────────
   The earthing-grid precedent, not the transformer one: a fixed well
   (`overflow: hidden`) around a viewBox SVG at `width:100%; height:auto`, so on
   a DESKTOP column the drawing scales rather than scrolls. Picked over the
   scroll pattern because the editor freezes units-per-pixel at gesture start and
   a horizontal scroller under a live drag would fight it. Every grid/flex
   ancestor carries min-width:0. `touch-action: pan-y` keeps one-finger vertical
   page-scroll working over the figure (the PC-chart lesson).

   BELOW 900px THAT REVERSES — see §3b-i. Scale-to-fit passes the 375px gate for
   the wrong reason (nothing overflows because everything shrank) while putting
   3px type and 24px touch targets on a phone. Narrow viewports get a 1:1
   drawing in a pan-x scroller instead. The drag concern does not follow it
   there: at 1:1 the scale is pinned, so a preview that widens the rung can no
   longer move content out from under the pointer — which was the whole reason
   units-per-pixel had to be frozen in the first place.
   ═══════════════════════════════════════════════════════════════════════════ */


/* ═══ 1 · The card ══════════════════════════════════════════════════════════
   `.plc-tool` is the page-scope root. Everything below is a descendant of it,
   so nothing in this file can reach the chrome, another calc, or the footer.  */

.plc-tool {
  /* ── the night ramp, pinned. Names are LOCAL (--plc-*) so they cannot
        collide with, or be overwritten by, _shared.css / calc-grouped.css. ── */
  --plc-ink:        #faf9f5;
  --plc-ink-soft:   #d5d3cb;
  --plc-ink-mute:   #a09d94;
  --plc-rule:       rgba(250, 249, 245, 0.10);
  --plc-rule-strong:rgba(250, 249, 245, 0.20);
  --plc-panel:      #1c1b1a;   /* --bg-deep,    night */
  --plc-panel-hi:   #201f1d;   /* --bg-card,    night */
  --plc-ground:     #262523;   /* --bg-deepest, night — the canvas well */
  --plc-copper:     #e08a66;   /* --amp-copper-night     */
  --plc-copper-deep:#d97757;   /* --amp-clay-text-night   */
  --plc-copper-sm:  #eb9d7e;   /* --amp-clay-small-night  */
  --plc-fail:       #ff5b50;   /* --amp-fail-night        */
  --plc-pass:       #93a877;   /* --amp-pass-night        */
  --plc-voltage:    #8ab4e8;   /* reserved: PLC-3 power flow */

  color: var(--plc-ink-soft);
}

.plc-tool * { box-sizing: border-box; }

/* head row — kept deliberately short. The e2e lane drags from a palette tile to
   a canvas slot with RAW viewport coordinates and no auto-scroll, so at
   1440x900 the tiles and the canvas must both sit above the fold. Every row
   added here pushes the canvas down. Long prose belongs under .plc-foot. */
.plc-tool .plc-head {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 14px; flex-wrap: wrap;
  padding: 2px 4px 10px; margin-bottom: 12px;
  border-bottom: 1px solid var(--plc-rule);
}
.plc-tool .plc-title {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap; min-width: 0;
}
.plc-tool .plc-title h1 {
  font-family: var(--chrome-sans); font-weight: 600; font-size: 17px;
  letter-spacing: -0.01em; color: var(--plc-ink); margin: 0;
}
.plc-tool .plc-title h1 em {
  font-family: var(--chrome-serif); font-style: italic; font-weight: 500;
  color: var(--plc-copper-deep);
}
.plc-tool .plc-title .plc-eyebrow {
  font-family: var(--chrome-mono); font-size: 9px; font-weight: 400;
  letter-spacing: 0.2em; text-transform: uppercase; color: var(--plc-ink-mute);
}
.plc-tool .plc-tools { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }


/* ═══ 1a · PLC-4 · the shared calc-save controls, on THIS page ══════════════
   The head row carries `vd-head` and `vd-tools`→`hr` so shared/calc-save.js can
   find a mount point (`.vd-head .hr`, falling back to `.vd-head`) and so
   ensureBanner() has an anchor. Both class names bring shared rules with them.

   `.vd .vd-head` is (0,2,0) and declares display/align-items/justify-content/
   gap/padding — every one of which `.plc-tool .plc-head` above also declares at
   (0,2,0), and this sheet loads last, so the head row needs no restatement.
   `.vd .vd-head .hr` (calc-grouped.css:73) is (0,3,0) and OUT-SPECIFIES
   `.plc-tool .plc-tools` at (0,2,0) — it would silently widen the tool row's gap
   from 6px to 14px. One selector at (0,3,0) is the whole fix.                */
.plc-tool .plc-head .plc-tools { gap: 6px; }

/* ── NO PRINTED REPORT UNTIL PLC-7 ─────────────────────────────────────────
   calc-save.js's mount() unconditionally injects a "Print / Save as PDF"
   button whose own title attribute promises "the audit-ready report", and
   calc-save.css swaps that report for a sign-in gate sheet when printing
   signed out. This page has no `.cahier-print` report to promise OR to gate —
   the Cahier report is PLC-7 (plan §5, Phase 2) — so on this page the button
   would be a claim the page cannot honour, and the gate sheet would print as a
   spurious extra page appended to the whole editor.

   Suppressed here rather than by editing shared/calc-save.js, which nine live
   calculators depend on. DELETE THIS BLOCK in the same commit that adds the
   report; the button and the gate become correct the moment it exists.       */
#vd-pdf-btn { display: none; }
@media print { body:not(.amp-can-print) > #amp-print-gate { display: none !important; } }

/* The document card sits BELOW the tool (see index.html for why) — so it needs
   the separation from the simulator that a top-mounted card gets for free. */
.plc-tool #amp-doc-card { margin-top: 18px; }


/* ═══ 2 · Controls ══════════════════════════════════════════════════════════
   site-chrome.css owns `.btn` (ink fill, min-width 240px) — the About-page
   lesson, plan §6 gotcha 9. Every CTA on this page is `.plc-btn`.            */

/* ── 2a · the ONE glass-skin override. See the header. Every selector here is
      (0,3,0) so it outranks `.vd-stage .vd input|select|button` at (0,2,1); a
      page-scoped `.plc-tool .plc-btn` at (0,2,0) does not, !important or not. ── */
.vd-stage .vd .plc-btn,
.vd-stage .vd .plc-select,
.vd-stage .vd .plc-tile,
.vd-stage .vd .plc-combo-input,
.vd-stage .vd .plc-span-bar button { font-family: var(--chrome-mono) !important; }

.plc-tool .plc-btn {
  font-family: var(--chrome-mono);
  font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  padding: 6px 12px; min-height: 30px;
  border: 1px solid var(--plc-rule-strong); border-radius: 2px;
  background: transparent; color: var(--plc-ink); cursor: pointer;
}
.plc-tool .plc-btn:hover:not(:disabled) { border-color: var(--plc-copper); color: var(--plc-copper); }
.plc-tool .plc-btn:focus-visible { outline: 2px solid var(--plc-copper); outline-offset: 1px; }
.plc-tool .plc-btn:disabled { opacity: 0.4; cursor: default; }
/* Undo / Redo are DIMMED, never `disabled` and never `aria-disabled`. A
   disabled button cannot be clicked, cannot be focused and — the point —
   cannot say WHY it did nothing; both attributes also fail a hit-tested click
   outright (tests/e2e/plc-editor.spec.mjs:718 clicks an exhausted Redo). An
   exhausted Redo is an operable control whose answer is "nothing to redo", and
   it narrates exactly that to #plc-a11y. */
.plc-tool .plc-btn[data-idle="1"] { opacity: 0.4; }
.plc-tool .plc-btn[data-idle="1"]:hover {
  border-color: var(--plc-rule-strong); color: var(--plc-ink);
}
.plc-tool .plc-btn--primary {
  border-color: var(--plc-copper); background: var(--plc-copper);
  color: #141413;                       /* near-black on copper = 7.02:1; white would be 3.12:1 */
}
.plc-tool .plc-btn--primary:hover:not(:disabled) {
  background: var(--plc-copper-sm); border-color: var(--plc-copper-sm); color: #141413;
}

.plc-tool .plc-select {
  font-family: var(--chrome-mono);
  font-size: 10px; letter-spacing: 0.08em;
  height: 30px; padding: 0 8px;
  border: 1px solid var(--plc-rule-strong); border-radius: 2px;
  background: var(--plc-panel); color: var(--plc-ink); cursor: pointer;
}
.plc-tool .plc-select:focus-visible { outline: 2px solid var(--plc-copper); outline-offset: 1px; }

/* 44px touch floor (calc-grouped.css:334 does the same for --ctl-h) */
@media (pointer: coarse) {
  .plc-tool .plc-btn, .plc-tool .plc-select { min-height: 44px; padding-block: 0; }
}

.plc-tool kbd {
  font-family: var(--chrome-mono); font-size: 9px; font-weight: 400;
  padding: 1px 4px; border: 1px solid var(--plc-rule-strong); border-radius: 2px;
  color: var(--plc-ink-soft); white-space: nowrap;
}


/* ═══ 3 · The work area ═════════════════════════════════════════════════════
   palette · canvas · tag register. min-width:0 everywhere so the grid children
   can shrink below their content — the documented 375px overflow-killer
   (library/transformer/index.html:25).                                        */

.plc-tool .plc-work {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr) 216px;
  gap: 14px;
  align-items: start;
}
@media (max-width: 1100px) { .plc-tool .plc-work { grid-template-columns: 120px minmax(0, 1fr); } }
@media (max-width: 760px)  { .plc-tool .plc-work { grid-template-columns: minmax(0, 1fr); } }

.plc-tool .plc-main,
.plc-tool .plc-side { min-width: 0; }

.plc-tool .plc-side h2,
.plc-tool .plc-sublabel {
  font-family: var(--chrome-mono); font-weight: 400;
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--plc-ink-mute); margin: 0 0 8px;
}
.plc-tool .plc-side-note {
  margin-top: 10px;
  font-family: var(--chrome-mono); font-size: 9.5px; line-height: 1.7;
  color: var(--plc-ink-mute);
}


/* ── 3a · palette ────────────────────────────────────────────────────────── */

.plc-tool .plc-palette { display: flex; flex-direction: column; gap: 7px; min-width: 0; }
@media (max-width: 760px) { .plc-tool .plc-palette { flex-direction: row; flex-wrap: wrap; } }

.plc-tool .plc-tile {
  font-family: var(--chrome-mono);
  width: 100%; max-width: 132px; min-height: 62px; padding: 5px 4px 6px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  background: var(--plc-panel);
  border: 1px solid var(--plc-rule-strong); border-radius: 4px;
  color: var(--plc-ink-soft);
  cursor: grab; touch-action: none; user-select: none;
}
.plc-tool .plc-tile:hover { border-color: var(--plc-copper); color: var(--plc-ink); }
.plc-tool .plc-tile:focus-visible { outline: 2px solid var(--plc-copper); outline-offset: 1px; }
.plc-tool .plc-tile[data-armed] {
  border-color: var(--plc-copper);
  background: color-mix(in srgb, var(--plc-copper) 12%, var(--plc-panel));
  color: var(--plc-ink);
}
.plc-tool .plc-tile svg { display: block; width: 52px; height: 24px; overflow: visible; }
.plc-tool .plc-tile-mn {
  font-size: 9.5px; letter-spacing: 0.12em; color: var(--plc-ink-mute);
}
.plc-tool .plc-tile[data-armed] .plc-tile-mn { color: var(--plc-copper-sm); }
.plc-tool .plc-tile-nm {
  font-size: 8.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--plc-ink-mute); opacity: 0.8;
}
.plc-tool .plc-tile-key {
  font-size: 8.5px; letter-spacing: 0.08em; color: var(--plc-copper-sm); opacity: 0.85;
}
/* the tile's own glyph preview reuses the canvas glyph classes */
.plc-tool .plc-tile .plc-bar,
.plc-tool .plc-tile .plc-arc,
.plc-tool .plc-tile .plc-slash { stroke: currentColor; }


/* ── 3b · THE CANVAS ─────────────────────────────────────────────────────────
   A dark drafting well inside the dark card — the library/earthing-grid
   `.eg-stage` pattern (index.html:195-206), with the ground pinned instead of
   theme-following, for the reason in the header.

   The numeric --plc-* tokens are the LAYOUT CONSTANTS ui/render.mjs reads back
   through readMetrics(). CHANGE THEM HERE, NOT IN JS — and re-run the crux-band
   sweep afterwards. One "obviously local" geometry fix in the spike silently
   shrank the branch drop band from 66 units to 52 and the whole drag arm stopped
   producing a parallel, with nothing failing loudly (interaction note §8.3).   */

.plc-tool .plc-canvas-wrap { position: relative; min-width: 0; }

.plc-tool .plc-canvas {
  /* drawing colours */
  --plc-wire:        var(--plc-ink-soft);
  --plc-wire-dim:    var(--plc-ink-mute);
  --plc-rail:        var(--plc-ink-mute);

  /* stroke weights — earthing-grid: 1.5 conductors, 2.5 emphasis */
  --plc-w-wire:  1.5;
  --plc-w-rail:  2;
  --plc-w-glyph: 1.8;

  /* layout constants, read by render.mjs readMetrics() */
  --plc-cell-w:      96;
  --plc-lane-h:      64;    /* 56 in the spike spec; 64 keeps a stacked branch's
                               tag baseline clear of the lane above's mnemonic —
                               measured, not guessed */
  --plc-par-pad:     16;
  --plc-lead-in:     56;
  --plc-lead-out:    96;
  --plc-lane-gap:    20;
  --plc-rung-pad-y:  26;
  --plc-rung-gap:    18;
  --plc-hit:         12;
  --plc-glyph-grab:   6;
  --plc-min-inner-w: 760;   /* 760, not 560: a rung that grows past the minimum
                               re-scales the SVG and moves the pointer out from
                               under its own live preview. 760 is wide enough
                               that the whole seal-in never changes the scale.
                               The editor also freezes units-per-pixel at drag
                               start — belt and braces. */

  position: relative;
  padding: 8px;
  border: 1px solid var(--plc-rule);
  border-radius: 12px;
  background: var(--plc-ground);
  overflow: hidden;                       /* the 375px guard; see the header */
}

@media (pointer: coarse) {
  .plc-tool .plc-canvas {
    --plc-cell-w:  108;
    --plc-lane-h:   72;
    --plc-hit:      18;
    --plc-lane-gap: 24;
    --plc-glyph-grab: 10;
  }
}

.plc-tool .plc-canvas .plc-svg {
  display: block; width: 100%; height: auto;
  touch-action: pan-y;                    /* one-finger vertical = page scroll */
}

/* ── 3b-i · NARROW VIEWPORTS PAN, THEY DO NOT SHRINK ────────────────────────
   `width:100%` over a fixed viewBox scales the whole drawing to the column. On
   a phone that took the seal-in to 0.347×: 9px slot labels rendered at 3.1 CSS
   px (grey smudges, measured) and the coarse-pointer hit pads — which are
   declared in SVG USER UNITS, so the same scale shrinks them — came out
   36 × 24 CSS px, against the 44px touch floor enforced on .plc-btn at line 198
   of this file. The coarse tokens were applied and ineffective on the one
   surface that matters.

   The 375px gate could not see any of it: `scrollWidth <= clientWidth` passed
   BECAUSE the content shrank rather than overflowed. So the fix is not a bigger
   token, it is refusing to scale below 1:1 — the drawing keeps its natural size
   (published by render.mjs as --plc-svg-natural-w) and the canvas pans, which is
   the same answer this repo already gives a wide table. At 1:1 the coarse tokens
   finally mean what they say: hit pad 104 × 68 CSS px, labels 9 CSS px.

   Scoped to narrow viewports on purpose. Above this breakpoint the column is
   wide enough that scale ≈ 1 anyway, and introducing a scroller there would
   change every desktop design-matrix shot for no legibility gain. */
@media (max-width: 900px) {
  .plc-tool .plc-canvas {
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;       /* panning the ladder never navigates back */
  }
  .plc-tool .plc-canvas .plc-svg {
    min-width: var(--plc-svg-natural-w, 0px);
    touch-action: pan-x pan-y;            /* one finger pans the ladder AND the page */
  }
}
.plc-tool .plc-canvas:focus-visible { outline: 2px solid var(--plc-copper); outline-offset: 2px; }

/* the overlay hosts the tag combobox and the span toolbar. Inert by default;
   its children opt back in. */
.plc-tool .plc-overlay { position: absolute; inset: 0; pointer-events: none; z-index: 5; }
.plc-tool .plc-overlay > * { pointer-events: auto; }


/* ── 3c · rails, conductors, glyphs ──────────────────────────────────────── */

.plc-tool .plc-rail {
  stroke: var(--plc-rail); stroke-width: var(--plc-w-rail); stroke-linecap: square;
}
.plc-tool .plc-wire {
  stroke: var(--plc-wire); stroke-width: var(--plc-w-wire); stroke-linecap: butt; fill: none;
}
.plc-tool .plc-branch-rail {
  stroke: var(--plc-wire); stroke-width: var(--plc-w-wire); stroke-linecap: round;
}

.plc-tool .plc-el-box { fill: none; stroke: none; }
.plc-tool .plc-bar,
.plc-tool .plc-arc {
  stroke: var(--plc-ink); stroke-width: var(--plc-w-glyph); stroke-linecap: round; fill: none;
}
.plc-tool .plc-slash {
  stroke: var(--plc-ink); stroke-width: var(--plc-w-glyph); stroke-linecap: round;
}
.plc-tool .plc-coil-letter {
  fill: var(--plc-ink); font-family: var(--chrome-mono); font-size: 11px; font-weight: 500;
  text-anchor: middle;
}
.plc-tool .plc-hit { fill: transparent; pointer-events: all; cursor: grab; }
.plc-tool .plc-node:active .plc-hit { cursor: grabbing; }

/* ── 3c-i · DECORATION IS NOT A HIT TARGET ───────────────────────────────────
   The rung layer paints ABOVE the slot layer (so a glyph always wins a
   contested point), which means every painted stroke in it competes for the
   pointer. A rung's conductors, rails, gutter, numbers and labels are
   DECORATION: an empty rung's full-width `.plc-wire` runs straight through the
   centre of its own caret slot, and because SVG strokes default to
   `pointer-events: visiblePainted` it was winning — document.elementFromPoint
   returned the wire, so the slot was unclickable to any hit-tested click
   (Playwright's `slot.click()` times out on exactly this).

   The rule is the interaction note's: anything above interactive content is
   inert until proven otherwise. The ONLY hit targets inside a rung are an
   element's `.plc-hit` pad and its glyph strokes. Everything else opts out. */
.plc-tool .plc-power,
.plc-tool .plc-rail,
.plc-tool .plc-wires,
.plc-tool .plc-wire,
.plc-tool .plc-branch-rails,
.plc-tool .plc-branch-rail,
.plc-tool .plc-gutter,
.plc-tool .plc-rung-no,
.plc-tool .plc-rung-comment,
.plc-tool .plc-par-box,
.plc-tool .plc-el-box,
.plc-tool .plc-tag,
.plc-tool .plc-mn,
.plc-tool .plc-flag { pointer-events: none; }


/* ── 3c-ii · POWER FLOW ──────────────────────────────────────────────────────
   The §3.6 trace, painted. ui/render.mjs gives every conductor a trace address
   and paintFlow() writes `data-power="1"|"0"` on it; nothing here computes
   anything and nothing here appears unless a simulation is attached.

   ── "0" MEANS NOT CARRYING. IT DOES NOT MEAN OPEN ──────────────────────────
   Semantics rev E §3.6 is normative: an instruction handler returns false the
   moment its rung-in is false, so a CLOSED contact on a dead rung is
   indistinguishable from an open one and renders identically. That is why the
   unpowered state is a DIM version of the resting conductor and not a new
   shape: a dashed or broken glyph would say "this contact is open", which this
   instrument does not know. The legend PLC-4 ships must say "not carrying".

   ── WHY WIDTH AND NOT ONLY COLOUR ──────────────────────────────────────────
   Measured against the pinned canvas ground (#262523) with the same formula
   tests/unit/landing-contrast.test.mjs uses:
     voltage #8ab4e8  →  7.12:1        (AA-small, comfortably)
     wire    #d5d3cb  → 10.22:1        ← the RESTING conductor
     dim     #a09d94  →  5.65:1
   So the live colour is genuinely DARKER than the wire it replaces — colour
   alone would read as recessive, the exact opposite of the intent, and would
   vanish entirely in grayscale. The live channel is therefore carried by stroke
   width as well (1.5 → 2.6, a 1.73× step), which is also the convention every
   online ladder monitor already uses. Unpowered conductors drop to the dim ramp
   so the carrying path is the brightest AND the heaviest thing on the rung.

   ── PRECEDENCE ─────────────────────────────────────────────────────────────
   This block sits BEFORE §3e on purpose. The glyph rules here and the
   validation rules there are both (0,4,0), so source order decides and
   validation wins: a rung that is carrying power while holding an error still
   reads as an error. §3h's drag preview outranks both, as it should — an
   authoring gesture in flight is not a measurement.                           */

.plc-tool .plc-canvas {
  --plc-w-wire-live:  2.6;
  --plc-w-glyph-live: 2.6;
}

.plc-tool .plc-wire[data-power="1"],
.plc-tool .plc-branch-rail[data-power="1"] {
  stroke: var(--plc-voltage); stroke-width: var(--plc-w-wire-live);
}
.plc-tool .plc-wire[data-power="0"],
.plc-tool .plc-branch-rail[data-power="0"] {
  stroke: var(--plc-wire-dim);
}

.plc-tool .plc-node[data-power="1"] .plc-bar,
.plc-tool .plc-node[data-power="1"] .plc-arc,
.plc-tool .plc-node[data-power="1"] .plc-slash {
  stroke: var(--plc-voltage); stroke-width: var(--plc-w-glyph-live);
}
.plc-tool .plc-node[data-power="0"] .plc-bar,
.plc-tool .plc-node[data-power="0"] .plc-arc,
.plc-tool .plc-node[data-power="0"] .plc-slash {
  stroke: var(--plc-wire-dim);
}

/* The tag and the mnemonic are IDENTITY, not state, and they stay put. Tying
   them to power would make a de-energised rung's labels read as disabled — and
   the tag is exactly what an engineer is trying to read while the sim runs. */


/* ── 3d · labels ─────────────────────────────────────────────────────────── */

.plc-tool .plc-tag {
  fill: var(--plc-ink); font-family: var(--chrome-mono); font-size: 11px;
  font-weight: 500; letter-spacing: 0.01em;
}
.plc-tool .plc-tag--empty { fill: var(--plc-ink-mute); }
.plc-tool .plc-mn {
  fill: var(--plc-ink-mute); font-family: var(--chrome-mono); font-size: 9px;
  font-weight: 400; letter-spacing: 0.14em;
}
.plc-tool .plc-rung-no {
  fill: var(--plc-ink-mute); font-family: var(--chrome-mono); font-size: 9.5px;
  letter-spacing: 0.08em;
}
.plc-tool .plc-rung-comment {
  fill: var(--plc-ink-mute); font-family: var(--chrome-serif); font-style: italic; font-size: 11px;
}


/* ── 3e · validation ─────────────────────────────────────────────────────────
   Three tiers. `error` and `warning` come from AmpPlc.validate(); `pending` is
   an EDITOR-ONLY focus demotion applied while the caret sits inside the
   offending construct. The canvas must NOT light red at the instant a
   first-timer is most fragile — the e2e spec pins this
   (tests/e2e/plc-editor.spec.mjs:698: zero [data-issue="error"] while a
   placement's tag box is open). Shape-coded (dash + ▲) as well as colour-coded
   so the state survives grayscale — the report kit's rule.                    */

.plc-tool .plc-node[data-issue="pending"] .plc-bar,
.plc-tool .plc-node[data-issue="pending"] .plc-arc,
.plc-tool .plc-node[data-issue="pending"] .plc-slash { stroke: var(--plc-ink-mute); }
.plc-tool .plc-node[data-issue="pending"] .plc-tag   { fill: var(--plc-ink-mute); }

.plc-tool .plc-node[data-issue="warning"] .plc-tag--empty { fill: var(--plc-ink-mute); }

.plc-tool .plc-node[data-issue="error"] .plc-bar,
.plc-tool .plc-node[data-issue="error"] .plc-arc,
.plc-tool .plc-node[data-issue="error"] .plc-slash {
  stroke: var(--plc-fail); stroke-dasharray: 3 2;
}
.plc-tool .plc-node[data-issue="error"] .plc-tag { fill: var(--plc-fail); }
.plc-tool .plc-flag   { fill: var(--plc-fail); font-family: var(--chrome-mono); font-size: 9px; }
.plc-tool .plc-gutter { fill: var(--plc-fail); }

.plc-tool .plc-par-box { fill: none; stroke: none; }
.plc-tool .plc-node.plc-par[data-issue="error"] .plc-par-box {
  stroke: var(--plc-fail); stroke-dasharray: 3 2;
}


/* ── 3f · selection + caret ──────────────────────────────────────────────────
   Ivory is the selection channel; copper is reserved for the active drop target
   and never appears here.

   `pointer-events: none` on the whole cursor layer is LOAD-BEARING (Phase 0
   review §7-2). The layer paints after the rungs, so without it a click on an
   already-selected element hit `rect.plc-sel`, `closest('.plc-node')` returned
   null, the selection collapsed to a bare caret — and the ⑂ Branch span toolbar,
   the gate's declared insurance path, went with it. Decoration must never be a
   hit target. ui/editor.mjs carries the elementsFromPoint() fallback as well.  */

.plc-tool .plc-cursor,
.plc-tool .plc-sel,
.plc-tool .plc-caret,
.plc-tool .plc-caret-tick,
.plc-tool .plc-ghost,
.plc-tool .plc-branch-label { pointer-events: none; }

.plc-tool .plc-sel {
  fill: rgba(250, 249, 245, 0.07);
  stroke: var(--plc-ink); stroke-width: 1; stroke-opacity: 0.55;
}
.plc-tool .plc-caret-tick { stroke: var(--plc-ink); stroke-width: 2; stroke-linecap: round; }
.plc-tool .plc-caret { animation: plc-blink 1.15s steps(2, start) infinite; }
@keyframes plc-blink { 0%, 60% { opacity: 1; } 61%, 100% { opacity: 0.28; } }


/* ── 3g · the latent slot field ──────────────────────────────────────────────
   Latent slots stay IN THE DOM and are hidden with `style.display = 'none'`
   (SVGElement.hidden does not reflect — the earthing-grid lesson), which is
   also exactly what the e2e lane's liveSlotKeys() reads
   (getComputedStyle(el).display !== 'none').

   NOTE THE DELIBERATE DIVERGENCE FROM THE SPIKE: css/spike.css:332 put
   `pointer-events: none` on the whole `.plc-slots` layer. That would make
   Playwright's `slot.click()` time out — its hit-target check requires
   document.elementFromPoint to return the slot or a descendant. Here the GROUP
   is inert and only the transparent hit rect takes pointer events, so a live
   slot is clickable while its decoration is not. The slot layer is painted
   BENEATH the node layer so an element glyph always wins a contested point.    */

.plc-tool .plc-slots { pointer-events: none; }
.plc-tool .plc-slot  { pointer-events: none; }
.plc-tool .plc-slot-hit { fill: transparent; pointer-events: all; cursor: copy; }
.plc-tool .plc-slot-tick,
.plc-tool .plc-slot-lane,
.plc-tool .plc-slot-gap,
.plc-tool .plc-slot-label { pointer-events: none; }

.plc-tool .plc-slot-tick { stroke: var(--plc-ink); stroke-opacity: 0.35; stroke-width: 2; stroke-linecap: round; }
.plc-tool .plc-slot-lane { stroke: var(--plc-copper); stroke-opacity: 0.30; stroke-width: 1; stroke-dasharray: 5 3; }

/* The rung-gap slot had no affordance in the spike beyond a faint dashed rule
   (interaction note §9.1 row 7, "cheap fix at PLC-2"). It now carries a label
   like every other lane, and its rule is a touch more present. */
.plc-tool .plc-slot-gap  { stroke: var(--plc-ink); stroke-opacity: 0.28; stroke-width: 1; stroke-dasharray: 4 4; }

/* The lane label is the entire onboarding for the branch gesture — but it only
   earns its place on the ACTIVE lane. Rendering it on every latent lane at once
   collides with the element tags and reads as noise. */
.plc-tool .plc-slot-label {
  fill: var(--plc-copper); fill-opacity: 0;
  font-family: var(--chrome-mono); font-size: 9px; letter-spacing: 0.12em;
  transition: fill-opacity 90ms ease-out;
}

/* the active drop target — the ONE copper thing on the canvas at any instant */
.plc-tool .plc-slot[data-active] .plc-slot-tick  { stroke: var(--plc-copper); stroke-opacity: 1; stroke-width: 2.5; }
.plc-tool .plc-slot[data-active] .plc-slot-lane  { stroke-opacity: 1; stroke-width: 1.5; }
.plc-tool .plc-slot[data-active] .plc-slot-gap   { stroke: var(--plc-copper); stroke-opacity: 1; }
.plc-tool .plc-slot[data-active] .plc-slot-label { fill-opacity: 1; }
.plc-tool .plc-slot--branch:hover .plc-slot-label,
.plc-tool .plc-slot--gap:hover .plc-slot-label { fill-opacity: 0.7; }


/* ── 3h · drag ghost + live preview ──────────────────────────────────────────
   The preview is a REAL node in a structuredClone shadow, so the rung re-lays
   itself out under the pointer and a branch lane materialises before release.
   `phantom` is the lane opened by ⌥↓ / ⑂ Branch: same shadow, glyph hidden, so
   the lane reads as empty even though the IR never holds an empty branch.      */

.plc-tool .plc-ghost { pointer-events: none; }
.plc-tool .plc-ghost .plc-bar,
.plc-tool .plc-ghost .plc-arc,
.plc-tool .plc-ghost .plc-slash {
  stroke: var(--plc-copper); stroke-width: var(--plc-w-wire);
  stroke-dasharray: 4 3; opacity: 0.55;
}
.plc-tool .plc-ghost .plc-tag,
.plc-tool .plc-ghost .plc-mn { fill: var(--plc-copper); opacity: 0.55; }

.plc-tool .plc-node[data-preview] .plc-bar,
.plc-tool .plc-node[data-preview] .plc-arc,
.plc-tool .plc-node[data-preview] .plc-slash {
  stroke: var(--plc-copper); stroke-dasharray: 4 3; opacity: 0.62;
}
.plc-tool .plc-node[data-preview] .plc-tag,
.plc-tool .plc-node[data-preview] .plc-mn { fill: var(--plc-copper); opacity: 0.62; }
.plc-tool .plc-node[data-preview="phantom"] .plc-glyph,
.plc-tool .plc-node[data-preview="phantom"] .plc-tag,
.plc-tool .plc-node[data-preview="phantom"] .plc-mn { display: none; }

.plc-tool .plc-branch-label {
  fill: var(--plc-copper); font-family: var(--chrome-mono); font-size: 9px; letter-spacing: 0.12em;
}
.plc-tool .plc-rung:has(.plc-node[data-preview]) .plc-branch-rail { stroke: var(--plc-wire); }

/* smooth the re-layout when a phantom lane opens — 90ms, transforms only */
.plc-tool .plc-rung,
.plc-tool .plc-node { transition: transform 90ms ease-out; }

/* One switch for every motion on the page. The design-matrix harness runs with
   reducedMotion:'reduce', so anything that survives this makes the shots
   non-deterministic. */
@media (prefers-reduced-motion: reduce) {
  .plc-tool .plc-caret,
  .plc-tool .plc-rung,
  .plc-tool .plc-node,
  .plc-tool .plc-slot-label { animation: none !important; transition: none !important; }
}


/* ═══ 4 · The span toolbar and the combobox ═════════════════════════════════
   Both are created by ui/editor.mjs into .plc-overlay. Styled here so the
   editor never writes a style attribute for anything but position.            */

.plc-tool .plc-span-bar {
  position: absolute; z-index: 6;
  display: flex; gap: 2px; padding: 2px; white-space: nowrap;
  background: var(--plc-panel); border: 1px solid var(--plc-rule-strong);
  border-radius: 3px; box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
}
.plc-tool .plc-span-bar button {
  font-family: var(--chrome-mono);
  font-size: 9.5px; letter-spacing: 0.06em; white-space: nowrap;
  padding: 4px 8px; min-height: 24px; border: 0; border-radius: 2px; cursor: pointer;
  background: transparent; color: var(--plc-ink-soft);
}
/* the ⑂ Branch chip is the gate's insurance path — it may read as the primary */
.plc-tool .plc-span-bar button:first-child { color: var(--plc-copper-sm); }
.plc-tool .plc-span-bar button:hover {
  background: color-mix(in srgb, var(--plc-copper) 18%, transparent); color: var(--plc-ink);
}
@media (pointer: coarse) { .plc-tool .plc-span-bar button { min-height: 44px; padding-inline: 12px; } }

.plc-tool .plc-combo {
  position: absolute; z-index: 7; width: 240px; max-width: calc(100% - 8px);
  background: var(--plc-panel-hi); border: 1px solid var(--plc-rule-strong);
  border-radius: 3px; box-shadow: 0 8px 26px rgba(0, 0, 0, 0.5);
}
.plc-tool .plc-combo-input {
  font-family: var(--chrome-mono);
  width: 100%; padding: 8px 10px; font-size: 12px;
  color: var(--plc-ink); background: transparent;
  border: 0; border-bottom: 1px solid var(--plc-rule); outline: none;
}
.plc-tool .plc-combo-input::placeholder { color: var(--plc-ink-mute); }
.plc-tool .plc-combo-list { max-height: 292px; overflow: auto; }
.plc-tool .plc-combo-row {
  display: flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 10px; cursor: pointer;
  white-space: nowrap; overflow: hidden;
  font-family: var(--chrome-mono); font-size: 11.5px; color: var(--plc-ink-soft);
}
@media (pointer: coarse) { .plc-tool .plc-combo-row { height: 44px; } }
.plc-tool .plc-combo-row[aria-selected="true"] {
  background: color-mix(in srgb, var(--plc-copper) 14%, transparent); color: var(--plc-ink);
}
.plc-tool .plc-combo-row .plc-lb { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.plc-tool .plc-combo-row .plc-sc { color: var(--plc-ink-mute); font-size: 11px; }
.plc-tool .plc-combo-row .plc-chip {
  font-size: 9px; letter-spacing: 0.08em; color: var(--plc-ink-mute);
  border: 1px solid var(--plc-rule-strong); border-radius: 2px; padding: 0 3px;
}
.plc-tool .plc-combo-row--create { color: var(--plc-copper-sm); }
/* the ＋ Create row's type / scope pickers. They carry the defaults inferred
   from context, so ⏎ alone finishes the job — they exist to be overridden, not
   to be visited. The UA default select is a fourth colour channel on a page
   that allows exactly three. */
.plc-tool .plc-combo-sel {
  font-family: var(--chrome-mono); font-size: 9px; letter-spacing: 0.06em;
  height: 18px; padding: 0 2px; max-width: 84px;
  border: 1px solid var(--plc-rule-strong); border-radius: 2px;
  background: var(--plc-panel); color: var(--plc-ink-soft); cursor: pointer;
}
@media (pointer: coarse) { .plc-tool .plc-combo-sel { height: 30px; font-size: 11px; } }
.plc-tool .plc-combo-foot {
  padding: 6px 10px; border-top: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 9px; line-height: 1.5; color: var(--plc-ink-mute);
}


/* ═══ 5 · Document strip · message line · hint strip ════════════════════════
   #plc-strip is the document truth ("2 rungs · 4 tags · no issues").
   #plc-msg is the refusal channel: if the tool declines to do what was asked,
   the reason is part of the interface (interaction note §8.3). Messages persist
   ~6 s or until the next user action, and every one is mirrored to #plc-a11y.  */

.plc-tool .plc-strip {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
  margin-top: 9px; padding: 7px 11px;
  border: 1px solid var(--plc-rule); border-radius: 8px;
  background: color-mix(in srgb, var(--plc-copper) 6%, transparent);
  font-family: var(--chrome-mono); font-size: 10.5px; letter-spacing: 0.02em;
  color: var(--plc-ink-mute);
}
.plc-tool .plc-strip b    { color: var(--plc-ink); font-weight: 500; }
.plc-tool .plc-strip .plc-bad { color: var(--plc-fail); font-weight: 500; }
.plc-tool .plc-strip .plc-warn { color: var(--plc-copper-sm); font-weight: 500; }
.plc-tool .plc-strip .plc-ok { color: var(--plc-pass); font-weight: 500; }

.plc-tool .plc-msg {
  min-height: 1.4em; margin: 7px 0 0;
  font-family: var(--chrome-mono); font-size: 10.5px; letter-spacing: 0.02em;
  color: var(--plc-ink-mute);
}
.plc-tool .plc-msg[data-sev="error"]   { color: var(--plc-fail); }
.plc-tool .plc-msg[data-sev="warning"] { color: var(--plc-copper-sm); }

.plc-tool .plc-hint {
  min-height: 1.5em; margin: 3px 0 0;
  font-family: var(--chrome-mono); font-size: 10px; letter-spacing: 0.04em;
  color: var(--plc-ink-mute); text-align: center;
}
.plc-tool .plc-hint em { font-family: var(--chrome-serif); font-style: italic; color: var(--plc-ink-soft); }
/* The hint strip is a real preference AND the Phase 0 §3.4 gate-arm switch:
   the discovery trial runs each tester once with it and once without. */
.plc-tool[data-hints="0"] .plc-hint { visibility: hidden; }

.plc-tool .plc-arms {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 10px; padding-top: 9px; border-top: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 9.5px; color: var(--plc-ink-mute);
}
.plc-tool .plc-arms label { display: flex; align-items: center; gap: 6px; cursor: pointer; }
/* the UA default check is system blue, which is a fourth colour channel on a
   page that allows exactly three */
.plc-tool .plc-arms input[type="checkbox"] {
  accent-color: var(--plc-copper); width: 13px; height: 13px; margin: 0;
}


/* ═══ 6 · Tag register ══════════════════════════════════════════════════════ */

.plc-tool .plc-tags { min-width: 0; }
.plc-tool .plc-tag-row {
  display: flex; align-items: baseline; gap: 6px;
  padding: 4px 0; border-bottom: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 11px; color: var(--plc-ink-soft);
}
.plc-tool .plc-tag-row .plc-nm { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.plc-tool .plc-tag-row .plc-chip {
  font-size: 8.5px; letter-spacing: 0.08em; color: var(--plc-ink-mute);
  border: 1px solid var(--plc-rule-strong); border-radius: 2px; padding: 0 3px;
}
.plc-tool .plc-tag-row .plc-sc { font-size: 10px; color: var(--plc-ink-mute); }
.plc-tool .plc-tag-row[data-unused] { opacity: 0.55; }
.plc-tool .plc-tag-row[data-fresh] {
  color: var(--plc-copper-sm);
  background: color-mix(in srgb, var(--plc-copper) 12%, transparent);
}
.plc-tool .plc-tags-empty {
  font-family: var(--chrome-mono); font-size: 9.5px; line-height: 1.7; color: var(--plc-ink-mute);
}


/* ═══ 6b · The simulator panel (PLC-3) ══════════════════════════════════════
   Transport · I/O rack · watch table · speed. Inside `.plc-tool` because
   ownsKeyboard() is a containment test against that root — a panel styled into
   place outside it would look right and be keyboard-dead.

   COLOUR. No fifth channel is introduced. `--plc-voltage` is the power channel
   declared at line 128 and reserved since PLC-0; a lamp reading TRUE is
   carrying, which is what that channel means, so it is the same channel doing
   the same job off-canvas. Everything else here is the ink ramp plus copper for
   an accent, fail for a refusal and pass for nothing at all.

   GRAYSCALE. Per the §grayscale rule this file sets itself for validation, a
   true/false lamp is shape-coded as well as colour-coded: ● filled versus ○
   hollow, so the rack survives a monochrome print and a colour-blind reader.

   TOUCH. §2 puts a 44px floor under `.plc-btn` on coarse pointers. The controls
   this panel adds — the switches, the number fields and the SPEED SLIDER'S
   THUMB — are new surfaces and take the same floor explicitly. A range input's
   thumb does not inherit anything, and a 12px thumb is unusable on a phone
   whatever the track's height says.                                          */

.plc-tool .plc-sim {
  margin-top: 14px; padding: 12px 13px 11px;
  border: 1px solid var(--plc-rule); border-radius: 10px;
  background: var(--plc-panel);
}
.plc-tool .plc-sim-head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  padding-bottom: 10px; border-bottom: 1px solid var(--plc-rule);
}
.plc-tool .plc-sim-head h2 {
  font-family: var(--chrome-mono); font-weight: 400;
  font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
  color: var(--plc-ink-mute); margin: 0; flex: 0 0 auto;
}
.plc-tool .plc-sim-transport { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }
.plc-tool .plc-sim-transport .plc-btn { display: inline-flex; align-items: center; gap: 7px; }
/* the key chip is generated from the ONE registry (ui/keymap.mjs) — never a
   hand-written string, which is the drift this repo has paid for before */
.plc-tool .plc-sim-key {
  font-family: var(--chrome-mono); font-size: 9px; letter-spacing: 0;
  text-transform: none; color: var(--plc-ink-mute);
  border: 1px solid var(--plc-rule-strong); border-radius: 2px; padding: 0 3px;
}
.plc-tool .plc-btn--primary .plc-sim-key { color: inherit; border-color: currentColor; opacity: 0.7; }

.plc-tool .plc-sim-speed {
  display: flex; align-items: center; gap: 8px; margin-left: auto;
  font-family: var(--chrome-mono); font-size: 9.5px; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-speed input[type="range"] {
  width: 132px; accent-color: var(--plc-copper); margin: 0;
}
.plc-tool .plc-sim-mult {
  font-family: var(--chrome-mono); font-size: 11px; color: var(--plc-ink); min-width: 34px;
}

/* the readout: scan · clock · S · mode · effective budgets. The EFFECTIVE ones
   (§2.6 rev D), never LIMITS' ceilings — printing the ceiling is how "a plan may
   lower, never raise" went unobservable for two whole revisions. */
.plc-tool .plc-sim-readout {
  display: flex; align-items: center; gap: 6px 14px; flex-wrap: wrap;
  margin-top: 9px;
  font-family: var(--chrome-mono); font-size: 10px; letter-spacing: 0.02em;
  color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-stat { display: inline-flex; align-items: baseline; gap: 5px; }
.plc-tool .plc-sim-stat b { color: var(--plc-ink); font-weight: 500; }
.plc-tool .plc-sim-lb { font-size: 8.5px; letter-spacing: 0.16em; text-transform: uppercase; }
.plc-tool .plc-sim-stat--warn { color: var(--plc-copper-sm); }
.plc-tool .plc-sim-stat--bad  { color: var(--plc-fail); }
.plc-tool .plc-sim-stop--fault b   { color: var(--plc-fail); }
.plc-tool .plc-sim-stop--ceiling b { color: var(--plc-copper-sm); }
.plc-tool .plc-sim-stop--unknown b { color: var(--plc-fail); }
.plc-tool .plc-sim-fault {
  flex: 1 1 100%; margin: 4px 0 0;
  font-family: var(--chrome-mono); font-size: 10px; line-height: 1.6; color: var(--plc-fail);
}

.plc-tool .plc-sim-msg {
  min-height: 1.4em; margin: 7px 0 0;
  font-family: var(--chrome-mono); font-size: 10.5px; letter-spacing: 0.02em;
  color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-msg[data-sev="error"]   { color: var(--plc-fail); }
.plc-tool .plc-sim-msg[data-sev="warning"] { color: var(--plc-copper-sm); }

.plc-tool .plc-sim-body {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 14px; margin-top: 10px;
}
@media (max-width: 760px) { .plc-tool .plc-sim-body { grid-template-columns: minmax(0, 1fr); } }
.plc-tool .plc-sim-col { min-width: 0; }
.plc-tool .plc-sim-note {
  margin: 0 0 8px;
  font-family: var(--chrome-mono); font-size: 9px; line-height: 1.7; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-empty {
  margin: 0; font-family: var(--chrome-mono); font-size: 9.5px; line-height: 1.7; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-group {
  margin: 9px 0 4px;
  font-family: var(--chrome-mono); font-weight: 400;
  font-size: 8.5px; letter-spacing: 0.2em; text-transform: uppercase; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-group:first-child { margin-top: 0; }

/* ── the rack row ─────────────────────────────────────────────────────────── */

.plc-tool .plc-sim-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto 40px;
  align-items: center; gap: 6px;
  padding: 4px 0; border-bottom: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 11px; color: var(--plc-ink-soft);
}
.plc-tool .plc-sim-nm { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.plc-tool .plc-sim-chip {
  font-size: 8.5px; letter-spacing: 0.08em; color: var(--plc-ink-mute);
  border: 1px solid var(--plc-rule-strong); border-radius: 2px; padding: 0 3px;
}
.plc-tool .plc-sim-ctl { display: inline-flex; align-items: center; }
.plc-tool .plc-sim-val { text-align: right; color: var(--plc-ink); }
/* SHAPE FIRST, THEN COLOUR — a lamp that is only a colour is not a lamp on a
   monochrome print or to a colour-blind reader. */
.plc-tool .plc-sim-val[data-on]::before {
  content: '○ '; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-val[data-on="1"]::before { content: '● '; color: var(--plc-voltage); }
.plc-tool .plc-sim-val[data-on="1"] { color: var(--plc-voltage); }

.plc-tool .plc-sim-queued {
  grid-column: 1 / -1;
  font-size: 9px; letter-spacing: 0.06em; color: var(--plc-copper-sm);
}
.plc-tool .plc-sim-why {
  grid-column: 1 / -1; margin: 2px 0 0;
  font-size: 9px; line-height: 1.6; color: var(--plc-ink-mute);
}
.plc-tool .plc-sim-row[data-refused] .plc-sim-nm { color: var(--plc-ink-mute); }

.plc-tool .plc-sim-sw {
  accent-color: var(--plc-copper); width: 15px; height: 15px; margin: 0;
}
.plc-tool .plc-sim-num {
  width: 74px; padding: 2px 5px; min-height: 24px;
  font-family: var(--chrome-mono); font-size: 11px;
  color: var(--plc-ink); background: var(--plc-ground);
  border: 1px solid var(--plc-rule-strong); border-radius: 3px;
}
.plc-tool .plc-sim-num:focus-visible,
.plc-tool .plc-sim-sw:focus-visible,
.plc-tool .plc-sim-speed input[type="range"]:focus-visible {
  outline: 2px solid var(--plc-copper); outline-offset: 1px;
}
.plc-tool .plc-sim-num:disabled, .plc-tool .plc-sim-sw:disabled { opacity: 0.4; }

.plc-tool .plc-sim-opt {
  display: flex; align-items: center; gap: 6px; margin-bottom: 6px;
  font-family: var(--chrome-mono); font-size: 9.5px; color: var(--plc-ink-mute); cursor: pointer;
}
.plc-tool .plc-sim-opt input[type="checkbox"] { accent-color: var(--plc-copper); width: 13px; height: 13px; margin: 0; }
.plc-tool .plc-sim-opt code { font-family: var(--chrome-mono); color: var(--plc-ink-soft); }

/* ── the watch table ─────────────────────────────────────────────────────── */

.plc-tool .plc-sim-wrow {
  display: grid; grid-template-columns: minmax(0, 1fr) 56px 56px;
  align-items: baseline; gap: 6px;
  padding: 3px 0; border-bottom: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 11px; color: var(--plc-ink-soft);
}
.plc-tool .plc-sim-wrow--head { color: var(--plc-ink-mute); font-size: 8.5px; letter-spacing: 0.16em; text-transform: uppercase; }
.plc-tool .plc-sim-wrow--head .plc-sim-val { color: inherit; }
.plc-tool .plc-sim-wrow[data-changed="1"] .plc-sim-nm { color: var(--plc-ink); }

.plc-tool .plc-sim-hint {
  margin: 10px 0 0; padding-top: 8px; border-top: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 9.5px; line-height: 1.7; color: var(--plc-ink-mute);
}

/* 44px TOUCH FLOOR — the same one §2 puts under .plc-btn. Declared here for the
   panel's own controls because none of them inherits it, and the range thumb
   has to be sized on its own pseudo-element in both engines. */
@media (pointer: coarse) {
  .plc-tool .plc-sim-sw,
  .plc-tool .plc-sim-opt input[type="checkbox"] { width: 24px; height: 24px; }
  .plc-tool .plc-sim-num { min-height: 44px; }
  /* The input itself must drop its native appearance BEFORE the thumb does, or
     Chromium renders a styled thumb on no track at all — an invisible control
     on the one device class this block exists for. Track and thumb are then
     both stated, in both engines. */
  .plc-tool .plc-sim-speed input[type="range"] {
    -webkit-appearance: none; appearance: none;
    height: 44px; width: 152px; background: transparent;
  }
  .plc-tool .plc-sim-speed input[type="range"]::-webkit-slider-runnable-track {
    height: 4px; border-radius: 2px; background: var(--plc-rule-strong);
  }
  .plc-tool .plc-sim-speed input[type="range"]::-webkit-slider-thumb {
    -webkit-appearance: none; appearance: none;
    width: 44px; height: 44px; margin-top: -20px; border-radius: 50%;
    background: var(--plc-copper); border: 0;
  }
  .plc-tool .plc-sim-speed input[type="range"]::-moz-range-track {
    height: 4px; border-radius: 2px; background: var(--plc-rule-strong);
  }
  .plc-tool .plc-sim-speed input[type="range"]::-moz-range-thumb {
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--plc-copper); border: 0;
  }
}


/* ═══ 7 · Keymap sheet ══════════════════════════════════════════════════════
   Every row is generated from the ONE registry in ui/keymap.mjs, which the
   keydown dispatcher, this sheet, the span toolbar and the hint strip all read.
   A binding cannot drift from its label — the sld ARCHITECTURE.md §10
   anti-pattern, fixed on day one because it is impossible to retrofit.        */

.plc-sheet {
  position: fixed; inset: 0; z-index: 60;
  display: flex; align-items: flex-start; justify-content: center;
  padding: 40px 20px; overflow: auto;
  background: rgba(20, 20, 19, 0.72);
}
.plc-sheet .plc-sheet-box {
  width: min(700px, 96vw);
  background: #201f1d; border: 1px solid rgba(250, 249, 245, 0.20);
  border-radius: 12px; padding: 18px 20px 16px; color: #d5d3cb;
}
.plc-sheet .plc-sheet-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 12px; margin-bottom: 12px; border-bottom: 1px solid rgba(250, 249, 245, 0.10);
}
.plc-sheet .plc-sheet-head h2 {
  font-family: var(--chrome-sans); font-weight: 600; font-size: 15px; color: #faf9f5; margin: 0;
}
.plc-sheet .plc-sheet-body h3 {
  font-family: var(--chrome-mono); font-size: 9px; letter-spacing: 0.24em; text-transform: uppercase;
  color: #a09d94; font-weight: 400; margin: 14px 0 6px;
}
.plc-sheet .plc-sheet-row {
  display: grid; grid-template-columns: 96px minmax(0, 1fr); gap: 10px; padding: 3px 0;
  font-family: var(--chrome-sans); font-size: 11.5px; line-height: 1.55; color: #a09d94;
}
.plc-sheet .plc-sheet-row .plc-k {
  font-family: var(--chrome-mono); font-size: 10.5px; color: #eb9d7e; text-align: right;
}
.plc-sheet .plc-sheet-row .plc-l b { color: #faf9f5; font-weight: 500; }
.plc-sheet .plc-sheet-foot {
  margin-top: 16px; padding-top: 10px; border-top: 1px solid rgba(250, 249, 245, 0.10);
  font-family: var(--chrome-mono); font-size: 9px; line-height: 1.7; color: #a09d94;
}
.plc-sheet .plc-sheet-foot code { color: #d5d3cb; }
/* the sheet lives outside .plc-tool, so it restates .plc-btn rather than
   inheriting it — glass-skin does not reach here, hence no !important */
.plc-sheet .plc-btn {
  font-family: var(--chrome-mono); font-size: 10px; letter-spacing: 0.14em; text-transform: uppercase;
  padding: 6px 12px; min-height: 30px; border: 1px solid rgba(250, 249, 245, 0.20);
  border-radius: 2px; background: transparent; color: #faf9f5; cursor: pointer;
}
.plc-sheet .plc-btn:hover { border-color: #e08a66; color: #e08a66; }


/* ═══ 8 · Footer note + the aria-live oracle ════════════════════════════════ */

.plc-tool .plc-foot {
  margin-top: 12px; padding-top: 10px; border-top: 1px solid var(--plc-rule);
  font-family: var(--chrome-mono); font-size: 9px; line-height: 1.75;
  color: var(--plc-ink-mute);
}
.plc-tool .plc-foot p { margin: 0 0 5px; }
.plc-tool .plc-foot p:last-child { margin-bottom: 0; }
.plc-tool .plc-foot b { color: var(--plc-ink-soft); font-weight: 500; }
.plc-tool .plc-limitations {
  font-family: var(--chrome-sans); font-size: 12px; line-height: 1.6;
  color: var(--plc-ink-soft);
}

/* Visually hidden, never display:none — a display:none live region is not
   announced, and this element is also the e2e lane's stable text oracle
   (preferred over SVG geometry, interaction note §8.6). */
.plc-a11y {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%);
  white-space: nowrap; border: 0;
}


/* ═══ 9 · Print ═════════════════════════════════════════════════════════════
   PLC-2 has NO print path — the Cahier test report is PLC-7. Until then, hide
   the interactive furniture so a browser Print of this page is not nonsense.  */
@media print {
  .plc-tool .plc-side,
  .plc-tool .plc-tools,
  .plc-tool .plc-arms,
  .plc-tool .plc-overlay,
  /* the simulator is a LIVE surface: a printed transport is a picture of
     buttons, and a printed watch table is one arbitrary scan with no way to say
     which. The Cahier test report (PLC-7) is the honest print path. */
  .plc-tool .plc-sim,
  .plc-tool .plc-hint { display: none; }
  .plc-tool .plc-work { grid-template-columns: minmax(0, 1fr); }
  .plc-tool .plc-limitations {
    break-inside: avoid; padding: 10px; border: 1px solid #111;
    color: #111; background: #fff;
  }
}
