/* css/13-coverage.css — coverage glass card.
   Split from the index.html <style> block (REFACTOR-PLAN Phase 2). Load order = cascade order; do not reorder. */
/* ---------- revamp 11 (client): the HUD STAT CLUSTER, top-right of the stage.
   The Sector screen was removed from the dock and its three numbers moved
   here. What was one 340 px card reading "1.8 / 5.9 km · SCI 92 · 0 valid ·
   0 closed" — a sentence, at 12 px, to a driver — is three tiles, each one
   label, one large mono value and one hairline sub. Dark glass, one hairline,
   no fill except the ring and the score bar. Nothing here animates except a
   300 ms value tween and the ring's own dashoffset. */
.hudstats{position:absolute;top:12px;right:12px;left:auto;z-index:5;
  display:flex;gap:8px;align-items:stretch;pointer-events:none;max-width:calc(100% - 24px)}
.hstat{width:112px;flex:0 0 auto;box-sizing:border-box;min-height:86px;
  padding:9px 11px 10px;border-radius:14px;border:1px solid var(--hair);
  background:var(--glass-solid);backdrop-filter:var(--blur);box-shadow:var(--sh-lg);
  display:flex;flex-direction:column;gap:6px;justify-content:flex-start}
/* loop pass 1 (U1): the three tiles are ONE INSTRUMENT, so they read off shared
   rules, not off whatever their own content happens to be tall. A four-row grid
   -- label / value / score bar / sub -- fixes the value row at the ring's 44 px
   and lets the tiles without a ring (and without a bar) leave their row empty.
   The values are BOTTOM-aligned in that row rather than centred: the coverage
   percentage is 20 px beside its ring and the other two are 26 px, and with
   line-height 1 a common bottom edge puts all three baselines within a pixel
   of each other -- centring them would not. The sub-lines sit on row 4 and so
   share a baseline too. */
.hstat{display:grid;grid-template-rows:auto 44px 4px auto;row-gap:6px;align-content:start}
.hstat .hl{grid-row:1;align-self:start}
.hstat .hrow{grid-row:2;align-items:flex-end}
.hstat .hv{grid-row:2;align-self:end}
.hstat .hbar{grid-row:3;align-self:center}
.hstat .hs{grid-row:4;align-self:end}
#hsCov{border-color:rgba(34,200,130,.30)}
/* fix: the 112 px tile is too narrow for the 44 px ring + 9 px gap + the
   20 px mono "100%" numeral -- they collided at full coverage. Only this
   tile widens; Detections and SCI stay at 112 px. */
#hsCov{width:140px}
.hstat .hl{font-size:10.5px;letter-spacing:.12em;text-transform:uppercase;
  color:var(--tx3);font-weight:700;line-height:1;white-space:nowrap}
.hstat .hv{font-family:var(--mono);font-size:26px;font-weight:700;line-height:1;
  color:var(--tx);font-variant-numeric:tabular-nums;letter-spacing:-.02em}
.hstat .hs{font-size:11px;line-height:1.2;color:var(--tx3);white-space:nowrap;
  overflow:hidden;text-overflow:ellipsis}
.hstat .hs.num{font-family:var(--mono);font-variant-numeric:tabular-nums}
.hstat .hbar{display:block;height:4px;border-radius:2px;background:rgba(255,255,255,.10);overflow:hidden}
.hstat .hbar i{display:block;height:100%;width:100%;border-radius:2px;background:var(--acc);
  transform:scaleX(0);transform-origin:0 50%;transition:transform .3s var(--ease),background-color .3s var(--ease)}
#hsSci.lvl-watch .hbar i{background:var(--med)}
#hsSci.lvl-action .hbar i{background:var(--crit)}
#hsSci.lvl-watch .hv{color:var(--med)}
#hsSci.lvl-action .hv{color:var(--crit)}
/* coverage: a 44 px ring beside a 20 px percentage — the ring is the glance,
   the numeral is the confirmation. */
.hstat .hrow{display:flex;align-items:center;gap:9px;min-height:44px}
.hring{position:relative;width:44px;height:44px;flex:0 0 auto;display:block}
.hring svg{position:absolute;inset:0;width:44px;height:44px}
.hring svg:first-child{transform:rotate(-90deg)}
.hring .trk{fill:none;stroke:rgba(255,255,255,.10);stroke-width:4}
.hring .arc{fill:none;stroke:var(--acc);stroke-width:4;stroke-linecap:round;
  stroke-dasharray:119.38;stroke-dashoffset:119.38;transition:stroke-dashoffset .3s var(--ease)}
