/* ==========================================================================
   The Real Blues Book — Material 3, white, minimal.
   ========================================================================== */

:root {
  /* Colour ------------------------------------------------------------- */
  --primary:            #1a73e8;
  --primary-hover:      #1b66c9;
  --primary-container:  #e8f0fe;
  --on-primary:         #ffffff;
  --on-primary-container:#174ea6;

  --surface:            #ffffff;
  --surface-1:          #fbfcfe;
  --surface-2:          #f6f8fc;
  --surface-3:          #f1f3f4;
  --surface-hover:      #f8f9fa;

  --on-surface:         #1f1f1f;
  --on-surface-variant: #5f6368;
  --on-surface-faint:   #80868b;

  --outline:            #dadce0;
  --outline-soft:       #e8eaed;

  --accent-warm:        #b06000;
  --accent-warm-bg:     #fef7e0;
  --accent-red:         #c5221f;
  --accent-red-bg:      #fce8e6;
  --accent-green:       #137333;
  --accent-green-bg:    #e6f4ea;
  --accent-purple:      #7b1fa2;
  --accent-purple-bg:   #f3e8fd;

  /* Elevation ---------------------------------------------------------- */
  --e1: 0 1px 2px 0 rgba(60,64,67,.10), 0 1px 3px 1px rgba(60,64,67,.06);
  --e2: 0 1px 2px 0 rgba(60,64,67,.14), 0 2px 6px 2px rgba(60,64,67,.07);
  --e3: 0 1px 3px 0 rgba(60,64,67,.16), 0 4px 8px 3px rgba(60,64,67,.08);

  /* Shape -------------------------------------------------------------- */
  --r-xs: 6px;
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 24px;
  --r-full: 999px;

  --font: "Google Sans", "Google Sans Text", Roboto, -apple-system,
          BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --mono: "Roboto Mono", ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  /* The chord sheet sets itself in a serif so it reads as an engraved page
     rather than as more UI. */
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia,
           "Times New Roman", Times, serif;
  /* The Real Book hand. Mansalva was picked over Caveat / Patrick Hand /
     Gochi because it is the only one that draws roman numerals with proper
     crossbars — in the others a bare "I" is a stroke, and the numerals are the
     whole point. Titles and chart lettering only; never body copy or controls. */
  --hand: "Mansalva", "Bradley Hand", "Segoe Print", cursive;

  /* Book paper — warm enough to read as a page, close enough to white to
     leave the Material chrome alone. */
  --paper:       #fdfcf6;
  --paper-edge:  #f2efe4;
  --paper-rule:  #ded9c8;

  /* Backdrop is separate from card surface — on the dark theme the page goes
     black while cards stay panels. */
  --backdrop: #eceef2;

  /* The select chevron is a data-URI, so its stroke colour has to be a token
     or it goes invisible when the surface under it flips. */
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235f6368' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");

  --ease: cubic-bezier(.2, 0, 0, 1);
}

/* ==========================================================================
   Dark theme — the book on a deep blue ground
   ========================================================================== */

/* Deep blue — the cool complement to cream.
 *
 * The backdrop's job is to stop the paper glaring, which is a luminance
 * problem: cream sits near L*98, and against black (L*3) the page runs ~19:1
 * against its own surround. This ground sits at L*≈20, taking that to ~12:1 —
 * the band document viewers use (Chrome's PDF canvas is #525659).
 *
 * Blue does the hue job better than anything: it is cream's complement, so
 * simultaneous contrast pushes the paper as warm as it will go. A warm ground
 * does the opposite and mutes it, which is where I went wrong first time.
 *
 * Surfaces step up from the backdrop, so panels still read as panels. */
[data-theme="dark"] {
  /* Pushed lighter and cooler than Google's #8ab4f8: a mid blue accent on a
     blue ground has no affordance left. */
  --primary:            #9fcbff;
  --primary-hover:      #bcdaff;
  --primary-container:  #334561;
  --on-primary:         #0a2544;
  --on-primary-container:#d8e8ff;

  --backdrop:           #1f2a39;
  --surface:            #29364a;
  --surface-1:          #2d3a4f;
  --surface-2:          #35435a;
  --surface-3:          #3f4f68;
  --surface-hover:      #303e53;

  --on-surface:         #e8ecf3;
  --on-surface-variant: #b3bdcc;
  --on-surface-faint:   #8895a7;

  --outline:            #4b5c74;
  --outline-soft:       #3a4859;

  --accent-warm-bg:     #322815;
  --accent-red-bg:      #3a1f1d;
  --accent-green-bg:    #16301f;
  --accent-green:       #7fd39a;
  --accent-purple-bg:   #2a1d33;
  --accent-purple:      #d0a8e8;

  --e1: 0 1px 2px rgba(0,0,0,.5), 0 1px 3px rgba(0,0,0,.4);
  --e2: 0 1px 2px rgba(0,0,0,.6), 0 2px 8px rgba(0,0,0,.45);
  --e3: 0 2px 6px rgba(0,0,0,.6), 0 8px 24px rgba(0,0,0,.5);

  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%23b3bdcc' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
}

[data-theme="dark"] .appbar { background: rgba(31, 42, 57, .86); }

/* Paper stays paper. Everything printed on it re-declares the light tokens
   locally, or the controls sitting on the page would render light-on-cream. */
[data-theme="dark"] .book,
[data-theme="dark"] .card--sheet {
  --surface:            #ffffff;
  --surface-1:          #fbfaf3;
  --surface-2:          #f3f1e7;
  --surface-3:          #eae7da;
  --surface-hover:      #f6f4ec;
  --on-surface:         #1f1c17;
  --on-surface-variant: #5c574c;
  --on-surface-faint:   #8b8474;
  --outline:            #cfc9b8;
  --outline-soft:       #e2ddcf;
  --primary:            #1a73e8;
  --primary-container:  #e3ebfa;
  --on-primary-container:#174ea6;
  --select-chevron: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24' fill='none' stroke='%235c574c' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
  color: var(--on-surface);
}

/* A cover around the spread: leather, a hairline, then the ground. Brown on
   blue is the complementary pairing, so the leather can stay warm here. */
