:root {
  /* ACA fallback for pre-bundle first paint. Source of truth is the TS
     base16 theme objects (client/themes/) — the applier sets these same
     vars plus derived tints. */
  --base00: #f6f4ec;
  --base01: #ffffff;
  --base02: #e3dfd2;
  --base03: #6b6759;
  --base04: #8a867a;
  --base05: #1e2818;
  --base06: #f1efe4;
  --base07: #ffffff;
  --base08: #dc2626;
  --base09: #d97706;
  --base0A: #c9a95c;
  --base0B: #43582e;
  --base0C: #0e7490;
  --base0D: #2f6fed;
  --base0E: #7c5cff;
  --base0F: #f7ecc8;
  --on-0B: #ffffff;
  --on-0A: #1e2818;
  --soft08: #fae1e1;
  --soft09: #faecdc;
  --soft0B: #e5e8e2;
  --soft0C: #ddecef;
  --soft0E: #ede8ff;
  --shade0B: #2a371d;
  --ring0B: rgba(67, 88, 46, 0.25);
  --glow0B: rgba(67, 88, 46, 0.45);
  --edge-on-accent: rgba(255, 255, 255, 0.6);
  --radius: 16px;
  /* Design-system geometry tokens (see design-system spec).
     Canonical interactive geometry comes from the topbar buttons:
     2px borders + 10px radius. 1px is reserved for hairlines. */
  --border-thin: 1px;
  --border-std: 2px;
  --border-thick: 3px;
  --radius-sm: 8px;
  --radius-md: 10px;
  --radius-lg: 12px;
  --radius-xl: 16px;
  --radius-pill: 999px;
}
* {
  box-sizing: border-box;
}
body {
  margin: 0;
  font-family: system-ui, -apple-system, sans-serif;
  background: var(--base00);
  color: var(--base05);
}
.topbar {
  display: flex;
  gap: 1rem;
  align-items: center;
  padding: 0.75rem 1rem;
  background: var(--base0B);
  color: var(--on-0B);
  position: sticky;
  top: 0;
  z-index: 5;
}
.topbar h1 {
  font-size: 1.25rem;
  margin: 0;
}
.topbar .muted-small {
  color: inherit;
  opacity: 0.8;
}
/* Visually-hidden accessible name (TopBar title lives in the lockup image). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
.brand-light-wrap {
  display: flex;
  justify-content: center;
  margin-bottom: 1rem;
}
.brand-light {
  height: 64px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  display: block;
}
.brand-loading {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}
.brand-emblem {
  height: 64px;
  width: 64px;
}
.brand-owl {
  height: 48px;
  width: auto;
}
.topbar button {
  border: var(--border-std) solid var(--edge-on-accent);
  /* One explicit height for every topbar action (Sign out is the
   * reference): icon glyphs (18px SVG) and text line boxes are different
   * heights, so content-driven sizing always mismatched them by a pixel
   * or two. Fixed height + centered content makes all four identical by
   * construction; horizontal padding still comes from .btn. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.5rem;
  padding-top: 0;
  padding-bottom: 0;
  line-height: 1;
  white-space: nowrap;
}
/* Narrow-viewport actions menu: at or below 480px the full action row
 * collapses into one hamburger so four actions can never overflow a
 * 390px bar. Desktop keeps the direct row: .topbar-actions is
 * display:contents there, laying buttons out exactly as before. */
.topbar-actions {
  display: contents;
}
#topbar-menu {
  display: none;
}
/* Small screens: title shrinks, kid context truncates with ellipsis, and
   actions live behind the hamburger — the bar stays one row without
   overflowing. Below ~360px it may wrap into two clean rows instead. */
@media (max-width: 480px) {
  .topbar {
    gap: 0.5rem;
    padding: 0.6rem 0.75rem;
  }
  .topbar h1 {
    font-size: 1rem;
  }
  .topbar .muted-small {
    min-width: 0;
    flex: 0 1 auto;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  .topbar button {
    flex: 0 0 auto;
    white-space: nowrap;
    padding: 0 0.65rem;
    height: 2.375rem;
    font-size: 0.85rem;
  }
  /* Hamburger owns the narrow bar: one menu button plus title/context
   * always fits. The panel drops below the sticky header; actions stack
   * full-width with their labels visible (icon-only on desktop). */
  #topbar-menu {
    display: inline-flex;
  }
  .topbar-actions {
    display: none;
    position: absolute;
    top: 100%;
    right: 0.5rem;
    flex-direction: column;
    align-items: stretch;
    gap: 0.5rem;
    background: var(--base0B);
    border: var(--border-std) solid var(--edge-on-accent);
    border-radius: var(--radius-md);
    padding: 0.5rem;
    margin-top: 0.25rem;
    /* Hug the longest entry instead of forcing a wide panel: buttons
     * size to content, all centered, so every row reads the same. */
    min-width: 0;
    width: max-content;
    max-width: calc(100vw - 1rem);
    z-index: 20;
  }
  .topbar-actions[data-open="true"] {
    display: flex;
  }
  .topbar-actions .btn {
    width: 100%;
    justify-content: center;
  }
  /* Icon-only actions borrow their aria-label as the visible menu label
   * (text buttons already show theirs). The 0.25em gap matches a normal
   * inter-word space, so icon rows space exactly like "⇄ Profiles".
   * Screen readers keep announcing the aria-label, so the name is
   * identical in both channels. */
  .topbar-actions .btn[aria-label]::after {
    content: attr(aria-label);
    margin-left: 0.25em;
  }
}
@media (max-width: 360px) {
  .topbar {
    flex-wrap: wrap;
  }
}
.view {
  max-width: 720px;
  margin: 0 auto;
  padding: 1rem;
}
.card {
  background: var(--base01);
  border-radius: var(--radius);
  padding: 1rem;
  margin-bottom: 1rem;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
}
.flash {
  min-height: 220px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: clamp(4rem, 20vw, 8rem);
  border: var(--border-thick) solid var(--base0B);
  border-radius: var(--radius);
  margin: 1rem 0;
  cursor: pointer;
  user-select: none;
  text-align: center;
  padding: 1rem;
}
.face small {
  display: block;
  font-size: 1rem;
}
.grade-row {
  display: flex;
  gap: 1rem;
}
.bigbtn {
  flex: 1;
  min-height: 64px;
  font-size: 1.25rem;
  border-radius: var(--radius);
  border: none;
  color: var(--on-0B);
  cursor: pointer;
}
.good {
  background: var(--base0B);
}
.miss {
  background: var(--base09);
}
.row {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.5rem 0;
}
input,
select,
button {
  font-size: 1rem;
  padding: 0.6rem 0.8rem;
  border-radius: var(--radius-md);
  border: var(--border-std) solid var(--base02);
}
input,
select {
  background: var(--base01);
  color: var(--base05);
}
button {
  cursor: pointer;
  color: inherit;
  background: transparent;
}
.navbtn {
  background: var(--base0B);
  color: var(--on-0B);
  border: none;
}
.shelf {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}
.badge {
  background: var(--base0A);
  color: var(--on-0A);
  border-radius: var(--radius-pill);
  padding: 0.4rem 0.8rem;
}
.muted {
  color: var(--base03);
}
.seg {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  background: var(--base02);
  border-radius: var(--radius-lg);
  padding: 4px;
  margin-bottom: 1rem;
}
.seg button {
  border: 0;
  background: transparent;
  border-radius: var(--radius-sm);
  padding: 0.6rem;
  font-weight: 700;
  color: var(--base03);
  min-height: 48px;
}
.seg button[aria-selected="true"] {
  background: var(--base01);
  color: var(--base05);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15);
}
#signin h2,
#onboarding h2 {
  margin: 0.1rem 0 0.25rem;
  font-size: 1.25rem;
}
#signin .sub,
#onboarding .sub {
  color: var(--base03);
  font-size: 0.9rem;
  margin: 0 0 1rem;
}
#signin label,
#onboarding label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  margin: 0.8rem 0 0.3rem;
}
.passwrap {
  position: relative;
}
.passwrap input {
  padding-right: 4.2rem;
}
.passwrap button {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  border: 0;
  background: var(--soft0B);
  border-radius: var(--radius-sm);
  padding: 0.4rem 0.7rem;
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--base0B);
  cursor: pointer;
}
#signin .hint,
#onboarding .hint {
  font-size: 0.8rem;
  color: var(--base03);
  margin: 0.35rem 0 0;
  min-height: 1.1em;
}
#signin .alert,
#onboarding .alert {
  display: none;
  background: var(--soft08);
  border: var(--border-thin) solid var(--base08);
  color: var(--base08);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.8rem;
  font-size: 0.88rem;
  margin-top: 0.9rem;
}
#signin .alert.show,
#onboarding .alert.show {
  display: block;
}
#signin .alert .linkbtn,
#onboarding .alert .linkbtn {
  background: none;
  border: none;
  color: var(--base0D);
  font-weight: 700;
  cursor: pointer;
  font-size: 0.88rem;
  padding: 0.2rem;
}
#signin .alert .linkbtn:hover,
#onboarding .alert .linkbtn:hover {
  text-decoration: underline;
}
.linkrow {
  text-align: center;
  margin-top: 0.8rem;
  font-size: 0.88rem;
  color: var(--base03);
}
.linkrow button {
  background: none;
  border: none;
  color: var(--base0D);
  font-weight: 700;
  cursor: pointer;
  font-size: 0.88rem;
  padding: 0.2rem;
}
.linkrow button:hover {
  text-decoration: underline;
}
.codes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
}
.codes input {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-align: center;
  font-weight: 800;
}
@media (max-width: 400px) {
  .codes {
    grid-template-columns: 1fr;
  }
}
.showbtn {
  float: right;
  font-size: 0.8rem;
  padding: 0.3rem 0.6rem;
}
.meter {
  height: 6px;
  background: var(--base02);
  border-radius: var(--radius-pill);
  margin-top: 0.5rem;
  overflow: hidden;
}
.meter i {
  display: block;
  height: 100%;
  background: var(--base0B);
  border-radius: var(--radius-pill);
  transition: width 0.2s;
}
/* Live password-requirements checklist (signup, admin setup, pw change). */
.pw-reqs {
  list-style: none;
  margin: 0.45rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.15rem;
  font-size: 0.8rem;
  color: var(--base03);
}
.pw-reqs li.met {
  color: var(--base05);
  font-weight: 600;
}
.divider {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--base03);
  font-size: 0.85rem;
  margin: 1.2rem 0 0.4rem;
}
.divider::before,
.divider::after {
  content: "";
  flex: 1;
  height: 1px;
  background: var(--base02);
}
#signin input,
#onboarding input,
#onboarding select {
  display: block;
  width: 100%;
  margin-top: 0.35rem;
}
.kidlist button {
  margin: 0.25rem;
  min-height: 48px;
}
[hidden] {
  /* biome-ignore lint/complexity/noImportantStyles: guard the hidden attribute against display overrides */
  display: none !important;
}
/* Family-first board (v6 split + expandable kids): two-column Family pairing + Kids list. */
.split {
  display: grid;
  grid-template-columns: minmax(300px, 380px) minmax(0, 1fr);
  gap: 1rem;
  align-items: start;
  margin-top: 0.8rem;
}
.panel {
  background: var(--base01);
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 1rem;
  min-width: 0;
}
.panel h3 {
  margin: 0.1rem 0 0.4rem;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--base03);
}
/* Reusable code component — same box + button row for family + every kid. */
.codebox {
  background: var(--soft0B);
  border: var(--border-std) dashed var(--base0B);
  border-radius: var(--radius-lg);
  padding: 0.7rem 0.9rem;
  text-align: center;
  margin: 0.5rem 0;
}
.codebox .codelabel {
  font-size: 0.72rem;
  color: var(--base03);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.codebox .code {
  display: block;
  font-size: 1.6rem;
  font-weight: 800;
  letter-spacing: 0.06em;
  margin-top: 0.1rem;
}
.codebox.small .code {
  font-size: 1.25rem;
}
.codeactions {
  display: flex;
  gap: 0.5rem;
  margin: 0.55rem 0;
}
.codeactions button {
  flex: 1;
  min-width: 0;
}
/* Expandable kid rows: name links to progress, chevron toggles details. */
.kid {
  border-top: var(--border-thin) solid var(--base02);
}
.kid-head {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  width: 100%;
  padding: 0.65rem 0.2rem;
  font-size: 1rem;
  color: inherit;
}
.kid-id {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  background: transparent;
  border: none;
  text-align: left;
  padding: 0;
  font-size: 1rem;
  color: var(--base0B);
  flex: 0 0 auto;
  min-width: 0;
}
.kid-id .avatar {
  font-size: 1.4rem;
  background: var(--base01);
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-md);
  width: 38px;
  height: 38px;
  display: grid;
  place-items: center;
  flex: 0 0 38px;
}
.kid-id .name {
  font-weight: 700;
  white-space: nowrap;
}
.kid-id:hover .name {
  text-decoration: underline;
}
.kid-expand {
  flex: 0 0 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: transparent;
  border: none;
  padding: 0;
  font-size: 1rem;
  color: inherit;
}
.kid-pair {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  margin-left: auto;
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-pill);
  padding: 0.2rem 0.65rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--base0B);
  background: var(--base01);
  white-space: nowrap;
  cursor: pointer;
}
.kid-pair:hover {
  border-color: var(--base0B);
}
.kid-pair:focus-visible {
  outline: 2px solid var(--base0D);
  outline-offset: 2px;
}
/* Edit hint: small pencil at the top right of the kid name — the
   name-and-avatar control opens the edit modal. */
