/* =========================================================================
   _tokens.css -- the contract.

   Every component class lives here, written purely in terms of custom
   properties. A theme file re-declares the property VALUES and adds whatever
   bespoke CSS its look needs; it does not restate component structure.

   Consequence: an app written against these classes renders correctly in
   every theme, and a new theme is ~100 lines.

   A theme has ONE palette (2026-09-24). There is no light/dark mode and no
   prefers-color-scheme anywhere: a page looks the same on every browser, which
   is the point -- `swiss`, `brutalist` and `paper` are light by nature,
   `aurora`, `terminal`, `console` and `everforest` dark, and each theme file
   declares its own `color-scheme` so scrollbars and native controls follow.
   The values below are only a fallback for the moment before the theme sheet
   lands; the theme file owns the palette.
   ========================================================================= */

:root {
  /* surfaces */
  --bg: #ffffff;
  --surface: #ffffff;
  --surface-2: #f4f4f5;
  --border: #e4e4e7;

  /* text */
  --text: #18181b;
  --text-muted: #52525b;
  --text-faint: #a1a1aa;

  /* accent + status */
  --accent: #2563eb;
  --accent-contrast: #ffffff;
  --accent-2: #7c3aed;
  --ok: #15803d;
  --warn: #b45309;
  --danger: #b91c1c;

  /* categorical data series */
  --series-1: #2563eb;
  --series-2: #db2777;
  --series-3: #15803d;
  --series-4: #b45309;
  --series-5: #7c3aed;
  --series-6: #0891b2;
  --series-7: #be123c;
  --series-8: #4d7c0f;

  /* type */
  --font-sans: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
  --font-display: var(--font-sans);
  --weight-normal: 400;
  --weight-medium: 500;
  --weight-bold: 700;
  --tracking: 0em;
  --tracking-display: 0em;
  --leading: 1.6;

  /* fluid type scale */
  --step--1: clamp(0.79rem, 0.77rem + 0.10vw, 0.84rem);
  --step-0:  clamp(1.00rem, 0.96rem + 0.19vw, 1.13rem);
  --step-1:  clamp(1.25rem, 1.18rem + 0.35vw, 1.50rem);
  --step-2:  clamp(1.56rem, 1.44rem + 0.60vw, 2.00rem);
  --step-3:  clamp(1.95rem, 1.75rem + 0.99vw, 2.66rem);
  --step-4:  clamp(2.44rem, 2.11rem + 1.60vw, 3.55rem);
  --step-5:  clamp(3.05rem, 2.54rem + 2.53vw, 4.73rem);

  /* shape + depth */
  --radius: 8px;
  --radius-lg: 14px;
  --radius-pill: 999px;
  --border-w: 1px;
  --shadow: 0 1px 2px rgb(0 0 0 / 0.06), 0 1px 3px rgb(0 0 0 / 0.10);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.10), 0 4px 6px -4px rgb(0 0 0 / 0.10);
  --ring: 0 0 0 3px color-mix(in srgb, var(--accent) 35%, transparent);

  /* motion */
  --ease: cubic-bezier(0.34, 1.25, 0.64, 1);   /* smooth with a slight overshoot -- every transition */
  --ease-out: cubic-bezier(0.2, 0, 0, 1);      /* for fades that must not overshoot */
  --dur: 180ms;
  --dur-slow: 420ms;                           /* anything that moves or fades */

  /* space + measure */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.5rem;
  --space-6: 2rem;
  --space-7: 3rem;
  --space-8: 4rem;
  --measure: 68ch;
  --container: 900px;
  --container-wide: 1400px;
}

/* ---------------------------------------------------------------- reset -- */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
[hidden] { display: none !important; }   /* so a class with its own display (grid, flex) still hides */

html { -webkit-text-size-adjust: 100%; }

body {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: var(--step-0);
  font-weight: var(--weight-normal);
  line-height: var(--leading);
  letter-spacing: var(--tracking);
  -webkit-font-smoothing: antialiased;
  min-height: 100vh;
}