.hring .hchk{fill:none;stroke:var(--acc);stroke-width:2.8;stroke-linecap:round;stroke-linejoin:round;
  opacity:0;transform:scale(.7);transform-origin:50% 50%;
  transition:opacity .25s var(--ease),transform .25s var(--ease)}
/* verification phase: the inspection pass is over, the ring is full and the
   percentage is joined by a drawn check. */
#hsCov.done .hchk{opacity:1;transform:scale(1)}
#hsCov.done .arc{stroke-dashoffset:0}
.hstat .hv#cov{font-size:20px;color:var(--acc)}
@media (prefers-reduced-motion: reduce){
  .hring .arc,.hring .hchk,.hstat .hbar i{transition:none}
}
/* client pass (12 Sep): the perception-gate chip ("Below 20 …") and the
   offline-map chip are removed from the guidance strip — the gate still runs,
   it just doesn't narrate. */
.guide .gate,#offMapChip{display:none!important}
/* verify pass (client, 14 Sep): every hero-card rule below ALSO matches
   #vhero — the verification decision card (renderVerifyHero) is the same
   .inc-card in its own slot above #cardSlot, so it reads exactly like the
   detection card it stands in for. Selectors extended, bodies not duplicated. */
/* redesign (client pass, 12 Sep v2): drive feed cards drop the severity edge
   for the app's own glass treatment — severity now lives on the .sev chip
   alone. Scoped to #view-drive so the Verify list's .inc-card is untouched. */
#view-drive #cardSlot .inc-card,#view-drive #list .inc-card,
#view-drive #vhero .inc-card{
  border:1px solid var(--hair)!important;
  border-left:1px solid var(--hair)!important;border-inline-start:1px solid var(--hair)!important;
  border-left-style:solid!important;border-inline-start-style:solid!important;
  background:var(--glass);-webkit-backdrop-filter:var(--blur);backdrop-filter:var(--blur);
  border-radius:16px;box-shadow:var(--sh)}
#view-drive #cardSlot .inc-card.rowfocus,#view-drive #list .inc-card.rowfocus,
#view-drive #vhero .inc-card.rowfocus{border-color:var(--acc)!important}

/* incident cards read bigger on the Drive stream, and every new one pops in
   — scoped to the hero card only (#cardSlot); #list gets its own compact rules below */
#view-drive #cardSlot .inc-card,
#view-drive #vhero .inc-card{padding:12px;
  /* the evidence plate's height ceiling -- see the thumb rules below. 204 px at
     the 604 px head unit leaves the enlarged text stack and the 56 px decision
     row inside the panel with room to spare; the vh term is what keeps that
     true on the 640x604 split and the 604x1280 portrait layouts. */
  --ev-cap:min(204px,34vh)}
/* revamp 10 -- THE GLANCE IS 1.5 SECONDS AT 70 CM.
   The class name and the violated KPI are the two things the inspector is
   actually deciding on, so they carry real type.
   client pass 23: "the text of the card on the left side ... is not readable at
   all when you are in the vehicle". The whole card goes up ONE deliberate step
   each, not a blanket multiply -- the point is that the hierarchy survives the
   enlargement, so the ratios between the four reads are held:
     class  22 -> 27 px / 800   the primary read, unmistakable at arm's length
     KPI    17 -> 20 px / 650   the metric the penalty is written against
     status 14 -> 16 px         the lifecycle sentence
     meta   13.6 -> 15 px       camera + time, provenance, deliberately last
   ~1.35 : 1.25 : 1.07 between the steps, so nothing collapses into its
   neighbour. The severity chip stays a CHIP (16 px): it is colour-coded, and
   growing it with the title would have it competing for the same glance. */
#view-drive #cardSlot .inc-card .cls,
#view-drive #vhero .inc-card .cls{font-size:27px;font-weight:800;line-height:1.14;
  letter-spacing:-.022em;-webkit-line-clamp:1}