.edit-hint {
  display: inline-block;
  vertical-align: super;
  margin-left: 0.2rem;
  opacity: 0.75;
}
.edit-hint svg {
  display: block;
  width: 0.65em;
  height: 0.65em;
}
.kid-head .chev {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-pill);
  padding: 0.2rem 0.65rem;
  font-size: 0.78rem;
  font-weight: 700;
  color: var(--base0B);
  background: var(--base01);
  white-space: nowrap;
}
.kid-head .chev-glyph {
  display: inline-block;
  transition: transform 0.15s;
  font-size: 0.75rem;
}
.kid[data-open="1"] .kid-head .chev-glyph {
  transform: rotate(180deg);
}
.kid-expand:hover .chev {
  border-color: var(--base0B);
}
.kid-expand:focus-visible .chev {
  outline: 2px solid var(--base0D);
  outline-offset: 2px;
}
.proglink {
  background: none;
  border: none;
  color: var(--base0D);
  font-size: 0.9rem;
  font-weight: 600;
  padding: 0.6rem 0 0;
  cursor: pointer;
  text-align: left;
}
.proglink:hover {
  text-decoration: underline;
}
.kid-body {
  display: none;
  padding: 0.1rem 0.2rem 0.8rem 3.2rem;
}
.kid[data-open="1"] .kid-body {
  display: block;
}
.setgrid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.45rem;
  margin-top: 0.4rem;
}
.setbtn {
  min-width: 0;
}
.setbtn[aria-pressed="true"] {
  background: var(--soft0B);
  border-color: var(--base0B);
}
.setbtn[aria-pressed="false"] {
  background: var(--base01);
}
.copied {
  color: var(--base0B);
  font-size: 0.82rem;
}
.copied.err {
  color: var(--base08);
}
.addrow {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.addrow input {
  flex: 2 1 140px;
  min-width: 0;
}
.addrow select {
  flex: 1 1 110px;
  min-width: 0;
}
.checkrow {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  font-size: 0.88rem;
  color: var(--base03);
  margin: 0.55rem 0 0;
}
.checkrow input {
  width: 1.1rem;
  height: 1.1rem;
  accent-color: var(--base0B);
}
/* Direction-A dashboard shell: sidebar nav, one visible section at a time. */
.shell {
  display: grid;
  grid-template-columns: 230px minmax(0, 1fr);
  align-items: start;
}
/* Wide screens: center the content card on the viewport, not the
   sidebar+content pair. The capped shell shifts left by half the 230px
   sidebar column so the card lands on viewport center with the sidebar
   glued to its left. `relative` + `left` (never transform) so fixed
   modals (.modal-veil) keep their viewport anchoring. Breakpoint keeps
   the shifted shell clear of the left viewport edge. */
@media (min-width: 1640px) {
  .shell {
    max-width: 1400px;
    margin: 0 auto;
    position: relative;
    left: -115px;
  }
}
.side {
  background: var(--base01);
  border-radius: var(--radius);
  padding: 0.75rem;
  position: sticky;
  top: 76px;
  margin: 1rem 0 1rem 1rem;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
  min-width: 0;
}
.side nav {
  display: grid;
  gap: 0.25rem;
}
.side nav button {
  display: block;
  text-align: left;
  padding: 0.6rem 0.7rem;
  border-radius: var(--radius-md);
  border: var(--border-thin) solid transparent;
  background: transparent;
  font-weight: 600;
}
.side nav button[aria-current="page"] {
  background: var(--base0B);
  color: var(--on-0B);
}
.main {
  padding: 1rem;
  min-width: 0;
}
#parent-shell .view {
  display: none;
  max-width: 1140px;
  margin: 0 auto 1rem;
}
#parent-shell .view.active {
  display: block;
}
/* Admin console reuses the parent one-visible-section shell. */
#admin-shell .view {
  display: none;
  max-width: 1140px;
  margin: 0 auto 1rem;
}
#admin-shell .view.active {
  display: block;
}
.kidrow,
.soundrow {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  flex-wrap: wrap;
  padding: 0.6rem 0;
  border-top: var(--border-thin) solid var(--base02);
}
.pill {
  font-size: 0.75rem;
  background: var(--soft0B);
  border: var(--border-thin) solid var(--base0B);
  color: var(--base0B);
  border-radius: var(--radius-pill);
  padding: 0.15rem 0.55rem;
}
.pill.seed {
  background: var(--soft0B);
  border-color: var(--base0B);
  color: inherit;
}
.pill.override {
  background: var(--soft09);
  border-color: var(--base09);
  color: inherit;
}
.audio-btn {
  min-height: 40px;
}
/* Sounds master-detail: toolbar + grouped list + detail inside the existing card. */
.sounds-toolbar {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.6rem 0 0.8rem;
  align-items: center;
}
.sounds-toolbar input,
.sounds-toolbar select {
  font-size: 0.92rem;
  padding: 0.55rem 0.7rem;
  background: var(--base01);
  max-width: 100%;
}
.sounds-toolbar .count {
  color: var(--base03);
  font-size: 0.82rem;
  margin-left: auto;
}
.sounds-split {
  display: grid;
  grid-template-columns: 290px minmax(0, 1fr);
  gap: 0.8rem;
  align-items: start;
  min-width: 0;
}
.sounds-panel {
  background: var(--base01);
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 0.8rem;
  min-width: 0;
}
.sounds-list {
  max-height: 600px;
  overflow: auto;
  min-width: 0;
}
.sounds-group {
  font-size: 0.72rem;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--base03);
  position: sticky;
  top: 0;
  background: var(--base01);
  padding: 0.45rem 0.2rem 0.25rem;
}
.sounds-group .n {
  font-weight: 400;
  text-transform: none;
  letter-spacing: 0;
}
.sounds-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.5rem 0.6rem;
  border-radius: var(--radius-md);
  border: var(--border-thin) solid transparent;
  background: transparent;
  text-align: left;
  width: 100%;
  font-size: 0.93rem;
  min-width: 0;
  cursor: pointer;
}
.sounds-item .dot {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-pill);
  background: var(--base0B);
  flex: 0 0 10px;
}
.sounds-item.over .dot {
  background: var(--base09);
}
.sounds-item .letters {
  font-weight: 800;
  font-size: 1.05rem;
  overflow: hidden;
  text-overflow: ellipsis;
}
.sounds-item .ipa {
  color: var(--base03);
  font-size: 0.78rem;
  margin-left: auto;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 45%;
}
.sounds-item[aria-selected="true"] {
  background: var(--base0B);
  color: var(--on-0B);
}
.sounds-item[aria-selected="true"] .ipa {
  opacity: 0.8;
}
.sounds-detail-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  flex-wrap: wrap;
  min-width: 0;
}
.sounds-settag {
  font-size: 0.72rem;
  background: var(--soft0C);
  border: var(--border-thin) solid var(--base0C);
  color: var(--base0C);
  border-radius: var(--radius-pill);
  padding: 0.15rem 0.55rem;
  white-space: nowrap;
}
.sounds-letters-big {
  font-size: 2.1rem;
  font-weight: 800;
  line-height: 1;
}
.sounds-sub {
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 0.75rem 0.8rem;
  margin-top: 0.65rem;
  background: var(--base01);
  min-width: 0;
}
.sounds-sub-top {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.sounds-sub-top h3 {
  margin: 0;
  font-size: 1rem;
}
.sounds-now {
  font-size: 0.8rem;
  color: var(--base03);
}
.sounds-now b {
  color: var(--base05);
}
.sounds-controls {
  display: grid;
  grid-template-columns: repeat(3, auto);
  gap: 0.45rem;
  justify-content: start;
  margin-top: 0.55rem;
}
.sounds-restore {
  background: none;
  border: none;
  color: var(--base0D);
  font-size: 0.83rem;
  padding: 0.3rem 0;
  cursor: pointer;
  text-decoration: underline;
}
.sounds-pager {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 1rem;
  gap: 0.5rem;
}
.muted-small {
  color: var(--base03);
  font-size: 0.85rem;
}
input.surname {
  max-width: 180px;
}
@media (max-width: 480px) {
  .grade-row {
    flex-direction: column;
  }
  .flash {
    min-height: 180px;
  }
  .addrow input,
  .addrow select {
    flex: 1 1 100%;
  }
  .kid-body {
    padding-left: 0.2rem;
  }
}
/* Family split → single column ≤900px; kid stats wrap below name ≤560px. */
@media (max-width: 900px) {
  .split {
    grid-template-columns: minmax(0, 1fr);
  }
}
@media (max-width: 560px) {
  .kid-head {
    gap: 0.5rem;
  }
}
/* Mid widths (tablet portrait ~768px, narrow desktop): sidebar goes top FIRST,
   then list/detail share the freed width instead of triple-squeezing. */
@media (max-width: 1024px) {
  .shell {
    grid-template-columns: minmax(0, 1fr);
  }
  .side {
    position: static;
    margin: 1rem 1rem 0;
  }
  .side nav {
    grid-auto-flow: column;
    grid-template-columns: none;
    overflow-x: auto;
  }
  .side nav button {
    white-space: nowrap;
  }
  .sounds-split {
    grid-template-columns: 240px minmax(0, 1fr);
  }
}
/* Phones: single column. Sounds list becomes a grouped tile grid (no tall
   triple column), detail takes full width, sound buttons go 2-up touch targets. */
@media (max-width: 700px) {
  .main {
    padding: 0.75rem;
  }
  .sounds-split {
    grid-template-columns: minmax(0, 1fr);
  }
  .sounds-list {
    max-height: 220px;
  }
  .sounds-list.tiles {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
    gap: 0.35rem;
    align-content: start;
  }
  .sounds-list.tiles .sounds-group {
    grid-column: 1 / -1;
    position: static;
  }
  .sounds-list.tiles .sounds-item {
    flex-direction: column;
    gap: 0.15rem;
    border-color: var(--base02);
    background: var(--base01);
    padding: 0.5rem 0.3rem;
    text-align: center;
  }
  .sounds-list.tiles .sounds-item .ipa {
    display: none;
  }
  .sounds-list.tiles .sounds-item .dot {
    width: 8px;
    height: 8px;
  }
  .sounds-controls {
    grid-template-columns: 1fr 1fr;
  }
  .sounds-controls .btn {
    min-height: 44px;
    font-size: 0.9rem;
  }
  .sounds-toolbar .count {
    margin-left: 0;
  }
}
/* Family kid rows: name links to progress, Pair opens the pair modal,
   Details toggles the expanded body. */
.kidline {
  display: flex;
  gap: 0.5rem;
  align-items: center;
}
.kidline .kid-head {
  flex: 1 1 auto;
  min-width: 0;
  width: auto;
}
/* Progress redesign (v3): one kid at a time — switcher, KPIs, charts, toolbar, detail table. */
.pg-switch {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 0.4rem 0 0.8rem;
}
.pg-switch button {
  display: flex;
  gap: 0.5rem;
  align-items: center;
  border: var(--border-std) solid var(--base02);
  background: var(--base01);
  border-radius: var(--radius-pill);
  padding: 0.45rem 0.9rem 0.45rem 0.5rem;
  font-weight: 700;
}
.pg-switch button.on {
  border-color: var(--base0B);
  background: var(--base0B);
  color: var(--on-0B);
}
.pg-switch button.on .streak {
  background: var(--edge-on-accent);
  color: var(--on-0B);
}
.pg-switch .streak {
  background: var(--base0A);
  color: var(--on-0A);
  border-radius: var(--radius-pill);
  padding: 0.1rem 0.5rem;
  font-size: 0.8rem;
}
.pg-kpis {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem;
  margin: 0.6rem 0;
}
.pg-kpi {
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 0.7rem 0.8rem;
  background: var(--base01);
}
.pg-kpi .v {
  font-size: 1.5rem;
  font-weight: 800;
}
.pg-kpi .l {
  font-size: 0.75rem;
  color: var(--base03);
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.pg-kpi.g {
  background: var(--soft0B);
  border-color: var(--base0B);
}
.pg-kpi.a {
  background: var(--soft09);
  border-color: var(--base09);
}
.pg-kpi.r {
  background: var(--soft08);
  border-color: var(--base08);
}
.pg-kpi.b {
  background: var(--soft0C);
  border-color: var(--base0C);
}
.pg-charts {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.6rem;
  margin: 0.6rem 0;
  align-items: stretch;
}
.pg-chartbox {
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 0.7rem;
  background: var(--base01);
  min-width: 0;
}
.pg-chartbox.pg-mastery {
  grid-column: span 1;
  text-align: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.pg-chartbox.pg-week {
  grid-column: span 3;
  display: flex;
  flex-direction: column;
}
.pg-chartbox.pg-week .pg-weekchart {
  margin-top: auto;
}
.pg-donut {
  width: 150px;
  height: 150px;
  border-radius: 50%;
  margin: 0.3rem auto;
  display: grid;
  place-items: center;
}
.pg-donut > div {
  background: var(--base01);
  border-radius: 50%;
  width: 104px;
  height: 104px;
  display: grid;
  place-items: center;
  text-align: center;
}
.pg-bars {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  height: 110px;
  padding: 0.4rem 0.2rem;
  border-bottom: var(--border-std) solid var(--base02);
}
.pg-bars div {
  flex: 1;
  background: linear-gradient(180deg, var(--base0A), var(--base0B));
  border-radius: 6px 6px 0 0;
  min-height: 8px;
  position: relative;
}
.pg-bars div span {
  position: absolute;
  top: -1.1rem;
  left: 50%;
  transform: translateX(-50%);
  font-size: 0.7rem;
  color: var(--base03);
}
.pg-bardays {
  display: flex;
  gap: 8px;
}
.pg-bardays span {
  flex: 1;
  text-align: center;
  font-size: 0.7rem;
  color: var(--base03);
}
.pg-toolbar {
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  align-items: center;
  margin: 0.6rem 0;
}
.pg-toolbar input,
.pg-toolbar select {
  padding: 0.55rem 0.7rem;
  border-radius: var(--radius-md);
  border: var(--border-thin) solid var(--base02);
  font-size: 0.92rem;
  background: var(--base01);
}
.pg-toolbar input {
  flex: 1 1 160px;
  min-width: 0;
}
.pg-toolbar .count {
  margin-left: auto;
  color: var(--base03);
  font-size: 0.82rem;
}
.pg-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.9rem;
}
.pg-table th,
.pg-table td {
  text-align: left;
  vertical-align: middle;
  padding: 0.45rem 0.5rem;
}
.pg-table th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--base03);
  border-bottom: var(--border-std) solid var(--base02);
  white-space: nowrap;
}
.pg-table th.sth {
  padding-left: 1.05rem;
}
.pg-table td {
  border-bottom: var(--border-thin) solid var(--base02);
}
.pg-table tr.pg-ghead td {
  background: var(--base0F);
  font-weight: 800;
  font-size: 0.78rem;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--base05);
}
.pg-table tr.pg-row-m td:first-child {
  border-left: 4px solid var(--base0B);
}
.pg-table tr.pg-row-l td:first-child {
  border-left: 4px solid var(--base09);
}
.pg-table tr.pg-row-s td:first-child {
  border-left: 4px solid var(--base08);
}
.pg-table tr.pg-row-s {
  background: var(--soft08);
}
.pg-table tr.pg-row-u td:first-child {
  border-left: 4px solid var(--base03);
}
.pg-table tr.pg-row-u {
  color: var(--base03);
}
.pg-table .pg-L {
  font-weight: 800;
  font-size: 1.05rem;
}
.pg-pill {
  display: inline-block;
  font-size: 0.68rem;
  font-weight: 800;
  border-radius: var(--radius-pill);
  padding: 0.15rem 0.55rem;
  white-space: nowrap;
}
.pg-pill.m {
  background: var(--soft0B);
  color: var(--base0B);
}
.pg-pill.l {
  background: var(--soft09);
  color: var(--base09);
}
.pg-pill.s {
  background: var(--soft08);
  color: var(--base08);
}
.pg-pill.u {
  background: var(--base02);
  color: var(--base03);
}
.pg-accbar {
  width: 90px;
  height: 7px;
  background: var(--base02);
  border-radius: var(--radius-pill);
  overflow: hidden;
  display: inline-block;
  vertical-align: middle;
}
.pg-accbar i {
  display: block;
  height: 100%;
}
.pg-tspark {
  display: inline-flex;
  gap: 2px;
  align-items: flex-end;
  height: 22px;
}
.pg-tspark i {
  width: 8px;
  border-radius: 3px 3px 0 0;
}
.pg-table tr.pg-exp td {
  background: var(--base01);
  font-size: 0.85rem;
}
@media (max-width: 760px) {
  .pg-kpis {
    grid-template-columns: 1fr 1fr;
  }
  .pg-charts {
    grid-template-columns: 1fr;
  }
  .pg-chartbox.pg-mastery,
  .pg-chartbox.pg-week {
    grid-column: span 1;
  }
  .pg-table {
    font-size: 0.82rem;
  }
  .pg-table .hideM {
    display: none;
  }
}
/* Profile-select card grid (Select A v3): true-centered avatar, name pinned bottom, no subtext. */
.profiles-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 0.7rem;
}
.pcard {
  background: var(--base01);
  border: var(--border-thick) solid var(--base02);
  border-radius: 14px;
  padding: 1rem 0.8rem 2.6rem;
  text-align: center;
  cursor: pointer;
  position: relative;
  min-height: 150px;
  font: inherit;
  color: inherit;
}
.pcard .ava {
  font-size: 2.6rem;
  position: absolute;
  inset: 0 0 0 0;
  display: grid;
  place-items: center;
}
.pcard .ava svg {
  width: 1em;
  height: 1em;
  display: block;
}
.pcard .nm {
  font-weight: 800;
  position: absolute;
  left: 0.5rem;
  right: 0.5rem;
  bottom: 0.8rem;
  text-align: center;
}
.pcard.parent {
  border-style: dashed;
}
.pcard.add {
  border-style: dashed;
  color: var(--base0B);
}
/* Parent unlock modal (Unlock A v3): centered over select, X top-right, click-off close. */
.modal-veil {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.4);
  display: grid;
  place-items: center;
  padding: 1rem;
  cursor: pointer;
  z-index: 20;
}
/* Dialog spacing doctrine: the modal component owns every dialog margin.
   One 1rem rhythm serves as dialog padding, inter-item gap, and action
   spacing. Direct children carry no margins — nothing to collapse across
   siblings or stack inside wrappers — so the title sits one padding from
   the top edge and trailing actions one padding from the bottom, in every
   modal, with no per-modal overrides. Content rules below keep their
   internal design (gaps, borders, text) but contribute no outer margins. */
