/* tool.css — shared tool-page styles.
   Pages set --accent / --accent-dim to their area colour; page-local <style>
   loaded after this sheet can still override. Prefer var(--accent) here so
   amber/green/indigo/etc. all work without per-page copies of the chrome. */

*{ box-sizing:border-box; }
html{ -webkit-text-size-adjust:100%; }
svg{ user-select:none; -webkit-user-select:none; -moz-user-select:none; }
body{
  margin:0;
  background:
    radial-gradient(1200px 600px at 78% -10%, var(--bg-rad-1) 0%, transparent 55%),
    radial-gradient(900px 500px at 0% 0%, var(--bg-rad-2) 0%, transparent 50%),
    var(--ink);
  color:var(--text);
  font-family:'Inter',system-ui,sans-serif;
  line-height:1.5;
  -webkit-font-smoothing:antialiased;
}
.wrap{ max-width:1180px; margin:0 auto; padding:26px 20px 64px; }
@media (max-width:560px){
  .wrap{ padding:18px 14px 48px; }
  header.mast{ align-items:flex-start; }
  .mast .right{ text-align:left; width:100%; }
  .refbar{ margin:18px 0 14px; font-size:11px; }
  section.block{ margin-top:48px; }
  .grid{ gap:var(--sp-4); }
  .panel{ padding:14px; border-radius:var(--r-panel); }
  .hero{ padding:12px; border-radius:var(--r-panel); }
  .playbar, .controls{ gap:var(--sp-3); margin-top:10px; }
  .playbtn{ padding:10px 14px; min-height:44px; } /* touch target */
  .field{ margin-bottom:12px; }
  .ro{ padding:11px 12px; }
  .ro .v{ font-size:clamp(14px,4.2vw,18px); }
  /* simulators: keep the viz legible, avoid horizontal page scroll */
  .hero svg, .panel svg, #anim, #springViz, #forceChart, #step,
  #dLoad, #dShear, #dMoment, #dDefl, svg[id$="Svg"], svg[id$="Chart"]{
    max-width:100%; height:auto;
  }
}
@media (max-width:400px){
  .ro-grid,
  .ro-grid.primary,
  .ro-grid.secondary{ grid-template-columns:1fr 1fr; gap:var(--sp-3); }
  .seg{ grid-template-columns:1fr 1fr; }
  .seg.seg3{ grid-template-columns:1fr 1fr 1fr; }
}

/* ---- chrome: crumb, refbar, mast ---- */
nav.crumb{
  display:flex; align-items:center; gap:var(--sp-3); flex-wrap:wrap;
  padding-bottom:13px; margin-bottom:7px;
  font-family:'IBM Plex Mono',monospace; font-size:11.5px;
}
nav.crumb a{ color:var(--muted); text-decoration:none; }
nav.crumb a:hover{ color:var(--text); }
nav.crumb .sep{ color:var(--muted-2); }
nav.crumb .here{ color:var(--accent); font-weight:600; letter-spacing:.03em; }
.refbar{
  display:flex; align-items:center; gap:var(--sp-3); padding:9px 13px; margin:28px 0 18px;
  background:linear-gradient(90deg,var(--banner-a),var(--banner-b));
  border:1px solid var(--line-soft); border-radius:var(--r-card);
  font-size:11.5px; color:var(--muted-2);
}
.refbar b{ color:var(--muted); font-weight:600; }
.refbar svg{ width:14px; height:14px; flex:none; color:var(--amber); }
header.mast{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:var(--sp-6); flex-wrap:wrap; padding-bottom:18px;
  border-bottom:1px solid var(--line-soft); margin-bottom:20px;
}
.brand{ display:flex; align-items:center; gap:var(--sp-4); }
.glyph{ width:42px; height:42px; flex:none; }
.mast h1{
  font-family:'Space Grotesk',sans-serif; font-weight:700;
  font-size:clamp(22px,3vw,30px); letter-spacing:-.02em; margin:0; line-height:1;
}
.mast .sub{ font-size:12.5px; color:var(--muted); margin-top:5px; }
.mast .kicker{
  font-size:10px; letter-spacing:.22em; text-transform:uppercase;
  color:var(--accent); font-weight:600; font-family:'IBM Plex Mono',monospace;
}
.mast .right{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted-2); text-align:right; }
.mast .right b{ color:var(--text); font-weight:600; }

/* ---- layout grid (sidebar + main) ---- */
.grid{ display:grid; grid-template-columns:300px 1fr; gap:var(--sp-5); align-items:start; }
@media (max-width:960px){ .grid{ grid-template-columns:1fr; } }
/* CSS Grid blowout: nested content must be allowed to shrink below content min-size */
.grid > *{ min-width:0; }

