/* Ear Trainer — see .agents/ear-trainer.md */

/*
  styles.css leaves `--text` at the light-mode value, and every page opts into
  the dark theme from its own stylesheet. Without this the page renders
  near-black text on dark navy and reads as washed out.
*/
body.ear-trainer-page {
  padding: 0;
  color: rgba(245, 247, 251, 0.92);
  --text: rgba(245, 247, 251, 0.92);
  --muted: rgba(230, 238, 250, 0.72);
  /* Mirrors tools.css so the ported .tool-* rules below read identically. */
  --tools-soft: rgba(255, 255, 255, 0.72);
  --tools-muted: rgba(245, 247, 251, 0.64);
  --tools-amber: var(--brand-amber, #D9A21B);
  background:
    radial-gradient(circle at top left, rgba(58, 92, 156, 0.16), transparent 35%),
    radial-gradient(circle at 82% 14%, rgba(42, 157, 181, 0.12), transparent 26%),
    linear-gradient(180deg, var(--bg-top), var(--bg-bottom));
}

body.ear-trainer-page h1,
body.ear-trainer-page h2,
body.ear-trainer-page h3 {
  color: #f7fbff;
}

.ear-wrap {
  padding-bottom: 40px;
}

.ear-hero {
  margin: 26px 0 22px;
}

.ear-hero h1 {
  margin: 6px 0 10px;
}

.ear-hero-copy {
  max-width: 62ch;
  margin: 0;
  color: var(--muted, rgba(230, 238, 250, 0.72));
  line-height: 1.55;
}

.ear-main {
  display: block;
}

/* ── Tool card shell ──────────────────────────────────────────────────────────
   Ported from tools.css so the Ear Trainer reads as a sibling of the Metronome,
   Ukulele Tuner, and Voice Warm-Up rather than a one-off page. tools.css is not
   loaded here (it is 6k lines and scoped to body.tools-page), so the handful of
   classes the layout needs are duplicated verbatim. Keep them in sync.
   ─────────────────────────────────────────────────────────────────────────── */

.tool-card {
  display: flex;
  flex-direction: column;
  margin-bottom: 22px;
}

.tool-card[hidden] {
  display: none !important;
}

.tool-card.tool-card--utility {
  border-radius: 22px;
  padding: 22px 20px 20px;
  border: 1px solid rgba(149, 198, 255, 0.22);
  border-left: 4px solid var(--tools-amber);
  background:
    linear-gradient(155deg, rgba(22, 40, 72, 0.98) 0%, rgba(14, 30, 56, 0.99) 52%, rgba(16, 52, 62, 0.42) 100%);
  box-shadow: 0 18px 44px rgba(4, 10, 24, 0.38);
}

.tool-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
}

.tool-eyebrow {
  font-size: 13px;
  font-weight: 800;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: rgba(240, 196, 91, 0.92);
}

.tool-card.tool-card--utility h2.utility-title {
  margin: 6px 0 0;
  font-size: clamp(1.28rem, 2.2vw, 1.68rem);
  font-weight: 800;
  letter-spacing: -0.03em;
  line-height: 1.12;
  color: #f7fbff;
  text-shadow: 0 6px 20px rgba(0, 0, 0, 0.2);
}

.tool-chip {
  padding: 8px 12px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: rgba(18, 34, 68, 0.92);
  background: linear-gradient(180deg, rgba(240, 196, 91, 0.96), rgba(214, 148, 37, 0.92));
}

.tool-copy,
.tool-note {
  color: var(--tools-soft);
  line-height: 1.5;
}

.tool-copy {
  margin: 12px 0 0;
  max-width: 68ch;
}

.tool-note {
  font-size: 0.84rem;
}