.modal {
  background: var(--base01);
  border-radius: 14px;
  padding: 1rem;
  max-width: 380px;
  width: 100%;
  position: relative;
  cursor: default;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}
.modal > * {
  margin: 0;
  min-width: 0;
}
/* Forms embedded in dialogs carry the same rhythm: without this the form
   is a single flex item and its inner block margins stack up the old way
   beside the uniform gap. */
.modal form {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  margin: 0;
}
.modal form > * {
  margin: 0;
}
/* Block buttons space themselves from page-form inputs via margin-top;
   inside gap-driven dialogs that margin would double-count the gap. */
.modal .btn-block {
  margin-top: 0;
}
/* The tour list is shared with the settings page, so its base margin
   stays for the page and is zeroed here, inside the dialog rhythm. */
.modal .tour-list {
  margin: 0;
}
.modal .x {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  border: none;
  background: transparent;
  font-size: 1.2rem;
  line-height: 1;
  padding: 0.4rem 0.6rem;
  cursor: pointer;
  color: var(--base03);
}
/* Shared modal header title: it shares the corner-pinned X's line, with
   right clearance so long titles wrap instead of running under the
   absolute X. Outer margins come from the dialog rhythm above. */
.modal > h3:first-of-type {
  padding-right: 2.5rem;
  overflow-wrap: anywhere;
}
/* Confirm modal actions: Cancel left, destructive confirm right. */
.modal .row {
  justify-content: space-between;
}
.modal label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
}
.modal input {
  display: block;
  width: 100%;
  box-sizing: border-box;
}
.modal .primary {
  width: 100%;
}
.modal .alert {
  display: none;
  background: var(--soft08);
  border: var(--border-thin) solid var(--base08);
  color: var(--base08);
  border-radius: var(--radius-md);
  padding: 0.6rem 0.8rem;
  font-size: 0.88rem;
}
.modal .alert.show {
  display: block;
}
/* Pair shortcut modal: stacked option buttons, plain-text code reference. */
.pair-modal {
  max-width: 400px;
}
.pair-stack {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}
.pair-codes {
  display: grid;
  gap: 0.6rem;
  padding: 0.7rem 0.9rem;
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-md);
  background: var(--base00);
}
.pair-code {
  margin: 0.15rem 0 0;
  font-size: 1.25rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  overflow-wrap: anywhere;
  user-select: text;
}
.pair-steps {
  padding-left: 1.3rem;
  font-size: 0.92rem;
  display: grid;
  gap: 0.25rem;
}
/* Pairing QR: fixed white card so themes never invert scannability; the
   SVG itself carries a 4-module quiet zone, the padding doubles it. */