/* THE CONTROL RAIL FOLLOWS YOU DOWN.
   With align-items:start the left column is its natural height, so on any page whose right
   column is longer - which is most of them - the remaining 300px is dead space running the
   whole way down. Measured across the site: 17 of 90 tool pages left more than HALF that
   column empty, and Sun & Moon left 3,352px of it, which is why the content read as shoved
   over to the right.

   Sticky fixes both halves of that at once. The gutter is never empty, and the controls stay
   reachable while you are looking at a chart two screens down - which is what you want from a
   calculator, since the whole point is changing an input and watching the answer move.

   The max-height is not optional. A rail taller than the viewport would pin its top and put
   its bottom permanently out of reach; with a cap it scrolls inside itself instead. Short
   rails never hit the cap and so are untouched. */
@media (min-width:961px){
  .grid > *:first-child{
    position:sticky;
    top:var(--sp-5);
    max-height:calc(100vh - var(--sp-5) * 2);
    overflow-y:auto;
    overscroll-behavior:contain;
    scrollbar-width:thin;
  }
  .grid > *:first-child::-webkit-scrollbar{ width:7px; }
  .grid > *:first-child::-webkit-scrollbar-thumb{
    background:var(--line); border-radius:var(--r-mark);
  }
}

/* ---- panels ---- */
.panel{
  background:linear-gradient(180deg,var(--panel),var(--ink-2));
  border:1px solid var(--line); border-radius:var(--r-panel); padding:18px;
}
.panel + .panel{ margin-top:14px; }
.panel .head{ display:flex; align-items:center; gap:var(--sp-3); margin-bottom:14px; }
.panel .head .dot{
  width:8px; height:8px; border-radius:50%;
  background:var(--accent); box-shadow:0 0 10px var(--accent);
}
.panel .head h2{ font-family:'Space Grotesk',sans-serif; font-size:15px; font-weight:600; margin:0; }
.panel .head .tag{
  margin-left:auto; font-size:9.5px; letter-spacing:.14em; text-transform:uppercase;
  color:var(--muted-2); font-family:'IBM Plex Mono',monospace;
}

/* ---- fields, selects, ranges ---- */
.field{ margin-bottom:14px; }
.field:last-child{ margin-bottom:0; }
.field > label{
  display:flex; justify-content:space-between;
  font-size:10.5px; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; margin-bottom:7px;
}
.field > label .vv{
  font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--text);
  text-transform:none; letter-spacing:0; font-weight:600;
}
.field > label .term{ color:var(--accent); font-family:'IBM Plex Mono',monospace; }
/* A second unit alongside the first — "8.8 oz (250 g)". Quieter than the primary reading so the
   eye lands on one number, but present so nobody has to convert. */
.unit-alt{ color:var(--muted-2); font-weight:500; }

select{
  width:100%; background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  color:var(--text); font-family:'IBM Plex Mono',monospace; font-size:12.5px;
  padding:9px 9px; outline:none; cursor:pointer;
}
select:focus{
  border-color:var(--accent);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--accent) 22%,transparent);
}

.slider{ display:flex; align-items:center; gap:var(--sp-4); }
.slider .val{
  font-family:'IBM Plex Mono',monospace; font-size:12.5px; color:var(--text);
  min-width:54px; text-align:right;
}

/* Range fill: --fill is 0%–100% of value (set by rot.js). Paint with background-size so
   the coloured bar is exactly as wide as the value fraction — no dual track layers that
   can drift from the thumb. Firefox uses native ::-moz-range-progress instead. */
input[type="range"]{
  -webkit-appearance:none; appearance:none; width:100%; height:4px; border-radius:var(--r-mark);
  background-color:var(--line);
  background-image:linear-gradient(var(--c,var(--accent)), var(--c,var(--accent)));
  background-size:var(--fill,0%) 100%;
  background-repeat:no-repeat;
  background-position:left center;
  outline:none; flex:1; cursor:pointer;
}
input[type="range"]::-webkit-slider-runnable-track{
  height:4px; border-radius:var(--r-mark); background:transparent; /* fill lives on the input itself */
}
input[type="range"]::-webkit-slider-thumb{
  -webkit-appearance:none; width:17px; height:17px; border-radius:50%;
  background:var(--c,var(--accent)); border:2px solid var(--ink);
  box-shadow:0 0 0 3px color-mix(in srgb,var(--c,var(--accent)) 28%,transparent);
  cursor:pointer; margin-top:-6.5px; /* centre 17px thumb on 4px track */
  position:relative; z-index:1;
}
/* Firefox: native progress follows the thumb exactly — don't also paint input fill */
input[type="range"]::-moz-range-track{
  height:4px; border-radius:var(--r-mark); border:none;
  background:var(--line);
}
input[type="range"]::-moz-range-progress{
  height:4px; border-radius:var(--r-mark); border:none;
  background:var(--c,var(--accent));
}
input[type="range"]::-moz-range-thumb{
  width:15px; height:15px; border-radius:50%;
  background:var(--c,var(--accent)); border:2px solid var(--ink); cursor:pointer;
  box-shadow:0 0 0 3px color-mix(in srgb,var(--c,var(--accent)) 28%,transparent);
}
@supports (-moz-appearance:none){
  input[type="range"]{
    background-color:transparent;
    background-image:none;
  }
}