.tool-controls-row {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.tool-control {
  display: grid;
  gap: 8px;
  min-width: 150px;
  flex: 1 1 0;
  position: relative;
}

/*
  tools.css swaps its selects for .picker-trigger buttons, so it never hits
  this: a bare <select> sizes to its widest option and, as a grid item with
  min-width auto, spills over the neighbouring control.
*/
.tool-control select {
  width: 100%;
  min-width: 0;
  text-overflow: ellipsis;
}

/* The pool labels name the intervals, so this control needs the extra room. */
.tool-control.ear-control-pool {
  flex: 2 1 260px;
}

/* Holds a slider and its test button side by side. */
.tool-control.ear-control-volume {
  flex: 1.4 1 220px;
}

.tool-controls-row + .tool-controls-row {
  margin-top: 14px;
}

.tool-control span:first-child {
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--tools-muted);
}

.tool-control select {
  min-height: 48px;
  border-radius: 0;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.06);
  color: #f5f7fb;
  padding: 0 36px 0 14px;
  font: inherit;
}

.tool-control select option {
  color: #122244;
  background: #f5f7fb;
}

/*
  Styled native <select>s on Windows Chromium paint the closed value without
  word spaces. Keep the real select clickable and show the label on a face
  that uses ordinary text rendering.
*/
.ear-select-face-wrap {
  position: relative;
  display: block;
  width: 100%;
  min-width: 0;
}

.ear-select-face-wrap select {
  position: absolute;
  inset: 0;
  z-index: 1;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.ear-select-face-wrap select:focus,
.ear-select-face-wrap select:focus-visible {
  outline: none;
}

.ear-select-face {
  display: flex;
  align-items: center;
  min-height: 48px;
  padding: 0 36px 0 14px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.06);
  color: #f5f7fb;
  letter-spacing: 0;
  word-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

.ear-select-face-wrap::after {
  content: "";
  position: absolute;
  right: 16px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 2px solid rgba(245, 247, 251, 0.86);
  border-bottom: 2px solid rgba(245, 247, 251, 0.86);
  transform: translateY(-65%) rotate(45deg);
  pointer-events: none;
}

.ear-select-face-wrap:focus-within .ear-select-face {
  outline: 3px solid rgba(231, 183, 62, 0.9);
  outline-offset: 3px;
}

.tool-actions {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 18px;
}

/* ── Setup ────────────────────────────────────────────────────────────────── */

/*
  Nothing is audible until Start is pressed, so the setup card is also the
  gesture that unlocks the AudioContext.
*/

/*
  "Start here" ladder. Deliberately quiet: it reads as an aside above the card
  grid, not as a competing control surface. Two accessible markers, because
  "current" must never be colour alone — the current row is bolded AND carries
  a "Next up" chip, the same belt-and-braces approach the exercise cards use
  with their check glyph.
*/
.ear-path {
  margin-top: 20px;
  padding: 16px;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.1);
  background: rgba(255, 255, 255, 0.035);
}

.ear-path[hidden] {
  display: none !important;
}

.ear-path-heading {
  margin: 0;
  font-size: 1rem;
  font-weight: 700;
  color: rgba(240, 200, 100, 0.95);
}

.ear-path-copy {
  margin: 6px 0 0;
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--muted, rgba(230, 238, 250, 0.7));
}

/*
  A vertical list, one step per row — NOT a wrapping flex row. An earlier
  version wrapped the pills horizontally, and because each item also carries a
  "why" line, the rows ended up different heights and the reason text floated
  away from its own step. One step per row also matches what this is: an
  ordered path you read top to bottom.
*/
.ear-path-steps {
  display: flex;
  flex-direction: column;
  gap: 4px;
  margin: 14px 0 0;
  padding: 0;
  list-style: none;
}

.ear-path-steps > li {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas:
    "num step"
    "num why";
  align-items: start;
  column-gap: 10px;
  padding: 6px 8px;
  border-radius: 12px;
}

.ear-path-steps > li.is-current {
  background: rgba(240, 200, 100, 0.1);
}

/*
  The step number sits in its own column, spoken by the button's aria-label
  instead of as separate text, so it is decorative here.
*/
.ear-path-step-num {
  grid-area: num;
  display: grid;
  place-items: center;
  width: 22px;
  height: 22px;
  margin-top: 2px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.1);
  font-size: 0.74rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.ear-path-step {
  grid-area: step;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  /* Global button reset makes every button full width; this is a text row. */
  width: auto;
  min-height: 0;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font-size: 0.9rem;
  line-height: 1.3;
  text-align: left;
  cursor: pointer;
}

