/* ==========================================================================
   An's Physics Lecture · Simulator Style (Physics Visualization Standard)
   --------------------------------------------------------------------------
   Source: extracted from 018_Wave_on_a_String.html (줄 파동).
   Guide:  Skill/physics-simulator-design/references/style-system.md

   Order
   ① Design tokens (light "paper" B = default, dark "soft" A)
   ② Typography & KaTeX
   ③ Layout (header, intro, workspace, footer, focus mode)
   ④ Components (buttons, inputs, dialogs, callouts, toast, tooltip, nav)
   ⑤ Simulation controls (stage, transport, readouts, control panel)
   ⑥ Graph & physics drawing tokens (read by canvas/SVG code)
   ⑦ Responsive, accessibility, motion, print

   Extending: add variants with a numbered suffix next to the base rule,
   e.g. .slider-2, .callout-2, .metric-2. Never change a token's meaning;
   add a new token instead.
   ========================================================================== */


/* ==========================================================================
   ① DESIGN TOKENS
   ========================================================================== */

:root {
  /* Fonts. Pretendard is loaded by the page (see style-system.md); system fallbacks follow. */
  --sans: "Pretendard Variable", Pretendard, "Apple SD Gothic Neo", "Noto Sans KR", system-ui, sans-serif;
  --mono: ui-monospace, SFMono-Regular, Consolas, monospace;
  --serif-math: KaTeX_Main, "Times New Roman", serif;

  /* Type scale (px). UI is dense; prose in dialogs uses --fs-prose. */
  --fs-2xs: 9px;    /* trace/axis captions on small screens */
  --fs-xs: 10px;    /* eyebrow, axis tick labels, stage scale */
  --fs-sm: 11px;    /* captions, metric labels, limits, footer links */
  --fs-md: 12px;    /* control labels, buttons in panels, values */
  --fs-prose: 13px; /* dialog text, section headings (h2 in panels) */
  --fs-base: 14px;  /* body */
  --fs-lg: 16px;    /* stopwatch value */
  --fs-metric: 20px;/* live readout values */
  --fs-h2: 21px;    /* dialog titles */
  --fs-h1: clamp(25px, 2.5vw, 36px);
  --lh-tight: 1.18;
  --lh-base: 1.5;
  --lh-caption: 1.6;
  --lh-prose: 1.8;
  --tracking-title: -.045em;
  --tracking-metric: -.04em;
  --tracking-eyebrow: .16em;

  /* Spacing scale (4-px base) */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;

  /* Radius */
  --radius-xs: 4px;   /* kbd */
  --radius-sm: 6px;   /* value inputs */
  --radius-md: 9px;   /* buttons */
  --radius-lg: 14px;  /* cards, instruments */
  --radius: 18px;     /* stage card, panel, dialog */
  --radius-pill: 999px;

  /* Layout */
  --content-max: 1700px;
  --gutter: clamp(18px, 3vw, 48px);
  --header-h: 55px;
  --panel-w: 306px;        /* control panel (sidebar) */
  --panel-w-wide: 326px;   /* ≥1500px */
  --panel-w-narrow: 280px; /* ≤1050px */
  --dialog-w: 620px;
  --dialog-w-wide: 1100px;
  --stage-h: clamp(285px, 36vh, 470px);
  --stage-h-wide: clamp(320px, 40vh, 540px);
  --stage-h-focus: clamp(320px, 43vh, 620px);
  /* Breakpoints (for reference; media queries cannot read variables):
     wide ≥1500 · desktop >1050 · tablet ≤1050 · stacked ≤800 · phone ≤480 */

  /* Controls */
  --control-h: 40px;
  --control-h-sm: 32px;
  --touch-target: 44px;
  --icon-size: 18px;
  --icon-stroke: 1.6;

  /* Layers */
  --z-base: 0;
  --z-canvas-overlay: 10;  /* hints, loading overlay inside the stage */
  --z-sticky: 20;          /* sticky header / bottom bar */
  --z-drawer: 50;
  --z-dropdown: 60;
  --z-tooltip: 70;
  --z-toast: 90;
  --z-skip: 100;           /* skip link above everything except dialogs (top layer) */

  /* Motion: UI only. Physical motion is driven by the simulation clock, never by CSS. */
  --dur-fast: .12s;
  --dur: .16s;
  --dur-slow: .2s;
  --ease: cubic-bezier(.2, .7, .2, 1);

  /* ⑥ Geometry of drawings (canvas/SVG read these with getComputedStyle) */
  --plot-margin: 24px;          /* minimum space around a plot so arrowheads and axis names never clip */
  --plot-axis-width: 1.5;       /* px, x/y axes */
  --plot-grid-width: .65;       /* px */
  --plot-tick-major: 7;         /* px */
  --plot-tick-minor: 4;         /* px */
  --plot-arrow-length: 9;       /* px, axis arrowhead */
  --plot-arrow-width: 6;        /* px */
  --plot-curve-width: 2.4;      /* px, main curve (y(x), string) */
  --plot-trace-width: 1.7;      /* px, time trace y(t) */
  --plot-point-radius: 4.5;     /* px, probe/marker dot */
  --plot-point-halo: 10;        /* px, translucent halo around a marker */
  --plot-label-size: 10;        /* px, tick and object labels (mono) */
  --plot-dash-equilibrium: "4 6";
  --plot-dash-guide: "2 5";
  --plot-dash-reference: "7 5";
  --plot-dash-open: "3 4";
  --vec-width: 2.5;             /* px, velocity / acceleration */
  --vec-width-force: 3;         /* px, force */
  --vec-arrow-length: 10;       /* px */
  --vec-arrow-width: 7;         /* px */
  --bead-radius-min: 3;         /* px, particle view */
  --bead-radius-max: 7.5;
  --object-stroke: 1.5;         /* px, outline of bodies and handles */
  --wall-width: 3;              /* px, fixed support */
  --hatch-gap: 9;               /* px, support hatch spacing */
}

