:root {
  --bg: #000000;
  --card: #161616;
  --card-2: #1f1f1f;
  --card-3: #2a2a2a;
  --fg: #ffffff;
  --muted: #8a8a8a;
  --accent: #d5ff3c;
  --accent-soft: rgba(213, 255, 60, 0.15);
  /* Accent for text/icons/thin strokes. In dark theme = lime (great contrast on
     dark bg). In light theme overridden to a darker chartreuse — lime-700 —
     because pure lime is invisible on white. Keeps brand feel without losing
     legibility. */
  --accent-text: var(--accent);
  --border: #262626;
  --radius-lg: 28px;
  --radius-md: 20px;
  --radius-sm: 14px;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: 'Google Sans', -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
  -webkit-tap-highlight-color: transparent;
  overscroll-behavior: none;
  font-feature-settings: 'tnum' on;
  height: 100%;
}

body {
  height: 100dvh;
  height: 100vh; /* fallback for older browsers */
  overflow: hidden;
}

button, input, select, textarea {
  font-family: inherit;
}

.app {
  max-width: 520px;
  margin: 0 auto;
  height: 100%;
  display: flex;
  flex-direction: column;
  padding:
    max(8px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    0
    max(16px, env(safe-area-inset-left));
  box-sizing: border-box;
  overflow: hidden;
}

/* Topbar + tab-bar are fixed-size; tab-views stretches between them.
   tab-views deliberately keeps overflow visible so the play-btn's lime
   glow can extend past its edges into .app's safe-area padding before
   .app's overflow:hidden clips at the viewport. */
.app > .topbar { flex: 0 0 auto; }
.app > .tab-views { flex: 1 1 auto; min-height: 0; }
.app > .tab-bar { flex: 0 0 auto; }

/* Tab views — only active one is visible. Each handles its own layout. */
.tab-view {
  display: none;
  height: 100%;
  flex-direction: column;
  gap: 10px;
}
.tab-view.active { display: flex; }

/* Метроном tab: no internal scroll — children are flex-shrink: 0 and the
   play-row's auto margins absorb extra space. overflow stays visible so
   shadows from play-btn can extend rightward (would otherwise be clipped
   right at the button's edge). */
#tab-metronome { padding-bottom: 8px; }
#tab-metronome > * { flex-shrink: 0; }
/* Both auto margins so the play-stack (Start row + active-trainer tags)
   sits in the middle of the remaining vertical space — equal gap above
   and below the entire group. Adapts to screen height automatically:
   tall phones get more breathing room, short ones collapse the gap. */
#tab-metronome > .play-stack { margin-top: auto; margin-bottom: auto; }

/* Training & Settings tabs: scroll inside the tab area */
#tab-training,
#tab-settings {
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding-bottom: 16px;
}
#tab-training > *,
#tab-settings > * { flex-shrink: 0; }

.tab-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  margin-bottom: 6px;
}

.tab-section-title {
  margin: 6px 4px 4px;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Topbar */
.topbar {
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 6px 4px 8px;
}

.page-title {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--fg);
}

/* Bottom tab bar */
.tab-bar {
  display: flex;
  border-top: 1px solid var(--border);
  background: var(--bg);
  padding: 6px 0 max(8px, env(safe-area-inset-bottom));
  margin: 0 -16px;
}

.tab-bar-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 6px 4px;
  background: none;
  border: none;
  cursor: pointer;
  color: var(--muted);
  font-family: inherit;
  font-size: 11px;
  font-weight: 500;
  transition: color 0.15s ease;
}

.tab-bar-item svg {
  width: 22px;
  height: 22px;
}

.tab-bar-item.active { color: var(--accent); }
.tab-bar-item:active { transform: scale(0.95); }

.icon-btn {
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: var(--card);
  color: var(--fg);
  border: none;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.icon-btn:active { transform: scale(0.94); background: var(--card-2); }

/* BPM card */
.bpm-card {
  position: relative;
  background: var(--card);
  border-radius: var(--radius-lg);
  padding: 16px 16px 14px;
  display: flex;
  flex-direction: column;
  gap: 12px;
  /* overflow:hidden so the easter-egg image is clipped by the card's
     rounded corners. */
  overflow: hidden;
}

/* Easter egg — fades in over the BPM/wheel area as the wheel scrolls
   from 300 to 320 BPM (opacity 0→1). Position is fixed within the card,
   never moves. Top-anchored with height 60% so the bottom of the image
   roughly aligns with the bottom of the BPM wheel — covers the BPM
   number + corner icons but stays out of the +/- buttons and TAP TEMPO.
   pointer-events: none lets the wheel be dragged through the image.
   z-index above icon buttons so the image visually sits on top. */
.bpm-easter {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  width: 100%;
  height: auto;
  opacity: 0;
  pointer-events: none;
  z-index: 5;
  user-select: none;
  -webkit-user-drag: none;
}

.bpm-icon-btn {
  position: absolute;
  top: 12px;
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--card-2);
  color: var(--muted);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.06s ease;
  z-index: 2;
}

.bpm-icon-btn--left { left: 12px; }
.bpm-icon-btn--right { right: 12px; }
.bpm-icon-btn svg { width: 18px; height: 18px; }
.bpm-icon-btn:hover { color: var(--fg); }
.bpm-icon-btn:active { transform: scale(0.94); background: var(--card-3); }

/* 3-column grid so the BPM number lands on the card's actual horizontal
   center: empty 1fr on the left mirrors the "BPM" label on the right.
   With flex+gap centering, the input+label group is centered as a unit,
   which visually shifts the number left of the card center. */
.bpm-display {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: baseline;
  column-gap: 10px;
}

#bpm-input { grid-column: 2; }
.bpm-label { grid-column: 3; justify-self: start; }

#bpm-input {
  width: 180px;
  font-size: 76px;
  font-weight: 700;
  line-height: 1;
  text-align: center;
  background: transparent;
  color: var(--fg);
  border: none;
  outline: none;
  padding: 0;
  font-variant-numeric: tabular-nums;
  -moz-appearance: textfield;
  letter-spacing: -0.02em;
}

#bpm-input::-webkit-outer-spin-button,
#bpm-input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.bpm-label {
  font-size: 16px;
  color: var(--muted);
  letter-spacing: 0.12em;
  font-weight: 500;
}

/* BPM wheel — wrap holds non-scrolling overlays (center line, edge fades);
   inner .bpm-wheel is the actual scroll container. Center line and fade
   must live OUTSIDE the scroll container, otherwise they scroll with the
   ticks and disappear off-viewport. */
.bpm-wheel-wrap {
  position: relative;
  width: 100%;
  height: 72px;
}

.bpm-wheel {
  height: 100%;
  width: 100%;
  overflow-x: scroll;
  overflow-y: hidden;
  scrollbar-width: none;
  -ms-overflow-style: none;
  touch-action: pan-x;
  cursor: grab;
  /* Edge fade via mask — clips visible viewport, not scroll content,
     so the fade stays at the edges as ticks scroll past. */
  -webkit-mask-image: linear-gradient(to right, transparent 0, black 96px, black calc(100% - 96px), transparent 100%);
          mask-image: linear-gradient(to right, transparent 0, black 96px, black calc(100% - 96px), transparent 100%);
}

.bpm-wheel::-webkit-scrollbar { display: none; }

