/* ============================================================================
   Toolsfully — Local Workbench
   Organised as: 1 tokens · 2 foundations · 3 layout · 4 components · 5 pages

   The site's 30-odd per-page <style> blocks consume the legacy variable names
   (--bg, --card, --line …), so those are kept as aliases of the new tokens.
   Retokenising here restyles every page without touching their markup.
   ========================================================================== */

/* ============================ 1 · TOKENS ================================= */
:root{
  color-scheme:light dark;

  /* warm work surface, near-black ink */
  --color-canvas:#f3f0e8;
  --color-surface:#fcfaf4;
  --color-raised:#ffffff;
  --color-ink:#181a17;
  --color-muted:#63665e;
  --color-faint:#d8d4c8;
  --color-brand:#2156d9;
  --color-brand-strong:#163b98;
  --color-local:#c7f36b;
  --color-on-local:#181a17;   /* lime keeps dark ink in both themes */
  --color-logo:#4a52dc;             /* the logo's blue-to-violet, stepped darker so white text reads: 5.95:1 */
  --color-logo-2:#7244e0;           /* 5.80:1 with white */
  --color-on-logo:#ffffff;
  --color-attention:#f26a3d;        /* accent marks only — 2.67:1, not for text */
  --color-attention-text:#b0451f;   /* same hue, 4.96:1 on canvas — AA for text */
  --color-success:#18794e;
  --color-danger:#c33c34;
  --color-focus:#2156d9;

  --font-ui:'Manrope',ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif;
  --font-mono:'IBM Plex Mono',ui-monospace,SFMono-Regular,Consolas,monospace;

  --text-xs:.6875rem; --text-sm:.875rem; --text-md:1rem; --text-lg:1.125rem;
  --text-xl:1.375rem;
  --text-2xl:clamp(1.5rem,2.6vw,2.15rem);
  --text-3xl:clamp(2rem,4.4vw,3.25rem);

  --space-1:.25rem; --space-2:.5rem; --space-3:.75rem; --space-4:1rem;
  --space-6:1.5rem; --space-8:2rem; --space-12:3rem; --space-16:4rem; --space-24:6rem;

  --radius-control:.625rem;
  --radius-panel:.875rem;
  --radius-round:999px;

  --border:1px solid var(--color-ink);
  --border-subtle:1px solid var(--color-faint);
  --shadow-offset:4px 4px 0 var(--color-ink);
  --shadow-offset-sm:3px 3px 0 var(--color-ink);
  --shadow-focus:0 0 0 2px var(--color-canvas),0 0 0 5px var(--color-focus);

  --duration-fast:120ms; --duration-standard:180ms; --duration-slow:280ms;
  --ease-out:cubic-bezier(.2,.8,.2,1);

  --page-max:77.5rem;
  --measure:68ch;
  --header-height:4.5rem;

  /* legacy aliases — every per-page style block still resolves through these */
  --bg:var(--color-canvas);
  --card:var(--color-surface);
  --ink:var(--color-ink);
  --muted:var(--color-muted);
  --line:var(--color-faint);
  --brand:var(--color-brand);
  --brand-2:var(--color-brand-strong);
  --ok:var(--color-success);
  --bad:var(--color-danger);
  --shadow:var(--shadow-offset-sm);
  --radius:var(--radius-panel);
}

/* drafting desk, not neon */
[data-theme="dark"]{
  --color-canvas:#171814; --color-surface:#20211c; --color-raised:#292a24;
  --color-ink:#f4f1e8; --color-muted:#aaa99f; --color-faint:#3b3c34;
  --color-brand:#7192f3; --color-brand-strong:#9bb0f5; --color-local:#b9e95e; --color-on-local:#181a17;
    --color-logo:#8f97f6; --color-logo-2:#b394f8; --color-on-logo:#181a17;
  --color-attention:#ff835d; --color-attention-text:#ff835d;
  --color-success:#74c69d; --color-danger:#ff8078;
  --color-focus:#91a8f7;
  --shadow-offset:4px 4px 0 #3b3c34;
  --shadow-offset-sm:3px 3px 0 #3b3c34;
}
@media (prefers-color-scheme:dark){
  :root:not([data-theme="light"]){
    --color-canvas:#171814; --color-surface:#20211c; --color-raised:#292a24;
    --color-ink:#f4f1e8; --color-muted:#aaa99f; --color-faint:#3b3c34;
    --color-brand:#7192f3; --color-brand-strong:#9bb0f5; --color-local:#b9e95e; --color-on-local:#181a17;
    --color-logo:#8f97f6; --color-logo-2:#b394f8; --color-on-logo:#181a17;
    --color-attention:#ff835d; --color-attention-text:#ff835d;
    --color-success:#74c69d; --color-danger:#ff8078;
    --color-focus:#91a8f7;
    --shadow-offset:4px 4px 0 #3b3c34;
    --shadow-offset-sm:3px 3px 0 #3b3c34;
  }
}

/* ========================= 2 · FOUNDATIONS =============================== */
/* self-hosted: no third-party font request is made at runtime */
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('fonts/manrope-var-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}
@font-face{font-family:'Manrope';font-style:normal;font-weight:400 800;font-display:swap;
  src:url('fonts/manrope-var-latin-ext.woff2') format('woff2');
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF}
@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;
  src:url('fonts/ibm-plex-mono-500-latin.woff2') format('woff2');
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD}

*{box-sizing:border-box}
html,body{margin:0;padding:0}
html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
body{
  font-family:var(--font-ui);
  font-size:var(--text-md);
  font-weight:450;
  background:var(--color-canvas);
  color:var(--color-ink);
  line-height:1.6;
  -webkit-font-smoothing:antialiased;
}
h1,h2,h3,h4{font-weight:750;letter-spacing:-.03em;line-height:1.15}
a{color:var(--color-brand);text-decoration:none}
a:hover{text-decoration:underline}
code,kbd,samp{font-family:var(--font-mono);font-size:.92em}


::selection{background:var(--color-local);color:var(--color-on-local)}

@media (prefers-reduced-motion:reduce){
  html{scroll-behavior:auto}
  *,*::before,*::after{
    animation-duration:.01ms !important;animation-iteration-count:1 !important;
    transition-duration:.01ms !important;
  }
  .cat.live:hover,.chooser a:hover,.stat:hover{transform:none !important}
}

/* forced-colors: rely on system paint rather than tokens */
@media (forced-colors:active){
  .card,.cat,.stat,.drop,.file,.tbl,.chooser a,.flagship{border:1px solid CanvasText}
  .go,.tab.active,.cta{forced-color-adjust:none;background:Highlight;color:HighlightText}
}

/* =========================== 3 · LAYOUT ================================== */
.wrap{max-width:var(--page-max);margin:0 auto;padding:0 var(--space-6)}
.narrow{max-width:var(--measure)}
@media (max-width:640px){.wrap{padding:0 var(--space-4)}}

/* --- utility header --- */
header{
  position:sticky;top:0;z-index:20;
  background:var(--color-canvas);
}
.bar{display:flex;align-items:center;gap:var(--space-4);min-height:var(--header-height);flex-wrap:wrap}
.logo{display:flex;align-items:center;gap:var(--space-2);color:var(--color-ink);flex:0 0 auto}
.logo:hover{text-decoration:none}
.logo .mark{width:26px;height:26px;display:block;object-fit:contain}
.logo .word{
  font-family:var(--font-ui);
  font-weight:800;font-size:1.3rem;letter-spacing:-.045em;line-height:1;
  color:var(--color-ink);
  /* no gradient text: the mark carries the colour, the wordmark carries the weight */
  background:none;-webkit-text-fill-color:currentColor;
}
.nav{display:flex;gap:var(--space-4);font-size:var(--text-sm);font-weight:600;flex-wrap:wrap;flex:1 1 auto}
.nav a{color:var(--color-muted);white-space:nowrap;padding:2px 0;border-bottom:2px solid transparent}
.nav a:hover{color:var(--color-ink);text-decoration:none;border-bottom-color:var(--color-ink)}
.nav a[aria-current="page"]{color:var(--color-ink);border-bottom-color:var(--color-brand)}

