/* ═══════════════════════════════════════════════════════════════════
   GN COLLECTION — THE CONSOLE AND THE COST LANDSCAPE (styles)
   Lifted out of p1.html on 1 Sep 2026 so two pages can wear it:
     /p1          the project page, where it sits inside the argument
     /ghostnets   the instrument on its own, a link she can hand out
   The markup lives in both pages; this file and gnlab.js are the one
   copy of everything that isn't markup. Change a colour here and both
   pages change together — that is the whole point of the split.
   Load it AFTER editorial.css: several rules here win on order alone.
   ═══════════════════════════════════════════════════════════════════ */

/* ═══ THE BOARD ═══ */
/* --b-panel is deliberately near-black in BOTH themes — it is the token
   for the dark pixel screens, not a surface colour. Using it for the
   board's chrome put light-mode text, which flips dark, onto a black
   panel at 1.07:1. The chrome follows the page; only the canvas stays a
   screen. */
/* The note above the console. Every colour here carries !important on
   purpose: editorial.css flattens colour on h1-h6/p/li/span with
   `color:inherit !important` to keep the skin uniform, and the file's own
   comment says the way back is a more specific !important rule. */
.lab-intro{ width:min(1180px,calc(100vw - 2.4rem)); margin:2.6rem auto .9rem; }
.lab-intro h2{ font-size:.62rem; letter-spacing:.16em; text-transform:uppercase;
      color:var(--b-muted) !important; margin:0 0 .6rem; font-weight:700; }
.lab-intro p{ margin:0 0 .5rem; max-width:62ch; font-size:.86rem; line-height:1.75;
      color:var(--b-ink) !important; }
.lab-intro p:last-of-type{ margin-bottom:0; }
.lab-intro p b{ font-weight:700; color:var(--b-ink) !important; }
/* measured in rem, not ch: at this font-size 62ch collapsed the two
   columns to 172px and broke every line. */
.lab-key{ list-style:none; margin:1rem 0 0; padding:0;
      display:grid; gap:.32rem 1.4rem; max-width:46rem;
      font-size:.62rem; letter-spacing:.03em; line-height:1.65;
      color:var(--b-muted) !important; }
@media(min-width:700px){ .lab-key{ grid-template-columns:1fr 1fr; } }
.lab-key li{ padding-left:.9rem; position:relative; color:var(--b-muted) !important; }
.lab-key li::before{ content:''; position:absolute; left:0; top:.5em;
      width:5px; height:5px; background:var(--b-acc); }
/* and the one line under the whole instrument. The console's own bottom
   margin is pulled in when this follows it, rather than cancelled with a
   negative margin that would drift if either value changed. */
.lab:has(+ .lab-foot){ margin-bottom:1rem; }
.lab-foot{ width:min(1180px,calc(100vw - 2.4rem)); margin:0 auto 3rem;
      font-size:.72rem; line-height:1.7; color:var(--b-muted) !important; }
.lab-foot span{ display:block; max-width:70ch; color:var(--b-muted) !important; }

.lab{ width:min(1180px,calc(100vw - 2.4rem)); margin:2.2rem auto 3rem;
      border:2px solid var(--b-ink); background:var(--b-bg);
      font-family:var(--b-mono,ui-monospace,Menlo,monospace); }
.lab-strip{ display:flex; flex-wrap:wrap; align-items:center; gap:.7rem;
      padding:.5rem .8rem; border-bottom:2px solid var(--b-ink);
      font-size:0.66rem; letter-spacing:.1em; text-transform:uppercase;
      color:var(--b-muted); font-variant-numeric:tabular-nums; }