/* ---- presets / segment toggles ---- */
.presets{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.presets.grid2{ display:grid; grid-template-columns:repeat(2,1fr); }
.presets button{
  font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted);
  background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  padding:7px 10px; cursor:pointer;
}
.presets button:hover{ border-color:var(--accent); color:var(--text); }
.presets button.on{
  color:var(--ink); background:var(--accent); border-color:var(--accent); font-weight:600;
}

.seg{ display:grid; grid-template-columns:repeat(3,1fr); gap:var(--sp-2); }
.seg.seg2{ grid-template-columns:repeat(2,1fr); }
.seg.seg4{ grid-template-columns:repeat(4,1fr); }
.seg button{
  font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--muted);
  background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  padding:9px 4px; cursor:pointer;
}
.seg button.on{
  color:var(--ink); background:var(--accent); border-color:var(--accent); font-weight:600;
}
.seg button:hover{ border-color:var(--accent); color:var(--text); }

/* ---- hero panel (main viz card) ---- */
.hero{
  background:linear-gradient(180deg,var(--panel-2),var(--ink-2));
  border:1px solid var(--line); border-radius:var(--r-panel); padding:16px;
}
.hero-head{ display:flex; align-items:center; gap:var(--sp-3); margin-bottom:8px; flex-wrap:wrap; }
.hero-head h2{ font-family:'Space Grotesk',sans-serif; font-size:15px; font-weight:600; margin:0; }
.hero-head .meta{ margin-left:auto; font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted-2); }

/* ---- play / transport controls ---- */
.playbar, .controls{
  display:flex; align-items:center; gap:var(--sp-3); margin-top:12px; flex-wrap:wrap;
}
.playbtn{
  display:inline-flex; align-items:center; gap:var(--sp-2); justify-content:center;
  font-family:'Inter',sans-serif; font-size:13px; font-weight:500;
  color:var(--ink); background:var(--accent); border:none; border-radius:var(--r-ctl);
  padding:9px 16px; cursor:pointer; min-width:88px;
}
.playbtn.ghost{
  color:var(--accent); background:var(--ink); border:1px solid var(--accent); min-width:auto;
}
.playbtn svg{ width:13px; height:13px; }
.speed{
  display:flex; align-items:center; gap:var(--sp-2); margin-left:auto;
  font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted-2);
}
.speed select{
  width:auto; background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  color:var(--text); font-family:'IBM Plex Mono',monospace; font-size:11.5px; padding:5px 8px;
}

/* ---- status pills ---- */
.warn-pill, .verdict{
  font-family:'IBM Plex Mono',monospace; font-size:11px; font-weight:600;
  padding:3px 10px; border-radius:var(--r-hero); border:1px solid currentColor;
}

/* ---- result readouts ---- */
.readouts{ margin-top:16px; }
.ro-label{
  font-size:10px; letter-spacing:.16em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600; margin:2px 0 9px;
}
.ro-grid{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-4); }
.ro-grid.primary{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-4); margin-bottom:14px; }
.ro-grid.secondary{ display:grid; grid-template-columns:repeat(4,1fr); gap:var(--sp-3); }
@media (max-width:760px){
  .ro-grid,
  .ro-grid.primary,
  .ro-grid.secondary{ grid-template-columns:repeat(2,1fr); }
}
.ro{
  background:linear-gradient(180deg,var(--panel),var(--ink-2));
  border:1px solid var(--line); border-radius:var(--r-card); padding:13px 14px;
  position:relative; overflow:hidden; min-width:0;
}
/* Long unbreakable values must wrap inside grid tracks */
.ro-grid .ro .v{ overflow-wrap:anywhere; }
.ro.sm{ padding:11px 12px; }
.ro .k{
  font-size:10px; letter-spacing:.08em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
}
.ro.sm .k{ font-size:9px; }
.ro .v{
  font-family:'IBM Plex Mono',monospace; font-weight:600; margin-top:7px;
  font-size:clamp(15px,2vw,20px); letter-spacing:-.01em; line-height:1; color:var(--text);
}
.ro.sm .v{ font-size:clamp(13px,1.8vw,16px); margin-top:6px; }
.ro .u{ font-size:12px; color:var(--muted); font-weight:500; margin-left:3px; }
.ro.sm .u{ font-size:10px; }
.ro .alt{
  font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--muted-2); margin-top:6px;
}
.ro.sm .alt{ font-size:9.5px; margin-top:4px; }