.pair-qr {
  margin: 0 auto;
  padding: 0.6rem;
  max-width: 220px;
  background: #fff;
  border-radius: var(--radius-md);
}
.pair-qr svg {
  display: block;
  width: 100%;
  height: auto;
}
/* Sound recorder modal: live mic meter, timer, local review playback. */
.rec-modal {
  max-width: 420px;
}
.rec-meter {
  width: 100%;
  height: 14px;
}
.rec-timer {
  font-variant-numeric: tabular-nums;
  font-weight: 600;
}
.rec-review {
  width: 100%;
}
.rec-actions {
  gap: 0.6rem;
}
/* Inline Sounds notice: replaces alert() dialogs on playback errors. */
.sounds-msg {
  font-size: 0.9rem;
  margin: 0.2rem 0;
  color: var(--base08);
}
/* Neutral variant for non-error notices (queued, uploaded). */
.sounds-msg.info {
  color: var(--base05);
}
/* Display-variant exceptions (NOT part of the canonical 2px/10px system):
   drill tiles (.opt 3px/15px), submit/next (.check 15px), profile cards
   (.pcard 3px/14px), modals (14px), kid switcher pills (999px), Done card
   (#flash-done.done-wrap 2px/24px celebration frame).
   New pages must opt into these explicitly, never copy them by accident. */
