/* ==========================================================================
   teacher.css — the teacher view (approved design, 2026-09-24)

   A fixed 248px sidebar + a calm, single-accent workspace. Everything here is
   scoped to body.teacher-mode (the shell) or to #teacherApp (the screens), so
   student mode is untouched. Legacy teacher chrome (the pupil nav bar, stats
   banner, XP pill, mascot, floating shapes) is HIDDEN here rather than deleted,
   because older modules still look those element ids up.

   Tokens: the --tv-* set below points at the shared brand layer css/brand.css
   (2026-09-25, "Math Quest Pro" cohesion), so the teacher view speaks the
   student's palette: brand purple accent, purple-tinted ink, lavender rules, the
   student's dark world. css/teacher-brand.css (loaded after the teacher sheets)
   adds the brand moments: logo, Nunito display type, purple buttons, switches,
   selection and cards. 8px spacing scale, 44px primary targets, no gradients,
   no emoji.
   ========================================================================== */

body.teacher-mode {
    /* Brand-linked (css/brand.css). The page keeps a whisper of the student's
       teal (--mq-bg #EAF8F8) and the neutrals take the student's lavender. */
    --tv-page: #f3f6f7;
    --tv-surface: #ffffff;
    --tv-subtle: #f1eff8;
    --tv-subtle-2: #faf9fd;
    --tv-border: var(--brand-rule);
    --tv-rule: #edeaf5;
    --tv-rule-soft: #f3f1f9;
    --tv-control: var(--brand-muted);
    --tv-control-soft: var(--brand-rule-2);
    --tv-text: var(--brand-ink);
    --tv-text-2: var(--brand-ink-2);
    --tv-nav-text: #3a3652;
    --tv-caption: var(--brand-caption);
    --tv-accent: var(--brand-purple-d);
    --tv-accent-hover: var(--brand-purple-dd);
    --tv-accent-tint: var(--brand-purple-soft);
    --tv-selected: var(--brand-ink);
    --tv-on-selected: #ffffff;
    --tv-danger: #b42318;
    --tv-side-w: 248px;
    --tv-font: Manrope, system-ui, -apple-system, 'Segoe UI', sans-serif;
    --tv-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;
    background: var(--tv-page);
    padding-left: var(--tv-side-w);
}

html.dark body.teacher-mode {
    /* The student's dark world (#1A1828), with cards one step calmer. */
    --tv-page: var(--brand-night);
    --tv-surface: var(--brand-night-surface);
    --tv-subtle: #2e2a44;
    --tv-subtle-2: #27243a;
    --tv-border: var(--brand-night-rule);
    --tv-rule: #312d46;
    --tv-rule-soft: #2b2840;
    --tv-control: var(--brand-night-muted);
    --tv-control-soft: var(--brand-night-rule-2);
    --tv-text: var(--brand-night-ink);
    --tv-text-2: var(--brand-night-ink-2);
    --tv-nav-text: #ddd8ee;
    --tv-caption: var(--brand-night-muted);
    --tv-accent: var(--brand-purple-l);
    --tv-accent-hover: var(--brand-purple-ll);
    --tv-accent-tint: var(--brand-purple-soft-dark);
    --tv-selected: var(--brand-night-ink);
    --tv-on-selected: var(--brand-night);
}

/* ---------------------------------------------------------------- the shell */

#teacherApp { display: none; }
body.teacher-mode #teacherApp { display: block; }

/* Legacy teacher/pupil chrome that the teacher view replaces. */
body.teacher-mode .nav-bar,
body.teacher-mode .bg-shapes,
body.teacher-mode #myStatsBar,
body.teacher-mode #studentBanner,
body.teacher-mode .mq-mascot-card { display: none !important; }

/* On a teacher screen the legacy home view (the pupil landing) is hidden; the
   other legacy views (quiz builder, navigator, MAP, games) still show when a
   teacher opens them, to the right of the sidebar. */
body.teacher-mode.tv-on-screen #homeView { display: none !important; }
body.teacher-mode .tv-main { display: none; }
body.teacher-mode.tv-on-screen .tv-main { display: block; }

/* Play views and the board window take the whole screen. */
body.teacher-mode.tv-play,
body.teacher-mode.tv-board { padding-left: 0; }
body.teacher-mode.tv-play .tv-side,
body.teacher-mode.tv-board .tv-side { display: none; }

/* Board display: one large question at a time for the whole class. */
body.teacher-mode.tv-bigboard #gameView { zoom: 1.35; }

.tv-side {
    position: fixed;
    left: 0; top: 0; bottom: 0;
    z-index: 50;
    width: var(--tv-side-w);
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    padding: 20px 16px 16px;
    background: var(--tv-surface);
    border-right: 1px solid var(--tv-border);
    font-family: var(--tv-font);
    color: var(--tv-text);
    overflow-y: auto;
}

.tv-side a { text-decoration: none; }
.tv-brand {
    display: flex; align-items: center; gap: 12px;
    padding: 4px 8px; border-radius: 8px; color: var(--tv-text);
}
.tv-brand-tile {
    display: flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; flex: none; border-radius: 8px;
    background: #1f2023; color: #fff;
    font-size: 18px; line-height: 24px; font-weight: 700;
}
.tv-brand-words { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; }
.tv-brand-name { font-size: 14px; line-height: 20px; font-weight: 700; color: var(--tv-text); }
.tv-badge {
    font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-text-2);
    background: var(--tv-subtle); border: 1px solid var(--tv-border); border-radius: 4px; padding: 0 6px;
}
.tv-nav-group { display: flex; flex-direction: column; gap: 2px; margin-top: 24px; }
.tv-nav-heading + .tv-nav-group { margin-top: 0; }
.tv-nav-heading {
    margin-top: 24px; padding: 0 12px 4px;
    font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-caption);
}
.tv-nav-spacer { flex: 1; min-height: 16px; }
.tv-nav-bottom { margin-top: 0; border-top: 1px solid var(--tv-border); padding-top: 12px; }
.tv-nav-link {
    display: flex; align-items: center; gap: 12px;
    height: 44px; padding: 0 12px; box-sizing: border-box; border-radius: 8px;
    font-size: 14px; line-height: 20px; font-weight: 600;
    color: var(--tv-nav-text); background: transparent;
    white-space: nowrap; overflow: hidden;
}
.tv-nav-link svg { flex: none; color: var(--tv-caption); }
.tv-nav-link:hover { background: var(--tv-subtle); }
.tv-nav-link[aria-current="page"] { background: var(--tv-accent-tint); color: var(--tv-accent); }
.tv-nav-link[aria-current="page"] svg { color: var(--tv-accent); }

#teacherApp [hidden] { display: none !important; }
#teacherApp :focus-visible { outline: 2px solid var(--tv-accent); outline-offset: 2px; }

/* ---------------------------------------------------------------- the workspace */

.tv-main {
    min-height: 100vh;
    box-sizing: border-box;
    padding: 32px 40px 40px;
    font-family: var(--tv-font);
    color: var(--tv-text);
    background: var(--tv-page);
    position: relative;
    z-index: 1;
    outline: none;
}
.tv-main *, .tv-main *::before, .tv-main *::after { box-sizing: border-box; }
.tv-main button, .tv-main input, .tv-main select, .tv-main textarea { font-family: inherit; }
.tv-screen { display: none; flex-direction: column; gap: 24px; max-width: 1600px; }
.tv-screen.is-active { display: flex; }