/* Lead accent bar on readouts */
.ro.lead:before{
  content:""; position:absolute; left:0; top:0; bottom:0; width:3px; opacity:.95;
}
.ro.am:before{ background:var(--amber); box-shadow:0 0 12px var(--amber); }
.ro.rd:before{ background:var(--red); box-shadow:0 0 12px var(--red); }
.ro.cy:before{ background:var(--cyan); box-shadow:0 0 12px var(--cyan); }
.ro.gr:before{ background:var(--green); box-shadow:0 0 12px var(--green); }
.ro.vi:before{ background:var(--violet); box-shadow:0 0 12px var(--violet); }
.ro.in:before{ background:var(--indigo); box-shadow:0 0 12px var(--indigo); }
.ro.pk:before{ background:var(--pink); box-shadow:0 0 12px var(--pink); }
.ro.tl:before{ background:var(--teal); box-shadow:0 0 12px var(--teal); }
.ro.cr:before{ background:var(--coral); box-shadow:0 0 12px var(--coral); }
.ro.lm:before{ background:var(--lime); box-shadow:0 0 12px var(--lime); }
.ro.az:before{ background:var(--azure); box-shadow:0 0 12px var(--azure); }

.ro.am .v{ color:var(--amber); }
.ro.rd .v{ color:var(--red); }
.ro.cy .v{ color:var(--cyan); }
.ro.gr .v{ color:var(--green); }
.ro.vi .v{ color:var(--violet); }
.ro.in .v{ color:var(--indigo); }
.ro.pk .v{ color:var(--pink); }
.ro.tl .v{ color:var(--teal); }
.ro.cr .v{ color:var(--coral); }
.ro.lm .v{ color:var(--lime); }
.ro.az .v{ color:var(--azure); }

/* ---- content blocks / glossary ---- */
section.block{ margin-top:76px; }
.rhead{ display:flex; align-items:baseline; gap:var(--sp-4); margin-bottom:24px; flex-wrap:wrap; }
.rhead .ey{
  font-size:10px; letter-spacing:.2em; text-transform:uppercase;
  color:var(--accent); font-weight:600; font-family:'IBM Plex Mono',monospace;
}
.rhead h2{
  font-family:'Space Grotesk',sans-serif; font-size:19px; font-weight:600;
  margin:0; letter-spacing:-.01em;
}
.rhead .hint{ margin-left:auto; font-size:11.5px; color:var(--muted-2); font-style:italic; }
.gloss{ display:grid; grid-template-columns:repeat(2,1fr); gap:var(--sp-4); }
@media (max-width:760px){ .gloss{ grid-template-columns:1fr; } }
.gcard{
  background:linear-gradient(180deg,var(--panel),var(--ink-2));
  border:1px solid var(--line); border-radius:var(--r-card); padding:15px 17px;
}
.gcard h3{ font-family:'Space Grotesk',sans-serif; font-weight:600; font-size:14px; margin:0 0 6px; }
.gcard p{ font-size:12.5px; color:var(--muted); line-height:1.6; margin:0; }
.gcard b{ color:var(--text); font-weight:600; }
.gcard code{
  font-family:'IBM Plex Mono',monospace; font-size:11.5px; color:var(--accent);
  background:var(--ink); padding:1px 5px; border-radius:var(--r-chip);
}
.gcard .fx{
  font-family:'IBM Plex Mono',monospace; font-size:12px; color:var(--accent);
  background:var(--ink); border:1px solid var(--line-soft); border-radius:var(--r-ctl);
  padding:7px 10px; margin:8px 0; display:inline-block;
}

footer{
  margin-top:34px; padding-top:18px; border-top:1px solid var(--line-soft);
  font-size:11.5px; color:var(--muted-2); line-height:1.6;
}
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }


/* ---- Quick scenarios — one-tap setups (same chrome as .presets) ---- */
.scenario-demos{ margin:0 0 14px; }
.scenario-demos .sc-label{
  font-family:'IBM Plex Mono',monospace; font-size:10px; font-weight:600;
  letter-spacing:.06em; text-transform:uppercase; color:var(--muted-2);
  margin:0 0 7px;
}
.scenario-demos .sc-row{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.scenario-demos button{
  font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted);
  background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  padding:7px 10px; cursor:pointer; text-align:left;
  transition:border-color var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out), background var(--t-1) var(--ease-out);
}
.scenario-demos button:hover{ border-color:var(--accent,var(--amber)); color:var(--text); }
.scenario-demos button:focus-visible{ outline:2px solid var(--accent,var(--amber)); outline-offset:2px; }
.scenario-demos button .sc-kicker{
  display:block; font-size:9px; font-weight:600; letter-spacing:.06em; text-transform:uppercase;
  color:var(--muted-2); margin-bottom:2px;
}
.scenario-demos button:hover .sc-kicker{ color:var(--muted); }
@media (max-width:560px){
  .scenario-demos button{ flex:1 1 calc(50% - 6px); min-height:40px; }
}

/* ---- viz hosts: theme-aware simulator / chart plates ----
   Prefer these tokens over hardcoded #0a111e / #fff so light mode stays legible. */