.lab-strip b{ color:var(--b-ink); font-weight:700; }
.lab-warn{ margin-left:auto; color:var(--b-b2); font-weight:700; }
.lab-body{ display:grid; grid-template-columns:1fr; }
@media(min-width:900px){ .lab-body{ grid-template-columns:170px 1fr 250px; } }
.lab-left,.lab-right{ padding:.8rem; }
@media(min-width:900px){
  .lab-left{ border-right:2px solid var(--b-ink); }
  .lab-right{ border-left:2px solid var(--b-ink); }
}
.lab-mid{ padding:.8rem; min-width:0; }
.ctrl-row{ display:block; font-size:0.66rem; letter-spacing:.08em;
      text-transform:uppercase; color:var(--b-muted); margin-bottom:.85rem; }
.ctrl-row .val{ float:right; color:var(--b-ink); font-variant-numeric:tabular-nums; }
.ctrl-row input[type=range]{ width:100%; margin-top:.3rem; }
.lab-rule{ border:0; border-top:1px solid var(--b-line2); margin:.9rem 0; }
.lab-acct{ font-size:0.66rem; line-height:1.9; color:var(--b-faint);
      letter-spacing:.06em; text-transform:uppercase; }
/* the chart keeps the field's true 600:380 aspect, whatever the column
   width — a fixed height stretched storms into ellipses next to their
   own perfectly round dashed outlines */
.board-wrap{ position:relative; aspect-ratio:600/380; max-height:640px;
  border:1px solid var(--b-line2); }

/* the console chart is SHARP by request — the pixel art belongs to the
   figures below, this panel is the tool */
#p1-board{ width:100%; height:100%; display:block; image-rendering:auto; }
/* the figure is light in both themes: it is a plot, and a resistance
   scale that followed the hue slider would be a scale that lies */