.bpm-wheel.dragging { cursor: grabbing; }

.wheel-track {
  display: flex;
  align-items: center;
  height: 100%;
  gap: 8px;
  /* padding-left/right set inline by JS so first/last tick can reach center */
}

.wheel-tick {
  flex: 0 0 2px;
  height: 56px;
  background: rgba(255, 255, 255, 0.28);
  border-radius: 1px;
}

/* Trailing scroll spacer (= halfW) so the last BPM tick can reach center
   on Safari, where padding-right on a flex scroll container is not always
   counted into scrollWidth. Real DOM child, width set inline in JS. */
.wheel-spacer { height: 1px; pointer-events: none; }

.wheel-center {
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--accent);
  border-radius: 2px;
  transform: translateX(-50%);
  pointer-events: none;
  box-shadow: 0 0 18px rgba(213, 255, 60, 0.8);
  z-index: 3;
}

.bpm-buttons {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.bpm-step {
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 11px;
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s, transform 0.06s;
}

.bpm-step:active { transform: scale(0.96); background: var(--card-3); }

.tap-btn {
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.16em;
  cursor: pointer;
  transition: background 0.15s, transform 0.06s;
}

.tap-btn:active { transform: scale(0.98); }

.tap-btn.pulse {
  animation: tapPulse 0.2s ease;
}

@keyframes tapPulse {
  0% { background: var(--accent); color: #000; transform: scale(1.02); }
  100% { background: var(--card-2); color: var(--fg); transform: scale(1); }
}

/* Mini cards row */
.row-cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.mini-card {
  background: var(--card);
  border: none;
  border-radius: var(--radius-md);
  padding: 12px 14px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  min-height: 76px;
  color: var(--fg);
  transition: background 0.15s, transform 0.06s;
}

.mini-card:active { transform: scale(0.98); background: var(--card-2); }

.time-sig-display {
  display: flex;
  align-items: baseline;
  gap: 6px;
  font-size: 38px;
  font-weight: 700;
  line-height: 1;
}

.time-sig-display .slash {
  color: var(--muted);
  font-weight: 400;
  font-size: 32px;
}

.sub-display {
  font-size: 38px;
  line-height: 1;
  color: var(--accent);
  font-weight: 500;
}

.mini-card-label {
  font-size: 12px;
  color: var(--muted);
  letter-spacing: 0.04em;
}

/* Beat indicator — Soundbrenner-style tappable stacks */
.beat-card {
  background: var(--card);
  border-radius: var(--radius-md);
  padding: 12px 12px;
  display: flex;
  justify-content: center;
}

.beat-indicator {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}

.beat-stack {
  width: 44px;
  height: 72px;
  background: var(--card-2);
  border: none;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 8px 0;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.12s ease, transform 0.06s ease, box-shadow 0.12s ease;
}

.beat-stack:active { transform: scale(0.95); }

.beat-stack .bdot {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: var(--card-3);
  transition: background 0.06s ease, box-shadow 0.06s ease, transform 0.06s ease;
}

/* Lit pattern by beat type (top → bottom intensity, like Soundbrenner) */
.beat-stack[data-type="accent"] .bdot { background: var(--accent); }
.beat-stack[data-type="beat"]   .bdot:nth-child(2),
.beat-stack[data-type="beat"]   .bdot:nth-child(3) { background: var(--fg); }
.beat-stack[data-type="soft"]   .bdot:nth-child(3) { background: var(--muted); }
/* mute = all dots dim */
.beat-stack[data-type="mute"] { opacity: 0.45; }

/* Active beat (currently playing) — flash background and slightly bump dots */
.beat-stack.active {
  background: var(--card-3);
}
.beat-stack.active[data-type="accent"] {
  background: var(--accent-soft);
}
.beat-stack.active .bdot {
  transform: scale(1.15);
}
.beat-stack.active[data-type="accent"] .bdot {
  box-shadow: 0 0 10px rgba(213, 255, 60, 0.7);
}

/* play-stack wraps the Start row plus the active-trainer tag list so
   they're centered together by the auto margins on #tab-metronome. */
.play-stack {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Active trainer tags — one pill per enabled trainer, with a × to
   disable. Hidden when none are active. Centered horizontally; wraps
   if multiple trainers are on at once. */
.active-trainers {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
}

.active-trainers:empty { display: none; }

.trainer-tag {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 6px 6px 14px;
  background: var(--card);
  color: var(--fg);
  border-radius: 100px;
  font-size: 13px;
  font-weight: 500;
}

.trainer-tag-close {
  width: 22px;
  height: 22px;
  border: none;
  border-radius: 50%;
  background: var(--card-2);
  color: var(--muted);
  cursor: pointer;
  display: grid;
  place-items: center;
  font-family: inherit;
  padding: 0;
  transition: background 0.15s ease, color 0.15s ease, transform 0.06s ease;
}

.trainer-tag-close:hover { color: var(--fg); }
.trainer-tag-close:active { transform: scale(0.92); background: var(--card-3); }
.trainer-tag-close svg { width: 12px; height: 12px; }

/* Play row — count-in pill sits BEHIND the main Start pill (same shape,
   only the leftmost ~--play-h is visible). Both share grid-area "row"
   so they stack; play-btn has margin-left so count-in's icon area peeks
   out, and z-index keeps Start on top.
   --play-h drives both heights so the visible shapes match pixel-perfect. */
.play-row {
  --play-h: 60px;
  display: grid;
  grid-template-areas: "row";
  height: var(--play-h);
}

.countin-btn {
  grid-area: row;
  width: 100%;
  height: 100%;
  border: none;
  border-radius: 100px;
  background: var(--card);
  color: var(--fg);
  display: flex;
  align-items: center;
  justify-content: flex-start;
  padding: 0;
  cursor: pointer;
  font-family: inherit;
  transition: background 0.15s ease, color 0.15s ease, transform 0.06s ease;
  z-index: 1;
}

/* Fixed-width left section so the icon (and the armed number) always
   sit at the same x position regardless of which is shown. Width matches
   --play-h so the icon visually centers in what looks like the round
   "tab" sticking out from under the Start button. */
.countin-btn-content {
  width: var(--play-h);
  height: 100%;
  display: grid;
  place-items: center;
  flex-shrink: 0;
}

.countin-btn svg { width: 22px; height: 22px; }
.countin-btn-num {
  display: none;
  font-size: 22px;
  font-weight: 700;
  line-height: 1;
  font-family: inherit;
}

.countin-btn:hover { color: var(--accent); }
.countin-btn:active { transform: scale(0.99); background: var(--card-2); }
.countin-btn:disabled { opacity: 0.5; cursor: default; }

/* Armed state — count-in is set, waiting for the user to press Start.
   White pill with the chosen seconds shown where the icon was. */
.countin-btn.armed { background: var(--fg); color: var(--bg); }
.countin-btn.armed svg { display: none; }
.countin-btn.armed .countin-btn-num { display: block; }
.countin-btn.armed:hover { color: var(--bg); }

/* Play button — pill, big yellow, sits on top of count-in.
   margin-left = visible count-in width + a small "lip" so the rounded
   countin tab is fully visible to the left of Start. */
.play-btn {
  grid-area: row;
  margin-left: calc(var(--play-h) + 10px);
  height: var(--play-h);
  padding: 0 24px;
  z-index: 2;
  border: none;
  border-radius: 100px;
  background: var(--accent);
  color: #000;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: 0.18em;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  box-shadow: 0 8px 32px rgba(213, 255, 60, 0.25);
  transition: transform 0.08s ease, box-shadow 0.2s ease, background 0.2s;
}

.play-btn:active { transform: scale(0.98); }

.play-btn.playing {
  background: var(--fg);
  color: #000;
  box-shadow: 0 8px 32px rgba(255, 255, 255, 0.2);
}

/* Outline in --bg color around Stop, but ONLY when count-in is also
   armed (i.e. both pills are white). Otherwise the two white pills run
   into each other where the count-in tab pokes out. The outline is
   invisible against bg on the other three sides. */
.countin-btn.armed + .play-btn.playing {
  box-shadow:
    0 0 0 4px var(--bg),
    0 8px 32px rgba(255, 255, 255, 0.2);
}

.play-icon { font-size: 24px; }

.hint {
  text-align: center;
  color: var(--muted);
  font-size: 12px;
  margin: 12px 0 0;
}

/* Mic live offset display (Метроном tab) */
.mic-live:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  padding: 10px 0 0;
}

.mic-live-offset {
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
  transition: color 0.1s ease;
}

.mic-live-quality {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.mic-live[data-quality="perfect"] .mic-live-offset { color: #4ade80; }
.mic-live[data-quality="good"]    .mic-live-offset { color: var(--accent); }
.mic-live[data-quality="ok"]      .mic-live-offset { color: #f59e0b; }
.mic-live[data-quality="miss"]    .mic-live-offset { color: #ef4444; }

/* Hide keyboard shortcut hint on touch-only devices */
@media (hover: none) and (pointer: coarse) {
  .hint { display: none; }
}

/* Details panels (in tab views) */
details {
  background: var(--card-2);
  border-radius: var(--radius-md);
  overflow: hidden;
}

details > summary {
  cursor: pointer;
  padding: 16px 44px 16px 18px;
  font-weight: 500;
  font-size: 15px;
  list-style: none;
  position: relative;
  user-select: none;
  display: flex;
  align-items: center;
  gap: 12px;
}

/* iOS-style grouped settings: multiple <details> share one rounded card,
   with a thin separator between rows (drawn from after the icon column
   so it doesn't slice through the icons). */
.settings-group {
  background: var(--card-2);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.settings-group > details {
  background: transparent;
  border-radius: 0;
}

.settings-group > details + details > summary::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50px;
  right: 18px;
  height: 1px;
  background: var(--card-3);
}

.settings-icon {
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  color: var(--fg);
}

details > summary::-webkit-details-marker { display: none; }

details > summary::after {
  content: '';
  position: absolute;
  right: 20px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--muted);
  border-bottom: 2px solid var(--muted);
  transform: translateY(-70%) rotate(45deg);
  transition: transform 0.2s ease;
}

details[open] > summary::after { transform: translateY(-30%) rotate(225deg); }

details > *:not(summary) { padding-left: 18px; padding-right: 18px; }
details > *:last-child { padding-bottom: 16px; }

.vol {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-bottom: 12px;
}

.vol label {
  font-size: 13px;
  color: var(--muted);
  display: flex;
  justify-content: space-between;
}

.vol input[type="range"] {
  width: 100%;
  -webkit-appearance: none;
  appearance: none;
  height: 22px;
  background: transparent;
}

.vol input[type="range"]::-webkit-slider-runnable-track {
  height: 4px;
  background: var(--card-3);
  border-radius: 2px;
}
.vol input[type="range"]::-moz-range-track {
  height: 4px;
  background: var(--card-3);
  border-radius: 2px;
}
.vol input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
  margin-top: -7px;
  border: none;
}
.vol input[type="range"]::-moz-range-thumb {
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--accent);
  border: none;
}

.toggle {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 6px 0 14px;
  font-size: 15px;
  cursor: pointer;
}

.toggle input { width: 20px; height: 20px; accent-color: var(--accent); }

.bt-detected-line code {
  font-family: ui-monospace, SFMono-Regular, monospace;
  font-size: 11px;
  background: var(--card-3);
  padding: 1px 5px;
  border-radius: 4px;
}

.disabled-control {
  opacity: 0.5;
  pointer-events: none;
}

.grid2 {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
}

.grid2 label,
.row-inline label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 13px;
  color: var(--muted);
}

.grid2 input,
.row-inline select,
.user-presets input {
  background: var(--card-3);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px;
  font-size: 16px;
  -moz-appearance: textfield;
}

.grid2 input::-webkit-outer-spin-button,
.grid2 input::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

.row-inline {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.muted { color: var(--muted); }
.small { font-size: 12px; }

.presets {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 14px;
}

.preset {
  flex: 0 1 auto;
  background: var(--card-3);
  color: var(--fg);
  border: none;
  border-radius: 999px;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 500;
  cursor: pointer;
  transition: background 0.15s;
}

.preset:active { background: var(--accent); color: #000; }

.preset.is-active {
  background: var(--accent);
  color: #000;
  box-shadow: 0 0 12px rgba(213, 255, 60, 0.4);
}

.preset-row {
  display: flex;
  gap: 4px;
  flex: 0 1 auto;
}

.preset-del {
  background: var(--card-3);
  color: var(--muted);
  border: none;
  border-radius: 999px;
  padding: 10px 12px;
  font-size: 12px;
  cursor: pointer;
}

.preset-del:hover { color: var(--accent); }

.user-presets {
  display: flex;
  gap: 8px;
  margin-bottom: 12px;
}

.user-presets input { flex: 1; }

#preset-save {
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px 18px;
  font-weight: 600;
  cursor: pointer;
}

/* Modals (bottom sheets) */
.modal {
  position: fixed;
  inset: 0;
  z-index: 110;
  display: none;
}

.modal.open {
  display: block;
}

.modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0,0,0,0.55);
  animation: fadeIn 0.2s ease;
}

.sheet {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  background: var(--card);
  border-radius: 28px 28px 0 0;
  padding: 8px 20px calc(28px + env(safe-area-inset-bottom));
  animation: slideUp 0.28s cubic-bezier(0.32, 0.72, 0.24, 1);
  max-height: 86vh;
  overflow-y: auto;
}

@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}

