/*
 * Woodshed — styled with the Program Partner design system.
 * Tokens, type roles, radii and button hierarchy follow the Program Partner
 * theme (src/styles.css and docs/design-system in the Program Partner repo).
 * Colors are the OKLCH values from that theme; fonts are self-hosted.
 */

/* Program Partner webfonts: the same static instances the product ships
   (public/fonts in Program Partner). One file per weight, latin + latin-ext
   subsets together. Fraunces is the static 500 instance, not the variable
   build, so opsz/SOFT/WONK settings have no effect. Never let the browser
   synthesise a missing weight. */
@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/dm-sans-400.woff2') format('woff2');
}

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/dm-sans-500.woff2') format('woff2');
}

@font-face {
  font-family: 'DM Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/dm-sans-600.woff2') format('woff2');
}

@font-face {
  font-family: Fraunces;
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/fraunces-500.woff2') format('woff2');
}

@font-face {
  font-family: 'Noto Music';
  src: url('../fonts/NotoMusic-Regular.woff2') format('woff2');
  font-display: block;
}

:root {
  color-scheme: light;
  --font-sans: 'DM Sans', ui-sans-serif, system-ui, sans-serif;
  --font-serif: Fraunces, ui-serif, Georgia, serif;
  --radius: 0.75rem;
  --radius-sm: calc(var(--radius) - 4px);
  --radius-md: calc(var(--radius) - 2px);
  --radius-lg: var(--radius);
  --radius-xl: calc(var(--radius) + 4px);

  /* The screen's safe area: room for the status bar, notch and home
     indicator. Only the native app draws under them (viewport-fit=cover),
     so these are 0 on the website. iOS reports env(); Capacitor's Android
     shell sets --safe-area-inset-* itself, since some Android WebViews
     report env() as 0. */
  --safe-top: var(--safe-area-inset-top, env(safe-area-inset-top, 0px));
  --safe-right: var(--safe-area-inset-right, env(safe-area-inset-right, 0px));
  --safe-bottom: var(--safe-area-inset-bottom, env(safe-area-inset-bottom, 0px));
  --safe-left: var(--safe-area-inset-left, env(safe-area-inset-left, 0px));

  /* Program Partner light theme: warm sand, calm charcoal, accessible terracotta. */
  --background: oklch(0.97 0.018 92);
  --foreground: oklch(0.28 0.018 210);
  --card: oklch(0.995 0.006 90);
  --card-foreground: oklch(0.28 0.018 210);
  --primary: oklch(0.52 0.14 35);
  --primary-foreground: oklch(0.99 0.005 90);
  --secondary: oklch(0.92 0.028 80);
  --secondary-foreground: oklch(0.32 0.025 210);
  --muted: oklch(0.94 0.015 85);
  --muted-foreground: oklch(0.47 0.025 215);
  --accent: oklch(0.9 0.05 40);
  --accent-foreground: oklch(0.38 0.09 35);
  --destructive: oklch(0.56 0.2 25);
  --destructive-foreground: oklch(0.99 0.005 90);
  --border: oklch(0.87 0.014 210);
  --input: oklch(0.87 0.014 210);
  --input-border: oklch(0.62 0.014 210);
  --ring: oklch(0.58 0.13 35);
  --neutral: oklch(0.22 0.01 210);
  --neutral-foreground: oklch(0.99 0.005 90);
  --success: oklch(0.53 0.13 155);
  --success-foreground: oklch(0.99 0.005 90);
  --warning: oklch(0.53 0.11 80);
  --warning-foreground: oklch(0.99 0.005 90);
  --shadow: 0 1px 2px oklch(0.28 0.018 210 / 6%), 0 4px 12px oklch(0.28 0.018 210 / 6%);
}

/* Dark follows the device; data-theme on <html> is an explicit override. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    color-scheme: dark;
    --background: oklch(0.2 0.018 210);
    --foreground: oklch(0.95 0.012 90);
    --card: oklch(0.25 0.02 210);
    --card-foreground: oklch(0.95 0.012 90);
    --primary: oklch(0.7 0.13 38);
    --primary-foreground: oklch(0.2 0.02 210);
    --secondary: oklch(0.32 0.025 210);
    --secondary-foreground: oklch(0.95 0.012 90);
    --muted: oklch(0.3 0.02 210);
    --muted-foreground: oklch(0.72 0.02 90);
    --accent: oklch(0.36 0.055 35);
    --accent-foreground: oklch(0.95 0.012 90);
    --destructive: oklch(0.68 0.18 25);
    --destructive-foreground: oklch(0.2 0.02 210);
    --border: oklch(1 0 0 / 12%);
    --input: oklch(1 0 0 / 16%);
    --input-border: oklch(0.58 0.02 210);
    --ring: oklch(0.7 0.13 38);
    --neutral: oklch(0.88 0.01 210);
    --neutral-foreground: oklch(0.2 0.02 210);
    --success: oklch(0.72 0.12 155);
    --success-foreground: oklch(0.2 0.02 210);
    --warning: oklch(0.78 0.12 80);
    --warning-foreground: oklch(0.2 0.02 210);
    --shadow: 0 1px 2px oklch(0 0 0 / 40%), 0 6px 18px oklch(0 0 0 / 35%);
  }
}

:root[data-theme='dark'] {
  color-scheme: dark;
  --background: oklch(0.2 0.018 210);
  --foreground: oklch(0.95 0.012 90);
  --card: oklch(0.25 0.02 210);
  --card-foreground: oklch(0.95 0.012 90);
  --primary: oklch(0.7 0.13 38);
  --primary-foreground: oklch(0.2 0.02 210);
  --secondary: oklch(0.32 0.025 210);
  --secondary-foreground: oklch(0.95 0.012 90);
  --muted: oklch(0.3 0.02 210);
  --muted-foreground: oklch(0.72 0.02 90);
  --accent: oklch(0.36 0.055 35);
  --accent-foreground: oklch(0.95 0.012 90);
  --destructive: oklch(0.68 0.18 25);
  --destructive-foreground: oklch(0.2 0.02 210);
  --border: oklch(1 0 0 / 12%);
  --input: oklch(1 0 0 / 16%);
  --input-border: oklch(0.58 0.02 210);
  --ring: oklch(0.7 0.13 38);
  --neutral: oklch(0.88 0.01 210);
  --neutral-foreground: oklch(0.2 0.02 210);
  --success: oklch(0.72 0.12 155);
  --success-foreground: oklch(0.2 0.02 210);
  --warning: oklch(0.78 0.12 80);
  --warning-foreground: oklch(0.2 0.02 210);
  --shadow: 0 1px 2px oklch(0 0 0 / 40%), 0 6px 18px oklch(0 0 0 / 35%);
}

* {
  box-sizing: border-box;
  border-color: var(--border);
}

html,
body {
  margin: 0;
  padding: 0;
}

body {
  font-family: var(--font-sans);
  font-size: 0.875rem;
  line-height: 1.5;
  color: var(--foreground);
  background: var(--background);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  text-rendering: optimizeLegibility;
}

a {
  color: var(--primary);
}

/* Type roles: headings are Fraunces 500, everything else DM Sans. */
h1,
h2,
h3 {
  font-family: var(--font-serif);
  font-weight: 500;
  margin: 0 0 0.5rem;
}

h1 {
  font-size: 1.5rem;
  line-height: 1.2;
}

@media (min-width: 720px) {
  h1 {
    font-size: 2rem;
  }
}

h2 {
  font-size: 1.25rem;
  line-height: 1.3;
}

h3 {
  font-size: 1rem;
  line-height: 1.4;
}

p {
  margin: 0 0 0.75rem;
}

.reading {
  font-size: 1rem;
  line-height: 1.6;
}

.muted {
  color: var(--muted-foreground);
}

.small {
  font-size: 0.75rem;
}

/* ------------------------------------------------------------ layout */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.6rem 1rem;
  background: var(--card);
  border-bottom: 1px solid var(--border);
  position: sticky;
  top: 0;
  z-index: 10;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  color: var(--foreground);
  text-decoration: none;
}

.brand-mark {
  width: 28px;
  height: 28px;
  display: block;
  color: var(--primary);
}

/* The name and its byline, stacked: "Woodshed / by Program Partner". The
   byline is part of the name, like a maker's mark, so it goes home with the
   rest of the brand link; the footer is where Program Partner is linked. */
.brand-text {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
}

.brand-name {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.25rem;
  line-height: 1;
}

.brand-by {
  font-size: 0.75rem;
  font-weight: 500;
  line-height: 1;
  color: var(--muted-foreground);
  white-space: nowrap;
}

.topnav {
  display: flex;
  gap: 0.25rem;
}

.topnav a {
  color: var(--muted-foreground);
  text-decoration: none;
  padding: 0.45rem 0.7rem;
  border-radius: var(--radius-md);
  font-weight: 500;
  white-space: nowrap;
}

.topnav a:hover {
  color: var(--foreground);
  background: var(--muted);
}

.topnav a.active {
  color: var(--accent-foreground);
  background: var(--accent);
}

.app {
  width: 100%;
  max-width: 1080px;
  margin: 0 auto;
  padding: 1.5rem 1rem 3rem;
  flex: 1;
}

/* The footer: where Woodshed comes from (Program Partner's wordmark, a line on
   what Program Partner is and its address), then the site links. It says what
   Program Partner is rather than selling it: no button, no banner. */
.footer {
  padding: 1.75rem 1rem 1.25rem;
  border-top: 1px solid var(--border);
  color: var(--muted-foreground);
  font-size: 0.75rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.25rem;
}

.footer-family {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.6rem;
  max-width: 34rem;
  text-align: center;
}

.footer-family-text {
  margin: 0;
  font-size: 0.875rem;
  line-height: 1.55;
  text-wrap: pretty;
}

.footer-family-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  border-radius: 4px;
}

.footer-family-link:hover {
  text-decoration-thickness: 2px;
}

.footer-family-link:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.footer-out {
  width: 0.85em;
  height: 0.85em;
  flex: none;
}

.footer-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  align-items: center;
  justify-content: center;
}

/* Native builds opt into viewport-fit=cover. Keep controls clear of notches
   and the home indicator; ordinary browser layout is unchanged. Panels
   (dialog.sheet), sticky rails and the toast use the same --safe-* insets. */
.native-app .topbar {
  padding-top: calc(0.6rem + var(--safe-top));
  padding-left: max(1rem, var(--safe-left));
  padding-right: max(1rem, var(--safe-right));
}
.native-app .app {
  padding-left: max(1rem, var(--safe-left));
  padding-right: max(1rem, var(--safe-right));
}
.native-app .footer {
  padding-bottom: calc(1.25rem + var(--safe-bottom));
}
.mobile-open input { width: 100%; min-width: 0; }
.mobile-open summary { cursor: pointer; font-weight: 600; }

.footer-links {
  display: inline-flex;
  gap: 1rem;
}

.footer-links a {
  color: var(--foreground);
  font-weight: 500;
  text-decoration: none;
}

.footer-links a:hover,
.footer-links a[aria-current='page'] {
  color: var(--primary);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.footer-brand img {
  height: 24px;
  width: auto;
  display: block;
}

.footer-brand-link {
  display: inline-flex;
  align-items: center;
  border-radius: 4px;
}

.footer-brand-link:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.footer-brand .dark-only {
  display: none;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .footer-brand .light-only {
    display: none;
  }

  :root:not([data-theme='light']) .footer-brand .dark-only {
    display: block;
  }
}

:root[data-theme='dark'] .footer-brand .light-only {
  display: none;
}

:root[data-theme='dark'] .footer-brand .dark-only {
  display: block;
}

.card {
  background: var(--card);
  color: var(--card-foreground);
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow);
  padding: 1.5rem;
}

.card + .card {
  margin-top: 1.5rem;
}

.grid {
  display: grid;
  gap: 1rem;
}

.grid.two {
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

.row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  align-items: center;
}

.spread {
  justify-content: space-between;
}

.stack > * + * {
  margin-top: 1rem;
}

/* ------------------------------------------------------------ controls */
/* A button with no style of its own is an outline: only .btn-primary is filled,
   so each view has one loud action (UX plan phase 92, D90). */
button,
.btn {
  font: inherit;
  font-weight: 500;
  cursor: pointer;
  border: 1px solid var(--input-border);
  background: var(--card);
  color: var(--foreground);
  border-radius: var(--radius-md);
  height: 2.25rem;
  padding: 0 1rem;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  white-space: nowrap;
  transition: background 0.15s, color 0.15s, border-color 0.15s, opacity 0.15s;
}

button:hover,
.btn:hover {
  opacity: 0.9;
}

button:focus-visible,
.btn:focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible,
.brand:focus-visible,
.topnav a:focus-visible,
.back-link:focus-visible,
.trail a:focus-visible,
.tool-tab:focus-visible,
.footer-links a:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-primary {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: transparent;
}

.btn-ghost {
  background: transparent;
  color: var(--foreground);
  border-color: transparent;
}

.btn-ghost:hover {
  background: var(--accent);
  color: var(--accent-foreground);
  border-color: var(--input-border);
  opacity: 1;
}

.btn-outline {
  background: var(--card);
  color: var(--foreground);
  border-color: var(--input-border);
}

.btn-outline:hover {
  background: var(--muted);
  opacity: 1;
}

.btn-lg {
  height: 2.5rem;
  padding: 0 1.5rem;
  font-size: 1rem;
}

.btn-sm {
  height: 2rem;
  padding: 0 0.75rem;
}

label.field {
  display: block;
  font-weight: 500;
}

label.field span,
.field > .field-label {
  display: block;
  margin-bottom: 0.35rem;
  font-weight: 500;
}

select,
input[type='text'],
input[type='search'],
input[type='date'],
input[type='url'],
input[type='email'],
textarea {
  font: inherit;
  width: 100%;
  height: 2.25rem;
  padding: 0 0.75rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--input-border);
  background: var(--card);
  color: var(--foreground);
}

textarea {
  height: auto;
  padding: 0.6rem 0.75rem;
}

input[type='search']::-webkit-search-decoration {
  appearance: none;
}

@media (max-width: 720px) {
  input[type='text'],
  input[type='search'],
  input[type='url'],
  input[type='email'] {
    font-size: 1rem;
  }
}

.check {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
  height: 2.25rem;
  padding: 0 0.75rem;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  cursor: pointer;
  background: var(--card);
}

.check input {
  accent-color: var(--primary);
  width: 1rem;
  height: 1rem;
  margin: 0;
}

.seg {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.35rem;
}

.seg button {
  background: var(--card);
  color: var(--foreground);
  border-color: var(--input-border);
}

.seg button.active {
  background: var(--accent);
  color: var(--accent-foreground);
  border-color: transparent;
}

.pill {
  display: inline-block;
  padding: 0.1rem 0.6rem;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.75rem;
  font-weight: 500;
}

.pill.bad {
  background: color-mix(in oklch, var(--destructive) 12%, transparent);
  color: var(--destructive);
}

code,
.linkbox {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8125rem;
}

.linkbox {
  width: 100%;
  padding: 0.6rem 0.75rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--border);
  background: var(--muted);
  word-break: break-all;
  user-select: all;
}

/* ------------------------------------------------------------ instrument picker */
/* A whole-ensemble link (roadmap phase 24): the instrument the student picked, with a way to pick another. */
.player-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0;
}

.player-choice h2 {
  margin: 0;
}

.inst-groups h3,
.inst-groups .inst-group-name {
  margin: 1.25rem 0 0.5rem;
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.inst-list {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
  gap: 0.5rem;
}

@media (max-width: 560px) {
  /* Two columns on phones, so the activities below aren't a long scroll away. */
  .inst-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.inst-btn {
  background: var(--card);
  color: var(--foreground);
  border: 1px solid var(--border);
  justify-content: flex-start;
  text-align: left;
  height: auto;
  min-height: 2.75rem;
  padding: 0.6rem 0.9rem;
  white-space: normal;
}

.inst-btn:hover {
  background: var(--muted);
  border-color: var(--input-border);
  opacity: 1;
}

.inst-btn.current {
  border-color: var(--ring);
  background: var(--accent);
  color: var(--accent-foreground);
}

.inst-btn.planned {
  opacity: 0.55;
  cursor: default;
}

/* ------------------------------------------------------------ Practice and Teach lists */
.hub-head p {
  margin: 0;
}

.hub-eyebrow,
.hub-section-title {
  margin: 0 0 0.35rem;
  font-family: var(--font-sans);
  font-weight: 500;
  color: var(--muted-foreground);
  font-size: 0.75rem;
  line-height: 1.4;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.hub-list {
  padding: 0;
  overflow: hidden;
}

.hub-section + .hub-section {
  border-top: 1px solid var(--border);
}

.hub-section-title {
  margin: 0;
  padding: 1rem 1.5rem 0.5rem;
}

.hub-rows {
  list-style: none;
  margin: 0;
  padding: 0 0 0.5rem;
}

.hub-row {
  display: grid;
  grid-template-columns: 2.5rem minmax(0, 1fr) auto;
  gap: 0.9rem;
  align-items: center;
  padding: 0.7rem 1.5rem;
  color: var(--foreground);
  text-decoration: none;
}

.hub-rows li + li .hub-row {
  border-top: 1px solid var(--border);
}

.hub-row:hover {
  background: var(--muted);
}

.hub-row:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: -2px;
}

.hub-icon {
  width: 2.5rem;
  height: 2.5rem;
  border-radius: var(--radius-md);
  background: var(--accent);
  color: var(--accent-foreground);
  display: grid;
  place-items: center;
}

.hub-icon .icon {
  width: 1.4rem;
  height: 1.4rem;
}

.hub-text {
  display: grid;
  gap: 0.1rem;
  min-width: 0;
}

.hub-name {
  font-weight: 500;
  font-size: 1rem;
}

.hub-blurb,
.hub-meta {
  color: var(--muted-foreground);
}

.hub-meta {
  font-size: 0.75rem;
}

.hub-chevron {
  width: 1.1rem;
  height: 1.1rem;
  color: var(--muted-foreground);
}

.hub-foot {
  margin-bottom: 0;
}

/* Practice: one equal tile per activity, then the tools as compact rows. */
.practice-section > * + * {
  margin-top: 0.75rem;
}

.practice-tiles,
.tool-rows {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 1rem;
}

/* A lone tool keeps one column's width rather than stretching across. */
.tool-rows {
  grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
}

.practice-tile {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius-xl);
  background: var(--card);
  box-shadow: var(--shadow);
  transition: border-color 0.15s;
}

.practice-tile:hover {
  border-color: var(--input-border);
}

.tile-link,
.tool-row {
  color: var(--foreground);
  text-decoration: none;
  border-radius: var(--radius-xl);
}

.tile-link:focus-visible,
.tool-row:focus-visible,
.tile-change:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.tile-link {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
  padding: 1.25rem;
  min-height: 12rem;
  box-sizing: border-box;
}

.tile-icon,
.tool-icon {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  color: var(--accent-foreground);
}

.tile-icon {
  width: 2.75rem;
  height: 2.75rem;
  background: var(--accent);
}

.tool-icon {
  width: 2.5rem;
  height: 2.5rem;
  background: var(--muted);
}

.tile-icon .icon {
  width: 1.4rem;
  height: 1.4rem;
}

.tool-icon .icon {
  width: 1.25rem;
  height: 1.25rem;
}

.tile-text {
  display: grid;
  gap: 0.2rem;
  min-width: 0;
}

.tile-name {
  font-weight: 500;
  font-size: 1.0625rem;
  line-height: 1.3;
}

.tile-instrument {
  color: var(--accent-foreground);
  font-weight: 500;
}

.tile-blurb,
.tool-blurb {
  color: var(--muted-foreground);
}

.tile-foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

/* The Practice filter (roadmap phase 24, decision D17): All · Band · Orchestra · Choir, in place of tags on each tile. */
.ensemble-filter-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
}

.tile-chevron {
  flex-shrink: 0;
  width: 1.1rem;
  height: 1.1rem;
  color: var(--muted-foreground);
}

.tile-change {
  align-self: flex-start;
  margin: -0.5rem 1.25rem 1.1rem;
  font-size: 0.8125rem;
  font-weight: 500;
}

.tool-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1.25rem;
  border: 1px solid var(--border);
  background: var(--card);
}

.tool-row:hover {
  border-color: var(--input-border);
}

.tool-row .tile-text {
  flex: 1;
}

.tool-name {
  font-weight: 500;
  font-size: 0.9375rem;
}

.tool-blurb {
  font-size: 0.8125rem;
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  margin: 0 0 0.5rem -0.3rem;
  padding: 0.15rem 0.4rem 0.15rem 0.1rem;
  border-radius: var(--radius-sm);
  color: var(--muted-foreground);
  font-weight: 500;
  text-decoration: none;
}

.back-link:hover {
  color: var(--foreground);
  background: var(--muted);
}

.back-icon {
  width: 1.1rem;
  height: 1.1rem;
}