.ear-path-step:hover .ear-path-step-label,
.ear-path-step:focus-visible .ear-path-step-label {
  text-decoration: underline;
  text-underline-offset: 2px;
}

.ear-path-step:focus-visible {
  outline: 2px solid rgba(240, 200, 100, 0.9);
  outline-offset: 3px;
  border-radius: 6px;
}

.ear-path-step-label {
  font-weight: 600;
}

.ear-path-step-why {
  grid-area: why;
  margin: 2px 0 0;
  font-size: 0.83rem;
  line-height: 1.45;
  color: var(--muted, rgba(230, 238, 250, 0.7));
}

/* The step the exercise cards currently point at. */
.ear-path-steps > li.is-current .ear-path-step-num {
  background: rgba(240, 200, 100, 0.9);
  color: #1f2d4f;
}

.ear-path-steps > li.is-current .ear-path-step-label {
  font-weight: 800;
}

.ear-path-step-chip {
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(240, 200, 100, 0.22);
  color: rgba(240, 200, 100, 0.98);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.ear-exercise-choices {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 14px;
  margin-top: 18px;
}

.ear-exercise-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  width: 100%;
  text-align: left;
  padding: 16px;
  border-radius: 16px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.05);
  color: inherit;
  cursor: pointer;
  transition: border-color 0.16s ease, background 0.16s ease;
}

.ear-exercise-choice:hover,
.ear-exercise-choice:focus-visible {
  border-color: rgba(240, 200, 100, 0.55);
  background: rgba(255, 255, 255, 0.08);
}

/* Selection is not colour-only: the chosen card also gains a check glyph. */
.ear-exercise-choice[aria-pressed="true"] {
  border-color: rgba(240, 200, 100, 0.85);
  border-width: 2px;
  background: rgba(240, 200, 100, 0.12);
}

.ear-exercise-choice-check {
  display: none;
  margin-left: auto;
  font-size: 1.15rem;
  font-weight: 800;
  color: rgba(240, 200, 100, 0.95);
}

.ear-exercise-choice[aria-pressed="true"] .ear-exercise-choice-check {
  display: block;
}

.ear-exercise-choice-icon {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
}

.ear-exercise-choice-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ear-exercise-choice-title {
  font-weight: 700;
  font-size: 1.05rem;
}

.ear-exercise-choice-desc {
  font-size: 0.9rem;
  color: var(--muted, rgba(230, 238, 250, 0.7));
  line-height: 1.45;
}

.ear-settings-group {
  margin: 0;
}

.ear-settings-group[hidden],
#earStartNoteControl[hidden] {
  display: none !important;
}

.ear-setup-start {
  width: auto;
  min-height: 48px;
  padding: 0 26px;
}

/* Matches the 48px select height so every control label sits on one line. */
.ear-volume-row {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 48px;
}

.ear-volume-row input[type="range"] {
  flex: 1 1 auto;
  min-width: 110px;
}

.ear-landing-note {
  margin: 18px 0 0;
  font-size: 0.9rem;
  color: var(--muted, rgba(230, 238, 250, 0.66));
  line-height: 1.5;
}

