:root {
    --paper: #f6f3ec;
    --paper-2: #efeadf;
    --ink: #1c1a15;
    --ink-2: #4a463d;
    --ink-3: #8a8478;
    --rule: #d9d3c2;
    --accent: #c8341a;
    --accent-2: #9a2818;
    --scope-bg: #0a1410;
    --scope-grid: #1a3028;
    --scope-grid-strong: #244438;
    --phosphor: #4dffb0;
    --phosphor-dim: rgba(77, 255, 176, 0.25);
    --warn: #d68a1a;
    --bad: #c8341a;
}

* { box-sizing: border-box; }

html, body {
    margin: 0;
    padding: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: 'Inter', -apple-system, sans-serif;
    font-size: 15px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
}

body {
    background-image:
        radial-gradient(circle at 20% 10%, rgba(200, 52, 26, 0.04) 0%, transparent 50%),
        radial-gradient(circle at 80% 80%, rgba(200, 52, 26, 0.03) 0%, transparent 50%);
}

.serif { font-family: 'Fraunces', Georgia, serif; }

.wrap {
    max-width: 1320px;
    margin: 0 auto;
    padding: 16px 16px 40px;
}

/* Header */
.masthead {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    border-bottom: 1px solid var(--rule);
    padding-bottom: 10px;
    margin-bottom: 16px;
    flex-wrap: wrap;
    gap: 8px;
}
.masthead h1 {
    font-family: 'Fraunces', Georgia, serif;
    font-weight: 500;
    font-size: clamp(22px, 4vw, 40px);
    margin: 0;
    letter-spacing: -0.02em;
    line-height: 1.1;
}
.masthead h1 em {
    font-style: italic;
    font-weight: 400;
    color: var(--accent);
}
/* "Show Introduction" text link on the right side of the masthead. Runs the
   guided intro on demand once the localStorage flag has suppressed the
   auto-run. Styled as a quiet link, not a button, so it reads as "available
   if you want it" rather than "click me." */
.masthead-link {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 500;
    color: var(--ink-3);
    background: transparent;
    border: none;
    padding: 6px 8px;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 3px;
    text-decoration-color: var(--rule);
    transition: color 0.15s, text-decoration-color 0.15s;
}
.masthead-link:hover {
    color: var(--accent);
    text-decoration-color: var(--accent);
}
.masthead-link:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
    border-radius: 3px;
}
/* The link group is meaningless while the intro is already on-screen.
   Hide the whole container so links and separator disappear together;
   visibility (not display) preserves the masthead's layout. */
body.intro-active .masthead-links { display: none }

/* Link group on the right side of the masthead. Flex row so the separator
   sits inline with both buttons and shares baseline alignment. */
.masthead-links {
    display: flex;
    align-items: center;
    gap: 2px;
}
.masthead-sep {
    color: var(--ink-3);
    font-size: 13px;
    user-select: none;
    padding: 0 2px;
    opacity: 0.6;
}

/* ===== Quick Reference modal =====
   A printed-card style reference for waveforms, properties, coupling,
   triggers, and measurements. Reuses .modal / .modal-backdrop chrome but
   adds typographic structure for sections and subsections plus tiny
   phosphor-on-dark waveform thumbnails that mirror what students see on
   the scope itself. Targeted at 10th-grade electronics students. */
.modal.quickref {
    max-width: 720px;
}
.quickref-section {
    padding: 14px 0 2px;
    border-bottom: 1px solid var(--rule);
}
.quickref-section:last-child {
    border-bottom: none;
    padding-bottom: 8px;
}
.quickref-section:first-child {
    padding-top: 2px;
}
.quickref-section-title {
    font-family: 'Fraunces', Georgia, serif;
    font-size: 19px;
    font-weight: 500;
    color: var(--ink);
    margin: 0 0 4px;
    letter-spacing: -0.01em;
}
.quickref-section-title em {
    font-style: italic;
    font-weight: 400;
    color: var(--accent);
}
.quickref-section-sub {
    font-size: 13px;
    color: var(--ink-3);
    margin: 0 0 12px;
    line-height: 1.5;
}
/* Subsection inside a section. Smaller than section title, lighter weight,
   used to divide content within a single topic (e.g. Measurements into
   Automatic vs Cursor). Top margin balances against the section title; no
   border-bottom (the parent section already has one). */
.quickref-subsection-title {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--ink-2);
    margin: 14px 0 6px;
}
.quickref-subsection-title:first-of-type {
    margin-top: 4px;
}
.quickref-subsection-sub {
    font-size: 13px;
    color: var(--ink-3);
    margin: 0 0 10px;
    line-height: 1.5;
}
/* Third-level grouping inside a subsection. Used inside Measurements to
   bucket the 17 readouts into Voltage / Time / Pulse shape / Signal quality.
   Smaller and lighter than subsection title; left-aligned without extra
   border so it reads as an inline category label rather than a divider. */
.quickref-group-title {
    font-family: 'Inter', sans-serif;
    font-size: 12px;
    font-weight: 600;
    color: var(--accent);
    letter-spacing: 0.04em;
    margin: 10px 0 4px;
    text-transform: none;
}
.quickref-group-title:first-of-type {
    margin-top: 2px;
}
/* Definition list inside each section. Term in bold ink, definition in
   slightly muted ink-2 for hierarchy without losing readability. */
.quickref-dl {
    margin: 0;
    display: grid;
    grid-template-columns: minmax(120px, max-content) 1fr;
    column-gap: 18px;
    row-gap: 8px;
    padding-bottom: 12px;
}
.quickref-dl dt {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
    line-height: 1.45;
}
.quickref-dl dd {
    margin: 0;
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.5;
}
.quickref-dl dd code,
.quickref-dl dt code {
    font-family: 'JetBrains Mono', monospace;
    font-size: 12.5px;
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 1px 5px;
    color: var(--ink);
    white-space: nowrap;
}
/* FORCE chip — mirrors the amber FORCE button on the trigger panel so a
   student looking at the reference instantly recognizes which control it
   refers to. Same fill, same dark text, no border, bold weight. */
.quickref-dl dt code.code-force {
    background: #ffd966;
    color: #6b4a00;
    border: none;
    font-weight: 700;
    letter-spacing: 0.04em;
}
/* Waveforms section uses a slightly different grid: a small phosphor
   thumbnail on the left, then term, then definition. The thumbnail mirrors
   the scope display so a student can map name to shape at a glance. */
.quickref-waves {
    margin: 0;
    display: grid;
    grid-template-columns: auto minmax(110px, max-content) 1fr;
    column-gap: 14px;
    row-gap: 10px;
    align-items: center;
    padding-bottom: 12px;
}
.quickref-waves .wave-name {
    font-weight: 600;
    color: var(--ink);
    font-size: 14px;
}
.quickref-waves .wave-desc {
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.5;
}
/* Waveform thumbnails: miniature scope screens. Dark phosphor-on-graticule
   so the reference card shows each shape exactly the way the instrument
   does. The center crosshair is faked with two background gradients — no
   extra SVG elements needed. */