img, svg, video, canvas { display: block; max-width: 100%; height: auto; }
input, button, textarea, select { font: inherit; color: inherit; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }

:where(a) {
  color: var(--accent);
  text-underline-offset: 0.2em;
  text-decoration-thickness: from-font;
}
:where(a:hover) { text-decoration-thickness: 2px; }

:where(:focus-visible) { outline: 2px solid var(--accent); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

/* --------------------------------------------------------------- layout -- */

.thon-page {
  max-width: var(--container);
  margin-inline: auto;
  padding: var(--space-7) var(--space-5) var(--space-8);
}
.thon-page.is-wide { max-width: var(--container-wide); }

.stack > * + * { margin-top: var(--space-4); }
.stack-lg > * + * { margin-top: var(--space-6); }

.row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.row.is-between { justify-content: space-between; }

.grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
}
.grid.is-2 { grid-template-columns: repeat(auto-fit, minmax(min(320px, 100%), 1fr)); }

/* ----------------------------------------------------------- typography -- */

h1, h2, h3, h4, h5, h6 {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-display);
  line-height: 1.15;
  text-wrap: balance;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }
h5 { font-size: var(--step-0); }
h6 { font-size: var(--step--1); text-transform: uppercase; letter-spacing: 0.08em; }

.lead { font-size: var(--step-1); color: var(--text-muted); text-wrap: pretty; }
.text-muted { color: var(--text-muted); }
.text-faint { color: var(--text-faint); }
.text-mono { font-family: var(--font-mono); }

.prose { max-width: var(--measure); }
.prose > * + * { margin-top: var(--space-4); }
.prose > * + :is(h2, h3, h4) { margin-top: var(--space-6); }
.prose :is(ul, ol) { padding-left: 1.4em; }
.prose li + li { margin-top: var(--space-2); }
.prose blockquote {
  border-left: 3px solid var(--accent);
  padding-left: var(--space-4);
  color: var(--text-muted);
  font-style: italic;
}
.prose hr { border: 0; border-top: var(--border-w) solid var(--border); }

.code, code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  background: var(--surface-2);
  border: var(--border-w) solid var(--border);
  border-radius: calc(var(--radius) / 2);
  padding: 0.12em 0.4em;
}
pre {
  font-family: var(--font-mono);
  font-size: var(--step--1);
  background: var(--surface-2);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-4);
  overflow-x: auto;
}
pre code { background: none; border: 0; padding: 0; font-size: inherit; }

.kbd {
  font-family: var(--font-mono);
  font-size: 0.82em;
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-bottom-width: calc(var(--border-w) + 1px);
  border-radius: calc(var(--radius) / 2);
  padding: 0.1em 0.45em;
  box-shadow: var(--shadow);
}

/* --------------------------------------------------------------- cards -- */

.card {
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow);
  padding: var(--space-5);
}
.card > * + * { margin-top: var(--space-3); }

/* A card that is itself a link shouldn't underline its entire contents; the
   title carries the affordance instead. */
a.card {
  display: block;
  color: inherit;
  text-decoration: none;
}
a.card .card-title { color: var(--accent); }
a.card:hover .card-title { text-decoration: underline; text-underline-offset: 0.2em; }
.card-title { font-size: var(--step-1); font-family: var(--font-display); font-weight: var(--weight-bold); }

/* ------------------------------------------------------------- buttons -- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  background: var(--surface);
  color: var(--text);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: var(--space-2) var(--space-4);
  font-weight: var(--weight-medium);
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease),
              transform var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.btn:hover { background: var(--surface-2); }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: 0.5; cursor: not-allowed; }

.btn-primary {
  background: var(--accent);
  color: var(--accent-contrast);
  border-color: var(--accent);
}
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 85%, var(--text)); }

.btn-ghost { background: transparent; border-color: transparent; box-shadow: none; }
.btn-ghost:hover { background: var(--surface-2); }

.btn-sm { padding: var(--space-1) var(--space-3); font-size: var(--step--1); }

/* --------------------------------------------------------------- forms -- */