.ear-landing-note a {
  color: #f0c85b;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.ear-landing-note a:hover,
.ear-landing-note a:focus-visible {
  color: #ffdd88;
}

/* ── Stage ────────────────────────────────────────────────────────────────── */

.ear-stage-status {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.ear-pill {
  display: inline-block;
  padding: 4px 11px;
  border-radius: 999px;
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  background: rgba(90, 170, 220, 0.20);
  border: 1px solid rgba(90, 170, 220, 0.42);
}

.ear-pill-soft {
  background: rgba(255, 255, 255, 0.07);
  border-color: rgba(255, 255, 255, 0.16);
  font-weight: 600;
}

.ear-instruction {
  margin: 10px 0 18px;
  font-size: 1.02rem;
  line-height: 1.5;
}

/* ── Pulse strip ──────────────────────────────────────────────────────────── */

/*
  Ties the trainer back to the site's core "see rhythm and pitch as dots"
  metaphor, in two states sharing one visual grammar. Before an answer, every
  dot sits at the same neutral baseline and only lights up in time with the
  note it represents — timing is safe to show because the audio engine keeps
  it answer-independent by design (see Audio Rules), but pitch is never safe
  before the answer, since pitch *is* the answer here. After an answer, the
  strip re-renders with real heights: nothing left to protect, so the dots
  can finally show the relationship the words next to them are describing.
  Purely decorative either way — the question and its explanation are fully
  conveyed by text and audio without it — so it carries aria-hidden rather
  than duplicating information into the accessibility tree.
*/
.ear-dot-row {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: 14px;
  min-height: 96px;
  padding-bottom: 4px;
  margin-bottom: 4px;
}

.ear-dot {
  --ear-dot-size: 14px;
  --ear-dot-lift: 9px;
  width: var(--ear-dot-size);
  height: var(--ear-dot-size);
  border-radius: 50%;
  background: radial-gradient(circle at 28% 22%, rgba(253, 233, 192, 0.9), rgba(217, 162, 27, 0.85) 72%);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.16);
  transform: translateY(calc(-1 * var(--ear-dot-lift)));
  transition: transform 0.35s ease-out, box-shadow 0.12s ease-out, background 0.12s ease-out;
}

/* Simultaneous notes (a chord) sit closer together than a left-to-right
   sequence, so "these happened at once" reads without any dot needing a
   different height, color, or size to say so. */
.ear-dot.is-clustered {
  margin-left: -4px;
  margin-right: -4px;
}

/* A real gap before a new passage starts, reused for two things: separating
   Melody Memory's two phrases in one continuous row (so they read as two
   passages, not one run of notes), and marking where a wrong-answer
   comparison group begins (there, paired with is-chosen-group's colour —
   position carries the primary information, colour is a supplementary
   cue, not the only one). */
.ear-dot.is-group-start {
  margin-left: 18px;
}

.ear-dot.is-chosen-group {
  background: radial-gradient(circle at 28% 22%, rgba(255, 214, 214, 0.9), rgba(224, 110, 110, 0.85) 72%);
}

.ear-dot.is-chosen-group.is-active {
  background: radial-gradient(circle at 28% 22%, #ffe6e6, rgba(230, 110, 110, 0.98) 74%);
  box-shadow:
    0 0 0 4px rgba(230, 110, 110, 0.22),
    0 0 18px rgba(230, 110, 110, 0.45);
}

/* Marks "you picked this position" on a single dot within one row, where a
   second group would have nothing new to show (the wrong answer is a wrong
   position, not a different pitch). Dashed, not just coloured, matching the
   dashed-border convention already used for a wrong answer button. */
.ear-dot.is-marked-chosen {
  box-shadow: 0 0 0 2px rgba(230, 110, 110, 0.9);
  outline: 2px dashed rgba(230, 110, 110, 0.85);
  outline-offset: 3px;
}

.ear-dot.is-active {
  background: radial-gradient(circle at 28% 22%, #fff3d6, rgba(255, 179, 71, 0.98) 74%);
  box-shadow:
    0 0 0 4px rgba(255, 179, 71, 0.22),
    0 0 18px rgba(255, 179, 71, 0.45);
  transform: translateY(calc(-1 * var(--ear-dot-lift))) scale(1.28);
  transition: transform 0.05s ease-out, box-shadow 0.05s ease-out, background 0.05s ease-out;
}

/* The post-answer reveal: heights just changed, so give it a beat longer
   than the pulse-in/out timing to read as "settling into place" rather than
   another flicker. */
.ear-dot.is-revealed {
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.12s ease-out, background 0.12s ease-out;
}

@media (prefers-reduced-motion: reduce) {
  .ear-dot {
    transition: none;
  }
}

/* ── Playback ─────────────────────────────────────────────────────────────── */

.ear-playback {
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
  margin-bottom: 20px;
}

.ear-play-button {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  width: auto;
  min-height: 60px;
  padding: 0 28px;
  border-radius: 999px;
  border: 1px solid rgba(240, 200, 100, 0.6);
  background: linear-gradient(180deg, rgba(240, 200, 100, 0.26), rgba(240, 200, 100, 0.14));
  color: inherit;
  font-size: 1.05rem;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.14s ease, box-shadow 0.14s ease;
}

.ear-play-button:hover:not(:disabled),
.ear-play-button:focus-visible {
  transform: translateY(-1px);
  box-shadow: 0 8px 22px rgba(240, 200, 100, 0.18);
}

.ear-play-button:disabled {
  opacity: 0.6;
  cursor: default;
}

.ear-play-icon {
  width: 0;
  height: 0;
  border-left: 15px solid currentColor;
  border-top: 9px solid transparent;
  border-bottom: 9px solid transparent;
}

.ear-play-button.is-playing .ear-play-icon {
  border: 0;
  width: 14px;
  height: 15px;
  background:
    linear-gradient(currentColor, currentColor) left / 4px 100% no-repeat,
    linear-gradient(currentColor, currentColor) right / 4px 100% no-repeat;
}

.ear-playback-meta {
  display: flex;
  flex-direction: column;
  gap: 3px;
  font-size: 0.86rem;
  color: var(--muted, rgba(230, 238, 250, 0.7));
}

.ear-direction-tag {
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  font-size: 0.75rem;
}

/* ── Interval reference ───────────────────────────────────────────────────── */

/*
  Sits above the exercise, so the rule goes underneath it — it closes off the
  reference section rather than hanging under the intro copy.
*/
.ear-explorer {
  margin: 18px 0 20px;
  padding-bottom: 20px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.10);
}

.ear-explorer-kicker {
  margin: 0 0 4px;
  color: var(--tools-muted);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.ear-explorer-heading {
  margin: 0 0 6px;
  font-size: 1rem;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.ear-explorer-copy {
  margin: 0 0 12px;
  color: var(--tools-muted);
  font-size: 0.9rem;
  line-height: 1.5;
}

.ear-mode-note {
  margin: 8px 0 0;
  color: var(--tools-muted);
  font-size: 0.85rem;
  line-height: 1.5;
  letter-spacing: 0;
  word-spacing: normal;
}

.ear-explorer-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 8px;
}

.ear-explorer-item {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  position: relative;
  padding: 9px 11px;
  border-radius: 11px;
  border: 1px solid rgba(255, 255, 255, 0.13);
  background: rgba(255, 255, 255, 0.04);
  color: inherit;
  text-align: left;
  cursor: pointer;
  transition: border-color 0.14s ease, background 0.14s ease;
}

.ear-explorer-item:hover,
.ear-explorer-item:focus-visible {
  border-color: rgba(240, 200, 100, 0.6);
  background: rgba(255, 255, 255, 0.09);
}

.ear-explorer-name {
  font-size: 0.92rem;
  font-weight: 650;
}

.ear-explorer-width {
  color: var(--tools-muted);
  font-size: 0.76rem;
}

/*
  Pool membership is a check glyph plus the button's accessible name, so the
  brighter border is reinforcement rather than the only signal.
*/
.ear-explorer-mark {
  position: absolute;
  top: 7px;
  right: 9px;
  color: rgba(240, 200, 100, 0.95);
  font-size: 0.8rem;
  font-weight: 800;
}

.ear-explorer-item.is-in-pool {
  border-color: rgba(240, 200, 100, 0.34);
  background: rgba(240, 200, 100, 0.07);
}

.ear-explorer-item.is-playing {
  border-color: rgba(90, 170, 220, 0.85);
  background: rgba(90, 170, 220, 0.16);
}

/* ── Answers ──────────────────────────────────────────────────────────────── */

.ear-answers {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}

.ear-answer {
  width: 100%;
  min-height: 56px;
  padding: 12px 14px;
  border-radius: 13px;
  border: 1px solid rgba(255, 255, 255, 0.16);
  background: rgba(255, 255, 255, 0.06);
  color: inherit;
  font-size: 1rem;
  font-weight: 650;
  cursor: pointer;
  transition: border-color 0.14s ease, background 0.14s ease, transform 0.14s ease;
}

.ear-answer:hover:not(:disabled),
.ear-answer:focus-visible {
  border-color: rgba(240, 200, 100, 0.6);
  background: rgba(255, 255, 255, 0.10);
}

.ear-answer:disabled {
  cursor: default;
}

/*
  Answer state is never colour-only: correct gains a check glyph and a solid
  border, the wrong pick gains a cross glyph and a dashed border.
*/
.ear-answer-mark {
  display: inline-block;
  width: 1.3em;
  font-weight: 800;
}

.ear-answer.is-correct {
  border-color: rgba(120, 210, 150, 0.85);
  border-style: solid;
  border-width: 2px;
  background: rgba(120, 210, 150, 0.16);
}

.ear-answer.is-wrong {
  border-color: rgba(240, 130, 130, 0.85);
  border-style: dashed;
  border-width: 2px;
  background: rgba(240, 130, 130, 0.12);
}

.ear-answer.is-muted {
  opacity: 0.5;
}

/*
  Lights the button whose interval is sounding during "Compare the two", so the
  sound is tied to a name. It has to beat .is-muted's fade, since the interval
  you picked wrongly is muted the moment the answer is marked.
*/
.ear-answer.is-sounding {
  opacity: 1;
  box-shadow: 0 0 0 2px rgba(90, 170, 220, 0.85) inset;
  background: rgba(90, 170, 220, 0.18);
}

/* ── Feedback ─────────────────────────────────────────────────────────────── */

.ear-feedback {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  min-height: 64px;
  padding: 14px 16px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  background: rgba(255, 255, 255, 0.04);
  margin-bottom: 18px;
}

.ear-feedback.is-correct {
  border-color: rgba(120, 210, 150, 0.6);
  background: rgba(120, 210, 150, 0.10);
}

.ear-feedback.is-wrong {
  border-color: rgba(240, 130, 130, 0.6);
  border-style: dashed;
  background: rgba(240, 130, 130, 0.09);
}

.ear-feedback-mark {
  font-size: 1.35rem;
  font-weight: 800;
  line-height: 1.2;
  min-width: 1.2em;
}

.ear-feedback-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ear-feedback-verdict {
  font-weight: 700;
}

.ear-feedback-detail {
  font-size: 0.92rem;
  color: var(--muted, rgba(230, 238, 250, 0.76));
  line-height: 1.5;
}

/* ── Actions and settings ─────────────────────────────────────────────────── */

.ear-stage-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
}

.ear-action {
  width: auto;
  min-height: 46px;
  padding: 0 20px;
}

/*
  .btn-ghost sets `display`, which outranks the UA `[hidden]` rule, so the
  attribute alone leaves "Compare the two" on screen before an answer exists.
*/
.ear-action[hidden] {
  display: none !important;
}

.ear-soundcheck {
  width: auto;
  flex: 0 0 auto;
  min-height: 48px;
  padding: 0 16px;
  white-space: nowrap;
}

.ear-setup-note,
.ear-stage-note {
  margin: 14px 0 0;
}

/* ── Summary ──────────────────────────────────────────────────────────────── */

.ear-summary-headline {
  font-size: 1.08rem;
  font-weight: 700;
  margin: 16px 0 14px;
  line-height: 1.5;
}

.ear-summary-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px;
  margin-bottom: 18px;
}

.ear-stat {
  padding: 12px 14px;
  border-radius: 12px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(255, 255, 255, 0.10);
}

.ear-stat-value {
  display: block;
  font-size: 1.4rem;
  font-weight: 800;
}

.ear-stat-label {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--muted, rgba(230, 238, 250, 0.62));
  margin-top: 2px;
}