.quickref-thumb {
    width: 96px;
    height: 40px;
    display: block;
    flex-shrink: 0;
    background-color: var(--scope-bg);
    background-image:
        linear-gradient(to right, transparent calc(50% - 0.5px),
            var(--scope-grid-strong) calc(50% - 0.5px),
            var(--scope-grid-strong) calc(50% + 0.5px), transparent calc(50% + 0.5px)),
        linear-gradient(to bottom, transparent calc(50% - 0.5px),
            var(--scope-grid-strong) calc(50% - 0.5px),
            var(--scope-grid-strong) calc(50% + 0.5px), transparent calc(50% + 0.5px));
    border: 1px solid #3a5a4e;
    border-radius: 4px;
}
.quickref-thumb path,
.quickref-thumb polyline {
    fill: none;
    stroke: var(--phosphor);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    filter: drop-shadow(0 0 2.5px rgba(77, 255, 176, 0.55));
}
/* "Real-world example" tag inside a waveform description. Compact, italic,
   set slightly muted so it reads as a secondary note rather than a second
   sentence. The label "Example:" is the visual anchor. */
.wave-example {
    display: block;
    margin-top: 3px;
    font-size: 12.5px;
    color: var(--ink-3);
    line-height: 1.4;
}
.wave-example b {
    color: var(--ink-2);
    font-weight: 600;
}
/* "Use this when" hint inside a dd. Distinct from the definition above it
   so a student can scan for the practical answer without re-reading the
   formal definition. Small accent-colored label, normal-weight body. */
.use-when {
    display: block;
    margin-top: 4px;
    font-size: 12.5px;
    color: var(--ink-3);
    line-height: 1.4;
}
.use-when b {
    color: var(--accent);
    font-weight: 600;
    margin-right: 4px;
}
/* Callout boxes for Pro Tip and Common Problem. Light-paper card with no
   border accent. The uppercase colored label is the visual anchor; the
   accent color comes from the label itself, not a border bar. */
.quickref-callout {
    margin: 10px 0 4px;
    padding: 8px 12px;
    background: var(--paper-2);
    border-radius: 3px;
    font-size: 13px;
    color: var(--ink-2);
    line-height: 1.5;
}
.quickref-callout .callout-label {
    display: inline-block;
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--accent);
    margin-right: 6px;
}
.quickref-callout.warn .callout-label {
    color: #8a6500;
}
/* ===== Annotated diagrams =====
   Larger figures that label concepts on a trace: amplitude, Vpp, period,
   coupling, trigger level, rise/fall, overshoot, cursors. Each figure is
   drawn as a miniature scope screen — dark bezel-green background, faint
   graticule (shared <pattern id="qa-grid-pattern">, defined once in the
   first diagram), phosphor trace, and the same marker colors the live
   canvas uses (green 0V flag, amber trigger, magenta/cyan cursors) — so
   students map the reference card directly onto the instrument. */
.qa-diagram {
    display: block;
    width: 100%;
    max-width: 360px;
    height: auto;
    margin: 8px auto 14px;
}
/* The screen itself: background plate + graticule fill. */
.qa-diagram .qa-screen {
    fill: var(--scope-bg);
    stroke: #3a5a4e;
    stroke-width: 1;
}
.qa-diagram .qa-gridfill {
    fill: url(#qa-grid-pattern);
}
.qa-diagram .qa-trace {
    fill: none;
    stroke: var(--phosphor);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    filter: drop-shadow(0 0 3px rgba(77, 255, 176, 0.5));
}
/* Dashed horizontal reference (0 V, Vmax, Vmin, 10%/90% levels). */
.qa-diagram .qa-ref {
    fill: none;
    stroke: rgba(255, 255, 255, 0.35);
    stroke-width: 0.8;
    stroke-dasharray: 3 3;
}
/* Solid dimension line connecting two arrowheads, marking amplitude /
   Vpp / period / rise-time spans. */
.qa-diagram .qa-dim {
    fill: none;
    stroke: #c8e8d8;
    stroke-width: 1;
}
.qa-diagram .qa-arrow {
    fill: #c8e8d8;
}
/* Bright marker for trigger crossing or 10%/90% crossings. Same amber the
   screenshot footer uses for derived values. */
.qa-diagram .qa-marker {
    fill: #ffb43c;
    stroke: none;
}
/* Trigger level line: amber dashed, exactly like the live trigger line. */
.qa-diagram .qa-trig-level {
    fill: none;
    stroke: var(--warn);
    stroke-width: 1.2;
    stroke-dasharray: 5 3;
}
/* On-screen flag markers, matching the live canvas: green 0V pentagon on
   the left edge, amber T pentagon on the right edge. Dark text inside. */
.qa-diagram .qa-flag-zero {
    fill: var(--phosphor);
}
.qa-diagram .qa-flag-trig {
    fill: var(--warn);
}
.qa-diagram .qa-flag-text {
    font-family: 'JetBrains Mono', monospace;
    font-size: 7.5px;
    font-weight: 700;
    fill: var(--scope-bg);
}
/* Cursor lines: the exact on-screen neon colors (magenta = time/vertical,
   cyan = voltage/horizontal) — they sit on the dark screen now, so no
   darkening needed. */
.qa-diagram .qa-cursor-t {
    fill: none;
    stroke: #ff6cb8;
    stroke-width: 1.2;
    stroke-dasharray: 4 2;
}
.qa-diagram .qa-cursor-v {
    fill: none;
    stroke: #5ad6ff;
    stroke-width: 1.2;
    stroke-dasharray: 4 2;
}
/* Labels inside the diagrams (they sit on the dark screen). Mono for the
   named quantities (matches the <code> chips in the dl); Inter for the
   faint reference notes. */
.qa-diagram .qa-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 500;
    fill: #c8e8d8;
}
.qa-diagram .qa-label-faint {
    font-family: 'Inter', sans-serif;
    font-size: 9.5px;
    fill: #8a9b94;
}
.qa-diagram .qa-label-trig {
    font-family: 'Inter', sans-serif;
    font-size: 9.5px;
    font-weight: 600;
    fill: #ffb43c;
}
.qa-diagram .qa-label-cursor-t {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 700;
    fill: #ff6cb8;
}
.qa-diagram .qa-label-cursor-v {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 700;
    fill: #5ad6ff;
}
/* Caption + sub-caption under a mini screen (e.g., "DC coupling" /
   "offset visible" beneath each half of a side-by-side comparison).
   These sit on the paper, below the dark panel, so they stay ink. */
.qa-diagram .qa-caption {
    font-family: 'Inter', sans-serif;
    font-size: 11px;
    font-weight: 600;
    fill: var(--ink-2);
}
.qa-diagram .qa-subcaption {
    font-family: 'Inter', sans-serif;
    font-size: 9.5px;
    fill: var(--ink-3);
}