#view-drive #cardSlot .inc-card .clsic,
#view-drive #vhero .inc-card .clsic{width:26px;height:26px;margin-top:2px}
#view-drive #cardSlot .inc-card .meta,
#view-drive #vhero .inc-card .meta{font-size:15px;line-height:1.3}
#view-drive #cardSlot .inc-card .sev,
#view-drive #vhero .inc-card .sev{font-size:16px;padding:4px 11px}
/* ---- the HERO card (revamp task 2) ---------------------------------------
   The whole card — evidence plate, three text rows and the two 52 px
   decisions — has to fit the panel at 1280x604 WITHOUT scrolling, or the
   inspector's only two controls sit below the fold at 25 km/h. Three things
   bought the room: the head went from 146 px to 62 px, the card's doubled
   padding (card 14 + .top 12/14) collapsed to one 12 px ring, and the plate is
   a true 16:9 of the column width (~174 px) instead of a 170 px crop.

   The evidence plate is `object-fit:contain` on near-black: the camera frame is
   the EVIDENCE, and a cover crop was throwing away the part of it the AI drew
   its box on.

   .body is a 3-row grid:
     row1  class name .................. severity
     row2  KPI chip ............... status line
     row3  street · camera · time (full width)
   .sevrow is `display:contents` so the severity chip and the KPI chip can sit
   on different rows of that grid while staying one element in the markup (the
   same markup the Verify list and the sheet render). */
#view-drive #cardSlot .inc-card .top,
#view-drive #vhero .inc-card .top{display:flex;flex-direction:column;gap:9px;padding:0}
/* client pass (14 Sep): THE FRAME IS SHOWN AT ITS OWN RATIO. No 16:9 box, no
   height cap, no `contain` letterbox and no black plate behind it -- the plate
   is the column's full width and its height is whatever the image's intrinsic
   ratio makes it. Nothing is cropped and there are no bars on any side. The
   blurred backdrop copy (.evbg) has nothing left to fill, so it is neither
   painted nor emitted (buildCard). The column scrolls if a tall frame needs
   the room. */
/* client pass 23: ...but a PORTRAIT frame at the column's full width is 380 px
   tall, which pushed the two decisions clean out of the panel -- the one thing
   on this card that must never be out of reach. The plate is therefore CAPPED
   in height, and the cap is honoured by shrinking the frame, never by cropping
   it: the image keeps `height:auto` against a max-height, takes `width:auto` so
   a tall frame simply comes in narrower, and is centred on the card's own
   (transparent) ground so there are no letterbox bars either. A wide frame is
   unchanged -- it is width-limited long before it reaches the cap. */
#view-drive #cardSlot .inc-card button.thumb,
#view-drive #vhero .inc-card button.thumb{width:100%;min-width:100%;height:auto;
  aspect-ratio:auto;max-height:var(--ev-cap);border-radius:12px;margin-bottom:0;
  background:transparent;display:flex;justify-content:center;align-items:flex-start}
#view-drive #cardSlot .inc-card button.thumb img,
#view-drive #vhero .inc-card button.thumb img{position:static;display:block;
  width:auto;max-width:100%;height:auto;max-height:var(--ev-cap);
  object-fit:contain;border-radius:12px}
#view-drive #cardSlot .inc-card button.thumb img.evbg,
#view-drive #vhero .inc-card button.thumb img.evbg{display:none}
/* no frame yet: the class glyph stands in, centred on its own quiet field */
#view-drive #cardSlot .inc-card button.thumb svg,
#view-drive #vhero .inc-card button.thumb svg{width:44px;height:44px;margin:26px auto;display:block}
/* column 2 is CAPPED at 58 % of the row: a long status ("Needs a look · low
   confidence · …") used to grow the auto column until the class name and the
   KPI chip in column 1 collapsed to zero width. The status ellipsises instead. */
#view-drive #cardSlot .inc-card .body,
#view-drive #vhero .inc-card .body{display:grid;grid-template-columns:minmax(0,1fr) fit-content(58%);
  grid-template-rows:auto auto auto auto;align-items:center;column-gap:10px;row-gap:6px;width:100%}
#view-drive #cardSlot .inc-card .clsrow,
#view-drive #vhero .inc-card .clsrow{grid-column:1;grid-row:1;min-width:0;margin:0;align-items:center}
#view-drive #cardSlot .inc-card .cls,
#view-drive #vhero .inc-card .cls{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#view-drive #cardSlot .inc-card .sevrow,
#view-drive #vhero .inc-card .sevrow{display:contents}
#view-drive #cardSlot .inc-card .sevrow .sev,
#view-drive #vhero .inc-card .sevrow .sev{grid-column:2;grid-row:1;justify-self:end}
/* revamp 10: the KPI takes its own FULL-WIDTH row under the title -- no pill,
   no border, just a small-caps label and the metric name -- and the lifecycle
   status line moves down to row 3 where it has the width to say a whole
   sentence instead of ellipsising at 58 % of the column. */