@keyframes slideUp {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}

.sheet-handle {
  width: 44px;
  height: 5px;
  border-radius: 4px;
  background: var(--card-3);
  margin: 8px auto 16px;
}

.sheet h3 {
  margin: 0 0 16px;
  font-size: 22px;
  font-weight: 700;
}

.sub-options {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.sub-option {
  display: grid;
  grid-template-columns: 64px 1fr;
  grid-template-rows: auto auto;
  align-items: center;
  gap: 0 16px;
  padding: 16px 18px;
  background: var(--card-2);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  color: var(--fg);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, transform 0.06s;
  text-align: left;
}

.sub-option:active { transform: scale(0.99); }

.sub-option.active {
  background: var(--accent-soft);
  border-color: var(--accent);
}

.sub-option .sub-glyph {
  grid-row: 1 / 3;
  font-size: 38px;
  line-height: 1;
  color: var(--accent);
  text-align: center;
  font-weight: 500;
}

.sub-option .sub-name {
  font-size: 17px;
  font-weight: 500;
}

.sub-option .sub-meta {
  font-size: 13px;
  color: var(--muted);
}

/* Time signature grid */
.time-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 8px;
}

.time-grid button {
  background: var(--card-2);
  color: var(--fg);
  border: 2px solid transparent;
  border-radius: var(--radius-sm);
  padding: 14px 8px;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
}