/* Drill: locked mode picker, 4-option multiple choice, select-then-submit.
   All color reads base16 slots; Submit and Next share the one green (0B). */
#kid-session .sess-head {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}
#sess-score {
  margin-left: auto;
  display: flex;
  gap: 0.4rem;
}
/* Drill back arrow: top-left mode-switch control. Large touch target that
   matches the tile radius language; arrow glyph only, labelled for AT. */
.mode-back {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--base01);
  border: var(--border-thin) solid var(--base02);
  color: var(--base05);
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
}
.mode-back:disabled {
  opacity: 0.45;
  cursor: default;
}
.mode-back svg {
  display: block;
}
#kid-session .meter {
  margin: 0.65rem 0 0.8rem;
  height: 10px;
}
.drill-notice {
  background: var(--soft09);
  border: var(--border-thin) solid var(--base09);
  border-radius: var(--radius-md);
  padding: 0.5rem 0.8rem;
  font-size: 0.85rem;
  margin: 0.5rem 0 0;
}
.prompt {
  border-radius: 18px;
  min-height: 180px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: 1.2rem;
  margin: 0.35rem 0;
  background: var(--base0F);
  border: var(--border-std) solid var(--base0B);
}
.prompt .big-letters {
  font-weight: 900;
  line-height: 1;
  letter-spacing: 0.01em;
  font-size: clamp(4rem, 20vw, 6.5rem);
  color: var(--base05);
}
.prompt .prompt-note {
  font-size: 1rem;
  font-weight: 600;
  color: var(--base03);
}
/* Hear-mode prompt is one large play button: the whole panel is the tap
   target so small fingers don't have to land on the speaker circle. */
button.prompt {
  width: 100%;
  font: inherit;
  color: inherit;
  cursor: pointer;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}
button.prompt-play {
  flex-direction: column;
  gap: 0.6rem;
}
.prompt-hint {
  font-size: 0.9rem;
  font-weight: 700;
  opacity: 0.65;
}
.bigplay {
  width: 104px;
  height: 104px;
  border-radius: 50%;
  color: var(--on-0B);
  position: relative;
  background: var(--base0B);
  box-shadow: 0 8px 22px var(--glow0B);
  padding: 0;
  display: block;
  flex: 0 0 auto;
}
.bigplay:active,
button.prompt-play:active .bigplay {
  transform: scale(0.95);
}
.bigplay svg {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(calc(-50% + 2px), -50%);
  display: block;
}
.opts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.65rem;
  margin: 0.6rem 0 0.2rem;
}
/* Grid items default to min-width: auto, so at larger type sizes (device
   text scaling, larger-type themes) the tile content forces its column
   wider than the viewport and the right column is cut off. Clamp both the
   tile and its label so columns always shrink and the label wraps. */
.opts > * {
  min-width: 0;
}
.opt {
  border-radius: 15px;
  min-height: 96px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  padding: 0.7rem;
  font-weight: 800;
  font-size: 1.15rem;
  background: var(--base01);
  border: var(--border-thick) solid var(--base02);
  color: var(--base05);
  box-shadow: 0 2px 0 var(--base02);
  font-family: inherit;
  width: 100%;
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}
button.opt {
  cursor: pointer;
}
button.opt:active {
  transform: scale(0.98);
}
.opt .prev {
  border-radius: var(--radius-pill);
  padding: 0.45rem;
  line-height: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--soft0B);
  border: var(--border-thin) solid var(--base0B);
  color: var(--base0B);
  flex: 0 0 auto;
  pointer-events: none;
}
.opt .prev svg {
  display: block;
}
.opt .opt-pick {
  border: 0;
  background: transparent;
  font: inherit;
  font-size: 1.45rem;
  color: inherit;
  padding: 0.2rem 0.4rem;
  flex: 1 1 auto;
  min-width: 0;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
}
.opt.sel {
  border-color: var(--base0B);
  background: var(--soft0B);
  box-shadow: 0 0 0 3px var(--ring0B);
}
.opt.right {
  border-color: var(--base0B);
  background: var(--soft0B);
}
.opt.wrong {
  border-color: var(--base08);
  background: var(--soft08);
}
.opt.dim {
  opacity: 0.5;
}
.opt:disabled {
  cursor: default;
}
.fb {
  text-align: center;
  font-weight: 800;
  min-height: 1.7em;
  margin: 0.3rem 0 0.1rem;
  font-size: 0.98rem;
}
.fb.ok {
  color: var(--base0B);
}
.fb.no {
  color: var(--base08);
}
/* Correct-answer celebration (inline, at the locus of attention):
   one-shot transform/opacity motion only, so tiles never shift layout
   and narrow phones never overflow. Praise text lives in .fb.ok; the
   tile pops and the prompt does a small happy bounce. All color from
   theme tokens; see the reduced-motion settle below. */
@keyframes drill-win-pop {
  0% {
    transform: scale(1);
  }
  40% {
    transform: scale(1.06);
  }
  100% {
    transform: scale(1);
  }
}
@keyframes drill-celeb-bounce {
  0% {
    transform: translateY(0) scale(1);
  }
  35% {
    transform: translateY(-6px) scale(1.015);
  }
  100% {
    transform: translateY(0) scale(1);
  }
}
@keyframes drill-praise-in {
  from {
    opacity: 0;
    transform: translateY(4px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}
.opt.right.win {
  position: relative;
  animation: drill-win-pop 0.45s ease;
  box-shadow: 0 0 0 3px var(--ring0B);
}
/* Winning check: the tile's content swaps to a big check that scales in
   with the same pop. Decorative (aria-hidden in JSX); the tile keeps its
   accessible name and the feedback line announces the win. */
.win-check {
  font-size: 2.4rem;
  font-weight: 900;
  line-height: 1;
  color: var(--base0B);
  animation: drill-check-in 0.4s ease;
}
@keyframes drill-check-in {
  from {
    transform: scale(0.4);
    opacity: 0;
  }
  60% {
    transform: scale(1.12);
    opacity: 1;
  }
  to {
    transform: scale(1);
    opacity: 1;
  }
}
/* Ray burst: 8 short lines anchored to the winning tile's edge midpoints
   and corners, shooting outward past the perimeter while fading. Overlay
   only (absolute, visible overflow, no pointer events) so no content moves
   and no scrollbars appear. Same 0.45s one-shot as the tile pop: a little
   synchronized pop, then static green + check for the rest of the dwell. */
.rays {
  position: absolute;
  inset: 0;
  overflow: visible;
  pointer-events: none;
}
.ray {
  position: absolute;
  background: var(--base0B);
  border-radius: 999px;
  opacity: 0;
  animation: ray-shoot 0.45s ease-out forwards;
}
@keyframes ray-shoot {
  from {
    transform: rotate(var(--r, 0deg)) translate(0, 0);
    opacity: 1;
  }
  to {
    transform: rotate(var(--r, 0deg))
      translate(var(--tx, 0px), var(--ty, -16px));
    opacity: 0;
  }
}
.ray.n {
  left: 50%;
  top: -3px;
  width: 3px;
  height: 15px;
  margin-left: -1.5px;
  --tx: 0px;
  --ty: -18px;
}
.ray.s {
  left: 50%;
  bottom: -3px;
  width: 3px;
  height: 15px;
  margin-left: -1.5px;
  --tx: 0px;
  --ty: 18px;
}
.ray.e {
  top: 50%;
  right: -3px;
  width: 15px;
  height: 3px;
  margin-top: -1.5px;
  --tx: 18px;
  --ty: 0px;
}
.ray.w {
  top: 50%;
  left: -3px;
  width: 15px;
  height: 3px;
  margin-top: -1.5px;
  --tx: -18px;
  --ty: 0px;
}
.ray.ne {
  top: -4px;
  right: -4px;
  width: 3px;
  height: 14px;
  --r: 45deg;
  --tx: 0px;
  --ty: -14px;
}
.ray.sw {
  bottom: -4px;
  left: -4px;
  width: 3px;
  height: 14px;
  --r: 45deg;
  --tx: 0px;
  --ty: 14px;
}
.ray.nw {
  top: -4px;
  left: -4px;
  width: 3px;
  height: 14px;
  --r: -45deg;
  --tx: 0px;
  --ty: -14px;
}
.ray.se {
  bottom: -4px;
  right: -4px;
  width: 3px;
  height: 14px;
  --r: -45deg;
  --tx: 0px;
  --ty: 14px;
}
#drill-prompt.celeb {
  animation: drill-celeb-bounce 0.5s ease;
}
#drill-feedback.fb.ok {
  animation: drill-praise-in 0.35s ease;
}
@media (prefers-reduced-motion: reduce) {
  .opt.right.win,
  #drill-prompt.celeb,
  #drill-feedback.fb.ok,
  .win-check,
  .ray {
    animation: none;
  }
}
.check {
  width: 100%;
  border: 0;
  border-radius: 15px;
  min-height: 60px;
  font-size: 1.12rem;
  font-weight: 900;
  cursor: pointer;
  margin-top: 0.45rem;
  letter-spacing: 0.01em;
  background: var(--base0B);
  color: var(--on-0B);
  box-shadow: 0 4px 0 var(--shade0B);
  touch-action: manipulation;
  -webkit-tap-highlight-color: transparent;
  -webkit-touch-callout: none;
  user-select: none;
}
.check:disabled {
  cursor: not-allowed;
  opacity: 0.45;
}
.check:active:not(:disabled) {
  transform: translateY(2px);
  box-shadow: none;
}
.foot {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  flex-wrap: wrap;
  font-size: 0.8rem;
  margin-top: 0.6rem;
  opacity: 0.8;
}
.foot button {
  background: none;
  border: none;
  text-decoration: underline;
  cursor: pointer;
  font-size: 0.8rem;
  color: inherit;
  padding: 0;
}
.pick h2 {
  margin: 0.2rem 0 0.4rem;
  font-size: 1.25rem;
}
.pick .sub {
  margin: 0 0 0.8rem;
  font-size: 0.9rem;
  opacity: 0.75;
}
.pick-seg {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  background: var(--base02);
  border-radius: 14px;
  padding: 5px;
  margin-bottom: 0.7rem;
}
.pick-seg button {
  border: 0;
  background: transparent;
  border-radius: var(--radius-md);
  padding: 0.6rem 0.5rem;
  margin: 0;
  cursor: pointer;
  display: grid;
  place-items: center;
  text-align: center;
  min-height: 0;
}
.pick-seg button .pk {
  display: grid;
  justify-items: center;
  gap: 0.15rem;
}
.pick-seg button b {
  font-size: 1.45rem;
  color: var(--base05);
  line-height: 1.2;
  margin: 0;
}
.pick-seg button .sub {
  position: static;
  font-size: 0.75rem;
  color: var(--base04);
  font-weight: 500;
  line-height: 1.3;
  margin: 0;
}
.pick-seg button.on {
  background: var(--base01);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14);
}
.pick-seg button.on .sub {
  color: var(--base05);
}
.pick-seg button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}
.pick-start {
  width: 100%;
  border: 0;
  border-radius: 15px;
  min-height: 58px;
  font-size: 1.08rem;
  font-weight: 900;
  cursor: pointer;
  background: var(--base0B);
  color: var(--on-0B);
  margin-top: 0;
}
/* Done: celebratory session-complete page (mockup B). Tokens only, no image
   assets. Confetti fires from the two bottom corners and hangs IN FRONT of
   the content; two-phase motion (ease-out launch, ease-in gravity fall) with
   a mid-fall sway so pieces fall instead of looking dragged. */
