/* Tokens, the page column and the header come from ../shared/theme.css;
   this file holds only what is the page's own. A score wants width, so the
   column takes the whole window; the shell keeps its lines from growing too
   long to follow, and draws them larger instead. */

:root {
  --app-width: none;
  --error: #b3261e;
}

@media (prefers-color-scheme: dark) {
  :root {
    --error: #ff9c92;
  }
}

/* The score is black ink on white paper whatever the page's theme: the
   sheet sets the page's tokens afresh, and the ones below are worked out
   on it, so they mix its ink and accent rather than the page's. */
.sheet {
  --panel: #ffffff;
  --ink: #000000;
  --muted: #555a63;
  --accent: #2f5fd0;
  --paper: var(--panel);
  --engraving: var(--ink);
  --staff: color-mix(in srgb, var(--ink) 70%, transparent);
  --now: #d0342c;
  --hit: #1e8e3e;
  --missed: #e37400;
  --cursor: color-mix(in srgb, var(--accent) 35%, transparent);
  --start: color-mix(in srgb, var(--accent) 9%, transparent);
  --range: color-mix(in srgb, var(--accent) 5%, transparent);
}

button {
  font: inherit;
  color: inherit;
}

/* --- opening a score ---------------------------------------------------------- */

.library {
  display: flex;
  min-width: 0;
}

.open-button,
.example,
.nudge,
.play,
.segment {
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}

/* The one way to a score: the piece open now, or a call to choose one. The
   picker it opens also opens a file from the device. */
.example::after {
  content: " ▾";
  color: var(--muted);
}

.open-button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  gap: 6px;
  font-weight: 400;
}

.open-button svg {
  display: block;
  flex: none;
}

.open-button:hover {
  border-color: var(--accent);
}

.example:hover,
.nudge:hover:enabled,
.segment:hover {
  border-color: var(--accent);
}

.nudge:disabled {
  opacity: 0.4;
  cursor: default;
}

.message {
  margin: -8px 0 0;
  font-size: 14px;
  color: var(--muted);
}

.message.is-error {
  color: var(--error);
}

.empty {
  max-width: 44em;
  margin: 24px auto;
  font-size: 15px;
  color: var(--muted);
  text-align: center;
}

/* --- the piece picker ---------------------------------------------------------- */

.example {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* A modal over the page: search on top, then the composers — or, once one
   is chosen, a way back and their pieces — scrolling on their own. */
.picker {
  width: min(640px, calc(100vw - 32px));
  max-height: min(720px, calc(100dvh - 32px));
  padding: 0;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.picker[open] {
  display: flex;
  flex-direction: column;
}

/* With a phone's keyboard up, what of the page still shows, set by the script. */
.picker.is-fitted {
  top: var(--shown-top);
  bottom: auto;
  margin-block: 8px 0;
  max-height: calc(var(--shown-height) - 16px);
}

.picker::backdrop {
  background: color-mix(in srgb, var(--ink) 35%, transparent);
}

.picker-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 14px 16px 0;
}

.picker-title {
  margin: 0;
  font-size: 17px;
}

.picker-close {
  padding: 4px 12px;
  font-size: 18px;
  line-height: 1;
}

.picker-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 12px 16px 0;
}