.hero svg,
.panel svg,
#anim, #springViz, #forceChart, #step, #dLoad, #dShear, #dMoment, #dDefl,
svg[id$="Svg"], svg[id$="Chart"], svg[id$="Viz"], canvas.viz {
  background: var(--viz-bg, var(--ink));
}
/* ...but NOT the little inline icons inside buttons. `.hero svg` and `.panel svg` are broad
   enough to catch every icon in a play/pause/reset/share control, painting an --ink plate behind
   a glyph that is itself filled with currentColor (= --ink on an accent-coloured button). The
   result was a solid dark square where the icon should be — on every simulator's play button.
   Charts are never inside a button, so this exclusion cannot affect them. */
.hero button svg,
.panel button svg,
button svg[id$="Svg"], button svg[id$="Chart"], button svg[id$="Viz"] {
  background: none;
}
/* Common inline style on viz wrappers */
.viz-host, .sim-stage, .chart-wrap {
  background: var(--viz-bg, var(--ink));
  border: 1px solid var(--viz-border, var(--line-soft));
  border-radius: var(--r-card);
}

/* Soften pure-black fills that some pages still hardcode when light theme is on */
:root[data-theme="light"] svg [fill="#0a111e"],
:root[data-theme="light"] svg [fill="#0e1830"],
:root[data-theme="light"] svg [fill="#111"],
:root[data-theme="light"] svg [fill="#000"],
:root[data-theme="light"] svg [fill="black"] {
  fill: var(--viz-bg);
}
:root[data-theme="light"] svg [stroke="#0a111e"],
:root[data-theme="light"] svg [stroke="#0e1830"] {
  stroke: var(--viz-border);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) svg [fill="#0a111e"],
  :root:not([data-theme="dark"]) svg [fill="#0e1830"],
  :root:not([data-theme="dark"]) svg [fill="#111"],
  :root:not([data-theme="dark"]) svg [fill="#000"],
  :root:not([data-theme="dark"]) svg [fill="black"] {
    fill: var(--viz-bg);
  }
  :root:not([data-theme="dark"]) svg [stroke="#0a111e"],
  :root:not([data-theme="dark"]) svg [stroke="#0e1830"] {
    stroke: var(--viz-border);
  }
}

/* Text drawn as SVG that used near-white fills: map to --text in light mode */
:root[data-theme="light"] svg [fill="#e9f0fb"],
:root[data-theme="light"] svg [fill="#fff"],
:root[data-theme="light"] svg [fill="#ffffff"],
:root[data-theme="light"] svg [fill="white"] {
  fill: var(--text);
}
:root[data-theme="light"] svg [stroke="#e9f0fb"],
:root[data-theme="light"] svg [stroke="#fff"],
:root[data-theme="light"] svg [stroke="#ffffff"],
:root[data-theme="light"] svg [stroke="white"] {
  stroke: var(--text);
}
@media (prefers-color-scheme: light) {
  :root:not([data-theme="dark"]) svg [fill="#e9f0fb"],
  :root:not([data-theme="dark"]) svg [fill="#fff"],
  :root:not([data-theme="dark"]) svg [fill="#ffffff"],
  :root:not([data-theme="dark"]) svg [fill="white"] {
    fill: var(--text);
  }
  :root:not([data-theme="dark"]) svg [stroke="#e9f0fb"],
  :root:not([data-theme="dark"]) svg [stroke="#fff"],
  :root:not([data-theme="dark"]) svg [stroke="#ffffff"],
  :root:not([data-theme="dark"]) svg [stroke="white"] {
    stroke: var(--text);
  }
}


/* ============================================================
   --- interaction polish ---

   Every control on a tool page reacted instantly or not at all: `.playbtn` — the play/pause/reset
   control on around forty pages, and the most-pressed thing on the site — had no hover state at all,
   and the segmented and preset buttons snapped between colours with no transition.

   Two rules followed here:

   1. Nothing that moves may change LAYOUT. The range thumb in particular is centred on its track by
      a hand-computed `margin-top:-6.5px` for its 17px size, so growing the thumb on hover would
      shift it off the track. The glow ring grows instead — it is a box-shadow, so it costs no space
      and cannot push anything out of alignment.
   2. All of it is off under `prefers-reduced-motion`, at the bottom of this block.
   ============================================================ */

.playbtn, .presets button, .seg button, .ctrlbtn, select, .catseg button{
  transition:background-color var(--t-1) var(--ease-out), border-color var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out),
             box-shadow var(--t-1) var(--ease-out), filter var(--t-1) var(--ease-out), transform var(--t-1) var(--ease-out);
}

/* the primary transport button: lift very slightly, brighten, then press in */
.playbtn:hover{ filter:brightness(1.08); transform:translateY(-1px); }
.playbtn:active{ transform:translateY(0) scale(.985); filter:brightness(.97); }
.playbtn.ghost:hover{
  background:color-mix(in srgb,var(--accent) 12%,var(--ink));
  filter:none;
}
.playbtn.ghost:active{ background:color-mix(in srgb,var(--accent) 18%,var(--ink)); }