/* B · warm paper light (default) */
:root,
:root[data-theme=light] {
  color-scheme: light;
  /* Surfaces */
  --bg: #f3eee3;
  --surface: #faf7f0;
  --surface-2: #f1ebdf;
  --surface-hover: #e9e1d1;
  --surface-sunken: #ece5d7;
  --surface-input: #fffdf8;
  --surface-stage: #fbf8f1;
  --surface-instruments: #faf7f0;
  --surface-card: #f7f3ea;
  --surface-dialog: #fbf8f2;
  --surface-tint: #eef0e8;
  --surface-selected: #dcebe6;
  --surface-selected-warm: #f3e3c8;
  /* Lines */
  --line: #ddd4c3;
  --line-soft: #e9e2d4;
  --line-strong: #c2b7a2;
  /* Text */
  --text: #3b3a36;
  --text-strong: #2a2926;
  --text-muted: #625e55;
  --text-faint: #6f695e;
  --text-dialog: #4a4740;
  /* Accent (primary action, the system itself: string, wave) */
  --accent: #286f66;   /* text-safe (≥4.5:1 on every surface); drawings keep --viz-string */
  --accent-hover: #215c55;
  --on-accent: #ffffff;
  --accent-text: #22645b;
  --accent-soft: #e3efe9;
  --accent-line: #b9d3cb;
  --accent-line-strong: #7fb0a4;
  --selected-warm-text: #8a5212;
  /* Observers */
  --probe-1: #955c15;
  --probe-1-line: #dcc39a;
  --probe-2: #6b55a8;
  --probe-2-line: #c9bfe3;
  /* Status */
  --info: #2f6f9a;
  --info-soft: #e4eef5;
  --success: #3d7f4a;
  --success-soft: #e5f0e3;
  --warn: #b5651d;
  --warn-soft: #f6e8d6;
  --danger: #b23a3a;
  --danger-soft: #f6e1dd;
  --state-running: #286f66;
  --state-paused: #955c15;
  /* Controls */
  --track: #cfc5b2;
  --thumb-ring: #faf7f0;
  --toast-bg: #2f3a36;
  --toast-text: #f3eee3;
  --toast-line: #2f3a36;
  --backdrop: rgba(60, 52, 40, .35);
  --shadow-dialog: 0 30px 80px rgba(60, 48, 30, .25);
  --shadow-card: 0 1px 2px rgba(60, 48, 30, .06);
  --focus-ring: #286f66;

  /* ⑥ Visualization colours (canvas/SVG). All are 6-digit hex so code can append alpha. */
  --viz-bg: #fbf8f1;
  --viz-bg-2: #f7f2e8;
  --viz-grid: #ebe4d6;
  --viz-axis: #b9ae99;
  --viz-axis-strong: #5e5a51;   /* graph axes with arrowheads */
  --viz-tick: #a79c86;
  --viz-label: #7a7466;
  --viz-equilibrium: #b9ae99;
  --viz-string: #2f7d73;
  --viz-string-dot: #d9efe9;
  --viz-bead-line: #9fbfb8;
  --viz-bead-light: #ffffff;
  --viz-bead: #4fa596;
  --viz-bead-dark: #256a61;
  --viz-bead-ref-light: #fff1ec;
  --viz-bead-ref: #d66b55;
  --viz-bead-ref-dark: #9a3b2b;
  --viz-outline: #ffffff;
  --viz-wall: #8a8172;
  --viz-hatch: #b3a991;
  --viz-pin: #6d675c;
  --viz-source-rail: #cfc5b2;
  --viz-source-fill: #dcebe6;
  --viz-source-ring: #2f7d73;
  --viz-source-mark: #2f7d73;
  --viz-source-label: #6e6a60;
  --viz-guide: #b3a991;
  --viz-ring: #5e5a51;
  --viz-ring-fill: #fbf8f1;
  --viz-open: #b9ae99;
  --viz-open-arrow: #8a8172;
  --viz-trace-zero: #d8cfbd;
  --viz-trace-label: #7a7466;
  --viz-ground: #a99f8b;
  --viz-trajectory: #8b8578;

  /* ⑥ Physical meaning colours. Same concept = same colour on every page. */
  --phys-position: #2f6f9a;      /* x, displacement */
  --phys-velocity: #3d7f4a;      /* v */
  --phys-acceleration: #b5651d;  /* a */
  --phys-force: #b23a3a;         /* F */
  --phys-momentum: #7a5c2e;      /* p */
  --phys-energy: #6b55a8;        /* E, E_k, E_p */
  --phys-field-e: #b23a3a;
  --phys-field-b: #2f6f9a;
  --phys-incident: #2f6f9a;      /* incident wave */
  --phys-reflected: #b5651d;     /* reflected wave */
  --phys-transmitted: #3d7f4a;
  --phys-resultant: #2a2926;     /* superposition / net */
  --phys-object-a: #2f6f9a;
  --phys-object-b: #b5651d;
  --phys-object-c: #6b55a8;
  --phys-spring: #6d675c;
  --phys-wave-1: #2f6f9a;       /* first of two superposed waves (solid) */
  --phys-wave-2: #b5651d;       /* second wave (dashed) */
  --phys-wave-sum: #2a2926;     /* their superposition (thick solid) */
  --phys-ball-1: #b4501f;       /* incident ball (outline, path, marks) — same rust as the lecture notes */
  --phys-ball-2: #1d6b7a;       /* target ball — lecture teal */
  --viz-ball: #a3a8ac;          /* steel/glass ball body */
  --viz-ball-light: #f4f6f7;
  --viz-ramp: #c9d2d6;
  --viz-paper: #f1ede4;         /* carbon paper sheet on the floor */
}