.ear-summary-block {
  margin-bottom: 16px;
}

.ear-summary-block h3 {
  font-size: 0.94rem;
  margin: 0 0 8px;
}

.ear-summary-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ear-summary-list li {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  font-size: 0.9rem;
}

.ear-summary-list .ear-summary-value {
  font-variant-numeric: tabular-nums;
  font-weight: 700;
  white-space: nowrap;
}

.ear-summary-mistakes-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.ear-summary-mistake {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 9px 12px;
  border-radius: 10px;
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
}

.ear-summary-mistake-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.ear-summary-mistake-verdict {
  font-size: 0.9rem;
  font-weight: 700;
}

.ear-summary-mistake-detail {
  font-size: 0.82rem;
  color: var(--muted, rgba(230, 238, 250, 0.62));
  line-height: 1.4;
}

.ear-summary-mistake-replay {
  flex-shrink: 0;
  width: auto;
  padding: 6px 14px;
  font-size: 0.85rem;
}

.ear-summary-mistake-replay.is-playing {
  border-color: rgba(240, 200, 100, 0.7);
  color: rgba(240, 200, 100, 0.95);
}

@media (max-width: 480px) {
  .ear-summary-mistake {
    flex-direction: column;
    align-items: stretch;
  }

  .ear-summary-mistake-replay {
    align-self: flex-start;
  }
}