/* theme control sits at the end of the bar */
.themebtn{
  flex:0 0 auto;display:inline-flex;align-items:center;gap:var(--space-2);
  min-height:40px;padding:0 var(--space-3);
  background:var(--color-surface);border:var(--border-subtle);border-radius:var(--radius-control);
  color:var(--color-muted);font:inherit;font-size:var(--text-xs);font-family:var(--font-mono);
  letter-spacing:.09em;text-transform:uppercase;cursor:pointer;
  transition:color var(--duration-fast) var(--ease-out),border-color var(--duration-fast) var(--ease-out);
}
.themebtn:hover{color:var(--color-ink);border-color:var(--color-ink)}
.themebtn .ico{width:14px;height:14px;flex:0 0 auto}
@media (max-width:940px){
  .bar{padding:var(--space-3) 0;row-gap:var(--space-2)}
  .nav{gap:var(--space-2) var(--space-4);order:3;width:100%}
  .themebtn .lbl{display:none}
  .themebtn{padding:0 var(--space-2)}
}

/* --- masthead: left-aligned editorial, never centred --- */
.hero{
  padding:var(--space-12) 0 var(--space-6);
  display:grid;grid-template-columns:minmax(0,8fr) minmax(0,4fr);
  gap:var(--space-8);align-items:end;
}
.hero h1{
  font-size:var(--text-3xl);line-height:.98;letter-spacing:-.045em;
  margin:0 0 var(--space-4);max-width:20ch;
}
/* emphasis without a gradient */
.hero h1 .g{
  color:inherit;background:none;-webkit-text-fill-color:currentColor;
  text-decoration:underline;text-decoration-color:var(--color-brand);
  text-decoration-thickness:.075em;text-underline-offset:.1em;
}
.hero p{font-size:var(--text-lg);color:var(--color-muted);max-width:var(--measure);margin:0}
@media (max-width:900px){
  .hero{grid-template-columns:1fr;gap:var(--space-4);padding:var(--space-8) 0 var(--space-4)}
  .hero h1{max-width:none}
}

/* --- footer directory --- */
footer{
  border-top:var(--border);margin-top:var(--space-16);padding:var(--space-8) 0 var(--space-12);
  color:var(--color-muted);font-size:var(--text-sm);
}
footer .fnav{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-4);margin-bottom:var(--space-4)}
footer .fnav a{color:var(--color-muted);margin:0}
footer .fnav a:hover{color:var(--color-ink)}

/* ========================= 4 · COMPONENTS ================================ */

/* --- bench label: small uppercase mono, the system's structural device --- */
.section-title{
  font-family:var(--font-mono);font-size:var(--text-xs);font-weight:600;
  letter-spacing:.09em;text-transform:uppercase;color:var(--color-muted);
  margin:var(--space-12) 0 var(--space-4);
  padding-bottom:var(--space-2);border-bottom:var(--border-subtle);
}

/* --- Local Signal: lime square + RUNS ON THIS DEVICE --- */
.badges{display:flex;gap:var(--space-2) var(--space-4);flex-wrap:wrap;margin:var(--space-6) 0 0;align-items:center}
.badge{
  display:inline-flex;align-items:center;gap:var(--space-2);
  background:none;border:0;border-radius:0;padding:0;
  font-family:var(--font-mono);font-size:var(--text-xs);font-weight:500;
  letter-spacing:.08em;text-transform:uppercase;color:var(--color-muted);
}
.badge::before{
  content:"";width:9px;height:9px;flex:0 0 auto;
  background:var(--color-local);border:1px solid var(--color-ink);
}
.badge b{color:var(--color-ink);font-weight:600}
.local{
  display:inline-flex;align-items:center;gap:var(--space-2);
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--color-muted);
}
.local::before{content:"";width:9px;height:9px;flex:0 0 auto;
  background:var(--color-local);border:1px solid var(--color-ink)}