/* A · soft dark */
:root[data-theme=dark] {
  color-scheme: dark;
  --bg: #1e2328;
  --surface: #252b31;
  --surface-2: #2c333a;
  --surface-hover: #343c44;
  --surface-sunken: #1a1e22;
  --surface-input: #1c2126;
  --surface-stage: #1b1f23;
  --surface-instruments: #22272d;
  --surface-card: #282e35;
  --surface-dialog: #262c32;
  --surface-tint: #2a3132;
  --surface-selected: #34433f;
  --surface-selected-warm: #45402f;
  --line: #3a424a;
  --line-soft: #2e353c;
  --line-strong: #4d5760;
  --text: #d6d2c8;
  --text-strong: #ece8de;
  --text-muted: #9a9c98;
  --text-faint: #959894;
  --text-dialog: #c4c0b6;
  --accent: #8fbcae;
  --accent-hover: #a6cdc1;
  --on-accent: #17201e;
  --accent-text: #b4d8cc;
  --accent-soft: #2a3633;
  --accent-line: #3f5550;
  --accent-line-strong: #5f8077;
  --selected-warm-text: #e2c590;
  --probe-1: #d8b37a;
  --probe-1-line: #5a4c36;
  --probe-2: #a99fd0;
  --probe-2-line: #4a4560;
  --info: #8db4d3;
  --info-soft: #24313b;
  --success: #9cc39f;
  --success-soft: #263229;
  --warn: #d9a066;
  --warn-soft: #3a2f24;
  --danger: #e09a8f;
  --danger-soft: #3b2827;
  --state-running: #8fbcae;
  --state-paused: #d8b37a;
  --track: #4a535b;
  --thumb-ring: #252b31;
  --toast-bg: #34433f;
  --toast-text: #e6efe9;
  --toast-line: #4f6862;
  --backdrop: rgba(10, 12, 14, .6);
  --shadow-dialog: 0 30px 90px rgba(0, 0, 0, .45);
  --shadow-card: 0 1px 2px rgba(0, 0, 0, .25);
  --focus-ring: #8fbcae;

  --viz-bg: #1b1f23;
  --viz-bg-2: #191d21;
  --viz-grid: #2a3036;
  --viz-axis: #4d5760;
  --viz-axis-strong: #a3a7a3;
  --viz-tick: #5d676f;
  --viz-label: #8d918d;
  --viz-equilibrium: #4f5960;
  --viz-string: #8fbcae;
  --viz-string-dot: #cfe4dc;
  --viz-bead-line: #4a6560;
  --viz-bead-light: #e9f5f1;
  --viz-bead: #7fb3a4;
  --viz-bead-dark: #3f6f64;
  --viz-bead-ref-light: #fbe3dc;
  --viz-bead-ref: #d9927f;
  --viz-bead-ref-dark: #94503f;
  --viz-outline: #15191c;
  --viz-wall: #7d858b;
  --viz-hatch: #4d575f;
  --viz-pin: #cfd3d0;
  --viz-source-rail: #3d464e;
  --viz-source-fill: #2c3b38;
  --viz-source-ring: #8fbcae;
  --viz-source-mark: #d6ebe4;
  --viz-source-label: #9a9c98;
  --viz-guide: #4d575f;
  --viz-ring: #c9cdc9;
  --viz-ring-fill: #1b1f23;
  --viz-open: #4d5760;
  --viz-open-arrow: #7d858b;
  --viz-trace-zero: #3a424a;
  --viz-trace-label: #8d918d;
  --viz-ground: #6a7279;
  --viz-trajectory: #7e817e;

  --phys-position: #8db4d3;
  --phys-velocity: #9cc39f;
  --phys-acceleration: #d9a066;
  --phys-force: #e09a8f;
  --phys-momentum: #c9ad7c;
  --phys-energy: #a99fd0;
  --phys-field-e: #e09a8f;
  --phys-field-b: #8db4d3;
  --phys-incident: #8db4d3;
  --phys-reflected: #d9a066;
  --phys-transmitted: #9cc39f;
  --phys-resultant: #ece8de;
  --phys-object-a: #8db4d3;
  --phys-object-b: #d9a066;
  --phys-object-c: #a99fd0;
  --phys-spring: #a3a7a3;
  --phys-wave-1: #8db4d3;
  --phys-wave-2: #d9a066;
  --phys-wave-sum: #ece8de;
  --phys-ball-1: #e29a74;
  --phys-ball-2: #84bfcb;
  --viz-ball: #8d959b;
  --viz-ball-light: #e6eaec;
  --viz-ramp: #56626a;
  --viz-paper: #262c31;
}


/* ==========================================================================
   ② TYPOGRAPHY & KATEX
   ========================================================================== */

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--sans);
  font-size: var(--fs-base);
  line-height: var(--lh-base);
}

button, input, select { font: inherit; }

h1 {
  font-size: var(--fs-h1);
  font-weight: 600;
  letter-spacing: var(--tracking-title);
  line-height: var(--lh-tight);
  margin: 0;
}

/* Numbers that change over time never jump in width. */
output, .num, .metric dd, .time-readout, .number-input { font-variant-numeric: tabular-nums; }

.eyebrow {
  font: var(--fs-xs) var(--mono);
  letter-spacing: var(--tracking-eyebrow);
  color: var(--accent);
  margin: 0 0 7px;
}

kbd {
  font: var(--fs-sm) var(--mono);
  padding: 2px 6px;
  background: var(--surface-2);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-xs);
}

/* KaTeX
   - $…$ inline symbols inside sentences (v, T, \mu, \lambda, units with \mathrm{}).
   - $$…$$ display equations in .formula-box / .equation, one idea per box, no equation numbers.
   - KaTeX inherits currentColor, so it follows both themes. */
.katex { color: inherit; }
dialog p .katex, dialog td .katex, dialog th .katex, dialog caption .katex { font-size: 1.06em; }
.help-table caption .katex { font-size: 1em; }

.equation {
  padding: 15px;
  background: var(--surface-sunken);
  border-radius: 10px;
  text-align: center;
  font: 18px Georgia, serif;
  color: var(--probe-1);
  overflow-x: auto;
  font-size: clamp(13px, 2.4vw, 18px);
}
.equation .katex-display { margin: 0; }

.formula-box {
  background: var(--surface-sunken);
  border-radius: 10px;
  padding: 8px 14px;
  margin: 10px 0;
  color: var(--probe-1);
  overflow-x: auto;       /* long equations scroll instead of breaking the layout on phones */
}
.formula-box .katex-display { margin: 6px 0; }
.formula-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 4px 18px;
}
.formula-label {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-muted);
  margin-top: 4px;
}
/* Inline formula next to a label, e.g. "파동의 속력 (v=√(T/μ))" */
.dt-formula { font-size: var(--fs-md); color: var(--text-muted); }


/* ==========================================================================
   ③ LAYOUT
   ========================================================================== */

[hidden] { display: none !important; }

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.skip {
  position: fixed;
  top: 8px; left: 8px;
  z-index: var(--z-skip);
  padding: 10px;
  background: var(--accent);
  color: var(--bg);
  transform: translateY(-160%);
}
.skip:focus { transform: none; }

/* Header: brand (home) on the left, back-to-collection link on the right. */
.brandbar {
  height: var(--header-h);
  border-bottom: 1px solid var(--line-soft);
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 var(--gutter);
  gap: 16px;
}
.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-size: var(--fs-prose);
  font-weight: 600;
  letter-spacing: .01em;
  color: var(--text-muted);
}
.brand svg { width: 24px; height: 24px; color: var(--accent); }
/* Brand wordmark in Times New Roman (site identity); the rest of the UI stays in Pretendard. */
.brand span { font-family: "Times New Roman", Times, "Noto Serif", serif; font-size: 16px; font-weight: 700; letter-spacing: 0; }
.brand:hover { color: var(--text-strong); }
.collection {
  font-size: var(--fs-md);
  color: var(--text-muted);
  display: flex;
  align-items: center;
  gap: 8px;
}
.collection:hover { color: var(--accent); }

main {
  max-width: var(--content-max);
  margin: 0 auto;
  padding: 25px var(--gutter) 0;
}

/* Page title block: eyebrow (unit) · h1 (topic) · one-line goal · top actions */
.intro {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
}
.intro-description { color: var(--text-muted); margin: 8px 0 0; font-size: var(--fs-prose); }
.top-actions { display: flex; gap: 10px; align-items: center; flex: none; }

/* Workspace: observation column + control panel (sidebar) */
.workspace {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--panel-w);
  gap: 18px;
  align-items: start;
}
.observation { min-width: 0; }