#flash-done.done-wrap {
  position: relative;
  overflow: hidden;
  text-align: center;
  padding: 2.5rem 1.5rem 1.5rem;
  border: var(--border-std) solid var(--base02);
  border-radius: 24px;
  background: var(--base01);
  box-shadow:
    0 10px 30px var(--ring0B),
    0 1px 4px rgba(0, 0, 0, 0.08);
  margin: 0.5rem 0 0;
}
.done-confetti {
  position: absolute;
  inset: 0;
  z-index: 5;
  pointer-events: none;
  overflow: hidden;
}
.conf-side {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 50%;
}
.conf-left {
  left: 0;
}
.conf-right {
  right: 0;
}
.done-confetti .p {
  position: absolute;
  bottom: -18px;
  width: var(--w);
  height: var(--h);
  border-radius: 2px;
  opacity: 0;
  animation: done-rise var(--t, 2s) forwards;
  animation-delay: var(--d, 0s);
}
.done-confetti .p.c1 {
  background: var(--base0A);
}
.done-confetti .p.c2 {
  background: var(--base0B);
}
.done-confetti .p.c3 {
  background: var(--base0D);
}
.done-confetti .p.c4 {
  background: var(--base0E);
}
.done-confetti .p.c5 {
  background: var(--base09);
}
.done-confetti .p.round {
  border-radius: 50%;
}
.done-confetti .p.strip {
  width: 5px;
  border-radius: 3px;
}
/* Vestibular safety (WCAG 2.3.3): a one-shot burst is still motion. The page
   is fully legible without decoration, so drop the confetti entirely. */
@media (prefers-reduced-motion: reduce) {
  .done-confetti {
    display: none;
  }
}
@keyframes done-rise {
  0% {
    transform: translate(0, 0) rotate(0deg);
    opacity: 0;
    animation-timing-function: cubic-bezier(0.12, 0.6, 0.28, 1);
  }
  9% {
    opacity: 1;
  }
  38% {
    transform: translate(calc(var(--mx) * 0.55), var(--rise))
      rotate(calc(var(--spin) * 0.45));
    opacity: 1;
    animation-timing-function: cubic-bezier(0.5, 0.05, 0.8, 0.45);
  }
  68% {
    transform: translate(calc(var(--mx) * 0.85), calc(var(--rise) * 0.15))
      rotate(calc(var(--spin) * 0.75));
    opacity: 1;
    animation-timing-function: ease-in;
  }
  100% {
    transform: translate(var(--mx), 60vh) rotate(var(--spin));
    opacity: 0;
  }
}
.done-badge {
  display: inline-grid;
  place-items: center;
  width: 92px;
  height: 92px;
  background: var(--base0F);
  border-radius: 50%;
  font-size: 3rem;
  margin-bottom: 0.4rem;
  box-shadow: 0 0 0 6px var(--base0A);
  position: relative;
}
.done-head {
  font-size: clamp(2rem, 8vw, 2.8rem);
  font-weight: 900;
  line-height: 1.05;
  margin: 0.3rem 0 0;
  color: var(--base05);
  position: relative;
}
/* Programmatic focus target on Done entry (screen-reader reading position):
   not interactive, so no focus ring. Keyboard users keep the global
   button:focus-visible styling on the real controls below. */
.done-head:focus {
  outline: none;
}
.done-sub {
  color: var(--base03);
  margin: 0.6rem 0 1rem;
  position: relative;
}
.done-stats {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin: 1rem 0;
  position: relative;
}
.done-pill {
  display: flex;
  align-items: baseline;
  gap: 0.4rem;
  background: var(--base01);
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-pill);
  padding: 0.5rem 1rem;
  font-weight: 800;
  color: var(--base05);
}
.done-pill small {
  font-weight: 700;
  color: var(--base03);
  font-size: 0.75rem;
}
.done-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.6rem;
  margin-top: 1.1rem;
  position: relative;
}
.done-go,
.done-exit {
  min-height: 60px;
  font-size: 1.1rem;
  font-weight: 900;
  border-radius: var(--radius-pill);
  cursor: pointer;
}
.done-go {
  border: 0;
  background: var(--base0B);
  color: var(--on-0B);
}
.done-go:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
.done-exit {
  background: var(--base01);
  border: var(--border-std) solid var(--base02);
  color: var(--base05);
}
.done-exit:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
@media (max-width: 560px) {
  #flash-done.done-wrap {
    padding: 1.8rem 1rem 1rem;
  }
  .done-actions {
    grid-template-columns: 1fr;
  }
}
/* Done sits vertically centered so short viewports don't leave a void below
   the card. Scoped with :has so the drill and picker screens stay
   top-aligned. Where :has() is unsupported the rule drops and the page
   top-aligns — accepted as the intentional fallback. */
#view-kid:has(#flash-done) {
  display: grid;
  align-items: center;
  /* 140px ≈ sticky topbar height + .view padding + breathing room. dvh wins
     where supported; otherwise the vh line above stands. */
  min-height: calc(100vh - 140px);
}
@supports (min-height: 100dvh) {
  #view-kid:has(#flash-done) {
    min-height: calc(100dvh - 140px);
  }
}
button:focus-visible {
  outline: var(--border-thick) solid var(--base0D);
  outline-offset: 2px;
}
@media (max-width: 480px) {
  .prompt {
    min-height: 150px;
  }
}
/* Settings tab: three stacked cards with two-column interiors. */
.set-card {
  margin-bottom: 1rem;
}
.set-card h3 {
  margin: 0.1rem 0 0.2rem;
}
.set-card h4 {
  margin: 0.6rem 0 0.4rem;
  font-size: 0.95rem;
}
.set-card .field {
  display: block;
  font-size: 0.88rem;
  font-weight: 600;
  margin: 0.5rem 0;
}
.set-card .field input {
  display: block;
  width: 100%;
  max-width: 320px;
  margin-top: 0.25rem;
  box-sizing: border-box;
}
/* Practice & audio card: keep the session-length label, select, and save
   button on one centered row with even gaps, and give the device-audio
   toggle breathing room below. */