/* --- indexed tool rows (replaces emoji category cards, no markup change) --- */
.cats{display:flex;flex-direction:column;gap:0;counter-reset:toolrow;border-top:var(--border-subtle)}
.cat{
  counter-increment:toolrow;
  display:grid;grid-template-columns:3.25rem minmax(0,1fr) auto;
  align-items:baseline;gap:0 var(--space-4);
  background:none;border:0;border-bottom:var(--border-subtle);border-radius:0;
  padding:var(--space-4) var(--space-3);position:relative;color:var(--color-ink);
  transition:background var(--duration-standard) var(--ease-out),color var(--duration-standard) var(--ease-out);
}
.cat::before{
  content:counter(toolrow,decimal-leading-zero);
  font-family:var(--font-mono);font-size:var(--text-sm);font-weight:500;
  color:var(--color-muted);letter-spacing:.04em;
}
.cat h3{margin:0;font-size:var(--text-lg);font-weight:700;letter-spacing:-.015em;color:inherit;grid-column:2}
.cat p{margin:var(--space-1) 0 0;color:var(--color-muted);font-size:var(--text-sm);grid-column:2;max-width:62ch}
.cat .tag{
  position:static;grid-column:3;grid-row:1;align-self:center;
  font-family:var(--font-mono);font-size:var(--text-xs);font-weight:500;
  letter-spacing:.08em;text-transform:uppercase;padding:0;border-radius:0;background:none;
}
.cat .tag.on{color:var(--color-success)}
.cat .tag.soon{color:var(--color-muted)}
.cat.live:hover{background:var(--color-brand);color:#fff;text-decoration:none}
.cat.live:hover::before{color:var(--color-local)}      /* index stays lime on hover */
.cat.live:hover p,.cat.live:hover .tag{color:rgba(255,255,255,.86)}
.cat.live:hover::after{content:"→";position:absolute;right:var(--space-3);top:var(--space-4);color:#fff}
.cat.soon{opacity:.65}
@media (max-width:720px){
  /* two-line row: index beside the title, description under it, status last —
     the tag is first in the DOM, so place it explicitly rather than let auto
     flow put it above the heading */
  .cat{grid-template-columns:2.5rem minmax(0,1fr);padding:var(--space-3) var(--space-2)}
  .cat h3{grid-column:2;grid-row:1}
  .cat p{grid-column:2;grid-row:2}
  .cat .tag{grid-column:2;grid-row:3;margin-top:var(--space-1);justify-self:start}
  .cat.live:hover::after{display:none}
}

/* --- tool panel: rules and offset depth, not floating cards --- */
.card{
  background:var(--color-surface);
  border:var(--border);border-radius:var(--radius-panel);
  box-shadow:var(--shadow-offset);
  padding:var(--space-6);
}
@media (max-width:640px){.card{padding:var(--space-4);box-shadow:var(--shadow-offset-sm)}}

/* --- tabs: bottom ink rule, never pills --- */
.tabs{display:flex;gap:var(--space-1);flex-wrap:wrap;margin:0 0 var(--space-6);border-bottom:var(--border-subtle)}
.tab{
  background:none;border:0;border-bottom:2px solid transparent;border-radius:0;
  padding:var(--space-2) var(--space-3);margin-bottom:-1px;
  font:inherit;font-size:var(--text-sm);font-weight:600;color:var(--color-muted);cursor:pointer;
  transition:color var(--duration-fast) var(--ease-out),border-color var(--duration-fast) var(--ease-out);
}
.tab:hover{color:var(--color-ink)}
.tab.active{color:var(--color-ink);border-bottom-color:var(--color-ink);background:none}
.panel{display:none}
.panel.active{display:block}
.panel h2{margin:0 0 var(--space-1);font-size:var(--text-xl);letter-spacing:-.03em}
.panel .sub{color:var(--color-muted);margin:0 0 var(--space-4);font-size:var(--text-sm)}

/* --- drop zone --- */
.drop{
  border:2px dashed var(--color-ink);border-radius:var(--radius-panel);
  padding:var(--space-8) var(--space-6);text-align:center;cursor:pointer;
  background:var(--color-surface);
  /* icon, then the instruction, then the promise — ordered here so the
     markup does not have to be rewritten on 37 zones */
  display:flex;flex-direction:column;align-items:center;gap:var(--space-1);
  transition:background var(--duration-standard) var(--ease-out),
             border-color var(--duration-standard) var(--ease-out),
             transform var(--duration-standard) var(--ease-out);
}
.drop:hover{border-color:var(--color-brand);background:var(--color-raised)}
.drop.drag{border-color:var(--color-brand);background:var(--color-raised);transform:translateY(-2px);box-shadow:var(--shadow-focus)}
/* 48px outlined square holds the document mark — no emoji anywhere */
.drop .ico{
  width:48px;height:48px;margin:0 auto var(--space-3);
  border:var(--border);border-radius:var(--radius-control);
  display:grid;place-items:center;color:var(--color-ink);background:var(--color-raised);
}
.drop .ico svg{width:24px;height:24px}
.drop b,.drop p{display:block;margin:0 0 var(--space-1);font-weight:700;font-size:var(--text-lg)}
.drop small,.drop>span:not(.local){display:block;color:var(--color-muted);font-size:var(--text-sm)}
.drop .ico{order:1}
.drop b,.drop p{order:2}
.drop small,.drop>span:not(.local){order:3}
.drop .local{order:4;margin-top:var(--space-3);justify-content:center}
.drop.drag .ico{border-color:var(--color-brand);color:var(--color-brand)}

/* Once a queue exists the zone stops advertising itself and becomes a slim
   "add more" strip. Done with :has() so no tool's JavaScript has to change;
   browsers without :has() simply keep the full zone, which still works. */
.panel:has(.files .file) .drop,
.mpanel:has(.files .file) .drop,
.card:has(.files .file) .drop{
  padding:var(--space-3) var(--space-4);
  border-width:1px;border-style:dashed;
  flex-direction:row;justify-content:center;gap:var(--space-2);
}
.panel:has(.files .file) .drop .ico,
.mpanel:has(.files .file) .drop .ico,
.card:has(.files .file) .drop .ico,
.panel:has(.files .file) .drop .local,
.mpanel:has(.files .file) .drop .local,
.card:has(.files .file) .drop .local{display:none}
.panel:has(.files .file) .drop b,
.panel:has(.files .file) .drop p,
.mpanel:has(.files .file) .drop b,
.mpanel:has(.files .file) .drop p,
.card:has(.files .file) .drop b,
.card:has(.files .file) .drop p{font-size:var(--text-sm);font-weight:600;color:var(--color-muted);margin:0}
/* --- file rows --- */
.files{list-style:none;margin:var(--space-4) 0 0;padding:0;display:flex;flex-direction:column;gap:0;border-top:var(--border-subtle)}
.file{display:flex;align-items:center;gap:var(--space-3);background:none;border:0;border-bottom:var(--border-subtle);border-radius:0;padding:var(--space-3) var(--space-1)}
.file .fi{
  width:34px;height:34px;border-radius:0;border:var(--border);
  background:var(--color-local);color:var(--color-on-local);
  display:grid;place-items:center;font-family:var(--font-mono);font-size:var(--text-xs);font-weight:600;flex:none;
}
.file .meta{flex:1;min-width:0}
.file .meta b{display:block;font-size:var(--text-sm);font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.file .meta span{font-family:var(--font-mono);font-size:var(--text-xs);color:var(--color-muted)}
.file .ctrls{display:flex;gap:var(--space-1);flex:none}

/* --- buttons --- */
.go{
  background:var(--color-brand);color:#fff;border:var(--border);
  padding:var(--space-3) var(--space-6);border-radius:var(--radius-control);
  font:inherit;font-weight:700;font-size:var(--text-md);cursor:pointer;
  min-height:44px;box-shadow:var(--shadow-offset-sm);
  transition:transform var(--duration-fast) var(--ease-out),box-shadow var(--duration-fast) var(--ease-out),background var(--duration-fast) var(--ease-out);
}
.go:hover{background:var(--color-brand-strong)}
.go:active{transform:translate(2px,2px);box-shadow:none}
.go:disabled{opacity:.45;cursor:not-allowed;box-shadow:none;transform:none}
.cta{
  background:var(--color-brand);color:#fff;border:var(--border);
  padding:var(--space-2) var(--space-4);border-radius:var(--radius-control);
  font:inherit;font-weight:600;font-size:var(--text-sm);cursor:pointer;min-height:40px;
}
.cta.ghost{background:var(--color-surface);color:var(--color-ink)}
.chip{
  background:var(--color-surface);border:var(--border-subtle);border-radius:var(--radius-control);
  padding:var(--space-2) var(--space-3);font:inherit;font-weight:600;font-size:var(--text-sm);
  color:var(--color-muted);cursor:pointer;min-height:40px;
  transition:color var(--duration-fast) var(--ease-out),border-color var(--duration-fast) var(--ease-out);
}
.chip:hover{color:var(--color-ink);border-color:var(--color-ink);text-decoration:none}
.iconbtn{
  width:34px;height:34px;min-width:34px;border:var(--border-subtle);background:var(--color-surface);
  border-radius:var(--radius-control);cursor:pointer;color:var(--color-muted);font-size:var(--text-sm);
  display:grid;place-items:center;
}
.iconbtn:hover{color:var(--color-danger);border-color:var(--color-danger)}
.btn-link{
  display:inline-block;background:var(--color-brand);color:#fff;border:var(--border);
  padding:var(--space-3) var(--space-6);border-radius:var(--radius-control);
  font-weight:700;margin-top:var(--space-2);box-shadow:var(--shadow-offset-sm);
}
.btn-link:hover{text-decoration:none;background:var(--color-brand-strong)}

/* --- fields --- */
.row{display:flex;gap:var(--space-3);align-items:flex-start;flex-wrap:wrap;margin-top:var(--space-4)}
.field{flex:1;min-width:180px}
.field label{display:block;font-size:var(--text-sm);font-weight:600;margin-bottom:var(--space-1)}
.field input,.field select,.field textarea{
  width:100%;padding:var(--space-3);
  border:var(--border-subtle);border-radius:var(--radius-control);
  background:var(--color-raised);color:var(--color-ink);
  font:inherit;font-size:var(--text-md);min-height:44px;
}
.field input:hover,.field select:hover,.field textarea:hover{border-color:var(--color-muted)}
/* numbers align on mono, per the system's instrument-panel character */
.field input[type=number]{font-family:var(--font-mono);font-size:var(--text-sm)}
.field input[type=range]{padding:0;border:0;background:none;accent-color:var(--color-brand);min-height:44px}
.field input[type=checkbox]{width:auto;min-height:0;accent-color:var(--color-brand)}
.field textarea{min-height:200px;line-height:1.6;resize:vertical;font-family:var(--font-mono);font-size:var(--text-sm)}
.checks{display:flex;flex-wrap:wrap;gap:var(--space-2) var(--space-6);margin-top:var(--space-4)}
.checks label{display:flex;align-items:center;gap:var(--space-2);font-size:var(--text-sm);font-weight:600;color:var(--color-muted);cursor:pointer;min-height:40px}
.checks input{accent-color:var(--color-brand);width:18px;height:18px}
.seg{display:inline-flex;border:var(--border);border-radius:var(--radius-control);overflow:hidden}
.seg button{background:var(--color-surface);border:0;padding:var(--space-2) var(--space-4);font:inherit;font-weight:600;font-size:var(--text-sm);color:var(--color-muted);cursor:pointer;min-height:40px}
.seg button.active{background:var(--color-ink);color:var(--color-canvas)}

/* --- status: named stage, polite region --- */
.status{
  margin-top:var(--space-4);font-size:var(--text-sm);font-weight:600;min-height:20px;
  display:flex;gap:var(--space-2);align-items:flex-start;
}
.status:not(:empty)::before{
  content:"";width:9px;height:9px;flex:0 0 auto;margin-top:.45em;
  background:var(--color-muted);border:1px solid var(--color-ink);
}
.status.ok{color:var(--color-success)}
.status.ok::before{background:var(--color-local)}
.status.err{color:var(--color-danger)}
.status.err::before{background:var(--color-danger)}
.status.warn{color:var(--color-attention-text)}
.status.warn::before{background:var(--color-attention)}

/* --- result tables: mono figures --- */
.tblwrap{max-height:360px;overflow:auto;border:var(--border-subtle);border-radius:var(--radius-control);margin-top:var(--space-2);background:var(--color-surface)}
.tbl{width:100%;border-collapse:collapse;font-size:var(--text-sm)}
.tbl th,.tbl td{padding:var(--space-2) var(--space-3);border-bottom:var(--border-subtle);text-align:right;white-space:nowrap}
.tbl td{font-family:var(--font-mono);font-size:var(--text-sm)}
.tbl th:first-child,.tbl td:first-child,.tbl th:nth-child(2),.tbl td:nth-child(2){text-align:left}
.tbl td:first-child,.tbl td:nth-child(2){font-family:var(--font-ui)}
.tbl th{
  position:sticky;top:0;background:var(--color-surface);z-index:1;
  font-family:var(--font-mono);font-size:var(--text-xs);font-weight:500;
  letter-spacing:.06em;text-transform:uppercase;color:var(--color-muted);
  border-bottom:var(--border);
}
.tbl tr:last-child td{border-bottom:none}
.kvgrid{display:grid;grid-template-columns:auto 1fr;gap:var(--space-2) var(--space-4);font-size:var(--text-sm);background:var(--color-surface);border:var(--border-subtle);border-radius:var(--radius-control);padding:var(--space-4)}
.kvgrid b{color:var(--color-muted);font-weight:600}
.kvgrid span{word-break:break-word;font-family:var(--font-mono)}

/* --- output metrics --- */
/* Flex, not grid: a grid leaves the last row short when the tile count does
   not divide evenly, and the container's border draws a box around the empty
   space. Flexed tiles grow to fill whatever row they land on. */
.stats{display:flex;flex-wrap:wrap;gap:0;margin-top:var(--space-6);
  border:var(--border-subtle);border-radius:var(--radius-control);
  overflow:hidden;background:var(--color-surface)}
.stat{flex:1 1 170px;min-width:0;background:none;border:0;
  border-right:var(--border-subtle);border-bottom:var(--border-subtle);
  border-radius:0;padding:var(--space-4)}
.stat span{
  display:block;font-family:var(--font-mono);font-size:var(--text-xs);font-weight:500;
  color:var(--color-muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:var(--space-1);
}
.stat b{font-size:var(--text-xl);letter-spacing:-.03em;line-height:1.15;display:block}
.stat.hi{background:var(--color-local)}
.stat.hi span,.stat.hi b{color:var(--color-on-local)}

/* --- ad slot: labelled, ruled, never button-shaped --- */
.ad{
  margin:var(--space-8) 0;border:var(--border-subtle);border-radius:0;
  padding:var(--space-4);text-align:center;color:var(--color-muted);
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.09em;text-transform:uppercase;
  background:none;min-height:120px;display:grid;place-items:center;
}
.ad::before{content:"Advertisement";display:block;margin-bottom:var(--space-2);opacity:.75}

/* --- feature strip --- */
.why{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:0;margin:var(--space-12) 0;border-top:var(--border-subtle)}
.why .c{background:none;border:0;border-bottom:var(--border-subtle);border-right:var(--border-subtle);border-radius:0;padding:var(--space-6) var(--space-4)}
.why .c h3{margin:0 0 var(--space-2);font-size:var(--text-md)}
.why .c p{margin:0;color:var(--color-muted);font-size:var(--text-sm)}

/* --- editorial content --- */
/* padding-block, not the shorthand: on pages where <main> is both the wrap
   and the article, `padding: X 0` wiped the wrap's side padding and put the
   text against the edge of the screen on mobile. */
.content{padding-block:var(--space-12)}
.wrap>.content.narrow{border-top:var(--border-subtle);margin-top:var(--space-8)}
.content h1{font-size:var(--text-3xl);letter-spacing:-.045em;margin:0 0 var(--space-2)}
.content .lead{color:var(--color-muted);font-size:var(--text-lg);margin:0 0 var(--space-2);max-width:var(--measure)}
.content h2{font-size:var(--text-2xl);letter-spacing:-.035em;margin:var(--space-12) 0 var(--space-3)}
.content h3{font-size:var(--text-lg);margin:var(--space-8) 0 var(--space-2)}
.content p,.content li{color:var(--color-ink);font-size:var(--text-md);max-width:var(--measure)}
.content .muted{color:var(--color-muted)}
.content ul,.content ol{padding-left:var(--space-6)}
.content li{margin:var(--space-1) 0}
.crumb{font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.06em;text-transform:uppercase;color:var(--color-muted);margin-bottom:var(--space-4)}
.callout{background:var(--color-surface);border:var(--border-subtle);border-left:3px solid var(--color-brand);border-radius:0;padding:var(--space-4);margin:var(--space-6) 0;font-size:var(--text-md)}

/* --- guide list: editorial rows, not a card grid --- */
.guide-list{display:flex;flex-direction:column;gap:0;margin-top:var(--space-2);border-top:var(--border-subtle)}
.guide-list a{background:none;border:0;border-bottom:var(--border-subtle);border-radius:0;padding:var(--space-4) var(--space-2);display:block;color:var(--color-ink)}
.guide-list a:hover{background:var(--color-surface);text-decoration:none;box-shadow:none}
.guide-list h3{margin:0 0 var(--space-1);font-size:var(--text-md)}
.guide-list p{margin:0;color:var(--color-muted);font-size:var(--text-sm);max-width:62ch}

/* ====================== 5 · PAGE-LEVEL PATTERNS ========================== */

/* stepper */
.steps{display:flex;flex-wrap:wrap;gap:var(--space-1);margin:0}
.stepbtn{
  display:inline-flex;align-items:center;gap:var(--space-2);
  background:none;border:0;border-bottom:2px solid transparent;border-radius:0;
  padding:var(--space-2) var(--space-3);font:inherit;font-weight:600;font-size:var(--text-sm);
  color:var(--color-muted);cursor:pointer;min-height:40px;
}
.stepbtn span{
  display:inline-flex;align-items:center;justify-content:center;width:20px;height:20px;
  border-radius:0;border:1px solid var(--color-faint);background:none;color:var(--color-muted);
  font-family:var(--font-mono);font-size:var(--text-xs);font-weight:600;flex:0 0 auto;
}
.stepbtn:hover{color:var(--color-ink)}
.stepbtn.done span{background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local)}
.stepbtn.active{color:var(--color-ink);border-bottom-color:var(--color-ink)}
.stepbtn.active span{background:var(--color-ink);border-color:var(--color-ink);color:var(--color-canvas)}
@media (max-width:640px){.stepbtn{font-size:var(--text-xs);padding:var(--space-2)}}

/* flagship callout */
.flagship{
  display:flex;justify-content:space-between;align-items:center;gap:var(--space-6);flex-wrap:wrap;
  background:var(--color-surface);border:var(--border);border-radius:var(--radius-panel);
  box-shadow:var(--shadow-offset);padding:var(--space-6);margin:var(--space-8) 0 var(--space-2);
  text-decoration:none;color:inherit;
  transition:transform var(--duration-standard) var(--ease-out),box-shadow var(--duration-standard) var(--ease-out);
}
.flagship:hover{text-decoration:none;transform:translate(-2px,-2px);box-shadow:6px 6px 0 var(--color-ink)}
.flagship h2{margin:var(--space-2) 0;font-size:var(--text-xl)}
.flagship p{margin:0;color:var(--color-muted);font-size:var(--text-sm);line-height:1.55;max-width:64ch}
.flagship .go{flex:0 0 auto;white-space:nowrap}
.flagship .tag{font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.09em;
  text-transform:uppercase;color:var(--color-muted);display:block;margin-bottom:var(--space-1)}
.flagship .tag.on{color:var(--color-success)}
@media (max-width:640px){.flagship{padding:var(--space-4)}.flagship h2{font-size:var(--text-lg)}.flagship .go{width:100%;text-align:center}}

/* chooser rows */
.chooser{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:var(--space-2);margin:var(--space-4) 0 var(--space-1)}
.chooser button,.chooser a{
  display:block;text-align:left;background:var(--color-surface);
  border:var(--border-subtle);border-radius:var(--radius-control);
  padding:var(--space-3) var(--space-4);color:var(--color-ink);font:inherit;
  text-decoration:none;cursor:pointer;min-height:44px;
  transition:border-color var(--duration-fast) var(--ease-out),background var(--duration-fast) var(--ease-out);
}
.chooser button:hover,.chooser a:hover{border-color:var(--color-ink);background:var(--color-raised);transform:none}
.chooser b{display:block;font-weight:700;font-size:var(--text-sm)}
.chooser span{font-size:var(--text-xs);color:var(--color-muted)}

/* solar / multi-mode panels */
.mpanel{display:none}
.mpanel.active{display:block}
.hint{display:block;margin-top:var(--space-1);font-size:var(--text-xs);color:var(--color-muted);line-height:1.45}
.warnlist{padding-left:var(--space-6)}
.warnlist li{margin:var(--space-1) 0;font-size:var(--text-sm);line-height:1.55;color:var(--color-muted)}
.warnlist li b{color:var(--color-ink)}

.prose{max-width:var(--measure)}
.prose li{margin:var(--space-1) 0}

/* line-item editors */
.lineitems .item{align-items:flex-end}
.itemrow{align-items:flex-end}
.debtrow{align-items:flex-end;margin-top:var(--space-3)}

/* ---- small screens: stack actions, primary fills the row ---- */
@media (max-width:560px){
  .row{gap:var(--space-2)}
  .field{min-width:100%}
  .go,.btn-link{width:100%;text-align:center}
  .card>.row:last-child .chip{flex:1 1 auto;text-align:center}
  .stat{flex:1 1 100%}
  .tabs{gap:0}
  .tab{flex:1 1 auto;min-width:max-content;text-align:center}
}

/* ---- focus: one treatment, defined last so no component can outrank it ---- */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible,
[tabindex]:focus-visible,
.drop:focus-visible{
  outline:3px solid var(--color-focus);
  outline-offset:2px;
  border-radius:var(--radius-control);
}
/* the tool surface is already ruled; keep its focus ring off the border */
.tab:focus-visible{outline-offset:-2px}
@media (forced-colors:active){
  a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,
  textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline-color:Highlight}
}

/* ==================== GROUPED NAV + GLOBAL SEARCH ======================== */
.vh{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip:rect(0 0 0 0);white-space:nowrap;border:0}

/* --- grouped navigation --- */
.navgroups{display:flex;gap:var(--space-4);flex:1 1 auto;flex-wrap:wrap;align-items:center}
.navgroup{position:relative}
.navgroup>button{
  display:inline-flex;align-items:center;gap:var(--space-1);
  background:none;border:0;border-bottom:2px solid transparent;border-radius:0;
  padding:var(--space-2) 0;font:inherit;font-size:var(--text-sm);font-weight:600;
  color:var(--color-muted);cursor:pointer;min-height:40px;
}
.navgroup>button:hover,.navgroup[data-open]>button{color:var(--color-ink);border-bottom-color:var(--color-ink)}
.navgroup>button svg{width:12px;height:12px;transition:transform var(--duration-fast) var(--ease-out)}
.navgroup[data-open]>button svg{transform:rotate(180deg)}
.navmenu{
  position:absolute;top:calc(100% + var(--space-2));left:0;z-index:30;min-width:14rem;
  background:var(--color-surface);border:var(--border);border-radius:var(--radius-panel);
  box-shadow:var(--shadow-offset);padding:var(--space-2);margin:0;list-style:none;
}
.navgroup:not([data-open]) .navmenu{display:none}
.navmenu a{
  display:block;padding:var(--space-2) var(--space-3);border-radius:var(--radius-control);
  color:var(--color-ink);font-size:var(--text-sm);font-weight:600;
}
.navmenu a:hover{background:var(--color-brand);color:#fff;text-decoration:none}
.navmenu .mdesc{display:block;font-weight:450;font-size:var(--text-xs);color:var(--color-muted);margin-top:1px}
.navmenu a:hover .mdesc{color:rgba(255,255,255,.85)}

/* Long menus run past the bottom of the window in one column — Games has 21
   entries, Security 24, Networking 30. Quantity queries let a menu decide its
   own shape from how many items it holds, so adding a tool never needs a
   layout change. Multi-column balances the heights on its own, which is why
   it beats a grid here: no row count to keep in step with the item count.

   All of this is scoped above the mobile breakpoint. Below it the menu is
   already a full-width drawer, and an unscoped `width:max-content` here
   silently overrode that and shrank it back to a narrow panel. */
@media (min-width:641px){
  .navmenu{max-height:calc(100vh - 6rem);overflow-y:auto}
  .navmenu > li{break-inside:avoid}

  /* 13 or more entries: two columns. */
  .navmenu:has(> li:nth-child(13)){
    columns:2;column-gap:var(--space-2);width:max-content;max-width:calc(100vw - 3rem);
  }
  /* 22 or more: three, where the window is wide enough to hold them. */
  @media (min-width:1201px){
    .navmenu:has(> li:nth-child(22)){columns:3}
  }

  /* A three-column menu is wider than the space beside most buttons, so it
     anchors to the header bar rather than to its own button. Anchoring it
     right instead pushed the Networking menu off the left edge, because it is
     wider than everything to the left of it. */
  .bar{position:relative}
  .navgroup:has(.navmenu > li:nth-child(22)){position:static}
  .navmenu:has(> li:nth-child(22)){left:var(--space-4);right:auto}
}

/* --- search command --- */
.searchbtn{
  display:inline-flex;align-items:center;gap:var(--space-2);flex:0 0 auto;
  min-height:40px;padding:0 var(--space-3);
  background:var(--color-surface);border:var(--border-subtle);border-radius:var(--radius-control);
  color:var(--color-muted);font:inherit;font-size:var(--text-sm);cursor:pointer;
  transition:border-color var(--duration-fast) var(--ease-out),color var(--duration-fast) var(--ease-out);
}
.searchbtn:hover{border-color:var(--color-ink);color:var(--color-ink)}
.searchbtn svg{width:15px;height:15px;flex:0 0 auto}
.searchbtn kbd{
  font-family:var(--font-mono);font-size:var(--text-xs);
  border:var(--border-subtle);border-radius:4px;padding:1px 5px;color:var(--color-muted);
}
@media (max-width:940px){.searchbtn .slabel,.searchbtn kbd{display:none}.searchbtn{padding:0 var(--space-2)}}

/* --- search dialog --- */
.searchdlg{
  position:fixed;inset:0;z-index:100;
  background:color-mix(in srgb,var(--color-ink) 45%,transparent);
  display:flex;align-items:flex-start;justify-content:center;padding:var(--space-12) var(--space-4);
}
.searchdlg[hidden]{display:none}
.searchbox{
  width:min(40rem,100%);max-height:min(34rem,80vh);display:flex;flex-direction:column;
  background:var(--color-surface);border:var(--border);border-radius:var(--radius-panel);
  box-shadow:var(--shadow-offset);overflow:hidden;
}
.searchhead{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-3);border-bottom:var(--border)}
.searchhead input{
  flex:1;min-height:44px;padding:var(--space-2) var(--space-3);
  border:var(--border-subtle);border-radius:var(--radius-control);
  background:var(--color-raised);color:var(--color-ink);font:inherit;font-size:var(--text-md);
}
.scount{
  margin:0;padding:var(--space-2) var(--space-4);border-bottom:var(--border-subtle);
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--color-muted);
}
.slist{list-style:none;margin:0;padding:var(--space-2);overflow-y:auto;flex:1}
.sgroup{
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.09em;text-transform:uppercase;
  color:var(--color-muted);padding:var(--space-3) var(--space-3) var(--space-1);
}
.sitem{padding:var(--space-2) var(--space-3);border-radius:var(--radius-control);cursor:pointer}
.sitem.on{background:var(--color-brand);color:#fff}
.sname{display:block;font-weight:700;font-size:var(--text-sm)}
.sdesc{display:block;font-size:var(--text-xs);color:var(--color-muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.sitem.on .sdesc{color:rgba(255,255,255,.85)}
.sempty{padding:var(--space-6)}
.sempty p{margin:0 0 var(--space-2)}
.sempty .sub{color:var(--color-muted);font-size:var(--text-sm)}
@media (max-width:560px){
  .searchdlg{padding:var(--space-4) var(--space-2)}
  .searchbox{max-height:88vh}
  .sdesc{white-space:normal}
}

/* on small screens a dropdown becomes a full-width directory, per §8 —
   a 224px drawer on a 390px screen wastes the room and reads as cramped */
@media (max-width:640px){
  .navgroups{width:100%;order:3;gap:var(--space-3)}
  .navgroup{position:static}
  .navmenu{
    left:0;right:0;width:100%;min-width:0;
    margin-top:var(--space-2);box-shadow:none;
    /* The header is sticky, so a menu taller than the screen travels with it
       and its tail can never be scrolled into view — twenty of the thirty
       networking tools were simply unreachable. The menu has to scroll
       inside itself. dvh rather than vh because mobile browser chrome
       changes the usable height as you scroll. */
    max-height:calc(100dvh - 13rem);
    overflow-y:auto;
    /* Stop the page scrolling underneath once the menu reaches its end. */
    overscroll-behavior:contain;
  }
  @supports not (height:100dvh){
    .navmenu{max-height:calc(100vh - 13rem)}
  }
  .navmenu a{padding:var(--space-3)}
  .bar{position:relative}
}

/* ================= WORKFLOW RAIL + MEASURED PROGRESS ==================== */

/* Input → Configure → Export. The stage is not decorative: :has() advances it
   as files arrive and as output appears, so the rail reports where you are
   rather than illustrating where you might be. */
.rail{
  display:flex;align-items:center;gap:var(--space-2);flex-wrap:wrap;
  margin:0 0 var(--space-4);padding-bottom:var(--space-3);
  border-bottom:var(--border-subtle);
  font-family:var(--font-mono);font-size:var(--text-xs);
  letter-spacing:.08em;text-transform:uppercase;color:var(--color-muted);
}
.rail li{display:flex;align-items:center;gap:var(--space-2);list-style:none}
.rail li::before{
  content:attr(data-n);
  display:inline-flex;align-items:center;justify-content:center;
  width:18px;height:18px;flex:0 0 auto;
  border:1px solid var(--color-faint);color:var(--color-muted);font-size:10px;
}
.rail li+li::after{content:none}
.rail .sep{width:var(--space-4);height:1px;background:var(--color-faint);flex:0 0 auto}
.rail li[data-on]{color:var(--color-ink)}
.rail li[data-on]::before{background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local)}
.rail li[data-done]::before{background:var(--color-ink);border-color:var(--color-ink);color:var(--color-canvas)}

/* stage 1 is live until a file lands */
.panel:not(:has(.files .file)) .rail li:nth-of-type(1),
.mpanel:not(:has(.files .file)) .rail li:nth-of-type(1){color:var(--color-ink)}
.panel:not(:has(.files .file)) .rail li:nth-of-type(1)::before,
.mpanel:not(:has(.files .file)) .rail li:nth-of-type(1)::before{
  background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local)}
/* once files are queued, stage 1 is done and stage 2 is live */
.panel:has(.files .file) .rail li:nth-of-type(1)::before{
  background:var(--color-ink);border-color:var(--color-ink);color:var(--color-canvas)}
.panel:has(.files .file) .rail li:nth-of-type(2){color:var(--color-ink)}
.panel:has(.files .file) .rail li:nth-of-type(2)::before{
  background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local)}
/* and when the tool reports success, export is where you are */
.panel:has(.status.ok:not(:empty)) .rail li:nth-of-type(2)::before{
  background:var(--color-ink);border-color:var(--color-ink);color:var(--color-canvas)}
.panel:has(.status.ok:not(:empty)) .rail li:nth-of-type(3){color:var(--color-ink)}
.panel:has(.status.ok:not(:empty)) .rail li:nth-of-type(3)::before{
  background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local)}