[data-theme="dark"] .book {
  box-shadow:
    0 0 0 14px #3a2717,
    0 0 0 15px rgba(255, 232, 194, .20),
    0 22px 48px -18px rgba(0, 0, 0, .55);
  /* The cover is a box-shadow ring: it draws 14px outward but occupies no
     layout space, so it eats the gap above. Add it back, and the visual
     spacing matches the light theme instead of looking half as wide. */
  margin-top: 32px;
  margin-bottom: 14px;
}
[data-theme="dark"] .card--sheet {
  box-shadow: 0 0 0 1px rgba(0, 0, 0, .28), 0 14px 32px -16px rgba(0, 0, 0, .45);
  border-color: transparent;
}
[data-theme="dark"] .toast { background: #0f1826; color: #e8ecf3; }

/* Filled buttons keep a saturated blue with white text on dark. The light
   --primary is right for links, but as a button fill it forces dark label
   text, which reads as disabled. The variants have to be restored explicitly:
   this selector is two classes deep and would otherwise beat them. */
[data-theme="dark"] .btn { background: #1a73e8; color: #fff; }
[data-theme="dark"] .btn:hover { background: #3b82f0; }
[data-theme="dark"] .btn--tonal { background: var(--primary-container); color: var(--on-primary-container); }
[data-theme="dark"] .btn--tonal:hover { background: #46587a; }
[data-theme="dark"] .btn--text { background: transparent; color: var(--primary); }
[data-theme="dark"] .btn--text:hover { background: var(--surface-2); }
[data-theme="dark"] .btn--outline {
  background: var(--surface); color: var(--on-surface-variant);
  border: 1px solid var(--outline);
}
[data-theme="dark"] .btn--outline:hover { background: var(--surface-hover); }

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: 14px;
  line-height: 1.5;
  color: var(--on-surface);
  background: var(--backdrop);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

h1, h2, h3, h4 { margin: 0; font-weight: 500; letter-spacing: -.01em; }
p { margin: 0; }
a { color: inherit; text-decoration: none; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--primary); outline-offset: 2px; border-radius: 4px; }

/* ==========================================================================
   App bar
   ========================================================================== */

.appbar {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgba(255, 255, 255, .92);
  backdrop-filter: saturate(180%) blur(12px);
  -webkit-backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid transparent;
  transition: border-color .2s var(--ease), box-shadow .2s var(--ease);
}
.appbar.is-scrolled { border-bottom-color: var(--outline-soft); }

/* Three columns so the nav is centred on the bar, not on whatever is left
   after the brand and the search. The 1fr sides balance each other. */
.appbar__inner {
  max-width: 1180px;
  margin: 0 auto;
  padding: 0 24px;
  min-height: 64px;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
}
/* Matches .page--wide, so the brand lines up with the content beneath it. */
.appbar__inner--wide { max-width: 1440px; }

.appbar__right {
  display: flex; align-items: center; gap: 8px;
  justify-self: end; min-width: 0;
}

/* Section nav ------------------------------------------------------------- */

.appbar__nav {
  display: flex; align-items: center; gap: 2px;
  padding: 4px;
  border-radius: var(--r-full);
  background: var(--surface-2);
}
.navlink {
  display: inline-flex; align-items: center;
  height: 34px; padding: 0 16px;
  border-radius: var(--r-full);
  font-size: 13.5px; font-weight: 500;
  color: var(--on-surface-variant);
  white-space: nowrap;
  transition: background .18s var(--ease), color .18s var(--ease), box-shadow .18s var(--ease);
}
.navlink:hover { color: var(--on-surface); }
.navlink[aria-current="page"] {
  background: var(--surface);
  color: var(--on-surface);
  box-shadow: var(--e1);
}

/* The catalogue ends here and your own list begins. A hairline plus a gap —
   enough to read as a different kind of destination without demoting it. */
.navlink--personal { margin-left: 11px; }
.navlink--personal::before {
  content: "";
  position: absolute; left: -6px; top: 50%; transform: translateY(-50%);
  width: 1px; height: 18px;
  background: var(--outline);
}
.appbar__nav { position: relative; }
.navlink { position: relative; }

/* Below this the three-column bar cannot hold brand + nav + search, so the
   nav drops to its own centred row. */
@media (max-width: 1040px) {
  .appbar__inner {
    grid-template-columns: 1fr auto;
    grid-template-areas: "brand right" "nav nav";
    padding-bottom: 10px;
    row-gap: 4px;
  }
  .brand { grid-area: brand; }
  .appbar__right { grid-area: right; }
  .appbar__nav { grid-area: nav; justify-self: center; }
}
@media (max-width: 560px) {
  .navlink { padding: 0 12px; font-size: 12.5px; }
}

.brand { display: flex; align-items: center; gap: 12px; min-width: 0; }
.brand__title { font-size: 19px; font-weight: 500; letter-spacing: -.015em; white-space: nowrap; }

.appbar__spacer { flex: 1; }

/* Search ------------------------------------------------------------------ */

.search {
  position: relative;
  flex: 0 1 380px;
  min-width: 140px;
}
.search__icon {
  position: absolute; left: 14px; top: 50%; transform: translateY(-50%);
  color: var(--on-surface-variant); pointer-events: none; display: flex;
}
.search__input {
  width: 100%;
  height: 44px;
  padding: 0 40px 0 44px;
  border: 1px solid transparent;
  border-radius: var(--r-full);
  background: var(--surface-2);
  transition: background .18s var(--ease), box-shadow .18s var(--ease), border-color .18s var(--ease);
}
.search__input::placeholder { color: var(--on-surface-faint); }
.search__input:hover { background: var(--surface-3); }
.search__input:focus {
  outline: none;
  background: var(--surface);
  border-color: transparent;
  box-shadow: var(--e2);
}
.search__clear {
  position: absolute; right: 8px; top: 50%; transform: translateY(-50%);
  width: 28px; height: 28px; border: 0; border-radius: var(--r-full);
  background: transparent; color: var(--on-surface-variant);
  display: none; place-items: center; cursor: pointer;
}
.search__clear:hover { background: var(--surface-3); }
.search.has-value .search__clear { display: grid; }

/* ==========================================================================
   Layout
   ========================================================================== */

.page { max-width: 1180px; margin: 0 auto; padding: 0 24px 96px; }
/* The song page carries a sidebar, so it gets more room than the list view. */
.page--wide { max-width: 1440px; }

/* Chart left, backing tracks right — YouTube's player/up-next proportions. */
.song-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 366px;
  gap: 20px;
  align-items: start;
  margin-top: 20px;
}
/* The container the chart sizes itself against — not the viewport, since the
   sidebar takes a fixed slice out of it. */
.song-layout__main { container-type: inline-size; container-name: chart; min-width: 0; }
.song-layout__main > .card { margin-top: 0; }
/* Two classes deep on purpose: the sidebar is also a .card, and `.card` sets a
   top margin further down the file. One class here loses to it and the column
   tops stop meeting. */
.song-layout > .song-layout__side {
  margin-top: 0;
  padding: 18px;
  position: sticky;
  top: 84px;
  /* Taller than the viewport and sticky would clip the bottom out of reach. */
  max-height: calc(100vh - 104px);
  overflow-y: auto;
}

@media (max-width: 1080px) {
  .song-layout { grid-template-columns: minmax(0, 1fr); }
  .song-layout__side { position: static; max-height: none; overflow: visible; }
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 20px 0 16px;
}

.section-head {
  display: flex; align-items: baseline; gap: 12px;
  padding: 32px 0 12px;
}
.section-head__title {
  font-family: var(--serif);
  font-size: 12.5px; font-weight: 600;
  letter-spacing: .16em; text-transform: uppercase;
  color: #4a453a;
}
.section-head__count {
  font-size: 12px; color: var(--on-surface-faint);
  font-variant-numeric: tabular-nums;
}
.section-head__rule { flex: 1; height: 1px; background: var(--paper-rule); }

/* ==========================================================================
   The book — an open spread for the repertoire
   ========================================================================== */

.book {
  position: relative;
  margin-top: 18px;
  padding: 38px 60px 46px;
  background: var(--paper);
  border-radius: 3px;
  box-shadow:
    0 0 0 1px rgba(120, 110, 85, .10),
    0 1px 2px rgba(60, 64, 67, .10),
    0 14px 40px -12px rgba(60, 64, 67, .22);
  /* Page edges: the outermost few millimetres of a stack of paper. */
  background-image:
    linear-gradient(90deg, var(--paper-edge) 0, rgba(253, 252, 246, 0) 14px),
    linear-gradient(270deg, var(--paper-edge) 0, rgba(253, 252, 246, 0) 14px);
  background-repeat: no-repeat;
}

/* The gutter. A real spine falls off into shadow on both sides of the fold. */
.book__spine {
  position: absolute; top: 0; bottom: 0; left: 50%;
  width: 120px; transform: translateX(-50%);
  pointer-events: none;
  background: linear-gradient(90deg,
    rgba(120, 108, 82, 0)    0%,
    rgba(120, 108, 82, .05)  26%,
    rgba(112, 100, 74, .11)  44%,
    rgba(88, 78, 56, .20)    50%,
    rgba(112, 100, 74, .11)  56%,
    rgba(120, 108, 82, .05)  74%,
    rgba(120, 108, 82, 0)   100%);
}

/* Running heads, the way a printed page carries them. */
.book__heads {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 24px;
  font-family: var(--serif);
  font-size: 11.5px; font-weight: 600;
  letter-spacing: .22em; text-transform: uppercase;
  color: #6b6455;
}
.book__rule {
  margin: 12px 0 4px;
  border-top: 2px solid #2b2823;
  border-bottom: 1px solid #2b2823;
  height: 3px;
}

/* Two pages. Groups flow across the gutter exactly as they would in print. */
.book__spread {
  column-count: 2;
  column-gap: 120px;
  column-fill: balance;
}
/* Typographic breaking: never strand a heading at the foot of a column, never
   split a song across the fold. */
.book__spread .section-head { break-after: avoid; page-break-after: avoid; }
.book__spread .song-row { break-inside: avoid; page-break-inside: avoid; }
.book__spread > .section-head:first-child { padding-top: 6px; }
/* An empty state is one message, not two columns of one. */
.book__spread .empty { column-span: all; }

.book__foot {
  margin-top: 34px; padding-top: 16px;
  border-top: 1px solid var(--paper-rule);
  display: flex; justify-content: space-between; align-items: center;
  font-family: var(--serif);
  font-size: 11.5px; letter-spacing: .16em; text-transform: uppercase;
  color: #8c8574;
}

/* On paper the rows lose their card-ish hover fill and get a page-ish one. */
.book .song-row:hover { background: rgba(120, 108, 82, .06); }
.book .song-row:active { background: rgba(120, 108, 82, .10); }
.book .song-row + .song-row::before { background: var(--paper-rule); opacity: .55; }
.book .keycap { background: rgba(120, 108, 82, .10); }
.book .badge { background: rgba(120, 108, 82, .11); color: #5e574a; }
.book .badge--staple { background: var(--accent-green-bg); color: var(--accent-green); }

@media (max-width: 1080px) {
  .book { padding: 30px 28px 34px; }
  .book__spread { column-count: 1; }
  .book__spine { display: none; }
}
@media (max-width: 720px) {
  .book { padding: 22px 16px 26px; border-radius: 2px; }
  .book__heads { font-size: 10px; letter-spacing: .16em; }
}

/* ==========================================================================
   Segmented control (grouping axis)
   ========================================================================== */

.segmented {
  display: inline-flex;
  padding: 0;
  border: 1px solid var(--outline);
  border-radius: var(--r-full);
  overflow: hidden;
  background: var(--surface);
}
.segmented__btn {
  appearance: none;
  border: 0;
  background: transparent;
  padding: 0 18px;
  height: 38px;
  font-size: 13px;
  font-weight: 500;
  color: var(--on-surface-variant);
  cursor: pointer;
  display: inline-flex; align-items: center; gap: 8px;
  transition: background .15s var(--ease), color .15s var(--ease);
  position: relative;
}
.segmented__btn + .segmented__btn { border-left: 1px solid var(--outline); }
.segmented__btn:hover { background: var(--surface-hover); }
.segmented__btn[aria-pressed="true"] {
  background: var(--primary-container);
  color: var(--on-primary-container);
}
.segmented__btn svg { flex: none; }

/* ==========================================================================
   Chips
   ========================================================================== */

.chip {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px;
  border: 1px solid var(--outline);
  border-radius: var(--r-sm);
  background: var(--surface);
  font-size: 13px; color: var(--on-surface-variant);
  cursor: pointer; white-space: nowrap;
  transition: background .15s var(--ease), border-color .15s var(--ease), color .15s var(--ease);
}
.chip:hover { background: var(--surface-hover); }
.chip[aria-pressed="true"] {
  background: var(--primary-container);
  border-color: transparent;
  color: var(--on-primary-container);
  font-weight: 500;
}
.chip--static { cursor: default; }
.chip--static:hover { background: var(--surface); }

.chip-row { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }

.toggle {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 13px; color: var(--on-surface-variant);
  cursor: pointer; user-select: none;
}
.toggle input { accent-color: var(--primary); width: 16px; height: 16px; cursor: pointer; }

/* ==========================================================================
   Song rows (repertoire)
   ========================================================================== */

.song-list { display: flex; flex-direction: column; }

.song-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 16px;
  padding: 14px 16px;
  border-radius: var(--r-md);
  cursor: pointer;
  transition: background .12s var(--ease);
  position: relative;
}
.song-row:hover { background: var(--surface-hover); }
.song-row:active { background: var(--surface-3); }
.song-row + .song-row::before {
  content: "";
  position: absolute; left: 16px; right: 16px; top: 0;
  height: 1px; background: var(--outline-soft);
}
.song-row:hover::before, .song-row:hover + .song-row::before { background: transparent; }

.song-row__main { min-width: 0; }
.song-row__title {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
}
/* The hand only gets the title itself — badges and metadata stay in Roboto,
   where they are read rather than looked at. */
.song-row__name {
  font-family: var(--hand);
  font-size: 20px; font-weight: 400; letter-spacing: .005em; line-height: 1.15;
}
.song-row__emoji { font-size: 14px; letter-spacing: 2px; }
.song-row__meta {
  margin-top: 3px;
  font-size: 12.5px; color: var(--on-surface-variant);
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
}
.song-row__meta .dot { color: var(--outline); }
/* The separator belongs to the bit that follows it, so it can never be left
   hanging at the end of a wrapped line. */
.song-row__bit + .song-row__bit::before {
  content: "·";
  color: var(--outline);
  margin-right: 6px;
}

.song-row__right { display: flex; align-items: center; gap: 10px; }

.bpm {
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  color: var(--on-surface-variant);
  min-width: 56px; text-align: right;
}
.bpm b { color: var(--on-surface); font-weight: 500; }

.keycap {
  min-width: 40px; height: 28px; padding: 0 9px;
  display: inline-grid; place-items: center;
  border-radius: var(--r-xs);
  background: var(--surface-2);
  font-size: 13px; font-weight: 500;
  color: var(--on-surface);
}

.badge {
  display: inline-flex; align-items: center; gap: 5px;
  height: 20px; padding: 0 8px;
  border-radius: var(--r-full);
  font-size: 11px; font-weight: 500; letter-spacing: .02em;
  background: var(--surface-3); color: var(--on-surface-variant);
  white-space: nowrap;
}
.badge--staple { background: var(--accent-green-bg);   color: var(--accent-green); }
.badge--alt    { background: var(--accent-purple-bg);  color: var(--accent-purple); }

.chevron { color: var(--on-surface-faint); display: flex; flex: none; }

/* ==========================================================================
   Song page
   ========================================================================== */

.song-hero { padding: 28px 0 8px; }

.backlink {
  display: inline-flex; align-items: center; gap: 6px;
  height: 32px; padding: 0 12px 0 8px;
  margin-left: -8px;
  border-radius: var(--r-full);
  font-size: 13px; font-weight: 500; color: var(--primary);
  transition: background .15s var(--ease);
}
.backlink:hover { background: var(--primary-container); }

.song-title {
  margin-top: 14px;
  font-family: var(--hand);
  font-size: 42px; font-weight: 400; letter-spacing: 0; line-height: 1.12;
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
}
.song-title__emoji { font-size: 24px; letter-spacing: 3px; }
.song-sub { margin-top: 8px; font-size: 14px; color: var(--on-surface-variant); }
.song-sub em { font-style: normal; color: var(--on-surface); }

.hero-badges { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; margin-top: 16px; }

/* Card -------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--outline-soft);
  border-radius: var(--r-lg);
  padding: 24px;
  margin-top: 20px;
}
.card--flush { padding: 0; overflow: hidden; }
.card__head {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 20px;
}
.card__head--tight { margin-bottom: 14px; }

/* Pill toggle — sits where a card title would, and switches what the card is. */
.pill-toggle {
  display: inline-flex;
  gap: 2px;
  padding: 4px;
  background: var(--surface-2);
  border-radius: var(--r-full);
}
.pill-toggle__btn {
  appearance: none; border: 0; background: transparent;
  height: 34px; padding: 0 17px;
  border-radius: var(--r-full);
  font-size: 14px; font-weight: 500;
  color: var(--on-surface-variant);
  cursor: pointer; white-space: nowrap;
  display: inline-flex; align-items: center; gap: 7px;
  transition: background .18s var(--ease), color .18s var(--ease), box-shadow .18s var(--ease);
}
.pill-toggle__btn:hover { color: var(--on-surface); }
.pill-toggle__btn[aria-pressed="true"] {
  background: var(--surface);
  color: var(--on-surface);
  box-shadow: var(--e1);
}
.pill-toggle__btn svg { flex: none; }
.card__title { font-size: 16px; font-weight: 500; }
.card__spacer { flex: 1; }
.card__hint { font-size: 12.5px; color: var(--on-surface-faint); }

.grid-2 { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 20px 32px; }

/* Fact list --------------------------------------------------------------- */

/* Tier one: the four you settle before the count-off. */
.facts-hero {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 12px;
  margin-bottom: 26px;
}
.fact-hero {
  display: flex; align-items: center; gap: 14px;
  padding: 15px 16px;
  border-radius: var(--r-md);
  background: var(--surface-2);
  min-width: 0;
}
.fact-hero__icon {
  width: 38px; height: 38px; flex: none;
  display: grid; place-items: center;
  border-radius: var(--r-full);
  background: var(--primary-container);
  color: var(--on-primary-container);
}
.fact-hero__text { min-width: 0; }
.fact-hero__label {
  font-size: 10.5px; font-weight: 500; letter-spacing: .07em; text-transform: uppercase;
  color: var(--on-surface-variant);
}
.fact-hero__value {
  margin-top: 2px;
  font-size: 17px; font-weight: 500; letter-spacing: -.01em;
  color: var(--on-surface);
}

/* Tier two: everything else, quieter. */
.facts { display: grid; grid-template-columns: repeat(auto-fill, minmax(196px, 1fr)); gap: 18px 24px; }
.fact { display: flex; gap: 10px; min-width: 0; }
.fact__icon { flex: none; margin-top: 1px; color: var(--on-surface-faint); display: flex; }
.fact__text { min-width: 0; }
.fact__label {
  font-size: 11px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase;
  color: var(--on-surface-faint);
}
.fact__value { margin-top: 2px; font-size: 14px; color: var(--on-surface); }
.fact__value.is-empty { color: var(--on-surface-faint); }

/* Callout ----------------------------------------------------------------- */

.callouts {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 24px;
}
@media (max-width: 720px) { .callouts { grid-template-columns: minmax(0, 1fr); } }
.callout {
  display: flex; gap: 10px;
  padding: 11px 13px;
  border-radius: var(--r-sm);
  background: var(--surface-2);
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--on-surface-variant);
}
.callout strong { color: var(--on-surface); font-weight: 500; }
.callout__icon { flex: none; margin-top: 1px; color: var(--on-surface-faint); display: flex; }

/* ==========================================================================
   Chord grid
   ========================================================================== */

.grid-controls {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin-bottom: 20px;
}

.field { display: inline-flex; flex-direction: column; gap: 5px; }
.field__label {
  font-size: 11px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase;
  color: var(--on-surface-faint);
}

.select {
  appearance: none;
  height: 40px;
  min-width: 96px;
  padding: 0 36px 0 14px;
  border: 1px solid var(--outline);
  border-radius: var(--r-sm);
  background: var(--surface) var(--select-chevron) no-repeat right 10px center;
  font-size: 14px;
  cursor: pointer;
  transition: border-color .15s var(--ease), background-color .15s var(--ease);
}
.select:hover { background-color: var(--surface-hover); }
.select:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }

.input {
  height: 40px;
  padding: 0 14px;
  border: 1px solid var(--outline);
  border-radius: var(--r-sm);
  background: var(--surface);
  width: 100%;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
.input:hover { border-color: var(--on-surface-faint); }
.input:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.input::placeholder { color: var(--on-surface-faint); }

.textarea {
  width: 100%;
  min-height: 340px;
  padding: 16px 18px;
  border: 1px solid var(--outline);
  border-radius: var(--r-md);
  background: var(--surface);
  font-family: var(--serif);
  font-size: 15.5px;
  line-height: 1.75;
  resize: vertical;
  transition: border-color .15s var(--ease), box-shadow .15s var(--ease);
}
.textarea:hover { border-color: var(--on-surface-faint); }
.textarea:focus { outline: none; border-color: var(--primary); box-shadow: 0 0 0 1px var(--primary); }
.textarea::placeholder { color: var(--on-surface-faint); font-family: var(--font); font-size: 14px; }

/* ==========================================================================
   Lyrics
   ========================================================================== */

.lyrics { position: relative; }
.lyrics__body {
  font-family: var(--serif);
  font-size: 16px;
  line-height: 1.8;
  color: var(--on-surface);
  max-width: 62ch;
  /* Two blank-line-separated stanzas become two paragraphs; single newlines
     inside a stanza are the line breaks the singer actually breathes on. */
  white-space: pre-line;
}
.lyrics__stanza + .lyrics__stanza { margin-top: 1.5em; }
.lyrics__actions { display: flex; gap: 8px; align-items: center; margin-top: 18px; }
.lyrics__meta { font-size: 12px; color: var(--on-surface-faint); }

/* The sheet — engraved like a lead-sheet page, not a card grid -------------- */

/* The chart is a page out of the same book as the repertoire spread. */
.card--sheet {
  padding: 26px 30px 30px;
  background: var(--paper);
  border-color: rgba(120, 108, 82, .16);
}

.sheet {
  --ink: #1f1c17;
  --ink-grey: #6f6a5f;
  --rule: #cdc7b6;
  color: var(--ink);
}

/* Chart head: feel on the left, title centred, composer right — the way a
   real chart in a fake book is laid out. */
.sheet__head {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: flex-end;
  gap: 16px;
  padding-bottom: 18px;
  margin-bottom: 26px;
  border-bottom: 1px solid var(--outline-soft);
}
/* No italic in the sheet head: Mansalva has no italic cut, and a
   synthetically slanted hand font reads as a rendering fault. */
.sheet__head-side {
  font-family: var(--hand);
  font-size: 15px;
  color: var(--on-surface-variant);
  min-width: 0;
}
.sheet__head-side--right { text-align: right; }
/* No nowrap: with `1fr auto 1fr` the title takes its natural width when there
   is room and wraps when there isn't. "Nobody Knows You When You're Down and
   Out" does not fit on a phone. */
.sheet__head-title {
  font-family: var(--hand);
  font-size: 26px; font-weight: 400; letter-spacing: .005em;
  text-align: center; min-width: 0; overflow-wrap: break-word;
}

/* A system = one line of the chart. The gutter holds the time signature and
   keeps every system's barlines aligned vertically. */
.system { display: grid; grid-template-columns: 44px 1fr; margin-bottom: 18px; }
.system:last-child { margin-bottom: 4px; }

.system__gutter {
  display: flex; align-items: center; justify-content: flex-end;
  padding-right: 13px;
}
.timesig {
  font-family: var(--hand);
  display: flex; flex-direction: column;
  line-height: .98; font-size: 26px; font-weight: 400;
  letter-spacing: -.02em; text-align: center;
}

.system__bars {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  border-left: 2.5px solid var(--ink);
}

.measure {
  position: relative;
  border-right: 1px solid var(--rule);
  min-height: 128px;
  padding: 24px 10px 18px;
  display: flex; align-items: center; justify-content: center;
}
.measure__num {
  position: absolute; top: 7px; left: 10px;
  font-family: var(--font);
  font-size: 10px; font-weight: 500;
  color: var(--on-surface-faint);
  font-variant-numeric: tabular-nums;
}

/* Final barline: thin, then thick, then the repeat dots — a blues form loops.
   The extra right padding keeps the last chord clear of the dots. */
.system--last .measure:last-child {
  border-right: 3.5px solid var(--ink);
  padding-right: 30px;
}
.system--last .measure:last-child::before {
  content: "";
  position: absolute; right: 5px; top: 0; bottom: 0;
  width: 1px; background: var(--ink);
}
.repeat-dots {
  position: absolute; right: 13px; top: 50%; transform: translateY(-50%);
  display: flex; flex-direction: column; gap: 8px;
}
.repeat-dots i { width: 4.5px; height: 4.5px; border-radius: 50%; background: var(--ink); }

/* Beats — one per chord in the bar. */
.measure__beats { display: flex; align-items: center; width: 100%; }
.beat {
  flex: 1; min-width: 0;
  display: flex; flex-direction: column; align-items: center;
  gap: 9px;
}
.beat + .beat { border-left: 1px dashed var(--outline); }

/* Numbers and chords are set at the same size — both need to be readable from
   a music stand. Colour carries the hierarchy instead: the number is the
   concept and gets the ink, the letter chord is just this week's key and sits
   back in grey. */
/* Mansalva ships one weight — asking for bold gets a synthesised smear, so
   both lines sit at 400 and colour alone carries the hierarchy. */
.beat__nash {
  font-family: var(--hand);
  font-size: 34px; font-weight: 400; line-height: 1;
  letter-spacing: .01em; white-space: nowrap;
  color: var(--ink);
}
.beat__nash sup { font-size: .44em; font-weight: 500; letter-spacing: 0; }

/* Accidentals are drawn (see ui.js accidentalGlyph) so their box is their ink
   and the spacing below is predictable on any machine. */
.beat .acc {
  display: inline-block;
  height: .60em;
  vertical-align: -.015em;
}
.beat .acc svg { display: block; width: 100%; height: 100%; overflow: visible; }
.beat .acc--flat { width: .28em; }
.beat .acc--sharp { width: .36em; }
.beat__nash .acc { margin-right: .07em; }                     /* leads:  ♭iii */
.beat__chord .acc { margin-left: .03em; margin-right: .05em; } /* trails: B♭  */

/* A slash bass sits smaller than the chord but far bigger than a superscript
   quality — it is a note you play, not a modifier. */
.beat__bass { font-size: .68em; letter-spacing: -.01em; }

.pulse { letter-spacing: -.14em; margin-right: .18em; }

.beat__chord {
  font-family: var(--hand);
  font-size: 34px; font-weight: 400; line-height: 1;
  letter-spacing: .01em; white-space: nowrap;
  color: var(--ink-grey);
}
.beat__chord sup { font-size: .44em; }

/* Chords-only mode promotes the letter chord into the headline slot. */
.beat--solo-chord .beat__chord { color: var(--ink); }

.measure--split .beat__nash,
.measure--split .beat__chord { font-size: 23px; }


/* ==========================================================================
   Scale-degree colour
   ==========================================================================
 * One hue per degree, keyed by semitones from the tonic, so a colour means the
 * same degree in every key. Hue follows the circle of fifths (step 11 of 12,
 * coprime, so all twelve are distinct): chords a fifth apart get neighbouring
 * hues, chromatic neighbours land opposite.
 *
 * Generated and validated with the dataviz validator against this paper
 * (#fdfcf6), not eyeballed. Worst adjacent CVD ΔE 9.2 — above the ≥8 target.
 * I/IV/V, the trio that carries a blues chart, clears 11.7 all-pairs.
 *
 * Twelve categories CANNOT be pairwise colourblind-distinct — the all-pairs
 * worst case is ΔE 2.3, and no ordering fixes that. It is acceptable here only
 * because colour is a secondary encoding: every measure prints its numeral and
 * its chord in ink, so identity is never carried by colour alone.
 *
 * The washes are pre-blended over the paper at 13%, so what ships is the
 * literal rendered value and the page still reads as a page.
 */
.sheet {
  --deg-0: #904700;  --wash-0: #efe4d6;   /* I    */
  --deg-1: #c86556;  --wash-1: #f6e8e1;   /* ♭II  */
  --deg-2: #ed86a7;  --wash-2: #fbedec;   /* II   */
  --deg-3: #853e80;  --wash-3: #ede3e7;   /* ♭III */
  --deg-4: #9372c8;  --wash-4: #efeaf0;   /* III  */
  --deg-5: #8ba6fd;  --wash-5: #eef1f7;   /* IV   */
  --deg-6: #00649e;  --wash-6: #dce8eb;   /* ♯IV  */
  --deg-7: #009ab1;  --wash-7: #dcefed;   /* V    */
  --deg-8: #1dc5ae;  --wash-8: #e0f5ed;   /* ♭VI  */
  --deg-9: #067132;  --wash-9: #ddeadd;   /* VI   */
  --deg-10: #7c9128; --wash-10: #eceedb;  /* ♭VII */
  --deg-11: #cba63a; --wash-11: #f7f1de;  /* VII  */
}

.measure[data-degree="0"]  { background: var(--wash-0); }
.measure[data-degree="1"]  { background: var(--wash-1); }
.measure[data-degree="2"]  { background: var(--wash-2); }
.measure[data-degree="3"]  { background: var(--wash-3); }
.measure[data-degree="4"]  { background: var(--wash-4); }
.measure[data-degree="5"]  { background: var(--wash-5); }
.measure[data-degree="6"]  { background: var(--wash-6); }
.measure[data-degree="7"]  { background: var(--wash-7); }
.measure[data-degree="8"]  { background: var(--wash-8); }
.measure[data-degree="9"]  { background: var(--wash-9); }
.measure[data-degree="10"] { background: var(--wash-10); }
.measure[data-degree="11"] { background: var(--wash-11); }

.chart-legend {
  display: flex; gap: 14px; flex-wrap: wrap; align-items: center;
  margin-top: 20px; font-size: 12px; color: var(--on-surface-variant);
}
.chart-legend span { display: inline-flex; align-items: center; gap: 6px; }
.chart-legend__note { color: var(--on-surface-faint); margin-left: 4px; }

/* The legend swatch carries the hue at full chroma — the wash is too pale to
   identify on its own at 12px. */
.swatch {
  width: 12px; height: 12px; border-radius: 3px;
  border: 1px solid rgba(0, 0, 0, .12);
  background: var(--paper);
}
.swatch[data-degree="0"]  { background: var(--deg-0); }
.swatch[data-degree="1"]  { background: var(--deg-1); }
.swatch[data-degree="2"]  { background: var(--deg-2); }
.swatch[data-degree="3"]  { background: var(--deg-3); }
.swatch[data-degree="4"]  { background: var(--deg-4); }
.swatch[data-degree="5"]  { background: var(--deg-5); }
.swatch[data-degree="6"]  { background: var(--deg-6); }
.swatch[data-degree="7"]  { background: var(--deg-7); }
.swatch[data-degree="8"]  { background: var(--deg-8); }
.swatch[data-degree="9"]  { background: var(--deg-9); }
.swatch[data-degree="10"] { background: var(--deg-10); }
.swatch[data-degree="11"] { background: var(--deg-11); }

/* ==========================================================================
   Backing tracks
   ========================================================================== */

.tracks { display: flex; flex-direction: column; gap: 12px; margin-bottom: 14px; }

.track {
  border: 1px solid var(--outline-soft);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  transition: box-shadow .18s var(--ease);
}
.track:hover { box-shadow: var(--e2); }

.track__video { position: relative; aspect-ratio: 16 / 9; background: var(--surface-3); }
/* Audio players are short fixed-height widgets, not 16:9 video. */
.track__video--fixed { aspect-ratio: auto; background: transparent; }
.track__video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* No embed available — tab sites, PDFs, anything else. */
.track__link-card {
  display: flex; align-items: center; gap: 10px;
  padding: 20px 16px;
  background: var(--surface-2);
  border-bottom: 1px solid var(--outline-soft);
  color: var(--on-surface-variant);
  transition: background .15s var(--ease), color .15s var(--ease);
}
.track__link-card:hover { background: var(--surface-3); color: var(--on-surface); }
.track__link-icon { display: flex; flex: none; color: var(--primary); }
.track__link-host {
  font-size: 13px; font-weight: 500;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.track__body { padding: 9px 10px 10px; display: flex; flex-direction: column; gap: 6px; }
.track__row { display: flex; align-items: center; gap: 4px; }
.track__name {
  width: 100%; min-width: 0;
  font-size: 13.5px; font-weight: 500; line-height: 1.3;
  border: 1px solid transparent; border-radius: var(--r-xs);
  padding: 4px 6px; margin: -2px -6px 0;
  background: transparent;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.track__name:hover { background: var(--surface-2); }
.track__name:focus { outline: none; background: var(--surface); border-color: var(--primary); }

/* Same, on the song page: a member sees the title, not a rename box. */
.track__name--static:hover { background: transparent; }

.track__keysel {
  height: 30px; min-width: 68px; padding: 0 26px 0 9px;
  font-size: 12.5px; font-weight: 500;
  background-position: right 7px center;
}

.track .icon-btn { width: 30px; height: 30px; }

/* Add-track form — sits at the bottom of the sidebar. */
.track-add {
  border: 1px dashed var(--outline);
  border-radius: var(--r-md);
  padding: 12px;
  display: flex; flex-direction: column; gap: 9px;
  background: var(--surface-1);
}
.track-add .input { height: 36px; font-size: 13px; }
.track-add__row { display: grid; grid-template-columns: 1fr auto; gap: 9px; align-items: center; }
.track-add__row .select { height: 36px; font-size: 13px; }
.track-add__row .btn { height: 36px; padding: 0 16px; font-size: 13px; }

/* Full-width sections have room to lay the form out in one line. */
.track-add--wide {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 260px) 128px auto;
  gap: 10px;
  align-items: center;
  padding: 14px;
}
/* Riffs and lessons carry no key, so the form loses a column. */
.track-add--nokey { grid-template-columns: minmax(0, 1fr) minmax(0, 260px) auto; }
.track-add--wide .select { height: 36px; font-size: 13px; }
.track-add--wide .btn { height: 36px; padding: 0 18px; font-size: 13px; }
@media (max-width: 860px) {
  .track-add--wide, .track-add--nokey { grid-template-columns: minmax(0, 1fr); }
}

/* Grooves ----------------------------------------------------------------- */

/* Sits above the book, not inside it — the spread is two columns, and a form
   rendered in there gets half the page and collapses its text inputs. */
.groove-add { margin: 0 0 18px; }
.groove-add__grid {
  display: grid;
  grid-template-columns: minmax(200px, 2fr) minmax(150px, 2fr) 140px 96px 132px 98px auto;
  gap: 10px;
  align-items: center;
}
.groove-add__grid .input, .groove-add__grid .select { height: 38px; font-size: 13px; min-width: 0; }
.groove-add__grid .btn { height: 38px; }
@media (max-width: 1180px) {
  .groove-add__grid { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .groove-add__grid .btn { grid-column: 1 / -1; }
}
@media (max-width: 560px) {
  .groove-add__grid { grid-template-columns: minmax(0, 1fr); }
}

/* Stacked rows, not cards. A groove costs about as much page as a song does:
   name and tags on the left, a small player on the right. */
.groove-list { display: flex; flex-direction: column; }

.groove-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 168px auto;
  gap: 14px;
  align-items: center;
  padding: 12px 14px;
  border-radius: var(--r-md);
  transition: background .12s var(--ease);
}
.groove-row:hover { background: rgba(120, 108, 82, .06); }
.groove-row + .groove-row::before {
  content: "";
  position: absolute; left: 14px; right: 14px; top: 0;
  height: 1px; background: var(--paper-rule); opacity: .55;
}
.groove-row:hover::before, .groove-row:hover + .groove-row::before { background: transparent; }

.groove-row__main { min-width: 0; display: flex; flex-direction: column; gap: 8px; }

.groove-row__name {
  width: 100%; min-width: 0;
  font-family: var(--hand);
  font-size: 19px; font-weight: 400; line-height: 1.2;
  border: 1px solid transparent; border-radius: var(--r-xs);
  padding: 3px 6px; margin: -3px -6px;
  background: transparent;
  transition: background .15s var(--ease), border-color .15s var(--ease);
}
.groove-row__name:hover { background: var(--surface-2); }
.groove-row__name:focus { outline: none; background: var(--surface); border-color: var(--primary); }

/* Members read the library rather than tag it — same type, no edit affordance. */
.groove-row__name--static:hover { background: transparent; }

.groove-row__controls { display: flex; gap: 6px; flex-wrap: wrap; }
.groove-row__sel {
  height: 30px; min-width: 0; flex: 1 1 76px; max-width: 122px;
  padding: 0 24px 0 8px;
  font-size: 12.5px; font-weight: 500;
  background-position: right 6px center;
}

.groove-row__thumb {
  position: relative;
  aspect-ratio: 16 / 9;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: var(--surface-3);
}
.groove-row__thumb iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

/* Poster + play badge. Clicking loads the docked player rather than trying to
   run a video in a box YouTube considers too small to play in. */
.groove-row__thumb--play {
  display: block; width: 100%; padding: 0;
  border: 0; cursor: pointer;
  background-size: cover; background-position: center;
  transition: transform .15s var(--ease), box-shadow .15s var(--ease);
}
.groove-row__thumb--play:hover { box-shadow: var(--e2); }
.groove-row__thumb--play:hover .groove-row__play { background: #ff0033; transform: scale(1.06); }
.groove-row__thumb--noposter {
  background: linear-gradient(135deg, var(--surface-3), var(--surface-2));
}
.groove-row__provider {
  position: absolute; top: 6px; left: 8px;
  font-size: 10.5px; font-weight: 500; letter-spacing: .04em;
  color: var(--on-surface-variant);
}
.groove-row__play {
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  width: 40px; height: 28px;
  display: grid; place-items: center;
  border-radius: 7px;
  background: rgba(20, 20, 24, .78);
  color: #fff;
  transition: background .15s var(--ease), transform .15s var(--ease);
}
.groove-row.is-playing { background: var(--primary-container); }
.groove-row.is-playing .groove-row__play { background: #ff0033; }

/* ==========================================================================
   Docked player
   ========================================================================== */

.groove-dock {
  position: fixed;
  right: 20px; bottom: 20px;
  z-index: 60;
  width: 380px; max-width: calc(100vw - 32px);
  border-radius: var(--r-md);
  overflow: hidden;
  background: var(--surface);
  box-shadow: var(--e3), 0 0 0 1px rgba(0, 0, 0, .18);
}
.groove-dock__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  grid-template-areas: "title close" "meta close";
  align-items: center;
  gap: 0 8px;
  padding: 9px 8px 9px 14px;
}
.groove-dock__title {
  grid-area: title;
  font-family: var(--hand);
  font-size: 17px; line-height: 1.2;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.groove-dock__meta {
  grid-area: meta;
  font-size: 11.5px; color: var(--on-surface-variant);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.groove-dock__head .icon-btn { grid-area: close; }
.groove-dock__video { position: relative; aspect-ratio: 16 / 9; background: #000; }
.groove-dock__video iframe { position: absolute; inset: 0; width: 100%; height: 100%; border: 0; }

@media (max-width: 560px) {
  .groove-dock { right: 8px; left: 8px; bottom: 8px; width: auto; }
}
.groove-row__thumb--link {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 5px;
  background: var(--surface-2);
  color: var(--on-surface-variant);
  font-size: 11.5px; font-weight: 500;
  text-align: center; padding: 8px;
}
.groove-row__thumb--link:hover { background: var(--surface-3); color: var(--on-surface); }

.groove-row__actions { display: flex; flex-direction: column; gap: 2px; }

/* One column of the spread is narrow — below this the player drops under the
   tags rather than squeezing both. */
@media (max-width: 900px) {
  .groove-row { grid-template-columns: minmax(0, 1fr) 128px auto; gap: 10px; }
}
@media (max-width: 560px) {
  .groove-row { grid-template-columns: minmax(0, 1fr) auto; }
  .groove-row__thumb { grid-column: 1 / -1; max-width: 260px; }
}

/* Riffs and lessons: roomier than the sidebar, since they have the full width. */
.video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(290px, 1fr));
  gap: 16px;
  margin-bottom: 16px;
}

/* Stacked layout gives the sidebar full width — spread the tracks out again. */
@media (max-width: 1080px) {
  .tracks {
    display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
    gap: 16px;
  }
}

/* ==========================================================================
   Buttons
   ========================================================================== */

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  height: 40px; padding: 0 22px;
  border: 0; border-radius: var(--r-full);
  font-size: 14px; font-weight: 500;
  cursor: pointer;
  background: var(--primary); color: var(--on-primary);
  transition: box-shadow .15s var(--ease), background .15s var(--ease), opacity .15s var(--ease);
  white-space: nowrap;
}
.btn:hover { background: var(--primary-hover); box-shadow: var(--e1); }
.btn:disabled { opacity: .45; cursor: not-allowed; box-shadow: none; }

.btn--tonal { background: var(--primary-container); color: var(--on-primary-container); }
.btn--tonal:hover { background: #d9e6fd; }

.btn--text { background: transparent; color: var(--primary); padding: 0 14px; }
.btn--text:hover { background: var(--primary-container); box-shadow: none; }

.btn--outline {
  background: var(--surface); color: var(--on-surface-variant);
  border: 1px solid var(--outline);
}
.btn--outline:hover { background: var(--surface-hover); box-shadow: none; }

.icon-btn {
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: var(--r-full);
  background: transparent; color: var(--on-surface-variant);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease);
}
.icon-btn:hover { background: var(--surface-3); color: var(--on-surface); }
.icon-btn--danger:hover { background: var(--accent-red-bg); color: var(--accent-red); }

/* ==========================================================================
   Empty / loading / toast
   ========================================================================== */

.empty {
  padding: 72px 24px;
  text-align: center;
  color: var(--on-surface-variant);
}
.empty__icon { font-size: 40px; margin-bottom: 12px; opacity: .5; }
.empty__title { font-size: 16px; font-weight: 500; color: var(--on-surface); margin-bottom: 4px; }

.skeleton {
  background: linear-gradient(90deg, var(--surface-2) 25%, var(--surface-3) 37%, var(--surface-2) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.3s ease-in-out infinite;
  border-radius: var(--r-sm);
}
@keyframes shimmer { 0% { background-position: 100% 0; } 100% { background-position: -100% 0; } }

.toast {
  position: fixed; left: 50%; bottom: 28px; transform: translate(-50%, 90px);
  z-index: 90;
  max-width: min(520px, calc(100vw - 32px));
  padding: 14px 20px;
  border-radius: var(--r-xs);
  background: #303134; color: #e8eaed;
  font-size: 13.5px;
  box-shadow: var(--e3);
  opacity: 0;
  transition: transform .28s var(--ease), opacity .28s var(--ease);
  pointer-events: none;
}
.toast.is-open { transform: translate(-50%, 0); opacity: 1; }

/* ==========================================================================
   Responsive
   ========================================================================== */

/* The chart sizes itself against its own column, not the viewport — the
   sidebar takes a fixed slice out of the page, so viewport width is the wrong
   question to ask. */
@container chart (max-width: 840px) {
  .beat__nash, .beat__chord { font-size: 28px; }
  .measure--split .beat__nash, .measure--split .beat__chord { font-size: 19px; }
  .measure { min-height: 112px; }
  .sheet__head-title { font-size: 19px; }
}
@container chart (max-width: 620px) {
  .beat__nash, .beat__chord { font-size: 24px; }
  .measure--split .beat__nash, .measure--split .beat__chord { font-size: 16px; }
  .measure { min-height: 100px; padding: 20px 6px 14px; }
  .system { grid-template-columns: 34px 1fr; }
  .system__gutter { padding-right: 9px; }
  .timesig { font-size: 19px; }
}
/* Four bars a line stops being legible below this, so the phrase wraps to two.
   The barlines and the final repeat still land correctly. */
@container chart (max-width: 430px) {
  .system__bars { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .beat__nash, .beat__chord { font-size: 30px; }
  .measure--split .beat__nash, .measure--split .beat__chord { font-size: 20px; }
  .measure { min-height: 116px; }
}

@media (max-width: 900px) {
  .song-title { font-size: 27px; }
}

@media (max-width: 720px) {
  .appbar__inner { padding: 0 16px; height: 60px; gap: 10px; }
  .page { padding: 0 16px 80px; }
  .card { padding: 18px; }
  .card--sheet { padding: 18px 16px 22px; }
  .song-row { padding: 12px 10px; grid-template-columns: 1fr auto; }
  .bpm { display: none; }
  .sheet__head { grid-template-columns: 1fr; gap: 2px; text-align: center; }
  .sheet__head-side, .sheet__head-side--right { text-align: center; }
  .facts-hero { grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 10px; }
  .fact-hero { padding: 12px 13px; gap: 11px; }
  .fact-hero__icon { width: 34px; height: 34px; }
  .fact-hero__value { font-size: 15.5px; }
}

@media (max-width: 460px) {
  .brand__title { font-size: 17px; }
  .segmented__btn { padding: 0 13px; font-size: 12.5px; }
  .segmented__btn .seg-label { display: none; }
  .segmented__btn .seg-label--short { display: inline; }
}
.seg-label--short { display: none; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ==========================================================================
   Sign-in — the cover of the book
   ==========================================================================
 * Modelled on a Real Book cover: cream board, double-rule frame with corner
 * flourishes, edition mark, oversized hand-cut title stacked bottom-right, and
 * a plastic comb binding down the spine.
 *
 * The Google button keeps its own white surface and official mark rather than
 * being restyled into the cream — brand compliance, and it reads as a label
 * affixed to the cover instead of a web widget dropped on top of it.
 */

/* The stage used to claim 100vh on its own, which pushed the credit mounted
   after it below the fold. The page is the column now, and the stage takes
   what is left once the credit has its line. */
.cover-page {
  background: var(--backdrop);
  min-height: 100vh;
  display: flex; flex-direction: column;
}

.cover-stage {
  flex: 1 1 auto; min-height: 0;
  display: grid;
  align-content: center; justify-items: center;
  padding: 32px 20px;
}

.cover-page .credit { flex: none; padding-top: 4px; }

.cover {
  position: relative;
  /* Sized by the height available, not by width alone. Driving it from width
     meant a 3:4 board 640px tall in a 390px-tall landscape window — the page
     scrolled and the cover ran off the screen. Height-first with a max-width
     clamp satisfies both axes and keeps the proportion on every screen. */
  /* Width-driven, with the available height folded into the same min() so one
     value satisfies both axes. Two earlier attempts failed here: height:100%
     never resolved (the stage is a stretched grid item, so its height is not
     definite) and collapsed the board to 52x69; and a definite height with
     max-width did not clamp the transferred width, leaving a 480px board in a
     412px viewport and a sideways scroll. dvh rather than vh so mobile browser
     chrome appearing and going does not clip it. */
  width: min(480px, 100%, calc((100dvh - 120px) * 3 / 4));
  height: auto;
  aspect-ratio: 3 / 4;
  container-type: inline-size;
  padding: 26px 30px 30px 44px;   /* extra left for the binding */
  background:
    /* faint tooth so the board is not a flat fill */
    radial-gradient(circle at 22% 18%, rgba(255,255,255,.55), transparent 55%),
    #f7efd4;
  border-radius: 2px 5px 5px 2px;
  box-shadow:
    0 0 0 1px rgba(60, 48, 20, .22),
    0 26px 60px -22px rgba(0, 0, 0, .75);
}

/* Comb binding: black teeth, the backdrop showing through the gaps. */
.cover__binding {
  position: absolute; left: -7px; top: 14px; bottom: 14px;
  width: 34px;
  background: repeating-linear-gradient(
    to bottom,
    #14141a 0 23px,
    transparent 23px 32px);
  /* Rounds the outer end of every tooth at once. */
  -webkit-mask-image: radial-gradient(circle at 100% 50%, #000 99%, transparent 100%),
                      linear-gradient(#000, #000);
  -webkit-mask-size: 100% 100%, calc(100% - 8px) 100%;
  -webkit-mask-position: 0 0, 8px 0;
  -webkit-mask-repeat: no-repeat;
  mask-image: radial-gradient(circle at 100% 50%, #000 99%, transparent 100%),
              linear-gradient(#000, #000);
  mask-size: 100% 100%, calc(100% - 8px) 100%;
  mask-position: 0 0, 8px 0;
  mask-repeat: no-repeat;
  pointer-events: none;
  filter: drop-shadow(1px 0 1px rgba(0, 0, 0, .5));
}

.cover__frame {
  position: relative;
  height: 100%;
  border: 2.5px solid #17150f;
  outline: 1px solid #17150f;
  outline-offset: 4px;
  padding: 26px 22px 22px;
  display: flex; flex-direction: column;
  color: #17150f;
}

.cover__corner { position: absolute; width: 42px; height: 42px; color: #17150f; }
.cover__corner--tl { top: 5px; left: 5px; }
.cover__corner--tr { top: 5px; right: 5px; transform: scaleX(-1); }
.cover__corner--br { bottom: 5px; right: 5px; transform: scale(-1); }
.cover__corner--bl { bottom: 5px; left: 5px; transform: scaleY(-1); }

.cover__edition {
  font-family: var(--font);
  font-size: 12px; font-weight: 500;
  letter-spacing: .17em; text-transform: uppercase;
  line-height: 1.45;
  transform: rotate(-1.5deg);
  align-self: flex-start;
}

/* The recognisable part is the composition: oversized, tightly stacked,
   right-aligned, each line kicked a degree or two off true. */
.cover__title {
  margin-top: auto;
  font-family: "Passion One", Impact, sans-serif;
  font-weight: 900;
  font-size: clamp(42px, 16cqw, 78px);
  line-height: .82;
  letter-spacing: .005em;
  text-transform: uppercase;
  text-align: right;
  align-self: flex-end;
}
.cover__title span { display: block; }
.cover__title span:nth-child(1) { transform: rotate(-2deg); }
.cover__title span:nth-child(2) { transform: rotate(1.2deg); }
.cover__title span:nth-child(3) { transform: rotate(-.8deg); }

.cover__plate { margin-top: auto; padding-top: 22px; }

.cover__error {
  margin-bottom: 14px; padding: 9px 12px;
  border: 1.5px solid #8c2f28;
  border-radius: 2px;
  background: rgba(140, 47, 40, .08);
  color: #7a2820;
  font-size: 12.5px; line-height: 1.45;
  text-align: center;
}

/* Google's light button: white surface, its own mark, Roboto Medium. */
.gbtn {
  display: flex; align-items: center; justify-content: center; gap: 11px;
  height: 44px;
  border: 1px solid #17150f;
  border-radius: 3px;
  background: #fff; color: #3c4043;
  font-family: var(--font);
  font-size: 14px; font-weight: 500;
  box-shadow: 3px 3px 0 rgba(23, 21, 15, .9);
  transition: transform .12s var(--ease), box-shadow .12s var(--ease);
}
.gbtn:hover { transform: translate(-1px, -1px); box-shadow: 4px 4px 0 rgba(23, 21, 15, .9); }
.gbtn:active { transform: translate(1px, 1px); box-shadow: 2px 2px 0 rgba(23, 21, 15, .9); }
.gbtn__logo { width: 18px; height: 18px; flex: none; }

/* No credentials configured: the button stays visible so the cover still reads
   as a sign-in gate, but it is inert and looks it. */
.gbtn--disabled {
  background: #e6e2d6; color: #6b6659;
  box-shadow: 2px 2px 0 rgba(23, 21, 15, .35);
  cursor: not-allowed;
}
.gbtn--disabled:hover, .gbtn--disabled:active {
  transform: none; box-shadow: 2px 2px 0 rgba(23, 21, 15, .35);
}

.cover__note {
  margin-top: 14px;
  font-family: var(--hand);
  font-size: 14px;
  text-align: center;
  color: #4a4433;
}

@media (max-width: 480px) {
  /* Chrome tightens on a phone, but the board keeps its proportion — dropping
     aspect-ratio here collapsed it to content height, a squat card adrift in
     ~244px of empty space above and below. */
  .cover {
    padding: 16px 16px 20px 36px;
    width: min(480px, 100%, calc((100dvh - 96px) * 3 / 4));  /* tighter chrome */
  }
  /* The comb binding hangs 7px past the board, so the stage keeps enough
     inset that the teeth are not flush against the screen edge. */
  .cover-stage { padding: 20px 15px; }
  .cover__frame { padding: 20px 16px 18px; gap: 26px; }
  .cover__title { font-size: clamp(30px, 15cqw, 43px); }
}

/* ==========================================================================
   Account chip
   ========================================================================== */

.account { position: relative; }
.account__btn {
  width: 34px; height: 34px; padding: 0;
  border: 0; border-radius: var(--r-full);
  background: transparent; cursor: pointer;
  display: grid; place-items: center;
}
.account__btn:hover { box-shadow: 0 0 0 2px var(--outline); }
.account__avatar {
  width: 30px; height: 30px; border-radius: var(--r-full);
  object-fit: cover; display: block;
}
.account__avatar--letter {
  display: grid; place-items: center;
  background: var(--primary-container); color: var(--on-primary-container);
  font-size: 13px; font-weight: 500;
}
.account__menu {
  position: absolute; right: 0; top: calc(100% + 8px);
  z-index: 70;
  width: 244px; padding: 16px;
  border-radius: var(--r-md);
  background: var(--surface);
  box-shadow: var(--e3), 0 0 0 1px var(--outline-soft);
  text-align: center;
}
.account__who { margin-bottom: 14px; }
.account__name { font-size: 14px; font-weight: 500; }
.account__email {
  margin-top: 2px; font-size: 12px; color: var(--on-surface-variant);
  overflow: hidden; text-overflow: ellipsis;
}
.account__who .badge { margin-top: 8px; }
.account__signout { width: 100%; }

/* ==========================================================================
   My Book ribbon
   ========================================================================== */

/* Sits inside the row link, so it stops the click itself (see repertoire.js). */
.bookmark {
  width: 30px; height: 30px; flex: none;
  display: grid; place-items: center;
  border: 0; border-radius: var(--r-full);
  background: transparent;
  color: var(--on-surface-faint);
  cursor: pointer;
  transition: background .15s var(--ease), color .15s var(--ease), transform .12s var(--ease);
}
.bookmark:hover { background: rgba(120, 108, 82, .12); color: var(--on-surface); }
.bookmark:active { transform: scale(.9); }
.bookmark.is-on { color: #c0392b; }
.bookmark.is-on:hover { color: #96291d; }

/* ==========================================================================
   Admin — who has signed in
   ========================================================================== */

.users { display: flex; flex-direction: column; }
.user-row {
  display: grid;
  grid-template-columns: 34px minmax(0, 1fr) auto auto;
  gap: 12px; align-items: center;
  padding: 10px 4px;
}
.user-row + .user-row { border-top: 1px solid var(--outline-soft); }
.user-row__avatar {
  width: 30px; height: 30px; border-radius: var(--r-full);
  object-fit: cover; display: block;
  background: var(--surface-2);
}
.user-row__avatar--letter {
  display: grid; place-items: center;
  background: var(--primary-container); color: var(--on-primary-container);
  font-size: 13px; font-weight: 500;
}
.user-row__name { font-size: 14px; font-weight: 500; }
.user-row__email {
  font-size: 12px; color: var(--on-surface-variant);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-row__count {
  font-size: 12px; color: var(--on-surface-variant);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* ==========================================================================
   Buttons printed on the page
   ==========================================================================
 * A button sitting on the book's paper should be set like the book, not like
 * the app chrome around it: ink rule, hard offset shadow, letterspaced serif
 * caps to match the section heads. Same letterpress idea as the sign-in
 * button, applied only where there is actual paper under it.
 *
 * Scoped to .book so it never leaks into the toolbar or the cards.
 */
[data-theme] .book .btn {
  height: 40px;
  padding: 0 22px;
  border-radius: 2px;
  border: 1.5px solid #17150f;
  background: transparent;
  color: #17150f;
  font-family: var(--serif);
  font-size: 12px; font-weight: 600;
  letter-spacing: .14em; text-transform: uppercase;
  box-shadow: 3px 3px 0 #17150f;
  transition: transform .12s var(--ease), box-shadow .12s var(--ease),
              background .15s var(--ease);
}
[data-theme] .book .btn:hover {
  background: rgba(23, 21, 15, .06);
  transform: translate(-1px, -1px);
  box-shadow: 4px 4px 0 #17150f;
}
[data-theme] .book .btn:active {
  transform: translate(1px, 1px);
  box-shadow: 2px 2px 0 #17150f;
}

/* Account menu — admin tools */
.account__link {
  display: flex; align-items: center; gap: 9px;
  margin: 0 -6px 10px;
  padding: 8px 10px;
  border-radius: var(--r-sm);
  font-size: 13.5px; font-weight: 500;
  color: var(--on-surface);
  text-align: left;
  transition: background .15s var(--ease);
}
.account__link:hover { background: var(--surface-2); }
.account__link svg { color: var(--on-surface-variant); flex: none; }

/* Users view */
.user-row--wide { grid-template-columns: 34px minmax(0, 1fr) 84px 92px 108px 108px; }
.user-row--head {
  font-size: 11px; font-weight: 500; letter-spacing: .06em; text-transform: uppercase;
  color: var(--on-surface-faint);
  padding-bottom: 8px;
}
.user-row--head + .user-row { border-top: 0; }
@media (max-width: 760px) {
  .user-row--wide { grid-template-columns: 34px minmax(0, 1fr) auto; }
  .user-row--wide > :nth-child(n + 4) { display: none; }
  .user-row--head { display: none; }
}

/* ==========================================================================
   Credit
   ==========================================================================
 * One quiet line at the foot of every page. Deliberately not a full footer:
 * there is nothing else to put in it, and a rule plus columns would give the
 * page a heavier ending than the content deserves.
 */

.credit {
  display: flex; align-items: center; justify-content: center;
  flex-wrap: wrap; gap: 6px;
  /* The theme switch is fixed in the bottom-right corner, so the line keeps
     clear of it rather than sliding underneath at the end of a scroll. */
  padding: 24px 76px 30px;
  font-size: 12.5px;
  /* Light weight so the line sits back from the page; the name is the only
     part meant to carry any emphasis. */
  font-weight: 300;
  color: var(--on-surface-variant);
}
.credit__link {
  display: inline-flex; align-items: center; gap: 5px;
  font-weight: 300;
  color: var(--on-surface-variant);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  transition: color .15s var(--ease), border-color .15s var(--ease);
}
.credit__link:hover,
.credit__link:focus-visible { color: var(--on-surface); border-bottom-color: currentColor; }
/* The byline is the one thing here worth reading, so it gets the full
   foreground tone while everything around it stays muted. */
.credit__link--name { color: var(--on-surface); font-weight: 400; }
[data-theme="dark"] .credit__link--name { color: #fff; }

.credit__icon { flex: none; opacity: .9; }
.credit__at { opacity: .65; }

@media (max-width: 560px) {
  .credit { padding: 20px 20px 64px; gap: 5px; font-size: 12px; }
}