#settings-practice-card .row {
  align-items: center;
}
#settings-practice-card .row > label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}
#settings-practice-card .checkrow {
  margin-top: 0.75rem;
}
/* Design-system buttons: one set, canonical 2px/10px geometry.
   Variants: primary (green constructive), secondary (default), danger
   (red destructive, never green), ghost, link. Display exceptions
   (drill tiles, profile cards, pills) live elsewhere, never here. */
.btn {
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-md);
  padding: 0.55rem 0.9rem;
  font-weight: 700;
  cursor: pointer;
  background: transparent;
  color: inherit;
}
.btn-secondary {
  background: var(--base01);
  border-color: var(--base02);
  color: inherit;
}
.btn-primary {
  background: var(--base0B);
  color: var(--on-0B);
  border: var(--border-std) solid var(--base0B);
  border-radius: var(--radius-md);
  padding: 0.55rem 0.9rem;
  font-weight: 700;
  cursor: pointer;
}
.btn-danger {
  background: var(--base08);
  color: #fff;
  border: var(--border-std) solid var(--shade0B);
  border-radius: var(--radius-md);
  padding: 0.45rem 0.8rem;
  font-weight: 700;
  cursor: pointer;
}
.btn-ghost {
  background: transparent;
  border-color: transparent;
}
/* On-dark actions (topbar on base0B chrome): transparent so the chrome
 * shows through, on-accent text, edge-on-accent border. Never white. */
.btn-ondark {
  background: transparent;
  color: var(--on-0B);
  border: var(--border-std) solid var(--edge-on-accent);
}
.btn-ondark:hover {
  background: rgba(255, 255, 255, 0.12);
}
.btn-link {
  background: none;
  border: none;
  color: var(--base0D);
  font-weight: 600;
  padding: 0.6rem 0;
  cursor: pointer;
  text-align: left;
}
.btn-link:hover {
  text-decoration: underline;
}
.btn-block {
  width: 100%;
  margin-top: 0.8rem;
}
/* Shared layout utilities (replace inline style={{}} layout): */
.spacer {
  flex: 1;
}
.row-flex {
  display: flex;
  gap: 0.5rem;
}
.seg-cols-3 {
  grid-template-columns: repeat(3, 1fr);
}
.modal-card {
  max-width: 440px;
}
.proglink,
.sounds-restore,
.linkbtn,
.linkrow button,
.foot button {
  background: none;
  border: none;
  color: var(--base0D);
  font-weight: 600;
  cursor: pointer;
}
.proglink:hover,
.sounds-restore:hover,
.linkbtn:hover,
.linkrow button:hover,
.foot button:hover {
  text-decoration: underline;
}
.btn-danger:disabled {
  opacity: 0.45;
  cursor: default;
}
.btn:disabled,
.btn-primary:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
/* Theme live preview: mini topbar + sample drill card in real tokens. */
.preview {
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-lg);
  overflow: hidden;
  min-width: 0;
}
.preview-top {
  padding: 0.45rem 0.7rem;
  font-weight: 800;
  font-size: 0.9rem;
}
.preview-card {
  margin: 0.7rem;
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-lg);
  padding: 0.9rem;
  text-align: center;
}
.preview-letters {
  font-size: 2.2rem;
  font-weight: 800;
}
.preview-row {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  align-items: center;
  margin-top: 0.5rem;
  flex-wrap: wrap;
}
.preview-hear {
  border-radius: var(--radius-pill);
  padding: 0.25rem 0.8rem;
  font-size: 0.85rem;
  font-weight: 700;
}
.preview-pill {
  border-radius: var(--radius-pill);
  padding: 0.15rem 0.55rem;
  font-size: 0.75rem;
  border: var(--border-thin) solid;
}
/* Devices panel: per-account collapsed rows (parent + one per kid). */
.dev-kid {
  border-top: var(--border-std) solid var(--base02);
}
.dev-kid summary {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  padding: 0.65rem 0.2rem;
  cursor: pointer;
  list-style: none;
}
.dev-kid summary::-webkit-details-marker {
  display: none;
}
.dev-kid-name {
  font-weight: 700;
  display: flex;
  gap: 0.5rem;
  align-items: center;
  min-width: 0;
}
.dev-kid-name .avatar {
  font-size: 1.3rem;
}
.dev-toggle {
  margin-left: auto;
  color: var(--base03);
  font-size: 1.1rem;
  transition: transform 0.15s ease;
}
.dev-kid[open] .dev-toggle {
  transform: rotate(90deg);
}
.dev-body {
  padding: 0 0.2rem 0.6rem;
}
.dev-row {
  display: flex;
  gap: 0.6rem;
  align-items: center;
  padding: 0.45rem 0;
  border-top: var(--border-std) dashed var(--base02);
}
.dev-row.dev-all {
  justify-content: flex-end;
}
.dev-row .dev-label {
  flex: 1 1 auto;
  min-width: 0;
}
.dev-row .btn-danger {
  flex: 0 0 auto;
}
@media (max-width: 900px) {
  .set-card .split {
    grid-template-columns: 1fr;
  }
}
/* Onboarding starting sets: same pill grid as the dashboard kid rows,
   with breathing room below the avatar select. */
.ob-sets {
  border: none;
  padding: 0;
  margin: 0.9rem 0 0;
  min-width: 0;
}
.ob-sets-title {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0;
  margin-bottom: 0.3rem;
}
.ob-sets .hint {
  margin: 0 0 0.2rem;
}
/* Family add-kid starting sets: same pill grid as onboarding, with
   breathing room below the add row. */
.fam-sets {
  border: none;
  padding: 0;
  margin: 0.6rem 0 0;
  min-width: 0;
}
.fam-sets-title {
  font-size: 0.85rem;
  font-weight: 600;
  padding: 0;
  margin-bottom: 0.3rem;
}
/* Admin log viewer (admin-log-viewer): glanceable tail table with
   in-column filters plus a session-timeline drill-down. The scroll
   container keeps the wide tail from pushing the whole shell sideways:
   overflow stays inside .logscroll, never page-level. */
.logscroll {
  overflow-x: auto;
  max-width: 100%;
  -webkit-overflow-scrolling: touch;
}
.logtable {
  width: 100%;
  min-width: 52rem;
  border-collapse: collapse;
  font-size: 0.92rem;
}
.logtable th {
  text-align: left;
  padding: 0.5rem 0.6rem 0.25rem;
  vertical-align: bottom;
  white-space: nowrap;
}
.logtable th .colfilter {
  display: block;
  width: 100%;
  min-width: 7rem;
  max-width: 11rem;
  margin-top: 0.35rem;
  font-weight: 400;
}
.logtable td {
  border-top: var(--border-thin) solid var(--base02);
  padding: 0.55rem 0.6rem;
  vertical-align: top;
}
.logtable td.mono,
.logtable .sesslink.mono,
.logtable code {
  overflow-wrap: anywhere;
  word-break: break-word;
}
.logtable tbody tr:hover td {
  background: var(--base06);
}
@media (max-width: 760px) {
  .logtable {
    min-width: 44rem;
    font-size: 0.82rem;
  }
  .logtable th,
  .logtable td {
    padding: 0.45rem 0.5rem;
  }
  .logtable th .colfilter {
    min-width: 5.5rem;
    max-width: 8rem;
  }
}
.mono {
  font-family: ui-monospace, Menlo, monospace;
  font-size: 0.85rem;
}
.dot {
  display: inline-block;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  margin-right: 0.35rem;
  background: var(--base04);
}
.dot.error {
  background: var(--base08);
}
.dot.warn {
  background: var(--base09);
}
.dot.info {
  background: var(--base0C);
}
.dot.debug {
  background: var(--base04);
}
.sesslink {
  background: none;
  border: 0;
  padding: 0;
  color: var(--base0C);
  text-decoration: underline;
  cursor: pointer;
  font: inherit;
}
.kpi {
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-md);
  padding: 0.3rem 0.7rem;
}
.kpi-miss {
  border-color: var(--base08);
  background: var(--soft08);
  font-weight: 700;
}
ol.tl {
  list-style: none;
  margin: 0;
  padding-left: 1.1rem;
  position: relative;
}
ol.tl::before {
  content: "";
  position: absolute;
  left: 0.35rem;
  top: 0.4rem;
  bottom: 0.4rem;
  width: 2px;
  background: var(--base02);
}
ol.tl li {
  position: relative;
  margin-bottom: 0.9rem;
}
ol.tl li::before {
  content: "";
  position: absolute;
  left: -1.02rem;
  top: 0.3rem;
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 50%;
  background: var(--base04);
}
ol.tl li.error::before {
  background: var(--base08);
}
ol.tl li.warn::before {
  background: var(--base09);
}
ol.tl li.info::before {
  background: var(--base0C);
}
.tlcard {
  border: var(--border-std) solid var(--base02);
  border-radius: var(--radius-md);
  padding: 0.5rem 0.8rem;
  margin-top: 0.15rem;
  min-width: 0;
  overflow-wrap: anywhere;
}
.join {
  background: var(--soft0C);
  border: var(--border-thin) solid var(--base0C);
  border-radius: var(--radius-md);
  padding: 0.4rem 0.7rem;
  margin-top: 0.4rem;
  font-size: 0.85rem;
}