.stack > .back-link + * {
  margin-top: 0;
}

/* The status line stays in the page (so screen readers hear the result) but takes no room until there is one. */
.feedback.verify-result:empty {
  min-height: 0;
}

p.verify-result:empty {
  display: none;
}

.tool-tabs {
  display: flex;
  gap: 0.25rem;
  overflow-x: auto;
  border-bottom: 1px solid var(--border);
}

.tool-tab {
  padding: 0.6rem 0.9rem;
  color: var(--muted-foreground);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;
}

.tool-tab.active {
  color: var(--foreground);
  border-bottom-color: var(--primary);
}

/* Tabs that switch a view in place (chorus) look like the Tools tabs. */
button.tool-tab {
  height: auto;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  border-radius: 0;
}

button.tool-tab:hover {
  opacity: 1;
  color: var(--foreground);
}

/* ------------------------------------------------------------ practice */
.practice-head {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem 1.5rem;
  align-items: baseline;
  justify-content: space-between;
  margin-bottom: 0.75rem;
}

.stats {
  display: flex;
  gap: 0.5rem 1.25rem;
  flex-wrap: wrap;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.stats .muted {
  font-weight: 400;
}

.progress {
  height: 6px;
  background: var(--muted);
  border-radius: 999px;
  overflow: hidden;
  margin: 0.4rem 0 1.25rem;
}

.progress > div {
  height: 100%;
  background: var(--primary);
  transition: width 0.2s;
}

.question {
  display: grid;
  grid-template-columns: minmax(220px, 300px) 1fr;
  gap: 1.5rem;
  align-items: start;
}

@media (max-width: 720px) {
  .question {
    grid-template-columns: 1fr;
  }
}

.prompt {
  text-align: center;
}

.prompt .staff {
  max-width: 100%;
  height: auto;
}

.prompt-text {
  font-weight: 500;
  margin-top: 0.4rem;
}

.answer-area {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1rem;
}

.diagram-wrap {
  width: 100%;
  display: flex;
  justify-content: center;
}

.diagram-wrap svg {
  max-width: 100%;
  height: auto;
}

.diagram-valves {
  width: 320px;
}

.diagram-slide {
  width: 520px;
}

/* Woodwind charts stand --chart-h tall (460px, less on a short phone screen
   so the staff, the keys and Check fit without scrolling): --chart-h times
   each layout's width over its height in js/diagrams/woodwind.js. They name
   a width because Safari draws a viewBox-only SVG with width: auto in this
   flex row at zero size. */
.diagram-wrap {
  --chart-h: 460px;
}

/* The flute chart lies sideways like the flute itself, so it is sized by width. */
.diagram-flute {
  width: min(100%, 560px);
}

.diagram-sax {
  width: calc(var(--chart-h) * 290 / 620);
}

.diagram-clarinet {
  width: calc(var(--chart-h) * 240 / 550);
}

.diagram-oboe {
  width: calc(var(--chart-h) * 250 / 470);
}

.diagram-bassoon {
  width: calc(var(--chart-h) * 310 / 440);
}

/* On a phone, a fingering question's staff and chart share one screen. This
   override comes after the --chart-h default above so it wins at the same
   specificity. Only the note-to-fingering question's staff shrinks
   (.prompt-fingering, js/activities/fingerings-page.js): other activities'
   prompt staffs have no chart under them. */
@media (max-height: 820px) {
  .diagram-wrap {
    /* Never below 400 px: smaller, the keys get too small to hit (UX plan 93.3). */
    --chart-h: min(460px, max(400px, 50dvh));
  }

  .prompt-fingering .staff {
    width: auto;
    max-height: 18dvh;
  }
}

.diagram-strings {
  width: 300px;
}

/* Cello and bass name their extended and half-position fingers in full down the left. */
.diagram-strings.wide-labels {
  width: 358px;
}

.diagram-keyboard {
  width: 100%;
  max-width: 920px;
}

.choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.75rem;
  width: 100%;
}

.choice {
  display: flex;
  flex-direction: column;
  align-items: center;
  height: auto;
  padding: 0.5rem;
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--foreground);
  border: 1px solid var(--border);
}

.choice:hover {
  background: var(--muted);
  opacity: 1;
}

.choice .staff {
  width: 100%;
  height: auto;
}

.choice.name {
  font-size: 1.25rem;
  font-weight: 500;
  padding: 0.9rem;
}

.choice.correct {
  border-color: var(--success);
  background: color-mix(in oklch, var(--success) 14%, var(--card));
}

.choice.wrong {
  border-color: var(--destructive);
  background: color-mix(in oklch, var(--destructive) 12%, var(--card));
}

/* Right and wrong show by more than a tint: a 2 px edge and a mark in the
   corner, at full strength even though the choices are disabled by then
   (UX plan 93.4). The mark is silent to screen readers; the feedback line
   says it in words. */
.choice.correct,
.choice.wrong {
  position: relative;
  box-shadow: inset 0 0 0 1px currentColor;
}

.choice.correct {
  box-shadow: inset 0 0 0 1px var(--success);
}

.choice.wrong {
  box-shadow: inset 0 0 0 1px var(--destructive);
}

.choice.correct::after,
.choice.wrong::after {
  position: absolute;
  top: 0.3rem;
  right: 0.5rem;
  font-size: 0.95rem;
  font-weight: 700;
  line-height: 1;
}

.choice.correct::after {
  content: '✓';
  content: '✓' / '';
  color: var(--success);
}

.choice.wrong::after {
  content: '✗';
  content: '✗' / '';
  color: var(--destructive);
}

.choice.correct:disabled,
.choice.wrong:disabled {
  opacity: 1;
}

/* Finishing an assessment early asks first (UX plan 93.5). Keep going takes
   Finish early's place: the right end of the row with a keyboard and mouse,
   where the keys line sits to its left, and the left end on a touch screen,
   where that line is hidden. */
.end-confirm {
  flex-wrap: wrap;
  flex-direction: row-reverse;
}

@media (hover: none) and (pointer: coarse) {
  .end-confirm {
    flex-direction: row;
  }
}

/* A timed round's clock: amber at a minute, red at ten seconds (UX plan 93.9). */
.stats-time.time-low {
  color: var(--warning);
}

.stats-time.time-out-soon {
  color: var(--destructive);
  font-weight: 700;
}

.stats-time.time-low .muted,
.stats-time.time-out-soon .muted {
  color: inherit;
}

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.feedback {
  min-height: 2.4rem;
  margin-top: 0.75rem;
  text-align: center;
  font-weight: 500;
}

.feedback.ok {
  color: var(--success);
}

.feedback.bad {
  color: var(--destructive);
}

.feedback.warn {
  color: var(--warning);
}

.kbd-hint {
  color: var(--muted-foreground);
  font-size: 0.75rem;
}

kbd {
  font: inherit;
  font-size: 0.75rem;
  border: 1px solid var(--input-border);
  border-bottom-width: 2px;
  border-radius: var(--radius-sm);
  padding: 0 0.35em;
  background: var(--muted);
  color: var(--foreground);
}

.btn-primary kbd {
  background: color-mix(in oklch, var(--primary-foreground) 22%, transparent);
  border-color: color-mix(in oklch, var(--primary-foreground) 40%, transparent);
  color: inherit;
}

/* ------------------------------------------------------------ staff svg */
.staff .staff-lines line,
.staff .ledger-lines line {
  stroke: var(--foreground);
  stroke-width: 1.1;
}

.staff .stem {
  stroke: var(--foreground);
  stroke-width: 1.4;
}

.staff .notehead {
  fill: var(--foreground);
}

.music-glyph {
  font-family: 'Noto Music', serif;
  fill: var(--foreground);
}

.staff-hint {
  fill: var(--muted-foreground);
  font-size: 13px;
  font-weight: 500;
  font-family: var(--font-sans);
}

/* Text under each note, 8va and 8vb, and notes marked right or wrong (roadmap phase 16). */
.staff-text,
.staff-ottava {
  fill: var(--foreground);
  font-size: 13px;
  font-family: var(--font-sans);
}

.staff-ottava {
  font-style: italic;
  font-weight: 600;
}

.staff .staff-note-right .notehead,
.staff .staff-note-right .accidental {
  fill: var(--success);
}

.staff .staff-note-right .stem,
.staff .staff-note-right .ledger-lines line {
  stroke: var(--success);
}

.staff .staff-note-wrong .notehead,
.staff .staff-note-wrong .accidental {
  fill: var(--destructive);
}

.staff .staff-note-wrong .stem,
.staff .staff-note-wrong .ledger-lines line {
  stroke: var(--destructive);
}

/* ------------------------------------------------------------ diagrams */
.diagram text {
  font-family: var(--font-sans);
}

.diagram .key {
  cursor: pointer;
  outline: none;
}

.diagram.static .key {
  cursor: default;
}

/* The invisible box behind each woodwind key that makes a thin lever as easy
   to tap as a tone hole (js/diagrams/woodwind.js). */
.diagram .key-hit {
  fill: transparent;
  stroke: none;
  pointer-events: all;
}

.diagram .key-shape {
  fill: var(--card);
  stroke: var(--foreground);
  stroke-width: 2;
  transition: fill 0.1s;
}

.diagram .key:hover .key-shape {
  fill: var(--muted);
}

.diagram.static .key:hover .key-shape {
  fill: var(--card);
}

.diagram .key:focus-visible .key-shape {
  stroke: var(--ring);
  stroke-width: 3;
}

.diagram .key.pressed .key-shape,
.diagram.static .key.pressed:hover .key-shape {
  fill: var(--primary);
  stroke: var(--primary);
}

.diagram .key-label {
  fill: var(--foreground);
  font-weight: 600;
  font-size: 18px;
  pointer-events: none;
}

.diagram .key-label.small {
  font-size: 12px;
}

.diagram .key.pressed .key-label {
  fill: var(--primary-foreground);
}

.diagram .key-caption {
  fill: var(--muted-foreground);
  font-size: 12px;
  paint-order: stroke;
  stroke: var(--card);
  stroke-width: 5px;
  stroke-linejoin: round;
}

.diagram .key-caption.strong {
  fill: var(--foreground);
  font-weight: 600;
  font-size: 15px;
}

.diagram .key.correct .key-shape,
.diagram.static .key.correct:hover .key-shape {
  fill: var(--success);
  stroke: var(--success);
}

.diagram .key.missed .key-shape,
.diagram.static .key.missed:hover .key-shape {
  fill: color-mix(in oklch, var(--success) 18%, var(--card));
  stroke: var(--success);
  stroke-dasharray: 4 3;
}

.diagram .key.wrong .key-shape,
.diagram.static .key.wrong:hover .key-shape {
  fill: var(--destructive);
  stroke: var(--destructive);
}

.diagram .key.correct .key-label {
  fill: var(--success-foreground);
}

.diagram .key.wrong .key-label {
  fill: var(--destructive-foreground);
}

.diagram .key.missed .key-label {
  fill: var(--success);
}

.diagram .body-line,
.diagram .slide-tube {
  stroke: var(--border);
  stroke-width: 6;
  stroke-linecap: round;
}

.diagram .quadrant-line {
  stroke: var(--border);
  stroke-width: 2;
}

.diagram .slide-bell,
.diagram .fingerboard {
  fill: var(--muted);
  stroke: var(--border);
}

.diagram .nut {
  fill: var(--foreground);
}

.diagram .string {
  stroke: var(--muted-foreground);
}

.diagram-keyboard .pkey.white .key-shape {
  fill: #fff;
  stroke: #555;
  stroke-width: 1;
}

.diagram-keyboard .pkey.black .key-shape {
  fill: #222;
  stroke: #222;
  stroke-width: 1;
}

.diagram-keyboard .pkey.white .key-label {
  fill: #555;
}

.diagram-keyboard .pkey.pressed .key-shape {
  fill: var(--primary);
}

.diagram-keyboard .pkey.correct .key-shape {
  fill: var(--success);
}

.diagram-keyboard .pkey.missed .key-shape {
  fill: color-mix(in oklch, var(--success) 25%, #fff);
  stroke: var(--success);
  stroke-width: 2;
}

.diagram-keyboard .pkey.wrong .key-shape {
  fill: var(--destructive);
}

/* ------------------------------------------------------------ results */
.score-big {
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 3rem;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.results-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 0.75rem;
}

.stat-tile {
  background: var(--muted);
  border-radius: var(--radius-lg);
  padding: 0.75rem 1rem;
}

.stat-tile .v {
  font-size: 1.5rem;
  font-weight: 500;
  font-family: var(--font-serif);
  font-variant-numeric: tabular-nums;
}

.stat-tile .k {
  color: var(--muted-foreground);
  font-size: 0.75rem;
}

.missed-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

textarea.report {
  width: 100%;
  min-height: 12rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  background: var(--muted);
}

.toast {
  position: fixed;
  left: 50%;
  bottom: calc(1.5rem + var(--safe-bottom));
  transform: translateX(-50%);
  background: var(--neutral);
  color: var(--neutral-foreground);
  padding: 0.55rem 1rem;
  border-radius: 999px;
  font-weight: 500;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.15s;
  z-index: 50;
}

.toast.show {
  opacity: 1;
}

/* An error stays until read (UX plan 95.2): above a passing message, with a Dismiss button, and out of the tab order while hidden. */
.toast-error {
  bottom: calc(4.75rem + var(--safe-bottom));
  display: flex;
  align-items: center;
  gap: 0.75rem;
  width: max-content;
  max-width: min(32rem, calc(100vw - 2rem));
  padding: 0.5rem 0.5rem 0.5rem 1rem;
  border-radius: var(--radius-lg);
  background: var(--destructive);
  color: var(--destructive-foreground);
  visibility: hidden;
  transition: opacity 0.15s, visibility 0.15s;
}

.toast-error.show {
  pointer-events: auto;
  visibility: visible;
}

.toast-error .toast-text {
  flex: 1;
}

.toast-error .toast-close {
  flex: none;
  color: inherit;
  border-color: color-mix(in oklch, currentColor 45%, transparent);
}

.toast-error .toast-close:hover {
  background: color-mix(in oklch, currentColor 15%, transparent);
}

/* A Copy button that just copied says so (UX plan 95.1). */
button.copied:not(.btn-primary),
.btn.copied:not(.btn-primary) {
  color: var(--success);
  border-color: var(--success);
}

/* A page's heading takes focus when the page changes (UX plan 95.4). It isn't a control, so it draws no ring: the next Tab goes on from it. */
h1[tabindex='-1']:focus,
.results-label:focus {
  outline: none;
}

.preview-staff {
  display: flex;
  gap: 1rem;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
}

.preview-staff .staff {
  width: 120px;
  height: auto;
}

/* ------------------------------------------------------------ responsive */
@media (max-width: 560px) {
  .topbar {
    padding: 0.5rem 0.75rem;
    gap: 0.75rem;
  }

  /* Phones keep the name beside the mark, a size smaller, and the byline at
     12px, the smallest text the page audit allows on a phone. Slightly
     narrower nav links make the room, so all of it fits on one line from
     360px up; the links keep their height. */
  .brand {
    gap: 0.4rem;
  }

  .brand-name {
    font-size: 1rem;
  }

  .topnav a {
    padding: 0.4rem 0.45rem;
  }

  .app {
    padding: 1rem 1rem 2rem;
  }

  .card {
    padding: 1rem;
  }

  .hub-list {
    padding: 0;
  }

  .hub-section-title {
    padding: 0.9rem 1rem 0.4rem;
  }

  .hub-row {
    gap: 0.75rem;
    padding: 0.65rem 1rem;
  }

  /* Two tiles across on phones: icon, name and who it's for. */
  .practice-tiles {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem;
  }

  .tile-link {
    gap: 0.6rem;
    padding: 1rem;
    min-height: 8.25rem;
  }

  .tile-icon {
    width: 2.5rem;
    height: 2.5rem;
  }

  .tile-name {
    font-size: 0.9375rem;
  }

  .tile-blurb,
  .tile-foot .tile-chevron {
    display: none;
  }

  .tile-change {
    margin: -0.4rem 1rem 0.9rem;
  }

  .tool-row {
    padding: 0.75rem 1rem;
  }
}

/* Below 360px the name and the three links don't fit on one line, so the
   mark stands alone, as it always has there; the footer still says where
   Woodshed comes from. */
@media (max-width: 359px) {
  .brand-text {
    display: none;
  }
}

/* Less motion when asked, for animations added later too. */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition: none !important;
    scroll-behavior: auto !important;
  }
}

/* ---------------------------------------------- skill pathway assessments */
.choice.chosen {
  border-color: var(--ring);
  background: var(--accent);
  color: var(--accent-foreground);
}
.pathway-notes ul,
.review-list {
  margin: 0.25rem 0 0;
  padding-left: 1.25rem;
  display: grid;
  gap: 0.35rem;
}
.review-list li span + span {
  margin-left: 0.5rem;
}
.pathway-status {
  padding: 0.75rem 1rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
  background: var(--muted);
  font-weight: 500;
}
.pathway-status.ok {
  border-color: var(--success);
  background: color-mix(in oklch, var(--success) 12%, var(--card));
}
.pathway-status.warn {
  border-color: var(--warning);
  background: color-mix(in oklch, var(--warning) 12%, var(--card));
}
.pathway-status.bad {
  border-color: var(--destructive);
  background: color-mix(in oklch, var(--destructive) 10%, var(--card));
}
.field-error {
  margin: 0;
  color: var(--destructive);
}
.field-error:empty {
  display: none;
}
.pp-card {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}
.pp-card > .stack {
  flex: 1 1 26rem;
  min-width: 0;
}

@media print {
  .topbar,
  .update-banner,
  .footer,
  button {
    display: none !important;
  }
}

/* The copyright line at the foot of every printed page, whatever prints: a
   worksheet, an answer key, a fingering chart or scale sheet, the glossary,
   any page. main sits in a real table (index.html, privacy.html,
   support.html) whose footer is the line: printed, the browser repeats a
   table's footer at the bottom of each page (a CSS table's it doesn't). On
   screen the table, its body and its cell have no boxes of their own, so main
   is a flex child of body as before, and the footer doesn't show. */
@media not print {
  .print-frame,
  .print-frame > tbody,
  .print-frame > tbody > tr,
  .print-frame > tbody > tr > td {
    display: contents;
  }

  .print-frame > tfoot {
    display: none;
  }
}

@media print {
  .print-frame {
    width: 100%;
    table-layout: fixed;
    border-collapse: collapse;
  }

  .print-frame > tbody > tr > td {
    padding: 0;
  }

  .print-copyright {
    padding: 0.5rem 0 0;
    color: #444;
    font-size: 7.5pt;
    text-align: center;
  }
}

/* ------------------------------------------------------------ My progress */
.btn-danger {
  background: var(--destructive);
  color: var(--destructive-foreground);
  border-color: transparent;
}

/* A button that reads as a link, inside a sentence. */
.text-button,
.text-button:hover {
  height: auto;
  padding: 0;
  border: 0;
  background: none;
  color: var(--primary);
  font: inherit;
  text-decoration: underline;
  text-underline-offset: 0.15em;
  opacity: 1;
}

.history-note .clear-history {
  display: inline;
}

.history-note .clear-history .btn-sm {
  margin-left: 0.25rem;
}

.progress-actions .clear-history {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.resume-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.progress-filter {
  display: flex;
}

/* Whose sessions (on a device with more than one name) and the PDF of what's shown (roadmap phase 45). */
.progress-whose {
  max-width: 20rem;
}

.progress-whose[hidden],
.progress-shown[hidden],
.progress-recap-link[hidden],
.progress-badges[hidden] {
  display: none;
}

.progress-shown {
  padding-top: 0.25rem;
}

.progress-list {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}

.progress-entry {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr) auto;
  grid-template-areas: 'when what score' 'when what actions';
  gap: 0.35rem 1rem;
  padding: 0.9rem 0;
  border-bottom: 1px solid var(--border);
}

.progress-when {
  grid-area: when;
  display: flex;
  flex-direction: column;
}

.progress-what {
  grid-area: what;
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.progress-score {
  grid-area: score;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
}

.progress-actions-row {
  grid-area: actions;
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  align-items: flex-start;
  gap: 0.4rem;
}

.score-pill {
  display: inline-block;
  background: var(--muted);
  border-radius: var(--radius-md);
  padding: 0.2rem 0.5rem;
  font-variant-numeric: tabular-nums;
}

.progress-entry.is-test .score-pill {
  background: var(--accent);
  color: var(--accent-foreground);
}

.progress-sent {
  color: var(--primary);
}

.progress-unsent {
  color: var(--destructive);
}

.progress-empty {
  padding: 2rem 0;
  text-align: center;
}

.progress-empty > * + * {
  margin-top: 0.75rem;
}

@media (max-width: 560px) {
  .progress-entry {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas: 'when score' 'what what' 'actions actions';
  }

  .progress-when {
    flex-direction: row;
    gap: 0.5rem;
    align-items: baseline;
  }

  .progress-actions-row {
    justify-content: flex-start;
  }
}

/* ------------------------------------------------------------ shared frames (js/frames.js) */
/* The activity header sits above the page: trail, heading, "Assigned by",
   and Settings on the right. On phones Settings shares the trail's row. */
.activity-header {
  margin-bottom: 1.25rem;
}

.activity-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: 'trail settings' 'title settings' 'meta settings' 'lead settings';
  column-gap: 1rem;
  align-items: end;
}