.tv-header { display: flex; align-items: flex-end; justify-content: space-between; gap: 24px; flex-wrap: wrap; }
.tv-header-actions { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tv-h1 { margin: 0; font-size: 28px; line-height: 36px; font-weight: 700; letter-spacing: -0.01em; color: var(--tv-text); }
.tv-sub { margin: 4px 0 0; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text-2); }
.tv-h2 { margin: 0; font-size: 18px; line-height: 24px; font-weight: 700; color: var(--tv-text); }
.tv-h2-sm { margin: 0; font-size: 14px; line-height: 20px; font-weight: 700; color: var(--tv-text); }
.tv-h3 { margin: 0; font-size: 14px; line-height: 20px; font-weight: 700; color: var(--tv-text); }
.tv-cap { margin: 0; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-caption); }
.tv-body { margin: 0; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text-2); }
.tv-muted { color: var(--tv-caption); }
.tv-sr { position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0; }

.tv-card {
    background: var(--tv-surface);
    border: 1px solid var(--tv-border);
    border-radius: 12px;
    padding: 24px;
    display: flex; flex-direction: column; gap: 16px;
    min-width: 0;
}
.tv-card.tv-flush { padding: 0; gap: 0; overflow: hidden; }
.tv-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: 16px;
    min-height: 52px; padding: 0 16px 0 24px; border-bottom: 1px solid var(--tv-rule);
}
.tv-card-foot { padding: 12px 24px; }
.tv-step { display: flex; align-items: center; gap: 12px; }
.tv-step-num {
    display: inline-flex; align-items: center; justify-content: center;
    width: 24px; height: 24px; border-radius: 6px; flex: none;
    border: 1px solid var(--tv-control-soft); font-size: 12px; font-weight: 700; color: var(--tv-text-2);
}

.tv-grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 24px; }
.tv-grid-2-1 { display: grid; grid-template-columns: minmax(0, 2fr) minmax(0, 1fr); gap: 24px; align-items: start; }
.tv-grid-1-1 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 24px; align-items: start; }
.tv-col { display: flex; flex-direction: column; gap: 24px; min-width: 0; }
.tv-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tv-fields-2 { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px 12px; }

/* ---------------------------------------------------------------- controls */

.tv-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    height: 44px; padding: 0 16px; border-radius: 8px;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
    font-size: 14px; line-height: 20px; font-weight: 600; white-space: nowrap;
    cursor: pointer; text-decoration: none;
}
.tv-btn:hover { border-color: var(--tv-control); background: var(--tv-subtle-2); }
.tv-btn svg { flex: none; }
.tv-btn-primary { background: var(--tv-accent); border-color: var(--tv-accent); color: #fff; padding: 0 20px; }
.tv-btn-primary:hover { background: var(--tv-accent-hover); border-color: var(--tv-accent-hover); }
.tv-btn-block { width: 100%; height: 48px; }
.tv-btn-sm { height: 36px; padding: 0 12px; }
.tv-btn-ghost { border-color: transparent; background: transparent; color: var(--tv-accent); height: 36px; padding: 0 8px; }
.tv-btn-ghost:hover { background: var(--tv-accent-tint); border-color: transparent; color: var(--tv-accent-hover); }
.tv-btn[disabled], .tv-btn[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.tv-link { background: none; border: 0; padding: 0; color: var(--tv-accent); font-weight: 600; cursor: pointer; font-size: inherit; text-decoration: none; }
.tv-link:hover { color: var(--tv-accent-hover); text-decoration: underline; }
.tv-icon-btn {
    display: inline-flex; align-items: center; justify-content: center;
    width: 36px; height: 36px; flex: none; padding: 0; border-radius: 8px;
    border: 1px solid transparent; background: transparent; color: var(--tv-text-2); cursor: pointer;
}
.tv-icon-btn:hover { background: var(--tv-subtle); }
.tv-icon-btn.is-framed { border-color: var(--tv-control-soft); }

.tv-label { display: block; margin: 0 0 4px; font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-text-2); }
.tv-input, .tv-select {
    display: block; width: 100%; height: 40px; padding: 0 12px;
    border: 1px solid var(--tv-control); border-radius: 8px; background: var(--tv-surface);
    font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text);
}
.tv-select {
    padding-right: 36px; appearance: none; -webkit-appearance: none; cursor: pointer;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%235b5f66' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-repeat: no-repeat; background-position: right 12px center;
}
.tv-search { position: relative; }
.tv-search svg { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--tv-caption); pointer-events: none; }
.tv-search .tv-input { padding-left: 40px; }

/* Segmented control (one of a few) */
.tv-seg { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(0, 1fr); gap: 4px; padding: 4px; background: var(--tv-subtle); border-radius: 10px; }
.tv-seg > button {
    height: 36px; padding: 0 8px; border-radius: 7px; cursor: pointer; white-space: nowrap;
    border: 1.5px solid transparent; background: transparent; color: var(--tv-text-2);
    font-size: 14px; line-height: 20px; font-weight: 600;
}
.tv-seg > button[aria-checked="true"] { border-color: var(--tv-selected); background: var(--tv-surface); color: var(--tv-text); font-weight: 700; }
.tv-seg > button[disabled] { opacity: .45; cursor: not-allowed; }

/* Toggle chips (Level K-6, letters, facts) */
.tv-chips { display: flex; flex-wrap: wrap; gap: 4px; }
.tv-chip {
    min-width: 36px; height: 36px; padding: 0 8px; border-radius: 8px; cursor: pointer;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
    font-size: 14px; line-height: 20px; font-weight: 600;
}
.tv-chip-sm { min-width: 28px; height: 28px; font-size: 12px; border-radius: 6px; padding: 0 6px; }
.tv-letters { gap: 3px; flex-wrap: nowrap; }
.tv-letters { gap: 2px; }
.tv-letters .tv-chip { min-width: 0; width: 22px; height: 32px; padding: 0; flex: none; font-size: 12px; }
.tv-chip[aria-pressed="true"] { border-color: var(--tv-selected); background: var(--tv-selected); color: var(--tv-on-selected); font-weight: 700; }

/* Switch */
.tv-switch {
    display: flex; align-items: center; width: 44px; height: 24px; flex: none; padding: 2px; border-radius: 12px; cursor: pointer;
    justify-content: flex-start; background: var(--tv-surface); border: 1px solid var(--tv-control);
}
.tv-switch::after { content: ''; display: block; width: 18px; height: 18px; border-radius: 9px; background: var(--tv-control); }
.tv-switch[aria-checked="true"] { justify-content: flex-end; background: var(--tv-selected); border-color: var(--tv-selected); }
.tv-switch[aria-checked="true"]::after { background: var(--tv-on-selected); }
.tv-setting { display: flex; align-items: flex-start; justify-content: space-between; gap: 16px; }
.tv-setting + .tv-setting, .tv-divided { border-top: 1px solid var(--tv-rule); padding-top: 16px; }

/* Check box */
.tv-check {
    display: flex; align-items: center; gap: 8px; min-height: 28px; padding: 0; border: 0; background: transparent;
    font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text); text-align: left; cursor: pointer;
}
.tv-check-box {
    display: inline-flex; align-items: center; justify-content: center; width: 20px; height: 20px; flex: none;
    border: 1.5px solid var(--tv-control); border-radius: 4px; background: var(--tv-surface); color: transparent;
}
.tv-check[aria-checked="true"] .tv-check-box { background: var(--tv-selected); border-color: var(--tv-selected); color: var(--tv-on-selected); }

.tv-code {
    display: inline-block; max-width: 100%; padding: 4px 8px; border-radius: 6px;
    background: var(--tv-page); border: 1px solid var(--tv-border);
    font-family: var(--tv-mono); font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-text);
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis; vertical-align: middle;
}
.tv-code-block { display: block; white-space: normal; word-break: break-all; padding: 8px 12px; font-size: 13px; line-height: 20px; }