.input, .select, .textarea {
  width: 100%;
  background: var(--surface);
  color: var(--text);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-2) var(--space-3);
  transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease);
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: var(--ring);
}
.textarea { min-height: 7rem; resize: vertical; }
.label {
  display: block;
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  color: var(--text-muted);
  margin-bottom: var(--space-1);
}
.field + .field { margin-top: var(--space-4); }

/* -------------------------------------------------------------- badges -- */

.badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  background: var(--surface-2);
  color: var(--text-muted);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-pill);
  padding: 0.15em 0.7em;
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  line-height: 1.5;
  white-space: nowrap;
}
.badge-accent { background: color-mix(in srgb, var(--accent) 14%, transparent); color: var(--accent); border-color: color-mix(in srgb, var(--accent) 35%, transparent); }
.badge-ok     { background: color-mix(in srgb, var(--ok) 14%, transparent);     color: var(--ok);     border-color: color-mix(in srgb, var(--ok) 35%, transparent); }
.badge-warn   { background: color-mix(in srgb, var(--warn) 14%, transparent);   color: var(--warn);   border-color: color-mix(in srgb, var(--warn) 35%, transparent); }
.badge-danger { background: color-mix(in srgb, var(--danger) 14%, transparent); color: var(--danger); border-color: color-mix(in srgb, var(--danger) 35%, transparent); }

/* --------------------------------------------------------------- table -- */

.table-wrap { overflow-x: auto; border-radius: var(--radius); }
.table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}
.table :is(th, td) {
  text-align: left;
  padding: var(--space-2) var(--space-3);
  border-bottom: var(--border-w) solid var(--border);
}
.table th {
  font-size: var(--step--1);
  font-weight: var(--weight-bold);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  white-space: nowrap;
}
.table tbody tr:hover { background: var(--surface-2); }
.table .num { text-align: right; }

/* --------------------------------------------------------------- stats -- */

.stat {
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
}
.stat-label {
  font-size: var(--step--1);
  color: var(--text-muted);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.stat-value {
  font-family: var(--font-display);
  font-size: var(--step-3);
  font-weight: var(--weight-bold);
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  margin-top: var(--space-1);
}
.stat-delta { font-size: var(--step--1); color: var(--text-muted); }
.stat-delta.is-up { color: var(--ok); }
.stat-delta.is-down { color: var(--danger); }

/* ---------------------------------------------------------------- tabs -- */

.tabs {
  display: flex;
  gap: var(--space-1);
  border-bottom: var(--border-w) solid var(--border);
  overflow-x: auto;
}
.tab {
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: var(--space-2) var(--space-4);
  color: var(--text-muted);
  font-weight: var(--weight-medium);
  cursor: pointer;
  white-space: nowrap;
  transition: color var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.tab:hover { color: var(--text); }
.tab[aria-selected="true"] { color: var(--accent); border-bottom-color: var(--accent); }

/* -------------------------------------------------------------- chart -- */
/* Chart.js with responsive + maintainAspectRatio:false sizes to its parent, so
   the parent must have a real height or the canvas grows without limit. */

.chart {
  position: relative;
  height: 280px;
  width: 100%;
}
.chart.is-short { height: 180px; }
.chart.is-tall { height: 420px; }

/* ------------------------------------------------------------- toolbar -- */

.toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius);
  padding: var(--space-3) var(--space-4);
}

/* ------------------------------------------------------------ switcher -- */
/* The floating design-language picker injected by static/js/switcher.js. */

