/* ===========================================================================
   /product illustration pass (2026-08-17). CSS boxes, not scaled SVG: a viewBox
   fitted to the 484px desktop card renders its labels at ~8px inside the 354px
   phone card, so every diagram below reflows instead of shrinking.
   Namespaced `pd-` (product diagram) — the page already uses .id, .st, .tt.
   =========================================================================== */

.ill.pd { display: flex; align-items: center; justify-content: center; padding: 16px 14px; }
.pd-w { width: 100%; }
.pd-cap { font-size: 10.5px; letter-spacing: .04em; color: var(--muted); }  /* lowercase, like the landing's diagram labels */
.pd-key { font: 500 11.5px/1 var(--mono); color: var(--fg); letter-spacing: .02em; }

/* --- 1. what one call returns: one issue, held, carrying three things ------- */
.pd-call { color: var(--muted); font: 500 11px/1 var(--mono); letter-spacing: .02em; margin-bottom: 2px; }
.pd-call b { color: var(--fg); font-weight: 500; }
.pd-ret { display: grid; grid-template-columns: minmax(0,1fr); gap: 12px; }
.pd-held { display: flex; align-items: center; gap: 9px; padding: 9px 11px; border-radius: var(--radius-md);
  background: var(--card); border: 1px solid var(--rt-claude); box-shadow: 0 0 0 3px color-mix(in srgb, var(--rt-claude) 10%, transparent); }
.pd-held .pd-lock { width: 13px; height: 13px; flex: none; color: var(--rt-claude); }
.pd-stems { display: grid; grid-template-columns: repeat(2, minmax(0,1fr)); gap: 10px; }
.pd-stem { position: relative; padding-top: 13px; min-width: 0; }
.pd-stem::before { content: ""; position: absolute; top: 0; left: 50%; width: 1px; height: 9px; background: var(--dim); }
.pd-chip { display: flex; align-items: center; justify-content: center; gap: 5px; min-width: 0;
  padding: 6px 4px; border-radius: var(--radius-sm); background: var(--surface); border: 1px solid var(--surface-border); }