/* Footer */
.site-footer {
  max-width: var(--content-max);
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px var(--gutter) 18px;
  color: var(--text-muted);
  font-size: var(--fs-xs);
}
.footer-links { display: flex; align-items: center; gap: 15px; }
.footer-links button {
  border: 0;
  background: none;
  color: var(--text-muted);
  min-height: 30px;
  padding: 0;
  font-size: var(--fs-sm);
}
.footer-links button:hover, .footer-links a:hover { color: var(--accent); }

/* Focus mode: hide brand, intro text and footer; keep exit, transport and controls. */
body.focus .brandbar,
body.focus .site-footer,
body.focus .intro-description,
body.focus .eyebrow { display: none; }
body.focus main { padding-top: 16px; }
body.focus .intro { margin-bottom: 16px; }
body.focus .canvas-wrap { height: var(--stage-h-focus); }
body.focus h1 { font-size: 24px; }

/* Breadcrumb and previous/next simulation (optional) */
.breadcrumb { display: flex; flex-wrap: wrap; gap: 6px; font-size: var(--fs-sm); color: var(--text-muted); margin: 0 0 6px; }
.breadcrumb a:hover { color: var(--accent); }
.breadcrumb [aria-current] { color: var(--text); }
.breadcrumb > * + *::before { content: "/"; margin-right: 6px; color: var(--text-faint); }
.sim-nav {
  max-width: var(--content-max);
  margin: 18px auto 0;
  padding: 0 var(--gutter);
  display: flex;
  justify-content: space-between;
  gap: 12px;
}
.sim-nav a {
  display: inline-flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface);
  font-size: var(--fs-md);
  min-width: 0;
}
.sim-nav a small { color: var(--text-muted); font-size: var(--fs-sm); }
.sim-nav a:hover { border-color: var(--accent-line-strong); }
.sim-nav .next { text-align: right; margin-left: auto; }


/* ==========================================================================
   ④ COMPONENTS
   ========================================================================== */

/* Icons: one line icon set (Lucide-style 24×24 paths), 18px, stroke 1.6, round caps. */
button svg, a svg {
  width: var(--icon-size);
  height: var(--icon-size);
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: var(--icon-stroke);
  stroke-linecap: round;
  stroke-linejoin: round;
}

a { color: inherit; text-decoration: none; }
button, a, input, select, summary { -webkit-tap-highlight-color: transparent; }
button, a, summary, input, select { outline-offset: 4px; }
:focus-visible { outline: 2px solid var(--focus-ring); }

/* Buttons. Text buttons for actions, icon-only buttons need aria-label + title. */
button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  border: 1px solid var(--line);
  border-radius: var(--radius-md);
  background: var(--surface-2);
  color: inherit;
  min-height: var(--control-h);
  padding: 8px 12px;
  cursor: pointer;
  transition: background var(--dur), border-color var(--dur);
}
button:hover { background: var(--surface-hover); border-color: var(--line-strong); }
button:active { transform: translateY(1px); }
button:disabled { opacity: .4; cursor: not-allowed; }
.primary { background: var(--accent); border-color: var(--accent); color: var(--on-accent); font-weight: 650; }
.primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.quiet { background: transparent; }
.icon-button { width: var(--control-h); padding: 0; }
.button-sm { min-height: var(--control-h-sm); font-size: var(--fs-sm); padding: 5px 9px; }
.is-loading { position: relative; color: transparent !important; pointer-events: none; }
.is-loading::after {
  content: "";
  position: absolute;
  width: 14px; height: 14px;
  border: 2px solid var(--text-muted);
  border-right-color: transparent;
  border-radius: 50%;
  animation: sim-spin .8s linear infinite;
}
@keyframes sim-spin { to { transform: rotate(360deg); } }

/* Header actions */
.language { display: flex; border: 1px solid var(--line); border-radius: var(--radius-md); padding: 3px; gap: 2px; }
.language button { min-height: 30px; padding: 3px 8px; border: 0; background: none; font: var(--fs-sm) var(--mono); color: var(--text-muted); }
.language button[aria-pressed=true] { background: var(--surface-selected); color: var(--text); }
.focus-button { background: transparent; font-size: var(--fs-md); min-height: 38px; }
.theme-toggle { background: transparent; font-size: var(--fs-md); min-height: 38px; }

/* Segmented control (one choice of 2–4). Use .segments + data-* + aria-pressed. */
.segments {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  padding: 3px;
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  border-radius: 10px;
  gap: 2px;
}
.segments button {
  min-height: var(--control-h-sm);
  background: transparent;
  border: 0;
  color: var(--text-muted);
  border-radius: 7px;
  font-size: var(--fs-md);
  padding: 6px 2px;
}
.segments button[aria-pressed=true] { background: var(--surface-selected); color: var(--accent-text); }
.segments-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.segments-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
/* Warm variant for boundary/condition choices */
.boundary button[aria-pressed=true] { background: var(--surface-selected-warm); color: var(--selected-warm-text); }
/* Compact segmented control in a stage header */
.view-toggle { grid-template-columns: repeat(2, auto); padding: 2px; margin-left: auto; margin-right: 10px; }
.view-toggle button { min-height: 28px; padding: 3px 12px; font-size: var(--fs-sm); }

/* Checkbox (tool toggles) */
.check { display: inline-flex; align-items: center; gap: 6px; font-size: var(--fs-md); cursor: pointer; min-height: 26px; white-space: nowrap; }
.check input { accent-color: var(--accent); width: 14px; height: 14px; margin: 0; }

/* Switch (on/off setting). <label class="switch"><input type="checkbox" role="switch"><span>Label</span></label> */
.switch { display: inline-flex; align-items: center; gap: 8px; font-size: var(--fs-md); cursor: pointer; }
.switch input {
  appearance: none;
  width: 34px; height: 20px;
  margin: 0;
  border-radius: var(--radius-pill);
  background: var(--track);
  position: relative;
  transition: background var(--dur);
  cursor: pointer;
}
.switch input::after {
  content: "";
  position: absolute;
  top: 3px; left: 3px;
  width: 14px; height: 14px;
  border-radius: 50%;
  background: var(--surface);
  transition: transform var(--dur) var(--ease);
}
.switch input:checked { background: var(--accent); }
.switch input:checked::after { transform: translateX(14px); }

/* Select */
select, .select {
  background: var(--surface-input);
  border: 1px solid var(--line);
  border-radius: 8px;
  color: var(--text);
  padding: 7px 5px;
  min-height: 38px;
}