.trail {
  grid-area: trail;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.trail a {
  color: inherit;
}

.trail a:hover {
  color: var(--foreground);
}

.activity-head > h1 {
  grid-area: title;
  margin: 0.25rem 0 0;
  overflow-wrap: anywhere;
}

.activity-meta {
  grid-area: meta;
  margin: 0.25rem 0 0;
}

.activity-lead {
  grid-area: lead;
  margin: 0.5rem 0 0;
  max-width: 44rem;
}

.activity-settings {
  grid-area: settings;
  align-self: end;
  height: 2.5rem;
}

.settings-icon {
  width: 1.15rem;
  height: 1.15rem;
}

@media (max-width: 560px) {
  .activity-head {
    grid-template-areas: 'trail settings' 'title title' 'meta meta' 'lead lead';
    align-items: center;
  }

  .activity-settings {
    align-self: center;
  }
}

/* Builders: grouped setting cards, and the link card beside them on wide
   screens (it stays in view) or last on phones. */
.builder-head {
  margin-bottom: 1.25rem;
}

.builder-head h1 {
  margin-bottom: 0.25rem;
}

.builder-intro {
  max-width: 40rem;
  margin: 0;
}

.builder-body {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.25rem;
}

.builder-settings {
  flex: 999 1 34rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

.builder-settings > .card + .card {
  margin-top: 0;
}

.builder-group {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  padding: 1.25rem 1.5rem;
}

.builder-group[hidden] {
  display: none;
}

.builder-group-title {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

.link-card {
  flex: 1 1 18rem;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 0.85rem;
}

.link-card > * {
  margin: 0;
}

.builder-settings + .link-card {
  margin-top: 0;
}

@media (min-width: 900px) {
  .link-card {
    position: sticky;
    top: calc(4.5rem + var(--safe-top));
  }
}

/* ------------------------------------------------------------ score PDF (js/score-page.js, #check) */
/* The start screen's line in the activity header. */
.sessions-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1rem;
  margin-top: 0.75rem;
  padding: 0.55rem 0.9rem;
  border-radius: var(--radius-lg);
  background: var(--muted);
  font-size: 0.8125rem;
}

.sessions-line[hidden] {
  display: none;
}

.table-scroll {
  overflow-x: auto;
}

.check-table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.8125rem;
}

.check-table th,
.check-table td {
  padding: 0.5rem 0.6rem;
  border-bottom: 1px solid var(--border);
  text-align: left;
  white-space: nowrap;
}

.check-table th {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--muted-foreground);
}

.check-table .num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.check-ok {
  color: var(--success);
  font-weight: 600;
}

.check-no {
  color: var(--destructive);
  font-weight: 600;
}

.check-bad td {
  background: color-mix(in oklch, var(--destructive) 6%, transparent);
}

/* ------------------------------------------------------------ phase 8: settings rows and the Settings panel */
/* Settings rows (js/setting-rows.js): the same rows on a builder's cards and
   in an activity's Settings panel. Each row shows its value, as a small
   picture where one exists; short choices are segmented buttons in the row,
   and rows with many choices open a panel. */
.setting-list {
  margin: -0.35rem 0;
}

.setting-row {
  padding: 0.7rem 0;
}

.setting-row[hidden] {
  display: none;
}

.setting-row:not([hidden]) ~ .setting-row:not([hidden]) {
  border-top: 1px solid var(--border);
}

.setting-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.setting-label {
  flex: 1 1 9rem;
  min-width: 0;
  font-weight: 500;
}

.setting-seg {
  flex: 0 1 auto;
}

.setting-seg button {
  height: auto;
  min-height: 2.25rem;
  padding: 0.35rem 0.85rem;
  white-space: normal;
  text-align: center;
}

.setting-toggle .sign-picture {
  margin: -0.2rem 0 -0.2rem -0.2rem;
}

/* Far enough under the row's buttons and boxes that their focus ring (2px,
   2px out) clears the words. */
.setting-help {
  margin: 0.5rem 0 0;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.setting-help[hidden] {
  display: none;
}

.setting-field input {
  flex: 1 1 14rem;
  max-width: 24rem;
}

.setting-number-box {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.setting-number-box input,
.setting-field input {
  font-weight: 400;
}

/* The tempo box. Scoped to settings rows: other number inputs (the
   metronome's big tempo display) keep their own styles. Three classes deep
   so rhythm.css's .rhythm-create input[type='number'] can't widen it. */
.setting-row .setting-number-box input[type='number'] {
  font: inherit;
  width: 6rem;
  height: 2.25rem;
  padding: 0 0.6rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--input-border);
  background: var(--card);
  color: var(--foreground);
}

/* A row that opens a panel: the whole row is its button. The value sits on
   the label's line when it fits and under it when it doesn't. */
.setting-open {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.75rem;
  width: calc(100% + 1rem);
  height: auto;
  min-height: 2.75rem;
  margin: -0.35rem -0.5rem;
  padding: 0.35rem 0.5rem;
  background: transparent;
  color: var(--foreground);
  border: 0;
  text-align: left;
  white-space: normal;
}

.setting-open:hover {
  background: var(--muted);
  opacity: 1;
}

/* The row reaches out into the space around it, so its focus ring goes just
   inside its edge, around the area hover fills, not over the help line under it. */
.setting-open:focus-visible {
  outline-offset: -2px;
}

.setting-open-text {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 1rem;
  min-width: 0;
}

.setting-open .setting-label {
  flex: 1 0 auto;
  max-width: 100%;
}

.setting-open .setting-value {
  margin-left: auto;
  justify-content: flex-end;
  text-align: right;
}

.setting-chevron {
  width: 1.1rem;
  height: 1.1rem;
  color: var(--muted-foreground);
}

.setting-value {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.5rem;
  min-width: 0;
  font-weight: 400;
  color: var(--muted-foreground);
}

.is-static .setting-value {
  color: var(--foreground);
  margin-left: auto;
  justify-content: flex-end;
  text-align: right;
}

.setting-number .setting-label {
  flex-basis: 6rem;
}

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

/* Pictures (js/setting-pictures.js). */
.range-picture {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  color: var(--foreground);
}

.range-picture .staff {
  display: block;
  max-width: 5.5rem;
  height: auto;
}

.range-to {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.sign-strip {
  display: inline-flex;
  align-items: center;
  gap: 0.1rem;
}

.sign-picture {
  display: block;
  overflow: visible;
}

/* A custom rhythm level's patterns (roadmap phase 10), drawn by the staff's
   own code (js/rhythm-staff.js) in currentColor, so they follow the theme. */
.rhythm-strip {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: 0.25rem 0.6rem;
  color: var(--foreground);
}

.rhythm-icon {
  display: block;
  flex: none;
  overflow: visible;
}

.rhythm-more {
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* "Rhythms in this exercise" in a rhythm page's header (roadmap phase 14):
   every pattern the measures can use, wrapping on phones. */
.rhythms-line {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.35rem 0.9rem;
  margin-top: 0.75rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.rhythms-line .rhythm-strip {
  justify-content: flex-start;
}

/* Panels: a modal <dialog>, docked at the side on wide screens and filling
   the screen on phones. A panel opened from another sits over it. */
dialog.sheet {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  height: 100dvh;
  max-width: 100%;
  max-height: 100%;
  max-height: 100dvh;
  margin: 0;
  padding: 0;
  border: 0;
  background: var(--card);
  color: var(--card-foreground);
  overflow: hidden;
  /* Its edges' safe-area insets: the panel's own color fills in under the
     status bar and notch, and its title, close button and Done stay clear
     of them. A docked panel has no left inset; it never reaches that edge. */
  --sheet-left: var(--safe-left);
  --sheet-right: var(--safe-right);
}

dialog.sheet::backdrop {
  background: oklch(0.2 0.02 210 / 45%);
}

dialog.sheet + dialog.sheet::backdrop {
  background: transparent;
}

@media (min-width: 720px) {
  dialog.sheet {
    inset: 0 0 0 auto;
    width: 26rem;
    border-left: 1px solid var(--border);
    box-shadow: var(--shadow);
    --sheet-left: 0px;
  }
}

.sheet-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.sheet-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: calc(0.85rem + var(--safe-top)) max(1rem, var(--sheet-right)) 0.85rem max(1.25rem, var(--sheet-left));
  border-bottom: 1px solid var(--border);
}

.sheet-title {
  margin: 0;
  font-size: 1.25rem;
}

.sheet-close {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  font-size: 1.5rem;
  line-height: 1;
}

.sheet-body {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1rem max(1.25rem, var(--sheet-right)) 1.25rem max(1.25rem, var(--sheet-left));
}

.sheet-lead {
  margin: 0 0 1rem;
}

.sheet-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  padding: 0.85rem max(1.25rem, var(--sheet-right)) max(0.85rem, var(--safe-bottom)) max(1.25rem, var(--sheet-left));
  border-top: 1px solid var(--border);
}

.sheet-done {
  margin-left: auto;
}

.sheet-create {
  font-weight: 500;
  color: var(--foreground);
}

.sheet-status {
  margin: 0.75rem 0 0;
  min-height: 0;
  text-align: left;
}

.sheet-status[hidden] {
  display: none;
}

.sheet-preview {
  display: flex;
  justify-content: center;
  padding: 0.5rem 0;
}

.sheet-preview .range-picture .staff {
  max-width: 7rem;
}

.settings-section + .settings-section {
  margin-top: 1.25rem;
}

.settings-section[hidden] + .settings-section {
  margin-top: 0;
}

.settings-group,
.choice-group {
  margin: 0 0 0.35rem;
  font-family: var(--font-sans);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

.choice-family + .choice-family {
  margin-top: 0.75rem;
}

.choice-list,
.choice-family,
.choice-checks {
  display: grid;
  gap: 0.25rem;
}

.choice-check:has(input:checked) {
  border-color: var(--primary);
  background: var(--accent);
  color: var(--accent-foreground);
}

/* 16px on phones, so focusing the box doesn't zoom the page. */
@media (max-width: 720px) {
  .setting-row .setting-number-box input[type='number'] {
    font-size: 1rem;
  }
}

.choice-option {
  justify-content: space-between;
  width: 100%;
  height: auto;
  min-height: 2.75rem;
  padding: 0.5rem 0.75rem;
  background: transparent;
  color: var(--foreground);
  text-align: left;
  white-space: normal;
}

.choice-option:hover {
  background: var(--muted);
  opacity: 1;
}

.choice-option.active {
  background: var(--accent);
  color: var(--accent-foreground);
}

.choice-text {
  display: grid;
  gap: 0.1rem;
}

.choice-option:not(.active) .choice-mark {
  visibility: hidden;
}

.choice-hint {
  font-size: 0.8125rem;
  font-weight: 400;
  color: var(--muted-foreground);
}

.choice-option.active .choice-hint {
  color: inherit;
}

.choice-checks {
  margin: 0;
  padding: 0;
  border: 0;
}

.choice-check {
  height: auto;
  min-height: 2.75rem;
  padding: 0.5rem 0.75rem;
}

/* A checklist in cards, each with Select all and Clear: the rhythm palette,
   whose options are notation (roadmap phase 10). */
.choice-cards {
  gap: 0.75rem;
}

.choice-card {
  display: grid;
  gap: 0.5rem;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
}

.choice-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem 0.75rem;
}

.choice-card-head .choice-group {
  margin: 0;
}

.choice-card-tools {
  display: inline-flex;
  gap: 1rem;
  font-size: 0.875rem;
}

.choice-card-tools .text-button {
  min-height: 1.5rem;
}

.choice-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.choice-tile {
  gap: 0.6rem;
  min-height: 3.25rem;
  padding: 0.35rem 0.75rem;
  color: var(--foreground);
}

/* A pattern that doesn't fit the measure (roadmap phase 14): grayed out, with why. */
.choice-check:has(input:disabled) {
  opacity: 0.55;
  cursor: not-allowed;
}

.choice-tile-hint {
  max-width: 7.5rem;
  font-size: 0.75rem;
  line-height: 1.25;
  color: var(--muted-foreground);
}

.setting-toggle .music-glyph {
  fill: currentColor;
}

/* ------------------------------------------------------------ practice routines (roadmap phase 26) */
/* The runner (js/routine-page.js): the step list beside the stage on wide
   screens, above it on phones; each step's activity runs in the stage. The
   builder (js/routine-create.js): steps in order with a goal each. */
.routine-plan,
.routine-review,
.routine-steps,
.routine-edit-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.routine-plan > li,
.routine-review > li,
.routine-edit-step {
  display: grid;
  grid-template-columns: 2rem minmax(0, 1fr);
  gap: 0.5rem 0.75rem;
  align-items: start;
  padding: 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}

.routine-review > li {
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
}

.routine-num {
  width: 2rem;
  height: 2rem;
  border-radius: 999px;
  display: inline-grid;
  place-items: center;
  background: var(--accent);
  color: var(--accent-foreground);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.routine-plan-text,
.routine-edit-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
}

.routine-plan-text strong,
.routine-edit-text strong {
  font-weight: 500;
  overflow-wrap: anywhere;
}

.routine-run {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1.25rem;
  align-items: start;
}

.routine-run > *,
.routine-stage,
.routine-stage-host {
  min-width: 0;
}

.routine-run > .card + .card {
  margin-top: 0;
}

.routine-rail {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  padding: 1rem 1.1rem;
}

.routine-rail > * {
  margin: 0;
}

.routine-rail-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.5rem;
}

.routine-rail-head h2 {
  margin: 0;
  font-size: 1.125rem;
}

.routine-progress {
  margin: 0;
}

.routine-now {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
}

.routine-clock-box {
  display: flex;
  flex-direction: column;
}

.routine-clock {
  font-family: var(--font-serif);
  font-size: 1.75rem;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
}

.routine-moves button[hidden] {
  display: none;
}

.routine-goal-line {
  color: var(--muted-foreground);
}

.routine-other {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  font-weight: 400;
}

.routine-steps-wrap > summary {
  cursor: pointer;
  font-weight: 500;
  padding: 0.25rem 0;
}

.routine-steps-wrap[open] > summary {
  margin-bottom: 0.5rem;
}

.routine-steps {
  gap: 0.25rem;
}

.routine-step {
  display: grid;
  grid-template-columns: 1.75rem minmax(0, 1fr);
  gap: 0.6rem;
  align-items: center;
  padding: 0.4rem 0.5rem;
  border-radius: var(--radius-md);
}

.routine-step[aria-current='step'] {
  background: var(--accent);
  color: var(--accent-foreground);
}

.routine-step-mark {
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 999px;
  display: inline-grid;
  place-items: center;
  font-size: 0.75rem;
  font-weight: 600;
  border: 1px solid var(--input-border);
  background: var(--card);
  color: var(--foreground);
}

.routine-step[data-status='done'] .routine-step-mark {
  background: var(--success);
  color: var(--success-foreground);
  border-color: transparent;
}

.routine-step[data-status='skipped'] .routine-step-mark {
  border-style: dashed;
  color: var(--muted-foreground);
}

.routine-step[aria-current='step'] .routine-step-mark {
  background: var(--primary);
  color: var(--primary-foreground);
  border-color: transparent;
}

.routine-step-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.routine-step-name {
  font-weight: 500;
  overflow-wrap: anywhere;
}

.routine-step-said {
  color: var(--muted-foreground);
}

.routine-step[aria-current='step'] .routine-step-said {
  color: inherit;
}

.routine-step-head {
  margin-bottom: 1rem;
}

.routine-step-head > * {
  margin: 0;
}

.routine-step-head h2 {
  margin-top: 0.15rem;
  overflow-wrap: anywhere;
  scroll-margin-top: calc(5rem + var(--safe-top));
}

.routine-step-goal {
  margin-top: 0.25rem;
}

.routine-step-head h2:focus,
.routine-set-card h3:focus,
.routine-results h2:focus {
  outline: none;
}

.routine-set-card h3 {
  margin: 0;
  font-size: 1.25rem;
}

.routine-metro {
  gap: 0.75rem;
}

.routine-metro > * {
  margin: 0;
}

.routine-metro-bpm {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.routine-metro-number {
  font-family: var(--font-serif);
  font-size: 4rem;
  line-height: 1.05;
  font-variant-numeric: tabular-nums;
}

.routine-metro-volume {
  width: 100%;
  max-width: 20rem;
  text-align: left;
}

.routine-metro-volume input {
  width: 100%;
  accent-color: var(--primary);
}

@media (min-width: 900px) {
  .routine-run {
    grid-template-columns: 17rem minmax(0, 1fr);
  }

  .routine-rail {
    position: sticky;
    top: calc(4.5rem + var(--safe-top));
  }
}

/* The builder. */
.routine-empty {
  padding: 1rem;
  border: 1px dashed var(--input-border);
  border-radius: var(--radius-lg);
  color: var(--muted-foreground);
}

.routine-empty[hidden],
.routine-edit-list[hidden] {
  display: none;
}

.routine-empty p {
  margin: 0;
}

.routine-edit-controls {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
}

.routine-edit-goal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.4rem;
}

.routine-edit-goal label {
  font-weight: 500;
}

.routine-edit-actions {
  display: flex;
  gap: 0.35rem;
}

.icon-button {
  width: 2.25rem;
  padding: 0;
}

.icon-button .icon {
  width: 1.1rem;
  height: 1.1rem;
}

.routine-create input[type='number'],
.routine-create .routine-goal-unit {
  font: inherit;
  height: 2.25rem;
  padding: 0 0.5rem;
  border-radius: var(--radius-md);
  border: 1px solid var(--input-border);
  background: var(--card);
  color: var(--foreground);
}

.routine-create .routine-goal-n {
  width: 4rem;
}

/* Labels sit side by side only when both fit. */
.routine-create .grid.two {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 16rem), 1fr));
}

.routine-start {
  max-width: 48rem;
}

.routine-create select.routine-goal-unit {
  width: auto;
}

.routine-create .routine-goal-unit {
  min-width: 6.5rem;
}

.routine-create .builder-group > p {
  margin: 0;
}

.routine-create span.routine-goal-unit {
  border: 0;
  padding: 0;
  display: inline-flex;
  align-items: center;
}

.routine-add-step {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-top: 0.5rem;
  border-top: 1px solid var(--border);
}

.routine-add-step > * {
  margin: 0;
}

.routine-add-step h3 {
  margin-top: 0.5rem;
}

.routine-add-step label.field span {
  margin-bottom: 0;
}

.routine-paste-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.routine-paste-row input {
  flex: 1 1 14rem;
  min-width: 0;
}

.routine-metro-row {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}

.routine-metro-row label.field {
  flex: 1 1 5.5rem;
}

.routine-metro-row label.field span {
  margin-bottom: 0.35rem;
}

.routine-metro-row input,
.routine-metro-row select {
  width: 100%;
}

.routine-warmup,
.routine-clear {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.routine-warmup p {
  margin: 0;
  flex-basis: 100%;
}

.routine-length {
  min-height: 0;
  text-align: left;
}

/* "Add to routine" beside every builder's "Student link" heading (js/routine-draft.js). */
.link-card-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.25rem 0.5rem;
}

.link-card-head h2 {
  margin: 0;
}

/* A real button, not a link-styled one: it's the way into a whole feature. */
.routine-add {
  gap: 0.25rem;
  font-size: 0.8125rem;
}

.routine-add-icon {
  width: 0.9rem;
  height: 0.9rem;
}

.routine-add-status {
  margin: 0;
}

.routine-add-status:empty {
  display: none;
}

@media (min-width: 640px) {
  .routine-edit-step {
    grid-template-columns: 2rem minmax(0, 1fr) auto;
  }

  .routine-edit-controls {
    grid-column: 3;
    justify-content: flex-end;
    align-self: center;
  }
}

@media (max-width: 720px) {
  .routine-create input[type='number'] {
    font-size: 1rem;
  }
}

/* ------------------------------------------------------------ audition kits (roadmap phase 42) */
/* A kit's page (js/audition-page.js) runs on the routine's layout: the parts
   beside the stage on wide screens, above it on phones. Practice lists its
   parts as buttons, to take in any order. The builder
   (js/audition-create.js) lists the scales, each with its key, scale and
   octaves. */
.audition-start {
  max-width: 48rem;
}

.audition-part-about > * {
  margin: 0;
}

.audition-part-about > * + * {
  margin-top: 0.5rem;
}

/* Every heading on the start card the same size: the parts and "How a mock audition goes". */
.audition-start h2 {
  font-size: 1.125rem;
}