.thon-switcher {
  position: fixed;
  right: max(var(--space-4), env(safe-area-inset-right));
  bottom: max(var(--space-4), env(safe-area-inset-bottom));
  z-index: 9999;
  font-family: var(--font-sans);
  font-size: 14px;
}
.thon-switcher__toggle {
  display: flex;
  align-items: center;
  gap: 0.5em;
  background: var(--surface);
  color: var(--text);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-pill);
  box-shadow: var(--shadow-lg);
  padding: 0.5em 1em;
  cursor: pointer;
  line-height: 1.2;
}
.thon-switcher__swatch {
  width: 0.7em;
  height: 0.7em;
  border-radius: 50%;
  background: var(--accent);
  flex: none;
}
.thon-switcher__menu {
  position: absolute;
  right: 0;
  bottom: calc(100% + 0.5em);
  min-width: 15rem;
  background: var(--surface);
  border: var(--border-w) solid var(--border);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  padding: 0.35em;
  display: none;
}
.thon-switcher[data-open="true"] .thon-switcher__menu { display: block; }
.thon-switcher__item {
  display: block;
  width: 100%;
  text-align: left;
  background: none;
  border: 0;
  border-radius: calc(var(--radius) - 2px);
  padding: 0.5em 0.7em;
  cursor: pointer;
  color: var(--text);
}
.thon-switcher__item:hover { background: var(--surface-2); }
.thon-switcher__item[aria-current="true"] { background: var(--surface-2); font-weight: var(--weight-bold); }
.thon-switcher__blurb { display: block; font-size: 0.82em; color: var(--text-muted); font-weight: 400; }
@media print { .thon-switcher { display: none; } }


/* ------------------------------------------------- stage, pills, motion -- */
/* 2026-09-17: jnap's rules for anything he looks at. An interface that fits
   the viewport is centred in x and y ("stage": true in app.json); every layout
   works on a phone; nothing on the page but the interface -- no title, no
   caption, no helper text unless it does something; motion is smooth and
   slightly bouncy (the --ease overshoot above), never instant, never springy
   enough to read as a toy. */

.thon-page.is-stage {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: var(--space-5);
}
.thon-page.is-stage > * { max-width: 100%; }

/* Pillbox buttons, as on jnap's YouTube: text only, flat, no icon beside a
   word. State is an inset ring, never a colour change; .filled is the one
   primary action on a view; .danger the destructive one. */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.25rem;
  padding: 0 var(--space-4);
  border: 0;
  border-radius: var(--radius-pill);
  background: var(--surface-2);
  color: var(--text);
  font-size: var(--step--1);
  font-weight: var(--weight-medium);
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur) var(--ease), box-shadow var(--dur) var(--ease),
              transform var(--dur) var(--ease), opacity var(--dur-slow) var(--ease);
}
.pill:hover  { background: color-mix(in srgb, var(--surface-2) 70%, var(--border)); }
.pill:active { transform: scale(0.97); }
.pill.on, .pill[aria-pressed="true"] { box-shadow: inset 0 0 0 1.5px var(--text); }
.pill.filled { background: var(--text); color: var(--bg); }
.pill.filled:hover { background: color-mix(in srgb, var(--text) 88%, var(--bg)); }
.pill.danger { color: var(--danger); }
.pill.danger.armed { background: var(--danger); color: var(--bg); }
.pill:disabled { opacity: 0.45; cursor: default; transform: none; }

/* A control whose label toggles (Start/Stop, Delete/Confirm, Enable/Disable)
   keeps one size: stack the labels in one cell and show one.
     <button class="pill swap"><span class="show">Start</span><span>Stop</span></button>
   Only a control that deliberately grows to reveal more may change size. */
.swap { display: inline-grid; align-items: center; justify-items: center; }
.swap > * { grid-area: 1 / 1; visibility: hidden; }
.swap > .show { visibility: visible; }

/* A ring spinner for "working"; the only element allowed to spin. */
.spinner {
  width: 2rem;
  height: 2rem;
  border-radius: 50%;
  border: 3px solid var(--border);
  border-top-color: var(--accent);
  animation: thon-spin 0.9s linear infinite;
}
@keyframes thon-spin { to { transform: rotate(360deg); } }

/* Fade helpers: add .is-out, wait var(--dur-slow), then hide. */
.fade { transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease); }
.fade.is-out { opacity: 0; transform: translateY(6px) scale(0.985); pointer-events: none; }
.fade.is-in-from { opacity: 0; transform: translateY(10px); }