#view-drive #cardSlot .inc-card .sevrow .kpichip,
#view-drive #vhero .inc-card .sevrow .kpichip{grid-column:1/-1;grid-row:2;justify-self:stretch;
  max-width:100%;display:flex;align-items:baseline;gap:9px;
  padding:0;border:0;background:none;border-radius:0}
#view-drive #cardSlot .inc-card .kpichip .kl,
#view-drive #vhero .inc-card .kpichip .kl{font-size:12px;letter-spacing:.12em;color:var(--tx3);font-weight:800}
#view-drive #cardSlot .inc-card .kpichip .kv,
#view-drive #vhero .inc-card .kpichip .kv{font-size:20px;font-weight:650;color:var(--tx);line-height:1.22}
#view-drive #cardSlot .inc-card .status,
#view-drive #vhero .inc-card .status{grid-column:1/-1;grid-row:3;justify-self:start;text-align:start;margin:0;white-space:nowrap;flex-wrap:nowrap;min-width:0;max-width:100%;overflow:hidden;font-size:16px;line-height:1.3}
#view-drive #cardSlot .inc-card .status>span,
#view-drive #vhero .inc-card .status>span{min-width:0;overflow:hidden;text-overflow:ellipsis}
#view-drive #cardSlot .inc-card .meta,
#view-drive #vhero .inc-card .meta{grid-column:1/-1;grid-row:4;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;margin:0}
#view-drive #cardSlot .inc-card .cardfoot,
#view-drive #vhero .inc-card .cardfoot{padding:0;margin-top:10px}
#view-drive #cardSlot .inc-card .acts,
#view-drive #vhero .inc-card .acts{flex-wrap:nowrap;gap:8px}
#view-drive #cardSlot .inc-card .acts .btn.valid,
#view-drive #cardSlot .inc-card .acts .btn.invalid,
#view-drive #vhero .inc-card .acts .btn.valid,
#view-drive #vhero .inc-card .acts .btn.invalid{height:56px;min-height:56px;font-size:19px;font-weight:800;flex:1 1 0}
#view-drive #cardSlot .inc-card .acts .btn.invalid,
#view-drive #vhero .inc-card .acts .btn.invalid{background:var(--crit);color:#fff;border:none}
/* the lifecycle / assignment foot is the same 52 px band as the decisions it
   replaces, so the card does not resize under the inspector's thumb */
#view-drive #cardSlot .inc-card .cardfoot .statusbar,
#view-drive #vhero .inc-card .cardfoot .statusbar{height:56px;font-size:16px}
#view-drive #cardSlot .inc-card .cardfoot .lcrow .statusbar,
#view-drive #cardSlot .inc-card .cardfoot .lcrow .btn.vfy,
#view-drive #vhero .inc-card .cardfoot .lcrow .statusbar,
#view-drive #vhero .inc-card .cardfoot .lcrow .btn.vfy{height:56px;min-height:56px;font-size:16px}

/* compact LIST rows below the hero: collapsed by default (real list look),
   expanded on .exp (toggled by renderList's row click handler, see JS) */
#view-drive #list .inc-card{padding:8px 10px}
#view-drive #list .inc-card:not(.exp){display:flex;flex-direction:row;align-items:center;
  gap:8px;min-height:64px;max-height:68px;overflow:hidden}
#view-drive #list .inc-card:not(.exp) .top{display:flex;align-items:center;gap:8px;flex:1 1 auto;min-width:0;padding:0}
#view-drive #list .inc-card:not(.exp) button.thumb{width:44px;min-width:44px;height:44px;border-radius:8px}
#view-drive #list .inc-card:not(.exp) button.thumb img{width:100%;height:100%;object-fit:cover;border-radius:8px}
#view-drive #list .inc-card:not(.exp) .body{min-width:0;flex:1 1 auto;gap:1px}
/* client pass 23: the collapsed rows are read from the same seat as the hero,
   so they come up with it -- 13.5/11.5 px was below anything legible at arm's
   length. The row grows to 64 px to carry it. */