/* Edge-slope mini diagram used inside the Triggers section. Two small
   phosphor-on-dark screens side by side with a label under each, matching
   the waveform thumbnails. */
.quickref-edges {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 18px;
    margin: 6px auto 12px;
    max-width: 320px;
}
.quickref-edge {
    text-align: center;
}
.quickref-edge svg {
    width: 100%;
    max-width: 130px;
    height: 44px;
    display: block;
    margin: 0 auto 4px;
    background: var(--scope-bg);
    border: 1px solid #3a5a4e;
    border-radius: 4px;
}
.quickref-edge svg .edge-trace {
    fill: none;
    stroke: var(--phosphor);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
    filter: drop-shadow(0 0 2.5px rgba(77, 255, 176, 0.55));
}
.quickref-edge svg .edge-marker {
    fill: #ffb43c;
}
.quickref-edge .edge-label {
    font-family: 'Inter', sans-serif;
    font-size: 12px;
    font-weight: 600;
    color: var(--ink-2);
}
/* Collapsible "More measurements" group. The summary is restyled to look
   like a centered secondary button. When opened, the same control reads
   "Hide" and reverses; the dashed rule above separates it visually from
   the "most useful" list above. */
.quickref-details {
    margin: 0 0 14px 0;
    padding-top: 14px;
    text-align: center;
}
.quickref-details > summary {
    list-style: none;
    cursor: pointer;
    display: inline-block;
    font-family: 'Inter', sans-serif;
    font-size: 12px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-2);
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 8px 18px;
    user-select: none;
    transition: background 0.12s ease, color 0.12s ease, border-color 0.12s ease;
}
.quickref-details > summary::-webkit-details-marker {
    display: none;
}
.quickref-details > summary:hover {
    color: var(--ink);
    background: var(--paper-2);
    border-color: var(--accent);
}
/* Once the section is expanded, the trigger goes away. There is no
   collapse-back affordance; the content stays visible for the rest of
   the session, which matches the read-once intent of a reference card. */
.quickref-details[open] > summary {
    display: none;
}
/* Inner content of the details block is left-aligned, even though the
   summary itself is centered. */
.quickref-details > *:not(summary) {
    text-align: left;
}
.quickref-details > .quickref-subsection-sub {
    margin-top: 14px;
}
/* ===== Print: the Quick Reference as a paper handout =====
   Active only while the Quick Reference modal is open (matched via :has),
   so printing the page normally is unaffected. The PRINT button in the
   modal footer calls window.print(); a beforeprint handler expands the
   collapsed "More measurements" section first (CSS can't open <details>).
   The dark mini-screen diagrams print as-is — they're small, and keeping
   them identical to the on-screen instrument is the whole point. */