.picker-search {
  flex: 1 1 220px;
  min-width: 0;
  padding: 8px 12px;
  font: inherit;
  font-size: 16px; /* under 16px, iOS zooms the page to a field focused */
  color: inherit;
  background: var(--bg);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* Major composers: lit while the composers are kept to them. */
.picker-major {
  flex: none;
  font-weight: 400;
}

.picker-search:focus-visible,
.picker-item:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.picker-crumb:not([hidden]) {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 12px;
  padding: 10px 16px 0;
}

.picker-back {
  padding: 4px 12px;
  font-weight: 400;
}

.picker-composer-name {
  margin: 0;
  font-size: 16px;
}

.picker-count {
  margin: 0;
  padding: 8px 16px;
  font-size: 13px;
  color: var(--muted);
  border-bottom: 1px solid var(--line);
}

.picker-results {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: 4px 8px 12px;
}

.picker-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.picker-item {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: space-between;
  gap: 2px 12px;
  width: 100%;
  padding: 8px;
  text-align: left;
  background: none;
  border: 0;
  border-radius: 8px;
  cursor: pointer;
}

.picker-item:hover,
.picker-item:focus-visible {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
}

.picker-item.is-current {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
}

.picker-item-title {
  font-size: 15px;
}

.picker-item-note {
  font-size: 13px;
  color: var(--muted);
}

/* A link offered is shown whole, broken wherever it must be to fit. */
.picker-item[data-url] .picker-item-note {
  overflow-wrap: anywhere;
}

/* --- the toolbar and transport ------------------------------------------------ */

/* One row across the window — the way home and the title, the piece, the
   transport, the practice controls — that stays in reach while the score
   scrolls under it, so the music starts right below it; where it does not
   fit, the practice controls are a row of their own. Opened out, what is
   set once and left is the last row. A narrow window comes apart (below)
   and only the deck, the transport, practice and settings, stays. */
.toolbar {
  position: sticky;
  top: 0;
  z-index: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 20px;
  padding: 8px 14px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.toolbar .app-header {
  display: contents;
}

.brand {
  display: flex;
  flex-direction: column;
}

.toolbar .site-nav {
  margin: 0;
}

.toolbar h1 {
  font-size: 16px;
  line-height: 1.2;
  white-space: nowrap;
}

.library .example {
  max-width: 28em;
}

.deck {
  display: contents;
}

.transport,
.practice {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 18px;
}

/* The way to the settings, a gear at the far end of the bar's last row. */
.options-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  margin-left: auto;
}

.options-toggle svg {
  display: block;
  flex: none;
}

.options-chevron {
  transition: transform 0.15s;
}

.options-toggle[aria-expanded="true"] {
  border-color: var(--accent);
}

.options-toggle[aria-expanded="true"] .options-chevron {
  transform: rotate(180deg);
}

.play {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-width: 96px;
  justify-content: center;
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.play.is-playing {
  background: var(--panel);
  color: var(--ink);
}

.tempo {
  display: flex;
  align-items: center;
  gap: 6px;
}

.tempo-note {
  display: inline-flex;
  align-items: center;
}

.tempo-equals {
  color: var(--muted);
}

.nudge {
  padding: 4px 10px;
  min-width: 34px;
}

.tempo-value {
  min-width: 3ch;
  font-size: 20px;
  font-weight: 700;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/* The reading between the − and +, a button of its own: it opens the
   slider and the way back to the tempo the score marks. */
.tempo-readout {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 2px 10px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 10px;
  cursor: pointer;
}

.tempo-readout:hover,
.tempo-readout.is-open {
  border-color: var(--accent);
}

/* Laid in the top layer under the reading by the script, so the deck's
   own scrolling on a narrow window cannot clip it. */
.tempo-pop {
  position: fixed;
  inset: auto;
  margin: 0;
  padding: 12px 14px;
  color: var(--ink);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: 0 6px 24px rgb(0 0 0 / 0.18);
}

.tempo-pop:popover-open {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}

.tempo-slider {
  width: min(280px, calc(100vw - 64px));
  accent-color: var(--accent);
}

.tempo-reset {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
}

.tempo-reset-mark {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}

/* The size as a small and a large A, so the buttons read as type, not as
   the tempo's − and +. */
.zoom {
  display: flex;
  gap: 8px;
}

.zoom-button {
  display: inline-flex;
  align-items: baseline;
  justify-content: center;
  gap: 1px;
}

.zoom-a {
  font-size: 15px;
  font-weight: 700;
}

.zoom-a.is-small {
  font-size: 11px;
}

/* What is set once and left, folded away under the gear at the end of the
   bar until asked for, and then the bar's last row: what is heard, what
   listens to the playing, the repeats, the score's size, printing, and
   the language. Each is its icon, then its controls, its name in its
   tooltip and for a screen reader. */
.options {
  display: flex;
  flex: 1 0 100%;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 32px;
  padding-top: 10px;
  border-top: 1px solid var(--line);
}

.setting {
  display: flex;
  align-items: center;
  gap: 8px;
}

.setting-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
  color: var(--muted);
}

.setting-label svg {
  display: block;
  flex: none;
  color: var(--ink);
}

/* Follow repeats: a button lit while on, like a chosen segment. */
.toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 13px;
}

.toggle svg {
  display: block;
  flex: none;
}

.toggle[aria-pressed="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.toggle[aria-pressed="false"] {
  color: var(--muted);
}

/* A name said to a screen reader only: the icon beside it says it on screen,
   and the setting's tooltip in words. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.setting-tail {
  display: flex;
  align-items: center;
  gap: 12px;
}

.setting-controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px;
}

.count-in,
.bars-range {
  display: flex;
  align-items: center;
  gap: 8px;
}

.control-label {
  font-size: 13px;
  color: var(--muted);
}

.segmented {
  display: inline-flex;
}

.segment {
  padding: 4px 10px;
  border-radius: 0;
  font-size: 13px;
}

.segment + .segment {
  border-left: 0;
}

.segment:first-child {
  border-radius: 10px 0 0 10px;
}

.segment:last-child {
  border-radius: 0 10px 10px 0;
}

.segment.is-active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-ink);
}

.range-number {
  width: 4em;
  padding: 4px 6px;
  font: inherit;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-align: center;
  color: inherit;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.range-number:focus {
  border-color: var(--accent);
  outline: none;
}

.range-dash {
  color: var(--muted);
}

.range-clear {
  padding: 2px 9px;
}

/* Loop: lit while the range goes round again at its end. */
.loop-toggle {
  padding: 2px 9px 2px 7px;
}

.sound-out {
  max-width: 14em;
  padding: 4px 6px;
  font: inherit;
  font-size: 13px;
  color: inherit;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
}

.sound-out:focus {
  border-color: var(--accent);
  outline: none;
}

.sound-out:disabled {
  opacity: 0.5;
}

.volume {
  width: 100px;
  accent-color: var(--accent);
}

.tally {
  margin-left: auto;
  white-space: nowrap;
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.icon {
  display: block;
}

.icon-fill {
  fill: currentColor;
}

.beat-note {
  color: var(--ink);
}

/* --- the score ------------------------------------------------------------------ */

.sheet {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 20px 18px 16px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.sheet-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
}

.score-title {
  margin: 0;
  font-size: 22px;
}

.score-subtitle {
  margin: 0;
  font-size: 16px;
}

.score-composer {
  margin: 0;
  font-size: 14px;
  color: var(--muted);
}

.score-credits {
  margin: 2px 0 0;
  font-size: 12px;
  color: var(--muted);
}

.score-credits a {
  color: inherit;
}

.parts {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 8px 0 0;
  padding: 0;
  border: 0;
}

.parts-label {
  float: left;
  padding: 0;
  font-size: 13px;
  color: var(--muted);
}

.parts-list {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 14px;
  font-size: 14px;
}

.part-toggle {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

.part-toggle input {
  accent-color: var(--accent);
}

/* Each system is its own SVG, drawn in staff spaces and scaled to the width
   the layout was made for. It clears the sticky transport when scrolled to. */
.score {
  position: relative;
  display: flex;
  flex-direction: column;
}

.system {
  display: block;
  width: 100%;
  height: auto;
  overflow: visible;
  scroll-margin-top: calc(var(--bar-height, 60px) + 12px);
  scroll-margin-bottom: 24px;
}

.glyph-sprite {
  position: absolute;
  width: 0;
  height: 0;
}

.staff-line,
.ledger {
  stroke: var(--staff);
}

.barline,
.stem {
  stroke: var(--engraving);
}

.head,
.rest,
.dot,
.accidental,
.clef,
.key,
.time,
.flag,
.beam,
.tremolo,
.arpeggio,
.tie,
.slur,
.tuplet,
.brace,
.repeat {
  fill: var(--engraving);
}

.bar-number {
  font-size: 1.3px;
  fill: var(--muted);
}

.dynamic,
.fingering,
.trill-line,
.octave,
.articulation,
.ornament,
.repeat-sign,
.pedal,
.tempo-mark {
  fill: var(--engraving);
}

.hairpin,
.octave-line,
.tuplet-bracket,
.volta,
.pedal-line,
.lyric-line {
  stroke: var(--engraving);
}

/* Cue notes are another player's line, printed for orientation: lighter. */
.cue {
  opacity: 0.5;
}

/* Text in the score is set in a book face, the way engravers set it; sizes
   are in staff spaces, the SVG's own unit. */
.words,
.fingering-text,
.lyric,
.harmony,
.rehearsal,
.volta-label,
.tempo-text {
  font-family: Georgia, "Times New Roman", "Noto Serif TC", serif;
  fill: var(--engraving);
}

.words {
  font-size: 1.5px;
  font-style: italic;
}

.words.bold {
  font-weight: 700;
}

.words.upright {
  font-style: normal;
}

.lyric {
  font-size: 1.6px;
}

.fingering-text {
  font-size: 1.3px;
}

.harmony {
  font-size: 1.7px;
  font-weight: 700;
}

.rehearsal {
  font-size: 1.9px;
  font-weight: 700;
}

.volta-label {
  font-size: 1.3px;
}

.tempo-text {
  font-size: 1.5px;
  font-weight: 700;
}

/* The bars are the click targets for choosing where to start and end; the
   start is tinted so it is visible before Play, and the rest of a range more
   lightly. The ink lets taps through to the bar under it, and a press held
   on a phone chooses an end rather than text or a callout. */
.system {
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  user-select: none;
}

.system > :not(.bar-hit) {
  pointer-events: none;
}

.bar-hit {
  fill: transparent;
  cursor: pointer;
}

.bar-hit.is-range {
  fill: var(--range);
}

.bar-hit.is-start {
  fill: var(--start);
}

/* How a note went on the keyboard; one sounding now shows that first. */
.head.is-hit {
  fill: var(--hit);
}

.head.is-missed {
  fill: var(--missed);
}

.head.is-now,
.rest.is-now {
  fill: var(--now);
}

.play-cursor {
  position: absolute;
  left: 0;
  background: var(--cursor);
  pointer-events: none;
  will-change: transform;
}

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

/* --- dropping a file ------------------------------------------------------------ */

.drop-veil {
  position: fixed;
  inset: 0;
  z-index: 3;
  display: grid;
  place-items: center;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  border: 3px dashed var(--accent);
  pointer-events: none;
}

.drop-hint {
  font-size: 20px;
  font-weight: 700;
}

/* Wide, the transport and the practice controls sit side by side, the
   tally just after the tempo rather than pushed to the far end. */
@media (min-width: 961px) {
  .tally {
    margin-left: 0;
  }
}

/* Too narrow for one row: the toolbar's parts become the page's, each its
   own row, and the deck alone stays pinned to the top — the transport and
   the way to the settings on its first row, the practice controls on the
   next. Opened out there, it can be taller than the screen leaves, so it
   scrolls on its own; the settings are a column of names and controls. */
@media (max-width: 960px) {
  .toolbar {
    display: contents;
  }

  .toolbar .app-header {
    display: flex;
  }

  .toolbar h1 {
    font-size: 20px;
  }

  .library .example {
    max-width: 100%;
  }

  .deck {
    position: sticky;
    top: 0;
    z-index: 2;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    max-height: 100dvh;
    overflow-y: auto;
    padding: 10px 14px;
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--radius);
  }

  .transport {
    grid-column: 1;
    grid-row: 1;
  }

  .options-toggle {
    grid-column: 2;
    grid-row: 1;
  }

  .practice,
  .options {
    grid-column: 1 / -1;
  }

  .options {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    align-items: center;
    gap: 10px 16px;
  }

  .sound-out {
    min-width: 0;
    max-width: 100%;
  }

  .setting {
    display: contents;
  }

  .repeats-toggle,
  .setting-tail {
    grid-column: 1 / -1;
  }

  .repeats-toggle {
    justify-self: start;
  }
}

@media (max-width: 640px) {
  .deck {
    padding: 8px 10px;
  }

  .transport,
  .practice {
    gap: 8px 10px;
  }

  .options-toggle {
    min-width: 0;
    padding-inline: 7px;
  }

  .play {
    min-width: 0;
  }

  /* The note says it is the tempo. */
  .tempo-label {
    display: none;
  }

  /* The count-in is its numbers alone: Off, 1, 2. */
  .segment-unit {
    display: none;
  }

  .range-number {
    width: 3.2em;
  }

  .sheet {
    padding: 14px 8px 12px;
  }
}

/* On a phone the play button is its icon alone, so the deck stays one
   row; its word is still there for a screen reader. */
@media (max-width: 480px) {
  .play {
    padding-inline: 12px;
  }

  .play span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* --- printing -------------------------------------------------------------------- */

.print-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding-inline: 12px;
}

.print-button svg {
  display: block;
}

/* On paper, the score alone: its title, subtitle, composer and credits,
   and the systems, black on white whatever the theme, none split across a
   page. What the screen marks — the start, the range, the cursor, the note
   sounding — is left off. The shell lays the systems out for the width
   between these margins before the browser prints. */
@page {
  margin: 15mm;
}

@media print {
  :root,
  .sheet {
    --bg: #ffffff;
    --panel: #ffffff;
    --ink: #000000;
    --muted: #444444;
    --paper: #ffffff;
    --engraving: #000000;
    --staff: #000000;
  }

  .toolbar,
  .message,
  .deck,
  .transport,
  .practice,
  .options,
  .parts,
  .hint,
  .empty,
  .picker,
  .tempo-pop,
  .drop-veil,
  .play-cursor {
    display: none !important;
  }

  .app {
    max-width: none;
    padding: 0;
  }

  .sheet {
    padding: 0;
    border: 0;
    border-radius: 0;
  }

  .sheet-header {
    margin-bottom: 4mm;
  }

  .score-credits a {
    text-decoration: none;
  }

  .system {
    break-inside: avoid;
  }

  .bar-hit,
  .bar-hit.is-range,
  .bar-hit.is-start {
    fill: transparent;
  }

  .head.is-now,
  .rest.is-now,
  .head.is-hit,
  .head.is-missed {
    fill: var(--engraving);
  }
}