@media (max-width:560px){.rail{font-size:10px;gap:var(--space-1)}.rail .sep{width:var(--space-2)}}

/* --- measured progress: a segmented rule, never a spinner --- */
.prog{display:flex;align-items:center;gap:var(--space-3);margin-top:var(--space-3)}
.prog[hidden]{display:none}
.prog .track{display:flex;gap:2px;flex:1;height:8px}
.prog .seg{flex:1;background:var(--color-faint);border:1px solid transparent}
.prog .seg.on{background:var(--color-local);border-color:var(--color-ink)}
.prog .lbl{
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--color-muted);white-space:nowrap;flex:0 0 auto;
}


/* ==================== HOMEPAGE CATEGORY SHELF =========================== */
/* A horizontally scrolling shelf of cards. Native scroll-snap rather than a
   carousel library: every card stays in the DOM and in the tab order, the
   trackpad and touch gestures people already know just work, and nothing
   rotates on its own. */
.shelfhead{display:flex;align-items:flex-end;justify-content:space-between;gap:var(--space-4)}
.shelfhead .section-title{flex:1;margin-bottom:var(--space-3)}
.stotal{
  float:right;font-family:var(--font-mono);font-size:var(--text-xs);
  letter-spacing:.08em;text-transform:none;color:var(--color-muted);font-weight:500;
}
.shelfnav{display:flex;gap:var(--space-2);margin-bottom:var(--space-3);flex:0 0 auto}
.shelfbtn{
  width:40px;height:40px;display:grid;place-items:center;
  background:var(--color-surface);border:var(--border);border-radius:var(--radius-control);
  color:var(--color-ink);cursor:pointer;
  transition:background var(--duration-fast) var(--ease-out),opacity var(--duration-fast) var(--ease-out);
}
.shelfbtn svg{width:18px;height:18px}
.shelfbtn:hover:not(:disabled){background:var(--color-brand);color:#fff}
.shelfbtn:disabled{opacity:.3;cursor:not-allowed}

.shelf{
  display:flex;gap:var(--space-4);list-style:none;margin:0;
  /* the vertical padding gives a hovered card room to grow without clipping */
  padding:var(--space-3) var(--space-6) var(--space-4) 0;
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;scroll-padding-left:0;
  scrollbar-width:none;
}
.shelf::-webkit-scrollbar{display:none}
.shelf:focus-visible{outline:3px solid var(--color-focus);outline-offset:4px;border-radius:var(--radius-panel)}

.scard{
  flex:0 0 clamp(15rem,23vw,17.5rem);scroll-snap-align:start;
  display:flex;flex-direction:column;
  background:var(--color-surface);border:var(--border);border-radius:var(--radius-panel);
  padding:var(--space-4);position:relative;
  transition:transform var(--duration-standard) var(--ease-out),
             box-shadow var(--duration-standard) var(--ease-out),
             border-color var(--duration-standard) var(--ease-out);
}
/* the card lifts and grows under the cursor, and does the same on keyboard
   focus so the two are not different experiences */
.scard:hover,.scard:focus-within{
  transform:translateY(-4px) scale(1.025);
  box-shadow:var(--shadow-offset);
  border-color:var(--color-ink);
  z-index:2;
}
.scard-hit{display:flex;flex-direction:column;color:var(--color-ink)}
.scard-hit:hover{text-decoration:none}
.scard-hit::after{content:"";position:absolute;inset:0;border-radius:var(--radius-panel)}
.scard-top{display:flex;align-items:center;gap:var(--space-2);margin-bottom:var(--space-3)}
.scard-num{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--color-muted);letter-spacing:.04em}
.scard-mark{
  width:34px;height:34px;display:grid;place-items:center;
  border:var(--border-subtle);border-radius:var(--radius-control);
  color:var(--color-muted);
  transition:color var(--duration-standard) var(--ease-out),
             background var(--duration-standard) var(--ease-out),
             border-color var(--duration-standard) var(--ease-out);
}
.scard-mark svg{width:20px;height:20px}
.scard:hover .scard-mark,.scard:focus-within .scard-mark{
  background:var(--color-local);border-color:var(--color-ink);color:var(--color-on-local);
}
.scard-count{
  margin-left:auto;font-family:var(--font-mono);font-size:var(--text-xs);
  letter-spacing:.08em;text-transform:uppercase;color:var(--color-muted);
}
.scard-title{font-size:var(--text-lg);font-weight:750;letter-spacing:-.025em;margin-bottom:var(--space-1)}
.scard-blurb{font-size:var(--text-sm);color:var(--color-muted);line-height:1.5}
.scard-links{
  list-style:none;margin:var(--space-4) 0 0;padding:0;
  border-top:var(--border-subtle);position:relative;z-index:1;
}
.scard-links li{border-bottom:var(--border-subtle)}
.scard-links a{
  display:block;padding:var(--space-2) 0;font-size:var(--text-sm);color:var(--color-muted);
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
}
.scard-links a:hover{color:var(--color-brand);text-decoration:none}
.scard-all{
  margin-top:auto;padding-top:var(--space-3);position:relative;z-index:1;
  font-family:var(--font-mono);font-size:var(--text-xs);letter-spacing:.08em;
  text-transform:uppercase;color:var(--color-ink);font-weight:600;
}
.scard-all:hover{color:var(--color-brand);text-decoration:none}