.tv-note { margin: 0; padding: 12px; border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-page); font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-text-2); }
.tv-empty {
    margin: 0; padding: 24px 16px; border: 1px solid var(--tv-border); border-radius: 10px; background: var(--tv-subtle-2);
    text-align: center; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-caption);
}
.tv-empty-lg { display: flex; flex-direction: column; align-items: center; gap: 8px; padding: 48px 24px; text-align: center; }
.tv-empty-icon { display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 10px; background: var(--tv-subtle); color: var(--tv-text-2); }

/* Tables */
.tv-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.tv-table th {
    text-align: left; padding: 8px 16px; font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-caption);
    border-bottom: 1px solid var(--tv-rule);
}
.tv-table td {
    padding: 12px 16px; border-bottom: 1px solid var(--tv-rule-soft); vertical-align: middle;
    font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text); font-variant-numeric: tabular-nums;
    overflow: hidden; text-overflow: ellipsis;
}
.tv-table tr:last-child td { border-bottom: 0; }
.tv-table th:first-child, .tv-table td:first-child { padding-left: 24px; }
.tv-table th:last-child, .tv-table td:last-child { padding-right: 24px; }
.tv-cell-title { display: block; font-weight: 600; color: var(--tv-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-cell-sub { display: block; font-size: 12px; line-height: 16px; color: var(--tv-caption); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-cell-title.tv-link-row { background: none; border: 0; padding: 0; cursor: pointer; font-size: 14px; text-align: left; max-width: 100%; }
.tv-cell-title.tv-link-row:hover { color: var(--tv-accent); }

/* Menus */
.tv-menu-wrap { position: relative; display: inline-block; }
.tv-menu {
    position: absolute; right: 0; top: calc(100% + 4px); z-index: 60; min-width: 208px;
    padding: 6px; background: var(--tv-surface); border: 1px solid var(--tv-border); border-radius: 10px;
    box-shadow: 0 8px 24px rgba(20, 20, 30, .10);
}
.tv-menu[hidden] { display: none; }
.tv-menu button {
    display: flex; align-items: center; gap: 10px; width: 100%; height: 36px; padding: 0 10px; border: 0; border-radius: 6px;
    background: transparent; color: var(--tv-text); font-size: 14px; font-weight: 500; cursor: pointer; text-align: left;
}
.tv-menu button:hover { background: var(--tv-subtle); }
.tv-menu hr { border: 0; border-top: 1px solid var(--tv-rule); margin: 6px 0; }
.tv-menu .is-danger { color: var(--tv-danger); }

.tv-toast {
    position: fixed; left: 50%; bottom: 24px; transform: translateX(-50%); z-index: 100001;
    padding: 10px 16px; border-radius: 8px; background: #1f2023; color: #fff;
    font-family: Manrope, system-ui, sans-serif; font-size: 14px; font-weight: 600;
    opacity: 0; pointer-events: none; transition: opacity .15s ease;
}
.tv-toast.is-on { opacity: 1; }

/* ---------------------------------------------------------------- Home */

.tv-job {
    display: flex; flex-direction: column; gap: 16px; min-height: 252px; padding: 24px;
    background: var(--tv-surface); border: 1px solid var(--tv-border); border-radius: 12px;
    color: var(--tv-text); cursor: pointer; text-align: left; font-size: inherit;
}
.tv-job:hover { border-color: var(--tv-control-soft); }
.tv-job-icon { display: flex; align-items: center; justify-content: center; width: 48px; height: 48px; border-radius: 10px; background: var(--tv-subtle); color: var(--tv-text); }
.tv-job-title { font-size: 18px; line-height: 24px; font-weight: 700; color: var(--tv-text); display: block; }
.tv-job-text { font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text-2); display: block; margin-top: 8px; }
.tv-job .tv-btn { margin-top: auto; align-self: flex-start; pointer-events: none; }

.tv-print-item { display: flex; align-items: center; gap: 16px; padding: 12px 16px 12px 24px; border-bottom: 1px solid var(--tv-rule-soft); }
.tv-print-item:last-child { border-bottom: 0; }
.tv-print-item > div { flex: 1; min-width: 0; }

/* ---------------------------------------------------------------- Send a skill set */

.tv-sets-grid { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 1.1fr) minmax(0, 1fr); gap: 24px; align-items: stretch; }
.tv-sets-grid > .tv-card:last-child { align-self: start; }
.tv-panel { height: calc(100vh - 156px); min-height: 560px; }
.tv-panel-head { padding: 24px 24px 16px; display: flex; flex-direction: column; gap: 16px; border-bottom: 1px solid var(--tv-rule); }
.tv-panel-body { flex: 1; min-height: 0; overflow-y: auto; padding: 12px; }
.tv-panel-foot { padding: 12px 24px; border-top: 1px solid var(--tv-rule); display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }

.tv-tree-btn {
    display: flex; align-items: center; gap: 8px; width: 100%; min-height: 36px; padding: 0 12px; border: 0; border-radius: 8px;
    background: transparent; color: var(--tv-text); font-size: 14px; line-height: 20px; font-weight: 700; text-align: left; cursor: pointer;
}
.tv-tree-btn:hover { background: var(--tv-subtle-2); }
.tv-tree-btn .tv-tree-count { margin-left: auto; font-size: 12px; font-weight: 600; color: var(--tv-caption); font-variant-numeric: tabular-nums; }
.tv-tree-btn svg { flex: none; color: var(--tv-caption); transition: transform .15s ease; }
.tv-tree-btn[aria-expanded="true"] svg.tv-chev { transform: rotate(90deg); }
.tv-tree-cat { padding-left: 32px; min-height: 32px; font-size: 12px; line-height: 16px; color: var(--tv-text-2); }
.tv-skill-row { display: flex; align-items: center; gap: 12px; padding: 6px 12px 6px 32px; border-radius: 8px; }
.tv-skill-row.is-added { background: var(--tv-page); }
.tv-skill-row .tv-add {
    display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; flex: none; padding: 0; border-radius: 8px; cursor: pointer;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
}
.tv-skill-row.is-added .tv-add { border-color: var(--tv-selected); background: var(--tv-selected); color: var(--tv-on-selected); }
.tv-skill-name { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--tv-text); }
.tv-skill-meta { font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-caption); }

.tv-set-item { border: 1px solid var(--tv-border); border-radius: 10px; padding: 12px; display: flex; flex-direction: column; gap: 8px; background: var(--tv-surface); }
.tv-set-item + .tv-set-item { margin-top: 8px; }
.tv-set-top { display: flex; align-items: flex-start; gap: 8px; }
.tv-set-top > div { flex: 1; min-width: 0; }
.tv-set-tools { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.tv-weight { display: inline-flex; align-items: center; margin-left: auto; border: 1px solid var(--tv-control-soft); border-radius: 8px; height: 32px; }
.tv-weight button { width: 32px; height: 30px; border: 0; background: transparent; color: var(--tv-text); cursor: pointer; border-radius: 8px; display: inline-flex; align-items: center; justify-content: center; }
.tv-weight button:hover { background: var(--tv-subtle); }
.tv-weight span { min-width: 32px; text-align: center; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.tv-opt-btn {
    display: inline-flex; align-items: center; gap: 6px; height: 32px; padding: 0 10px; border-radius: 8px; cursor: pointer;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text); font-size: 12px; font-weight: 700;
}
.tv-opt-btn[aria-expanded="true"] { border: 1.5px solid var(--tv-selected); }
.tv-opt-panel { border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-subtle-2); padding: 12px; display: flex; flex-direction: column; gap: 8px; }
.tv-opt-panel dl { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; font-size: 12px; line-height: 16px; }
.tv-opt-panel dt { font-weight: 600; color: var(--tv-text-2); }
.tv-opt-panel dd { margin: 0; color: var(--tv-text); font-weight: 500; }