/* Number input. In panels it is the value display itself (.value-edit). */
.number-input {
  width: 80px;
  min-width: 0;
  flex: none;
  padding: 5px 6px;
  min-height: 34px;
  border: 1px solid var(--line-strong);
  border-radius: 7px;
  background: var(--surface-input);
  color: var(--text);
  font: var(--fs-md) var(--mono);
}
.number-input:invalid { border-color: var(--warn); }

/* Value + unit shown above a slider and editable in place: <span class="value-edit"><input class="number-input" style="--w:5"><span class="unit">cm</span></span> */
.value-edit { display: inline-flex; align-items: baseline; gap: 4px; font: var(--fs-md) var(--mono); color: var(--accent); flex: none; }
.value-edit .number-input {
  width: calc(var(--w, 5) * 1ch + 14px);
  min-height: 28px;
  padding: 2px 6px;
  border: 1px solid var(--accent-line);
  border-radius: var(--radius-sm);
  background: var(--surface-input);
  color: inherit;
  text-align: right;
  font: inherit;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  appearance: textfield;
  cursor: text;
  transition: border-color var(--dur), background var(--dur);
}
.value-edit .number-input:hover { border-color: var(--accent-line-strong); }
.value-edit .number-input:focus { background: var(--surface-input); border-color: var(--accent); }
.value-edit .number-input::-webkit-inner-spin-button,
.value-edit .number-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.value-edit .unit { color: var(--text-muted); font-size: var(--fs-sm); }
.value-edit .unit:empty { display: none; }

/* Slider (slider-1 = default). Value and unit sit above the slider in .field-head, never beside it.
   Variants: .probe-range (probe 1), .probe2 .probe-range (probe 2). Add .slider-2, .slider-3 … as needed. */
input[type=range] {
  width: 100%;
  accent-color: var(--accent);
  cursor: pointer;
  margin: 0;
  display: block;
  appearance: none;
  -webkit-appearance: none;
  background: transparent;
  height: 20px;
}
input[type=range]::-webkit-slider-runnable-track { height: 3px; background: var(--track); border-radius: 9px; }
input[type=range]::-webkit-slider-thumb {
  appearance: none;
  -webkit-appearance: none;
  height: 15px; width: 15px;
  margin-top: -6px;
  background: var(--accent);
  border: 3px solid var(--thumb-ring);
  border-radius: 50%;
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 50%, transparent);
}
input[type=range]::-moz-range-track { height: 3px; background: var(--track); border-radius: 9px; }
input[type=range]::-moz-range-progress { height: 3px; background: var(--accent); }
input[type=range]::-moz-range-thumb { height: 11px; width: 11px; background: var(--accent); border: 2px solid var(--thumb-ring); border-radius: 50%; }
.probe-range { width: 100%; margin-top: 8px !important; accent-color: var(--probe-1) !important; }
.probe-range::-webkit-slider-thumb { background: var(--probe-1) !important; box-shadow: 0 0 0 1px color-mix(in srgb, var(--probe-1) 50%, transparent) !important; }
.probe2 .probe-range { accent-color: var(--probe-2) !important; }
.probe2 .probe-range::-webkit-slider-thumb { background: var(--probe-2) !important; box-shadow: 0 0 0 1px color-mix(in srgb, var(--probe-2) 50%, transparent) !important; }

/* Callouts: info / tip / warning / error. Always start with a word, not only a colour. */
.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--info);
  background: var(--info-soft);
  border-radius: 0 8px 8px 0;
  padding: 9px 12px;
  font-size: var(--fs-md);
  line-height: var(--lh-caption);
  margin: 10px 0;
}
.callout > b:first-child { margin-right: 6px; }
.callout.tip { border-left-color: var(--accent); background: var(--accent-soft); }
.callout.warning { border-left-color: var(--warn); background: var(--warn-soft); }
.callout.error { border-left-color: var(--danger); background: var(--danger-soft); }
.callout.success { border-left-color: var(--success); background: var(--success-soft); }
/* "해 보기" inside study topics */
.try { background: var(--accent-soft); border-left: 3px solid var(--accent); padding: 9px 12px !important; border-radius: 0 8px 8px 0; }
.try b { color: var(--accent); margin-right: 6px; }

/* Colour swatch beside a heading or legend entry: <span class="swatch" style="color:var(--phys-wave-1)"></span>.
   .dashed draws the line style used for the same curve, so colour is never the only cue. */
.swatch {
  display: inline-block;
  width: 18px;
  height: 0;
  border-top: 3px solid currentColor;
  border-radius: 2px;
  vertical-align: middle;
  margin-right: 7px;
}
.swatch.dashed { border-top-style: dashed; }

/* Badge / chip */
.badge { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px; border-radius: var(--radius-pill); border: 1px solid var(--line); font-size: var(--fs-sm); color: var(--text-muted); }

/* Tooltip: <span data-tooltip="text">. Use for icon-only buttons on pointer devices; keep aria-label too. */
[data-tooltip] { position: relative; }
[data-tooltip]:hover::after,
[data-tooltip]:focus-visible::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  left: 50%;
  transform: translateX(-50%);
  white-space: nowrap;
  padding: 4px 8px;
  border-radius: 6px;
  background: var(--toast-bg);
  color: var(--toast-text);
  font-size: var(--fs-sm);
  z-index: var(--z-tooltip);
  pointer-events: none;
}

/* Dialogs (모델 · 조작법, 공부하기) */
dialog {
  color: var(--text);
  background: var(--surface-dialog);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  width: min(var(--dialog-w), calc(100vw - 32px));
  max-height: 85svh;
  padding: 26px;
  box-shadow: var(--shadow-dialog);
}
dialog::backdrop { background: var(--backdrop); backdrop-filter: blur(4px); }
.dialog-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
dialog h2 { font-size: var(--fs-h2); margin: 0; }
dialog h3 { font-size: var(--fs-prose); color: var(--accent); margin: 22px 0 8px; }
dialog p, dialog li { font-size: var(--fs-prose); color: var(--text-dialog); line-height: var(--lh-prose); }
dialog a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.dialog-wide, #study { width: min(var(--dialog-w-wide), calc(100vw - 32px)); max-height: 90svh; }

/* Study page inside a dialog: lead, chip TOC, topic cards, wide card */
.study-lead { margin: 10px 0 0; }
.study-toc { display: flex; flex-wrap: wrap; gap: 6px; margin: 12px 0 18px; }
.study-toc a { font-size: var(--fs-md); padding: 5px 11px; border: 1px solid var(--line); border-radius: var(--radius-pill); color: var(--text-muted); text-decoration: none !important; }
.study-toc a:hover { color: var(--accent); border-color: var(--accent-line-strong); }
.study-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 440px), 1fr)); gap: 14px; }
.topic { background: var(--surface-card); border: 1px solid var(--line); border-radius: var(--radius-lg); padding: 16px 18px; min-width: 0; scroll-margin-top: 12px; }
.topic h3 { margin: 0 0 8px !important; }
.topic p { margin: 8px 0; }
.topic-wide { grid-column: 1 / -1; }