@media print {
    body:has(#quickref-modal:not([hidden])) {
        background: #fff;
        background-image: none;
    }
    body:has(#quickref-modal:not([hidden])) .masthead,
    body:has(#quickref-modal:not([hidden])) .main-stack,
    body:has(#quickref-modal:not([hidden])) .colophon,
    body:has(#quickref-modal:not([hidden])) .modal-backdrop:not(#quickref-modal) {
        display: none !important;
    }
    body:has(#quickref-modal:not([hidden])) #quickref-modal {
        position: static;
        display: block;
        background: none;
        padding: 0;
        animation: none;
    }
    body:has(#quickref-modal:not([hidden])) .modal.quickref {
        max-width: 100%;
        max-height: none;
        border: none;
        border-radius: 0;
        box-shadow: none;
        display: block;
    }
    body:has(#quickref-modal:not([hidden])) .modal.quickref .modal-body {
        overflow: visible;
        max-height: none;
        padding: 0;
    }
    body:has(#quickref-modal:not([hidden])) .modal.quickref .modal-close,
    body:has(#quickref-modal:not([hidden])) .modal.quickref .modal-footer,
    body:has(#quickref-modal:not([hidden])) .quickref-details > summary {
        display: none !important;
    }
    /* Keep each figure and callout on one page. */
    .qa-diagram, .quickref-edges, .quickref-callout,
    .quickref-thumb, .quickref-dl dt, .quickref-dl dd {
        break-inside: avoid;
    }
    .quickref-section-title {
        break-after: avoid;
    }
}

/* On narrow screens, collapse the two-column DLs into stacked rows so
   nothing wraps awkwardly. */
@media (max-width: 560px) {
    .quickref-dl {
        grid-template-columns: 1fr;
        row-gap: 4px;
    }
    .quickref-dl dt { margin-top: 6px; }
    .quickref-waves {
        grid-template-columns: auto 1fr;
    }
    .quickref-waves .wave-desc {
        grid-column: 1 / -1;
        margin-left: 0;
    }
    .quickref-edges {
        max-width: 100%;
    }
}

/* ===== Function generator steppers — compact horizontal controls matching
   the oscilloscope front-panel aesthetic (light paper, ink, terracotta accent).
   No knobs — pure button + readout + button, fully consistent with scope
   segmented/knob-readout styling. ===== */
.stepper {
    display: grid;
    grid-template-columns: auto 1fr auto;
    gap: 4px;
    align-items: stretch;
}
.step-btn {
    background: var(--paper);
    color: var(--ink);
    border: 1px solid var(--rule);
    border-radius: 3px;
    width: 28px;
    height: 30px;
    padding: 0;
    cursor: pointer;
    font-family: 'JetBrains Mono', monospace;
    font-size: 18px;
    font-weight: 700;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    transition: all 0.12s;
    box-shadow:
        inset 0 1px 0 rgba(255, 255, 255, 0.8),
        inset 0 -1px 0 rgba(0, 0, 0, 0.06);
    user-select: none;
}
.step-btn:hover {
    background: #fff;
    color: var(--accent);
    border-color: var(--accent);
}
.step-btn:active {
    background: var(--paper-2);
    box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
}
.step-btn:disabled,
.step-btn.disabled {
    opacity: 0.3;
    cursor: not-allowed;
    pointer-events: none;
}

/* Readout styled like scope knob-readout and trig-readout: light paper with
   clean border, ink text. Amber tint kept for subtle FG identity while
   staying in the same visual family as the scope. */
.step-readout {
    background: var(--paper);
    border: 1px solid var(--rule);
    color: var(--ink);
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.04em;
    padding: 4px 8px;
    border-radius: 3px;
    text-align: center;
    box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.04);
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    white-space: nowrap;
    overflow: hidden;
}
/* Editable readouts — tappable for direct entry, matches scope editable fields. */
.step-readout.editable {
    cursor: text;
    transition: box-shadow 0.12s, border-color 0.12s;
}
.step-readout.editable:hover {
    border-color: var(--accent);
    box-shadow: 0 0 0 1px rgba(200, 52, 26, 0.15);
}
.step-readout.editable.editing,
.step-readout.editable:focus {
    outline: none;
    border-color: var(--accent);
    caret-color: var(--accent);
    box-shadow:
        inset 0 1px 2px rgba(0, 0, 0, 0.06),
        0 0 0 2px rgba(200, 52, 26, 0.12);
}

/* Waveform button group — styled like scope segmented buttons for consistency
   with the oscilloscope front-panel interface. Light paper theme, terracotta
   accent on active. No knobs anywhere in the function generator. */
.wave-buttons {
    display: grid;
    grid-template-columns: repeat(6, 1fr);
    gap: 2px;
    background: var(--rule);
    border-radius: 4px;
    padding: 2px;
    border: 1px solid var(--rule);
}
.wave-btn {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 6px 4px;
    cursor: pointer;
    transition: all 0.12s;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 3px;
    color: var(--ink-2);
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    min-width: 0;
}
.wave-btn:hover { background: #fff; color: var(--ink); }
.wave-btn.active {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
.wave-btn svg { width: 26px; height: 14px; flex-shrink: 0; }

/* ===== Main layout: scope on left, front panel on right ===== */
.main-stack {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 340px;
    gap: 12px;
    align-items: start;
}
@media (max-width: 1100px) {
    .main-stack { grid-template-columns: 1fr; }
}

/* ===== Scope ===== */
.scope-shell {
    background: var(--scope-bg);
    border-radius: 12px;
    overflow: hidden;
}
.scope-bezel {
    padding: 10px 16px 6px;
    display: flex;
    justify-content: space-between;
    align-items: center;
    font-family: 'JetBrains Mono', monospace;
    font-size: 13px;
    color: #8a9b94;
    flex-wrap: wrap;
    gap: 8px;
    border-bottom: 1px solid #1a3028;
}
/* Scale readouts in the bezel header — V/DIV, TIME/DIV, TRIG LVL.
   Labels in dim grey, values in phosphor green so they read as live
   readouts in the scope's display area, matching real bench-scope bezels. */
.scope-scale-bezel {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    color: #8a9b94;
}
.scope-scale-bezel span b {
    color: var(--phosphor);
    font-weight: 600;
    margin-left: 6px;
}
.scope-status {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
}
.scope-status .pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    color: #8a9b94;
}
.scope-status .pill b {
    color: var(--phosphor);
    font-weight: 600;
}
.scope-status .pill.warn b { color: var(--warn); }
.scope-status .pill.bad b { color: var(--bad); }

canvas#scope {
    display: block;
    width: 100%;
    height: auto;
    background: var(--scope-bg);
}

/* Bottom readout strip — measurement pills only. Collapses to nothing when
   no measurement slots are assigned, since the empty footer would otherwise
   leave dead space below the trace. */
.scope-footer {
    padding: 10px 16px;
    border-top: 1px solid #1a3028;
    display: flex;
    flex-wrap: wrap;
    gap: 8px 18px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 13px;
    color: #8a9b94;
    align-items: center;
    min-height: 20px;
}
.scope-footer:has(#meas-display:empty) {
    display: none;
}
/* Suppress measurement readouts entirely while the guided intro is running.
   The MEASURE/CURSOR buttons live in the front panel (already hidden via
   .intro-active) so the controls are unreachable; this hides any readouts
   that were already populated from a previous session. State is not
   cleared — they reappear naturally once the intro ends. */
body.intro-active .scope-footer { display: none; }
/* Measurement readouts: four fixed columns spaced equally along the bezel
   (slot N always renders in position N, like MEAS 1–4 on a real scope —
   empty slots leave a gap so values never shift sideways). No pill chrome:
   each column is a plain stack of Channel / Name / Value. The channel row
   only appears while CH2 is on (class .two-ch on the container), in the
   channel's trace color at full size; the value inherits the channel color
   too, so a reading is attributable at a glance. */
.scope-footer .meas-info {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    width: 100%;
}
.scope-footer .meas-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    text-align: center;
    min-width: 0;
}
.scope-footer .meas-cell .mc-ch {
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.05em;
}
.scope-footer .meas-cell.c1 .mc-ch { color: var(--phosphor); }
.scope-footer .meas-cell.c2 .mc-ch { color: #ffdd57; }
.scope-footer .meas-cell .mc-name {
    font-size: 12px;
    color: #8a9b94;
}
.scope-footer .meas-cell .mc-value {
    font-size: 14px;
    font-weight: 600;
    color: var(--phosphor);
}
.scope-footer .meas-info.two-ch .meas-cell.c2 .mc-value { color: #ffdd57; }

/* ===== Front-panel (right of scope, vertically stacked sections) ===== */
.front-panel {
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: 10px;
    padding: 0;
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.fp-section {
    padding: 10px 12px 12px;
    border-bottom: 1px solid var(--rule);
    display: flex;
    flex-direction: column;
    gap: 8px;
    min-width: 0;
}
.fp-section[hidden] { display: none; }
.fp-section:last-child { border-bottom: none; }
.fp-section-header {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.16em;
    color: #c8341a;
    text-transform: uppercase;
    font-weight: 700;
    padding-bottom: 4px;
    border-bottom: 1px solid var(--rule);
    margin-bottom: 2px;
}
.fp-section.utility {
    gap: 8px;
    padding: 14px 16px;
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
}
@media (max-width: 1100px) {
    /* On narrow screens, keep utility 3-col but allow the panel to span full width */
    .front-panel { width: 100%; }
}
@media (max-width: 480px) {
    .fp-section.utility { grid-template-columns: 1fr; }
}

/* ===== Intro / onboarding overlay =====
   Replaces the front panel column during the guided introduction. Sits in
   the same DOM slot so the page layout doesn't shift when the intro ends.
   The scope canvas keeps rendering normally; an SVG overlay sits on top of
   it to label voltage, zero, time, and trigger. */
.intro-card {
    background: var(--paper-2);
    border: 1px solid var(--rule);
    border-radius: 10px;
    padding: 18px 18px 16px;
    display: flex;
    flex-direction: column;
    gap: 14px;
    box-shadow: 0 1px 0 rgba(0,0,0,0.02), 0 2px 12px rgba(28, 26, 21, 0.05);
}
/* The card uses display:flex which overrides the HTML `hidden` attribute.
   Re-assert hidden so introEnd() actually removes it from view. */
.intro-card[hidden] { display: none; }
.intro-title {
    font-family: 'Fraunces', Georgia, serif;
    font-size: 24px;
    line-height: 1.2;
    color: var(--ink);
    margin: 0;
    font-weight: 600;
}
.intro-title em {
    color: var(--accent);
    font-style: italic;
}
.intro-body {
    color: var(--ink-2);
    font-size: 14px;
    line-height: 1.55;
    margin: 0;
}
.intro-body strong { color: var(--ink); font-weight: 600; }
/* Inline flag icon: mirrors the green ground flag and orange trigger flag
   drawn on the scope so students see the same shape twice (the label and
   the screen marker). Used at first mention only. */
.intro-body .flag-icon,
.intro-title .flag-icon,
.intro-knob-prompt .flag-icon {
    display: inline-block;
    vertical-align: -4px;
    width: 28px;
    height: 18px;
    margin-right: 5px;
}

/* Slot where a live knob is injected during interactive steps. The actual
   .knob-cell DOM node is moved here from the front panel at step entry and
   moved back when leaving, so the existing knob handlers remain bound. */
.intro-knob-slot {
    background: rgba(200, 52, 26, 0.06);
    border: 1px dashed rgba(200, 52, 26, 0.35);
    border-radius: 8px;
    padding: 12px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    animation: introKnobSlotIn 360ms ease;
}
.intro-knob-slot[hidden] { display: none; }
.intro-knob-slot .intro-knob-prompt {
    font-size: 13px;
    color: var(--ink-2);
    text-align: center;
    line-height: 1.4;
}
.intro-knob-slot .intro-knob-prompt b {
    color: var(--accent);
    font-weight: 600;
}
@keyframes introKnobSlotIn {
    from { opacity: 0; transform: translateY(4px); }
    to { opacity: 1; transform: translateY(0); }
}

.intro-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: auto;
    padding-top: 6px;
}
.intro-actions .intro-skip {
    margin-right: auto;
    background: transparent;
    border: none;
    color: var(--ink-3);
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 500;
    padding: 8px 10px;
    border-radius: 6px;
    cursor: pointer;
    transition: color 150ms ease, background 150ms ease;
}
.intro-actions .intro-skip:hover {
    color: var(--ink);
    background: rgba(28, 26, 21, 0.05);
}
.intro-actions .intro-nav {
    display: flex;
    gap: 8px;
}
.intro-actions button.intro-btn {
    font-family: 'Inter', sans-serif;
    font-size: 13px;
    font-weight: 600;
    padding: 9px 16px;
    border-radius: 6px;
    cursor: pointer;
    border: 1px solid var(--rule);
    background: var(--paper);
    color: var(--ink);
    transition: all 150ms ease;
}
.intro-actions button.intro-btn:hover:not(:disabled) {
    border-color: var(--ink-3);
    background: #fff;
}
.intro-actions button.intro-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
.intro-actions button.intro-btn.primary {
    background: var(--accent);
    border-color: var(--accent-2);
    color: #fff;
}
.intro-actions button.intro-btn.primary:hover:not(:disabled) {
    background: var(--accent-2);
}

/* Pulse animation for the Next button when we want to draw the student's
   eye toward advancing. Applied conditionally per step (see introApplyStep). */
@keyframes btn-pulse {
    0%, 100% {
        box-shadow: 0 0 0 0 rgba(200, 52, 26, 0.55);
    }
    50% {
        box-shadow: 0 0 0 8px rgba(200, 52, 26, 0);
    }
}
.btn.pulse,
.intro-btn.pulse {
    animation: btn-pulse 1.4s ease-in-out infinite;
}

/* ===== Scope annotation overlay =====
   An SVG positioned exactly over the scope <canvas>. Coordinates are kept
   in sync with geom.* by JS so labels line up with the rendered grid. */
.scope-shell { position: relative; }
.intro-overlay {
    position: absolute;
    pointer-events: none;
    /* JS sets top/left/width/height to match the canvas's CSS box. */
    z-index: 5;
    overflow: visible;
}
.intro-overlay[hidden] { display: none; }
.intro-overlay text {
    font-family: 'JetBrains Mono', monospace;
    font-weight: 600;
    fill: #f4ecd8;
}
.intro-overlay .anno-group {
    opacity: 0;
    transition: opacity 320ms ease;
}
.intro-overlay .anno-group.visible { opacity: 1; }
.intro-overlay .anno-axis-line {
    stroke: #ffd66b;
    stroke-width: 2;
    fill: none;
    filter: drop-shadow(0 0 4px rgba(255, 214, 107, 0.55));
}
.intro-overlay .anno-axis-tick {
    stroke: #ffd66b;
    stroke-width: 1.5;
    fill: none;
    opacity: 0.85;
}
.intro-overlay .anno-axis-label {
    font-size: 13px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    fill: #ffd66b;
}
.intro-overlay .anno-axis-sub {
    font-size: 10px;
    fill: #d8d0bf;
    letter-spacing: 0.06em;
}
.intro-overlay .anno-flag-green path { fill: #4dffb0; }
.intro-overlay .anno-flag-green text { fill: #0a1410; font-size: 10px; font-weight: 700; }
.intro-overlay .anno-flag-orange path { fill: #ff9a3c; }
.intro-overlay .anno-flag-orange text { fill: #1a0a04; font-size: 10px; font-weight: 700; }
.intro-overlay .anno-callout-line {
    stroke: rgba(255, 214, 107, 0.85);
    stroke-width: 1.25;
    stroke-dasharray: 4 3;
    fill: none;
}
.intro-overlay .anno-callout-text {
    font-size: 11px;
    fill: #f4ecd8;
    letter-spacing: 0.04em;
}
.intro-overlay .anno-callout-bg {
    fill: rgba(10, 20, 16, 0.72);
    stroke: rgba(255, 214, 107, 0.5);
    stroke-width: 1;
    rx: 4;
}
/* A gentle pulsing ring used to draw the eye to the highlighted element. */
.intro-overlay .anno-pulse {
    fill: none;
    stroke: #ffd66b;
    stroke-width: 1.5;
    animation: introPulse 1.6s ease-in-out infinite;
    transform-origin: center;
}
@keyframes introPulse {
    0%, 100% { opacity: 0.85; }
    50% { opacity: 0.25; }
}

/* Hide the front panel column entirely while the intro is active. The
   intro card uses the same grid slot so the scope width does not change. */
body.intro-active .fp-host > .front-panel,
body.intro-active .fp-host > #set-fg-btn,
body.intro-active .fp-host > #mystery-badge {
    display: none !important;
}

/* Mobile refinements: tighter bezel, better spacing, prevent any
   potential overflow/cutoff on narrow phones. */
@media (max-width: 600px) {
    .scope-bezel {
        padding: 6px 10px 4px;
        font-size: 11px;
        gap: 6px;
    }
    .scope-scale-bezel {
        gap: 8px;
        font-size: 12px;
    }
    .scope-scale-bezel span b {
        margin-left: 3px;
    }
    .scope-status {
        gap: 8px;
    }
    .scope-status .pill {
        font-size: 11px;
    }
    .wrap {
        padding: 10px 8px 20px;
    }
    .main-stack {
        gap: 8px;
    }
}

/* Knob + label cluster — knobs side by side in a section */
.knob-cluster {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    align-items: start;
}

/* Single-knob usage (Trigger Level) — center nicely in its column */
.knob-cluster:has(> .knob-cell:only-child) {
    display: flex;
    align-items: center;
    justify-content: center;
    height: auto;
    width: auto;
    padding: 0 6px;
}

/* Make .knob-cell fill the full height so the knob is vertically centered in the same space as Edge/Mode/Force */
.knob-cluster:has(> .knob-cell:only-child) .knob-cell {
    height: 100%;
    justify-content: center;
}
.knob-cell {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    min-width: 0;
}
.knob-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.12em;
    color: var(--ink-3);
    text-transform: uppercase;
    font-weight: 600;
    text-align: center;
}
.knob-readout {
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    font-weight: 600;
    color: var(--ink);
    text-align: center;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 3px 5px;
    width: 100%;
    line-height: 1.1;
}

#trig-readout {
    background: #fff;
    border: 1.5px solid var(--rule);
    border-radius: 4px;
    padding: 4px 7px;
    font-weight: 700;
    box-shadow: inset 0 1px 2px rgba(0,0,0,0.06);
}

/* Knob + flanking +/− glyphs. The +/− glyphs are visual affordances
   showing the drag direction (− = down/left, + = up/right). The entire
   row is one click-and-drag surface: pointer-down anywhere in the row
   (knob, glyphs, or the small pad around them) starts a drag.
   Also doubles as the "center mark" host — a colored circle painted behind
   the knob marks where the value is centered/zero, visible only when the
   knob is rotated away from center. */
.knob-row {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    position: relative;
    width: 100%;
    /* Expand the click target slightly past the glyphs and around the knob
       so the user doesn't have to land precisely on the dial. Horizontal
       expansion is kept small (3px) so adjacent knobs in a 2-column cluster
       (10px gap) retain a comfortable 4px dead zone between hit areas.
       The negative margin keeps the visual layout unchanged. */
    padding: 6px 3px;
    margin: -6px -3px;
    cursor: grab;
    touch-action: none;
    user-select: none;
}
.knob-row.dragging,
.knob-row:active {
    cursor: grabbing;
}
.knob-glyph {
    font-family: 'JetBrains Mono', monospace;
    font-size: 16px;
    font-weight: 700;
    color: var(--ink-3);
    user-select: none;
    pointer-events: none;
    line-height: 1;
    flex-shrink: 0;
}
.knob-glyph.disabled { opacity: 0.25; }
.knob-wrap.center-marked::before {
    /* Painted behind the knob: a small colored ring/dot at the 12 o'clock
       tick position to identify the "center" or "zero" of the knob's sweep.
       Visible only when the knob is rotated off-center (it disappears under
       the knob's pointer when at center). For stepped knobs (V/Div, T/Div,
       frequency) this marks the "default" or middle of the standard range. */
    content: '';
    position: absolute;
    top: -3px;
    left: 50%;
    transform: translateX(-50%);
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--accent);
    box-shadow: 0 0 4px rgba(200, 52, 26, 0.5);
    z-index: 0;
}

/* Rotary knob */
.knob {
    width: 42px;
    height: 42px;
    border-radius: 50%;
    background:
        radial-gradient(circle at 30% 25%, #fbf9f3 0%, #ddd6c5 50%, #b8b0a0 100%);
    border: 1px solid #98907f;
    box-shadow:
        0 2px 4px rgba(28, 26, 21, 0.15),
        inset 0 -2px 4px rgba(28, 26, 21, 0.1),
        inset 0 2px 3px rgba(255, 255, 255, 0.6);
    position: relative;
    cursor: grab;
    user-select: none;
    touch-action: none;
    transition: transform 0.08s;
}
.knob:hover {
    box-shadow:
        0 3px 6px rgba(28, 26, 21, 0.2),
        inset 0 -2px 4px rgba(28, 26, 21, 0.1),
        inset 0 2px 3px rgba(255, 255, 255, 0.6);
}
.knob:active { cursor: grabbing; }
.knob.small { width: 52px; height: 52px; }
/* Inner ring */
.knob::before {
    content: '';
    position: absolute;
    inset: 9px;
    border-radius: 50%;
    background:
        radial-gradient(circle at 30% 25%, #fefcf6 0%, #e8e2d2 70%, #d4ccba 100%);
    box-shadow: inset 0 1px 2px rgba(28, 26, 21, 0.15);
}
.knob.small::before { inset: 7px; }
/* Pointer/indicator line — rotates via CSS variable --rot */
.knob::after {
    content: '';
    position: absolute;
    top: 3px;
    left: 50%;
    width: 2px;
    height: 10px;
    background: var(--accent);
    border-radius: 1px;
    transform-origin: 50% calc(42px / 2 - 3px);
    transform: translateX(-50%) rotate(var(--rot, 0deg));
    z-index: 2;
    box-shadow: 0 0 2px rgba(200, 52, 26, 0.3);
}
.knob.small::after {
    height: 8px;
    transform-origin: 50% calc(36px / 2 - 3px);
}
/* Tick marks around the knob (drawn into a wrapper) */
.knob-wrap {
    position: relative;
    width: 42px;
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: center;
}
.knob-wrap.small { width: 36px; height: 36px; }
.knob-wrap svg.ticks {
    position: absolute;
    inset: -6px;
    pointer-events: none;
}

/* Segmented button row (coupling, trigger edge, trigger mode) */
.segmented {
    display: grid;
    gap: 2px;
    background: var(--rule);
    border-radius: 4px;
    padding: 2px;
    border: 1px solid var(--rule);
}
.segmented.cols-2 { grid-template-columns: 1fr 1fr; }
.segmented.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.seg-btn {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 6px 8px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 600;
    color: var(--ink-2);
    cursor: pointer;
    transition: all 0.12s;
    letter-spacing: 0.04em;
    line-height: 1.1;
}
.seg-btn:hover { background: #fff; }
.seg-btn.active {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
/* Unavailable segmented option (CH2 without a probe-2 point). Kept visible
   so students learn the control exists. */
.seg-btn:disabled {
    opacity: 0.35;
    cursor: not-allowed;
}
/* Channel identity colors on the CH1/CH2 buttons — three states per
   channel:
     • selected (knobs control it):  bright trace color, black text
     • on but not selected:         darker shade, white text
     • off:                         white, black text
   So brightness reads as "how engaged is this channel": bright = yours,
   dark = on screen, white = off. ID selectors outrank the generic
   .seg-btn.active ink/paper inversion. */
.ch-select #ch1-btn {
    background: #fff;
    color: var(--ink);
}
.ch-select #ch1-btn.ch-on:not(.active) {
    background: #0b8f5a;         /* dark green: on, knobs elsewhere */
    color: #fff;
    border-color: #0a7c4e;
}
.ch-select #ch1-btn.active {
    background: #4dffb0;         /* CH1 trace color */
    color: #0a1410;
    border-color: #2bbf7f;
}
.ch-select #ch2-btn {
    background: #fff;
    color: var(--ink);
}
.ch-select #ch2-btn.ch-on:not(.active) {
    background: #8f6b00;         /* dark gold: on, knobs elsewhere */
    color: #fff;
    border-color: #7d5d00;
}
.ch-select #ch2-btn.active {
    background: #ffdd57;         /* CH2 trace color */
    color: #0a1410;
    border-color: #d9b53a;
}

/* Per-slot measurement source chip (Measurements modal). Appears only while
   CH2 is on; tap flips the slot between channels. Channel-colored like the
   CH1/CH2 buttons: darkened text on a faint trace-color tint. */
.meas-src-btn {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 700;
    padding: 3px 7px;
    border-radius: 3px;
    cursor: pointer;
    letter-spacing: 0.04em;
    transition: all 0.12s;
}
.meas-src-btn.src-ch1 {
    color: #0b8f5a;
    background: rgba(77, 255, 176, 0.14);
    border: 1px solid rgba(11, 143, 90, 0.45);
}
.meas-src-btn.src-ch2 {
    color: #a97e00;
    background: rgba(255, 221, 87, 0.2);
    border: 1px solid rgba(169, 126, 0, 0.45);
}
/* Readouts showing a CH2 value pick up the channel tint (darkened for the
   light panel background). */
.knob-readout.ch2-value {
    color: #8a6500;
    font-weight: 700;
}

.fp-sublabel {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    letter-spacing: 0.1em;
    color: var(--ink-3);
    text-transform: uppercase;
    font-weight: 600;
    margin-bottom: 3px;
    margin-top: 1px;
}

/* Utility column buttons */
.btn {
    background: var(--ink);
    color: var(--paper);
    border: none;
    border-radius: 4px;
    padding: 8px 10px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
    transition: all 0.15s;
    letter-spacing: 0.08em;
    width: 100%;
}
.btn:hover { background: var(--accent); }
/* RUN button: green while running, red while stopped. Both use the same
   structure (.btn with a state modifier). Hover state nudges the color
   one shade darker so users get standard button affordance. */
.btn.running { background: #2d8a4d; }
.btn.running:hover { background: #246e3e; }
.btn.stopped { background: var(--bad); }
.btn.stopped:hover { background: var(--accent-2); }
.btn-secondary {
    background: var(--paper);
    color: var(--ink);
}
.btn-secondary:hover {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
/* Accent variant — used for primary/commit actions like the DONE buttons
   in the Function Generator and Measurements modals. Matches the accent
   color of the SET FUNCTION GENERATOR button for visual consistency. */
.btn-accent {
    background: var(--accent);
    color: #fff;
    border: 1px solid var(--accent-2);
}
.btn-accent:hover {
    background: var(--accent-2);
    border-color: var(--accent-2);
}

/* ===== Modal dialog (Measurements configuration) =====
   Used by the front-panel CONFIGURE button to expose the slot picker and the
   export-screenshot action. Backdrop dims the page; the dialog sits centered.
   Hidden via the [hidden] attribute when closed. */
.modal-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 20, 16, 0.55);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 100;
    padding: 16px;
    animation: modal-fade-in 0.12s ease-out;
}
.modal-backdrop[hidden] { display: none; }
.modal {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 10px;
    width: 100%;
    max-width: 520px;
    max-height: calc(100vh - 40px);
    display: flex;
    flex-direction: column;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.3);
    overflow: hidden;
    animation: modal-rise 0.16s ease-out;
}
.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px 10px;
    border-bottom: 1px solid var(--rule);
}
.modal-header h2 {
    margin: 0;
    font-size: 22px;
    font-weight: 500;
    color: var(--ink);
}
.modal-close {
    background: none;
    border: none;
    color: var(--ink-2);
    font-size: 24px;
    line-height: 1;
    cursor: pointer;
    padding: 4px 8px;
    border-radius: 4px;
    transition: background 0.12s, color 0.12s;
}
.modal-close:hover { background: var(--rule); color: var(--ink); }
.modal-body {
    padding: 14px 18px;
    overflow-y: auto;
    flex: 1 1 auto;
}
.modal-intro {
    font-size: 14px;
    color: var(--ink-2);
    margin: 0 0 12px;
    line-height: 1.5;
}
.modal-footer {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: 10px;
    padding: 12px 18px;
    border-top: 1px solid var(--rule);
    background: var(--paper-2);
}
@keyframes modal-fade-in {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes modal-rise {
    from { transform: translateY(8px); opacity: 0; }
    to   { transform: translateY(0);    opacity: 1; }
}

/* Four named slots (MEAS 1..4) like a real benchtop scope. Each slot shows
   either an assigned measurement + live value, or an "empty" prompt. Tapping
   a slot opens an inline picker right below it so students never leave the
   scope context. */
.meas-slots {
    display: flex;
    flex-direction: column;
    gap: 6px;
}
.meas-slot {
    display: grid;
    /* number | label+value | (optional source chip) | +/- indicator */
    grid-template-columns: auto 1fr auto auto;
    align-items: center;
    gap: 8px;
    padding: 7px 10px;
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 4px;
    cursor: pointer;
    transition: all 0.12s;
    min-height: 38px;
}
.meas-slot:hover { border-color: var(--ink-2); }
.meas-slot.empty { background: transparent; border-style: dashed; }
.meas-slot.empty:hover {
    background: var(--paper);
    border-style: solid;
}
.meas-slot.editing {
    border-color: var(--accent);
    box-shadow: 0 0 0 2px rgba(200, 52, 26, 0.12);
}
.meas-slot-num {
    font-family: 'JetBrains Mono', monospace;
    font-size: 11px;
    font-weight: 700;
    letter-spacing: 0.1em;
    color: var(--ink-3);
    text-transform: uppercase;
    width: 52px;
    flex-shrink: 0;
}
.meas-slot-body {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}
.meas-slot-label {
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    letter-spacing: 0.05em;
    color: var(--ink-2);
    font-weight: 600;
    line-height: 1.0;
}
.meas-slot-value {
    font-family: 'JetBrains Mono', monospace;
    font-size: 15px;
    font-weight: 700;
    color: var(--ink);
    line-height: 1.0;
}
.meas-slot.empty .meas-slot-label {
    font-family: 'Fraunces', serif;
    font-size: 14px;
    font-style: italic;
    font-weight: 400;
    color: var(--ink-3);
    letter-spacing: 0;
    text-transform: none;
}
.meas-slot-action {
    font-family: 'JetBrains Mono', monospace;
    font-size: 14px;
    color: var(--ink-3);
    width: 16px;
    text-align: center;
    flex-shrink: 0;
    font-weight: 700;
}
.meas-slot:hover .meas-slot-action { color: var(--ink); }
.meas-slot.editing .meas-slot-action { color: var(--accent); }

/* Inline picker that appears under the slot being edited */
.meas-picker {
    background: var(--paper);
    border: 1px solid var(--accent);
    border-radius: 4px;
    padding: 10px;
    margin-top: -2px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 5px;
}
.meas-pick-btn {
    background: var(--paper);
    border: 1px solid var(--rule);
    border-radius: 3px;
    padding: 7px 9px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
    color: var(--ink-2);
    cursor: pointer;
    text-align: left;
    transition: all 0.1s;
    font-weight: 600;
}
.meas-pick-btn:hover {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
.meas-pick-btn.active {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
.meas-pick-btn.off {
    grid-column: 1 / -1;
    color: var(--accent);
    border-color: var(--accent);
}
.meas-pick-btn.off:hover {
    background: var(--accent);
    color: var(--paper);
}

footer.colophon {
    margin-top: 28px;
    text-align: center;
    font-size: 13px;
    color: var(--ink-3);
}
footer.colophon a { color: var(--ink-2); text-decoration: none; border-bottom: 1px solid var(--rule); }
footer.colophon a:hover { color: var(--accent); border-color: var(--accent); }

/* CONFIGURE + CURSOR + CAPTURE side by side. Smaller font lets all three
   fit on one row at the front panel's width without truncation. */
.meas-action-row {
    display: grid;
    grid-template-columns: 1fr 1fr 1fr;
    gap: 6px;
}
.meas-action-row .btn {
    font-size: 10px;
    padding: 8px 6px;
    letter-spacing: 0.06em;
}
/* CURSOR button latches "on" when the cursor panel is open, mirroring how
   real benchtop scopes light a function button while its sub-menu is up.
   Uses the same ink-on-paper inversion as .seg-btn.active so it reads as
   "this control is currently engaged" without competing with the accent
   color reserved for primary actions. */
.meas-action-row .btn.cursor-active {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}

/* ===== CURSORS SECTION =====
   Inline fp-section in the front panel, hidden until the CURSOR button
   toggles it on. The TIME/VOLTAGE toggle uses the same .segmented control
   styling as coupling/edge/mode for visual consistency, and the readout
   below uses a tight 2-column mono grid to keep the live values aligned. */
.cursor-readout {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 0 12px;
    font-family: 'JetBrains Mono', monospace;
    font-size: 12px;
}
.cursor-col {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 6px 8px;
    min-width: 0;
}
/* Labels styled to mirror the colored chips drawn on the scope canvas
   itself (drawCursorTag): magenta box for T1/T2/ΔT/1/ΔT, cyan box for
   V1/V2/ΔV. Dark text on the colored fill keeps the readout visually
   linked to the matching cursor line on the screen. */
.cursor-readout .lbl {
    font-family: 'JetBrains Mono', monospace;
    font-size: 10px;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-align: center;
    color: #0a1410;
    padding: 2px 5px;
    border-radius: 2px;
    align-self: center;
    justify-self: start;
    min-width: 28px;
    line-height: 1;
}
.cursor-readout .lbl-time {
    background: #ff6cb8;  /* CURSOR_COLOR_TIME — magenta */
}
.cursor-readout .lbl-voltage {
    background: #5ad6ff;  /* CURSOR_COLOR_VOLTAGE — cyan */
}
/* Delta and 1/Δ labels are derived values, not pointers to a specific
   on-screen cursor line — render them as plain text so the chips stay
   reserved for items the student can grab and drag on the trace. */
.cursor-readout .lbl-plain {
    background: transparent;
    color: var(--ink-3);
    font-weight: 600;
    padding: 2px 0;
}
.cursor-readout .val {
    color: var(--ink);
    font-weight: 600;
    text-align: right;
}
.cursor-readout .val.delta {
    color: var(--accent);
}

/* Crosshair cursor on the scope canvas while cursors mode is on, so the
   draggability is discoverable. Switches to grabbing during an active drag. */
#scope.cursors-on { cursor: crosshair; }
#scope.cursors-dragging { cursor: grabbing; }

/* ===== FORCE button — Visually distinct from the other Mode
   buttons (which are sticky/toggle): FORCE is momentary. Amber/yellow
   color signals a manual-intervention action and keeps it clearly
   separate from the accent-colored SET FUNCTION GENERATOR and from
   the green RUN / red STOPPED states. */

/* FORCE sits beside the RISING/FALLING segmented group rather than
   inside it, so it doesn't share their gray frame. FORCE has its own
   wrapper styled like a segmented group but with a transparent
   background and border so heights match without a visible frame. */
.edge-force-row {
    display: flex;
    gap: 4px;
    align-items: stretch;
}
.edge-force-row .segmented { flex: 2 1 0; min-width: 0; }
.edge-force-row .force-wrap {
    flex: 1 1 0;
    min-width: 0;
    background: transparent;
    border-color: transparent;
    grid-template-columns: 1fr;
}

.seg-btn.trig-force-seg {
    color: #6b4a00;
    background: #ffd966;
    font-weight: 700;
    border: none;
}
.seg-btn.trig-force-seg:hover {
    background: #f0b500;
    color: #2a1d00;
}
/* Force "armed" flash: when the user fires a force trigger (or the
   scope captures a single-shot sweep), the button briefly flashes a
   deeper amber so they get visual confirmation that the action fired. */
.seg-btn.trig-force-seg.flash {
    background: #f0b500;
    color: #2a1d00;
}

/* Attention pulse on the SET FUNCTION GENERATOR button until the student
   clicks it for the first time. Uses a box-shadow ring that grows and fades,
   keyed off the accent color so it harmonizes with the button's own fill.
   The .pulse-attn class is removed in JS on first click. */
@keyframes set-fg-pulse {
    0% {
        box-shadow: 0 0 0 0 rgba(200, 52, 26, 0.7);
    }
    70% {
        box-shadow: 0 0 0 12px rgba(200, 52, 26, 0);
    }
    100% {
        box-shadow: 0 0 0 0 rgba(200, 52, 26, 0);
    }
}
#set-fg-btn.pulse-attn {
    animation: set-fg-pulse 1.5s ease-out infinite;
    position: relative;
}
/* Respect users who prefer reduced motion: keep the visual cue but make it
   a gentle steady glow instead of a pulsing ring. */
@media (prefers-reduced-motion: reduce) {
    #set-fg-btn.pulse-attn {
        animation: none;
        box-shadow: 0 0 0 3px rgba(200, 52, 26, 0.45);
    }
}

/* Stronger, more obvious pulse used only during the guided introduction
   for teaching buttons (CURSOR, MEASURE). */
.teaching-pulse {
    animation: teaching-pulse-anim 1.2s ease-in-out infinite !important;
    box-shadow: 0 0 0 6px rgba(200, 52, 26, 0.6) !important;
    position: relative;
}
@keyframes teaching-pulse-anim {
    0%, 100% { box-shadow: 0 0 0 6px rgba(200, 52, 26, 0.6); }
    50% { box-shadow: 0 0 0 18px rgba(200, 52, 26, 0.15); }
}
@media (prefers-reduced-motion: reduce) {
    .teaching-pulse {
        animation: none !important;
        box-shadow: 0 0 0 8px rgba(200, 52, 26, 0.5) !important;
    }
}