/* segmented / preset buttons: a hint of the accent behind them before they are chosen, and a
   real pressed state so a tap on a phone visibly registers */
.presets button:hover, .seg button:hover, .catseg button:hover{
  background:color-mix(in srgb,var(--accent) 9%,var(--ink));
}
.presets button:active, .seg button:active, .catseg button:active{ transform:scale(.98); }
/* the already-selected one should not pretend to be selectable */
.presets button.on:hover, .seg button.on:hover, .catseg button.on:hover{
  filter:brightness(1.06); background:var(--accent);
}

select:hover{ border-color:color-mix(in srgb,var(--accent) 55%,var(--line)); }

/* slider: widen the glow on hover and again while dragging. Size is untouched on purpose —
   see note 1 above. */
input[type="range"]{ transition:box-shadow var(--t-1) var(--ease-out); }
input[type="range"]:hover::-webkit-slider-thumb{
  box-shadow:0 0 0 5px color-mix(in srgb,var(--c,var(--accent)) 30%,transparent);
}
input[type="range"]:active::-webkit-slider-thumb{
  box-shadow:0 0 0 7px color-mix(in srgb,var(--c,var(--accent)) 34%,transparent);
}
input[type="range"]:hover::-moz-range-thumb{
  box-shadow:0 0 0 5px color-mix(in srgb,var(--c,var(--accent)) 30%,transparent);
}
input[type="range"]:active::-moz-range-thumb{
  box-shadow:0 0 0 7px color-mix(in srgb,var(--c,var(--accent)) 34%,transparent);
}
input[type="range"]::-webkit-slider-thumb{ transition:box-shadow var(--t-1) var(--ease-out); }
input[type="range"]::-moz-range-thumb{ transition:box-shadow var(--t-1) var(--ease-out); }

/* a disabled control should look unavailable rather than merely unresponsive */
.playbtn:disabled, .ctrlbtn:disabled, .seg button:disabled, .presets button:disabled{
  opacity:.45; cursor:default; filter:none; transform:none;
}
.playbtn:disabled:hover, .ctrlbtn:disabled:hover{ filter:none; transform:none; }

/* links inside prose: underline on hover only, so body copy stays quiet until pointed at */
.rot-content a:not(.rot-btn), .rot-fieldnotes a{
  text-decoration-color:color-mix(in srgb,var(--accent) 45%,transparent);
  transition:text-decoration-color var(--t-1) var(--ease-out), color var(--t-1) var(--ease-out);
}
.rot-content a:not(.rot-btn):hover, .rot-fieldnotes a:hover{
  text-decoration-color:var(--accent);
}

/* Respect the reader's setting. Colour changes stay — they carry meaning and do not move —
   but nothing translates, scales or eases. */
@media (prefers-reduced-motion:reduce){
  .playbtn, .presets button, .seg button, .ctrlbtn, select, .catseg button,
  input[type="range"], input[type="range"]::-webkit-slider-thumb,
  input[type="range"]::-moz-range-thumb,
  .rot-content a, .rot-fieldnotes a{ transition:none; }
  .playbtn:hover, .playbtn:active,
  .presets button:active, .seg button:active, .catseg button:active{ transform:none; }
}

/* Chain backlinks — the reverse edge of the chain pages, generated by build-registry.py.
   Deliberately quiet: it is a wayfinding aid at the foot of a tool, not a call to action. */
.rot-chainlink{
  display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-3) var(--sp-4);
  margin:22px 0 0; padding:12px 15px; background:var(--ink);
  border:1px solid var(--line-soft); border-radius:var(--r-card);
  font-size:13px; color:var(--muted);
}
.rot-chainlink .cl-ey{
  font-size:10px; letter-spacing:.09em; text-transform:uppercase;
  color:var(--muted-2); font-weight:600;
}
.rot-chainlink a{ color:var(--accent); text-decoration:none; }
.rot-chainlink a:hover{ text-decoration:underline; }
.rot-chainlink .cl-all{ margin-left:auto; font-size:12px; }

/* Unusual-units toggle on the converter. Quiet by design: the units behind it are real and
   correctly converted, they are just not what anyone reaches for by accident. */
.oddbar{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3) var(--sp-4); margin-top:22px; }
.oddchk{ display:inline-flex; align-items:center; gap:var(--sp-3); font-size:13px; color:var(--muted); cursor:pointer; }
.oddchk input{ width:auto; accent-color:var(--accent); }
/* opt-in rounding controls sit on the same bar as the unusual-units toggle */
.roundbar{ margin-top:12px; }
.roundsel{ width:auto; min-width:58px; padding:5px 7px; font-size:12px; }
.roundsel:disabled{ opacity:.45; cursor:not-allowed; }
.oddnote{ font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted-2); }
.allcell.odd{ border-style:dashed; }
.allcell.odd .sym{ color:var(--amber); }