/* Tables in dialogs */
.help-table-wrap { overflow-x: auto; margin: 12px 0; }
.help-table { width: 100%; border-collapse: collapse; font-size: var(--fs-md); color: var(--text); }
.help-table caption { caption-side: bottom; text-align: left; font-size: var(--fs-sm); color: var(--text-muted); padding-top: 8px; line-height: var(--lh-caption); }
.help-table th, .help-table td { border-bottom: 1px solid var(--line); padding: 7px 8px; text-align: left; }
.help-table th { color: var(--accent); font-weight: 600; font-size: var(--fs-sm); }
.help-table td:first-child { font-family: var(--mono); }

/* Toast: short status after an action (role=status, aria-live=polite) */
.toast {
  position: fixed;
  left: 50%;
  bottom: 20px;
  transform: translate(-50%, 15px);
  background: var(--toast-bg);
  color: var(--toast-text);
  border: 1px solid var(--toast-line);
  border-radius: 10px;
  padding: 10px 16px;
  font-size: var(--fs-md);
  z-index: var(--z-toast);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-slow), transform var(--dur-slow);
  max-width: 90vw;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }


/* ==========================================================================
   ⑤ SIMULATION CONTROLS
   ========================================================================== */

/* Stage: status bar · canvas · transport · live readouts */
.stage-card { background: var(--surface-stage); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.stage-top {
  min-height: 49px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 10px 18px;
  border-bottom: 1px solid var(--line-soft);
}
.status { display: flex; align-items: center; gap: 8px; font-size: var(--fs-md); }
/* Running/paused/idle are shown by dot colour AND by the status text. */
.status-dot { width: 6px; height: 6px; background: var(--state-running); border-radius: 50%; box-shadow: 0 0 9px color-mix(in srgb, var(--accent) 20%, transparent); }
.is-paused .status-dot { background: var(--state-paused); box-shadow: none; }
.stage-scale { color: var(--text-muted); font: var(--fs-xs) var(--mono); text-align: right; }

/* Canvas: fills the wrap; the drawing code resizes the backing store with devicePixelRatio ≤ 2. */
.canvas-wrap { position: relative; height: var(--stage-h); min-width: 0; overflow: hidden; }
.canvas-wrap canvas, .canvas-wrap svg { display: block; width: 100%; height: 100%; touch-action: pan-y; }
.canvas-wrap.dragging canvas { touch-action: none; cursor: grabbing; }
.canvas-wrap:fullscreen { height: 100vh; background: var(--viz-bg); }
.canvas-hint { position: absolute; left: 20px; bottom: 10px; font-size: var(--fs-sm); color: var(--text-muted); pointer-events: none; max-width: 80%; margin: 0; }

/* Loading / error overlays inside .canvas-wrap */
.sim-overlay {
  position: absolute;
  inset: 0;
  z-index: var(--z-canvas-overlay);
  display: grid;
  place-content: center;
  gap: 8px;
  text-align: center;
  padding: 24px;
  background: color-mix(in srgb, var(--viz-bg) 88%, transparent);
  color: var(--text);
  font-size: var(--fs-prose);
}
.sim-overlay.is-error { color: var(--danger); }
.sim-overlay .spinner { width: 22px; height: 22px; margin: 0 auto; border: 2px solid var(--line-strong); border-right-color: var(--accent); border-radius: 50%; animation: sim-spin .8s linear infinite; }

/* Transport: ▶/⏸ · step · t · speed (0.25×/0.5×/1×/2× + number) · clear · reset all */
.transport { display: flex; align-items: center; gap: 8px; border-top: 1px solid var(--line-soft); padding: 12px 16px; }
.play { min-width: 100px; }
.time-readout { display: flex; align-items: baseline; gap: 8px; margin-left: 7px; font: var(--fs-md) var(--mono); color: var(--text-muted); white-space: nowrap; }
.time-readout output { color: var(--text); }
.transport-spacer { flex: 1; }
.speed { display: flex; align-items: center; gap: 6px; color: var(--text-muted); font-size: var(--fs-sm); flex-wrap: wrap; }
.speed select { background: var(--surface-input); border: 1px solid var(--line); border-radius: 8px; color: var(--text); padding: 7px 5px; min-height: 38px; }
.speed .number-input { width: 60px; }
.clear-label { font-size: var(--fs-md); }

/* Live readouts: label (+ inline formula) / value + unit. Cells reflow; hidden cells leave no gap. */
.metrics { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); border-top: 1px solid var(--line); }
.metrics dl { margin: 0; }
.metric { padding: 13px 18px; min-width: 0; }
.metrics .metric { box-shadow: 1px 0 0 var(--line), 0 1px 0 var(--line); }
.metric dt { color: var(--text-muted); font-size: var(--fs-sm); margin-bottom: 4px; display: flex; align-items: center; gap: 5px; flex-wrap: wrap; min-height: 22px; }
.metric dd { font: var(--fs-metric) var(--mono); letter-spacing: var(--tracking-metric); margin: 0; color: var(--text-strong); }
.metric dd small { font: var(--fs-sm) var(--sans); color: var(--text-muted); margin-left: 3px; }
/* Short qualitative note under a readout value, e.g. "보강 간섭" */
.metric-note {
  display: block;
  font: var(--fs-sm) var(--sans);
  letter-spacing: 0;
  color: var(--text-muted);
  margin-top: 2px;
}
.probe1-metric dd { color: var(--probe-1) !important; }
.probe2-metric dd { color: var(--probe-2) !important; }