.tv-result { border: 1px solid var(--tv-border); border-radius: 10px; background: var(--tv-subtle-2); padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.tv-result-row { display: flex; align-items: center; justify-content: space-between; gap: 8px; }

/* ---------------------------------------------------------------- Print */

.tv-print-grid { display: grid; grid-template-columns: minmax(300px, 1fr) minmax(0, 1.25fr) minmax(260px, .8fr); gap: 24px; align-items: start; }
.tv-section { border: 1px solid var(--tv-border); border-radius: 10px; padding: 16px; display: flex; flex-direction: column; gap: 12px; }
.tv-section-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.tv-fields-type { display: grid; grid-template-columns: minmax(0, 1fr) 88px; gap: 12px; }
.tv-preview { display: flex; flex-direction: column; gap: 12px; min-width: 0; }
.tv-preview-stage {
    position: relative; overflow: hidden; border: 1px solid var(--tv-border); border-radius: 8px; background: #d9d9d6;
    display: flex; justify-content: center; padding: 16px;
}
.tv-preview-frame { border: 0; background: #fff; transform-origin: top left; display: block; }
.tv-preview-box { position: relative; overflow: hidden; background: #fff; box-shadow: 0 1px 2px rgba(0,0,0,.12); }
.tv-preview-msg { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; text-align: center; padding: 24px; font-size: 13px; color: var(--tv-caption); background: rgba(255,255,255,.85); }
.tv-fits { margin: 0; font-size: 12px; line-height: 16px; color: var(--tv-text-2); }
.tv-fits strong { color: var(--tv-text); }
.tv-pick-results { max-height: 280px; overflow-y: auto; border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-surface); }
.tv-pick-results button { display: block; width: 100%; padding: 8px 12px; border: 0; border-bottom: 1px solid var(--tv-rule-soft); background: transparent; text-align: left; cursor: pointer; color: var(--tv-text); font-size: 14px; }
.tv-pick-results button:hover { background: var(--tv-subtle); }

/* ---------------------------------------------------------------- Run practice */

.tv-run-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(300px, 360px); gap: 24px; align-items: start; }
.tv-src { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }
.tv-radio-card {
    display: flex; align-items: flex-start; gap: 12px; padding: 12px 16px; border-radius: 10px; cursor: pointer; text-align: left;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
}
.tv-radio-card[aria-checked="true"] { border: 1.5px solid var(--tv-selected); }
.tv-radio-dot { width: 18px; height: 18px; border-radius: 9px; border: 1.5px solid var(--tv-control); flex: none; margin-top: 1px; display: inline-flex; align-items: center; justify-content: center; }
.tv-radio-card[aria-checked="true"] .tv-radio-dot { border-color: var(--tv-selected); }
.tv-radio-card[aria-checked="true"] .tv-radio-dot::after { content: ''; width: 8px; height: 8px; border-radius: 4px; background: var(--tv-selected); }
.tv-radio-title { display: block; font-size: 14px; line-height: 20px; font-weight: 700; }
.tv-radio-text { display: block; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-caption); }
.tv-modes { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 12px; }
.tv-mode {
    position: relative; display: flex; flex-direction: column; gap: 12px; padding: 16px; min-height: 168px; border-radius: 10px; cursor: pointer; text-align: left;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
}
.tv-mode[aria-checked="true"] { border: 1.5px solid var(--tv-selected); }
.tv-mode-icon { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: 8px; background: var(--tv-subtle); }
.tv-mode-tick { position: absolute; top: 12px; right: 12px; display: none; }
.tv-mode[aria-checked="true"] .tv-mode-tick { display: inline-flex; }
.tv-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.tv-pill { display: inline-flex; align-items: center; gap: 6px; min-height: 32px; padding: 4px 10px; border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-page); font-size: 14px; font-weight: 600; color: var(--tv-text); }
.tv-pill small { font-size: 12px; font-weight: 500; color: var(--tv-caption); }
.tv-dl { margin: 0; display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; padding: 12px 16px; border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-subtle-2); }
.tv-dl dt { font-size: 12px; line-height: 20px; font-weight: 600; color: var(--tv-caption); margin: 0; }
.tv-dl dd { font-size: 14px; line-height: 20px; font-weight: 600; color: var(--tv-text); margin: 0; min-width: 0; }

/* ---------------------------------------------------------------- Progress */

.tv-card.tv-notice { flex-direction: row; align-items: center; gap: 16px; padding: 16px 20px; }
.tv-notice-icon { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; flex: none; border-radius: 8px; background: var(--tv-subtle); }
.tv-bullets { margin: 0; padding-left: 18px; display: flex; flex-direction: column; gap: 6px; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text); }

/* ---------------------------------------------------------------- narrower screens */

@media (max-width: 1360px) {
    .tv-sets-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .tv-sets-grid > :last-child { grid-column: 1 / -1; }
    .tv-panel { height: auto; min-height: 0; }
    .tv-panel-body { max-height: 560px; }
    .tv-print-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
    .tv-print-grid > .tv-preview-card { grid-column: 1 / -1; grid-row: 2; }
    .tv-modes { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 1100px) {
    .tv-grid-2-1, .tv-run-grid { grid-template-columns: minmax(0, 1fr); }
}

@media (max-width: 1023px) {
    body.teacher-mode { --tv-side-w: 72px; }
    .tv-side { padding: 20px 12px 16px; }
    .tv-brand { padding: 4px; justify-content: center; }
    .tv-brand-words, .tv-nav-text, .tv-nav-heading { display: none; }
    .tv-nav-heading + .tv-nav-group { margin-top: 24px; }
    .tv-nav-link { justify-content: center; padding: 0; }
    .tv-main { padding: 24px; }
    .tv-grid-3, .tv-grid-1-1, .tv-sets-grid, .tv-print-grid { grid-template-columns: minmax(0, 1fr); }
    .tv-print-grid > .tv-preview-card { grid-row: auto; }
}

@media (max-width: 1180px) {
    .tv-job .tv-btn { max-width: 100%; padding: 0 12px; white-space: normal; text-align: left; line-height: 18px; }
}

/* ---------------------------------------------------------------- Skill previews (teacher-preview.js)
   The List | Thumbnails toggle, the thumbnail grid and the floating hover preview. A sample is the
   practice card's black-and-white paper cell (screen-cell.css), drawn small: its frame stays paper
   white in dark mode too, as the cell does on the pupil side. */

.tvp-head-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.tvp-viewseg { display: inline-grid; gap: 2px; padding: 3px; border-radius: 9px; }
.tvp-viewseg > button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; height: 30px; padding: 0 10px; font-size: 13px; }
.tvp-viewseg > button svg { flex: none; color: var(--tv-caption); }
.tvp-viewseg > button[aria-checked="true"] svg { color: var(--tv-text); }