/* A landmark above the modelled atmosphere. Its height is real and shown; the arrow says the
   chart cannot reach it, which is honest about a limit rather than hiding the number. */
.lmbtn.beyond{ border-style:dashed; opacity:.9; }
.lmbtn.beyond .v{ color:var(--amber); }

/* ---------- paint page: picker and colour converter ---------- */
.pickwrap{ display:grid; grid-template-columns:minmax(220px,1fr) minmax(260px,1.2fr); gap:var(--sp-5); }
@media (max-width:760px){ .pickwrap{ grid-template-columns:1fr; } }
.svfield{ position:relative; width:100%; aspect-ratio:1.25; border-radius:var(--r-card);
  border:1px solid var(--line); cursor:crosshair; touch-action:none; }
.svdot{ position:absolute; width:16px; height:16px; border-radius:50%; border:2px solid #fff;
  box-shadow:0 0 0 1px rgba(0,0,0,.55); transform:translate(-50%,-50%); pointer-events:none; }
.huerail{ position:relative; height:18px; margin-top:10px; border-radius:var(--r-ctl);
  border:1px solid var(--line); cursor:pointer; touch-action:none; }
.huedot{ position:absolute; top:50%; width:14px; height:22px; border-radius:var(--r-chip); background:transparent;
  border:2px solid #fff; box-shadow:0 0 0 1px rgba(0,0,0,.55); transform:translate(-50%,-50%); pointer-events:none; }
.pickbtns{ display:flex; flex-wrap:wrap; align-items:center; gap:var(--sp-3); margin-top:12px; }
.nativelab{ display:inline-flex; align-items:center; gap:var(--sp-2); font-size:12px; color:var(--muted); }
.nativelab input[type="color"]{ width:34px; height:28px; padding:0; border:1px solid var(--line);
  border-radius:var(--r-ctl); background:var(--ink); cursor:pointer; }
.pbtn{ font-family:'Inter',sans-serif; font-size:12.5px; color:var(--text); background:var(--ink);
  border:1px solid var(--line); border-radius:var(--r-ctl); padding:8px 13px; cursor:pointer; }
.pbtn:hover{ border-color:var(--accent); color:var(--accent); }
.pbtn.primary{ background:var(--accent-dim); border-color:var(--accent); }
.cfprev{ height:46px; border-radius:var(--r-card); border:1px solid var(--line); margin-bottom:12px; }
.cffields{ display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr)); gap:var(--sp-3); }
.cffields label{ display:flex; flex-direction:column; gap:var(--sp-2); font-size:10.5px;
  letter-spacing:.07em; text-transform:uppercase; color:var(--muted-2); font-weight:600; }
.cffields input{ background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  color:var(--text); font-family:'IBM Plex Mono',monospace; font-size:13px; padding:8px 10px; outline:none; }
.cffields input:focus{ border-color:var(--accent); }
.cffields input[readonly]{ color:var(--muted); }
.cfmeta{ display:flex; flex-wrap:wrap; gap:var(--sp-3) var(--sp-4); margin-top:11px;
  font-family:'IBM Plex Mono',monospace; font-size:11px; color:var(--muted-2); }
.cfmeta b{ color:var(--text); }
.cfnote{ font-size:11.5px; color:var(--muted-2); line-height:1.6; margin-top:11px; }
.cfnote code{ font-family:'IBM Plex Mono',monospace; color:var(--muted); }
.cfnote b{ color:var(--muted); }

/* the gamut verdict — the answer to "why does the tin look duller than my screen" */
.gamut{ margin-top:18px; padding:14px 16px; border-radius:var(--r-card); border:1px solid var(--line-soft);
  background:var(--ink); font-size:13px; color:var(--muted); }
.gamut.close{ border-color:color-mix(in srgb,var(--green) 45%,transparent);
  background:color-mix(in srgb,var(--green) 8%,transparent); }
.gamut.near{ border-color:color-mix(in srgb,var(--amber) 45%,transparent);
  background:color-mix(in srgb,var(--amber) 8%,transparent); }
.gamut.far{ border-color:color-mix(in srgb,var(--red) 45%,transparent);
  background:color-mix(in srgb,var(--red) 8%,transparent); }
.gamut .g-head{ font-family:'Space Grotesk',sans-serif; font-weight:600; font-size:15px;
  color:var(--text); margin-bottom:10px; }
.gamut .g-sw{ display:flex; gap:0; margin-bottom:11px; border-radius:var(--r-ctl); overflow:hidden;
  border:1px solid var(--line); }
.gamut .g-sw span{ flex:1; height:42px; }
.gamut .g-rows div{ display:flex; flex-wrap:wrap; align-items:baseline; gap:var(--sp-3) var(--sp-4); padding:5px 0;
  border-top:1px dashed var(--line-soft); font-family:'IBM Plex Mono',monospace; font-size:12px; }
.gamut .g-rows div:first-child{ border-top:0; }
.gamut .g-rows span{ min-width:118px; color:var(--muted-2); font-size:10.5px;
  letter-spacing:.06em; text-transform:uppercase; }