/* Instruments: tool toggles, probe positions + y(t) trace, reference line, stopwatch */
.instruments { margin-top: 14px; border: 1px solid var(--line); border-radius: var(--radius-lg); background: var(--surface-instruments); overflow: hidden; }
.tools-row { display: flex; align-items: center; flex-wrap: wrap; gap: 7px 16px; padding: 12px 16px; }
.tools-title { font-size: var(--fs-sm); color: var(--text-muted); margin-right: auto; }
.probe-panel { border-top: 1px solid var(--line-soft); padding: 10px 16px; display: grid; grid-template-columns: 185px minmax(0, 1fr); gap: 18px; align-items: center; }
.probe-label { color: var(--probe-1); font-size: var(--fs-sm); display: flex; justify-content: space-between; gap: 8px; align-items: center; }
.probe-label label { color: var(--probe-1); }
.probe-label .value-edit { color: var(--probe-1); }
.probe-label .value-edit .number-input { border-color: var(--probe-1-line); }
.probe-field + .probe-field { margin-top: 10px; }
.probe2 .probe-label label, .probe2 .value-edit { color: var(--probe-2); }
.probe2 .value-edit .number-input { border-color: var(--probe-2-line); }
.trace { height: 108px; position: relative; border-left: 1px solid var(--line); padding-left: 12px; min-width: 0; }
.trace canvas { width: 100%; height: 100%; display: block; }
.trace-label { position: absolute; top: 0; right: 0; color: var(--text-muted); font: var(--fs-2xs) var(--mono); }
.tool-extra { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: center; padding: 10px 16px; border-top: 1px solid var(--line-soft); }
.ref-field { display: flex; align-items: center; gap: 12px; width: min(420px, 100%); font-size: var(--fs-md); }
.ref-field label { white-space: nowrap; }
.ref-field input[type=range] { flex: 1; min-width: 80px; accent-color: var(--probe-1); }
.ref-field .value-edit { color: var(--probe-1); }
.ref-field .value-edit .number-input { border-color: var(--probe-1-line); }
.stopwatch { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; }
.stopwatch output { color: var(--probe-1); font: var(--fs-lg) var(--mono); min-width: 66px; }
.stopwatch button { min-height: var(--control-h-sm); font-size: var(--fs-sm); padding: 5px 9px; }

/* Control panel (sidebar): numbered sections 01, 02 … */
.controls { border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); overflow: hidden; }
.control-section { padding: 10px 16px 11px; }
.control-section + .control-section { border-top: 1px solid var(--line); }
.section-heading { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.section-heading h2 { font-size: var(--fs-prose); font-weight: 600; margin: 0; }
.section-number { font: var(--fs-xs) var(--mono); color: var(--text-faint); }
/* Field: label + editable value on one line, slider below */
.field { margin-top: 10px; }
.field-head { display: flex; justify-content: space-between; gap: 10px; align-items: center; margin-bottom: 4px; }
.field-head label { font-size: var(--fs-md); }
.field-head output { font: var(--fs-md) var(--mono); color: var(--accent); font-variant-numeric: tabular-nums; }
.field-limits { display: flex; justify-content: space-between; color: var(--text-faint); font: var(--fs-xs) var(--mono); margin-top: 4px; }
.field-caption { font-size: var(--fs-sm); color: var(--text-muted); margin: 7px 0 0; line-height: var(--lh-caption); }
.manual-field { padding: 10px 12px; background: var(--surface-tint); border-radius: 10px; margin-top: 13px; }
.manual-field .field-head { margin-bottom: 5px; }
.pulse-button { width: 100%; margin-top: 10px; }
/* Start block: initial-condition button + start button + hint */
.start-block { grid-column: 1 / -1; margin-top: 10px; padding-top: 10px; border-top: 1px dashed var(--line); }
.start-row { display: flex; flex-wrap: wrap; gap: 8px; }
.start-row button { flex: 1 1 120px; padding: 8px 6px; }
.standing-toggle { justify-content: center; }
.start-block .field-caption { margin: 8px 0 0; }
.start-button.quiet { background: transparent; color: var(--text); border-color: var(--line); font-weight: 500; }

/* Drawer + bottom control bar for phones (optional pattern; 018 stacks the panel instead) */
.sim-drawer { position: fixed; inset: auto 0 0 0; max-height: 75svh; overflow-y: auto; z-index: var(--z-drawer); background: var(--surface); border-top: 1px solid var(--line); border-radius: var(--radius) var(--radius) 0 0; box-shadow: var(--shadow-dialog); transform: translateY(100%); transition: transform var(--dur-slow) var(--ease); }
.sim-drawer.open { transform: none; }
.bottom-bar { position: sticky; bottom: 0; z-index: var(--z-sticky); display: flex; gap: 8px; align-items: center; padding: 8px 12px; background: var(--surface); border-top: 1px solid var(--line); }


/* ==========================================================================
   ⑥ GRAPH & PHYSICS DRAWING RULES
   Colours and sizes live in tokens (①). Canvas/SVG code reads them:
     const cs=getComputedStyle(document.documentElement);
     const color=cs.getPropertyValue('--viz-string').trim();
     const w=parseFloat(cs.getPropertyValue('--plot-curve-width'));
   Re-read after a theme change. See style-system.md for the full standard.
   ========================================================================== */

/* Labels inside a drawing are HTML, not canvas text, so symbols are typeset by KaTeX.
   <div class="viz-labels" aria-hidden="true"> sits inside .canvas-wrap; drawing code sets left/top in px. */
.viz-labels { position: absolute; inset: 0; pointer-events: none; z-index: var(--z-canvas-overlay); }
/* Name + symbol at the left of a stacked graph ("파동 1 / y₁ →") */
.strip-label {
  position: absolute;
  transform: translateY(-50%);
  display: flex;
  flex-direction: column;
  gap: 1px;
  font-size: var(--fs-md);
  font-weight: 600;
  line-height: 1.25;
}
.strip-sym { display: flex; align-items: center; gap: 4px; font-weight: 400; }
.dir-arrow { font: 600 var(--fs-md) var(--sans); }
/* Direct label at the end of a curve (overlaid curves must not rely on colour alone) */
.curve-tag { position: absolute; transform: translateY(-50%); font-size: var(--fs-md); font-weight: 600; white-space: nowrap; }
/* Legend box inside the plot */
.viz-legend {
  position: absolute;
  display: grid;
  gap: 3px;
  padding: 7px 10px;
  border: 1px solid var(--line);
  border-radius: 8px;
  background: color-mix(in srgb, var(--viz-bg) 88%, transparent);
  font-size: var(--fs-md);
  color: var(--text);
}
.viz-legend > div { display: flex; align-items: center; gap: 4px; }
.viz-labels .wave1 { color: var(--phys-wave-1); }
.viz-labels .wave2 { color: var(--phys-wave-2); }
.viz-labels .sum { color: var(--phys-wave-sum); }
.swatch.thick { border-top-width: 4px; }
.swatch.dotted { border-top: 2px dotted currentColor; }

/* SVG drawings can use the same tokens directly. */
.viz-axis { stroke: var(--viz-axis-strong); stroke-width: 1.5; fill: none; }
.viz-grid { stroke: var(--viz-grid); stroke-width: .65; }
.viz-tick-label { fill: var(--viz-label); font: var(--fs-xs) var(--mono); }
.viz-curve { stroke: var(--viz-string); stroke-width: 2.4; fill: none; stroke-linejoin: round; }
.viz-equilibrium { stroke: var(--viz-equilibrium); stroke-dasharray: 4 6; }
.vec-velocity { stroke: var(--phys-velocity); fill: var(--phys-velocity); stroke-width: 2.5; }
.vec-acceleration { stroke: var(--phys-acceleration); fill: var(--phys-acceleration); stroke-width: 2.5; stroke-dasharray: 6 4; }
.vec-force { stroke: var(--phys-force); fill: var(--phys-force); stroke-width: 3; }
.viz-trajectory { stroke: var(--viz-trajectory); stroke-dasharray: 2 5; fill: none; }
.viz-ground { stroke: var(--viz-ground); stroke-width: 3; }


/* ==========================================================================
   ⑦ RESPONSIVE · ACCESSIBILITY · MOTION · PRINT
   ========================================================================== */

/* Panel follows the observation column's height and scrolls only if it must (desktop). */
@media (min-width: 801px) {
  .workspace { align-items: stretch; }
  .controls { height: 0; min-height: 100%; display: flex; flex-direction: column; overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--line) transparent; }
  .controls > * { flex: none; }
}