.pd-chip .pd-key { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pd-bar { width: 30px; height: 5px; border-radius: 3px; background: var(--dim); overflow: hidden; flex: none; }
.pd-bar i { display: block; height: 100%; background: var(--success); }
.pd-fork { width: 13px; height: 13px; flex: none; color: var(--secondary); }

/* --- 2. peek vs claim ------------------------------------------------------ */
.pd-pk { display: grid; grid-template-columns: minmax(0,1fr) 38px minmax(0,1fr);
  grid-auto-rows: minmax(22px, auto); align-items: center; column-gap: 0; row-gap: 7px; }
.pd-cap-l { grid-column: 1; } .pd-cap-r { grid-column: 3; }
.pd-row { grid-column: 1; display: flex; align-items: center; gap: 7px; height: 22px; padding: 0 8px; border-radius: var(--radius-sm); }
.pd-loose { border: 1px dashed var(--dim); }
.pd-loose i { display: block; height: 4px; border-radius: 2px; background: var(--dim); flex: 1; }
.pd-tk { grid-column: 3; }
.pd-taken { border: 1px solid var(--rt-claude); background: color-mix(in srgb, var(--rt-claude) 7%, transparent); }
.pd-taken i { display: block; height: 4px; border-radius: 2px; background: var(--rt-claude); flex: 1; }
.pd-taken .pd-lock { width: 11px; height: 11px; flex: none; color: var(--rt-claude); }
/* one arrow per row, and it lives in the same grid row as the pair it joins,
   so it can never drift out of alignment with them */
.pd-arrow { grid-column: 2; position: relative; height: 100%; min-height: 22px; }
/* 9px of air either side of the arrow, so the gap to the box it leaves equals
   the gap to the box it points at. 38px column = 9 + 12 line + 8 head + 9. */
.pd-arrow::before { content: ""; position: absolute; left: 9px; right: 17px; top: 50%; margin-top: -1px;
  height: 2px; border-radius: 1px; background: var(--dim); }
.pd-arrow::after { content: ""; position: absolute; right: 9px; top: 50%; margin-top: -4px;
  border-left: 8px solid var(--dim); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }

/* --- 4. the fencing token: the number decides, not the name --------------- */
/* Two identical runs at one boundary. The only difference is the number each
   carries, and whether it is the number the issue currently holds — so the
   picture argues from the token, never from who is writing. */
.pd-fn { display: grid; grid-template-columns: auto minmax(0,1fr) auto;
  grid-template-rows: 32px 32px; column-gap: 10px; row-gap: 26px; align-items: center; }
.pd-fn .agent { font-size: var(--t-label); }

/* a write in flight: run, the token it carries, run, verdict */
.pd-fn-path { display: flex; align-items: center; min-width: 0; position: relative; z-index: 2; line-height: 0; }
.pd-fn-line { flex: 1 1 0; min-width: 4px; height: 2px; border-radius: 2px; }
.pd-fn-tok { flex: none; margin: 0 5px; padding: 3px 7px; border-radius: var(--radius-sm); border: 1px solid;
  font: 500 10.5px/1.2 var(--mono); letter-spacing: .02em; white-space: nowrap; }
.pd-fn-mk { flex: none; width: 21px; height: 21px; border-radius: 50%; border: 1.5px solid; box-sizing: border-box;
  background: var(--surface); display: flex; align-items: center; justify-content: center; align-self: center; }

/* stale token: dashed run, dies well clear of the boundary */
.pd-fn-stale { padding-right: 15px; }
.pd-fn-stale .pd-fn-line { background: repeating-linear-gradient(90deg, var(--error) 0 4px, transparent 4px 8px); }
.pd-fn-stale .pd-fn-tok { color: var(--error); background: var(--error-bg); border-color: var(--error-border); }
.pd-fn-stale .pd-fn-mk { border-color: var(--error); color: var(--error); margin-left: 5px; }

/* current token: solid run that crosses the boundary and lands inside */
.pd-fn-live .pd-fn-line { background: var(--rt-codex); }
.pd-fn-live .pd-fn-tok { color: var(--success); background: var(--success-bg); border-color: var(--success-border); }
.pd-fn-live .pd-fn-mk { border-color: var(--success); color: var(--success); background: var(--card);
  margin-left: -8px; margin-right: -40px; }

/* the issue: everything past the boundary. Its key sits on row 1, the token it
   currently holds on row 2 — level with the run that carries the same number. */
.pd-fn-rec { grid-column: 3; grid-row: 1 / span 2; align-self: stretch; position: relative; z-index: 1;
  display: flex; flex-direction: column; align-items: flex-start; justify-content: space-between;
  padding: 10px 12px 6px 44px; background: var(--card); border-left: 1px dashed var(--sep);
  border-radius: 0 var(--radius-md) var(--radius-md) 0; }
.pd-fn-key { font: 500 11px/1 var(--mono); color: var(--fg); letter-spacing: .02em; }
.pd-fn-cur { padding: 3px 7px; border-radius: var(--radius-sm); border: 1px solid var(--success-border);
  background: var(--success-bg); color: var(--success);
  font: 500 10.5px/1.2 var(--mono); letter-spacing: .02em; white-space: nowrap; }

/* Narrow card: the name lifts above its own run rather than squeezing it, so the
   run keeps its length and the two verdicts keep their difference in reach. */
@media (max-width: 480px) {
  .pd-fn { grid-template-rows: 30px 30px; row-gap: 20px; column-gap: 7px; }
  .pd-fn .agent { font-size: var(--t-label); }
  .pd-fn-tok, .pd-fn-cur { font-size: 9.5px; padding: 2px 5px; margin: 0 3px; }
  .pd-fn-line { min-width: 11px; }          /* a dash run must still read as a run */
  .pd-fn-mk { width: 18px; height: 18px; }
  /* On a phone card the verdict rings are positioned off the COLUMN EDGE, not
     carried at the end of the flex run: below ~390px the run's own min-content
     (two dash stubs + the token chip) overflows the column and used to shove
     the ring as far as 74px past the boundary. Absolute against the path keeps
     the geometry true by construction at every width. The X sits centred ON the
     dashed line (9px half-ring + 7px column gap = 16) — refused at the gate it
     points at, where the desktop's "dies well clear" gap just reads as a miss —
     and the tick keeps its established +18px landing inside the record. */
  .pd-fn-path .pd-fn-mk { position: absolute; top: 50%; transform: translateY(-50%); }
  .pd-fn-stale { padding-right: 0; }
  .pd-fn-stale .pd-fn-mk { margin: 0; right: -16px; }
  .pd-fn-live .pd-fn-mk { margin: 0; right: -34px; }
  /* The live run has to REACH its tick. Lifting the rings out of the flex flow
     (above) left the last stretch of line ending at the path's edge while the
     ring sat 16px further in, so the accepted write appeared to stop short of
     the verdict it earns — the desktop row has them touching, with the ring
     overlapping the line by 8px. -22px closes the 16 and tucks 6 under the
     ring, whose own fill hides the join. The refused run needs nothing: its
     ring already overlaps the path edge by 2px. */
  .pd-fn-live .pd-fn-tok + .pd-fn-line { margin-right: -22px; }
  .pd-fn-rec { padding: 8px 8px 6px 40px; }
}
@media (max-width: 380px) {
  .pd-fn .agent { font-size: var(--t-label); }
  .pd-fn-tok, .pd-fn-cur { font-size: 10px; padding: 3px 6px; margin-left: 4px; margin-right: 4px; }
  .pd-fn-cur { margin: 0; }
  .pd-fn-mk { width: 19px; height: 19px; }
  .pd-fn-stale .pd-fn-mk { right: -16.5px; }  /* 9.5px half-ring + 7px gap */
  .pd-fn-live .pd-fn-mk { right: -34.5px; }
  .pd-fn-rec { padding-left: 34px; padding-right: 10px; }
}

/* --- 5. review: it goes back on the queue, in another lane ----------------- */
/* ONE grid for the whole diagram, not one per lane. The label column is sized by
   the widest label, so a caption can never run into the slot beside it (`reviewer`
   needs 76px and the phone column was a hard 62px, so it sat on the slot border),
   and the arrow and the dependents row land in the track column by position
   rather than by an offset hand-copied from the column width. That width used to
   be written in four places, twice per breakpoint, which is how they drifted apart. */
.pd-rv { display: grid; grid-template-columns: auto minmax(0,1fr); align-items: center; gap: 10px; }
.pd-lane { display: contents; }
.pd-who { display: flex; align-items: center; gap: 6px; min-width: 0; }
.pd-av { width: 16px; height: 16px; border-radius: 50%; flex: none; display: flex; align-items: center;
  justify-content: center; font: 600 9px/1 var(--sans); color: var(--on-hue); }
@media (prefers-color-scheme: light) {
  /* the light claude hue is the one that leaves white at 4.31; the avatar disc (and
     only the disc) takes a darker cut of the same hue so the letter clears AA */
  :root:not([data-theme="dark"]) .pd-a1 { background: #9a5320; }
}
:root[data-theme="light"] .pd-a1 { background: #9a5320; }
.pd-a1 { background: var(--rt-claude); }
.pd-a2 { background: var(--rt-codex); }
.pd-slot { position: relative; height: 24px; border-radius: var(--radius-sm); border: 1px dashed var(--dim); }
.pd-slot.pd-has { border-style: solid; border-color: var(--review); background: var(--review-bg); }
/* .40, not .55: the key printed ON this bar was dark ink on a mid-violet — 6.3:1
   in light and 6.1 in dark, legible but muddy, because ink and bar share a hue
   (Andrey, 8-25). Lightening the bar lifts both to ~7.9, inside the comfort band,
   and the bar still reads as an occupied slot against the dashed empty one above. */
.pd-item { position: absolute; inset: 4px 6px; border-radius: 2px; background: var(--review); opacity: .40; }
.pd-move { grid-column: 2; position: relative; height: 18px; }
/* shaft and head are one weight: a 2px stem meeting a head of the same visual mass,
   with the head's tip stopping 2px clear of the slot below so it never overlaps it. */
.pd-move::before { content: ""; position: absolute; left: 13px; top: 1px; bottom: 7px; width: 2px;
  border-radius: 1px; background: var(--sep); }
.pd-move::after { content: ""; position: absolute; left: 9px; bottom: 2px; border-top: 6px solid var(--sep);
  border-left: 5px solid transparent; border-right: 5px solid transparent; }
.pd-dep { grid-column: 2; display: flex; align-items: center; gap: 6px; }
.pd-dep i { width: 26px; height: 6px; border-radius: 3px; background: var(--dim); }

/* --- 6. the gate: same human refused, different human passes --------------- */
.pd-gt { display: grid; gap: 12px; }
.pd-pair { display: grid; grid-template-columns: auto minmax(0,1fr) auto; align-items: center; gap: 10px; }
.pd-nm { display: flex; align-items: center; gap: 6px; }
.pd-nm .pd-cap { white-space: nowrap; }
.pd-gate { position: relative; height: 22px; }
.pd-gate::before { content: ""; position: absolute; inset: 50% 0 auto 0; height: 1px; background: var(--dim); }
.pd-barred::before { background: repeating-linear-gradient(90deg, var(--error) 0 5px, transparent 5px 10px); }
.pd-open::before { background: var(--success); }
.pd-mk { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 17px; height: 17px;
  border-radius: 50%; background: var(--card); display: flex; align-items: center; justify-content: center; }
.pd-barred .pd-mk { border: 1px solid var(--error); color: var(--error); }
.pd-open .pd-mk { border: 1px solid var(--success); color: var(--success); }
.pd-mk svg { width: 9px; height: 9px; }

/* --- 7. one key, one human -------------------------------------------------
   Each key is NAMED. Three anonymous glyphs under an avatar say nothing a cold
   reader can decode — and the bar beside the name is what the suspension acts
   on, so without it "suspended" and "active" drew identically. */
.pd-kglyph { width: 11px; height: 11px; flex: none; color: var(--muted); }
.pd-kn { font: 500 10px/1 var(--mono); color: var(--ink);
  white-space: nowrap; }
.pd-gone .pd-kn { color: var(--muted); }
.pd-ky { display: grid; grid-template-columns: minmax(0,1fr) 1px minmax(0,1fr); gap: 14px; align-items: start; }
.pd-sep { align-self: stretch; background: var(--surface-border); }
/* The two captions must break TOGETHER. "andrey · suspended" is longer than
   "andrey · active", so between 370 and 409px the right one wrapped while the left
   stayed on one line and the two halves of a symmetric diagram stopped lining up.
   Below the threshold both stack, and the separator goes with the single line it
   belonged to — a dot at the end of a line is punctuation pointing at nothing. */
.pd-ky .pd-cap { display: flex; align-items: baseline; gap: 4px; }
.pd-ky .pd-who, .pd-ky .pd-state { white-space: nowrap; }
.pd-ky .pd-dot { font-style: normal; }
@media (max-width: 415px) {
  .pd-ky .pd-cap { flex-direction: column; align-items: flex-start; gap: 1px; }
  .pd-ky .pd-dot { display: none; }
  .pd-ky .pd-person { align-items: flex-start; }
}
.pd-person { display: flex; align-items: center; gap: 7px; margin-bottom: 10px; }
.pd-keys { display: flex; flex-direction: column; gap: 7px; }
.pd-k { display: flex; align-items: center; gap: 7px; }

.pd-k b { display: block; height: 8px; border-radius: 2px; background: var(--rt-claude); opacity: .8; flex: 1; }
.pd-k.pd-k2 b { background: var(--rt-codex); }
.pd-k.pd-k3 b { background: var(--rt-cursor); }
.pd-gone .pd-person { opacity: .4; }
.pd-gone .pd-k b { background: var(--dim); position: relative; opacity: 1; }
.pd-gone .pd-k b::after { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: var(--error); }

/* --- 8. sealed rows, one org key -------------------------------------------
   A REDACTION, not a barcode: the field is there, its content is not readable.
   Three equal-length striped blocks read as a loading skeleton and the striping
   was the loudest texture on the page; three solid bars of different lengths
   read as three fields whose contents differ and are hidden. The per-row locks
   went with it — three identical padlocks beside a line that already says the
   rows are sealed is the same fact drawn four times. */
.pd-enc { display: grid; gap: 9px; }
.pd-seal { display: grid; grid-template-columns: 60px minmax(0,1fr); align-items: center; gap: 10px; }
.pd-seal .pd-cap { font-size: 9.5px; }
 /* filled, not outlined: an outlined bar in a row with a label beside it is a
    text input, and a redaction that reads as a form is worse than no mark */
.pd-cipher { height: 11px; width: var(--w, 100%); border-radius: 3px;
  background: var(--well-line); }
.pd-orgkey { display: flex; align-items: center; gap: 7px; margin-top: 2px; padding-top: 9px;
  border-top: 1px solid var(--surface-border); }
.pd-orgkey svg { width: 13px; height: 13px; color: var(--secondary); flex: none; }

@media (max-width: 720px) {
  .pd-pk { display: grid; grid-template-columns: minmax(0,1fr) 38px minmax(0,1fr);
  grid-auto-rows: minmax(22px, auto); align-items: center; column-gap: 0; row-gap: 7px; }
  /* no .pd-lane / .pd-move / .pd-dep overrides here: the lane column is content-sized
     at every width now, so the phone cannot get a narrower column than its labels need. */
  .pd-ky { gap: 10px; }
}

/* --- the lease, as the ticket in two states (pd-ls) ------------------------
   No chart. The site draws the same issue twice and lets the skin carry the
   change (.pi-old vs .pi-n, .fr-done vs .fr-wait), so this does the same: the
   ticket holds a lease meter, a heartbeat keeps topping it up, and when the
   heartbeat stops the same ticket comes back unheld with the meter empty. */
.pd-ls { display: grid; grid-template-columns: minmax(0,1fr) auto minmax(0,1fr);
  align-items: center; gap: 10px; }
.pd-ls-t { display: grid; gap: 8px; padding: 11px 12px; border-radius: var(--radius-md);
  background: var(--card); border: 1px solid var(--surface-border); min-width: 0; }
.pd-ls-hd { display: flex; align-items: center; gap: 7px; min-width: 0; }
.pd-ls-sw { width: 9px; height: 9px; border-radius: 2px; flex: none; background: var(--rt-claude); }
.pd-ls-key { font: 500 11.5px/1 var(--mono); color: var(--fg);
  letter-spacing: .02em; white-space: nowrap; }
.pd-ls-m { display: flex; align-items: center; gap: 8px; }
.pd-ls-bar { flex: 1; height: 7px; border-radius: 4px; background: var(--dim); overflow: hidden; }
.pd-ls-bar i { display: block; height: 100%; background: var(--success); }
.pd-ls-lab { font: 500 10.5px/1 var(--mono); color: var(--secondary); letter-spacing: .03em; }
/* the heartbeat that keeps it full, drawn on the ticket it acts on */
/* The live mark is a DOT now, not a drawn pulse, so the box is the dot: at 15 the
   ink sat in the middle of an empty square and the gap to the bar read as a
   mistake. 9px is the dot's own size on the 15-grid. */
.pd-ls-beat { width: 9px; height: 9px; flex: none; color: var(--success); }

/* the transition. No glyph: the two tickets already differ in three ways at once
   (holder swatch, lease meter, pulse mark), which is what carries the event. */
.pd-ls-ev { position: relative; width: 30px; height: 2px; border-radius: 1px; background: var(--dim); }
.pd-ls-ev::after { content: ""; position: absolute; right: 0; top: 50%; margin-top: -4px;
  border-left: 8px solid var(--dim); border-top: 4px solid transparent; border-bottom: 4px solid transparent; }

/* the same ticket, unheld: dashed skin, empty holder, empty meter */
.pd-ls-t.pd-ls-free { background: none; border-style: dashed; border-color: var(--sep); }
.pd-ls-free .pd-ls-sw { background: none; border: 1px dashed var(--sep); }
.pd-ls-free .pd-ls-key { color: var(--secondary); }
.pd-ls-free .pd-ls-beat { display: none; }
.pd-ls-free .pd-ls-bar i { background: var(--dim); }

@media (max-width: 480px) {
  .pd-ls { gap: 7px; }
  .pd-ls-t { padding: 9px 10px; gap: 7px; }
  .pd-ls-ev { width: 22px; }
}

/* .s-formula moved to styles.css 2026-08-20: two pages use it now. */