.time-grid button.active {
  background: var(--accent-soft);
  border-color: var(--accent);
  color: var(--accent);
}

.time-section-label {
  grid-column: 1 / -1;
  margin: 12px 0 4px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted);
}

/* Programs (training) */
/* Difficulty + duration pickers and the "Далее" button. Three columns,
   the first two flex (so labels can grow on long values like
   "Продвинутый") and "Далее" sits on the right at intrinsic width. */
.programs-picker {
  display: grid;
  grid-template-columns: 1fr 1fr auto;
  gap: 8px;
}

.programs-picker-btn {
  background: var(--card);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 14px 12px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.programs-picker-btn:active { transform: scale(0.97); background: var(--card-2); }

.programs-picker-text {
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.programs-picker-text.is-filled { color: var(--fg); }

.programs-picker-chevron {
  width: 14px;
  height: 14px;
  color: var(--muted);
  flex-shrink: 0;
}

.programs-picker-next {
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 14px 18px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 700;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease, opacity 0.15s ease;
}

.programs-picker-next:active:not(.is-disabled) { transform: scale(0.97); }

/* Visually disabled but still clickable — the click handler shows a
   toast instead of being blocked by the `disabled` attribute. */
.programs-picker-next.is-disabled {
  background: var(--card);
  color: var(--muted);
}

/* User-imported programs list — same row pattern as the saved-rhythms
   sheet: a wide load-button on the left + a square delete-button on
   the right. */
.user-programs-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 4px;
}

.user-program-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
}

.user-program-load {
  background: var(--card);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 14px 16px;
  font-family: inherit;
  cursor: pointer;
  text-align: left;
  display: flex;
  flex-direction: column;
  gap: 4px;
  transition: background 0.15s ease, transform 0.06s ease;
}

.user-program-load:active { transform: scale(0.98); background: var(--card-2); }