@media (min-width: 1500px) {
  .workspace { grid-template-columns: minmax(0, 1fr) var(--panel-w-wide); }
  .canvas-wrap { height: var(--stage-h-wide); }
}

@media (max-width: 1050px) {
  main { padding: 20px 20px 0; }
  .workspace { grid-template-columns: minmax(0, 1fr) var(--panel-w-narrow); gap: 12px; }
  .control-section { padding: 15px; }
  .metric { padding: 12px; }
  .metric dd { font-size: 17px; }
  .transport { padding: 10px; gap: 5px; flex-wrap: wrap; }
  .time-readout { gap: 4px; font-size: var(--fs-sm); }
  .clear-label { display: none; }
  .tools-row { gap: 6px 11px; }
  .probe-panel { grid-template-columns: 165px minmax(0, 1fr); }
  .top-actions { gap: 6px; }
}

@media (max-width: 800px) {
  .workspace { grid-template-columns: 1fr; }
  .controls { display: grid; grid-template-columns: 1fr 1fr; }
  .control-section + .control-section { border-top: 0; border-left: 1px solid var(--line); }
  .control-section:last-of-type { border-top: 1px solid var(--line); }
  .intro-description { max-width: 420px; }
  .canvas-wrap { height: clamp(290px, 47vh, 470px); }
  .stage-scale { font-size: var(--fs-xs); }
  .brandbar { padding: 0 20px; }
  .collection span { display: none; }
  .focus-button span, .theme-toggle span { display: none; }
  .site-footer { padding: 16px 20px; flex-wrap: wrap; }
  .controls .field:first-of-type { margin-top: 10px; }
  .sim-nav { flex-direction: column; }
}

@media (max-width: 480px) {
  :root { --fs-2xs: 11px; --fs-xs: 12px; --fs-sm: 12px; --fs-md: 13px; }
  /* Stage header: status and view toggle on one line, scale text on its own line */
  .stage-top { flex-wrap: wrap; row-gap: 6px; }
  .status, .segments button { white-space: nowrap; }
  .stage-scale { order: 3; flex-basis: 100%; max-width: none; text-align: left; }
  main { padding: 17px 12px 0; }
  .brandbar { height: 48px; padding: 0 14px; }
  .brand { font-size: var(--fs-sm); gap: 7px; }
  .brand svg { width: 20px; }
  .brand span { font-size: 14px; }
  .intro { gap: 8px; margin-bottom: 16px; align-items: flex-start; }
  h1 { font-size: 26px; }
  .eyebrow { font-size: var(--fs-2xs); letter-spacing: .11em; }
  .intro-description { font-size: var(--fs-md); max-width: 240px; margin-top: 7px; }
  .top-actions { flex-direction: column-reverse; gap: 6px; align-items: flex-end; }
  .focus-button, .theme-toggle { min-height: 30px; padding: 5px 9px; }
  .language { padding: 2px; }
  .language button { min-height: 26px; padding: 2px 6px; }
  .stage-top { padding: 10px 12px; }
  .canvas-wrap { height: 290px; }
  .canvas-hint { left: 12px; font-size: var(--fs-xs); max-width: 90%; }
  .transport { flex-wrap: wrap; gap: 6px; padding: 10px; }
  .play { min-width: 90px; }
  .transport .time-readout { margin-left: auto; }
  .transport-spacer { display: none; }
  .speed { margin-left: auto; }
  .metric { padding: 10px; }
  .metric dt { font-size: var(--fs-xs); }
  .metric dd { font-size: 16px; }
  .metric dd small { font-size: var(--fs-2xs); }
  .tools-row { padding: 10px 12px; gap: 4px 13px; }
  .tools-title { width: 100%; margin-bottom: 4px; }
  .probe-panel { grid-template-columns: 1fr; padding: 10px 12px; gap: 10px; }
  .trace { border-left: 0; padding-left: 0; }
  .controls { display: block; }
  .control-section + .control-section { border-left: 0; border-top: 1px solid var(--line); }
  .control-section { padding: 17px; }
  .field { margin-top: 18px; }
  .field-head label, .segments:not(.view-toggle) button { font-size: var(--fs-prose); }
  .site-footer { padding: 15px 14px; font-size: var(--fs-xs); }
  .footer-links { gap: 10px; }
  .stage-scale { max-width: 130px; font-size: var(--fs-2xs); }
  body.focus .canvas-wrap { height: 48svh; min-height: 280px; }
  .tool-extra { padding: 10px 12px; }
  .number-input { width: 84px; }
  dialog { padding: 20px; }
}

/* Short desktop screens (≤920 px tall, e.g. a 1440×900 laptop): the workspace must fit without scrolling.
   Hide the unit eyebrow and put the one-line goal beside the title. */
@media (min-width: 801px) and (max-height: 920px) {
  main { padding-top: 12px; }
  .intro { margin-bottom: 12px; }
  .intro > div:first-child { display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 16px; }
  .eyebrow { display: none; }
  h1 { font-size: 26px; }
  .intro-description { margin: 0; }
}

/* Touch: every interactive target reaches 44px. */
@media (pointer: coarse) {
  button, .check, .language button, .focus-button, .theme-toggle, .segments button, .stopwatch button, .footer-links button { min-height: var(--touch-target); }
  .collection { min-width: var(--touch-target); min-height: var(--touch-target); justify-content: center; }
  input[type=range] { height: 36px; }
  .number-input { min-height: var(--touch-target); }
  .value-edit .number-input { min-height: 40px; }
}

/* Reduced motion: UI transitions off. Simulation time stays user-controlled (pause/step). */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; scroll-behavior: auto !important; }
}

/* Print / capture: keep the stage, readouts and explanations; drop chrome and controls. */
@media print {
  .brandbar, .controls, .transport, .top-actions, .instruments, .site-footer, .sim-nav, .toast, .skip { display: none; }
  .workspace { display: block; }
  body { background: #fff; }
  canvas { max-width: 100%; }
}