/* how far along the shelf you are */
.shelfhint{margin:0 0 var(--space-6);display:flex;align-items:center}
.shelfprog{display:block;height:2px;width:100%;background:var(--color-faint);position:relative}
.shelfbar{
  display:block;height:100%;background:var(--color-ink);width:30%;
  transition:width var(--duration-standard) var(--ease-out),
             transform var(--duration-standard) var(--ease-out);
}
@media (prefers-reduced-motion:reduce){
  .scard:hover,.scard:focus-within{transform:none;box-shadow:var(--shadow-offset-sm)}
  .shelf{scroll-behavior:auto}
  .shelfbar{transition:none}
}
@media (max-width:640px){
  .shelfnav{display:none}                       /* the thumb is the control */
  .shelf{padding-right:var(--space-4);gap:var(--space-3);scroll-snap-type:x mandatory}
  .scard{flex-basis:min(78vw,17rem)}
  .scard:hover,.scard:focus-within{transform:none}
}

/* ====================== EDITORIAL COLUMNS =============================== */
/* The block spans the full container, matching the rule above it and the card
   below. Setting the prose in two columns is what makes that possible: run as
   a single measure across this width the lines would reach about 125
   characters, which is roughly twice what anyone reads comfortably. Two
   columns fill the same space at about 55 characters each. */