/* Product tours (parent-product-tour): spotlight veil + elevated target,
   step card, picker/tutorials lists, and Hear-vs-See mock illustrations.
   Theme colors come from tokens; only the dim scrim uses a black rgba. */
.tour-veil {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  z-index: 30;
}
.tour-spot {
  position: relative;
  z-index: 31;
  border-radius: var(--radius-sm);
  outline: var(--border-thick) solid var(--base0D);
  outline-offset: 3px;
}
.tour-card {
  position: fixed;
  z-index: 32;
  width: 340px;
  max-width: calc(100vw - 24px);
  max-height: calc(100dvh - 24px);
  overflow-y: auto;
  background: var(--base01);
  color: var(--base05);
  border: var(--border-std) solid var(--base0B);
  border-radius: var(--radius-lg);
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.3);
  padding: 1rem;
}
.tour-card.pos-center {
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}
.tour-card h3 {
  margin: 0.3rem 2rem 0.4rem 0;
}
.tour-card p {
  margin: 0.4rem 0 0.6rem;
}
.tour-card .x {
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  border: none;
  background: transparent;
  font-size: 1.2rem;
  line-height: 1;
  padding: 0.4rem 0.6rem;
  cursor: pointer;
  color: var(--base03);
  min-width: 44px;
  min-height: 44px;
}
.tour-eyebrow {
  font-size: 0.78rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--base03);
}
.tour-card .btn,
.tour-list .btn {
  min-height: 44px;
}
/* Card actions: Back stays left, Next/Done pins right — including on step
   one where Next is the only row button. */
.tour-card .row {
  align-items: center;
}
.tour-card #tour-next,
.tour-card #tour-done {
  margin-left: auto;
}
.tour-list {
  list-style: none;
  margin: 0.6rem 0;
  padding: 0;
}
.tour-list-item {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  padding: 0.6rem 0;
  border-top: var(--border-thin) solid var(--base02);
}
.tour-list-item > div {
  flex: 1 1 200px;
  min-width: 0;
}
.tour-status {
  font-size: 0.8rem;
  font-weight: 700;
  white-space: nowrap;
}
.tour-status.done {
  color: var(--base0B);
}
.tour-status.todo {
  color: var(--base03);
}
/* Hear-vs-See miniature drill illustrations (static, ThemePreview kin). */
.tour-mock {
  background: var(--base06);
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-md);
  padding: 0;
  overflow: hidden;
  margin: 0.6rem 0;
}
.tour-mock-letters {
  font-size: 2rem;
  font-weight: 800;
  line-height: 1.1;
}
.tour-mock-sub {
  font-size: 0.85rem;
  color: var(--base03);
  margin: 0.25rem 0 0.5rem;
}
.tour-mock-opts {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
}
.tour-mock-opts span {
  border: var(--border-thick) solid var(--base02);
  border-radius: 15px;
  padding: 0.35rem 0.7rem;
  font-weight: 700;
  font-size: 1.1rem;
  min-height: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--base01);
  box-shadow: 0 2px 0 var(--base02);
}
.tour-mock-opts span.on {
  border-color: var(--base0B);
  background: var(--soft0B);
  box-shadow: 0 0 0 3px var(--ring0B);
}
.tour-mock-badge {
  display: inline-block;
  margin-top: 0.5rem;
  border: var(--border-thin) solid var(--base0B);
  color: var(--base0B);
  border-radius: var(--radius-pill);
  padding: 0.25rem 0.7rem;
  font-size: 0.8rem;
  font-weight: 700;
}
.tour-mock-note {
  font-size: 0.8rem;
  color: var(--base03);
  margin-top: 0.5rem;
}
/* Mock window chrome + page miniatures: echo the live screens — green
   topbar, drill prompt/option tiles, mode picker, profile cards, pairing
   codes — as compact silhouettes, not pixel-perfect copies. */
.tour-mock-top {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  background: var(--base0B);
  color: var(--on-0B);
  padding: 0.35rem 0.6rem;
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.02em;
}
.tour-mock-owl {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--on-0B);
  opacity: 0.85;
  flex: 0 0 auto;
}
.tour-mock-body {
  padding: 0.6rem;
  display: grid;
  gap: 0.5rem;
}
.tour-mock-prompt {
  border-radius: 14px;
  background: var(--base0F);
  border: var(--border-std) solid var(--base0B);
  padding: 0.7rem 0.6rem;
  text-align: center;
}
.tour-mock-prompt .tour-mock-letters {
  font-size: 1.9rem;
}
.tour-mock-prompt .tour-mock-sub {
  margin: 0.15rem 0 0;
}
.tour-mock-play {
  width: 54px;
  height: 54px;
  border-radius: 50%;
  background: var(--base0B);
  box-shadow: 0 6px 16px var(--glow0B);
  display: inline-block;
  position: relative;
}
.tour-mock-play::after {
  content: "";
  position: absolute;
  left: 55%;
  top: 50%;
  transform: translate(-50%, -50%);
  border-left: 16px solid var(--on-0B);
  border-top: 10px solid transparent;
  border-bottom: 10px solid transparent;
}
.tour-mock-h {
  font-weight: 800;
  font-size: 0.9rem;
}
.tour-mock-h.small {
  font-size: 0.78rem;
}
.tour-mock-seg {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 4px;
  background: var(--base02);
  border-radius: 12px;
  padding: 4px;
}
.tour-mock-seg span {
  text-align: center;
  padding: 0.45rem 0.3rem;
  border-radius: var(--radius-md);
  font-weight: 800;
  color: var(--base04);
}
.tour-mock-seg span.on {
  background: var(--base01);
  color: var(--base05);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.14);
}
.tour-mock-start {
  display: block;
  text-align: center;
  background: var(--base0B);
  color: var(--on-0B);
  border-radius: 14px;
  padding: 0.7rem;
  font-weight: 900;
}
.tour-mock-panes {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
  padding: 0.5rem;
}
.tour-mock-pane {
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--base00);
}
.tour-mock-shell {
  display: grid;
  grid-template-columns: 56px 1fr;
  gap: 0.3rem;
  padding: 0.4rem;
}
.tour-mock-side {
  display: grid;
  gap: 2px;
  align-content: start;
}
.tour-mock-side span {
  font-size: 0.55rem;
  font-weight: 700;
  padding: 0.2rem 0.3rem;
  border-radius: 5px;
  color: var(--base04);
}
.tour-mock-side span.on {
  background: var(--base0B);
  color: var(--on-0B);
}
.tour-mock-panel {
  background: var(--base01);
  border-radius: 6px;
  padding: 0.4rem;
  display: grid;
  gap: 0.3rem;
  align-content: start;
}
.tour-mock-line {
  height: 8px;
  border-radius: 4px;
  background: var(--base02);
}
.tour-mock-line.short {
  width: 60%;
}
.tour-mock-pbody {
  padding: 0.45rem;
  display: grid;
  gap: 0.35rem;
}
.tour-mock-pgrid {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 0.25rem;
}
.tour-mock-pgrid span {
  background: var(--base01);
  border: var(--border-std) solid var(--base02);
  border-radius: 8px;
  min-height: 44px;
  display: grid;
  place-items: center;
  font-size: 0.62rem;
  font-weight: 800;
}
.tour-mock-pgrid span.lock {
  border-style: dashed;
}
.tour-mock-pgrid span.add {
  border-style: dashed;
  color: var(--base0B);
}
.tour-mock-pgrid span.kid {
  grid-column: 1 / -1;
  min-height: 34px;
}
.tour-mock-pgrid svg {
  width: 16px;
  height: 16px;
}
.tour-mock-caption {
  font-size: 0.6rem;
  font-weight: 700;
  color: var(--base03);
  text-align: center;
  padding: 0.3rem 0.4rem 0.45rem;
}
.tour-mock-codes {
  display: grid;
  gap: 0.35rem;
  background: var(--base00);
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-md);
  padding: 0.5rem 0.6rem;
}
.tour-mock-codes b {
  display: block;
  font-size: 0.95rem;
  letter-spacing: 0.08em;
}
.tour-mock-label {
  display: block;
  font-size: 0.62rem;
  color: var(--base03);
}
.tour-mock-pair-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 0.5rem;
  align-items: center;
}
.tour-mock-qr {
  width: 56px;
  height: 56px;
  padding: 4px;
  background: var(--base01);
  border: var(--border-thin) solid var(--base02);
  border-radius: var(--radius-sm);
  fill: var(--base05);
}
/* TopBar icon actions: glyphs center via the shared .topbar button flex
 * rule above — no per-icon sizing, so icons can never drift from the
 * text buttons again. */
.topbar button svg {
  display: block;
}
@media (max-width: 480px) {
  .tour-card {
    width: calc(100vw - 24px);
  }
  .tour-list-item .btn {
    width: 100%;
  }
}