.board-wrap{ background:#f4f8fd !important; border-color:#c9d4de !important; }
.board-legend{ position:absolute; right:.5rem; top:.4rem;
  font-size:0.66rem; letter-spacing:.05em; display:flex; gap:.75rem;
  align-items:center; background:rgba(244,248,253,.92);
  border:1px solid #c9d4de; padding:.2rem .45rem; color:#1a1a1a;
  pointer-events:none; }
.board-legend .lg-div{ display:flex; align-items:center; gap:.3rem; }
.board-legend .lg-div i{ display:block; width:46px; height:7px;
  background:linear-gradient(90deg,#b2182b,#f7f7f7,#2166ac); }
.board-legend .lg-gr{ color:#4a545e; } .board-legend .lg-rp{ color:#2e4057; }
.board-legend .lg-net{ display:flex; align-items:center; gap:.28rem; }
.board-legend .lg-net b{ width:7px; height:7px; border-radius:50%;
  background:#2e7d4f; display:block; }
/* closed water: the hatched core of a storm where the sea is over the
   vessel's limit — the same hatch the chart draws */
.board-legend .lg-nogo{ display:flex; align-items:center; gap:.28rem; }
.board-legend .lg-nogo i{ display:block; width:12px; height:9px; box-sizing:border-box;
  border:1px solid #b2182b;
  background:repeating-linear-gradient(135deg, transparent 0 2px, rgba(178,24,43,.55) 2px 3px); }
.board-scale{ position:absolute; left:.5rem; bottom:.4rem;
  display:flex; align-items:center; gap:.35rem; font-size:0.66rem;
  color:#1a1a1a; background:rgba(244,248,253,.92); border:1px solid #c9d4de;
  padding:.15rem .4rem; pointer-events:none; }
.board-time{ display:flex; align-items:center; gap:.7rem; margin:.55rem 0 0; }
.board-time .tplay{ width:2.4rem; flex:none; }
.board-time input[type=range]{ flex:1; min-width:0; accent-color:var(--b-acc); }
#t-clock{ font:600 11px/1 var(--b-mono, ui-monospace, monospace);
  color:var(--b-muted); flex:none; min-width:4.4rem; text-align:right; }
.board-scale i{ display:block; width:74px; height:7px;
  background:linear-gradient(90deg,#f7fbff,#c6dbef,#6baed6,#2171b5,#08306b); }
.lab-tog{ display:flex; align-items:center; gap:.45rem; font-size:0.66rem;
  letter-spacing:.06em; text-transform:uppercase; color:var(--b-muted);
  margin:.3rem 0; cursor:pointer; }
.lab-tog input{ accent-color:var(--b-acc); }
.lab-tog .ls{ display:inline-block; width:16px; flex:none; border-top:2px solid var(--b-acc); }
.lab-tog .ls.dash{ border-top-style:dashed; border-top-color:var(--b-b2); }
.lab-tog .ls.dot{ border-top-style:dotted; border-top-color:var(--b-faint); }
.lab-tog .ls.storm{ border-top-style:dashed; border-top-color:var(--b-b2); width:10px; }
.lab-tog .ls.chase{ border-top-color:#b2182b; border-top-width:3px; width:12px; }
#t-status{ color:var(--b-acc); font-weight:700; }
/* the convergence subfigure: paper in both themes, like the chart */
.curve-cv{ width:100%; height:96px; display:block;
  background:#f4f8fd; border:1px solid #c9d4de; }

/* p1 only: plain white paper, no hue system. The one accent is the
   card's steel blue; the theme toggle is hidden because white is the
   design here, not a preference. */
html[data-theme="light"]{
  --b-acc:#1d4e73;
  --b-b1:#245c8a; --b-b1-ink:#ffffff;
  --b-b2:#5a646e; --b-b2-ink:#ffffff;
}
.theme-toggle{ display:none !important; }
#t-status{ color:#1d4e73; }
.btn.inst.active{ background:var(--b-ink); color:var(--b-bg); }
.stoplist{ max-height:230px; overflow:auto; }
.board-legend .lg-you{ color:var(--b-ink); }
.board-legend .lg-opt{ color:var(--b-acc); }
.board-legend .lg-gr{ color:var(--b-b2); }
.board-legend .lg-rp{ color:var(--b-faint); }
.arc-line{ min-height:2.6rem; margin-top:.5rem; padding:.4rem .5rem;
      border:1px solid var(--b-line2); font-size:0.66rem; line-height:1.7;
      color:var(--b-muted); display:flex; flex-wrap:wrap; gap:.1rem .9rem;
      font-variant-numeric:tabular-nums; }
.arc-line b{ color:var(--b-ink); }
.arc-line .good{ color:var(--b-acc); font-weight:700; }
.arc-line .bad{ color:var(--b-b2); font-weight:700; }
/* /ghostnets gets the same real-arc readout as /p1, but kept secondary —
   a cold visitor gets the extra explanation without it competing with
   the console's actual controls for attention. No border box, smaller
   and fainter text, less reserved height (it wraps to two lines instead
   of reserving one tall empty box up front). */
.arc-line-compact{ min-height:0; border:0; padding:.35rem 0 0; margin-top:.4rem;
      font-size:0.62rem; line-height:1.6; color:var(--b-faint); }
.rail-h{ font-size:0.66rem; letter-spacing:.14em; text-transform:uppercase;
      color:var(--b-muted); margin:0 0 .5rem; font-weight:700; }
.stoplist{ list-style:none; margin:0; padding:0; }
.stop{ display:flex; align-items:center; gap:.35rem; padding:.22rem 0;
      font-size:0.66rem; border-bottom:1px solid var(--b-line2);
      font-variant-numeric:tabular-nums; }
.stop .ord{ color:var(--b-faint); }
.stop .nm{ color:var(--b-ink); font-weight:700; }
.stop .kg{ color:var(--b-muted); }
.stop .dlt{ margin-left:auto; font-weight:700; }
.stop .dlt.neg{ color:var(--b-acc); } .stop .dlt.pos{ color:var(--b-muted); }
.stop.over{ opacity:.5; text-decoration:line-through; }
.stop.over .dlt{ color:var(--b-b2); text-decoration:none; }
.stop.closed .dlt{ color:#b2182b; }
.stop .acts button{ background:none; border:0; color:var(--b-faint);
      cursor:pointer; font-size:.6rem; padding:0 .12rem; }
.stop .acts button:hover{ color:var(--b-ink); }
.rail-empty{ font-size:0.66rem; color:var(--b-faint); line-height:1.6; }
.rail-add{ display:flex; gap:.3rem; margin-top:.6rem; }
.rail-add select{ flex:1; min-width:0; font-family:inherit; font-size:0.66rem;
      background:var(--b-bg); color:var(--b-ink);
      border:1px solid var(--b-line2); padding:.25rem; }
.ratio-eq{ font-size:0.66rem; color:var(--b-faint); }
.ratio-big{ font-size:1.5rem; font-weight:700; color:var(--b-ink);
      line-height:1.2; font-variant-numeric:tabular-nums; }
.ratio-big small{ font-size:0.66rem; font-weight:400; color:var(--b-muted); }
.ratio-sub{ font-size:0.66rem; color:var(--b-muted); letter-spacing:.06em; }
#b-fsolve.stale{ opacity:.4; }
.lam-note{ font-size:0.66rem; color:var(--b-faint); line-height:1.55; margin:.4rem 0 0; }
.lab-res{ border-top:2px solid var(--b-ink); padding:.8rem; }
.resrow{ display:flex; align-items:center; gap:.6rem; margin-bottom:.4rem;
      font-size:0.66rem; font-variant-numeric:tabular-nums; }
/* the band, her prototype's reading: names uppercase, the winner's own
   name in accent and bold behind an uppercase MIN marker. editorial.css
   already hatches the losers and solidifies the winner's bar. */
.resrow .rl{ width:9.5rem; flex:none; color:var(--b-muted);
      text-transform:uppercase; letter-spacing:.08em;
      letter-spacing:.1em; text-transform:uppercase; }
.resrow .rbar{ flex:1; min-width:40px; height:13px; background:var(--b-line2); }
.resrow .rbar i{ display:block; height:100%; background:var(--b-b2); }
.resrow.best .rbar i{ background:var(--b-acc); }
.resrow.best .rl{ color:var(--b-acc) !important; font-weight:700; }
.resrow.best .rl::before{ content:'MIN \25B8  '; }
.resrow.best .rv{ color:var(--b-acc) !important; font-weight:700; }
.resrow .rv{ width:6.5rem; flex:none; text-align:right; color:var(--b-ink); }
.resrow .rn{ width:8rem; flex:none; text-align:right; color:var(--b-faint); }
.lab-bar{ display:flex; flex-wrap:wrap; gap:.4rem; padding:.7rem .8rem;
      border-top:2px solid var(--b-ink); }
.lab-bar .btn{ font-family:inherit; font-size:0.66rem; letter-spacing:.1em;
      text-transform:uppercase; padding:.42rem .8rem; cursor:pointer;
      background:var(--b-bg); color:var(--b-ink);
      border:2px solid var(--b-ink); }
.lab-bar .btn:hover{ background:var(--b-ink); color:var(--b-bg); }
.lab-bar .btn-fill{ background:var(--b-b1); color:var(--b-b1-ink);
      border-color:var(--b-b1); margin-left:auto; }
/* RECOMPUTE/CONSTRUCTION while a solve/replay is running — same "don't
   pretend this is idle" signal the PNG export button already gives
   itself (.cost-actions .btn[disabled], elsewhere in this sheet). Native
   disabled buttons don't fire :hover in any mainstream browser, so
   opacity alone is enough — no separate hover override needed, which
   also avoids fighting .btn-fill's own background on b-solve. */
.lab-bar .btn[disabled]{ opacity:.5; cursor:default; }
/* ═══ PHONES ═══
   This block sits at the END of the sheet on purpose. Placed earlier it
   lost to the base .lab rules below it — same specificity, later wins,
   media query or not — which is why the select stayed at 9px.
   Measured on a 375px screen before this block: the smallest text in the
   console was 8px, the controls 9.3px, the stop-list buttons 10x12px and
   the checkboxes 13px — against a 44px touch-target guideline. The legend
   and the scale, corner chips on a desktop, covered a fifth of a chart
   that was itself only 19% of the screen height. */
@media(max-width:899px){
  /* the chart keeps its aspect; the legend and scale stop sitting on top
     of it and become rows underneath, inside the same frame */
  .board-wrap{ aspect-ratio:auto; max-height:none; }
  #p1-board{ height:auto; aspect-ratio:600/380; }
  .board-legend,.board-scale{ position:static; border:0; border-top:1px solid #c9d4de;
    width:auto; padding:.4rem .5rem; background:none; font-size:0.66rem;
    display:flex; flex-wrap:wrap; align-items:center; gap:.5rem; }
  .board-legend{ justify-content:flex-start; }

  /* type: nothing in the console below 11px */
  .lab-strip,.lab-tog,.ctrl-row,.rail-h,.arc-line,.lab-acct,.stop,.ratio-sub,
  .lam-note,.storm-note,.rail-empty,.resrow,.ratio-eq,.lab-bar .btn,
  .board-legend,.board-legend span,.board-scale,.board-scale span{
    font-size:.72rem !important; }
  .lab-strip{ gap:.45rem .8rem; }
  .lab-key{ font-size:.72rem; }

  /* the result rows carry three fixed columns adding up to 25rem plus
     the bar, which needs about 450px. A phone has 375, body clips the
     overflow, and the last column — the one with the kilograms in it —
     was simply gone. The label takes its own line instead. */
  .resrow{ flex-wrap:wrap; }
  .resrow .rl{ width:100%; }
  .resrow .rv{ width:auto; min-width:5rem; }
  .resrow .rn{ width:auto; }

  /* touch targets. 16px on the select because iOS zooms the whole page
     when a focused control is smaller than that. */
  .lab-tog{ min-height:44px; gap:.7rem; margin:0; }
  .lab-tog input[type=checkbox]{ width:22px; height:22px; flex:none; }
  .ctrl-row{ padding:.35rem 0; }
  .lab input[type=range]{ height:34px; }
  .rail-add select{ font-size:16px; min-height:44px; }
  .ratio-big small{ font-size:.72rem; }
  .rail-add .btn,.lab-bar .btn{ min-height:44px; padding:.6rem 1rem; }
  .board-time .tplay{ min-width:44px; min-height:44px; font-size:1rem; }
  .board-time input[type=range]{ height:34px; }
  #b-stops .acts button{ width:34px; height:34px; font-size:.8rem; }
  .stop{ gap:.35rem; padding:.3rem 0; }
  .stoplist{ max-height:none; }

  /* the buttons under the console stack into reachable rows */
  .lab-bar{ gap:.5rem; }
  .lab-bar .btn{ flex:1 1 45%; }
  .lab-bar .btn-fill{ flex-basis:100%; margin-left:0; }
}

/* ═══ THE COST LANDSCAPE ═══
   The resistance field the chart above draws flat, drawn instead as
   terrain: height is litres per hour. Ridgelines rather than a filled
   mesh, which is how her own surface plots read and costs nothing to
   draw. */
.cost-wrap{ width:min(1180px,calc(100vw - 2.4rem)); margin:0 auto 3rem; }
.cost-h{ font-size:.72rem; letter-spacing:.16em; text-transform:uppercase;
  color:var(--b-muted) !important; margin:0 0 .6rem; font-weight:700; }
.cost-lead{ margin:0 0 .9rem; max-width:62ch; font-size:.86rem; line-height:1.75;
  color:var(--b-ink) !important; }
.cost-box{ position:relative; border:1px solid #c9d4de; background:#ffffff; }
.cost-box svg{ display:block; width:100%; height:auto; touch-action:none; }

.cost-read{ display:flex; flex-wrap:wrap; align-items:baseline; gap:.4rem 1.8rem;
  margin-top:.8rem; font-family:var(--b-mono,ui-monospace,Menlo,monospace);
  font-size:.72rem; letter-spacing:.04em; color:var(--b-muted) !important;
  font-variant-numeric:tabular-nums; }
.cost-read b{ color:var(--b-ink) !important; font-weight:700; }
.cost-read .hot{ color:#b2182b !important; font-weight:700; }
/* the two numbers the picture exists to deliver, at the size of an answer */
.cost-read .big{ font-size:1.6rem; font-weight:700; letter-spacing:-.01em;
  color:var(--b-ink) !important; line-height:1; }
.cost-read .big small{ font-size:.72rem; font-weight:400; letter-spacing:.06em;
  color:var(--b-muted) !important; margin-left:.25rem; }
.cost-read .cols{ display:flex; flex-wrap:wrap; gap:.3rem 1.2rem; }
.cost-time{ display:flex; align-items:center; gap:.8rem; margin-top:.9rem;
  font-family:var(--b-mono,ui-monospace,Menlo,monospace); font-size:.7rem;
  letter-spacing:.08em; text-transform:uppercase; color:var(--b-muted) !important; }
.cost-time input[type=range]{ flex:1; min-width:0; max-width:26rem;
  accent-color:var(--b-acc); height:30px; }
#cost-meet-v{ min-width:5.5rem; text-align:right; font-weight:700;
  color:var(--b-ink) !important; font-variant-numeric:tabular-nums; }
@media(max-width:899px){ .cost-time input[type=range]{ height:44px; } }
.cost-actions{ display:flex; align-items:center; gap:.9rem; flex-wrap:wrap; margin-top:.9rem; }
.cost-actions .btn{ font-family:var(--b-mono,ui-monospace,Menlo,monospace);
  font-size:.66rem; letter-spacing:.1em; text-transform:uppercase;
  padding:.5rem .9rem; cursor:pointer;
  background:var(--b-bg); color:var(--b-ink) !important;
  border:2px solid var(--b-ink); }
.cost-actions .btn:hover{ background:var(--b-ink); color:var(--b-bg) !important; }
.cost-actions .btn[disabled]{ opacity:.5; cursor:default; }
.cost-note{ font-family:var(--b-mono,ui-monospace,Menlo,monospace);
  font-size:.66rem; color:var(--b-muted) !important; }
@media(max-width:899px){ .cost-actions .btn{ min-height:44px; } }
@media(max-width:899px){
  .cost-box{ aspect-ratio:1180/560; }
  .cost-read{ font-size:.72rem; gap:.3rem 1rem; }
}

/* ═══ PLAIN ═══════════════════════════════════════════════════════════
   The console as /ghostnets wears it: one frame instead of eleven. On
   /p1 the instrument sits inside a long argument and the rules help the
   eye find its edges; standing on its own page it only has to be itself,
   and the boxes started reading as apparatus.

   Every rule below removes a border or quiets a line. Not one of them
   changes a control, a reading or a number — the page passes the same
   class to the same markup, and gnlab.js never looks at it. Add `plain`
   to the body of /p1 and it gets the same treatment.
   ═══════════════════════════════════════════════════════════════════ */
.plain .lab{ border-width:1px; border-color:var(--b-line2); }
.plain .lab-strip{ border-bottom:1px solid var(--b-line2); }
@media(min-width:900px){
  /* air between the rails and the chart instead of a rule, which needs
     a little more of it than a border did */
  .plain .lab-body{ grid-template-columns:178px 1fr 254px; }
  .plain .lab-left{ border-right:0; padding-right:1.2rem; }
  .plain .lab-right{ border-left:0; padding-left:1.2rem; }
}
.plain .board-wrap{ border:0; }
/* the legend and the scale lose their frames and go back to being
   labels. The pale wash under them stays: they sit ON the chart, and a
   storm can put deep blue exactly where the legend is — dropping it
   entirely traded a border for an unreadable line. */
.plain .board-legend,.plain .board-scale{ border:0;
  background:rgba(244,248,253,.84); }
.plain .arc-line{ border:0; padding:.45rem 0 0; }
.plain .curve-cv{ border:0; }
.plain .lab-res,.plain .lab-bar{ border-top:1px solid var(--b-line2); }
.plain .stop{ border-bottom:0; padding:.26rem 0; }
.plain .rail-add select{ border:1px solid var(--b-line2); }
/* the row of buttons was seven black rectangles; a hairline is enough to
   say "pressable", and editorial.css's 2px !important has to be told */
.plain .lab-bar .btn{ border:1px solid var(--b-line2) !important; }
.plain .lab-bar .btn:hover{ border-color:var(--b-ink) !important; }
/* and the loaded example finally shows which one it is: editorial.css
   flattens .btn with !important, so the active state never landed */
.plain .lab-bar .btn.inst.active{ background:var(--b-ink) !important;
  color:var(--b-bg) !important; border-color:var(--b-ink) !important; }
/* .storm-note has no base rule anywhere, so this line — the only prose
   in the left rail — came out at browser default size next to 10px type */
.plain .storm-note{ font-size:0.66rem; line-height:1.6; margin:.35rem 0 0;
  color:var(--b-faint) !important; }
/* the strip on /ghostnets carries only the badge, and .lab-warn pushes
   itself right with margin-left:auto — alone, that stranded it across an
   empty bar. First child means it is the only thing there. */
.plain .lab-warn:first-child{ margin-left:0; }

/* ═══ PLAIN, ON A PHONE ═══════════════════════════════════════════════
   The desktop console is three columns: controls, chart, route. Stacked
   on a phone in that order the chart — the thing itself — arrived after
   six hundred pixels of sliders. So on a narrow screen the order is what
   a thumb wants: the chart first, then the route it builds, then the
   things you can change; the controls pack two and three to a row, and
   the convergence plot — a diagnostic — stays on the wide screen. Scoped
   to .plain: /p1 keeps its own phone layout. */
@media(max-width:899px){
  .plain .lab-body{ display:flex; flex-direction:column; }
  .plain .lab-mid{ order:1; padding:.6rem .6rem 0; }
  .plain .lab-right{ order:2; padding:.8rem .8rem .2rem; }
  .plain .lab-left{ order:3; padding:.4rem .8rem .8rem; }

  /* the controls pack: sliders full width but tighter, the two
     algorithm toggles side by side, the three storms in one row */
  .plain .lab-left{ display:flex; flex-wrap:wrap; align-items:center; gap:0 .7rem; }
  .plain .lab-left > *{ flex:1 1 100%; }
  .plain .lab-left .ctrl-row{ padding:.1rem 0; margin-bottom:.35rem; }
  .plain .lab-left .lab-rule{ margin:.5rem 0; }
  .plain .lab-left .rail-h{ margin:.1rem 0 .2rem; }
  .plain .lab-left .lab-tog{ min-height:40px; margin:0; }
  /* the three storms share a row; their labels are short enough not to
     wrap once the gaps inside the row are trimmed */
  .plain .lab-left .lab-tog:has(input[id^="storm-"]){ flex:1 1 26%; gap:.3rem; }
  .plain .lab-left .lab-tog:has(input[id^="storm-"]) span{ white-space:nowrap; }
  .plain .lab-left .lab-tog:has(input[id^="storm-"]) .ls{ width:8px; }
  .plain .lab-left .storm-note{ margin:0 0 .2rem; }

  /* the route rail: the list, the ratio, nothing else */
  .plain .lab-right .rail-h:has(+ .curve-cv),
  .plain .lab-right .lab-rule:has(+ .rail-h + .curve-cv),
  .plain .lab-right .curve-cv{ display:none; }

  /* the three examples share one row; the rest pair up */
  .plain .lab-bar{ gap:.4rem; }
  .plain .lab-bar .btn.inst{ flex:1 1 28%; }
  .plain .lab-bar .btn{ padding:.55rem .4rem; }
  .plain .lab-res{ padding:.6rem .8rem .3rem; }
}