.editorial{
  display:grid;grid-template-columns:minmax(0,15rem) minmax(0,1fr);
  gap:var(--space-8);align-items:start;
  padding:var(--space-12) 0;border-top:var(--border-subtle);
}
.ed-head h2{
  font-size:var(--text-2xl);letter-spacing:-.035em;line-height:1.05;
  margin:0 0 var(--space-4);
}
.ed-body{
  max-width:none;
  columns:2;column-gap:var(--space-8);column-rule:var(--border-subtle);
}
.ed-body>*:first-child{margin-top:0}
.ed-body p{
  font-size:var(--text-md);line-height:1.65;color:var(--color-ink);
  margin:0 0 var(--space-4);
  /* never strand a single line of a paragraph at the foot of a column */
  orphans:2;widows:2;break-inside:avoid-column;
}
.ed-body p:last-child{margin-bottom:0}
/* Between about 820 and 1200 the title beside two columns would squeeze each
   below 45 characters, so the title stacks above instead and the columns take
   the whole width — which fills the same space at a comfortable measure. */
@media (max-width:1199px){
  .editorial{grid-template-columns:1fr;gap:var(--space-4);padding:var(--space-8) 0}
  .ed-head h2{margin-bottom:var(--space-3)}
  .ed-head{display:flex;align-items:baseline;gap:var(--space-4);flex-wrap:wrap}
  .ed-head h2{margin-bottom:0}
}
/* one column once two would be too narrow to read */
@media (max-width:819px){
  .ed-body{columns:1;column-rule:none;max-width:var(--measure)}
}