.audition-scale-list {
  margin: 0;
  padding-left: 1.25rem;
  display: grid;
  gap: 0.25rem;
}

/* A director's etude note may hold a note value (♩ = 92): Noto Music draws what DM Sans hasn't. */
.audition-etude-text {
  font-family: 'DM Sans', 'Noto Music', ui-sans-serif, system-ui, sans-serif;
  font-size: 1.0625rem;
  font-weight: 500;
  overflow-wrap: anywhere;
}

.audition-etude-card > * {
  margin: 0;
}

.audition-parts > li {
  list-style: none;
}

.audition-part-open {
  width: 100%;
  height: auto;
  min-height: 2.75rem;
  text-align: left;
  white-space: normal;
  font-weight: 400;
  background: transparent;
  color: inherit;
  border: 0;
}

.audition-part-open:hover {
  background: var(--muted);
  opacity: 1;
}

.audition-part-open[aria-current='step'],
.audition-part-open[aria-current='step']:hover {
  background: var(--accent);
  color: var(--accent-foreground);
}

.audition-review + .audition-review {
  margin-top: 0.75rem;
}

.audition-review p {
  margin: 0 0 0.25rem;
}

.audition-edit-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.audition-edit-list[hidden] {
  display: none;
}

.audition-edit-scale .routine-edit-text strong {
  overflow-wrap: anywhere;
}

.audition-edit-controls {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
}

.audition-edit-controls select {
  width: auto;
  flex: 1 1 6.5rem;
  min-width: 0;
}

.audition-edit-controls .icon-button {
  flex: none;
}

.audition-order {
  margin: 0;
  overflow-wrap: anywhere;
}

/* ------------------------------------------------------------ marching drill (roadmap phase 40) */
/* The field (js/drill-field.js) is drawn in steps; its lines keep one
   screen width at any zoom. Dark lines on light turf in light mode, light
   lines on dark turf in dark mode, for reading outdoors. */
:root {
  --drill-turf: oklch(0.955 0.03 145);
  --drill-endzone: oklch(0.915 0.04 145);
  --drill-outside: oklch(0.92 0.018 90);
  --drill-line: oklch(0.4 0.05 155);
  --drill-grid: oklch(0.4 0.05 155 / 16%);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
    --drill-turf: oklch(0.29 0.035 155);
    --drill-endzone: oklch(0.33 0.04 155);
    --drill-outside: oklch(0.23 0.015 210);
    --drill-line: oklch(0.9 0.025 150);
    --drill-grid: oklch(0.9 0.025 150 / 14%);
  }
}

:root[data-theme='dark'] {
  --drill-turf: oklch(0.29 0.035 155);
  --drill-endzone: oklch(0.33 0.04 155);
  --drill-outside: oklch(0.23 0.015 210);
  --drill-line: oklch(0.9 0.025 150);
  --drill-grid: oklch(0.9 0.025 150 / 14%);
}

/* Marching is the first Practice section with a single tile: keep every
   tile one column wide, as on phones, so none takes more room than another. */
@media (min-width: 561px) {
  .practice-tiles {
    grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  }
}

/* A drill question uses the full width: the field, then the answers. */
.question.drill-question {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1rem;
}

.drill-prompt {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

.drill-prompt > p {
  margin: 0;
}

.drill-ask {
  font-family: var(--font-serif);
  font-size: 1.25rem;
  line-height: 1.3;
}

.drill-coord {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--muted);
  padding: 0.65rem 0.9rem;
}

.drill-coord-title {
  margin: 0 0 0.35rem;
  font-weight: 600;
}

.drill-coord dl {
  margin: 0;
  display: grid;
  gap: 0.35rem;
}

.drill-coord dl > div {
  display: grid;
  grid-template-columns: 7.5rem minmax(0, 1fr);
  gap: 0.75rem;
}

.drill-coord dt {
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}

.drill-coord dd {
  margin: 0;
  font-weight: 600;
  font-size: 0.9375rem;
}

.drill-pair {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 0.75rem;
}

@media (max-width: 420px) {
  .drill-coord dl > div {
    grid-template-columns: 1fr;
    gap: 0;
  }
}

.drill-field-wrap {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--drill-outside);
}

.drill-field-wrap[role='application'] {
  cursor: crosshair;
  touch-action: manipulation;
}

.drill-field-wrap:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.drill-field {
  display: block;
  width: 100%;
  height: auto;
  font-family: var(--font-sans);
  user-select: none;
  -webkit-user-select: none;
}

.drill-field .drill-outside {
  fill: var(--drill-outside);
}

.drill-field .drill-turf {
  fill: var(--drill-turf);
}

.drill-field .drill-endzone {
  fill: var(--drill-endzone);
}

.drill-field line,
.drill-field .drill-boundary {
  vector-effect: non-scaling-stroke;
  stroke: var(--drill-line);
}

.drill-field .drill-grid {
  stroke: var(--drill-grid);
  stroke-width: 1px;
}

.drill-field .drill-yard {
  stroke-width: 1.5px;
}

.drill-field .drill-fifty {
  stroke-width: 2.25px;
}

.drill-field .drill-goal {
  stroke-width: 2.75px;
}

.drill-field .drill-hash-tick {
  stroke-width: 1.5px;
}

.drill-field .drill-hash-yard {
  stroke-width: 2px;
}

.drill-field .drill-hash-line {
  stroke-width: 0.75px;
  stroke-dasharray: 2 3;
}

.drill-field .drill-boundary {
  fill: none;
  stroke-width: 2.5px;
}

.drill-field text {
  fill: var(--drill-line);
  stroke: var(--drill-turf);
  paint-order: stroke;
  stroke-linejoin: round;
}

.drill-field .drill-number {
  font-weight: 600;
}

.drill-field .drill-landmark,
.drill-field .drill-side {
  font-weight: 500;
}

.drill-field .drill-arrow {
  fill: var(--drill-line);
}

.drill-field .drill-dot circle {
  stroke: var(--drill-turf);
  stroke-width: 2px;
  vector-effect: non-scaling-stroke;
}

.drill-field .drill-dot.target circle {
  fill: var(--primary);
}

.drill-field .drill-dot.ref circle {
  fill: var(--muted-foreground);
}

.drill-field .drill-dot.ok circle {
  fill: var(--success);
}

.drill-field .drill-dot.bad circle {
  fill: var(--destructive);
}

.drill-field .drill-dot.mine circle {
  fill: none;
  stroke: var(--foreground);
  stroke-width: 2.5px;
}

.drill-field .drill-dot.mine .drill-dot-center {
  fill: var(--foreground);
  stroke: none;
}

.drill-field .drill-caption {
  font-weight: 600;
}

.drill-field .drill-move line {
  stroke: var(--foreground);
  stroke-width: 2px;
  stroke-dasharray: 5 4;
}

.drill-field .drill-move path {
  fill: var(--foreground);
}

.drill-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1.25rem;
}

.drill-nudges {
  display: flex;
  gap: 0.35rem;
}

.drill-nudge {
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
}

.drill-nudge-icon {
  width: 1.2rem;
  height: 1.2rem;
}

.drill-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 0.75rem;
}

.choice.drill-choice {
  flex-direction: row;
  align-items: flex-start;
  justify-content: flex-start;
  gap: 0.75rem;
  padding: 0.75rem 0.9rem;
  text-align: left;
  white-space: normal;
}

.drill-choice-n {
  flex-shrink: 0;
  display: grid;
  place-items: center;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.75rem;
}

.drill-choice-text {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
  min-width: 0;
}

.drill-size {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-weight: 500;
}

.drill-size input {
  width: 5rem;
}

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