.tv-panel-body.tvp-thumbs-body { padding: 16px; }
.tvp-group { display: flex; align-items: baseline; gap: 8px; margin: 20px 4px 10px; font-size: 13px; line-height: 20px; font-weight: 700; color: var(--tv-text); }
.tvp-group:first-child { margin-top: 0; }
.tvp-group-domain { font-size: 12px; font-weight: 500; color: var(--tv-caption); }
.tvp-group .tv-tree-count { margin-left: auto; font-size: 12px; font-weight: 600; color: var(--tv-caption); font-variant-numeric: tabular-nums; }
.tvp-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(176px, 1fr)); gap: 12px; }
.tvp-card {
    display: flex; flex-direction: column; gap: 10px; min-width: 0; padding: 8px 8px 10px;
    border: 1px solid var(--tv-border); border-radius: 10px; background: var(--tv-surface);
}
.tvp-card:hover { border-color: var(--tv-control-soft); }
.tvp-card.is-added { border-color: var(--tv-selected); box-shadow: 0 0 0 1px var(--tv-selected); }
.tvp-card-body { display: flex; align-items: flex-start; gap: 8px; padding: 0 2px; }
.tvp-card-text { flex: 1; min-width: 0; }
.tvp-clamp { display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.tvp-card .tv-add {
    display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; flex: none; padding: 0; border-radius: 8px; cursor: pointer;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
}
.tvp-card .tv-add:hover { border-color: var(--tv-control); }
.tvp-card.is-added .tv-add { border-color: var(--tv-selected); background: var(--tv-selected); color: var(--tv-on-selected); }
.tvp-more { display: flex; align-items: center; justify-content: center; gap: 12px; flex-wrap: wrap; padding: 20px 0 8px; }

/* The sample frame: paper, scaled to fit. */
.tvp-frame { position: relative; overflow: hidden; background: #fff; border: 1px solid var(--tv-border); border-radius: 8px; }
.tvp-thumb { height: 128px; }
.tvp-stage {
    position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); transform-origin: center center;
    width: max-content; max-width: 400px; padding: 10px; pointer-events: none;
}
.tvp-stage .tvp-cell { display: flex; flex-direction: column; align-items: center; gap: 10px; padding: 0; text-align: center; }
.tvp-stage .tvp-instr, .tvp-stage .tvp-q { font-size: var(--mq-text); line-height: 1.3; max-width: 360px; }
.tvp-stage .tvp-visual { max-width: 400px; }
.tvp-stage .tvp-options { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; max-width: 360px; }
.tvp-stage .tvp-opt { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; min-height: 40px; padding: 4px 12px; border: 1px solid #000; border-radius: 6px; font-size: var(--mq-text); }
.tvp-stage .tvp-answerrow { display: flex; justify-content: center; }
.tvp-frame.is-unavailable { display: flex; align-items: center; justify-content: center; background: var(--tv-subtle-2); }
/* R2: a legacy print item's answer choices ("Circle the even numbers": 3 54 62 21 9 71) keep
   their gaps in a sample: the print stylesheet that spaces them is not loaded here. */
.tvp-stage .tvp-printed .opt-list { display: grid; grid-template-columns: repeat(3, auto); justify-content: center; gap: 10px 28px; margin-top: 10px; }
.tvp-stage .tvp-printed .opt-list.cols-2 { grid-template-columns: repeat(2, auto); }
.tvp-stage .tvp-printed .opt-list.cols-4 { grid-template-columns: repeat(4, auto); }
.tvp-stage .tvp-printed .opt-list.cols-5 { grid-template-columns: repeat(5, auto); }
.tvp-stage .tvp-printed .opt-list .opt { display: inline-block; min-width: 1.6em; font-size: var(--mq-text, 22px); line-height: 1.3; text-align: center; }
/* A sample too small to read at thumbnail scale (a wide place-value table) is shown as a crop of
   its top-left corner at a legible size, faded at the cut edges, instead of hairlines. */
.tvp-frame.is-cropped .tvp-stage { left: 6px; top: 6px; transform-origin: top left; }
.tvp-frame.is-cropped::after {
    content: ''; position: absolute; inset: 0; pointer-events: none;
    background: linear-gradient(to right, transparent 80%, #fff), linear-gradient(to bottom, transparent 78%, #fff);
}
.tvp-unavail { display: flex; flex-direction: column; align-items: center; gap: 6px; font-family: var(--tv-font); font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-caption); }

/* The floating preview (a child of <body>, so it carries its own box model and font). */
.tvp-pop {
    position: fixed; left: 0; top: 0; z-index: 100000; box-sizing: border-box;
    width: 344px; max-width: calc(100vw - 16px); padding: 12px;
    display: flex; flex-direction: column; gap: 12px;
    background: var(--tv-surface); border: 1px solid var(--tv-border); border-radius: 12px;
    box-shadow: 0 12px 32px rgba(20, 20, 30, .14);
    font-family: var(--tv-font); color: var(--tv-text); pointer-events: none;
}
.tvp-pop[hidden] { display: none; }
.tvp-pop *, .tvp-pop *::before, .tvp-pop *::after { box-sizing: border-box; }
html.dark body.teacher-mode .tvp-pop { box-shadow: 0 12px 32px rgba(0, 0, 0, .5); }
.tvp-pop-frame { height: 192px; }
.tvp-pop-body { padding: 0 4px 2px; }
.tvp-pop-title { font-size: 14px; line-height: 20px; font-weight: 700; color: var(--tv-text); }
.tvp-pop-desc { margin: 4px 0 0; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-text-2); }
.tvp-pop-opts { margin: 8px 0 0; padding: 6px 8px; border-radius: 6px; background: var(--tv-accent-tint); font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-text); }
.tvp-pop-opts span { font-weight: 700; margin-right: 4px; }

/* Triggers: the skill name in a set is focusable so the keyboard reaches its preview. */
.tvp-name { border-radius: 6px; }
.tv-pill[data-tvp], .tvp-name[data-tvp] { cursor: default; }

/* The (i) button: only on a touch screen. html.tvp-touch is set by teacher-preview.js from
   (any-hover) and then from the pointer actually used, so a touch laptop gets it when touched. */
.tvp-info {
    display: none; align-items: center; justify-content: center; width: 32px; height: 32px; flex: none; padding: 0;
    border: 0; border-radius: 8px; background: transparent; color: var(--tv-caption); cursor: pointer; vertical-align: middle;
}
.tvp-info[aria-expanded="true"] { background: var(--tv-accent-tint); color: var(--tv-accent); }
html.tvp-touch .tvp-info { display: inline-flex; }
html.tvp-touch .tv-skill-row .tvp-info { margin-left: auto; }
html.tvp-touch .tv-skill-name .tvp-info { width: 28px; height: 28px; margin: -4px 0 -4px 4px; }
html.tvp-touch .tv-pill .tvp-info { width: 28px; height: 28px; margin: -4px -6px -4px 0; }

/* Types of practice: "what pupils see" schematics (Run practice mode cards, the Send Mode picker).
   Neutral chrome in the teacher palette; the paper cells hold the chosen skill's sample item. */