.ear-summary-suggestion {
  margin: 0 0 18px;
  padding: 12px 14px;
  border-radius: 12px;
  border-left: 3px solid rgba(240, 200, 100, 0.8);
  background: rgba(240, 200, 100, 0.08);
  line-height: 1.5;
}

.ear-seed-note {
  margin: 16px 0 0;
  font-size: 0.76rem;
  color: var(--muted, rgba(230, 238, 250, 0.45));
  font-variant-numeric: tabular-nums;
}

/* ── Embed mode (?embed=1, launched from the Practice Tools hub) ──────────── */

.dotbeat-embed-toolbar {
  display: none;
  position: fixed;
  top: 12px;
  right: 12px;
  z-index: 200;
  margin: 0;
  padding: 0;
  background: transparent;
}

html.dotbeat-embed .dotbeat-embed-toolbar {
  display: flex;
}

.dotbeat-embed-close {
  width: auto !important;
  min-height: 44px;
  padding: 0 20px;
  font-weight: 800;
  border-radius: 12px;
  box-shadow:
    0 2px 12px rgba(4, 10, 24, 0.45),
    0 0 0 1px rgba(255, 255, 255, 0.1);
}

html.dotbeat-embed .nav,
html.dotbeat-embed .ear-hero,
html.dotbeat-embed .siteFooter {
  display: none !important;
}