/* Long-form sections carry several headings with flat markup (h2, p, p, h2…).
   A grid that puts every h2 in a left column and everything else in a right
   one gives the same editorial rhythm as .editorial without regrouping the
   HTML on three dozen pages. Below 900px it collapses to a single column. */
@media (min-width:901px){
  .wrap .content.narrow{
    max-width:none;
    display:grid;grid-template-columns:minmax(0,4fr) minmax(0,8fr);
    column-gap:var(--space-12);row-gap:0;
    align-items:start;
  }
  .wrap .content.narrow>h2{
    grid-column:1;margin:var(--space-8) 0 var(--space-4);
    font-size:var(--text-xl);letter-spacing:-.03em;max-width:16ch;
  }
  .wrap .content.narrow>h2:first-child{margin-top:0}
  .wrap .content.narrow>*:not(h2){grid-column:2;max-width:var(--measure)}
  .wrap .content.narrow>h3{grid-column:2;margin-top:var(--space-6)}
  .wrap .content.narrow>p,
  .wrap .content.narrow>ul,
  .wrap .content.narrow>ol{margin-top:0;margin-bottom:var(--space-4)}
  /* the first element on each row lines its baseline up with its heading */
  .wrap .content.narrow>h2+*{margin-top:var(--space-8)}
  .wrap .content.narrow>h2:first-child+*{margin-top:0}
}

/* ------------------------------------------------------------------ *
 * Site resource picker (solar)
 * ------------------------------------------------------------------ */
.site-open{display:inline-flex;align-items:center;gap:var(--space-2);
  font:inherit;font-weight:600;color:var(--color-brand);background:none;
  border:var(--border-subtle);border-radius:var(--radius-control);
  padding:var(--space-3) var(--space-4);cursor:pointer;text-align:left}
.site-open:hover{border-color:var(--color-brand);background:var(--color-surface)}
.site-open-i{font-size:1.1em;line-height:1}
.site-banner{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-2);
  font-size:var(--text-sm);color:var(--color-muted);
  border-left:3px solid var(--color-local);padding:var(--space-2) var(--space-3);
  background:var(--color-surface);border-radius:var(--radius-control);
  margin-bottom:var(--space-3)}
.site-panel{border:var(--border-subtle);border-radius:var(--radius-control);
  padding:var(--space-6);margin-top:var(--space-3);background:var(--color-surface)}