.user-program-name {
  font-size: 15px;
  font-weight: 600;
  color: var(--fg);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.user-program-duration {
  font-size: 12px;
  color: var(--muted);
}

.user-program-delete {
  background: var(--card);
  color: var(--muted);
  border: none;
  border-radius: var(--radius-md);
  width: 44px;
  height: 100%;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease, transform 0.06s ease;
}

.user-program-delete:active { transform: scale(0.94); background: var(--card-2); color: var(--fg); }
.user-program-delete svg { width: 18px; height: 18px; }

/* Difficulty/duration option list inside the bottom sheet — same look
   as the count-in / rhythm pickers. */
.program-picker-options {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin-top: 8px;
}

.program-picker-option {
  padding: 16px;
  border: none;
  border-radius: var(--radius-md);
  background: var(--card-2);
  color: var(--fg);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.program-picker-option:active { transform: scale(0.97); background: var(--card-3); }
.program-picker-option.is-active { background: var(--accent); color: #000; }

.programs-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 14px;
}

.program-action-btn {
  background: var(--card);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 14px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.program-action-btn:active { transform: scale(0.97); background: var(--card-2); }
.program-action-btn svg { width: 18px; height: 18px; }

/* Program preview sheet */
.program-preview-meta {
  margin: -8px 0 8px;
  font-size: 13px;
  color: var(--muted);
}

.program-preview-description {
  margin: 0 0 14px;
  padding: 10px 12px;
  background: var(--card-2);
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.45;
  color: var(--fg);
}

.program-preview-blocks {
  list-style: none;
  margin: 0 0 18px;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.program-preview-block {
  display: grid;
  grid-template-columns: 90px 1fr auto;
  align-items: baseline;
  gap: 10px;
  padding: 10px 12px;
  background: var(--card-2);
  border-radius: var(--radius-sm);
}

.program-preview-block-type {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--muted);
}

.program-preview-block-title {
  font-size: 14px;
  font-weight: 500;
  color: var(--fg);
}

.program-preview-block-meta {
  font-size: 12px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.program-start-btn {
  width: 100%;
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 16px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.06s ease, background 0.15s ease;
}

.program-start-btn:active { transform: scale(0.98); }

/* Program runner — full-screen overlay with block content */
.program-runner {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: none;
  background: var(--bg);
  flex-direction: column;
  padding:
    max(8px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    max(8px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
}

.program-runner.open {
  display: flex;
  animation: fadeIn 0.18s ease;
}

.runner-top {
  display: grid;
  grid-template-columns: 44px 1fr 44px;
  align-items: center;
  gap: 10px;
  padding: 4px 0 10px;
}

.runner-title-wrap {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.runner-program-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--fg);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

.runner-block-pos {
  font-size: 11px;
  color: var(--muted);
  letter-spacing: 0.04em;
}

.runner-spacer { width: 44px; }

.runner-content {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 8px 4px 16px;
}

.runner-block-type {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent-text);
  font-weight: 600;
}

.runner-block-title {
  margin: 0;
  font-size: 24px;
  font-weight: 700;
  color: var(--fg);
  text-align: center;
  line-height: 1.15;
}

.runner-exercise {
  width: 100%;
  display: flex;
  justify-content: center;
  margin: 4px 0;
}

.runner-exercise[data-kind="free"] { display: none; }

.runner-sticking {
  font-size: clamp(20px, 6vw, 32px);
  font-weight: 700;
  font-family: 'Google Sans', monospace;
  letter-spacing: 0.08em;
  color: var(--fg);
  background: var(--card);
  padding: 18px 22px;
  border-radius: var(--radius-md);
  text-align: center;
  white-space: pre-wrap;
}

/* Groove grid: hi-hat / snare / kick rows × N cells (8 or 16 per bar) */
.groove-grid {
  --cells: 8;
  display: flex;
  flex-direction: column;
  gap: 4px;
  background: var(--card);
  padding: 14px 14px 14px 12px;
  border-radius: var(--radius-md);
  width: 100%;
  max-width: 460px;
}

.groove-row {
  display: grid;
  grid-template-columns: 44px repeat(var(--cells), 1fr);
  gap: 3px;
  align-items: center;
}

.groove-label {
  font-size: 11px;
  color: var(--muted);
  text-transform: lowercase;
  text-align: right;
  padding-right: 6px;
}

.groove-cell {
  aspect-ratio: 1 / 1;
  display: grid;
  place-items: center;
  background: var(--card-2);
  border-radius: 6px;
  font-size: 14px;
  color: var(--muted);
  min-width: 0;
}

.groove-cell.beat { background: var(--card-3); }

.groove-cell.hit {
  background: var(--accent);
  color: #000;
  font-weight: 700;
}

.runner-reference {
  margin: -2px 0 0;
  font-size: 12px;
  color: var(--muted);
  text-align: center;
  font-style: italic;
}

.runner-meta {
  display: flex;
  gap: 18px;
  justify-content: center;
  padding: 4px 0;
}

.runner-meta-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 56px;
}

.runner-meta-label {
  font-size: 10px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.runner-meta-value {
  font-size: 18px;
  font-weight: 700;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

.runner-beat-indicator {
  margin: 2px 0;
}

.runner-notes {
  margin: 0;
  font-size: 13px;
  line-height: 1.45;
  color: var(--muted);
  text-align: center;
  max-width: 460px;
}

/* Footer: timer + progress + controls */
.runner-foot {
  flex: 0 0 auto;
  padding: 12px 0 4px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.runner-timer-row {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
}

.runner-timer {
  font-size: 32px;
  font-weight: 700;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.runner-timer[data-user-paced="true"] {
  font-size: 16px;
  color: var(--muted);
  font-weight: 500;
}

.runner-done-btn {
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 12px 22px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}

.runner-done-btn:active { transform: scale(0.98); }

.runner-progress {
  height: 4px;
  background: var(--card-2);
  border-radius: 2px;
  overflow: hidden;
}

.runner-progress-fill {
  height: 100%;
  background: var(--accent);
  width: 0%;
  transition: width 0.3s linear;
}

.runner-controls {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  padding: 4px 0;
}

.runner-ctrl-btn {
  height: 48px;
  background: var(--card);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background 0.15s ease, transform 0.06s ease;
}

.runner-ctrl-btn:active { transform: scale(0.97); background: var(--card-2); }
.runner-ctrl-btn:disabled { opacity: 0.35; pointer-events: none; }

.runner-play-btn {
  width: 80px;
  height: 80px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #000;
  display: grid;
  place-items: center;
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(213, 255, 60, 0.25);
  transition: transform 0.08s ease, background 0.2s ease, box-shadow 0.2s ease;
  justify-self: center;
}

.runner-play-btn:active { transform: scale(0.95); }
.runner-play-btn.playing { background: var(--fg); color: var(--bg); box-shadow: 0 6px 20px rgba(255, 255, 255, 0.15); }
[data-theme="light"] .runner-play-btn { box-shadow: none; }
[data-theme="light"] .runner-play-btn.playing { background: var(--fg); color: #fff; box-shadow: none; }

.runner-play-icon {
  font-size: 28px;
  line-height: 1;
  margin-left: 3px;
}
.runner-play-btn.playing .runner-play-icon { margin-left: 0; }

/* Block-transition overlay (between blocks) and program finish overlay.
   position: fixed (not absolute) so we cover the parent's safe-area padding too. */
.runner-transition,
.runner-finish {
  position: fixed;
  inset: 0;
  display: none;
  background: rgba(0, 0, 0, 0.65);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 140;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

.runner-transition.open,
.runner-finish.open {
  display: flex;
  animation: fadeIn 0.2s ease;
}

.runner-transition-card {
  background: var(--card);
  border-radius: var(--radius-lg);
  padding: 28px 24px;
  width: 100%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  text-align: center;
}

.runner-transition-prefix {
  margin: 0;
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted);
}

.runner-transition-title {
  margin: 0;
  font-size: 22px;
  font-weight: 700;
  color: var(--fg);
}

.runner-transition-meta {
  margin: 0 0 12px;
  font-size: 14px;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.runner-transition-btn {
  width: 100%;
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 14px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 700;
  cursor: pointer;
}

.runner-transition-btn:active { transform: scale(0.98); }

/* Footer: version + update button */
.footer-version {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  margin-top: 16px;
  padding-bottom: 4px;
}

.version-label {
  font-size: 12px;
  color: var(--muted);
}

.update-btn {
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--card);
  color: var(--muted);
  font-family: inherit;
  font-size: 12px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 0.15s ease, color 0.15s ease, background 0.15s ease;
}

.update-btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.update-btn:disabled {
  opacity: 0.5;
  cursor: default;
}

/* Toast */
.update-toast {
  position: fixed;
  bottom: 32px;
  left: 50%;
  transform: translateX(-50%) translateY(20px);
  background: var(--card);
  color: var(--fg);
  border: 1px solid var(--border);
  padding: 12px 22px;
  border-radius: 999px;
  font-size: 14px;
  font-family: inherit;
  z-index: 1000;
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease;
  white-space: nowrap;
  max-width: calc(100vw - 32px);
  overflow: hidden;
  text-overflow: ellipsis;
}

.update-toast.visible {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

/* ==================================================
   Rhythm builder ("Конструктор ритма")
   ================================================== */

/* Trainer-list entry — same visual weight as <summary> but tap-to-open
   instead of toggle. Sits inside the "Тренажёры" section alongside the
   regular details/summary trainers. */
.trainer-row {
  background: var(--card-2);
  border-radius: var(--radius-md);
  border: none;
  padding: 16px 18px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 500;
  color: var(--fg);
  cursor: pointer;
  text-align: left;
  position: relative;
  display: flex;
  align-items: center;
  transition: background 0.15s ease, transform 0.06s ease;
}

.trainer-row:active { transform: scale(0.99); background: var(--card-3); }

.trainer-row::after {
  content: '';
  position: absolute;
  right: 20px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-right: 2px solid var(--muted);
  border-top: 2px solid var(--muted);
  transform: translateY(-50%) rotate(45deg);
}

/* Editor — fullscreen overlay laid out as LANDSCAPE (meta | grid |
   actions). Mirrors the structural pattern of #flash-screen exactly:
   3-column grid container, rotates 90° clockwise on portrait phones
   so the user turns the phone 90° left to view horizontally. */
.rhythm-editor {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: none;
  background: var(--bg);
  padding:
    max(16px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    max(16px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
  overflow: hidden;
}

.rhythm-editor.open {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 20px;
  align-items: stretch;
  animation: fadeIn 0.18s ease;
}

/* Shared icon-button — same visual contract as .bpm-icon-btn on the
   main screen (36px circle on card-2). */
.rhythm-icon-btn {
  width: 36px;
  height: 36px;
  border: none;
  border-radius: 50%;
  background: var(--card-2);
  color: var(--muted);
  display: grid;
  place-items: center;
  cursor: pointer;
  padding: 0;
  flex-shrink: 0;
  transition: background 0.15s ease, color 0.15s ease, transform 0.06s ease;
}

.rhythm-icon-btn svg { width: 18px; height: 18px; }
.rhythm-icon-btn:hover { color: var(--fg); }
.rhythm-icon-btn:active { transform: scale(0.94); background: var(--card-3); }
.rhythm-icon-btn[aria-pressed="true"] { background: var(--accent); color: #000; }

/* === Left column: meta strip === */
.rhythm-meta {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 18px;
  z-index: 2;
}

.rhythm-meta-item {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 56px;
}

/* Tappable meta items (size + division). Same visual presentation as
   the BPM stepper — just text — but with a subtle press feedback so
   they read as actionable. */
.rhythm-meta-button {
  background: transparent;
  border: none;
  color: inherit;
  font-family: inherit;
  cursor: pointer;
  padding: 6px 8px;
  border-radius: 8px;
  transition: background 0.15s ease, transform 0.06s ease;
}
.rhythm-meta-button:active {
  background: var(--card-2);
  transform: scale(0.97);
}

.rhythm-meta-value {
  font-size: 22px;
  font-weight: 700;
  line-height: 1.1;
  font-variant-numeric: tabular-nums;
  color: var(--fg);
}

.rhythm-meta-value-symbol { font-size: 26px; }

.rhythm-meta-label {
  font-size: 11px;
  color: var(--muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  font-weight: 500;
  margin-top: 4px;
}

/* BPM stepper — chevrons above + below the number; small "BPM" label
   below to match the other meta items. */
.rhythm-bpm-stepper { gap: 0; }

.rhythm-bpm-arrow {
  background: transparent;
  border: none;
  color: var(--muted);
  cursor: pointer;
  padding: 1px 6px;
  display: grid;
  place-items: center;
  transition: color 0.15s ease, transform 0.06s ease;
}

.rhythm-bpm-arrow svg { width: 14px; height: 14px; }
.rhythm-bpm-arrow:hover { color: var(--fg); }
.rhythm-bpm-arrow:active { transform: scale(0.9); }

#rhythm-bpm {
  width: 64px;
  color: var(--fg);
  text-align: center;
  font-size: 22px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  letter-spacing: -0.01em;
  user-select: none;
  -webkit-user-select: none;
  /* Drag-to-change BPM gesture: prevent the OS from interpreting the
     finger motion as a scroll/pan, otherwise pointermove never fires
     consistently. */
  touch-action: none;
  cursor: ns-resize;
}

/* === Middle column: grid === */
.rhythm-editor-body {
  display: flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  z-index: 2;
}

/* 7 voice rows × N time cells, with the voice label in the auto column
   on the left. The cell count (and `grid-template-columns`) is set
   inline by buildRhythmGrid() since N depends on beats × division. */
.rhythm-grid {
  display: grid;
  grid-template-rows: repeat(7, 1fr);
  gap: 4px;
  width: 100%;
  height: 100%;
}

.rhythm-voice-label {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  padding-right: 8px;
  color: var(--muted);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.rhythm-cell {
  background: var(--card);
  border: none;
  border-radius: 5px;
  cursor: pointer;
  padding: 0;
  transition: background 0.06s ease, transform 0.06s ease;
}

/* Every 4th column (downbeat) is a touch lighter so beats are readable. */
.rhythm-cell[data-beat="true"] { background: var(--card-2); }
.rhythm-cell.hit { background: var(--accent); }
.rhythm-cell:active { transform: scale(0.9); }
.rhythm-cell.playing { box-shadow: 0 0 0 2px var(--fg); }

/* === Right column: action icons === */
.rhythm-actions {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 22px;
  z-index: 2;
}

.rhythm-play-btn {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--accent);
  color: #000;
  border: none;
  cursor: pointer;
  display: grid;
  place-items: center;
  font-size: 20px;
  font-weight: 700;
  box-shadow: 0 4px 16px rgba(213, 255, 60, 0.25);
  transition: transform 0.06s ease, background 0.15s ease;
  flex-shrink: 0;
}

.rhythm-play-btn:active { transform: scale(0.95); }
.rhythm-play-btn.playing { background: var(--fg); }
.rhythm-play-icon { line-height: 1; }

/* Portrait phone — pre-rotate the editor 90° clockwise so the user
   physically turns the phone 90° left to read it. Same pattern as
   flash-screen. */
@media (orientation: portrait) and (pointer: coarse), (orientation: portrait) and (max-width: 900px) {
  .rhythm-editor.open {
    width: 100dvh;
    height: 100dvw;
    transform: rotate(90deg);
    transform-origin: 50dvmin 50dvmin;
    padding:
      max(16px, env(safe-area-inset-right))
      max(16px, env(safe-area-inset-bottom))
      max(16px, env(safe-area-inset-left))
      max(16px, env(safe-area-inset-top));
  }

  /* When the editor is open and a modal opens on top of it, rotate the
     modal too — same trick as the editor. The body class is toggled in
     openRhythmEditor / closeRhythmEditor. The sheet inside the modal
     stays anchored to the modal's bottom, which after rotation lands at
     the user's perceived bottom (i.e. the phone's left edge). */
  body.rhythm-editor-open .modal.open {
    width: 100dvh;
    height: 100dvw;
    transform: rotate(90deg);
    transform-origin: 50dvmin 50dvmin;
  }

  /* The rotated sheet's horizontal axis maps to the phone's vertical
     axis, so the notch / Dynamic Island sits on the sheet's LEFT and
     the home indicator on the RIGHT. Pad both sides to clear them,
     otherwise the start of long text gets eaten by the notch. */
  body.rhythm-editor-open .modal.open .sheet {
    padding-left: max(24px, env(safe-area-inset-top));
    padding-right: max(24px, env(safe-area-inset-bottom));
  }
}


/* Saved-rhythms sheet — slides up from bottom (uses existing .modal/.sheet
   patterns from time-sig and presets modals). */
.rhythm-save-form {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  margin-top: 16px;
  padding-top: 16px;
  border-top: 1px solid var(--card-2);
}

.rhythm-save-form input {
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-family: inherit;
  font-size: 15px;
  outline: none;
}

.rhythm-save-form-btn {
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px 18px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

.rhythm-save-form-btn:active { transform: scale(0.97); }

.rhythm-saved-title { margin-top: 4px; }

.rhythms-saved-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.rhythms-saved-list:empty::before {
  content: 'Сохранённых ритмов пока нет';
  display: block;
  text-align: center;
  color: var(--muted);
  padding: 18px 0;
  font-size: 13px;
}

.rhythm-saved-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 8px;
  align-items: center;
}

.rhythm-saved-load {
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-sm);
  padding: 12px 14px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 500;
  cursor: pointer;
  text-align: left;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.rhythm-saved-load:active { background: var(--card-3); }

.rhythm-saved-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rhythm-saved-bpm { color: var(--muted); font-size: 12px; flex-shrink: 0; }

.rhythm-saved-active {
  background: var(--accent);
  color: #000;
  font-weight: 600;
}

.rhythm-saved-active .rhythm-saved-bpm { color: rgba(0,0,0,0.6); }

.rhythm-saved-del {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: none;
  background: var(--card-2);
  color: var(--muted);
  cursor: pointer;
  display: grid;
  place-items: center;
}

.rhythm-saved-del:hover { color: var(--fg); }
.rhythm-saved-del svg { width: 16px; height: 16px; }

@media (max-width: 380px) {
  #bpm-input { font-size: 64px; width: 150px; }
  .play-row { --play-h: 54px; }
  .play-btn { font-size: 17px; padding: 0 20px; }
  .grid2 { grid-template-columns: 1fr; }
  .time-sig-display { font-size: 32px; }
  .sub-display { font-size: 32px; }
}

/* === Light theme === */
/* Default :root above is dark. Light theme is a switch via <html data-theme="light">. */
[data-theme="light"] {
  --bg: #f5f5f7;
  --card: #ffffff;
  --card-2: #ececef;
  --card-3: #dcdce0;
  --fg: #0a0a0a;
  --muted: #6b6b70;
  --accent: #d5ff3c;
  --accent-soft: rgba(213, 255, 60, 0.45);
  /* lime-700 — readable on white (~5.5:1) while staying in the same hue
     family as the lime fill. Used wherever dark theme paints text/strokes
     in --accent. */
  --accent-text: #4d7c0f;
  --border: #d8d8dc;
}

/* Subtle elevation on cards in light theme — without it surfaces blend into bg */
[data-theme="light"] .bpm-card,
[data-theme="light"] .mini-card,
[data-theme="light"] .beat-card,
[data-theme="light"] details,
[data-theme="light"] .program-action-btn,
[data-theme="light"] .programs-picker-btn {
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}

[data-theme="light"] .runner-block-type { color: var(--accent-text); }
[data-theme="light"] .groove-cell.hit { color: #000; }
[data-theme="light"] .program-start-btn,
[data-theme="light"] .runner-done-btn,
[data-theme="light"] .runner-transition-btn { box-shadow: none; }
[data-theme="light"] .sheet { box-shadow: 0 -4px 24px rgba(0, 0, 0, 0.08); }

/* Tick row needs darker color than rgba(255,255,255,0.28) on white */
[data-theme="light"] .wheel-tick { background: rgba(0, 0, 0, 0.22); }

/* These rules only differ structurally (drop dark-theme glow shadows that
   look wrong on white); accent text/stroke colors come from --accent-text
   automatically because the base rules already use var(--accent) — but
   the base rules use var(--accent), not var(--accent-text). So we still
   override here, just with --accent-text for branded look. */
[data-theme="light"] .wheel-center { background: var(--accent-text); box-shadow: none; }
[data-theme="light"] .sub-display { color: var(--accent-text); }
[data-theme="light"] .beat-stack[data-type="accent"] .bdot { background: var(--accent-text); }
[data-theme="light"] .beat-stack.active[data-type="accent"] .bdot {
  box-shadow: none;
  transform: scale(1.25);
}
[data-theme="light"] .play-btn { box-shadow: none; }
[data-theme="light"] .play-btn.playing { background: var(--fg); color: #fff; box-shadow: none; }
[data-theme="light"] .countin-btn.armed + .play-btn.playing { box-shadow: 0 0 0 4px var(--bg); }
[data-theme="light"] .vol input[type="range"]::-webkit-slider-thumb { background: var(--accent-text); }
[data-theme="light"] .vol input[type="range"]::-moz-range-thumb { background: var(--accent-text); }
[data-theme="light"] .toggle input { accent-color: var(--accent-text); }
[data-theme="light"] .preset { background: var(--card-2); }
[data-theme="light"] .preset.is-active { background: var(--accent); color: #000; box-shadow: none; }
[data-theme="light"] .preset-del { background: var(--card-2); }
[data-theme="light"] .preset-del:hover { color: var(--accent-text); }
[data-theme="light"] .grid2 input,
[data-theme="light"] .row-inline select,
[data-theme="light"] .user-presets input { background: var(--card-2); }
[data-theme="light"] .bt-detected-line code { background: var(--card-2); }
[data-theme="light"] .modal-backdrop { background: rgba(0, 0, 0, 0.35); }
[data-theme="light"] .sub-option .sub-glyph { color: var(--accent-text); }
[data-theme="light"] .time-grid button.active { color: var(--accent-text); }
[data-theme="light"] .update-btn:hover { border-color: var(--accent-text); color: var(--accent-text); }
[data-theme="light"] .update-toast { background: var(--fg); color: var(--card); }
[data-theme="light"] .tab-bar-item.active { color: var(--accent-text); }

/* Very short screens (iPhone SE territory) — compress further so everything fits without scroll */
@media (max-height: 720px) {
  .bpm-card { padding: 12px 14px; gap: 10px; }
  #bpm-input { font-size: 60px; width: 150px; }
  .bpm-label { font-size: 14px; }
  .bpm-wheel-wrap { height: 56px; }
  .wheel-tick { height: 42px; }
  .bpm-step { padding: 9px; font-size: 14px; }
  .tap-btn { padding: 9px; font-size: 12px; }
  .mini-card { min-height: 64px; padding: 10px; }
  .time-sig-display { font-size: 28px; }
  .sub-display { font-size: 28px; }
  .mini-card-label { font-size: 11px; }
  .beat-card { padding: 8px 10px; }
  .beat-stack { width: 38px; height: 56px; gap: 4px; padding: 6px 0; }
  .beat-stack .bdot { width: 10px; height: 10px; }
  .play-row { --play-h: 50px; }
  .play-btn { padding: 0 16px; font-size: 16px; }
  .topbar { padding: 2px 4px 2px; }
  .brand { font-size: 16px; }
  .icon-btn { width: 38px; height: 38px; }
}

/* === Fullscreen flash view === */
.flash-screen {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: none;
  background: var(--bg);
  padding:
    max(16px, env(safe-area-inset-top))
    max(16px, env(safe-area-inset-right))
    max(16px, env(safe-area-inset-bottom))
    max(16px, env(safe-area-inset-left));
  overflow: hidden;
}

.flash-screen.open {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 20px;
  align-items: stretch;
  animation: fadeIn 0.18s ease;
}

.flash-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 14px;
  z-index: 2;
}

.flash-info-item {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 64px;
}

.flash-info-label {
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}

.flash-info-value {
  font-size: 22px;
  font-weight: 700;
  color: var(--fg);
  font-variant-numeric: tabular-nums;
}

[data-theme="light"] .flash-info-value { color: var(--fg); }

.flash-stacks {
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

.beat-indicator--big {
  gap: clamp(12px, 2vmax, 32px);
  flex-wrap: nowrap;
}

.beat-indicator--big .beat-stack {
  /* Width tracks the LONG axis (vmax) so stacks fill the wide edges;
     height tracks the SHORT axis (vmin) so they fit between the safe
     paddings. Works the same in native landscape and CSS-rotated portrait
     (since vmin/vmax always reference the actual viewport). */
  width: clamp(90px, 14vmax, 240px);
  height: clamp(280px, 88vmin, 540px);
  gap: clamp(14px, 3.5vmin, 32px);
  padding: clamp(18px, 3.5vmin, 32px) 0;
  border-radius: clamp(18px, 3vmin, 32px);
}

.beat-indicator--big .beat-stack .bdot {
  width: clamp(16px, 3.5vmin, 36px);
  height: clamp(16px, 3.5vmin, 36px);
}

.flash-controls {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  /* Center the column vertically so close/play/lamp don't stretch to the
     extreme top/bottom of the grid row (which would push lamp into the
     phone's bottom edge as soon as stacks get tall). The natural column
     height = close + play + lamp + 2 gaps, comfortably under viewport. */
  align-self: center;
  gap: clamp(28px, 6vmin, 64px);
  z-index: 2;
}

.flash-lamp-btn[aria-pressed="true"] {
  background: var(--accent);
  color: #000;
}

/* Big round Start/Stop button in the middle of the controls column */
.flash-play-btn {
  width: 72px;
  height: 72px;
  border: none;
  border-radius: 50%;
  background: var(--accent);
  color: #000;
  display: grid;
  place-items: center;
  cursor: pointer;
  box-shadow: 0 6px 20px rgba(213, 255, 60, 0.25);
  transition: transform 0.08s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.flash-play-btn:active { transform: scale(0.95); }
.flash-play-btn.playing { background: var(--fg); color: var(--bg); box-shadow: 0 6px 20px rgba(255, 255, 255, 0.15); }
[data-theme="light"] .flash-play-btn { box-shadow: none; }
[data-theme="light"] .flash-play-btn.playing { background: var(--fg); color: #fff; box-shadow: none; }

.flash-play-icon {
  font-size: 26px;
  line-height: 1;
  /* SF rendering of ▶ leans slightly right; nudge left for optical centering */
  margin-left: 3px;
}
.flash-play-btn.playing .flash-play-icon { margin-left: 0; }

/* Lamp mode (toggled by the bulb button in fullscreen) — instead of
   flashing the whole screen, we just paint the ACTIVE stack background
   at full brightness so each beat reads from across the room. No
   photosensitivity risk, so the warning modal is gone. */
.flash-screen.lamp-on .beat-stack.active {
  background: var(--fg);
}
.flash-screen.lamp-on .beat-stack.active[data-type="accent"] {
  background: var(--accent);
}

/* Recolor the dots when the bg is bright — otherwise they vanish
   (lime dots on lime bg, white dots on white bg). On the lime-accent
   active bg use pure black; on the white/--fg active bg use --bg
   (black in dark theme, light gray in light theme — both contrasty). */
.flash-screen.lamp-on .beat-stack.active .bdot { background: var(--bg); }
.flash-screen.lamp-on .beat-stack.active[data-type="accent"] .bdot { background: #000; }

/* Portrait phone — pre-rotate the fullscreen content 90° clockwise so the
   user only has to physically turn the phone 90° left to read it upright.
   When the phone is actually held in landscape (orientation: landscape),
   this rule doesn't apply and the layout is rendered natively.
   Desktop is matched by `pointer: coarse` filter — only touch + portrait
   triggers rotation. */
@media (orientation: portrait) and (pointer: coarse), (orientation: portrait) and (max-width: 900px) {
  .flash-screen.open {
    width: 100dvh;
    height: 100dvw;
    transform: rotate(90deg);
    transform-origin: 50dvmin 50dvmin;
    /* In rotated frame, content's edges map to phone edges as:
         content-top    ← phone-right
         content-right  ← phone-bottom (home indicator)
         content-bottom ← phone-left
         content-left   ← phone-top (notch)
       So we feed the env() insets to the matching content side. */
    padding:
      max(16px, env(safe-area-inset-right))
      max(16px, env(safe-area-inset-bottom))
      max(16px, env(safe-area-inset-left))
      max(16px, env(safe-area-inset-top));
  }

}

/* === Count-in popup options === */
.countin-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-top: 8px;
}

.countin-option {
  padding: 18px;
  border: none;
  border-radius: var(--radius-md);
  background: var(--card-2);
  color: var(--fg);
  font-family: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.countin-option:active { transform: scale(0.97); background: var(--card-3); }

.countin-option.is-active {
  background: var(--accent);
  color: #000;
}

/* Odd 5th option ("Без задержки") sits alone on the last grid row —
   span both columns so it doesn't look orphaned next to empty space. */
.countin-options .countin-option:nth-child(5) { grid-column: 1 / -1; }

/* The rhythm editor sits at z-index 130; its picker/confirm modals must
   stack above it so the sheets aren't hidden behind the editor. */
#rhythm-size-modal,
#rhythm-division-modal,
#rhythm-confirm-modal,
#rhythms-modal {
  z-index: 140;
}

/* === Rhythm meter & division pickers === */
.rhythm-meter-options,
.rhythm-division-options {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-top: 8px;
}

.rhythm-meter-option,
.rhythm-division-option {
  padding: 18px;
  border: none;
  border-radius: var(--radius-md);
  background: var(--card-2);
  color: var(--fg);
  font-family: inherit;
  font-size: 18px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.rhythm-meter-option:active,
.rhythm-division-option:active {
  transform: scale(0.97);
  background: var(--card-3);
}

.rhythm-meter-option.is-active,
.rhythm-division-option.is-active {
  background: var(--accent);
  color: #000;
}

.rhythm-division-option {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.rhythm-division-glyph {
  font-size: 26px;
  line-height: 1;
}

.rhythm-division-name {
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0.02em;
  opacity: 0.85;
}

/* === Rhythm change-confirmation sheet === */
.rhythm-confirm-text {
  margin: 8px 0 16px;
  color: var(--fg);
  font-size: 15px;
  line-height: 1.4;
}

.rhythm-confirm-actions {
  display: flex;
  gap: 10px;
}

.rhythm-confirm-cancel,
.rhythm-confirm-ok {
  flex: 1;
  padding: 14px;
  border: none;
  border-radius: var(--radius-md);
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.rhythm-confirm-cancel {
  background: var(--card-2);
  color: var(--fg);
}

.rhythm-confirm-ok {
  background: #e64a4a;
  color: #fff;
}

.rhythm-confirm-cancel:active,
.rhythm-confirm-ok:active { transform: scale(0.97); }

/* Override the default blue link color inside collapsible settings
   sections (e.g. the Telegram link in Поддержка) — it doesn't fit the
   muted dark UI. */
details a {
  color: var(--fg);
  text-decoration-color: var(--muted);
  text-underline-offset: 3px;
}

/* === Import modals === */

/* Big primary "paste from clipboard" button — the recommended path
   since iOS PWAs can't intercept https:// deeplinks. */
.import-clipboard-btn {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 16px;
  margin-top: 6px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.06s ease;
}

.import-clipboard-btn svg { width: 18px; height: 18px; }
.import-clipboard-btn:active { transform: scale(0.97); }

.import-or {
  margin: 14px 0 6px;
  text-align: center;
}

.import-input {
  width: 100%;
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 12px 14px;
  font-family: inherit;
  font-size: 14px;
  resize: vertical;
  outline: none;
}

.import-error {
  margin: 8px 0 0;
  color: #e64a4a;
  font-size: 13px;
  line-height: 1.4;
}

.import-submit-btn {
  width: 100%;
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 14px;
  margin-top: 12px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.import-submit-btn:active { transform: scale(0.97); background: var(--card-3); }

/* Confirm sheet — Cancel + Save side-by-side */
.import-actions {
  display: flex;
  gap: 10px;
  margin-top: 14px;
}

.import-cancel-btn {
  flex: 1;
  background: var(--card-2);
  color: var(--fg);
  border: none;
  border-radius: var(--radius-md);
  padding: 14px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.06s ease;
}

.import-save-btn {
  flex: 1;
  background: var(--accent);
  color: #000;
  border: none;
  border-radius: var(--radius-md);
  padding: 14px;
  font-family: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  transition: transform 0.06s ease;
}

.import-cancel-btn:active,
.import-save-btn:active { transform: scale(0.97); }

/* Settings reset — destructive action, paint it red. */
.settings-reset-btn {
  background: #e64a4a;
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  padding: 12px 16px;
  font-family: inherit;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.06s ease;
}
.settings-reset-btn:active { transform: scale(0.97); }

/* === Count-in countdown overlay === */
.countin-overlay {
  position: fixed;
  inset: 0;
  z-index: 130;
  display: none;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.7);
  pointer-events: none;
}

.countin-overlay.open { display: flex; animation: fadeIn 0.18s ease; }

.countin-num {
  font-size: clamp(120px, 28vw, 240px);
  font-weight: 700;
  color: var(--accent);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.05em;
  line-height: 1;
}

/* === Epilepsy warning modal === */
.warning-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 14px;
}

.warning-cancel,
.warning-ok {
  padding: 14px;
  border-radius: var(--radius-md);
  border: none;
  font-family: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.warning-ok { background: var(--accent); color: #000; }
.warning-ok:active { transform: scale(0.98); }

/* Single-button variant of warning-actions (one CTA spans the row) */
.training-actions { grid-template-columns: 1fr; }