.tvp-mode-wrap { position: relative; display: flex; min-width: 0; }
.tvp-mode-wrap > .tv-mode { flex: 1; min-width: 0; }
.tvp-mode-wrap > .tvp-info { position: absolute; right: 8px; bottom: 8px; }
.tvp-mode-frame { background: var(--tv-subtle); }
.tvp-mode { position: absolute; inset: 0; display: flex; flex-direction: column; gap: 8px; padding: 10px; font-family: var(--tv-font); }
.tvp-mtop { display: flex; align-items: center; gap: 6px; min-height: 20px; }
.tvp-mgrow { flex: 1; }
.tvp-mchip {
    display: inline-flex; align-items: center; height: 20px; padding: 0 8px; border-radius: 10px; white-space: nowrap;
    background: var(--tv-surface); border: 1px solid var(--tv-border); color: var(--tv-text-2); font-size: 10px; font-weight: 700;
}
.tvp-mchip.is-dark { background: rgba(255, 255, 255, .10); border-color: rgba(255, 255, 255, .22); color: #fff; }
.tvp-mbar { flex: 1; height: 8px; border-radius: 4px; background: var(--tv-surface); border: 1px solid var(--tv-border); overflow: hidden; }
.tvp-mbar > span { display: block; height: 100%; background: var(--tv-text-2); }
.tvp-mcell { flex: 1; min-height: 0; border-radius: 6px; }
.tvp-mbtns { display: flex; align-items: center; gap: 6px; }
.tvp-mbtns > span { width: 40px; height: 16px; border-radius: 5px; background: var(--tv-surface); border: 1px solid var(--tv-border); }
.tvp-mbtns > span.tvp-mgrow { background: none; border: 0; }
.tvp-mbtns > span.is-primary { margin-left: auto; width: 56px; background: var(--tv-accent); border-color: var(--tv-accent); }
.tvp-mbtns > span.is-wide { margin: 0 auto; width: 88px; }
.tvp-marena { display: flex; align-items: center; justify-content: center; gap: 18px; min-height: 28px; }
.tvp-mhero { width: 22px; height: 22px; border-radius: 11px; background: var(--tv-accent); }
.tvp-mboss { width: 28px; height: 28px; border-radius: 7px; background: var(--tv-text-2); }
.tvp-mvs { font-size: 10px; font-weight: 700; color: var(--tv-caption); }
.tvp-mlanes { display: flex; flex-direction: column; gap: 4px; }
.tvp-mlane { display: flex; align-items: center; gap: 6px; }
.tvp-mlane-l { width: 26px; font-size: 10px; font-weight: 700; color: var(--tv-text-2); }
.tvp-mtrack { position: relative; flex: 1; height: 14px; border-radius: 7px; background: var(--tv-surface); border: 1px solid var(--tv-border); }
.tvp-mcar { position: absolute; top: 50%; width: 18px; height: 9px; border-radius: 3px; background: var(--tv-text-2); transform: translate(-50%, -50%); }
.tvp-mcar.is-you { background: var(--tv-accent); }
.tvp-mflag { width: 3px; height: 16px; border-radius: 1px; background: var(--tv-text); }
.tvp-mwsgrid { flex: 1; min-height: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-rows: minmax(0, 1fr); gap: 6px; }
.tvp-mwscard { position: relative; display: flex; min-height: 0; padding: 12px 3px 3px; border-radius: 6px; background: var(--tv-surface); border: 1px solid var(--tv-border); }
.tvp-mwscard .tvp-mcell { border-radius: 4px; }
.tvp-mnum { position: absolute; left: 5px; top: 1px; font-size: 9px; line-height: 11px; font-weight: 700; color: var(--tv-text-2); }
.tvp-mboard { position: absolute; inset: 6px; display: flex; flex-direction: column; gap: 8px; padding: 10px; border-radius: 8px; background: #1f2023; }
.tvp-mcell-big { border-color: #1f2023; }
html.tvp-touch .tv-label .tvp-info { width: 24px; height: 24px; margin: -4px 0 -4px 4px; }
/* Six items side by side: each mini cell drops its instruction line so the item itself reads. */
.tvp-mwscard { padding-top: 11px; }
.tvp-mwscard .tvp-stage { padding: 4px; }
.tvp-mwscard .tvp-instr { display: none; }

/* ==========================================================================
   Shell pass 2 (2026-09-25): targets, legacy overlays, popover, board code,
   Send action bar, Print layout + page-type cards, teacher-launched play.
   Additive: every rule below overrides an earlier one by order, never edits it.
   ========================================================================== */

/* ---------------------------------------------------------------- legacy overlays
   .container is its own stacking context (z-index:1), which kept every legacy
   modal scrim UNDER the fixed sidebar (z 50): the sidebar stayed bright and
   clickable behind a modal. In teacher mode the container does not overlap the
   sidebar (the body is padded), so it can drop the context and let its fixed
   overlays cover the whole window. */
body.teacher-mode > .container { z-index: auto; }

/* Dark mode: white type on the light indigo accent read at about 2.6:1. The primary button
   takes the page's dark ink instead (about 7:1). */
html.dark body.teacher-mode .tv-btn-primary,
html.dark body.teacher-mode .tv-btn-primary:hover { color: var(--tv-on-selected); }

/* ---------------------------------------------------------------- 44px targets */
.tv-btn, .tv-btn-sm, .tv-btn-ghost { height: 44px; min-height: 44px; }
#teacherApp .tv-btn { min-height: 44px; }
.tv-btn.tv-btn-block { height: 48px; }
.tv-icon-btn { width: 44px; height: 44px; }
.tv-input, .tv-select { height: 44px; min-height: 44px; }
.tv-seg > button { height: 44px; }
.tvp-viewseg > button { height: 44px; }
.tv-chip { min-width: 44px; height: 44px; }
.tv-chip-sm { min-width: 44px; height: 44px; font-size: 14px; border-radius: 8px; }
.tv-letters { flex-wrap: wrap; gap: 4px; }
.tv-letters .tv-chip { width: 44px; height: 44px; font-size: 14px; }
.tv-check { min-height: 44px; }
.tv-opt-btn { height: 44px; padding: 0 12px; }
.tv-weight { height: auto; }
.tv-weight button { width: 44px; height: 44px; }
.tv-skill-row .tv-add, .tvp-card .tv-add { width: 44px; height: 44px; }
.tv-tree-btn, .tv-tree-cat { min-height: 44px; }
.tv-menu button { height: 44px; }
#teacherApp .tv-link { display: inline-flex; align-items: center; min-height: 44px; vertical-align: middle; }
.tv-cell-title.tv-link-row { padding: 12px 0; margin: -12px 0; }
.tv-pick-results button { min-height: 52px; }
html.tvp-touch .tvp-info { width: 44px; height: 44px; }
html.tvp-touch .tv-skill-name .tvp-info,
html.tvp-touch .tv-pill .tvp-info,
html.tvp-touch .tv-label .tvp-info { width: 44px; height: 44px; margin: -12px -10px -12px 0; }

/* The switch: a 52×44 hit area that draws the same 44×24 track. */
.tv-switch {
    position: relative; display: inline-block; width: 52px; height: 44px; padding: 0;
    border: 0; border-radius: 8px; background: transparent;
}
.tv-switch::before {
    content: ''; position: absolute; left: 4px; top: 10px; width: 44px; height: 24px; box-sizing: border-box;
    border-radius: 12px; border: 1px solid var(--tv-control); background: var(--tv-surface);
}
.tv-switch::after { position: absolute; left: 8px; top: 13px; transition: left .12s ease; }
.tv-switch[aria-checked="true"] { background: transparent; border-color: transparent; }
.tv-switch[aria-checked="true"]::before { background: var(--tv-selected); border-color: var(--tv-selected); }
.tv-switch[aria-checked="true"]::after { left: 26px; }
@media (prefers-reduced-motion: reduce) { .tv-switch::after { transition: none; } }

/* ---------------------------------------------------------------- skill options popover (teacher mode)
   skill-options-ui.js draws it with these classes when body.teacher-mode is on. The option
   controls carry inline styles in the app's --text/--border vocabulary, so the popover maps
   that vocabulary onto the teacher tokens. */
.tv-sko {
    --text: var(--tv-text); --text-dim: var(--tv-caption); --border: var(--tv-border);
    --bg-card: var(--tv-surface); --bg-card-light: var(--tv-subtle-2);
    position: fixed; z-index: 10050; box-sizing: border-box;
    display: flex; flex-direction: column; overflow: hidden;
    background: var(--tv-surface); color: var(--tv-text);
    border: 1px solid var(--tv-border); border-radius: 12px;
    box-shadow: 0 12px 32px rgba(20, 20, 30, .16);
    font-family: var(--tv-font);
}
html.dark body.teacher-mode .tv-sko { box-shadow: 0 12px 32px rgba(0, 0, 0, .5); }
.tv-sko *, .tv-sko *::before, .tv-sko *::after { box-sizing: border-box; }
.tv-sko.is-sheet { left: 0 !important; right: 0; bottom: 0; top: auto !important; width: auto !important; border-radius: 16px 16px 0 0; }
.tv-sko-head { display: flex; align-items: flex-start; gap: 12px; padding: 16px 12px 12px 20px; border-bottom: 1px solid var(--tv-rule); }
.tv-sko-head > div { flex: 1; min-width: 0; }
.tv-sko-title { margin: 0; font-size: 16px; line-height: 24px; font-weight: 700; color: var(--tv-text); }
.tv-sko-sum { margin: 2px 0 0; font-size: 13px; line-height: 18px; font-weight: 500; color: var(--tv-text-2); }
.tv-sko-body { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 20px 16px; }
.tv-sko-row { padding: 12px 0; border-bottom: 1px solid var(--tv-rule); }
.tv-sko-help { margin: 6px 0 0; font-size: 12px; line-height: 16px; font-weight: 500; color: var(--tv-caption); }
.tv-sko-none { margin: 16px 0 8px; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-text-2); }
.tv-sko label { min-height: 44px; font-size: 14px !important; }
.tv-sko select, .tv-sko input[type="number"] { min-height: 44px; font-size: 14px !important; border-color: var(--tv-control) !important; border-radius: 8px !important; }
.tv-sko button:not(.tv-btn):not(.tv-icon-btn) { min-height: 44px; min-width: 56px; font-size: 13px !important; font-weight: 600; color: var(--tv-text) !important; border-radius: 8px !important; }
.tv-sko input[type="checkbox"] { width: 18px !important; height: 18px !important; }
.tv-sko-sample { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.tv-sko-frame { height: 156px; }
/* R2: the sample is pinned under the title, outside the scrolling body, so it stays in view while
   the options change. The tick lists are the only thing that scrolls. */
.tv-sko-sample.is-pinned { flex: none; margin: 0; padding: 12px 20px; border-bottom: 1px solid var(--tv-rule); background: var(--tv-subtle-2); }
.tv-sko-sample.is-pinned .tv-sko-frame { height: 140px; background: var(--tv-surface); }
.tv-sko .sko-group-head { margin-top: 16px; }
.tv-sko select.tv-select { width: 100%; }
@media (max-height: 640px) { .tv-sko-sample.is-pinned .tv-sko-frame { height: 110px; } }
.tv-sko-foot { display: flex; justify-content: flex-end; gap: 8px; padding: 12px 20px 16px; border-top: 1px solid var(--tv-rule); background: var(--tv-surface); }

/* ---------------------------------------------------------------- board code overlay */
.tv-boardcode {
    position: fixed; inset: 0; z-index: 100002; overflow-y: auto;
    display: flex; align-items: center; justify-content: center; padding: 40px 24px;
    background: var(--tv-page); color: var(--tv-text); font-family: var(--tv-font);
}
.tv-boardcode *, .tv-boardcode *::before, .tv-boardcode *::after { box-sizing: border-box; }
.tv-boardcode-card {
    display: flex; flex-direction: column; align-items: center; gap: 24px; width: min(960px, 100%);
    margin: auto; padding: 48px 40px 40px; text-align: center;
    background: var(--tv-surface); border: 1px solid var(--tv-border); border-radius: 16px;
}
.tv-boardcode-kicker { margin: 0; font-size: 16px; line-height: 24px; font-weight: 600; color: var(--tv-caption); }
.tv-boardcode-name { margin: -16px 0 0; font-size: clamp(28px, 4vw, 44px); line-height: 1.2; font-weight: 700; color: var(--tv-text); overflow-wrap: anywhere; }
.tv-boardcode-steps { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: 8px; font-size: clamp(18px, 2.2vw, 24px); line-height: 1.4; font-weight: 500; color: var(--tv-text-2); }
.tv-boardcode-steps strong { color: var(--tv-text); font-weight: 700; }
.tv-boardcode-code {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 8px 0; max-width: 100%;
    padding: 20px 32px; border: 2px solid var(--tv-selected); border-radius: 16px;
    font-family: var(--tv-mono); font-size: clamp(44px, 8vw, 96px); line-height: 1.15; font-weight: 600; letter-spacing: .08em; color: var(--tv-text);
}
.tv-boardcode-code span { white-space: nowrap; }
.tv-boardcode-note { margin: 0; font-size: 14px; line-height: 20px; font-weight: 500; color: var(--tv-caption); }

/* ---------------------------------------------------------------- Send: sticky action bar */
.tv-actionbar {
    position: sticky; bottom: 0; z-index: 5; margin: 0 -40px -40px; padding: 12px 40px;
    display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap;
    background: var(--tv-surface); border-top: 1px solid var(--tv-border);
    box-shadow: 0 -4px 16px rgba(20, 20, 30, .06);
}
.tv-actionbar[hidden] { display: none !important; }
.tv-actionbar-text { flex: 1; min-width: 0; }
.tv-actionbar-text .tv-h3, .tv-actionbar-text .tv-cap { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.tv-actionbar .tv-row { flex-wrap: nowrap; }
@media (max-width: 1023px) { .tv-actionbar { margin: 0 -24px -24px; padding: 12px 24px; } }

/* ---------------------------------------------------------------- Print: preview beside the controls
   ≥1361px: three columns (what · preview · setup). 1024–1360px: what + setup on the left, the
   preview on the right. At desktop widths the preview sticks while the controls scroll. */
.tv-print-grid { grid-template-areas: "what preview setup"; }
.tv-print-grid > .tv-print-what { grid-area: what; }
.tv-print-grid > .tv-preview-card { grid-area: preview; position: sticky; top: 24px; align-self: start; }
.tv-print-grid > #tvSetup { grid-area: setup; }
@media (max-width: 1360px) {
    .tv-print-grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); grid-template-areas: "what preview" "setup preview"; }
    .tv-print-grid > .tv-preview-card { grid-column: auto; grid-row: auto; }
}
@media (max-width: 1023px) {
    .tv-print-grid { grid-template-columns: minmax(0, 1fr); grid-template-areas: "what" "preview" "setup"; }
    .tv-print-grid > .tv-preview-card { position: static; }
}

/* Page-type cards: a small drawing of the page, a name and one line. */
.tv-ptypes { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 8px; }
.tv-ptype {
    display: flex; align-items: center; gap: 12px; min-height: 76px; padding: 10px 12px; border-radius: 10px; cursor: pointer; text-align: left;
    border: 1px solid var(--tv-control-soft); background: var(--tv-surface); color: var(--tv-text);
}
.tv-ptype:hover { border-color: var(--tv-control); }
.tv-ptype[aria-checked="true"] { border-color: var(--tv-selected); box-shadow: 0 0 0 1px var(--tv-selected); }
.tv-ptype svg { flex: none; }
.tv-ptype .tv-radio-text { margin-top: 2px; }
.tv-fields-cols { display: grid; grid-template-columns: repeat(2, minmax(0, 160px)); gap: 12px; }

/* The classic mixed worksheet (the older automatic layout) and its extras. */
.tv-extras { border-top: 1px solid var(--tv-rule); }
.tv-extras > summary {
    display: flex; align-items: center; gap: 8px; min-height: 52px; padding: 0 24px; cursor: pointer; list-style: none;
    font-size: 14px; line-height: 20px; font-weight: 700; color: var(--tv-text);
}
.tv-extras > summary::-webkit-details-marker { display: none; }
.tv-extras > summary svg { flex: none; color: var(--tv-caption); transition: transform .15s ease; }
.tv-extras[open] > summary svg { transform: rotate(90deg); }
.tv-extras-body { padding: 0 24px 24px; display: flex; flex-direction: column; gap: 12px; }

/* The classic worksheet preview (#printPreviewContainer) opened from the Print screen gets a
   teacher toolbar in place of the pupil-app one. */
.tv-classic-bar { display: none; }
body.teacher-mode .tv-classic-bar {
    position: sticky; top: 0; z-index: 2; display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap;
    padding: 12px 24px; background: var(--tv-surface); border-bottom: 1px solid var(--tv-border);
    font-family: var(--tv-font); color: var(--tv-text);
}
body.teacher-mode #printPreviewContainer .print-preview-toolbar { display: none; }

/* ---------------------------------------------------------------- teacher-launched play views */
/* The adaptive chip reads "L3 · Add within…" beside a Level K skill: on the board it reads as a
   grade level and repeats the skill badge. The teacher's board shows the skill badge only. */
body.teacher-mode #adaptiveLevelChip { display: none !important; }
/* Dark mode: the online worksheet kept a white page behind dark cards. */
html.dark body.teacher-mode #worksheetView.online-edition { background: var(--tv-page); color: var(--tv-text); }
html.dark body.teacher-mode #worksheetView.online-edition .game-header { background: var(--tv-surface); border-color: var(--tv-border); color: var(--tv-text); }

/* Page-type picker, every working role (2026-09-25 merge): quiet groups of compact cards. */
.tv-ptype-groups { display: flex; flex-direction: column; gap: 12px; }
.tv-ptype-group { display: flex; flex-direction: column; gap: 6px; }
.tv-ptype-h { font-size: 12px; line-height: 16px; font-weight: 600; color: var(--tv-caption); }
.tv-ptype-groups .tv-ptypes { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); gap: 6px; }
.tv-ptype-groups .tv-ptype { min-height: 60px; padding: 8px 10px; gap: 10px; }
.tv-ptype-groups .tv-ptype .tv-radio-title { font-size: 13px; line-height: 18px; }
.tv-ptype-thumb { flex: none; color: var(--tv-text-2); }
.tv-ptype[aria-checked="true"] .tv-ptype-thumb { color: var(--tv-text); }
.tv-ptype.is-unfit { border-style: dashed; }
/* A page type withheld for the chosen skills (Stretch with no open problem yet): shown, not choosable. */
.tv-ptype[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
.tv-ptype-why {
    display: flex; align-items: flex-start; gap: 8px; margin: 8px 0 0; padding: 10px 12px;
    border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-subtle-2);
    font-size: 13px; line-height: 18px; font-weight: 500; color: var(--tv-text);
}
.tv-ptype-why svg { flex: none; margin-top: 1px; color: var(--tv-caption); }
.tv-fits-warn { display: flex; align-items: flex-start; gap: 8px; margin-top: 8px; padding: 8px 10px; border: 1px solid var(--tv-border); border-radius: 8px; background: var(--tv-subtle-2); color: var(--tv-text); }
.tv-fits-warn svg { flex: none; color: var(--tv-caption); }

/* R2 Print: the chosen page type as one card with Change (the grid opens on demand), the plain
   fits line with its "Why?" disclosure, and the preview first on narrow screens. */
.tv-ptype-now { display: flex; align-items: center; gap: 12px; }
.tv-ptype-now > .tv-ptype { flex: 1 1 auto; min-width: 0; }
.tv-ptype.is-static { cursor: default; min-height: 60px; padding: 8px 10px; gap: 10px; border-color: var(--tv-selected); box-shadow: 0 0 0 1px var(--tv-selected); }
.tv-ptype.is-static:hover { border-color: var(--tv-selected); }
.tv-ptype.is-static .tv-ptype-thumb { color: var(--tv-text); }
.tv-ptype.is-static.is-unfit { border-style: dashed; }
.tv-ptype-now + .tv-ptype-groups { margin-top: 12px; }
.tv-seg > button[aria-disabled="true"] { opacity: .45; cursor: not-allowed; }
.tv-cap-why { display: flex; align-items: flex-start; gap: 6px; }
.tv-cap-why svg { flex: none; margin-top: 1px; }
.tv-fits { font-size: 14px; line-height: 20px; }
.tv-fits-line { display: block; color: var(--tv-text); font-weight: 600; }
.tv-fits-why > summary {
    display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; cursor: pointer;
    color: var(--tv-accent); font-weight: 600; text-decoration: underline; text-underline-offset: 2px;
}
.tv-fits-why ul { margin: 0; padding-left: 20px; font-size: 13px; line-height: 18px; color: var(--tv-text-2); }
.tv-fits-why li + li { margin-top: 4px; }
@media (max-width: 1023px) {
    .tv-print-grid { grid-template-areas: "preview" "what" "setup"; }
}

/* critic r2 (R2-5): a segment whose label is longer than its share ("After each page" at 1366) wraps
   inside its 44 px pill instead of running past it. Additive. */
.tv-seg.tv-seg-wrap > button { white-space: normal; line-height: 16px; min-height: 44px; height: auto; padding: 2px 6px; }
/* Owner 2026-10-03: the options popover DOCKS beside the print preview (over the settings column), so the preview page
   stays in view and updates live; at narrow widths it is a bottom sheet over the lower half. Additive. */
.tv-sko.is-docked { border-radius: 12px; }
.tv-sko.is-halfsheet { left: 0 !important; right: 0; bottom: 0; top: auto !important; width: auto !important; border-radius: 16px 16px 0 0; }
.tv-sko .sko-tip-text { background: var(--tv-subtle-2); color: var(--tv-text); }
.tv-sko .sko-tip { color: var(--tv-text-2) !important; border-color: var(--tv-control); }
/* The sample is a whole row, never the phone's swipe strip (owner 2026-10-03). */
.tv-sko-frame .k2-swipe-cues { display: none !important; }
.tv-sko-frame [data-mq-swiperow] { overflow: visible !important; }
/* the count-by row reads as one sentence: its drop-downs size to their words, not the panel's width */
.tv-sko .sko-row-line select.tv-select { width: auto; flex: 0 1 auto; min-width: 0; max-width: 100%; }
/* critic countby-arrows r1 D6 (2026-10-09): the sample row is never capped at the stage's width, so the stage measures the
   whole row and fit() scales it inside the frame instead of clipping its last box. Additive. */
.tv-sko-frame :is(.tvp-visual, .k2-twin, .k2-countrow, .k2-countrow-frame, [data-mq-swiperow]):has(.k2-countrow-body) { max-width: none !important; width: max-content !important; min-width: 0 !important; }
.tv-sko-frame .k2-countrow-frame [data-mq-swiperow] { flex: none !important; }
/* critic search-terms r5 U-E (2026-10-09): the Sets search box keeps the line for its "Showing results for ..." notice
   reserved at all times, so the Level row never jumps when a correction appears or goes. Additive. */
.tv-panel-head .tv-search:has(> #tvSkillSearch) { margin-bottom: 12px; }
/* critic answer-key r4 (R4-1, 2026-10-10): the Print button keeps a short label; the double-sided sheet count sits as a
   caption directly under it. If a label is ever longer than the column, it wraps inside a taller button instead of
   being clipped at both ends. Additive. */
.tv-print-sheets { margin: -4px 0 0; text-align: center; }
.tv-btn.tv-btn-block[data-act="print"], #teacherApp .tv-btn.tv-btn-block[data-act="print"] { white-space: normal; height: auto; min-height: 48px; padding: 6px 16px; text-align: center; }
.tv-btn.tv-btn-block[data-act="print"] > span { min-width: 0; overflow-wrap: anywhere; }
.tv-btn.tv-btn-block[data-act="print"] .tv-print-l { white-space: nowrap; }