#view-drive #list .inc-card:not(.exp) .cls{font-size:16px;font-weight:700;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#view-drive #list .inc-card:not(.exp) .meta{font-size:13.5px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
#view-drive #list .inc-card:not(.exp) .sevrow,
#view-drive #list .inc-card:not(.exp) .status,
#view-drive #list .inc-card:not(.exp) .clsrow svg{display:none}
#view-drive #list .inc-card:not(.exp) .cardfoot{flex:0 0 auto;padding:0;background:none;border:0;margin:0}
#view-drive #list .inc-card:not(.exp) .acts{display:flex;gap:6px;flex:0 0 auto;width:auto}
#view-drive #list .inc-card:not(.exp) .acts .btn{width:34px;height:34px;min-height:34px;min-width:34px;
  padding:0;border-radius:9px;flex:0 0 auto}
#view-drive #list .inc-card:not(.exp) .acts .btn span{display:none}
#view-drive #list .inc-card:not(.exp) .acts .btn svg{width:16px;height:16px}
#view-drive #list .inc-card:not(.exp) .statusbar{display:none}
/* expanded row: restore the full card, thumb full-width, labels back, buttons
   sized like the hero's but a touch smaller */
#view-drive #list .inc-card.exp{padding:12px}
#view-drive #list .inc-card.exp .top{display:flex;flex-direction:column;gap:8px}
#view-drive #list .inc-card.exp button.thumb{width:100%;min-width:100%;height:auto;aspect-ratio:auto;max-height:min(170px,28vh);border-radius:12px;background:transparent;display:flex;justify-content:center;align-items:flex-start}
#view-drive #list .inc-card.exp button.thumb img{position:static;display:block;width:auto;max-width:100%;height:auto;max-height:min(170px,28vh);object-fit:contain;border-radius:12px}
#view-drive #list .inc-card.exp button.thumb img.evbg{display:none}
#view-drive #list .inc-card.exp button.thumb svg{width:40px;height:40px;margin:22px auto;display:block}
#view-drive #list .inc-card.exp .body{display:grid;grid-template-columns:minmax(0,1fr) auto;column-gap:10px;row-gap:4px;align-items:center;width:100%}
#view-drive #list .inc-card.exp .clsrow{display:flex;margin:0;justify-self:start;grid-column:1;grid-row:1;min-width:0}
#view-drive #list .inc-card.exp .cls{display:-webkit-box;font-size:19px;font-weight:800;color:var(--tx);line-height:1.16;-webkit-line-clamp:2}
/* client pass (14 Sep): the KPI now reads "code · metric" ("2.1 a-a/1 · 2.2 a-b/1 ·
   Bin collection"), far too wide to share a row with the class name — in the
   expanded row it takes its own full-width line under the title, exactly as
   on the hero, and the severity chip alone sits at the end of the title row.
   (Sharing the row let the chip overlap the tap target, which also broke the
   smoke test's second tap on a #list row.) */
#view-drive #list .inc-card.exp .sevrow{display:contents}
#view-drive #list .inc-card.exp .sevrow .sev{grid-column:2;grid-row:1;justify-self:end}
#view-drive #list .inc-card.exp .sevrow .kpichip{grid-column:1/-1;grid-row:2;justify-self:stretch;max-width:100%;
  display:flex;align-items:baseline;gap:8px;padding:0;border:0;background:none;border-radius:0;white-space:normal}
#view-drive #list .inc-card.exp .kpichip .kl{font-size:11.5px;letter-spacing:.12em;color:var(--tx3);font-weight:800}
#view-drive #list .inc-card.exp .kpichip .kv{font-size:16px;font-weight:600;color:var(--tx);line-height:1.22}
#view-drive #list .inc-card.exp .status{display:flex;grid-column:1/-1;grid-row:3;justify-self:start;text-align:start;margin:0}
#view-drive #list .inc-card.exp .meta{grid-column:1/-1;grid-row:4}
#view-drive #list .inc-card.exp .cardfoot{padding:0;margin-top:8px}
#view-drive #list .inc-card.exp .acts{gap:8px}
#view-drive #list .inc-card.exp .acts .btn.valid,
#view-drive #list .inc-card.exp .acts .btn.invalid{min-height:52px;font-size:17px;font-weight:800;flex:1 1 40%}
#view-drive #list .inc-card.exp .acts .btn.invalid{background:var(--crit);color:#fff;border:none}
/* hide the Drive filter tabs row (and pileup banner) per client pass */
#view-drive .tabs{display:none!important}
#view-drive #pileup{display:none!important}
/* Project Officer demo message hidden (belt-and-braces alongside disabling the seed below) */
#poMsg{display:none!important}
/* the live pop-in itself is the existing FLIP entrance in renderList() — only
   the one arriving card animates, never a re-render */