.site-ways{display:grid;gap:var(--space-6)}
@media (min-width:820px){.site-ways{grid-template-columns:repeat(3,minmax(0,1fr));gap:var(--space-6)}}
.site-way{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.site-way-n{font-size:var(--text-xs);letter-spacing:.08em;text-transform:uppercase;
  color:var(--color-muted);font-weight:700}
.site-way .hint{margin:0}
.site-cityrow,.site-coordrow{display:flex;gap:var(--space-2);min-width:0}
.site-country{flex:0 1 40%;min-width:0}
.site-cityw{position:relative;flex:1 1 auto;min-width:0}
.site-city{width:100%}
.site-coord{flex:1 1 auto;min-width:0}
.site-hits{position:absolute;z-index:30;left:0;right:0;top:calc(100% + 2px);
  margin:0;padding:0;list-style:none;max-height:16rem;overflow:auto;
  background:var(--color-canvas);border:1px solid var(--color-ink);
  border-radius:var(--radius-control);box-shadow:var(--shadow-offset) var(--color-ink)}
.site-hits button{display:flex;justify-content:space-between;gap:var(--space-3);
  width:100%;text-align:left;font:inherit;background:none;border:0;
  padding:var(--space-2) var(--space-3);cursor:pointer}
.site-hits button:hover,.site-hits button.is-hi{background:var(--color-brand);color:var(--color-canvas)}
.site-hit-r{color:var(--color-muted);font-size:var(--text-sm);flex:0 0 auto}
.site-hits button:hover .site-hit-r,.site-hits button.is-hi .site-hit-r{color:inherit;opacity:.8}
.site-status{margin:var(--space-4) 0 0;font-size:var(--text-sm);color:var(--color-muted);min-height:1.2em}
.site-status.is-err{color:var(--color-danger)}
.site-result{margin-top:var(--space-6);border-top:var(--border-subtle);padding-top:var(--space-6)}
.site-head{display:flex;flex-wrap:wrap;align-items:baseline;gap:var(--space-3)}
.site-place{font-size:var(--text-md)}
.site-coords{font-family:var(--font-mono);font-size:var(--text-sm);color:var(--color-muted)}
.site-figure{margin-top:var(--space-3)}
.site-big{display:flex;align-items:baseline;gap:var(--space-2);flex-wrap:wrap}
.site-num{font-size:clamp(2rem,6vw,2.75rem);font-weight:800;line-height:1;
  font-variant-numeric:tabular-nums;color:var(--color-brand)}
.site-unit{font-size:var(--text-sm);color:var(--color-muted)}
.site-sub{margin:var(--space-2) 0 0;font-size:var(--text-sm);color:var(--color-muted)}
.site-plane{display:flex;flex-wrap:wrap;gap:var(--space-4);margin-top:var(--space-4)}
/* the page-wide .field rule sets min-width:180px, and min-width wins over
   max-width — so this sits just above it rather than fighting it */
.site-plane .field{max-width:12rem}
.site-bars{display:flex;align-items:flex-end;gap:2px;height:7.5rem;margin-top:var(--space-6)}
.site-bar{flex:1 1 0;min-width:0;display:flex;flex-direction:column;
  align-items:center;justify-content:flex-end;height:100%;gap:2px}
.site-bar-f{width:100%;background:var(--color-brand);border-radius:2px 2px 0 0;min-height:2px}
.site-bar.is-best .site-bar-f{background:var(--color-local)}
.site-bar.is-worst .site-bar-f{background:var(--color-attention)}
.site-bar-v,.site-bar-m{font-size:10px;font-family:var(--font-mono);color:var(--color-muted);
  line-height:1.2;white-space:nowrap}
.site-bar-v{order:-1}
.site-apply{display:flex;flex-wrap:wrap;align-items:center;gap:var(--space-4);margin-top:var(--space-6)}
/* There is no .btn.primary in this design system, so the apply action
   carries its own emphasis rather than relying on a class that does
   nothing. It is the one thing in the panel people are meant to press. */
.site-apply .btn{background:var(--color-brand);color:var(--color-canvas);
  border-color:var(--color-brand);font-weight:700}
.site-apply .btn:hover:not([disabled]){background:var(--color-ink);border-color:var(--color-ink)}
.site-apply .btn[disabled]{background:none;color:var(--color-muted);
  border-color:var(--color-faint);font-weight:600;cursor:default}
.site-warn{margin:var(--space-3) 0 0;font-size:var(--text-sm);
  border-left:3px solid var(--color-faint);padding-left:var(--space-3);color:var(--color-muted)}
.site-warn.is-warning{border-left-color:var(--color-attention);color:var(--color-ink)}
.site-note{margin:var(--space-4) 0 0;font-size:var(--text-xs);color:var(--color-muted)}
.linkish{font:inherit;font-size:var(--text-sm);background:none;border:0;padding:0;
  color:var(--color-brand);text-decoration:underline;cursor:pointer}
@media (max-width:520px){
  .site-cityrow{flex-wrap:wrap}
  .site-country{flex:1 1 100%}
  .site-bar-v{display:none}
}
.site-credit{margin:var(--space-6) 0 0;padding-top:var(--space-3);
  border-top:var(--border-subtle);font-size:var(--text-xs);color:var(--color-muted)}
.site-credit a{color:inherit}

/* ------------------------------------------------------------------ *
 * Platform preset preview (image resizer)
 * ------------------------------------------------------------------ */
#rsSocialRow{align-items:flex-start}
#rsPlan{margin-top:var(--space-2)}
#rsPlan p{font-size:var(--text-sm);line-height:1.5;margin:var(--space-2) 0 0;
  color:var(--color-muted);border-left:3px solid var(--color-faint);
  padding-left:var(--space-3)}
#rsPlan p b{color:var(--color-ink)}
#rsPlan p.warn{border-left-color:var(--color-attention);color:var(--color-ink);
  background:none;border-radius:0;padding:0 0 0 var(--space-3);font-weight:400;font-size:var(--text-sm)}

/* Metric/imperial switch, shared by the telecom tools.

   Sticky below the site header rather than parked at the top of the page.
   Unit-bearing inputs are spread across a long tool — the microwave lab has
   them in five separate stages — so a switch that scrolls away is a switch
   you have to go and find. z-index stays under the header's 20. */
.nunits{display:flex;align-items:center;gap:10px;margin:0 0 18px;
  position:sticky;top:var(--header-height);z-index:15;
  background:var(--bg);padding:8px 12px;border:1px solid var(--line);
  border-radius:var(--radius-control);box-shadow:0 1px 6px rgba(0,0,0,.06)}
.nunits-label{font-size:13px;color:var(--muted);font-weight:600}
.nunits-btns{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius-control);overflow:hidden}
.nunits-btns button{font:inherit;font-size:13px;font-weight:600;padding:6px 14px;border:0;
  background:var(--bg);color:var(--muted);cursor:pointer}
.nunits-btns button+button{border-left:1px solid var(--line)}
.nunits-btns button[aria-pressed="true"]{background:var(--brand);color:#fff}
.nunits-hint{font-size:12px;color:var(--muted);flex:1 1 auto;min-width:0}
@media (max-width:36rem){
  .nunits{position:static}
  .nunits-hint{display:none}
  /* A 33px control is under the 44px a finger reliably hits. Desktop has a
     pointer and does not need the extra height; a phone does. */
  .nunits-btns button{min-height:44px;padding:6px 16px}
  .ncoordfmt-btns button{min-height:44px;padding:6px 14px}
}

/* Coordinate entry: one field, any notation. */
.ncoordfmt{display:flex;align-items:center;gap:10px;flex-wrap:wrap;margin:0 0 14px}
.ncoordfmt-label{font-size:13px;color:var(--muted);font-weight:600}
.ncoordfmt-btns{display:inline-flex;border:1px solid var(--line);border-radius:var(--radius-control);overflow:hidden}
.ncoordfmt-btns button{font:inherit;font-size:12.5px;font-weight:600;padding:5px 11px;border:0;
  background:var(--bg);color:var(--muted);cursor:pointer}
.ncoordfmt-btns button+button{border-left:1px solid var(--line)}
.ncoordfmt-btns button[aria-pressed="true"]{background:var(--brand);color:#fff}
.ncoordfmt-hint{font-size:12px;color:var(--muted);flex:1 1 12rem}
.ncoordnote{font-size:11.5px;line-height:1.4;margin-top:3px;min-height:1.2em;
  font-family:var(--font-mono);color:var(--muted)}
.ncoordnote[data-state="bad"]{color:#c0392b;font-family:var(--font-ui)}
input[aria-invalid="true"]{border-color:#c0392b}