.gamut .g-rows b{ color:var(--text); }
.gamut .g-rows i{ color:var(--muted-2); font-style:normal; }
.gamut .g-why{ margin-top:11px; font-size:12.5px; line-height:1.65; }
.gamut .g-why b{ color:var(--text); }

/* hue reachability strip — screen against mixable, hue by hue */
.huestrip{ margin-top:16px; }
.huestrip svg{ width:100%; height:auto; display:block; }
.huestrip .hs-axis{ stroke:var(--line); stroke-width:1; }
.huestrip .hs-lab{ fill:var(--muted-2); font-family:'Inter',sans-serif; font-size:11px;
  text-anchor:middle; }
.huestrip .hs-mark{ stroke:var(--text); stroke-width:1.5; stroke-dasharray:3 3; opacity:.75; }
.huestrip .hs-you{ fill:var(--text); font-family:'Inter',sans-serif; font-size:10px;
  text-anchor:middle; letter-spacing:.05em; }
.huestrip .hs-key{ display:flex; flex-wrap:wrap; gap:var(--sp-3) var(--sp-5); margin-top:6px;
  font-size:11.5px; color:var(--muted-2); }
.huestrip .hs-key span{ display:inline-flex; align-items:center; gap:var(--sp-2); }
.huestrip .hs-key i{ width:15px; height:11px; border-radius:var(--r-mark); }
/* outlined vs filled, because two chips at different opacities of the same grey read as one */
.huestrip .sw-ghost{ background:transparent; border:1px dashed var(--muted-2); }
.huestrip .sw-solid{ background:var(--muted-2); }
.huestrip .hs-cap{ font-size:12px; line-height:1.65; color:var(--muted); margin-top:9px; }
.huestrip .hs-cap b{ color:var(--text); }

/* ---- colour library, saved list, gamut outline ---- */
.libsearch{ width:100%; background:var(--ink); border:1px solid var(--line); border-radius:var(--r-ctl);
  color:var(--text); font-family:'Inter',sans-serif; font-size:12.5px; padding:7px 10px;
  outline:none; margin-bottom:8px; }
.libsearch:focus{ border-color:var(--accent); }
.libfams{ display:flex; flex-wrap:wrap; gap:var(--sp-1); margin-bottom:9px; }
.libfams button{ font-family:'IBM Plex Mono',monospace; font-size:10px; color:var(--muted-2);
  background:var(--ink); border:1px solid var(--line); border-radius:var(--r-chip); padding:4px 7px;
  cursor:pointer; }
.libfams button:hover{ border-color:var(--accent); color:var(--text); }
.libfams button.on{ color:var(--ink); background:var(--accent); border-color:var(--accent);
  font-weight:600; }
.libgrid{ display:grid; grid-template-columns:repeat(9,1fr); gap:var(--sp-1); }
@media (max-width:520px){ .libgrid{ grid-template-columns:repeat(7,1fr); } }
.libsw{ aspect-ratio:1; border-radius:var(--r-chip); border:1.5px solid var(--line); cursor:pointer;
  padding:0; }
.libsw:hover{ border-color:var(--text); transform:translateY(-1px); }
.libempty{ font-size:11.5px; color:var(--muted-2); line-height:1.6; padding:4px 0; }

.savedlist{ display:flex; flex-direction:column; gap:var(--sp-2); margin-bottom:10px; }
.savedrow{ display:flex; align-items:center; gap:var(--sp-3); padding:6px 8px; border:1px solid var(--line);
  border-radius:var(--r-ctl); background:var(--ink); }
.savedrow .sw{ width:20px; height:20px; border-radius:var(--r-chip); flex:none;
  border:1px solid var(--line-soft); }
.savedrow .nm{ font-size:12px; color:var(--text); flex:1; min-width:0; overflow:hidden;
  text-overflow:ellipsis; white-space:nowrap; }
.savedrow code{ font-family:'IBM Plex Mono',monospace; font-size:10.5px; color:var(--muted-2); }
.savedrow .rm{ flex:none; width:20px; height:20px; border-radius:var(--r-chip); border:1px solid var(--line);
  background:var(--panel); color:var(--muted-2); cursor:pointer; font-size:12px; line-height:1; }
.savedrow .rm:hover{ border-color:var(--red); color:var(--red); }
.savedfoot{ display:flex; flex-wrap:wrap; gap:var(--sp-2); }
.savedfoot .pbtn{ text-decoration:none; display:inline-flex; align-items:center; }

.svgamut{ position:absolute; inset:0; width:100%; height:100%; border-radius:var(--r-card);
  pointer-events:none; }
.gamtoggle{ display:flex; align-items:center; gap:var(--sp-2); margin-top:9px; font-size:11.5px;
  color:var(--muted-2); cursor:pointer; }
.gamtoggle input{ accent-color:var(--accent); }