html.dotbeat-embed .ear-wrap {
  padding: 52px 16px 24px;
  box-sizing: border-box;
}

/* ── Responsive ───────────────────────────────────────────────────────────── */

@media (max-width: 700px) {
  .tool-card.tool-card--utility {
    padding: 18px 16px 16px;
  }

  .tool-card-head {
    flex-direction: column;
    align-items: stretch;
  }

  .tool-chip {
    align-self: flex-start;
  }

  .ear-setup-start {
    width: 100%;
  }

  .ear-answers {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .ear-play-button {
    width: 100%;
    justify-content: center;
  }

  .ear-stage-actions .ear-action {
    flex: 1 1 auto;
  }

  .ear-summary-list li {
    flex-direction: column;
    gap: 2px;
  }
}

@media (max-width: 380px) {
  /*
    Stay at two columns even here. Interval names are short enough to fit, and
    a full pool is up to 13 buttons — one column would turn the answer grid
    into a scroll, pushing choices off screen while the sound is still fresh.
  */
  .ear-answer {
    min-height: 50px;
    padding: 10px;
    font-size: 0.94rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ear-exercise-choice,
  .ear-play-button,
  .ear-answer {
    transition: none;
  }

  .ear-play-button:hover:not(:disabled),
  .ear-play-button:focus-visible {
    transform: none;
  }
}