/* full-screen "calculating" veil between End-confirm and the summary (note E) */
.calcveil{position:fixed;inset:0;z-index:80;display:grid;place-items:center;
  background:rgba(7,10,11,.94);backdrop-filter:blur(6px);opacity:0;transition:opacity .35s ease}
.calcveil.on{opacity:1}
.endfilters{display:flex;gap:6px;flex-wrap:wrap;margin:6px 0 8px}
.endfilters .pill{font:600 11px system-ui;padding:4px 10px;border-radius:999px;border:1px solid var(--hair);color:var(--tx2);background:transparent;cursor:pointer}
.endfilters .pill.on{border-color:var(--acc);color:var(--acc)}
/* revamp 9: the end sequence - a thin 120 px ring that fills as the four steps
   complete, a mono counter, the step title, and the step list drawing a check
   on each finished line. A slow radial pulse carries the backdrop (the old 3D
   car loop was noise behind a ring). */
#calc::before{content:"";position:absolute;inset:0;pointer-events:none;
  background:radial-gradient(44% 50% at 50% 50%,rgba(34,200,130,.12),rgba(34,200,130,0) 70%);
  animation:calcpulse 4.2s ease-in-out infinite}
@keyframes calcpulse{0%,100%{opacity:.3;transform:scale(.92)}50%{opacity:.95;transform:scale(1.06)}}
.calcbox{position:relative;z-index:2;display:flex;flex-direction:column;align-items:center;gap:18px;text-align:center;padding:0 24px;
  transition:opacity .2s var(--ease),transform .2s var(--ease)}
/* the box leaves FASTER than the scrim so the step list never ghosts over
   the summary tiles that are rising in behind it */
#calc:not(.on) .calcbox{opacity:0;transform:scale(.96)}
.calcring{position:relative;width:120px;height:120px;flex:0 0 auto}
.calcring svg{display:block;width:120px;height:120px;transform:rotate(-90deg)}
.calcring circle{fill:none;stroke-width:3;stroke-linecap:round}
.calcring .trk{stroke:rgba(255,255,255,.10)}
.calcring .arc{stroke:var(--acc);stroke-dasharray:339.3;stroke-dashoffset:339.3;
  transition:stroke-dashoffset 1.2s linear;filter:drop-shadow(0 0 6px rgba(34,200,130,.4))}
.calcring .ctr{position:absolute;inset:0;display:grid;place-items:center;
  font-family:var(--mono);font-variant-numeric:tabular-nums}
.calcring .ctr span{display:flex;align-items:baseline;gap:6px}
.calcring .ctr b{font-size:34px;font-weight:700;letter-spacing:-.04em;color:var(--tx)}
.calcring .ctr i{font-style:normal;font-size:15px;font-weight:700;color:var(--tx3)}
#calcTxt{position:static;margin:0;font-size:clamp(18px,2.2vw,24px);font-weight:700;letter-spacing:-.02em;
  color:var(--tx,#E8F0EE);text-shadow:none;min-height:1.2em}
.calclist{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:7px;align-items:flex-start}
.calclist li{display:flex;align-items:center;gap:9px;font-size:var(--fz-body);color:var(--tx3);opacity:.5;
  transition:opacity .25s var(--ease),color .25s var(--ease)}
.calclist li.now{color:var(--tx);opacity:1}
.calclist li.done{color:var(--tx2);opacity:1}
.calclist .ck{width:14px;height:14px;flex:0 0 auto;fill:none;stroke:var(--acc);stroke-width:2.2;
  stroke-linecap:round;stroke-linejoin:round}
.calclist .ck path{stroke-dasharray:16;stroke-dashoffset:16}
.calclist li.done .ck path{stroke-dashoffset:0;transition:stroke-dashoffset .4s var(--ease)}
@media (prefers-reduced-motion: reduce){
  #calc::before{animation:none;opacity:.5;transform:none}
  .calcbox{transition:none}
  .calcring .arc{transition:none}
  .calclist li,.calclist li.done .ck path{transition:none}
}


/* revamp polish, retired by the 14 Sep client pass: the plate no longer has a
   height cap to yield -- the frame is always drawn at its true ratio, and the
   column scrolls when the head carries its third row. */