/* Start screen: the activity and hash switch, and the whole field small. */
.drill-switch {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.drill-seg a {
  display: inline-flex;
  align-items: center;
  height: 2.25rem;
  padding: 0 0.85rem;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
  font-weight: 500;
  text-decoration: none;
  white-space: nowrap;
}

.drill-seg a:hover {
  background: var(--muted);
}

.drill-seg a.active {
  background: var(--accent);
  color: var(--accent-foreground);
  border-color: transparent;
}

.drill-overview {
  margin-inline: 0;
  margin-bottom: 0;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.drill-overview .drill-field {
  max-width: 40rem;
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
}

.drill-overview figcaption {
  margin: 0;
}

.drill-sheet-line {
  font-weight: 500;
}

/* Your dot sheet: paste, see what was read, saved sheets. */
textarea.drill-sheet-input {
  min-height: 9rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.8125rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.drill-sheet-status > * {
  margin: 0;
}

.drill-sheet-status > * + * {
  margin-top: 0.5rem;
}

.drill-read {
  font-weight: 600;
}

.drill-read.ok {
  color: var(--success);
}

.drill-read.bad,
.drill-sheet-errors {
  color: var(--destructive);
}

.drill-sheet-errors p {
  margin: 0;
}

.drill-sheet-errors ul {
  margin: 0.25rem 0 0;
  padding-left: 1.25rem;
  overflow-wrap: anywhere;
}

.drill-sheet-table summary {
  cursor: pointer;
  font-weight: 500;
}

.drill-sheet-table .check-table td {
  white-space: normal;
}

.drill-saved {
  list-style: none;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--border);
}

.drill-saved-item {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--border);
}

.drill-saved-name {
  display: flex;
  flex-direction: column;
  min-width: 0;
  overflow-wrap: anywhere;
}

/* ---------------------------------------------- scales (roadmap phase 21) */
.scale-prompt {
  gap: 0.35rem;
}

.scale-name {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.25rem;
}

.scale-progress {
  margin: 0;
}

.scale-staff-scroll {
  max-width: 100%;
  overflow-x: auto;
}

.scale-staff-scroll svg {
  display: block;
  margin: 0 auto;
  max-width: none;
}

.staff-note-current .notehead,
.staff-note-current .accidental {
  fill: var(--primary);
}

.staff-note-current .stem,
.staff-note-current .ledger-lines line {
  stroke: var(--primary);
}

.staff-note-done .notehead,
.staff-note-done .accidental {
  fill: var(--muted-foreground);
}

.staff-note-done .stem {
  stroke: var(--muted-foreground);
}

.scale-list {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
}

/* ---------------------------------------------- key signatures (roadmap phase 21) */
.keysig-prompt {
  gap: 0.5rem;
}

.keysig-key {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 2rem;
}

.keysig-staff {
  max-width: 100%;
  height: auto;
}

.keysig-order {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.25rem;
  margin: 0;
}

.keysig-chip {
  display: inline-grid;
  place-items: center;
  min-width: 2.5rem;
  height: 2.25rem;
  padding: 0 0.5rem;
  border: 1.5px solid var(--input-border);
  border-radius: var(--radius-md);
  font-weight: 600;
}

.keysig-chip.blank {
  border-style: dashed;
  color: var(--muted-foreground);
}

.keysig-order.correct .keysig-chip {
  border-color: var(--success);
}

.keysig-order.wrong .keysig-chip {
  border-color: var(--destructive);
}

.keysig-build {
  display: grid;
  gap: 0.75rem;
  justify-items: center;
  width: 100%;
}

.keysig-taps {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.35rem;
  width: 100%;
  max-width: 28rem;
}

.keysig-tap {
  padding: 0;
  background: var(--card);
  color: var(--foreground);
  border-color: var(--input-border);
}

.keysig-counts {
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

.keysig-answer svg {
  max-width: 100%;
  height: auto;
}

/* ---------------------------------------------- finger patterns (roadmap phase 22) */
.pattern-prompt {
  gap: 0.4rem;
}

.pattern-where {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.25rem;
}

.pattern-staff {
  max-width: 100%;
  height: auto;
}

.pattern-choices {
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
}

.pattern-choice {
  gap: 0.35rem;
  white-space: normal;
  text-align: center;
}

.pattern-fingers .choice.name {
  white-space: normal;
  font-size: 1.1rem;
}

.pattern-picture {
  width: 100%;
  max-width: 160px;
  height: auto;
}

.pattern-picture .pattern-string {
  stroke: var(--foreground);
  stroke-width: 1.5;
}

.pattern-picture .pattern-nut {
  stroke: var(--foreground);
  stroke-width: 3;
}

.pattern-picture .pattern-tick {
  stroke: var(--muted-foreground);
  opacity: 0.6;
}

.pattern-picture .pattern-dot {
  fill: var(--primary);
}

.pattern-picture .pattern-finger {
  fill: var(--primary-foreground);
  font-size: 10px;
  font-weight: 600;
}

.pattern-answer {
  display: flex;
  justify-content: center;
  width: 100%;
}

.pattern-answer:empty {
  display: none;
}

.pattern-key-list {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
}

/* ---------------------------------------------- reading: keys, transposition, clefs (roadmap phase 20) */
/* Transposition: the concert note (or the tuning question) large, then what to name. */
.transpose-prompt {
  gap: 0.4rem;
}

.transpose-concert,
.transpose-tuning {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 2rem;
  text-align: center;
}

.transpose-tuning {
  font-size: 1.4rem;
}

/* The fingering builder's link card: the written key's concert key. */
.concert-line {
  margin: 0;
  font-weight: 500;
}

/* Clef reading: the clef's name over the staff, and the seven letters in a row (two rows on phones). */
.clef-prompt {
  gap: 0.35rem;
}

.clef-name {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.25rem;
}

.clef-staff {
  max-width: 100%;
  height: auto;
}

.clef-letters {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.5rem;
  width: 100%;
  max-width: 32rem;
  margin: 0 auto;
}

.clef-letters .choice.name {
  min-height: 2.75rem;
  padding: 0.6rem 0;
}

@media (max-width: 480px) {
  .clef-letters {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.clef-preview .staff {
  width: 96px;
}

.clef-range-list {
  display: grid;
  gap: 0.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.clef-range-list li {
  display: grid;
  grid-template-columns: 6.5rem auto 1fr;
  gap: 0.75rem;
  align-items: center;
}

.clef-range-list .staff {
  width: 116px;
  height: auto;
}

.clef-ranges h3 {
  margin: 0.75rem 0 0.5rem;
  font-size: 1rem;
}

@media (max-width: 400px) {
  .clef-range-list li {
    grid-template-columns: 1fr auto;
  }

  .clef-range-list li > .muted {
    grid-column: 1 / -1;
  }
}

/* ---------------------------------------------- terms, symbols and road maps (roadmap phase 23) */
/* Symbols (js/term-symbols.js) draw in currentColor, so they follow the
   theme and a choice marked right or wrong. */
.term-symbol {
  color: var(--foreground);
  overflow: visible;
  max-width: 100%;
}

.choice .term-symbol,
.terms-tap .term-symbol {
  color: inherit;
}

.term-symbol .term-staff line {
  stroke: currentColor;
  stroke-width: 1.1;
}

.term-symbol .term-head {
  fill: currentColor;
}

.term-symbol .term-head.open {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.7;
}

.term-symbol .term-stem,
.term-symbol .term-bar {
  stroke: currentColor;
  stroke-width: 1.4;
}

.term-symbol .term-fill {
  fill: currentColor;
}

.term-symbol .term-line {
  fill: none;
  stroke: currentColor;
  stroke-width: 2.2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.term-symbol .term-line.square,
.term-symbol .term-line.bracket {
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

.term-symbol .term-line.bracket {
  stroke-width: 1.6;
}

.term-symbol .term-line.hairpin {
  stroke-width: 2;
}

.term-symbol .term-line.slash {
  stroke-width: 3;
  stroke-linecap: butt;
}

.term-glyph {
  font-family: 'Noto Music', serif;
  fill: currentColor;
}

/* Time signature digits, as the rhythm staff draws them. */
.term-digit {
  font-family: Georgia, 'Times New Roman', serif;
  font-weight: 700;
  fill: currentColor;
}

.term-text {
  font-family: var(--font-sans);
  font-size: 13px;
  font-weight: 600;
  fill: currentColor;
}

/* Sizes: drawings are about a staff tall; dynamics, signs and hairpins are drawn smaller. */
.terms-prompt-symbol {
  height: 156px;
  width: auto;
}

.terms-prompt-symbol.term-symbol-dynamic {
  height: 72px;
}

.terms-prompt-symbol.term-symbol-glyph {
  height: 88px;
}

.terms-prompt-symbol.term-symbol-crescendo,
.terms-prompt-symbol.term-symbol-decrescendo {
  height: 56px;
}

.terms-symbol-box {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 160px;
}

/* Four choices: a symbol or a term with meanings, or a meaning with symbols or terms. */
.terms-choices {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.terms-choice {
  justify-content: center;
  min-height: 3.75rem;
  padding: 0.75rem 0.9rem;
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
  white-space: normal;
}

.terms-symbol-choice {
  min-height: 7rem;
}

.terms-symbol-choice svg {
  height: 92px;
  width: auto;
}

.terms-symbol-choice .term-symbol-dynamic {
  height: 48px;
}

.terms-symbol-choice .term-symbol-glyph {
  height: 60px;
}

.terms-symbol-choice .term-symbol-crescendo,
.terms-symbol-choice .term-symbol-decrescendo {
  height: 40px;
}

@media (max-width: 420px) {
  .terms-choices:not(.terms-symbol-choices) {
    grid-template-columns: 1fr;
  }

  .terms-symbol-choice svg {
    height: 76px;
  }
}

.terms-prompt {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.5rem;
}

.terms-term {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 2rem;
  line-height: 1.2;
}

.terms-meaning {
  margin: 0;
  font-family: var(--font-serif);
  font-weight: 500;
  font-size: 1.4rem;
  line-height: 1.3;
}

/* Putting in order and road maps use the full width: the question, then the answers. */
.question.terms-q-order,
.question.terms-q-map,
.question.terms-q-next {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 1rem;
}

.terms-build {
  display: grid;
  gap: 0.75rem;
  justify-items: center;
  width: 100%;
}

.terms-taps {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.5rem;
}

.terms-tap {
  min-width: 4.5rem;
  height: 3.5rem;
  padding: 0 0.9rem;
  background: var(--card);
  color: var(--foreground);
  border-color: var(--input-border);
  font-size: 1.05rem;
}

.terms-tap .terms-dynamic {
  height: 30px;
  width: auto;
}

.terms-tap:disabled {
  opacity: 0.35;
}

.terms-chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem;
  min-height: 2.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.terms-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.5rem;
  height: 2.5rem;
  padding: 0 0.55rem;
  border: 1.5px solid var(--input-border);
  border-radius: var(--radius-md);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.terms-chip .terms-dynamic {
  height: 22px;
  width: auto;
}

.terms-chips-empty {
  align-self: center;
}

.terms-chips.correct .terms-chip,
.terms-chip.right {
  border-color: var(--success);
}

.terms-chips.wrong .terms-chip,
.terms-chip.wrong {
  border-color: var(--destructive);
}

.terms-chip.wrong {
  background: color-mix(in oklch, var(--destructive) 12%, var(--card));
}

.terms-chip.after {
  opacity: 0.5;
}

/* In the right order, the measure the student missed. */
.terms-chips.correct .terms-chip.first-miss {
  background: color-mix(in oklch, var(--success) 16%, var(--card));
}

.terms-answer {
  display: grid;
  gap: 0.35rem;
  justify-items: center;
}

.terms-answer:empty {
  display: none;
}

.terms-answer p {
  margin: 0;
}

/* A road map (js/roadmap-view.js): four measures a row, three on phones.
   Each measure is a button drawn as its stretch of staff; with no gap
   between them, the staff runs across the row. */
.roadmap {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  row-gap: 0.25rem;
  width: 100%;
  max-width: 42rem;
  margin: 0 auto;
}

/* Three across on phones, with the words and numbers drawn larger so they
   stay readable at that size. */
@media (max-width: 560px) {
  .roadmap {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .roadmap .rm-word {
    font-size: 16px;
  }

  .roadmap .rm-ending {
    font-size: 13px;
  }

  .roadmap .rm-number {
    font-size: 21px;
  }
}

.rm-measure {
  --rm-bg: var(--card);
  display: block;
  height: auto;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: var(--rm-bg);
  color: var(--foreground);
  cursor: pointer;
}

.rm-measure:hover:not(:disabled) {
  --rm-bg: color-mix(in oklch, var(--primary) 9%, var(--card));
  opacity: 1;
}

.rm-measure:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: -2px;
}

.rm-measure:disabled {
  cursor: default;
  opacity: 1;
}

/* The Coda starts a row of its own, a little apart. */
.rm-coda-start {
  grid-column-start: 1;
}

.rm-coda {
  margin-top: 0.5rem;
}

.rm-asked {
  --rm-bg: color-mix(in oklch, var(--accent) 80%, var(--card));
}

/* Right and wrong also get an edge, so they never read as the measure asked about. */
.rm-measure.correct {
  --rm-bg: color-mix(in oklch, var(--success) 20%, var(--card));
  box-shadow: inset 0 0 0 2px var(--success);
}

.rm-measure.wrong {
  --rm-bg: color-mix(in oklch, var(--destructive) 16%, var(--card));
  box-shadow: inset 0 0 0 2px var(--destructive);
}

.rm-measure.chosen {
  --rm-bg: var(--accent);
}

.rm-tapped {
  animation: rm-flash 0.5s ease-out;
}

@keyframes rm-flash {
  from {
    background: color-mix(in oklch, var(--primary) 32%, var(--card));
  }
}

@media (prefers-reduced-motion: reduce) {
  .rm-tapped {
    animation: none;
  }
}

.rm-svg {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
}

.rm-staff line {
  stroke: currentColor;
  stroke-width: 1;
}

.rm-bar {
  stroke: currentColor;
  stroke-width: 1.3;
}

/* The line at the start of each row; the first measure of a row shows it. */
.rm-system {
  display: none;
}

.rm-row-start .rm-system {
  display: inline;
}

.rm-fill {
  fill: currentColor;
}

.rm-bracket {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.4;
}

.rm-ending {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 600;
  fill: currentColor;
}

/* Fine, To Coda and the D.C. or D.S. in italics, as music prints them. */
.rm-word {
  font-family: Georgia, 'Times New Roman', serif;
  font-size: 13.5px;
  font-style: italic;
  fill: currentColor;
}

.rm-glyph {
  font-family: 'Noto Music', serif;
  font-style: normal;
  font-size: 16px;
}

/* The number students tap, over the staff with a halo in the measure's own color. */
.rm-number {
  font-family: var(--font-sans);
  font-size: 19px;
  font-weight: 600;
  fill: var(--muted-foreground);
  stroke: var(--rm-bg);
  stroke-width: 5px;
  stroke-linejoin: round;
  paint-order: stroke;
}

.rm-asked .rm-number,
.rm-measure.chosen .rm-number {
  fill: var(--accent-foreground);
}

.rm-measure.correct .rm-number {
  fill: var(--success);
}

.rm-measure.wrong .rm-number {
  fill: var(--destructive);
}

.rm-prompt .prompt-text {
  margin: 0;
}

.rm-prompt p {
  margin: 0;
}

.terms-create-list {
  margin: 0.35rem 0 0;
  padding-left: 1.1rem;
}

/* Tools › Glossary (js/glossary-page.js). */
.glossary-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
  align-items: end;
}

.glossary-search {
  flex: 1 1 14rem;
  min-width: 0;
}

.glossary-search input {
  width: 100%;
}

.glossary-count {
  margin: 0;
}

.glossary-list {
  display: grid;
  gap: 1.5rem;
}

.glossary-section h2 {
  margin: 0 0 0.25rem;
  font-size: 1.3rem;
}

.glossary-terms {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 22rem), 1fr));
  gap: 0 1.5rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.glossary-entry {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: 0.75rem;
  align-items: start;
  padding: 0.65rem 0;
  border-top: 1px solid var(--border);
  break-inside: avoid;
}

.glossary-symbol {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 2.5rem;
}

.glossary-symbol-svg {
  height: 84px;
  width: auto;
}

.glossary-symbol-svg.term-symbol-dynamic {
  height: 36px;
}

.glossary-symbol-svg.term-symbol-glyph {
  height: 46px;
}

.glossary-symbol-svg.term-symbol-crescendo,
.glossary-symbol-svg.term-symbol-decrescendo {
  height: 28px;
}

.glossary-term,
.glossary-def {
  margin: 0;
}

.glossary-abbr {
  margin-left: 0.5rem;
  color: var(--muted-foreground);
  font-family: Georgia, 'Times New Roman', serif;
  font-style: italic;
}

.glossary-def {
  margin-top: 0.15rem;
  font-size: 0.95rem;
  line-height: 1.45;
}

@media print {
  .glossary-sheet {
    --foreground: #000;
    --card: #fff;
    --card-foreground: #000;
    --border: #999;
    --muted-foreground: #444;
    color: #000;
    background: #fff;
  }

  .glossary-head {
    padding-bottom: 0.5rem;
    background: #fff;
    color: #000;
  }

  .glossary-terms {
    grid-template-columns: 1fr 1fr;
  }
}

/* Four Tools tabs on a phone: shorter names where a tab has one (the
   fingering chart is "Chart"), and less room around each. */
@media (max-width: 480px) {
  .tools-nav .tool-tab {
    padding: 0.6rem 0.45rem;
  }

  .tools-nav .tool-tab[data-short] {
    font-size: 0;
  }

  .tools-nav .tool-tab[data-short]::after {
    content: attr(data-short);
    font-size: 0.875rem;
  }
}


/* ---------------------------------------------- ear training and written theory (roadmap phase 27) */
.ear-prompt,
.written-prompt {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  align-content: start;
}

.ear-controls {
  justify-content: center;
}

.ear-replay .icon {
  width: 1.15rem;
  height: 1.15rem;
}

.ear-status {
  margin: 0;
  color: var(--warning);
}

.ear-status:empty,
.ear-answer:empty {
  display: none;
}

.ear-answer {
  display: flex;
  justify-content: center;
  width: 100%;
}

.ear-staff,
.written-staff {
  max-width: 100%;
  height: auto;
}

/* Two across even on a 320 px phone, so seven or more choices leave room for the verdict above them (97.2). */
.ear-choices.ear-many {
  grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
}

.ear-choices .choice.name,
.written-choices .choice.name {
  justify-content: center;
  font-size: 1.05rem;
  white-space: normal;
  text-align: center;
}

.written-levels summary {
  cursor: pointer;
  font-weight: 500;
}

.written-levels dl {
  margin: 0.5rem 0 0;
}

.written-levels dt {
  font-weight: 600;
  margin-top: 0.5rem;
}

.written-levels dd {
  margin: 0;
  color: var(--muted-foreground);
  font-size: 0.875rem;
}

/* ---------------------------------------------- tuning ear (roadmap phase 28) */
.tuning-note {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  margin: 0;
  color: var(--muted-foreground);
  font-size: 0.875rem;
}

.tuning-note .icon {
  flex: none;
  width: 1.25rem;
  height: 1.25rem;
}

.tuning-choices .choice.name {
  justify-content: center;
  gap: 0.25rem;
}

.tuning-choice-hint {
  color: var(--muted-foreground);
  font-size: 0.8125rem;
  font-weight: 400;
}

.tuning-controls {
  display: grid;
  gap: 1rem;
  align-content: start;
  min-width: 0;
}

.tuning-slider-row {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.tuning-slider {
  flex: 1 1 auto;
  width: 100%;
  min-width: 0;
  height: 2.75rem;
  margin: 0;
  accent-color: var(--primary);
}

/* "Lower" and "Higher" under the slider's ends. */
.tuning-ends {
  display: flex;
  justify-content: space-between;
  margin: -0.75rem 3.25rem 0;
  color: var(--muted-foreground);
  font-size: 0.8125rem;
}

.tuning-nudge {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  padding: 0;
  font-size: 1.25rem;
  background: var(--card);
  color: var(--foreground);
  border-color: var(--input-border);
}

.tuning-actions,
.tuning-after {
  flex-wrap: wrap;
}

.result-measure {
  margin: 0;
  font-weight: 500;
}

/* ------------------------------------------------------------ compound and cut time (roadmap phase 29) */
/* A choice in a plain checklist that can't be made says why under its name
   (Mixed meters: "With level 6 or a custom level"). */
.choice-check-hint {
  display: block;
  font-size: 0.75rem;
  line-height: 1.25;
  color: var(--muted-foreground);
}

/* ---------------------------------------------- tap the rhythm (roadmap phase 31) */
/* A take is one column: the measure, the beat, the tap pad and how it went. */
.question.tap-question {
  display: block;
}

.tap-main,
.tap-calibration {
  display: grid;
  justify-items: center;
  gap: 0.75rem;
  text-align: center;
}

.tap-main[hidden],
.tap-calibration-box[hidden] {
  display: none;
}

.tap-info {
  margin: 0;
}

/* The measure shrinks to fit, down to a size it can still be read at; past that it scrolls inside its box. */
.tap-music {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.tap-notation {
  position: relative;
  width: 100%;
  margin: 0 auto;
}

/* Rhythm counting's staff keeps its full size for the count boxes under it; a tapped measure shrinks to fit. */
.tap-notation .rhythm-staff {
  display: block;
  width: 100%;
  min-width: 0;
  height: auto;
}

.tap-marks {
  position: relative;
  height: 2.6rem;
}

.tap-mark {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  min-width: 1.6rem;
  padding: 0.05rem 0.3rem;
  border-radius: 999px;
  font-size: 0.75rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  line-height: 1.2rem;
  white-space: nowrap;
}

.tap-mark-low {
  top: 1.3rem;
}

.tap-mark-on {
  color: var(--success);
  background: color-mix(in oklch, var(--success) 12%, transparent);
}

.tap-mark-close {
  color: var(--warning);
  background: color-mix(in oklch, var(--warning) 14%, transparent);
}

.tap-mark-off,
.tap-mark-missed {
  color: var(--destructive);
  background: color-mix(in oklch, var(--destructive) 12%, transparent);
}

/* Extra taps: a dot over the staff where each one fell. */
.tap-extras {
  position: absolute;
  inset: 0.25rem 0 auto;
  height: 0.6rem;
}

.tap-extra {
  position: absolute;
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 50%;
  background: var(--destructive);
  transform: translateX(-50%);
}

/* Holding each note: under the staff, each note's length as an outlined bar, and inside it how long it was held. */
.tap-holds {
  position: relative;
  height: 0.9rem;
  margin-top: 0.2rem;
}

.tap-hold-track,
.tap-hold {
  position: absolute;
  border-radius: 999px;
}

/* A sliver of space at the right keeps two notes side by side apart. */
.tap-hold-track {
  top: 0;
  height: 0.9rem;
  border-right: 3px solid transparent;
  background: var(--muted);
  background-clip: padding-box;
  box-shadow: inset 0 0 0 1px var(--muted-foreground);
}

.tap-hold {
  top: 0.22rem;
  height: 0.46rem;
}

.tap-hold-held {
  background: var(--success);
}

.tap-hold-short,
.tap-hold-long {
  background: var(--destructive);
}

.tap-stage {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  min-height: 2.5rem;
}

.tap-beats {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.35rem;
}

.tap-beat {
  display: inline-grid;
  place-items: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.8rem;
  font-weight: 600;
}

.tap-beat-on {
  border-color: transparent;
  background: var(--primary);
  color: var(--primary-foreground);
}

.tap-count {
  min-width: 4.5rem;
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.5rem;
  font-weight: 500;
}

.tap-count:empty {
  display: none;
}

/* The tap pad: big enough for a thumb, and it never zooms or selects text under fast taps. */
.tap-pad {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  width: min(100%, 24rem);
  height: 7.5rem;
  border-radius: var(--radius-xl);
  border-color: transparent;
  background: var(--primary);
  color: var(--primary-foreground);
  touch-action: manipulation;
  user-select: none;
  -webkit-user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  transition: transform 0.06s ease-out, box-shadow 0.06s ease-out;
}

.tap-pad-label {
  font-size: 1.4rem;
  font-weight: 600;
}

.tap-pad-hint {
  font-size: 0.8rem;
  font-weight: 400;
  opacity: 0.85;
}

.tap-pad-hint:empty {
  display: none;
}

.tap-pad-live {
  background: var(--neutral);
  color: var(--neutral-foreground);
  /* A finger held on the pad for a long note never starts a scroll, which would cancel it. */
  touch-action: none;
}

/* A tap flashes; a note held down keeps the pad pressed until it's let go. */
.tap-pad.tap-hit,
.tap-pad.tap-held {
  transform: scale(0.97);
  box-shadow: 0 0 0 4px var(--ring);
}

@media (prefers-reduced-motion: reduce) {
  .tap-pad {
    transition: none;
  }

  .tap-pad.tap-hit,
  .tap-pad.tap-held {
    transform: none;
  }
}

.tap-status {
  min-height: 1.5em;
  margin: 0;
  font-weight: 500;
}

.tap-status:empty {
  min-height: 0;
}

.tap-result {
  width: 100%;
  max-width: 40rem;
}

.tap-result:focus {
  outline: none;
}

.tap-legend,
.tap-retry {
  margin: 0.25rem 0;
}

.tap-retry:empty {
  display: none;
}

/* Each note's timing in words, for screen readers. */
.tap-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.tap-actions {
  justify-content: center;
}

/* Calibration: on the start screen, and in place of the measure before a device's first take. */
.tap-device-text {
  margin: 0;
}

.tap-calibration {
  margin-top: 0.75rem;
  padding: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
}

.tap-calibration h2 {
  margin: 0;
  font-size: 1.25rem;
}

.tap-calibration p {
  margin: 0;
  max-width: 34rem;
}

.question .tap-calibration {
  margin-top: 0;
}

@media (max-width: 480px) {
  .tap-pad {
    height: 6.5rem;
  }
}

.tap-scroll-hint {
  margin: -0.5rem 0 0;
}

.tap-scroll-hint[hidden] {
  display: none;
}

/* ---------------------------------------------- bowings (roadmap phase 38) */
/* The melody across the card, the bow buttons under it. */
.question.bowing-question {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

.bowing-music {
  width: 100%;
  min-width: 0;
}

/* A marked note can be tapped to change its bow (UX plan 94.9). */
.bowing-music .music-note {
  cursor: pointer;
}

.bowing-music .measures {
  justify-items: center;
}

.bowing-prompt {
  display: grid;
  gap: 0.5rem;
}

/* Down-bow and Up-bow, then Back and Check: four in a row, or two and two on a phone. */
.bowing-buttons {
  display: grid;
  grid-template-columns: repeat(4, auto);
  justify-content: center;
  gap: 0.5rem;
}

.bow-button {
  min-width: 8.5rem;
}

@media (max-width: 480px) {
  .bowing-buttons {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .bow-button {
    min-width: 0;
  }
}

.bow-glyph {
  display: inline-block;
  min-width: 1.2em;
  font-family: var(--font-serif);
  font-weight: 600;
}

.bowing-status {
  min-height: 1.5em;
  margin: 0;
  text-align: center;
}

.bowing-why {
  margin: 0;
  padding-left: 1.2rem;
}

.bowing-why:empty {
  display: none;
}

.bowing-rules {
  margin: 0;
  padding-left: 1.2rem;
}

/* ---------------------------------------------- melodic dictation (roadmap phase 36) */
.question.melodic-question {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 1rem;
}

.melodic-prompt {
  display: grid;
  gap: 0.6rem;
  justify-items: center;
  min-width: 0;
  overflow-wrap: anywhere;
}

.melodic-controls {
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
}

/* The rhythm a dictation melody has, a measure at a time. */
.melodic-rhythm {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0 0.25rem;
  max-width: 100%;
}

.melodic-rhythm svg {
  max-width: 100%;
  height: auto;
}

/* The rhythm under a melody fits its card instead of the 650 px a measure
   to count needs (UX plan 94.2). */
.melodic-rhythm .rhythm-staff {
  min-width: 0;
  width: 100%;
}

.melodic-written,
.melodic-music {
  width: 100%;
  min-width: 0;
  display: grid;
  justify-items: center;
  overflow-x: auto;
}

.melodic-written svg {
  max-width: 100%;
  height: auto;
}

.melodic-answer {
  justify-items: center;
  min-width: 0;
}

.melodic-status {
  min-height: 1.5em;
  margin: 0;
  text-align: center;
}

.melodic-choices {
  grid-template-columns: repeat(auto-fill, minmax(6.5rem, 1fr));
  max-width: 44rem;
}

.melodic-choices .choice.name {
  justify-content: center;
  white-space: normal;
  text-align: center;
}

.melodic-lengths,
.melodic-ask {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
}

.melodic-lengths [aria-checked="true"],
.melodic-ask [aria-checked="true"] {
  border-color: var(--primary);
  background: var(--accent);
  color: var(--accent-foreground);
}

.melodic-ask-label {
  font-weight: 600;
  margin-right: 0.25rem;
}

.melodic-buttons {
  justify-content: center;
  gap: 0.5rem;
}

/* Find the mistake: every note can be tapped. */
.melodic-music .music-note.is-pickable {
  cursor: pointer;
}

/* ---------------------------------------------- sight-reading (roadmap phase 35) */
/* The melody across the card; under it what to do now: study, play, or rate. */
.question.sight-question {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

.sight-music {
  width: 100%;
  min-width: 0;
}

.sight-music .measures {
  justify-items: center;
}

.sight-answer {
  justify-items: center;
}

.sight-status {
  min-height: 1.5em;
  margin: 0;
  text-align: center;
}

.sight-actions {
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.sight-play {
  min-width: 8rem;
}

.sight-rating {
  width: 100%;
  justify-items: center;
}

.sight-rate-ask {
  margin: 0.5rem 0 0;
  font-weight: 600;
}

/* Clean, Close and Lost, each with what it means: three across, or one under another on a phone. */
.sight-rates {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 0.5rem;
  width: 100%;
  max-width: 44rem;
}

.sight-rate {
  display: flex;
  justify-content: flex-start;
  height: auto;
  min-height: 4.5rem;
  padding: 0.6rem 0.75rem;
  white-space: normal;
  text-align: left;
}

.sight-rate > span {
  display: grid;
  gap: 0.15rem;
  width: 100%;
  justify-items: start;
}

.sight-rate-blurb {
  color: var(--muted-foreground);
  font-size: 0.85rem;
  font-weight: 400;
}

.sight-rate.chosen {
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary);
}

@media (max-width: 560px) {
  .sight-rates {
    grid-template-columns: 1fr;
  }

  .sight-rate {
    min-height: 0;
  }
}

.sight-example .measures {
  justify-items: start;
}

/* Two-part sight-singing (roadmap phase 37): each part with its name, the higher on top. */
.sight-score {
  display: grid;
  gap: 0.75rem;
  width: 100%;
  min-width: 0;
}

.sight-part {
  display: grid;
  gap: 0.25rem;
  min-width: 0;
}

.sight-part-name {
  margin: 0;
  color: var(--muted-foreground);
  font-size: 0.85rem;
  font-weight: 600;
}

.sight-other .music-line {
  opacity: 0.85;
}

/* Sight-reading and sight-singing's microphone check (roadmap phase 41): the box on the study row, and the line after. */
.sight-mic-note {
  margin: 0;
  text-align: center;
}

.sight-mic-summary {
  margin: 0;
  font-weight: 600;
  text-align: center;
}

/* Play-along's game score (roadmap phase 61): under the microphone's line, in the primary color. */
.sight-game {
  margin: 0;
  text-align: center;
  font-weight: 600;
  color: var(--primary);
}

.sight-mic-summary:empty,
.sight-game:empty,
.sight-mic-legend:empty {
  display: none;
}

.sight-mic-legend {
  margin: 0;
  text-align: center;
}

/* ---------------------------------------------- playing checks (roadmap phase 41) */
/* What to play and its music across the card; under it Start, the count, and how it went. */
.question.playcheck-question {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

.playcheck-prompt {
  display: grid;
  gap: 0.5rem;
  justify-items: center;
  text-align: center;
}

.playcheck-what,
.playcheck-concert {
  margin: 0;
}

.playcheck-what {
  font-weight: 600;
}

.playcheck-music {
  width: 100%;
  min-width: 0;
}

.playcheck-music .measures {
  justify-items: center;
}

.playcheck-example .measures {
  justify-items: start;
}

.playcheck-answer {
  justify-items: center;
}

.playcheck-actions {
  justify-content: center;
  flex-wrap: wrap;
  gap: 0.5rem;
}

.playcheck-start {
  min-width: 8rem;
}

/* The count, big enough to read from a music stand. */
.playcheck-count {
  min-height: 2.25rem;
  margin: 0;
  color: var(--primary);
  font-family: var(--font-serif);
  font-size: 2.25rem;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.playcheck-status {
  min-height: 1.5em;
  margin: 0;
  text-align: center;
}

/* A long tone's pitch and volume as it's held, across the counts. */
.playcheck-traces {
  display: grid;
  gap: 0.25rem;
  width: 100%;
  max-width: 32rem;
}

.playcheck-trace {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--muted);
}

.playcheck-trace .trace-line {
  stroke: var(--primary);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.playcheck-trace .trace-band {
  fill: color-mix(in oklch, var(--success) 18%, transparent);
}

.playcheck-trace .trace-target {
  stroke: var(--success);
  stroke-dasharray: 4 3;
  stroke-width: 1;
}

.playcheck-trace .trace-counts line {
  stroke: var(--border);
  stroke-width: 1;
}

.playcheck-trace-name {
  margin: 0.25rem 0 0;
  text-align: left;
}

/* What a long tone measured, each with ✓ or ✗ beside it (and the words say which). */
.playcheck-measured {
  display: grid;
  gap: 0.25rem;
  width: 100%;
  max-width: 32rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.playcheck-measured:empty,
.playcheck-retry:empty {
  display: none;
}

.playcheck-ok {
  display: inline-block;
  width: 1.25rem;
  font-weight: 700;
  text-align: center;
}

.playcheck-ok.is-ok {
  color: var(--success);
}

.playcheck-ok.is-off {
  color: var(--destructive);
}

.playcheck-info {
  padding-left: 1.5rem;
  color: var(--muted-foreground);
}

.playcheck-legend {
  max-width: 40rem;
  margin: 0;
  text-align: center;
}

.playcheck-privacy {
  margin: 0;
  text-align: center;
}

/* ---------------------------------------------- rudiments (roadmap phase 33) */
/* Read the sticking and name the rudiment: the measure, then the four choices under it. */
.question.rudiment-question {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
}

/* A flam or drag's grace notes, "(LL)", a little smaller than the strokes, as on the staff. */
.sticking-grace {
  font-size: 0.78em;
  letter-spacing: 0.04em;
}

/* A rudiment's measure shrinks to fit, as a tapped measure does, with grace notes, accents and R and L on the staff. */
.rudiment-music {
  margin: 0 auto;
}

.rudiment-prompt {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
}

.rudiment-name {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.25rem;
}

.rudiment-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.25rem 1.25rem;
  margin: 0;
  padding-left: 1.1rem;
}

/* Four choices: stickings read best letter by letter, with a little room between them. */
.rudiment-choices {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.rudiment-choice {
  justify-content: center;
  min-height: 3.75rem;
  padding: 0.75rem 0.9rem;
  font-size: 1.05rem;
  font-weight: 500;
  line-height: 1.3;
  text-align: center;
  white-space: normal;
}

.sticking-choice {
  font-size: 1.15rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.12em;
}

@media (max-width: 420px) {
  .rudiment-choices {
    grid-template-columns: 1fr;
  }
}

/* Two pads, left hand and right: quiet until the count-in starts, then lit like Tap the rhythm's pad. */
.rudiment-pads {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.75rem;
  width: min(100%, 30rem);
  touch-action: manipulation;
}

.rudiment-pads .tap-pad {
  width: 100%;
  border: 1px solid var(--border);
  background: var(--muted);
  color: var(--muted-foreground);
}

.rudiment-pads-live .tap-pad {
  border-color: transparent;
  background: var(--primary);
  color: var(--primary-foreground);
}

.rudiment-start[hidden] {
  display: none;
}

/* The builder's preview: each rudiment as students see it. */
.rudiment-preview {
  display: grid;
  gap: 1rem;
}

.rudiment-preview-item {
  display: grid;
  gap: 0.25rem;
  margin: 0;
}

/* ---------------------------------------------- rhythm dictation and composition (roadmap phase 32) */
.question.ear-question {
  display: block;
}

.ear-main {
  display: grid;
  gap: 0.75rem;
}

.ear-top {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  text-align: center;
}

.ear-top p {
  margin: 0;
}

.ear-play {
  min-width: 12rem;
}

.ear-prompt {
  margin: 0;
  font-weight: 500;
  text-align: center;
}

.ear-status:empty {
  display: none;
}

/* A measure shrinks to fit, down to a size it can still be read at; past that it scrolls inside its box. */
.ear-music {
  width: 100%;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}

.ear-notation {
  position: relative;
  width: 100%;
  margin: 0 auto;
}

.ear-notation .rhythm-staff {
  display: block;
  width: 100%;
  min-width: 0;
  height: auto;
}

.ear-beats {
  display: grid;
  gap: 0.75rem;
}

.ear-measure {
  display: grid;
  gap: 0.35rem;
}

.ear-beat-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
}

.ear-beat {
  min-width: 3rem;
  font-size: 1.15rem;
  font-weight: 600;
}

.ear-none {
  justify-self: center;
  min-width: 12rem;
}

.ear-answer:empty {
  display: none;
}

.ear-answer {
  display: grid;
  gap: 0.35rem;
}

.ear-played-label,
.ear-swap {
  margin: 0;
  text-align: center;
}

.ear-swap svg {
  display: inline-block;
  vertical-align: middle;
  color: var(--foreground);
}

.ear-actions {
  justify-content: center;
}

/* Rhythm tiles (js/rhythm-tiles.js): a row of beat slots per measure, then the tiles. */
.rt {
  display: grid;
  gap: 0.6rem;
}

.rt-measures {
  display: grid;
  gap: 0.6rem;
}

.rt-measure {
  display: grid;
  gap: 0.25rem;
}

.rt-grid,
.rt-marks {
  display: grid;
  gap: 0.3rem;
}

.rt-slot,
.rt-piece {
  height: 3.4rem;
  min-width: 0;
  padding: 0.2rem;
  border-radius: var(--radius-md);
  color: var(--foreground);
}

.rt-slot {
  border: 1px dashed var(--input-border);
  background: var(--card);
  color: var(--muted-foreground);
  font-weight: 600;
}

.rt-slot-on {
  border-style: solid;
  border-color: var(--ring);
  box-shadow: 0 0 0 2px color-mix(in oklch, var(--ring) 35%, transparent);
  color: var(--foreground);
}

.rt-piece {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border: 1px solid var(--input-border);
  background: var(--secondary);
}

.rt-piece svg {
  max-width: 100%;
  height: auto;
  max-height: 2.6rem;
}

.rt-piece.rt-right,
.rt-slot.rt-right {
  border-color: var(--success);
  background: color-mix(in oklch, var(--success) 14%, var(--card));
}

.rt-piece.rt-wrong,
.rt-slot.rt-wrong {
  border-color: var(--destructive);
  background: color-mix(in oklch, var(--destructive) 12%, var(--card));
}

.rt-marks span {
  text-align: center;
  font-weight: 600;
}

.rt-mark-right {
  color: var(--success);
}

.rt-mark-wrong {
  color: var(--destructive);
}

.rt-status {
  min-height: 1.4em;
  margin: 0;
  color: var(--muted-foreground);
}

.rt-tiles-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
}

.rt-tiles {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

.rt-tile {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 3.25rem;
  height: 3.25rem;
  padding: 0.25rem 0.5rem;
  border: 1px solid var(--input-border);
  border-radius: var(--radius-md);
  background: var(--card);
  color: var(--foreground);
}

.rt-tile:hover:not(:disabled) {
  background: var(--muted);
  opacity: 1;
}

.rt-key {
  position: absolute;
  top: 0.1rem;
  left: 0.3rem;
  font-size: 0.65rem;
  color: var(--muted-foreground);
}

/* Composition. */
.compose h2 {
  margin: 0.5rem 0 0;
  font-size: 1.15rem;
}

.compose-score {
  display: grid;
  gap: 0.5rem;
}

.compose-measure {
  display: grid;
  gap: 0.2rem;
}

.compose-empty {
  margin: 0;
}

.compose-counts {
  position: relative;
  height: 1.8rem;
}

.compose-counts[hidden] {
  display: none;
}

.compose-count {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  font-weight: 600;
  white-space: nowrap;
}

.compose-actions {
  justify-content: flex-start;
}

.compose-link {
  gap: 0.5rem;
}

.compose-tap:empty {
  display: none;
}

.compose-tap {
  display: grid;
  gap: 0.6rem;
  padding-top: 0.75rem;
  border-top: 1px solid var(--border);
}

.compose-tap-nav {
  justify-content: center;
}

@media (max-width: 480px) {
  .rt-slot,
  .rt-piece {
    height: 3rem;
  }

  .rt-tile {
    min-width: 3rem;
    height: 3rem;
  }
}

/* A locked answer stays readable: its tiles are marked, not grayed out. */
.rt-piece:disabled,
.rt-slot:disabled {
  opacity: 1;
  cursor: default;
}

/* ------------------------------------------------------------ Teach (roadmap phase 47) */
/* Each part: a heading, a line on what it's for, then its rows in the
   section-list card Practice and the builders already use. */
.teach > .teach-group + .teach-group,
.teach > .pp-card {
  margin-top: 2rem;
}

.teach-title,
.teach-lead {
  margin: 0;
}

.teach-lead {
  margin-top: 0.25rem;
  max-width: 65ch;
}

.teach-group > .hub-list {
  margin-top: 0.75rem;
}

/* A list with no section heading of its own starts as far from the top as from the bottom. */
.hub-list-single > .hub-rows {
  padding-top: 0.5rem;
}

@media (max-width: 560px) {
  .teach > .teach-group + .teach-group,
  .teach > .pp-card {
    margin-top: 1.5rem;
  }
}

/* ------------------------------------------------------------ offline: the new-version banner (js/offline.js) */
.update-banner {
  background: var(--accent);
  color: var(--accent-foreground);
  border-bottom: 1px solid var(--border);
}

.update-banner[hidden] {
  display: none;
}

.update-banner-inner {
  max-width: 1080px;
  margin: 0 auto;
  padding: 0.5rem 1rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 1rem;
}

.update-banner p {
  margin: 0;
  font-weight: 500;
}

.update-banner-actions {
  display: flex;
  gap: 0.5rem;
}

.update-banner .btn-ghost {
  color: inherit;
}

.update-banner .btn-ghost:hover {
  background: color-mix(in oklch, var(--accent-foreground) 12%, transparent);
  color: inherit;
}

/* ------------------------------------------------------------ pitched measures (roadmap phase 34)
   Lines of music (js/measure-staff.js): one svg a line, drawn in currentColor so it follows the theme and the
   playing note takes the primary color, with a band behind it. A line is drawn at the width it was laid out
   for and only ever shrinks with its box, so it never scrolls sideways. */
.measures {
  display: grid;
  gap: 0.35rem;
  color: var(--foreground);
}

.music-line {
  display: block;
  max-width: 100%;
  height: auto;
  overflow: visible;
}

.music-line .staff-lines line,
.music-line .ledger-lines line,
.music-line .music-bar {
  stroke: currentColor;
  stroke-width: 1.1;
}

.music-line .music-glyph {
  fill: currentColor;
}

.music-line .music-fill {
  fill: currentColor;
}

.music-line .music-stroke {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.music-line .music-stroke.square {
  stroke-linecap: butt;
  stroke-linejoin: miter;
}

.music-line .staff-text {
  fill: currentColor;
}

.music-cursor {
  fill: color-mix(in oklch, var(--primary) 16%, transparent);
}

.music-note.is-current {
  color: var(--primary);
}

/* ---------------------------------------------- paper worksheets (roadmap phase 48)
   Teach › Print for paper's box, the worksheet page's settings card, and the
   pages themselves: white paper and black ink in either theme, Letter-sized
   (8.5 × 11 in, half-inch margins), on screen as a preview and on paper as
   printed. Each row of questions is a table row, so the title and version
   letter repeat at the top of every printed page and no question splits. */
.paper-link {
  margin-top: 0.75rem;
}

.paper-link .field-error:empty {
  display: none;
}

.ws-controls {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem 1.5rem;
  align-items: start;
}

.ws-field {
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
}

.ws-field legend {
  margin-bottom: 0.35rem;
  padding: 0;
  font-weight: 500;
}

.ws-versions {
  gap: 0.4rem;
}

.ws-field .muted {
  margin: 0.4rem 0 0;
}

.ws-settings .ws-help {
  margin-top: 0.5rem;
}

.ws-sheet {
  --foreground: #111;
  --card: #fff;
  --card-foreground: #111;
  --background: #fff;
  --border: #9a9a9a;
  --input-border: #777;
  --muted: #ececec;
  --muted-foreground: #444;
  --primary: #111;
  --primary-foreground: #fff;
  --accent: #e2e2e2;
  --accent-foreground: #111;
  --success: #111;
  --success-foreground: #fff;

  color-scheme: light;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  color: #111;
  font-size: 15px;
  line-height: 1.35;
}

.ws-page {
  width: 100%;
  max-width: 8.5in;
  margin: 0 auto;
  padding: clamp(0.75rem, 4vw, 0.5in);
  border-radius: 4px;
  background: #fff;
  color: #111;
  box-shadow: 0 1px 3px oklch(0 0 0 / 18%), 0 8px 24px oklch(0 0 0 / 12%);
}

.ws-table {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.ws-running {
  padding: 0 0 0.5rem;
  font-weight: inherit;
  text-align: left;
}

.ws-running-line {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: 0.25rem 1rem;
  margin: 0;
  padding-bottom: 0.35rem;
  border-bottom: 1.5px solid #111;
  font-family: var(--font-serif);
  font-size: 1.15rem;
  font-weight: 500;
  line-height: 1.25;
}

.ws-title {
  min-width: 0;
  overflow-wrap: anywhere;
}

.ws-version-mark {
  padding: 0.05rem 0.5rem;
  border: 1.5px solid #111;
  border-radius: 4px;
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 600;
  white-space: nowrap;
}

.ws-head-row > td {
  padding: 0.6rem 0 0.4rem;
}

.ws-name-date {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem 1.5rem;
}

.ws-write-in {
  display: flex;
  flex: 1 1 10rem;
  align-items: flex-end;
  gap: 0.4rem;
  font-weight: 600;
}

.ws-name {
  flex-grow: 2;
}

.ws-line {
  flex: 1;
  min-width: 3rem;
  height: 1.5em;
  border-bottom: 1px solid #111;
}

.ws-about,
.ws-directions {
  margin: 0.5rem 0 0;
  font-size: 0.9rem;
}

.ws-about {
  color: #444;
}

.ws-row {
  break-inside: avoid;
  page-break-inside: avoid;
}

.ws-cell {
  padding: 0.75rem 0.75rem 0.9rem 0;
  vertical-align: top;
}

.ws-row + .ws-row > .ws-cell {
  border-top: 1px solid #d4d4d4;
}

.ws-head-row + .ws-row > .ws-cell {
  border-top: 0;
}

.ws-q-head {
  display: flex;
  gap: 0.35rem;
  margin: 0 0 0.4rem;
  font-size: 0.9rem;
}

.ws-num {
  flex: none;
  min-width: 1.5em;
  font-weight: 700;
}

.ws-instruction {
  min-width: 0;
  color: #333;
}

.ws-prompt {
  min-width: 0;
  padding-left: 1.85em;
}

.ws-stack {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.4rem;
}

.ws-pair {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
}

.ws-pair > * {
  min-width: 0;
}

.ws-big {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.3rem;
  font-weight: 500;
  line-height: 1.2;
}

.ws-meaning {
  margin: 0;
  font-size: 1.05rem;
  font-weight: 500;
}

.ws-prompt-text,
.ws-caption {
  margin: 0;
}

.ws-caption {
  max-width: 9rem;
  color: #444;
  font-size: 0.8rem;
}

.ws-staff {
  width: 100%;
  max-width: 9rem;
  height: auto;
}

.ws-staff-empty {
  max-width: 12rem;
}

/* A line to write on, never wider than its question. */
.ws-answer {
  display: inline-flex;
  align-items: flex-end;
  gap: 0.4rem;
  max-width: 100%;
  font-weight: 600;
}

.ws-blank {
  display: inline-block;
  max-width: 100%;
  height: 1.7rem;
  border-bottom: 1px solid #111;
}

.ws-blank-short {
  width: 5.5rem;
}

.ws-blank-medium {
  width: 9.5rem;
}

.ws-answer:has(.ws-blank-long),
.ws-blank-long {
  display: block;
  width: 100%;
}

/* Choices to circle: a letter in a ring, then the choice. */
.ws-choices {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.35rem 1rem;
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ws-choices-wide {
  grid-template-columns: minmax(0, 1fr);
}

.ws-choice {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  min-width: 0;
}

.ws-choice-text {
  min-width: 0;
  overflow-wrap: anywhere;
}

.ws-letter {
  display: inline-grid;
  flex: none;
  place-items: center;
  width: 1.45rem;
  height: 1.45rem;
  border: 1px solid #777;
  border-radius: 50%;
  font-size: 0.75rem;
  font-weight: 700;
}

/* Diagrams on paper: small enough for two questions across, and only a picture. */
.ws-diagram {
  display: flex;
  justify-content: center;
  max-width: 100%;
}

.ws-diagram svg {
  max-width: 100%;
  height: auto;
}

.ws-diagram .diagram-valves {
  width: 9.5rem;
}

.ws-diagram .diagram-sax,
.ws-diagram .diagram-clarinet,
.ws-diagram .diagram-oboe,
.ws-diagram .diagram-bassoon {
  width: auto;
  height: 2in;
  max-height: none;
}

/* The flute chart lies sideways, so on paper it is sized by width. */
.ws-diagram .diagram-flute {
  width: 3.6in;
  max-width: 100%;
  height: auto;
}

.ws-diagram .diagram-slide {
  width: 100%;
  max-width: 20rem;
}

.ws-diagram .diagram-strings {
  width: 8rem;
}

.ws-diagram .diagram-keyboard {
  width: 100%;
  max-width: 6.8in;
}

/* A keyboard goes beside its note, the width of the page. */
.ws-fill-keyboard {
  flex-wrap: nowrap;
}

.ws-fill-keyboard .ws-diagram {
  flex: 1;
}

/* Terms: symbols as the screen draws them, a little smaller. */
.ws-symbol {
  display: flex;
  align-items: center;
  min-height: 3.5rem;
}

.ws-term-symbol {
  width: auto;
  height: 64px;
}

.ws-term-symbol.term-symbol-dynamic {
  height: 34px;
}

.ws-term-symbol.term-symbol-glyph {
  height: 40px;
}

.ws-term-symbol.term-symbol-crescendo,
.ws-term-symbol.term-symbol-decrescendo {
  height: 26px;
}

.ws-symbol-choice {
  display: inline-flex;
  align-items: center;
  min-height: 2.5rem;
}

.ws-symbol-choice .ws-term-symbol {
  height: 48px;
}

.ws-symbol-choice .ws-term-symbol.term-symbol-dynamic {
  height: 28px;
}

.ws-symbol-choice .ws-term-symbol.term-symbol-glyph {
  height: 32px;
}

.ws-symbol-choice .ws-term-symbol.term-symbol-crescendo,
.ws-symbol-choice .ws-term-symbol.term-symbol-decrescendo {
  height: 22px;
}

.ws-order-items {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.6rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ws-order-items > li {
  display: inline-flex;
  align-items: center;
  min-height: 2.25rem;
  padding: 0.1rem 0.6rem;
  border: 1px solid #9a9a9a;
  border-radius: 6px;
}

.ws-order-symbol .terms-dynamic {
  display: block;
  height: 26px;
  width: auto;
}

.ws-order-blanks {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.4rem;
  margin: 0;
  padding-left: 1.4rem;
}

.ws-order-blanks > li {
  padding-left: 0.1rem;
}

.ws-order-blanks .ws-blank-short {
  width: 4.5rem;
}

/* A road map: four measures a row on paper, whatever the screen's width. */
.ws-sheet .roadmap {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  max-width: 4.6in;
  margin: 0;
}

.rm-paper {
  cursor: default;
}

.ws-wide {
  width: 100%;
}

/* Rhythm: the measure, with a box under each note and rest. */
.ws-rhythm {
  padding-left: 0;
}

.ws-rhythm-staff {
  display: block;
  max-width: 100%;
  height: auto;
  color: #111;
}

.ws-count-boxes rect {
  fill: none;
  stroke: currentColor;
  stroke-width: 1.2;
}

.ws-held {
  fill: #777;
  font-family: var(--font-sans);
  font-size: 20px;
}

/* The answer key: compact, two answers across. */
.ws-key .ws-cell {
  padding: 0.35rem 0.75rem 0.4rem 0;
}

.ws-key-answer {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.9rem;
}

.ws-key-body {
  display: flex;
  flex: 1;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.25rem 0.6rem;
  min-width: 0;
}

.ws-key-words {
  flex: 1 1 8rem;
  min-width: 0;
  overflow-wrap: anywhere;
}

.ws-key-drawn {
  display: inline-flex;
  align-items: center;
}

.ws-key-drawn .ws-diagram .diagram-valves {
  width: 6.5rem;
}

.ws-key-drawn .ws-diagram .diagram-sax,
.ws-key-drawn .ws-diagram .diagram-clarinet,
.ws-key-drawn .ws-diagram .diagram-oboe,
.ws-key-drawn .ws-diagram .diagram-bassoon {
  height: 1.2in;
}

.ws-key-drawn .ws-diagram .diagram-flute {
  width: 2.4in;
}

.ws-key-drawn .ws-diagram .diagram-slide,
.ws-key-drawn .ws-diagram .diagram-keyboard {
  width: 100%;
  max-width: 14rem;
}

.ws-key-drawn .ws-diagram .diagram-strings {
  width: 4.5rem;
}

.ws-key-drawn .ws-key-staff {
  width: 6rem;
  height: auto;
}

.ws-key-counts {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.6rem;
  max-width: 100%;
}

.ws-key-measure {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 0.2rem 0.55rem;
}

.ws-key-bar {
  color: #777;
}

/* A rest's slashed count, drawn with a border: printers leave out backgrounds. */
.ws-sheet .rhythm-slashed::after {
  height: 0;
  border-top: 1.5px solid currentColor;
  background: none;
}

@media (max-width: 560px) {
  .ws-sheet {
    font-size: 14px;
  }

  .ws-cell {
    padding-right: 0.4rem;
  }

  .ws-prompt {
    padding-left: 0;
  }

  .ws-choices {
    grid-template-columns: minmax(0, 1fr);
  }
}

@media print {
  body {
    background: #fff;
  }

  .ws-page-wrap > * + * {
    margin-top: 0;
  }

  .ws-sheet {
    display: block;
    font-size: 11.5pt;
  }

  .ws-page {
    max-width: none;
    padding: 0;
    border-radius: 0;
    box-shadow: none;
  }

  .ws-page + .ws-page {
    break-before: page;
  }
}

/* ---------------------------------------------- more paper worksheets (roadmap phase 49)
   Scales, finger patterns, solfège, composition paper and marching drill on
   the worksheet page: a settings card that says what it can't choose, each
   scale's notes under its name, and the field printed black on white. */
.ws-field-name {
  margin: 0 0 0.35rem;
  font-weight: 500;
}

.ws-fixed,
.ws-no-key {
  margin: 0;
}

.ws-no-key {
  font-weight: 500;
}

/* A group's heading: a scale's name over its notes, across the page. */
.ws-group-cell {
  padding-bottom: 0.25rem;
}

.ws-group-row {
  break-after: avoid;
  page-break-after: avoid;
}

.ws-group-row + .ws-row > .ws-cell {
  border-top: 0;
}

.ws-group-name {
  margin: 0;
  font-family: var(--font-serif);
  font-size: 1.05rem;
  font-weight: 500;
}

.ws-group-shape {
  color: #444;
  font-family: var(--font-sans);
  font-size: 0.85rem;
  font-weight: 400;
}

/* Scales: a note on its small staff, as the scale sheets draw it, over its fingering. */
.ws-scale-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  padding-left: 0;
}

.ws-scale-staff {
  max-width: 6.5rem;
}

.ws-scale-card .ws-diagram .diagram-valves {
  width: 6.5rem;
}

.ws-scale-card .ws-diagram .diagram-sax,
.ws-scale-card .ws-diagram .diagram-clarinet,
.ws-scale-card .ws-diagram .diagram-oboe {
  height: 1.6in;
}

.ws-scale-card .ws-diagram .diagram-flute {
  width: 100%;
  max-width: 2.6in;
}

.ws-scale-card .ws-diagram .diagram-bassoon {
  height: 1.45in;
}

/* A narrow keywork diagram goes beside its note, so an octave takes two short
   rows; the flute's chart lies on its side, so it stays under its note. */
.ws-scale-card.ws-fill-sax,
.ws-scale-card.ws-fill-clarinet,
.ws-scale-card.ws-fill-oboe {
  flex-direction: row;
  justify-content: center;
  gap: 0.3rem;
}

.ws-fill-sax .ws-scale-staff,
.ws-fill-clarinet .ws-scale-staff,
.ws-fill-oboe .ws-scale-staff {
  flex: 0 1 5rem;
  min-width: 0;
}

/* Names to write: the number beside its line, eight across. */
.ws-question:has(> .ws-scale-name) {
  display: flex;
  align-items: flex-end;
  gap: 0.15rem;
}

.ws-question:has(> .ws-scale-name) .ws-q-head {
  margin: 0;
}

.ws-scale-name {
  min-width: 0;
  padding-left: 0;
}

.ws-scale-name .ws-blank-short {
  width: 3.2rem;
}

/* Block flow, not flex: a staff scaled to the page's width keeps its full height above the next one. */
.ws-scale-write,
.ws-scale-key {
  display: block;
  padding-left: 0;
}

.ws-scale-write > * + *,
.ws-scale-key > * + * {
  margin-top: 0.25rem;
}

.ws-scale-shape {
  max-width: none;
  margin-bottom: 0.25rem;
}

.ws-scale-line {
  display: block;
  width: 100%;
  max-width: 6.8in;
  height: auto;
}

.ws-key-scale-name {
  margin: 0 0 0.2rem;
  font-family: var(--font-serif);
  font-weight: 500;
}

/* A whole scale in the key: its name and staffs, then its notes in words, its number at the top. */
.ws-key-answer:has(.ws-scale-key) {
  align-items: flex-start;
}

.ws-key .ws-key-body:has(.ws-scale-key) {
  flex-direction: column;
  align-items: stretch;
}

.ws-key .ws-key-body:has(.ws-scale-key) > * {
  flex: none;
}

.ws-key .ws-key-drawn:has(.ws-scale-key) {
  display: block;
}

.ws-key .ws-key-body:has(.ws-scale-key) .ws-key-words {
  margin-top: 0.35rem;
}

/* Finger patterns: the key and string over the staff, and each pattern drawn beside its name. */
.ws-where {
  margin: 0;
  font-weight: 600;
}

.ws-pattern-staff {
  max-width: 12rem;
}

.ws-pattern-choice {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.2rem 0.6rem;
}

.ws-pattern-choice .pattern-picture {
  width: 7.5rem;
  max-width: 100%;
}

/* Solfège: the staff, and a line under it for each syllable. */
.ws-solfege-staff {
  max-width: 10rem;
}

.ws-solfege-phrase {
  max-width: 16rem;
}

.ws-syllable-blanks {
  gap: 0.5rem 1.1rem;
}

.ws-syllable-blanks .ws-blank-short {
  width: 3.4rem;
}

/* Composition paper: the rhythms to use, then lines of empty measures across the page. */
.ws-palette {
  margin-top: 0.6rem;
}

.ws-palette-title {
  margin: 0 0 0.3rem;
  font-size: 0.9rem;
  font-weight: 600;
}

.ws-palette-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ws-palette-tile {
  display: inline-flex;
  align-items: center;
  min-height: 2.6rem;
  padding: 0.15rem 0.5rem;
  border: 1px solid #9a9a9a;
  border-radius: 6px;
  color: #111;
}

.ws-palette-tile .rhythm-icon {
  display: block;
}

.ws-compose {
  padding-left: 0;
}

.ws-compose-line {
  display: block;
  width: 100%;
  height: auto;
  color: #111;
}

.ws-counts-row line {
  stroke: #6f6f6f;
  stroke-dasharray: 2 3;
}

/* Marching drill: the field printed black on white, with the dot sheet's two columns. */
.ws-sheet {
  --drill-turf: #fff;
  --drill-endzone: #ececec;
  --drill-outside: #fff;
  --drill-line: #111;
  --drill-grid: #c2c2c2;
}

.ws-field-wrap {
  width: 100%;
  max-width: 3.3in;
  border: 1px solid #777;
  border-radius: 4px;
  overflow: hidden;
  background: #fff;
}

.ws-sheet .drill-field .drill-dot.target circle {
  fill: #111;
}

.ws-sheet .drill-field .drill-dot.ref circle {
  fill: #fff;
  stroke: #111;
  stroke-width: 2px;
}

.ws-coord {
  width: 100%;
  font-size: 0.85rem;
}

.ws-coord-title {
  margin: 0 0 0.15rem;
  font-weight: 600;
}

.ws-coord dl {
  display: grid;
  gap: 0.1rem;
  margin: 0;
}

.ws-coord dl > div {
  display: grid;
  grid-template-columns: 6.5rem minmax(0, 1fr);
  gap: 0.5rem;
}

.ws-coord dt {
  color: #444;
}

.ws-coord dd {
  margin: 0;
}

.ws-coord-blanks {
  width: 100%;
}

.ws-coord-blanks .ws-answer,
.ws-coord-blanks .ws-answer:has(.ws-blank-long) {
  display: flex;
  width: 100%;
}

.ws-coord-blanks .ws-answer-label {
  flex: none;
  width: 6.5rem;
  font-weight: 500;
}

.ws-coord-blanks .ws-blank-long {
  flex: 1;
  width: auto;
}

.ws-steps {
  flex-wrap: nowrap;
  align-items: flex-start;
}

.ws-steps-sets {
  flex: 1 1 0;
  min-width: 0;
}

.ws-steps .ws-field-wrap {
  flex: 0 1 2.9in;
}

.ws-coord-choice {
  display: flex;
  flex-direction: column;
}

.ws-counts {
  max-width: none;
}

@media (max-width: 560px) {
  .ws-scale-card.ws-fill-sax,
  .ws-scale-card.ws-fill-clarinet,
  .ws-scale-card.ws-fill-oboe {
    flex-direction: column;
  }

  /* On a phone's preview, a name's number goes over its line, which takes the column's width. */
  .ws-question:has(> .ws-scale-name) {
    flex-direction: column;
    align-items: stretch;
  }

  .ws-scale-name .ws-answer,
  .ws-scale-name .ws-blank-short {
    width: 100%;
  }

  .ws-coord dl > div {
    grid-template-columns: minmax(0, 1fr);
    gap: 0;
  }

  .ws-coord-blanks .ws-answer-label {
    width: auto;
  }

  .ws-steps {
    flex-wrap: wrap;
  }

  .ws-steps .ws-field-wrap {
    flex-basis: 100%;
  }
}

/* The streak card on the Practice home (roadmap phase 53). */
.streak-card {
  padding: 1rem 1.25rem;
}

.streak-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.streak-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.5rem;
}

.streak-flame {
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
}

.streak-flame .icon {
  width: 1.6rem;
  height: 1.6rem;
}

.streak-main {
  min-width: 0;
}

.streak-count {
  font-family: var(--font-serif);
  font-size: 1.35rem;
  font-weight: 500;
  line-height: 1.2;
  font-variant-numeric: tabular-nums;
}

.streak-goal {
  margin-top: 0.85rem;
}

.goal-bar {
  height: 0.6rem;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}

.goal-fill {
  height: 100%;
  background: var(--primary);
  border-radius: 999px;
  transition: width 240ms ease;
}

.goal-fill.met {
  background: var(--success);
}

.goal-line {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 0.35rem;
  font-size: 0.9rem;
}

.goal-choose {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

/* Game mode (roadmap phase 86): the home's switch while it's off, and the line that turns it off on the streak card. */
.game-slot:focus {
  outline: none;
}

.game-mode-row {
  padding: 0.75rem 1.25rem;
}

.game-mode-line {
  display: flex;
  align-items: center;
  gap: 0.85rem;
}

.game-mode-mark {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
}

.game-mode-mark .icon {
  width: 1.35rem;
  height: 1.35rem;
}

.game-mode-text {
  flex: 1;
  min-width: 0;
}

.game-mode-text .hub-eyebrow {
  margin-bottom: 0.15rem;
}

.game-mode-text p {
  margin: 0;
}

.game-mode-problem:empty {
  display: none;
}

/* The switch: a track and knob with the state in words beside it, at least 44px tall to tap. */
.game-switch {
  flex: none;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  padding: 0 0.5rem;
  border: 0;
  border-radius: var(--radius-md);
  background: transparent;
  color: var(--foreground);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.game-switch:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.game-switch-track {
  position: relative;
  width: 2.75rem;
  height: 1.5rem;
  border-radius: 999px;
  background: var(--input-border);
  transition: background-color 0.15s;
}

.game-switch-knob {
  position: absolute;
  top: 0.1875rem;
  left: 0.1875rem;
  width: 1.125rem;
  height: 1.125rem;
  border-radius: 999px;
  background: var(--card);
  box-shadow: 0 1px 2px oklch(0 0 0 / 0.25);
  transition: transform 0.15s;
}

.game-switch[aria-checked='true'] .game-switch-track {
  background: var(--primary);
}

.game-switch[aria-checked='true'] .game-switch-knob {
  transform: translateX(1.25rem);
}

.game-switch-state {
  min-width: 1.6rem;
  text-align: left;
}

@media (prefers-reduced-motion: reduce) {
  .game-switch-track,
  .game-switch-knob {
    transition: none;
  }
}

.game-mode-row[data-game='on'] .game-mode-mark {
  background: var(--accent);
  color: var(--accent-foreground);
}

/* Remind me (roadmap phase 60): a switch and a time in the app; one line on the website. */
.streak-remind {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  margin: 0.75rem 0 0;
}

.streak-remind p {
  flex: 1 1 100%;
  margin: 0;
}

.streak-remind-switch {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
  cursor: pointer;
}

.streak-remind input[type='time'] {
  min-height: 44px;
  max-width: 100%;
}

.streak-remind input[type='time'][hidden] {
  display: none;
}

.goal-seg button {
  font-size: 0.85rem;
  padding: 0.3rem 0.6rem;
}

@media (prefers-reduced-motion: reduce) {
  .goal-fill {
    transition: none;
  }
}

/* Level and XP on the streak card (roadmap phase 54). */
.streak-level {
  margin-top: 0.75rem;
}

.streak-level-line {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  font-size: 0.95rem;
}

.level-bar {
  height: 0.35rem;
  margin-top: 0.3rem;
  border-radius: 999px;
  background: var(--muted);
  overflow: hidden;
}

.level-fill {
  height: 100%;
  background: var(--accent);
  border-radius: 999px;
  transition: width 240ms ease;
}

/* The Badges shelf on My progress, and a new badge on a results screen. */
.badge-shelf {
  padding: 0.25rem 0 0;
}

.badge-grid {
  list-style: none;
  margin: 0.5rem 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: 0.5rem;
}

.badge {
  display: flex;
  align-items: flex-start;
  gap: 0.55rem;
  padding: 0.55rem 0.65rem;
  border-radius: var(--radius-md);
  background: var(--muted);
  color: var(--muted-foreground);
}

.badge.earned {
  background: var(--card);
  color: var(--foreground);
  box-shadow: inset 0 0 0 1px var(--border);
}

.badge-mark {
  flex: none;
  width: 2rem;
  height: 2rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--border);
  color: var(--muted-foreground);
}

.badge.earned .badge-mark {
  background: var(--accent);
  color: var(--accent-foreground);
}

.badge-mark .icon {
  width: 1.25rem;
  height: 1.25rem;
}

.badge-text {
  display: flex;
  flex-direction: column;
  gap: 0.1rem;
  min-width: 0;
  font-size: 0.9rem;
  line-height: 1.3;
}

.badge-new {
  display: inline-flex;
  align-items: center;
  gap: 0.3rem;
  color: var(--foreground);
  font-weight: 500;
}

.badge-new .icon {
  width: 1rem;
  height: 1rem;
  color: var(--accent-foreground);
  background: var(--accent);
  border-radius: 999px;
  padding: 0.1rem;
}

@media (prefers-reduced-motion: reduce) {
  .level-fill {
    transition: none;
  }
}

/* The Skills page (roadmap phase 55): nodes that fill in from gray to the section's color. */
.streak-head-links {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
}

.skills-summary {
  margin: 0;
}

.skill-legend {
  list-style: none;
  margin: 0;
  padding: 0.6rem 0.85rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  border-radius: var(--radius-md);
  background: var(--muted);
  font-size: 0.9rem;
}

.skill-legend li {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.skill-section,
.tour-leg {
  /* Each section's own hue; the ring fills with it as the level rises. */
  --skill-hue: 35;
}

:is(.skill-section, .tour-leg)[data-section='scales'] { --skill-hue: 80; }
:is(.skill-section, .tour-leg)[data-section='rhythm'] { --skill-hue: 155; }
:is(.skill-section, .tour-leg)[data-section='ear'] { --skill-hue: 230; }
:is(.skill-section, .tour-leg)[data-section='reading'] { --skill-hue: 290; }
:is(.skill-section, .tour-leg)[data-section='theory'] { --skill-hue: 330; }
:is(.skill-section, .tour-leg)[data-section='chorus'] { --skill-hue: 20; }
:is(.skill-section, .tour-leg)[data-section='percussion'] { --skill-hue: 60; }
:is(.skill-section, .tour-leg)[data-section='marching'] { --skill-hue: 200; }

.skill-nodes {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
  gap: 0.5rem;
}

.skill-link {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--foreground);
  text-decoration: none;
  transition: border-color 0.15s;
}

.skill-link:hover {
  border-color: var(--input-border);
}

.skill-link:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.skill-ring {
  --skill-color: oklch(0.6 0.12 var(--skill-hue, 35));
  --share: 0;
  flex: none;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 999px;
  padding: 0.25rem;
  box-sizing: border-box;
  background: conic-gradient(var(--skill-color) calc(var(--share) * 1turn), var(--border) 0);
}

.skill-ring-inner {
  display: grid;
  place-items: center;
  width: 100%;
  height: 100%;
  border-radius: 999px;
  background: var(--card);
  color: var(--muted-foreground);
}

.skill-node[data-level='0'] .skill-ring-inner {
  background: var(--muted);
}

.skill-node[data-level='4'] .skill-ring-inner {
  background: var(--skill-color);
  color: oklch(0.99 0.005 90);
}

.skill-ring .icon {
  width: 1.25rem;
  height: 1.25rem;
}

.skill-ring-sm {
  width: 1.5rem;
  height: 1.5rem;
  padding: 0.18rem;
}

.skill-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.skill-name {
  font-weight: 500;
}

.skill-level {
  font-size: 0.8rem;
  color: oklch(0.45 0.1 var(--skill-hue, 35));
}

.skill-node[data-level='0'] .skill-level {
  color: var(--muted-foreground);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .skill-ring {
    --skill-color: oklch(0.7 0.12 var(--skill-hue, 35));
  }

  :root:not([data-theme='light']) .skill-level {
    color: oklch(0.78 0.1 var(--skill-hue, 35));
  }

  :root:not([data-theme='light']) .skill-node[data-level='4'] .skill-ring-inner {
    color: oklch(0.2 0.02 210);
  }
}

:root[data-theme='dark'] .skill-ring {
  --skill-color: oklch(0.7 0.12 var(--skill-hue, 35));
}

:root[data-theme='dark'] .skill-level {
  color: oklch(0.78 0.1 var(--skill-hue, 35));
}

:root[data-theme='dark'] .skill-node[data-level='4'] .skill-ring-inner {
  color: oklch(0.2 0.02 210);
}

/* The tour (roadmap phase 87): legs that fold up to a strip of dots, and stops that fill like skill rings. */
.tour-summary {
  margin: 0;
}

.tour-next {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.75rem 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--muted);
}

.tour-next-mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
}

/* The avatar stands in for the flame when the student has picked one. */
.tour-next-mark .avatar-slot:not([hidden]) ~ .icon {
  display: none;
}

.tour-next-text {
  flex: 1;
  min-width: 0;
}

.tour-next-name {
  font-weight: 600;
  overflow-wrap: anywhere;
}

.tour-legs {
  gap: 0.5rem;
}

.tour-leg {
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  padding: 0 0.85rem;
}

.tour-leg-head {
  cursor: pointer;
  padding-block: 0.6rem;
}

.tour-leg-title {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.25rem 0.6rem;
}

.tour-leg-name {
  font-weight: 600;
}

/* The route at a glance: one dot per stop, filled to its state, then the final. */
.tour-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  margin-top: 0.4rem;
}

.tour-dot {
  --skill-color: oklch(0.6 0.12 var(--skill-hue, 35));
  width: 0.65rem;
  height: 0.65rem;
  border-radius: 999px;
  box-sizing: border-box;
  border: 1.5px solid var(--border);
  background: var(--card);
}

.tour-dot[data-level='1'] { background: color-mix(in oklch, var(--skill-color) 25%, var(--card)); border-color: var(--skill-color); }
.tour-dot[data-level='2'] { background: color-mix(in oklch, var(--skill-color) 50%, var(--card)); border-color: var(--skill-color); }
.tour-dot[data-level='3'] { background: color-mix(in oklch, var(--skill-color) 75%, var(--card)); border-color: var(--skill-color); }
.tour-dot[data-level='4'] { background: var(--skill-color); border-color: var(--skill-color); }

.tour-dot[data-next='true'] {
  outline: 2px solid var(--foreground);
  outline-offset: 1px;
}

.tour-dot-final {
  border-radius: 2px;
  transform: rotate(45deg) scale(0.85);
  border-style: dashed;
}

.tour-stops {
  list-style: none;
  margin: 0.25rem 0 0.85rem;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13.5rem, 1fr));
  gap: 0.5rem;
}

.tour-stop-link,
.tour-final-box {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.7rem;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  background: var(--card);
  color: var(--foreground);
  text-decoration: none;
  transition: border-color 0.15s;
}

.tour-stop-link:hover {
  border-color: var(--input-border);
}

.tour-stop-link:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

.tour-stop[data-next='true'] .tour-stop-link {
  border-color: var(--skill-color, var(--foreground));
  border-width: 2px;
  padding: calc(0.6rem - 1px) calc(0.75rem - 1px);
  --skill-color: oklch(0.6 0.12 var(--skill-hue, 35));
}

.tour-final-box {
  border-style: dashed;
  color: var(--muted-foreground);
}

.tour-final .skill-ring {
  background: var(--border);
}

.tour-stop-text {
  display: flex;
  flex-direction: column;
  min-width: 0;
  line-height: 1.3;
}

.tour-stop-name {
  font-weight: 500;
}

.tour-stop-level {
  font-size: 0.85rem;
  color: var(--muted-foreground);
}

/* Where the avatar stands: the next stop's corner. */
.tour-here {
  position: absolute;
  top: -0.6rem;
  right: 0.5rem;
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
  padding: 0.05rem 0.45rem 0.05rem 0.1rem;
  border-radius: 999px;
  background: var(--foreground);
  color: var(--background);
  font-size: 0.75rem;
  font-weight: 600;
}

.tour-here .avatar-slot[hidden] + .tour-here-word {
  padding-left: 0.35rem;
}

.tour-here .avatar-mark {
  display: block;
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 999px;
}

.next-stop-row .hub-eyebrow a {
  white-space: nowrap;
  font-weight: 500;
  text-transform: none;
  letter-spacing: 0;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .tour-dot,
  :root:not([data-theme='light']) .tour-stop[data-next='true'] .tour-stop-link {
    --skill-color: oklch(0.7 0.12 var(--skill-hue, 35));
  }
}

:root[data-theme='dark'] .tour-dot,
:root[data-theme='dark'] .tour-stop[data-next='true'] .tour-stop-link {
  --skill-color: oklch(0.7 0.12 var(--skill-hue, 35));
}

/* Today's and this week's challenge on the Practice home (roadmap phase 56). */
.challenge-card {
  padding: 0.5rem 1.25rem;
}

.challenge-row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.75rem 0;
}

.challenge-row + .challenge-row {
  border-top: 1px solid var(--border);
}

.challenge-mark {
  flex: none;
  width: 2.5rem;
  height: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--accent);
  color: var(--accent-foreground);
}

.challenge-row[data-done='true'] .challenge-mark {
  background: var(--success);
  color: var(--success-foreground);
}

.challenge-mark .icon {
  width: 1.35rem;
  height: 1.35rem;
}

.challenge-text {
  flex: 1;
  min-width: 0;
}

.challenge-text .hub-eyebrow {
  margin-bottom: 0.15rem;
}

.challenge-name {
  font-weight: 500;
  line-height: 1.3;
}

.challenge-bonus {
  display: inline-block;
  margin-left: 0.15rem;
  padding: 0.05rem 0.45rem;
  border-radius: 999px;
  background: var(--muted);
  color: var(--muted-foreground);
  font-size: 0.78rem;
  font-weight: 500;
  white-space: nowrap;
}

.challenge-row[data-done='true'] .challenge-bonus {
  background: var(--success);
  color: var(--success-foreground);
}

.challenge-row .btn {
  flex: none;
}

@media (max-width: 420px) {
  .challenge-row {
    flex-wrap: wrap;
  }

  .challenge-row .btn {
    margin-left: 3.35rem;
  }
}

/* Speed rounds (roadmap phase 57): the start button, the window bar and the results. */
.sprint-start {
  border-color: var(--accent-foreground);
  color: var(--accent-foreground);
  background: var(--accent);
}

.sprint-start:hover {
  background: var(--accent);
  border-color: var(--primary);
}

.sprint-best-tag {
  font-weight: 400;
  opacity: 0.85;
}

.sprint-window > div {
  background: var(--accent-foreground);
  transition: width 0.1s linear;
}

.sprint-results .score-big {
  font-size: 3.5rem;
}

.sprint-best {
  margin: 0;
  font-weight: 500;
}

@media (prefers-reduced-motion: reduce) {
  .sprint-window > div {
    transition: none;
  }
}

/* Pass and play (roadmap phase 90): two names, the screen that passes the device, whose turn, and the winner. */
.pass-play-names {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: 0.75rem 1rem;
}

.pass-play-options {
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
}

.pass-play-pass {
  text-align: center;
  padding-block: 2rem;
}

.pass-play-pass h2 {
  font-size: 1.75rem;
  margin: 0;
}

.pass-play-pass .row {
  justify-content: center;
}

.pass-play-ready {
  min-width: 10rem;
  min-height: 3.5rem;
  font-size: 1.15rem;
}

.pass-play-turn {
  font-weight: 600;
  overflow-wrap: anywhere;
}

/* A long name in "Pass to …" or the score wraps inside the card rather than running off a phone. */
.pass-play-round .btn-primary {
  white-space: normal;
  height: auto;
  min-height: 2.25rem;
  padding-block: 0.4rem;
  text-align: left;
}

.pass-play-round .practice-head,
.pass-play-round .stats {
  flex-wrap: wrap;
  min-width: 0;
}

.pass-play-score,
.pass-play-pass h2,
.pass-play-winner {
  overflow-wrap: anywhere;
}

.pass-play-round[data-player='1'] .pass-play-turn,
.pass-play-pass[data-player='1'] h2 {
  color: var(--accent-foreground);
}

.pass-play-score {
  font-variant-numeric: tabular-nums;
}

.pass-play-winner {
  font-size: 2rem;
  margin: 0;
}

.pass-play-saved {
  margin: 0;
  padding-left: 1.1rem;
}

/* ------------------------------------------------------------ Your look (roadmap phase 58) */
/* The avatar beside "Your streak" and "My progress". */
.streak-title-row,
.progress-title {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.progress-title h1 {
  margin: 0;
}

.avatar-slot {
  display: inline-flex;
  flex: none;
}

.avatar-slot[hidden] {
  display: none;
}

.avatar-mark {
  flex: none;
  border-radius: 50%;
  box-shadow: var(--shadow);
}

.look-link {
  display: inline-flex;
  align-items: center;
  gap: 0.25rem;
}

.look-link .icon {
  width: 1em;
  height: 1em;
}

/* The home's title, tinted by the season (D52). */
.hub-head {
  padding: 0.75rem 1rem;
  border-radius: 1rem;
  background: linear-gradient(135deg, oklch(0.9 0.06 var(--season-hue, 35) / 45%), transparent 70%);
}

.hub-head-text {
  min-width: 0;
}

:root[data-season='marching'] { --season-hue: 60; }
:root[data-season='concert'] { --season-hue: 260; }
:root[data-season='contest'] { --season-hue: 345; }
:root[data-season='summer'] { --season-hue: 190; }

@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) .hub-head {
    background: linear-gradient(135deg, oklch(0.4 0.06 var(--season-hue, 35) / 45%), transparent 70%);
  }
}

:root[data-theme='dark'] .hub-head {
  background: linear-gradient(135deg, oklch(0.4 0.06 var(--season-hue, 35) / 45%), transparent 70%);
}

/* The page itself: swatches, avatars and hue sliders. */
.look-swatches,
.look-avatars {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(7rem, 1fr));
  gap: 0.5rem;
}

.look-swatch,
.look-avatar {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.4rem;
  height: auto;
  min-height: 2.25rem;
  padding: 0.6rem 0.4rem;
  white-space: normal;
  font-weight: 400;
  background: var(--card);
  color: var(--foreground);
  border: 1px solid var(--input-border);
  border-radius: 0.75rem;
  font-size: 0.85rem;
  line-height: 1.2;
}

.look-swatch.active,
.look-avatar.active {
  border-color: var(--ring);
  box-shadow: 0 0 0 2px var(--ring);
}

.look-avatar.locked {
  opacity: 0.55;
  cursor: not-allowed;
}

.look-avatar.locked img {
  filter: grayscale(1);
}

.look-avatar img,
.look-avatar-none {
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
}

.look-avatar-none {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--muted);
  color: var(--muted-foreground);
}

.look-avatar-none .icon {
  width: 1.75rem;
  height: 1.75rem;
}

.look-swatch-dot {
  position: relative;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--swatch);
  box-shadow: 0 0 0 3px var(--card), 0 0 0 5px var(--swatch-ring);
}

.look-swatch-second {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: linear-gradient(135deg, transparent 50%, var(--swatch-ring) 50%);
}

.look-school {
  display: grid;
  gap: 0.75rem;
}

.look-school[hidden] {
  display: none;
}

.look-hue .row {
  align-items: center;
  gap: 0.75rem;
}

.look-hue input[type='range'] {
  flex: 1;
  min-width: 0;
  accent-color: var(--primary);
}

.look-hue-dot {
  flex: none;
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: var(--swatch);
  border: 1px solid var(--border);
}

/* Paper stays light whatever the theme or accent: a worksheet or a progress log prints the same for everyone.
   !important, because the look's accent is set inline on <html> (js/look-store.js), which a plain rule can't override. */
@media print {
  :root,
  :root[data-theme='dark'] {
    color-scheme: light;
    --background: oklch(1 0 0) !important;
    --foreground: oklch(0.28 0.018 210) !important;
    --card: oklch(1 0 0) !important;
    --card-foreground: oklch(0.28 0.018 210) !important;
    --primary: oklch(0.52 0.14 35) !important;
    --primary-foreground: oklch(0.99 0.005 90) !important;
    --ring: oklch(0.58 0.13 35) !important;
    --secondary: oklch(0.92 0.028 80) !important;
    --secondary-foreground: oklch(0.32 0.025 210) !important;
    --muted: oklch(0.94 0.015 85) !important;
    --muted-foreground: oklch(0.47 0.025 215) !important;
    --accent: oklch(0.9 0.05 40) !important;
    --accent-foreground: oklch(0.38 0.09 35) !important;
    --border: oklch(0.87 0.014 210) !important;
    --input: oklch(0.87 0.014 210) !important;
    --input-border: oklch(0.62 0.014 210) !important;
    --neutral: oklch(0.22 0.01 210) !important;
    --neutral-foreground: oklch(0.99 0.005 90) !important;
    --shadow: none !important;
  }

  .hub-head {
    background: none;
  }
}

/* ------------------------------------------------------------ Share cards and My semester (roadmap phase 59) */
.share-button .icon {
  width: 1em;
  height: 1em;
}

.share-preview {
  display: flex;
  justify-content: center;
  margin: 0.75rem 0;
}

.share-preview svg {
  width: 100%;
  max-width: 16rem;
  height: auto;
  border-radius: 0.75rem;
  box-shadow: var(--shadow);
}

.share-preview[data-size='square'] svg {
  max-width: 20rem;
}

.share-name-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.share-name[hidden] {
  display: none;
}

.progress-title .progress-recap-link {
  margin-left: auto;
  align-self: center;
}

.progress-title {
  width: 100%;
}

.recap-range {
  flex-wrap: wrap;
  align-items: flex-end;
  gap: 0.75rem;
}

.recap-title {
  margin: 0;
}

.recap-tiles {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: 0.75rem;
}

.recap-tile {
  padding: 0.85rem 1rem;
  border: 1px solid var(--border);
  border-radius: 0.75rem;
  background: var(--card);
}

.recap-value {
  font-family: Fraunces, Georgia, serif;
  font-size: 2rem;
  line-height: 1.1;
  color: var(--primary);
}

.recap-facts {
  margin: 0;
  padding-left: 1.2rem;
}

@media print {
  .recap-page {
    box-shadow: none;
    border: 0;
    padding: 0;
  }

  .recap-range,
  .recap-actions,
  .recap-page .back-link {
    display: none !important;
  }

  .recap-tiles {
    grid-template-columns: repeat(3, 1fr);
  }

  .recap-page {
    break-inside: avoid;
  }
}

/* ------------------------------------------------------------ touch screens */
/* On a touch screen every control is at least 44 px tall (WCAG 2.5.5, Apple's
   Human Interface Guidelines) and square controls are 44 px across, so a thumb
   doesn't land on the neighbor. A mouse keeps the compact sizes. Links inside a
   sentence (.text-button too) stay inline; WCAG 2.5.8 exempts them.
   (UX plan phase 92.) */
@media (pointer: coarse) {
  button:not(.text-button),
  .btn,
  select,
  input[type='text'],
  input[type='search'],
  input[type='number'],
  input[type='date'],
  input[type='url'],
  input[type='email'],
  input[type='range'],
  .check,
  .brand,
  .topnav a,
  .back-link,
  .tool-tab,
  .footer-links a,
  .footer-family-link,
  .footer-brand-link {
    min-height: 2.75rem;
  }

  .topnav a,
  .tool-tab,
  .footer-links a {
    display: inline-flex;
    align-items: center;
  }

  /* A summary keeps its disclosure triangle (display: list-item), so it grows
     by padding. */
  summary {
    box-sizing: border-box;
    min-height: 2.75rem;
    padding-block: 0.6rem;
  }

  /* Standalone small links: "Change instrument" on the Fingerings tile, and
     the links in the streak card's and Pick up where you left off's heads. */
  .tile-change,
  .streak-head-links a,
  .resume-head a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    padding-inline: 0.25rem;
  }

  /* Below its tile's link, not over it, so a tap near the tile's edge opens
     the tile. */
  .tile-change {
    margin: 0 1rem 0.5rem;
  }

  /* Rules that pin a control's height below 44 px (drill's segments, the
     chorus page's tabs) meet the floor too; so do the chorus page's link-styled
     buttons, which stand on their own lines rather than inside sentences. */
  .drill-seg a,
  .chorus-page .text-tabs button:not(.text-button),
  .chorus-page .chorus-progress-link,
  .chorus-page button.text-button,
  .sheet-create {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
  }

  .drill-seg a {
    height: auto;
  }

  /* The trail grows its targets without growing the header. */
  .trail a {
    display: inline-flex;
    align-items: center;
    min-height: 2.75rem;
    margin-block: -0.75rem;
  }

  .icon-button,
  .drill-nudge {
    width: 2.75rem;
    height: 2.75rem;
  }

  .lesson-step {
    height: 2.75rem;
  }

  .check input {
    width: 1.25rem;
    height: 1.25rem;
  }
}

/* Keyboard shortcuts mean nothing on a phone or tablet with no keyboard: the
   hint lines and the key caps on buttons go (UX plan phase 92, D102). */
@media (hover: none) and (pointer: coarse) {
  .kbd-hint,
  .chorus-page .answer-help,
  button kbd,
  .btn kbd {
    display: none;
  }
}

/* ------------------------------------------------------------ a round on a phone */
/* While a round runs (session.js puts .in-round on the page), a phone shows a
   one-line heading and keeps the score, question count and clock in view, so
   the question, Check and Next fit without scrolling (UX plan 93.1). The top
   bar scrolls away with the page instead of covering the round's strip. */
@media (max-width: 720px) {
  html.in-round .topbar {
    position: static;
  }

  html.in-round .activity-header {
    margin-bottom: 0.5rem;
  }

  html.in-round .activity-head .trail,
  html.in-round .activity-head .activity-meta,
  html.in-round .activity-head .activity-lead,
  html.in-round .activity-header > :not(.activity-head) {
    display: none;
  }

  html.in-round .activity-head {
    align-items: center;
  }

  html.in-round .activity-head > h1 {
    margin: 0;
    font-size: 1.2rem;
    line-height: 1.25;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  html.in-round .practice-head {
    position: sticky;
    top: 0;
    z-index: 5;
    margin: -0.25rem -0.25rem 0.5rem;
    padding: 0.5rem 0.25rem;
    background: var(--card);
  }

  html.in-round .practice-head > .muted.small {
    display: none;
  }

  html.in-round .progress {
    margin: 0 0 0.75rem;
  }
}

/* A link that opened nothing (UX plan 95.3), and a line the last page left (95.5). */
.page-alert,
.page-note {
  margin: 0;
  padding: 0.75rem 1rem;
  border: 1px solid var(--warning);
  border-radius: var(--radius-lg);
  background: color-mix(in oklch, var(--warning) 12%, var(--card));
}

.page-note {
  margin-bottom: 1rem;
}

/* The results screen (UX plan phase 96). The score and the report's code side by side, wrapping on a phone. */
.result-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem 1.5rem;
}

.result-code {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.result-code-value {
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.06em;
}

/* Sending the results, closed on a round the student started for themselves (96.1). */
details.send-results > summary {
  font-family: var(--font-serif);
  font-size: 1.125rem;
  font-weight: 600;
}

details.send-results[open] > summary {
  margin-bottom: 0.75rem;
}

/* A missed note's pill opens it to practice on its own (96.5). */
a.pill.missed-drill {
  text-decoration: none;
}

a.pill.missed-drill:hover {
  text-decoration: underline;
}

@media (pointer: coarse) {
  a.pill.missed-drill {
    min-height: 2.75rem;
    display: inline-flex;
    align-items: center;
    padding: 0 0.9rem;
    font-size: 0.875rem;
  }
}

/* What the round earned, on its own row; where it's kept, on a quiet line under it (96.3). */
.history-note {
  display: grid;
  gap: 0.75rem;
}

.results-gains {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 0.75rem;
  padding: 0.75rem 1rem;
  border-radius: var(--radius-lg);
  background: var(--muted);
}

.results-gains-label {
  font-weight: 600;
}

.history-note .history-privacy {
  margin: 0;
}

/* ---------------------------------------------- sound and the microphone (UX plan phase 97) */
/* A button whose sound is playing says so, and its icon pulses (still, with reduced motion). */
.is-playing {
  border-color: var(--primary);
  color: var(--primary);
}

.is-playing .icon {
  animation: sound-pulse 0.9s ease-in-out infinite alternate;
}

@keyframes sound-pulse {
  from {
    opacity: 1;
  }

  to {
    opacity: 0.35;
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-playing .icon {
    animation: none;
  }
}

.sound-hint {
  margin: 0;
  text-align: center;
}

/* Right or wrong under the staff of what was heard, above the choices (97.2). */
.ear-verdict {
  width: 100%;
}

.ear-verdict .feedback {
  margin-top: 0;
}

/* The microphone's level: a bar, and what it hears (97.10, 97.11). */
.mic-level {
  display: grid;
  justify-items: center;
  gap: 0.35rem;
  width: min(100%, 18rem);
  margin: 0.25rem auto 0;
}

.mic-level[hidden] {
  display: none;
}

.mic-level-bar {
  display: block;
  width: 100%;
  height: 0.5rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: 999px;
  background: var(--muted);
}

.mic-level-fill {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--success);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.08s linear;
}

.mic-level-words {
  margin: 0;
  color: var(--muted-foreground);
  text-align: center;
}

.mic-level[data-hears='quiet'] .mic-level-words {
  color: var(--warning);
  font-weight: 500;
}

.mic-ask {
  margin: 0;
}

/* Stop, apart from the tap pad, while a take runs (97.7). */
.tap-stop-row {
  justify-content: center;
}

.tap-stop-row:has(> [hidden]:only-child) {
  display: none;
}

.tap-stop {
  min-width: 8rem;
}

/* In an assessment, Next (or See results) takes the pad's place once the take is in (97.9). */
.tap-pad-slot,
.rudiment-start-slot {
  display: flex;
  justify-content: center;
  width: 100%;
}

.tap-pad-slot > .btn-primary:not(.tap-pad) {
  width: min(100%, 24rem);
  min-height: 3.5rem;
  font-size: 1.1rem;
}

/* What has to happen before Start, right above it (97.8). */
.start-wait {
  margin: 0;
  font-weight: 500;
}

.start-wait[hidden] {
  display: none;
}

/* Why Check waits, under the rhythm tiles (97.6). */
.ear-waiting {
  margin: 0;
  text-align: center;
}

.ear-waiting:empty {
  display: none;
}

/* Sight-reading's study clock: quiet for a screen reader, amber at time up, and Play pulses once (97.13). */
.sight-clock {
  min-height: 1.5em;
  margin: 0;
  text-align: center;
}

.sight-clock[hidden] {
  display: none;
}

.sight-answer .sight-status:empty {
  min-height: 0;
}

.sight-clock-up {
  color: var(--warning);
  font-weight: 600;
}

.pulse-once {
  animation: pulse-once 0.6s ease-out 2;
}

@keyframes pulse-once {
  50% {
    transform: scale(1.06);
    box-shadow: 0 0 0 0.35rem color-mix(in oklch, var(--primary) 25%, transparent);
  }
}

@media (prefers-reduced-motion: reduce) {
  .pulse-once {
    animation: none;
  }
}

/* The microphone check, the backing track and two-part options, folded under Play (97.14). */
.sight-study {
  justify-items: center;
  width: 100%;
}

.sight-options {
  width: min(100%, 30rem);
}

.sight-options > summary {
  padding-block: 0.5rem;
  cursor: pointer;
  font-weight: 500;
  text-align: center;
}

.sight-option-list {
  display: grid;
  justify-items: center;
  gap: 0.5rem;
  padding: 0.25rem 0 0.5rem;
}

/* The drill's dot before it's placed: faint and dashed, to drag or tap past (97.16). */
.drill-field .drill-dot.ghost circle {
  fill: none;
  stroke: var(--foreground);
  stroke-width: 2px;
  stroke-dasharray: 3 3;
  opacity: 0.55;
}

.drill-field .drill-dot.ghost .drill-dot-center {
  fill: var(--foreground);
  stroke: none;
  opacity: 0.55;
  stroke-dasharray: none;
}

.drill-zoom[hidden] {
  display: none;
}
