/* Piano specific styles */

:root {
    --chassis-color: #1E7F50;
    --chassis-dark: #16613c;
    --bg: #D1D1D6;
    --bg-grad-a: #D8D8DC;
    --bg-grad-b: #C8C8CD;
    --toolbar-bg: rgba(0, 0, 0, 0.5);
    --toolbar-border: rgba(255,255,255,0.12);
    --white-key: #fafafa;
    --white-key-active: #c8c8c8;
    --white-key-shadow: rgba(0,0,0,0.08);
    --white-key-border: rgba(0,0,0,0.06);
    --black-key: #1c1c1c;
    --black-key-top: #2a2a2a;
    --black-key-active: #5a5a5a;
    --white-label-color: #000;
    --white-hint-color: #000;
    --black-label-color: #fff;
    --black-hint-color: #fff;
    --input-control-text: #000;
    --key-gap: 4px;
    --radius: 16px;
    --text: #222;
    --text-dim: rgba(0,0,0,0.45);
    --group-bg: rgba(0,0,0,0.05);
    --btn-bg: rgba(0,0,0,0.07);
    --btn-hover: rgba(0,0,0,0.12);
    --white-key-w: 60px;
    --navbar-counterheight: 128px;
    --song-chip-bg: rgba(0, 0, 0, 0.07);
    --song-chip-hover: rgba(0, 0, 0, 0.12);
    --bottom-swatch-size: 48px;
    --bottom-swatch-border: 4px;
}

body.dark-bg {
    --bg: #121212;
    --bg-grad-a: #1e1e1e;
    --bg-grad-b: #0a0a0a;
    --text: #fff;
    --text-dim: rgba(255,255,255,0.5);
    --group-bg: rgba(255,255,255,0.06);
    --btn-bg: rgba(255,255,255,0.1);
    --btn-hover: rgba(255,255,255,0.18);
    --song-chip-bg: rgba(255, 255, 255, 0.1);
    --song-chip-hover: rgba(255, 255, 255, 0.18);
}
body.dark-keys {
    --white-key: #2a2a2a;
    --white-key-active: #444;
    --white-key-shadow: rgba(0,0,0,0.3);
    --white-key-border: rgba(0,0,0,0.2);
    --black-key: #d0d0d0;
    --black-key-top: #e0e0e0;
    --black-key-active: #999;
    --white-label-color: #fff;
    --white-hint-color: #fff;
    --black-hint-color: #000;
    --black-label-color: #000;
    --input-control-text: #fff;
}

html {
    height: 100%;
    width: 100%;
    overflow-x: hidden;
    background: var(--bg);
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
}

body {
    min-height: 100%;
    min-height: 100dvh;
    width: 100%;
    overflow-x: hidden;
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    background: radial-gradient(ellipse at 50% 40%, var(--bg-grad-a), var(--bg-grad-b));
    color: var(--text);
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    user-select: none;
    -webkit-user-select: none;
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    display: flex;
    flex-direction: column;
}

/* ========== TOOLBAR ========== */

#toolbar {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    padding: 10px 16px;
    margin: 10px 12px 0;
    background: var(--toolbar-bg);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1px solid var(--toolbar-border);
    border-radius: 14px;
    flex-shrink: 0;
    z-index: 10;
    flex-wrap: wrap;
    color: #fff;
}

#toolbar .spacer {
    flex: 1;
    min-width: 4px;
}

.app-icon {
    flex-shrink: 0;
    border-radius: 5px;
}

/* Scribe toolbar icon: 24×24 indigo tile with the white wordmark
   glyph. Sources the canonical images/Scribe.svg directly so we
   don't duplicate path data — the wrapper paints the indigo
   background and `filter: invert(1)` flips the SVG's black source
   pixels to white. Same trick as `.menu-icon-scribe` in shared.css. */
.app-icon.app-icon-scribe {
    width: 24px;
    height: 24px;
    background: #5856D6;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    overflow: hidden;
}
.app-icon.app-icon-scribe img {
    width: 100%;
    height: 100%;
    display: block;
    filter: invert(1);
}

#toolbar .app-title {
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.3px;
    white-space: nowrap;
    margin-right: 6px;
}

#appstore-link {
    flex-shrink: 0;
    transition: opacity 0.15s;
    padding-left: 8px;
}
#appstore-link:hover { opacity: 0.8; }
#appstore-link img { height: 28px; display: block; }

#toolbar-groups {
    display: contents;
}

.toolbar-action-controls {
    display: flex;
    align-items: center;
    gap: 6px;
}

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

.toolbar-group label {
    display: none;
}

#sound-group,
#labels-group {
    background: var(--group-bg);
    padding: 4px 8px;
    border-radius: 10px;
}

#sound-group label,
#labels-group label {
    display: block;
    font-size: 11px;
    font-weight: 600;
    color: rgba(255, 255, 255, 0.72);
    text-transform: uppercase;
    letter-spacing: 0.5px;
    opacity: 1;
}

#dark-group {
    flex-wrap: wrap;
}.toolbar-divider {
    width: 1px;
    height: 24px;
    background: rgba(255, 255, 255, 0.2);
    margin: 0 4px;
}

.dropdown-menu {
    position: absolute;
    top: 100%;
    left: 0;
    margin-top: 8px;
    background: var(--toolbar-bg, rgba(255,255,255,0.95));
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1px solid var(--toolbar-border, rgba(0,0,0,0.1));
    border-radius: 12px;
    padding: 8px;
    display: none;
    flex-direction: column;
    gap: 4px;
    min-width: 200px;
    z-index: 100;
}
.dropdown-menu.open {
    display: flex;
}
.menu-item {
    padding: 10px 14px;
    border-radius: 8px;
    text-decoration: none;
    color: #fff;
    font-size: 14px;
    font-weight: 500;
    transition: background 0.15s;
    white-space: nowrap;
    display: flex;
    align-items: center;
    gap: 10px;
    background: none;
    border: none;
    cursor: pointer;
    width: 100%;
    text-align: left;
}
.menu-icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
}
.menu-item:hover {
    background: rgba(255,255,255,0.12);
}

/* Piano-specific toolbar overrides - force white text on dark toolbar */
#toolbar, #toolbar * {
    color: #fff;
}

.toolbar-btn.active { background: var(--chassis-color); color: #fff; }
.toolbar-btn:disabled { opacity: 0.4; pointer-events: none; }

select.toolbar-select {
    background: rgba(255,255,255,0.1);
    border: none;
    color: #fff;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    font-size: 14px;
    font-weight: 600;
    padding: 6px 14px;
    border-radius: 999px;
    cursor: pointer;
    outline: none;
}
select.toolbar-select option { background: #222; color: #fff; }

/* Ilo area is a parallel sibling to #piano-area. Hidden by default;
   visible only in scribe-ilo-mode. Follows the same overlay migration. */
#scribe-ilo-area {
    display: none;
    flex-direction: column;
    align-items: center;
    width: 100%;
}
body.scribe-ilo-mode #scribe-ilo-area { display: flex; }
body.scribe-ilo-mode #piano-area      { display: none; }

body.scribe-instrument-hidden #piano-area,
body.scribe-instrument-hidden #scribe-ilo-area { display: none; }

body:not(.has-floating-piano).piano-collapsed #piano-area,
body:not(.has-floating-piano).piano-collapsed #scribe-ilo-area { display: none; }

/* Labels are always on in ilo mode — the toggle is meaningless there. */
body.scribe-ilo-mode #labels-group    { display: none; }

/* Scribe ilo uses the same compact overlay form as contentview's floating
   ilophone — compact chassis, key-hints hidden, bars sized to match piano
   key widths. Always shows this way (both inline and in the floating overlay). */
#scribe-ilo {
    width: max-content;
    max-width: calc(100vw - 16px);
    flex-shrink: 0;
    /* Compact height: bar height (white-key-h + title-bar 24px + gap 4px) + chassis padding (4px top + 4px bottom) */
    height: calc(var(--white-key-h, 145px) + 36px);
    padding-bottom: 0;
    --instrument-color: var(--chassis-color, #1E7F50);
    --il-key-hints-display: none;
    --il-chassis-pad: 4px;
    --il-chassis-radius: 16px;
    --il-chassis-shadow: 0 2px 6px rgba(0,0,0,0.2), 0 8px 24px rgba(0,0,0,0.22);
    --il-bar-w: var(--white-key-w);
    --bar-gap: var(--key-gap, 4px);
    --il-bar-radius: var(--white-key-r);
    --il-first-bar-radius: 12px var(--white-key-r) var(--white-key-r) 12px;
    --il-last-bar-radius: var(--white-key-r) 12px 12px var(--white-key-r);
    --il-label-size: 14px;
    --il-label-weight: 600;
    --il-muted-bar-size: 10px;
}

/* In floating overlay: zero-width container + explicit ilo width,
   mirrors the #piano-area / #piano-container treatment. */
body.has-floating-piano #floating-piano-wrap > #scribe-ilo-area {
    position: static;
    width: 0; min-width: 0;
    overflow: visible;
    align-items: center;
    transition: opacity 0.2s, max-height 0.2s;
    max-height: 500px;
}
body.has-floating-piano #floating-piano-wrap #scribe-ilo {
    width: max-content;
    max-width: calc(100vw - 16px);
    overflow: visible;
    border-radius: var(--il-chassis-radius, 16px);
}
body.has-floating-piano.piano-collapsed #floating-piano-wrap > #scribe-ilo-area {
    opacity: 0; max-height: 0; pointer-events: none;
}

#color-toggle {
    background: none;
    border: none;
    cursor: pointer;
    padding: 0;
    transition: transform 0.15s;
    flex-shrink: 0;
}
#color-toggle:hover { transform: scale(1.1); }
#color-toggle:active { transform: scale(0.95); }

/* Swatch lives in the top toolbar — size it to match the toolbar row height */
#toolbar #color-swatch {
    width: 28px;
    height: 28px;
    border-width: 2px;
}

/* Record controls + the bottom bar that houses them are hidden for now */
#rec-controls { display: none; }
#bottom-bar { display: none; }

.color-swatch {
    display: block;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 4px solid #fff;
    flex-shrink: 0;
}

/* Duo-tone color picker: left half tracks the current page light/dark
   mode (white in light, black in dark); right half is the current
   chassis color. Tapping the left half toggles dark-bg, the right
   half cycles color — see the #color-toggle click handler below.
   Only applied to the toolbar swatch, not the rec-swatch (which shares
   the .color-swatch class). */
#color-swatch {
    --swatch-left: #fff;
    --swatch-right: var(--chassis-color, #1E7F50);
    background: linear-gradient(
        to right,
        var(--swatch-left) 0 50%,
        var(--swatch-right) 50% 100%
    );
    position: relative;
}
body.dark-bg #color-swatch {
    --swatch-left: #000;
}

/* Inner circle: represents current piano-key shade (white = light keys, black = dark keys).
   Tapping it toggles the Dark Keys mode. */
#key-toggle-dot {
    position: absolute;
    width: 40%;
    height: 40%;
    border-radius: 50%;
    background: #fff;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    box-shadow: 0 0 0 1.5px rgba(0,0,0,0.18);
    cursor: pointer;
    pointer-events: auto;
}
body.dark-keys #key-toggle-dot {
    background: #000;
    box-shadow: 0 0 0 1.5px rgba(255,255,255,0.25);
}

/* Recording styles now in shared.css */

/* ========== INSTRUMENT AREA ========== */

#instrument-area {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 0;
    min-height: 0;
    position: relative;
}

/* Large Desktop: cap the song row independently of notation zoom.
   Piano's keyboard stays full-width since it scrolls internally. */
#instrument-area > #song-row {
    max-width: 1300px;
    width: 100%;
    margin-inline: auto;
    align-self: stretch;
}

#content-view > #notation-area {
    max-width: var(--scribe-notation-area-max, 1300px);
    width: 100%;
    margin-inline: auto;
    align-self: stretch;
}
@media (min-height: 801px) {
    body:not(.notation-zoom-override) #content-view > #notation-area {
        --scribe-notation-area-max: 1625px;
    }
}

/* Content view is a VStack grouping notation area and piano area together
   with flex spacers above/below and a capped spacer in between. */
#content-view {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    flex: 1;
}

/* Piano area groups the keyboard and its navbar together, analogous to
   #notation-area grouping the notation view and notation navbar. */
#piano-area {
    display: flex;
    flex-direction: column;
    align-items: center;
    width: 100%;
    /* Constrain the scroll host to the viewport (same as contentview piano-keyboard). */
    min-width: 0;
}

/* Hide the notation-area wrapper when neither the scroll nor the nav is
   active, so the debug border / 1340 frame doesn't sit empty above the
   keyboard when no song is loaded. */
#notation-area:not(:has(> .visible)) {
    display: none;
}


/* Content-view spacer sits between notation-area and piano-area with a
   100px max-height. Only visible when notation is active. */
.content-view-spacer {
    display: none;
    flex: 1 0 0;
    max-height: 100px;
    width: 100%;
}

#notation-area:has(> .visible) ~ .content-view-spacer {
    display: flex;
}

#piano-container {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
    width: 100%;
    max-width: 100%;
    min-width: 0;
}

/* Square viewport frame; rounded shape + drop shadow live on #piano-inner. */
#chassis {
    width: 100%;
    max-width: 100%;
    display: flex;
    flex-direction: column;
    border-radius: 0;
}

/* Scrollable piano viewport (matches Touch Instruments/piano.js). */
#piano-scroll {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-padding-inline: 12px;
    width: 100%;
}


#piano-scroll::-webkit-scrollbar { height: 0; display: none; }
#piano-scroll { scrollbar-width: none; }

#piano-inner {
    display: flex;
    flex-direction: column;
    width: fit-content;
    margin-inline: auto;
    background: linear-gradient(180deg, var(--chassis-color, #1E7F50), var(--chassis-dark, #16613c));
    border-radius: var(--radius);
    padding: 4px;
    box-shadow:
        0 2px 6px rgba(0,0,0,0.2),
        0 8px 24px rgba(0,0,0,0.25),
        0 20px 60px rgba(0,0,0,0.15),
        inset 0 1px 0 rgba(255,255,255,0.15);
}

/* Title bar with octave badges and accidental labels */
#title-bar {
    position: relative;
    display: flex;
    align-items: center;
    height: 24px;
    padding: 0;
    flex-shrink: 0;
    margin-bottom: 4px;
    cursor: grab;
    touch-action: pan-x;
}
#title-bar:active { cursor: grabbing; }

.accidental-label {
    position: absolute;
    bottom: 2px;
    font-size: 15px;
    font-weight: 500;
    color: rgba(255,255,255,0.7);
    pointer-events: none;
    text-align: center;
    opacity: 0;
    transition: opacity 0.2s;
    z-index: 2;
}
.show-labels .accidental-label { opacity: 1; }

.octave-segment {
    display: flex;
    align-items: center;
    justify-content: flex-start;
    height: 100%;
    flex-shrink: 0;
}

.octave-badge {
    background: rgba(255,255,255,0.3);
    backdrop-filter: blur(8px);
    -webkit-backdrop-filter: blur(8px);
    border-radius: 999px;
    padding: 2px 13px;
    font-size: 13px;
    font-weight: 600;
    color: #fff;
    white-space: nowrap;
}
body.dark-bg .octave-badge {
    background: rgba(0,0,0,0.3);
}

/* Keyboard container */
#keyboard {
    position: relative;
    display: flex;
    touch-action: none;
    flex-shrink: 0;
}

/* White keys */
.white-key {
    position: relative;
    width: var(--white-key-w);
    background: var(--white-key);
    border-radius: 0 0 var(--white-key-r, 8px) var(--white-key-r, 8px);
    cursor: pointer;
    box-shadow:
        inset 0 -2px 4px var(--white-key-shadow),
        1px 0 0 var(--white-key-border);
    flex-shrink: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding-bottom: 10px;
    z-index: 1;
    touch-action: none;
}
.white-key + .white-key { margin-left: var(--key-gap); }
.white-key.first-key { border-radius: 0 0 var(--white-key-r, 8px) 12px; }
.white-key.last-key  { border-radius: 0 0 12px var(--white-key-r, 8px); }

.white-key.active {
    background: var(--white-key-active);
}
/* Two-stage lyric-driven highlight, matching the notation chip:
   `.selected-lyric` is the 50%-opacity cursor state that stays lit
   while a note is the current notation selection, and `.active-lyric`
   bumps to fully opaque while that same note is actively pressed
   (spacebar, arrow-step, pointer-down, or recorder playback).

   The selection state paints as an overlay (::before pseudo with
   z-index: -1 so it sits above the key's own background but below
   its label/hint children) instead of swapping the background,
   because the piano chassis shares the chassis accent color — a
   semi-transparent background would blend straight into the chassis
   and read as 100% no matter what alpha we picked. The overlay,
   by contrast, blends over the *key* color (white or black), so 0.67
   stays visibly distinct from the 1.0 press state. */
.white-key.selected-lyric::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--chassis-color);
    opacity: 0.67;
    border-radius: inherit;
    pointer-events: none;
    z-index: -1;
}
.white-key.selected-lyric .key-label { color: rgba(255,255,255,0.85) !important; }
.white-key.active-lyric {
    background: var(--chassis-color) !important;
}
.white-key.active-lyric .key-label { color: rgba(255,255,255,0.85) !important; }

/* Tonic / Middle C indicator */
.white-key.tonic-mark::after,
.black-key.tonic-mark::after {
    content: '';
    position: absolute;
    bottom: 5px;
    left: 15%; right: 15%;
    height: 4px;
    background: rgba(0,0,0,0.2);
    border-radius: 2px;
}
.black-key.tonic-mark::after {
    background: rgba(255,255,255,0.3);
}
body.dark-keys .white-key.tonic-mark::after {
    background: rgba(255,255,255,0.3);
}
body.dark-keys .black-key.tonic-mark::after {
    background: rgba(0,0,0,0.2);
}

/* Black keys */
.black-key {
    position: absolute;
    top: 0;
    background: linear-gradient(180deg, var(--black-key-top), var(--black-key));
    border-radius: 0 0 var(--black-key-r, 5px) var(--black-key-r, 5px);
    cursor: pointer;
    z-index: 2;
    box-shadow:
        0 4px 8px rgba(0,0,0,0.5),
        inset 0 -1px 2px rgba(255,255,255,0.05);
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-end;
    padding-bottom: 8px;
    touch-action: none;
}
.black-key.active {
    background: var(--black-key-active);
    box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
/* Mirrors the two-stage highlight on the white keys: a 50%-opacity
   overlay (::before) for the cursor/selection state so the chassis
   accent blends with the key color itself — swapping the background
   would blend with the chassis behind the key and disappear — plus a
   full solid-background swap for the press state. */
.black-key.selected-lyric::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--chassis-color);
    opacity: 0.67;
    border-radius: inherit;
    pointer-events: none;
    z-index: -1;
}
.black-key.selected-lyric .key-label { color: rgba(255,255,255,0.85) !important; }
.black-key.active-lyric {
    background: var(--chassis-color) !important;
    box-shadow: 0 2px 4px rgba(0,0,0,0.4);
}
.black-key.active-lyric .key-label { color: rgba(255,255,255,0.85) !important; }

/* Key labels */
.key-label {
    font-size: 14px;
    font-weight: 600;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
    line-height: 1;
}
.white-key .key-label { color: var(--white-label-color, rgba(0,0,0,0.45)); }
.black-key .key-label { display: none; font-size: 11px; }
.scale-mode .black-key .key-label,
.show-accidentals .black-key .key-label { display: block; color: var(--black-label-color, rgba(255,255,255,0.55)); }
.show-labels .key-label, .show-labels .accidental-label { opacity: 1; }

/* Computer keyboard hints */
.kb-hint {
    font-size: 14px;
    font-weight: 600;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s;
    margin-bottom: 8px;
    background: rgba(0,0,0,0.08);
    border: 1.5px solid rgba(0,0,0,0.12);
    border-radius: 6px;
    min-width: 28px;
    height: 28px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0 6px;
    color: var(--white-hint-color, #000);
}
.black-key .kb-hint {
    background: rgba(255,255,255,0.12);
    border: 1.5px solid rgba(255,255,255,0.18);
    color: var(--black-hint-color, #fff);
}
.black-key .key-label { font-weight: 500; }
.kb-mapped .kb-hint { opacity: 1; }

/* Solfege out-of-scale keys — keep full opacity, still playable */
.muted-key { opacity: 1; }

/* Scribe: pitch held before pointer/key up — grey overlay on keys; staff uses
   SVG ghost. Rejected (duplicate / fifth stack member) matches red staff tint.
   No position override here: white keys are already `relative` and black keys
   MUST stay `absolute` (overlaid on the white keys). The ::after overlay is
   `position: absolute` so it positions itself relative to whichever containing
   block the key already provides — no change needed. */
.white-key.scribe-compose-preview::after,
.black-key.scribe-compose-preview::after {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
    z-index: 3;
    background: rgba(0, 0, 0, 0.2);
}
/* Black keys are dark so a dark overlay is invisible — use a light one instead. */
.black-key.scribe-compose-preview::after {
    background: rgba(255, 255, 255, 0.2);
}
body.dark-keys .white-key.scribe-compose-preview::after {
    background: rgba(0, 0, 0, 0.35);
}
/* dark-keys mode inverts key colors; black keys become light so revert to dark overlay. */
body.dark-keys .black-key.scribe-compose-preview::after {
    background: rgba(0, 0, 0, 0.25);
}
.white-key.scribe-compose-preview.scribe-compose-rejected::after,
.black-key.scribe-compose-preview.scribe-compose-rejected::after {
    background: rgba(200, 55, 55, 0.38);
}

/* ========== NAV BAR ========== */

#nav-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    max-width: 640px;
    margin: 8px auto 0;
}
#nav-bar[hidden] { display: none; }

.nav-bar-left-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* The shared `.notation-nav-btn` class now uses `flex: 1 1 0` so the four
   notation-nav buttons can share the 540px row (with the iconless space
   button stretching to fill). In piano's page-nav row, though, we still want
   the two arrows to stay fixed 48px pills at each end so `justify-content:
   space-between` leaves real breathing room between them and the centered
   dots cluster. */
#nav-bar .notation-nav-btn {
    flex: 0 0 40px;
    width: 40px;
}

/* Return button (insert-a-new-note + "return" keyboard-shortcut
   hint). Same 44px pill as the other transport buttons. */
#notation-return {
    flex: 0 0 40px;
    width: 40px;
}

/* Shift toggle button: white bg + chassis-color fill icon (outline glyph)
   by default; chassis-color bg + white fill icon (solid glyph) when active.
   Width matches the standard 44px nav pill. */
#notation-shift-toggle {
    background: #fff;
    box-shadow: inset 0 0 0 4px var(--chassis-color, #1E7F50);
    flex: 0 0 40px;
    width: 40px;
}
#notation-shift-toggle svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: var(--edit-key-fg, rgba(0,0,0,0.45));
    stroke-width: 2;
    stroke-linecap: round;
    stroke-linejoin: round;
}
#notation-shift-toggle.active {
    background: #fff;
    box-shadow: inset 0 0 0 4px var(--chassis-color, #1E7F50);
    position: relative;
    overflow: hidden;
}
/* Chassis-color overlay at the same 0.67 opacity as the selected-lyric
   piano key — white shows through at the same level as a remotely-triggered key. */
#notation-shift-toggle.active::before {
    content: '';
    position: absolute;
    inset: 0;
    background: var(--chassis-color, #1E7F50);
    opacity: 0.67;
    border-radius: inherit;
    pointer-events: none;
}
#notation-shift-toggle.active svg {
    position: relative; /* sit above the ::before overlay */
    fill: #fff;
    stroke: #fff;
}

/* Transport nav: caption (e.g. "space") is inside the button. */
#notation-nav.notation-nav.visible > .notation-nav-btn:has(.notation-nav-caption) {
    position: relative;
}

/* Each button + its caption wrapped in a column stack so the label
   sits visually below the pill, outside the button background. */
.nav-btn-stack {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
}
.nav-btn-stack .notation-nav-caption,
.nav-btn-stack > .notation-nav-caption {
    position: static;
    font-size: 8px;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: #fff;
    opacity: 0.6;
    line-height: 1;
    pointer-events: none;
    user-select: none;
    text-align: center;
}

/* Tiny lowercase keyboard-shortcut hint inside a transport button.
   Lowercase + low-contrast matches Apple's own keycap labeling
   (space, return, delete), so it reads as a subtle keyboard cue
   rather than a full button label. Absolute + flush-bottom keeps the
   flex-centered icon above untouched — adding or removing the caption
   doesn't shift the glyph off-center. Typography values (8px / 600 /
   0.04em) match the original keycap-hint tuning; only the all-caps
   transform was dropped to match Apple's own keyboard. */
.notation-nav-caption {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 3px;
    text-align: center;
    font-size: 8px;
    font-weight: 600;
    letter-spacing: 0.04em;
    color: #fff;
    line-height: 1;
    pointer-events: none;
    user-select: none;
}

/* Trash (delete selected note) button. Same 48px pill as the other
   fixed-width transport buttons. The lowercase "delete" caption below
   the glyph is enough to signal the action, so the icon wears the
   same neutral white-on-glass color as the other transport icons
   instead of shouting in red. Hover / active fall through to the
   shared `.notation-nav-btn` states. Disabled state falls back to
   the shared `.notation-nav-btn:disabled` styling (opacity + no-
   pointer) so it's obviously unavailable when nothing is selected. */
#notation-trash {
    flex: 0 0 40px;
    width: 40px;
}


/* Rest-insert button — same fixed pill as the other transport buttons. */
#notation-rest {
    flex: 0 0 40px;
    width: 40px;
}
#notation-rest .notation-phrase-glyph {
    font-size: 22px;
    font-weight: 600;
    line-height: 1;
}
/* The quarter-rest glyph is a filled path so the shared svg rule's
   fill:none / stroke must not apply here. */
#notation-rest[hidden] { display: none; }

/* Fill-playback button — trailing position, same fixed pill as the
   other transport buttons. The triangle icon is explicitly filled so
   it reads as a solid play glyph against the standard translucent
   button background. */
#notation-fill {
    flex: 0 0 40px;
    width: 40px;
}
#notation-fill svg {
    fill: currentColor;
    stroke: none;
}
#notation-fill[hidden] { display: none; }
#notation-fill .fill-pause-icon { display: none; }
#notation-fill.is-playing .fill-play-icon { display: none; }
#notation-fill.is-playing .fill-pause-icon { display: block; }

/* Two-row layout: edit bar row is still a flex line of buttons. */
#notation-edit-bar .nav-row {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
}

/* Edit bar: hidden until notation is active; same visibility trigger as
   the notation scroll (both get .visible from notation-view.js show()). */
#notation-edit-bar {
    display: none;
    margin: 8px auto;
}
#notation-area:has(> .visible) ~ #notation-edit-bar {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Edit row chassis — now lives in #notation-edit-bar, not #notation-nav. */
#notation-edit-bar .nav-row-edit {
    --edit-key-fg: rgba(0, 0, 0, 0.45);
    --edit-key-focus-fg: var(--input-control-text, #000);
    justify-content: center;
    background: rgba(30, 30, 30, 0.72);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-radius: var(--radius, 16px);
    padding: 4px;
    gap: var(--key-gap, 4px);
    align-items: center;
    box-shadow:
        0 2px 6px rgba(0,0,0,0.2),
        0 8px 24px rgba(0,0,0,0.25),
        0 20px 60px rgba(0,0,0,0.15);
}
body.dark-keys #notation-edit-bar .nav-row-edit {
    --edit-key-fg: rgba(255, 255, 255, 0.65);
}

/* Vertical divider stays a faint white rule on the accent chassis. */
.nav-row-edit .nav-divider {
    width: 1px;
    height: 28px;
    background: rgba(255, 255, 255, 0.2);
    border-radius: 1px;
    flex-shrink: 0;
}

/* Action buttons (shift, chord, trash, return, rest…): white-key style. */
#notation-edit-bar .nav-row-edit .notation-nav-btn {
    width: 40px;
    height: 40px;
    flex: 0 0 40px;
    background: var(--white-key, #fafafa);
    color: var(--edit-key-fg);
    border-radius: var(--white-key-r, 8px);
    box-shadow:
        inset 0 -2px 4px var(--white-key-shadow, rgba(0,0,0,0.08)),
        1px 0 0 var(--white-key-border, rgba(0,0,0,0.06));
    font-size: 14px;
    font-weight: 600;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    transition: background 0.08s;
    transform: none;
}
#notation-edit-bar .nav-row-edit .notation-nav-btn svg {
    stroke: currentColor;
    fill: currentColor;
    width: 20px;
    height: 20px;
}
#notation-edit-bar .nav-row-edit .notation-nav-btn:active,
#notation-edit-bar .nav-row-edit .notation-nav-btn.key-active,
#notation-edit-bar .nav-row-edit .notation-nav-btn.active {
    background: var(--white-key-active, #c8c8c8);
    transform: none;
}

/* Steppers (pitch, layer, beats): white-key background, label-color text. */
#notation-edit-bar .nav-row-edit .nav-stepper {
    background: var(--white-key, #fafafa);
    border-radius: var(--white-key-r, 8px);
    box-shadow:
        inset 0 -2px 4px var(--white-key-shadow, rgba(0,0,0,0.08)),
        0 0 0 1px var(--white-key-border, rgba(0,0,0,0.06));
    height: 40px;
    color: var(--edit-key-fg);
}
#notation-edit-bar .nav-row-edit .nav-stepper-btn {
    color: var(--edit-key-fg);
}
#notation-edit-bar .nav-row-edit .nav-stepper-btn.key-active {
    background: var(--white-key-active, #c8c8c8);
    border-radius: var(--white-key-r, 8px);
}
#notation-edit-bar .nav-row-edit .nav-stepper-value {
    color: var(--edit-key-focus-fg);
}

/* Stepper pill: same background + radius as notation-nav-btn but wider,
   with − / value / + laid out in a single horizontal row inside. */
.nav-stepper {
    display: flex;
    align-items: center;
    justify-content: center;
    background: rgba(255, 255, 255, 0.3);
    border-radius: 12px;
    height: 40px;
    padding: 0 4px;
    gap: 0;
    flex-shrink: 0;
    transition: background-color 0.08s;
}
.nav-stepper-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 100%;
    background: none;
    border: none;
    cursor: pointer;
    color: #fff;
    font-size: 20px;
    font-weight: 300;
    line-height: 1;
    padding: 0;
    touch-action: manipulation;
    opacity: 0.85;
}
.nav-stepper-btn:active { opacity: 1; }
.nav-stepper-value {
    min-width: 38px;
    text-align: center;
    font-size: 15px;
    font-weight: 600;
    color: #fff;
    user-select: none;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 2px;
}
.stepper-rhythm {
    display: inline-flex;
    flex-direction: row;
    align-items: center;
    justify-content: center;
    gap: 2px;
    line-height: 1;
}
.stepper-rhythm-svg {
    width: 44px;
    height: 24px;
    display: block;
    overflow: visible;
}
.stepper-duration-value {
    display: inline-flex;
    align-items: center;
    justify-content: flex-end;
    gap: 1px;
    font-size: 0.7em;
    font-weight: 700;
    line-height: 1;
    opacity: 0.82;
    width: 20px;
    min-width: 20px;
    text-align: right;
}
.stepper-duration-colon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 5px;
    min-width: 5px;
    font-size: 0.7em;
    font-weight: 700;
    line-height: 1;
    opacity: 0.82;
}
.stepper-duration-value .stepper-frac { font-size: 0.75em; }
.stepper-frac {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    font-size: 0.7em;
    font-weight: 700;
    line-height: 1.1;
    gap: 0;
}
.stepper-frac-num {
    border-bottom: 1px solid rgba(255,255,255,0.85);
    padding-bottom: 0;
    line-height: 1.2;
}
.stepper-frac-den {
    line-height: 1.2;
}

/* Stretch the play/advance button to fill space between prev and fill. */
#notation-nav.notation-nav.visible > #notation-space {
    flex: 1 1 0;
    min-width: 0;
    width: auto;
}

/* ── Transport nav: piano-key styling ──────────────────────────────
   #notation-nav itself is now the chassis row — same translucent gray
   material as the edit bar, with 4pt padding framing white-key buttons. */
#notation-nav.notation-nav.visible {
    --transport-key-fg: rgba(0, 0, 0, 0.45);
    display: flex;
    flex-direction: row;
    align-items: stretch;
    background: rgba(30, 30, 30, 0.72);
    -webkit-backdrop-filter: saturate(180%) blur(20px);
    backdrop-filter: saturate(180%) blur(20px);
    border-radius: var(--radius, 16px);
    padding: 4px;
    gap: var(--key-gap, 4px);
    box-shadow:
        0 2px 6px rgba(0,0,0,0.2),
        0 8px 24px rgba(0,0,0,0.25),
        0 20px 60px rgba(0,0,0,0.15);
    margin: 8px auto;
    touch-action: manipulation;
    overflow: visible;
}
body.dark-keys #notation-nav.notation-nav.visible {
    --transport-key-fg: rgba(255, 255, 255, 0.65);
}

/* Inline strip view: the instrument-mode menu opens above this row and
   overlaps the piano. Without an explicit z-index, the keyboard's own
   stacking (white/black keys) can composite above the nav so the menu
   reads underneath and misses clicks. The floating overlay uses
   body.has-floating-piano + a fixed wrapper z-index instead. */
body:not(.has-floating-piano) #notation-nav.notation-nav.visible {
    position: relative;
    z-index: 40;
}

/* Keep the keyboard on a predictable base layer under the transport row
   so the instrument menu (a child of #notation-nav) always wins paint
   order in strip view. */
body:not(.has-floating-piano) #piano-area {
    position: relative;
    z-index: 0;
}

/* Show the disclosure button in the notation nav (shared.css defaults it to
   display:none and only un-hides it inside #floating-piano-wrap). */
#notation-nav.notation-nav.visible > .overlay-disclosure-btn,
#notation-nav.notation-nav.visible > #piano-disclosure-wrap > .overlay-disclosure-btn {
    display: flex;
}

/* Every button looks like a white piano key. */
#notation-nav.notation-nav.visible > .notation-nav-btn,
#notation-nav.notation-nav.visible > .overlay-disclosure-btn,
#notation-nav.notation-nav.visible > #piano-disclosure-wrap > .overlay-disclosure-btn {
    flex: 0 0 var(--white-key-w, 48px);
    width: var(--white-key-w, 48px);
    height: 40px;
    background: var(--white-key, #fafafa);
    color: var(--transport-key-fg);
    border-radius: var(--white-key-r, 8px);
    box-shadow:
        inset 0 -2px 4px var(--white-key-shadow, rgba(0,0,0,0.08)),
        1px 0 0 var(--white-key-border, rgba(0,0,0,0.06));
    font-size: 14px;
    font-weight: 600;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    transition: background 0.08s;
    transform: none;
}

/* Spacebar stretches to fill but matches the key height. */
#notation-nav.notation-nav.visible > #notation-space {
    flex: 1 1 0;
    width: auto;
    height: 40px;
}

/* End key corners. */
#notation-nav.notation-nav.visible > #notation-prev {
    border-radius: 12px var(--white-key-r, 8px) var(--white-key-r, 8px) 12px;
}
#notation-nav.notation-nav.visible > #notation-fill {
    border-radius: var(--white-key-r, 8px) 12px 12px var(--white-key-r, 8px);
}

/* Instrument disclosure is the first "white key" in the row — left bookend
   radius (same as #notation-prev before this slot existed). The grouped
   rule above gives every key a uniform radius; override here for strip and
   floating alike (previously only applied under body.has-floating-piano). */
#notation-nav.notation-nav.visible > #piano-disclosure-wrap > #piano-disclosure-btn {
    border-radius: 12px var(--white-key-r, 8px) var(--white-key-r, 8px) 12px;
}
#notation-nav.notation-nav.visible > #piano-disclosure-btn {
    border-radius: 12px var(--white-key-r, 8px) var(--white-key-r, 8px) 12px;
}

/* When the disclosure wrap is present, prev is an interior key, not the
   left bookend (matches floating-overlay treatment). */
#notation-nav[has-disclosure].notation-nav.visible > #notation-prev,
#notation-nav[has-instrument-menu].notation-nav.visible > #notation-prev {
    border-radius: var(--white-key-r, 8px);
}

body.has-floating-piano #notation-nav.notation-nav.visible > #notation-prev {
    border-radius: var(--white-key-r, 8px);
}

/* Disclosure wrapper: positions the popup relative to the button. */
#piano-disclosure-wrap {
    position: relative;
    flex: 0 0 var(--white-key-w, 48px);
    width: var(--white-key-w, 48px);
    height: 40px;
    overflow: visible;
    z-index: 1;
}

/* The popup menu floats above the disclosure button. */
#instrument-mode-menu {
    display: flex;
    flex-direction: column;
    position: absolute;
    bottom: calc(100% + 8px);
    left: 0;
    min-width: 120px;
    padding: 6px 0;
    background: rgba(0, 0, 0, 0.85);
    backdrop-filter: blur(24px);
    -webkit-backdrop-filter: blur(24px);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 12px;
    z-index: 500;
    opacity: 0;
    pointer-events: none;
    transform: translateY(4px);
    transition: opacity 0.14s, transform 0.14s;
}
#instrument-mode-menu.open {
    opacity: 1;
    pointer-events: auto;
    transform: translateY(0);
}
.instr-mode-item {
    all: unset;
    display: block;
    padding: 8px 16px;
    font-size: 14px;
    font-weight: 500;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    color: rgba(255,255,255,0.85);
    cursor: pointer;
    white-space: nowrap;
}
.instr-mode-item:hover {
    background: rgba(255,255,255,0.1);
}
.instr-mode-item.active {
    color: #fff;
    font-weight: 700;
}
.instr-mode-item.active::before {
    content: '✓ ';
}

/* SVG icons match white key label color. */
#notation-nav.notation-nav.visible > .notation-nav-btn svg {
    stroke: currentColor;
    fill: currentColor;
    width: 20px;
    height: 20px;
}

/* Pressed state. */
#notation-nav.notation-nav.visible > .notation-nav-btn:active,
#notation-nav.notation-nav.visible > .notation-nav-btn.key-active,
#notation-nav.notation-nav.visible > .overlay-disclosure-btn:active,
#notation-nav.notation-nav.visible > #piano-disclosure-wrap > .overlay-disclosure-btn:active {
    background: var(--white-key-active, #c8c8c8);
    transform: none;
}

/* While playing, fill button keeps white-key look. */
#notation-nav.notation-nav.visible > .notation-nav-btn.filled {
    background: var(--white-key, #fafafa);
}
#notation-nav.notation-nav.visible > .notation-nav-btn.filled:active,
#notation-nav.notation-nav.visible > .notation-nav-btn.filled.key-active {
    background: var(--white-key-active, #c8c8c8);
}

/* Edit bar end-key corners: axis-toggle is the left end, rest is the right end. */
#notation-edit-bar .nav-row-edit #notation-axis-toggle {
    border-radius: 12px var(--white-key-r, 8px) var(--white-key-r, 8px) var(--white-key-r, 8px);
}
#notation-edit-bar .nav-row-edit #notation-rest {
    border-radius: var(--white-key-r, 8px) 12px var(--white-key-r, 8px) var(--white-key-r, 8px);
}

/* "space" caption: inline like a piano key label. */
#notation-nav.notation-nav.visible .notation-nav-caption {
    position: static;
    font-size: 14px;
    font-weight: 600;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    color: var(--transport-key-fg);
    opacity: 1;
    letter-spacing: normal;
    pointer-events: none;
}

/* Page-view ("fullscreen") mode — FLOATING PIANO OVERLAY.
   When the body is marked .is-notation-fullscreen (toggled in
   _handleFullscreenChange whenever the staff flips to the paginated
   "page" layout), both the piano (#piano-area) and the playback
   transport pill (#notation-nav) get reparented into a shared wrapper
   (#floating-piano-wrap) appended to <body>, and pinned to the bottom
   of the viewport via position: fixed. This mirrors how bandonion
   overlays clarinet/recorder fingerings + the notation-stepper as a
   single docked pill, and how piano.html ("I Love a Piano") implements
   the same overlay.

   Reparenting to <body> is required because any ancestor with
   transform / filter / contain / backdrop-filter establishes a
   containing block that silently steals the fixed context, and iOS
   URL-bar shifts compound the problem. Hoisting to <body> gives a
   clean top-level layer where fixed actually anchors to the viewport.

   The keyboard ALSO shrinks while the overlay is active: the overrides
   on `effectiveSizeKey` and `keyHeight` further down in the JS pin it
   to a fixed width-driven size (small at ≤800px, medium otherwise)
   with the short 3.3 ratio. Height is explicitly ignored — the overlay
   docks as a self-contained pill that doesn't compete with the staff
   vertically, so the height-tier downgrade flow used by the inline
   strip-view sticky dock would only cause needless flicker as the user
   scrolls or the URL bar collapses. */
#floating-piano-wrap {
    display: none;
}
body.has-floating-piano #floating-piano-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    position: fixed;
    left: 50%;
    bottom: calc(8px + env(safe-area-inset-bottom, 0px));
    transform: translateX(-50%);
    z-index: 9999;
    padding: 4px 8px calc(4px + env(safe-area-inset-bottom, 0px));
    background: rgba(30,30,30,0.72);
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    border-radius: 22px;
    box-shadow:
        0 2px 6px rgba(0,0,0,0.2),
        0 8px 24px rgba(0,0,0,0.25),
        0 20px 60px rgba(0,0,0,0.15);
    /* Piano overflows sides intentionally */
    overflow: visible;
    touch-action: manipulation;
}

/* Inside the floating wrapper, neutralize #piano-area's sticky-dock
   chrome. width:0 so it doesn't widen the glass pill — height still
   stretches the wrap to cover the keyboard. Piano overflows sides. */
body.has-floating-piano #floating-piano-wrap > #piano-area {
    position: static;
    width: 0; min-width: 0;
    padding-block: 0;
    background: none;
    z-index: auto;
    overflow: visible;
    transition: opacity 0.2s, max-height 0.2s;
    max-height: 500px;
}

/* Give piano-container an explicit viewport width so its children
   resolve their max-width:100% correctly. align-items:center on
   piano-area (which is 0-wide) centers it over the wrap's midpoint. */
body.has-floating-piano #floating-piano-wrap #piano-container {
    width: calc(100vw - 16px);
    max-width: calc(100vw - 16px);
    will-change: transform;
}
body.has-floating-piano #floating-piano-wrap #chassis {
    max-width: calc(100vw - 16px);
}

/* Tighter drop shadow in the floating overlay (was on square #chassis). */
body.has-floating-piano #floating-piano-wrap #piano-inner {
    background: linear-gradient(180deg, var(--chassis-color, #1E7F50), var(--chassis-dark, #16613c));
    box-shadow:
        0 2px 6px rgba(0,0,0,0.2),
        0 8px 24px rgba(0,0,0,0.22),
        inset 0 1px 0 rgba(255,255,255,0.15);
}

/* When piano is collapsed in the floating overlay */
body.has-floating-piano.piano-collapsed #floating-piano-wrap > #piano-area {
    opacity: 0;
    max-height: 0;
    pointer-events: none;
}

/* When collapsed, keep the edit bar and transport stacked vertically in
   the floating pill; only the instrument keyboard itself collapses away. */
body.has-floating-piano.piano-collapsed #floating-piano-wrap {
    flex-direction: column;
    align-items: center;
    gap: var(--key-gap, 4px);
    max-width: calc(100vw - 16px);
    overflow-x: auto;
    padding-bottom: 4px;
}

body.has-floating-piano.piano-collapsed #floating-piano-wrap > #notation-edit-bar {
    margin: 0;
    flex: 0 0 auto;
}

body.has-floating-piano.piano-collapsed #floating-piano-wrap > #notation-nav.notation-nav.visible {
    flex: 0 0 auto;
}

body.has-floating-piano.piano-collapsed #floating-piano-wrap > #notation-nav.notation-nav.visible > #notation-space {
    min-width: calc(2 * var(--white-key-w, 48px) + var(--key-gap, 4px));
}

/* Piano container and chassis inside the floating overlay: allow
   content to overflow naturally so keyboard edges aren't clipped. */
body.has-floating-piano #piano-container,
body.has-floating-piano #chassis {
    overflow: visible;
}

/* Notation-nav inside wrap: size to content, strip own chassis (wrap provides glass). */
body.has-floating-piano #floating-piano-wrap > #notation-nav.notation-nav.visible {
    position: static;
    margin: 0;
    padding: 0;
    gap: 4px;
    width: max-content;
    align-self: center;
    background: none;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transform: none;
    border-radius: 0;
}

/* Strip edit-bar row glass — the wrap provides the shared background. */
body.has-floating-piano #floating-piano-wrap .nav-row-edit {
    background: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    box-shadow: none;
    border-radius: 0;
    padding: 0;
}

/* Spacebar: always at least 5 key-widths so the pill reads comfortably.
   Must beat the base rule's min-width:0 (2 IDs + 3 classes specificity). */
body.has-floating-piano #floating-piano-wrap > #notation-nav.notation-nav.visible > #notation-space {
    min-width: calc(5 * var(--white-key-w, 48px) + 4 * var(--key-gap, 4px));
}

/* When #notation-edit-bar is reparented into the floating wrap, the
   normal sibling selector no longer applies — show it explicitly. */
body.has-floating-piano #floating-piano-wrap > #notation-edit-bar {
    display: flex;
    align-items: center;
    justify-content: center;
}

/* Reserve runway at the bottom of #notation-area so the last row of
   music can never end up under the floating piano. We put the gap on
   #bottom-bar's own margin-bottom — #bottom-bar is the last child of
   #instrument-area, and #instrument-area is the scrolling column, so
   this margin becomes real runway at the very bottom of the scroll.
   --scribe-float-nav-h is written from JS by a ResizeObserver on the
   wrapper (see `_observeFloatingNavHeight`); it already includes the
   wrapper's measured height PLUS its 8px bottom offset + safe-area
   inset. Fallback ≈ wrapper's natural height + gap, so the layout is
   stable for one frame before JS first measures. */
body.has-floating-piano #bottom-bar {
    margin-bottom: var(--scribe-float-nav-h, 280px);
}

/* Same idea for `scrollIntoView({ block: 'nearest' })`: the browser
   defines "in view" as the element's rect intersecting the scroll
   container's padding box, not the visual safe area, so the floating
   overlay would otherwise sit on top of the selected column for a
   full step or two before a scroll kicks in. */
body.has-floating-piano {
    scroll-padding-bottom: var(--scribe-float-nav-h, 280px);
    scroll-padding-top: 16px;
}

#nav-dots {
    display: flex;
    align-items: center;
    gap: 12px;
}

.nav-dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--text-dim);
    cursor: pointer;
    transition: background 0.15s;
    flex-shrink: 0;
}
.nav-dot:hover { transform: scale(1.3); }
.nav-dot.active {
    background: var(--text);
}

/* ========== INFO BAR ========== */

#info-bar {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 16px;
    padding: 8px;
    font-size: 12px;
    color: var(--text-dim);
    flex-shrink: 0;
}

@keyframes pulse { 0%,100% { opacity: 1; } 50% { opacity: 0.3; } }

/* ========== SUSTAIN INDICATOR ========== */

#sustain-indicator {
    position: fixed;
    bottom: 12px;
    right: 16px;
    background: rgba(255,255,255,0.1);
    backdrop-filter: blur(12px);
    padding: 4px 12px;
    border-radius: 8px;
    font-size: 11px;
    font-weight: 600;
    color: var(--text-dim);
    opacity: 0;
    transition: opacity 0.2s;
    pointer-events: none;
}
#sustain-indicator.active { opacity: 1; color: var(--text); }

/* ========== RESPONSIVE ========== */

@media (max-width: 1023px) {
    #bottom-bar .import-btn,
    #bottom-bar .export-btn { font-size: 15px; padding: 0 16px; }
    .ilophone-bars { transform: rotate(-180 60 60); }
}

@media (max-height: 500px) {
    #toolbar { margin: 4px 8px 0; padding: 6px 10px; gap: 6px; }
    #instrument-area { padding: 0; }
    #piano-inner { padding: 4px; }
    #song-row { padding: 8px 12px; min-height: 88px; }
    #rec-controls { gap: 4px; }
    #left-chips { left: 12px; }
    .color-swatch { width: 36px; height: 36px; border-width: 3px; }
    .rec-close-btn { width: 28px; height: 28px; font-size: 14px; }
    .rec-restart-btn { width: 28px; height: 28px; }
    #bottom-bar { padding: 4px 12px 16px 12px; }
    #title-bar { height: 18px; margin-bottom: 2px; }
    .octave-badge { font-size: 11px; padding: 1px 9px; }
    #song-title { font-size: 20px; }
}

@media (max-width: 1023px) {
    #song-title { font-size: 17px; }
    #info-bar { display: none; }
    /* Type-to-Play is desktop-only (no physical keyboard on phones /
       tablets), so the Typing group hides entirely at narrow widths
       even though every other toolbar group is always reachable via
       the hamburger. */
    #typing-group { display: none; }
}

/* ========== HAMBURGER TOOLBAR (ALL WIDTHS) ==========
   Scribe keeps every Size / Sound / Labels / Dark / Typing control
   behind the ☰ button regardless of viewport size. A wide
   always-on toolbar crowds the top of the app and pulls focus away
   from the staff — the melody is the thing the student should see
   first, and the controls are secondary tools they reach for
   intermittently. Stashing them in a dropdown gives the page one
   consistent look across phone, tablet, and desktop. */

/* Override shared.css's default "always hidden except under 800px"
   — in Scribe the hamburger is the single entry point at every
   width. */
#menu-toggle {
    display: block;
}

    #toolbar {
        position: relative;
        flex-wrap: nowrap;
    }

    #toolbar-groups {
        display: flex;
        flex-direction: column;
        gap: 0;
        position: absolute;
        top: 100%;
        right: 0;
        margin-top: 6px;
        padding: 8px 0;
        background: rgba(0, 0, 0, 0.85);
        backdrop-filter: blur(24px);
        -webkit-backdrop-filter: blur(24px);
        border: 1px solid var(--toolbar-border);
        border-radius: 14px;
        opacity: 0;
        pointer-events: none;
        transform: translateY(-4px);
        transition: opacity 0.15s, transform 0.15s;
        min-width: 200px;
    /* Float above the song row + notation so the dropdown never
       gets clipped by a sibling's stacking context. */
    z-index: 50;
    }

    #toolbar-groups.open {
        opacity: 1;
        pointer-events: auto;
        transform: translateY(0);
    }

    .toolbar-group label {
        display: block;
        font-size: 14px;
        font-weight: 500;
        opacity: 0.8;
    }

    .toolbar-group {
        flex-direction: row;
        justify-content: space-between;
        padding: 8px 14px;
        gap: 12px;
    }

    .toolbar-group:hover {
        background: rgba(255,255,255,0.08);
    }

    .toolbar-divider {
        width: auto;
        height: 1px;
        margin: 6px 0;
    }

    #sound-group,
#labels-group {
        flex-wrap: nowrap;
        background: none;
        padding: 8px 14px;
        border-radius: 0;
    }

    #sound-group label,
#labels-group label {
        font-size: 14px;
        font-weight: 500;
        color: rgba(255, 255, 255, 0.75);
        opacity: 1;
        flex-shrink: 0;
        text-transform: none;
        letter-spacing: 0;
    }

    .toolbar-group .toolbar-btn {
        padding: 5px 10px;
        font-size: 13px;
    }

    #toolbar-groups > .toolbar-action-controls {
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        padding: 8px 14px;
        border-bottom: 1px solid rgba(255,255,255,0.14);
    }

    #toolbar-groups > .toolbar-action-controls > * {
        width: 100%;
    }

    #toolbar-groups > .toolbar-action-controls #color-toggle,
    #toolbar-groups > .toolbar-action-controls #scribe-input-mode-picker {
        justify-content: center;
    }

@media (max-width: 767px) {
    #toolbar { gap: 6px; padding: 8px 10px; }
    #toolbar .app-title { font-size: 14px; }
    .color-swatch { width: 40px; height: 40px; border-width: 3px; }
    .rec-close-btn { width: 30px; height: 30px; font-size: 16px; }
    #bottom-bar { padding: 6px 16px 16px 16px; }
    #bottom-bar .import-btn,
    #bottom-bar .export-btn { font-size: 14px; padding: 0 14px; }
    #song-title { font-size: 24px; }

    #notation-edit-bar .nav-row-edit#notation-main-edit-panel #notation-axis-toggle {
        border-radius: var(--white-key-r, 8px);
    }

    #notation-edit-bar .nav-row-edit#notation-main-edit-panel #notation-rest {
        border-radius: var(--white-key-r, 8px);
    }

}

@media (max-width: 600px) {
    #notation-main-edit-panel {
        flex-wrap: wrap;
        row-gap: 6px;
        max-width: 100%;
        width: 100%;
        gap: 4px;
    }

    #notation-main-edit-panel::after {
        content: '';
        flex: 0 0 100%;
        height: 0;
        order: 1;
    }

    #notation-main-edit-panel .nav-divider {
        display: none;
    }

    #notation-main-edit-panel .nav-btn-stack {
        order: 2;
    }

    #notation-main-edit-panel .nav-btn-stack:has(#notation-pitch-stepper),
    #notation-main-edit-panel .nav-btn-stack:has(#notation-stepper) {
        order: 0;
        flex: 1 1 0;
        min-width: 0;
    }

    /* Square action buttons: drop the fixed 40×40 footprint so all seven
       stay on one row; they shrink proportionally but stay square. */
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel .nav-btn-stack:has(> .notation-nav-btn),
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel .nav-btn-stack:has(#notation-stack-cycler) {
        flex: 1 1 0;
        min-width: 0;
        max-width: 40px;
    }

    body.has-floating-piano.piano-collapsed #floating-piano-wrap #notation-main-edit-panel {
        flex-wrap: wrap;
        max-width: 100%;
        width: 100%;
    }

    body.has-floating-piano.piano-collapsed #floating-piano-wrap #notation-main-edit-panel::after {
        display: block;
    }
}

/* ========== BOTTOM BAR ========== */

#bottom-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 8px 24px 16px 24px;
    flex-shrink: 0;
    position: relative;
    align-self: stretch;
}

.import-export-group {
    display: flex;
    align-items: center;
    gap: 8px;
}

/* Piano-specific rec-controls positioning */
#rec-controls {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
}

#bottom-bar .import-btn,
#bottom-bar .export-btn {
    background: var(--btn-bg);
    border: var(--bottom-swatch-border, 2px) solid #fff;
    color: #fff;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    font-size: 16px;
    font-weight: 600;
    height: var(--bottom-swatch-size, 48px);
    min-height: var(--bottom-swatch-size, 48px);
    padding: 0 18px;
    border-radius: 999px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    cursor: pointer;
    transition: background 0.15s, transform 0.15s;
    flex-shrink: 0;
    line-height: 1;
}

#bottom-bar .import-btn:hover,
#bottom-bar .export-btn:hover {
    background: rgba(255,255,255,0.18);
    transform: scale(1.05);
}

#bottom-bar .import-btn:active,
#bottom-bar .export-btn:active {
    transform: scale(0.95);
}

#bottom-bar .import-btn svg,
#bottom-bar .export-btn svg {
    flex-shrink: 0;
}

/* ========== SONG BAR ========== */

/* Shared base in song-bar.css; Scribe constrains the title width and layers. */
#song-bar { max-width: calc(100% - 120px); z-index: 2; }

/* Extra height so both the key transposer and BPM controls
   fit inside the song-row without overflowing the #left-chips column. */
#song-row { min-height: 88px; }

/* Key display — no chip background; plain text matching credits style. */
#key-display {
    background: transparent;
    z-index: 2;
}

/* BPM metronome — plain text matching credits style (no chip background). */
#metronome-display {
    display: flex;
    flex-direction: row;
    align-items: center;
    gap: 0;
    background: transparent;
    padding: 4px 6px;
}

#bpm-value {
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    font-size: 13px;
    font-weight: 600;
    letter-spacing: 0.01em;
    padding: 0 2px;
    line-height: 1.25;
    color: inherit;
    min-width: 28px;
    text-align: center;
}

.bpm-unit {
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-dim);
    padding-right: 2px;
    line-height: 1.25;
}

/* A tiny bit of vertical breathing room above/below the staff. The lyric
   input now renders inline at the same y as the SVG syllable — no floating
   box below the staff to reserve a gutter for — so the bottom pad is just
   matched to the top pad. The ✕ button overlays the top of the selected
   column directly; most student melodies don't reach far enough above the
   staff for that to collide with a ledger-high note.
   Scoped to non-sticky strip modes because sticky-header mode relies on the
   header panel and notes-scroll children filling the card's rounded
   corners edge-to-edge (matching piano's layout). Page/phrase view already
   nests selection chips with CHIP_INSET inside the SVG — outer padding here
   would stack a second 8px band below the highlight. */
#notation-inner:not(.sticky-header-mode):not(.fullscreen-mode):not(.phrase-mode) {
    padding-top: 8px;
    padding-bottom: 8px;
}
/* The ID selector above beats .notation-inner.has-beat-numbers in shared.css,
   so re-apply the zero top-pad for beat-number mode here. */
#notation-inner.has-beat-numbers:not(.sticky-header-mode):not(.fullscreen-mode):not(.phrase-mode) {
    padding-top: 0;
}

/* The floating overlay is absolutely-positioned inside #notation-scroll,
   so we need to establish a positioning context there. (shared.css doesn't
   set one because the other apps don't overlay anything on the staff.) */
#notation-scroll { position: relative; }

/* The lyric for each note IS an <input> — no separate overlay. Every
   column's lyric field lives inside a <foreignObject> anchored to the
   same lyric baseline the engine renders to. The field has two visual
   states driven entirely by the `readonly` attribute:
     - locked (readonly): faint grey capsule, no border — reads like a
       static label but is still a real input element. Pointer-events
       stay on so clicking it still routes through to the column's
       selection handler (capture-phase listener on #notation-inner
       notices the lyric-input target and sets _pendingLyricFocus).
     - unlocked (not readonly): accent-colored fill with a matching
       stroke, wider min-width, visible caret. The surrounding column
       is also painted via `.col-bg` so "this is the one you're
       editing" reads at a glance.
   field-sizing:content lets the pill hug its own text so locked cells
   collapse to their content; min-width keeps an obvious tap target
   even for empty syllables. */
.notation-lyric-input {
    box-sizing: border-box;
    height: 100%;
    margin: 0;
    /* Keep horizontal padding tight — 6px each side reads as "a label
       for this word" without hoarding empty space inside the pill for
       short syllables, and it keeps the pill from bleeding into the
       adjacent column once the engine has budgeted per-column width
       around its chrome. */
    padding: 2px 6px;
    font-family: "SF Pro Rounded", ui-rounded, system-ui, sans-serif;
    font-size: 18px;
    font-weight: 500;
    line-height: 1.1;
    color: inherit;
    text-align: center;
    outline: none;
    cursor: text;
    caret-color: var(--chassis-color, #1E7F50);
    /* Width is set explicitly in JS via a canvas measurement per value
       change — `field-sizing: content` would work in modern Chrome /
       Safari but isn't reliable cross-browser, so we drive it
       ourselves. min-width keeps an obvious tap target even when
       empty. */
    min-width: 32px;
    border: 1.5px solid transparent;
    /* 4pt rounded rect reads as "label for a word" — a capsule felt too
       much like a chat bubble or pill-button, and the squarer corners
       align visually with the grid of noteheads above. */
    border-radius: 4px;
    /* Locked (not-currently-selected) lyrics read as plain text —
       no background or border. Only the one the student is editing
       gets a pill. This keeps the melody row visually quieter and
       makes the selection state pop. */
    background: transparent;
}
.notation-lyric-input[readonly] {
    cursor: pointer;
    caret-color: transparent;
}
.notation-lyric-input:not([readonly]) {
    /* Selection reads through the text color alone — no fill, no
       border. The accent glyph plus the column's own selection
       landmark is enough signal, and a filled chip under an already
       selected note starts to feel noisy while a student is typing. */
    color: var(--chassis-color, #1E7F50);
}
.notation-lyric-input::placeholder {
    color: rgba(0, 0, 0, 0.35);
    font-style: italic;
    font-weight: 500;
}
/* The wrapping foreignObject. Sized and positioned by JS per lyric. */
.notation-lyric-input-fo {
    overflow: visible;
}
/* Horizontally center the input within the foreignObject so the
   pill's width-change between locked and unlocked states stays
   centered on the notehead. */
.notation-lyric-input-fo > div {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}

.key-step-btn {
    font-size: 9px;
    color: var(--text-dim);
    padding: 0 2px;
}
.key-step-btn:hover { color: var(--text); }

#key-display-btn {
    color: var(--text);
    white-space: nowrap;
}

/* Key-display button: match credits text size so both left-column
   controls read at the same visual weight as the credits. */
#key-display-btn {
    font-size: 13px;
    min-width: 28px;
}

#notation-axis-toggle {
    flex: 0 0 40px;
    width: 40px;
}
#notation-edit-bar #notation-axis-toggle svg {
    width: 22px;
    height: 19px;
    fill: none;
    stroke: currentColor;
}
#notation-edit-bar #notation-undo svg {
    fill: none;
}
/* Active: accent background, white arrow — 2 IDs beat the general
   .notation-nav-btn rule (1 ID + 2 classes = lower specificity). */
#notation-edit-bar #notation-axis-toggle.active {
    background: var(--chassis-color, #1E7F50);
    color: #fff;
}
#notation-edit-bar #notation-axis-toggle.active svg {
    fill: currentColor;
    stroke: none;
}

/* Stack cycler: same footprint as the single edit-bar buttons. */
#notation-stack-cycler {
    flex: 0 0 40px;
    width: 40px;
    padding: 0;
}
#notation-stack-cycler .nav-stepper-btn {
    width: 100%;
}
#notation-stack-cycler.inactive,
#notation-pitch-stepper.inactive {
    opacity: 0.35;
    pointer-events: none;
}

#notation-stack-cycler svg {
    stroke-width: 2.5;
}

#notation-pitch-stepper,
#notation-stepper {
    width: 120px;
}

#notation-pitch-stepper {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr) 28px;
}

@media (max-width: 600px) {
    /* Beat the fixed-footprint rules above once the edit bar is in its
       mobile two-row layout (steppers on top, square actions below). */
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel .nav-btn-stack .notation-nav-btn,
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel #notation-stack-cycler {
        width: 100%;
        height: auto;
        aspect-ratio: 1;
        flex: 0 0 auto;
        max-height: 40px;
    }
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel #notation-pitch-stepper,
    #notation-edit-bar .nav-row-edit#notation-main-edit-panel #notation-stepper {
        width: 100%;
        max-width: 120px;
    }
}

#notation-pitch-label {
    white-space: nowrap;
    font-size: 0.7em;
    width: auto;
    min-width: 0;
    max-width: none;
    text-align: center;
    overflow: hidden;
    text-overflow: clip;
}

#notation-pitch-label.chord-label {
    font-size: 0.72em;
    letter-spacing: -0.04em;
}

#notation-pitch-label.chord-label-four {
    font-size: 0.7em;
}

/* Import/Export Modals */
.modal-overlay {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0, 0, 0, 0.5);
    backdrop-filter: blur(8px);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10000;
    padding: 20px;
}

.modal-content {
    background: var(--bg);
    border-radius: 16px;
    padding: 24px;
    max-width: 600px;
    width: 100%;
    max-height: 90vh;
    display: flex;
    flex-direction: column;
    box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
}

.modal-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 16px;
}

.modal-header h2 {
    margin: 0;
    font-size: 24px;
    font-weight: 700;
    color: var(--text);
}

.close-modal-btn {
    background: rgba(0, 0, 0, 0.06);
    border: none;
    border-radius: 50%;
    width: 32px;
    height: 32px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 20px;
    color: var(--text);
    cursor: pointer;
    transition: background 0.15s;
}

.close-modal-btn:hover {
    background: rgba(0, 0, 0, 0.12);
}

.modal-instructions {
    font-size: 14px;
    color: var(--text-dim);
    margin: 0 0 16px;
    line-height: 1.4;
}

.modal-textarea {
    flex: 1;
    min-height: 300px;
    font-family: "SF Mono", ui-monospace, Menlo, Consolas, monospace;
    font-size: 13px;
    line-height: 1.5;
    padding: 12px;
    background: rgba(0, 0, 0, 0.03);
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    color: var(--text);
    resize: vertical;
    white-space: pre;
    box-sizing: border-box;
    margin-bottom: 16px;
}

.modal-textarea:focus {
    outline: none;
    border-color: var(--instrument-color);
}

.modal-select {
    width: 100%;
    padding: 10px 12px;
    border: 1.5px solid rgba(128,128,128,0.3);
    border-radius: 10px;
    font-size: 16px;
    font-family: inherit;
    background: var(--modal-input-bg, rgba(128,128,128,0.08));
    color: inherit;
    margin-bottom: 16px;
    appearance: none;
    -webkit-appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23888' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 14px center;
    cursor: pointer;
}

.modal-select:focus {
    outline: none;
    border-color: var(--instrument-color);
}

.import-status {
    font-size: 14px;
    margin-top: 12px;
    padding: 12px;
    border-radius: 8px;
    display: none;
}

.import-status.ok {
    display: block;
    background: rgba(52, 199, 89, 0.1);
    color: #34c759;
    border: 1px solid rgba(52, 199, 89, 0.3);
}

.import-status.err {
    display: block;
    background: rgba(255, 59, 48, 0.1);
    color: #ff3b30;
    border: 1px solid rgba(255, 59, 48, 0.3);
}

.btn-big.primary {
    background: var(--instrument-color);
    border: 2px solid var(--instrument-color);
    color: white;
    padding: 12px 24px;
    border-radius: 10px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s, background 0.15s;
}

.btn-big.primary:hover {
    opacity: 0.9;
}

.btn-big.primary:disabled {
    opacity: 0.5;
    cursor: not-allowed;
}

.btn-big.primary.copied {
    background: #34c759;
    border-color: #34c759;
}

.dark-bg .modal-content {
    background: rgba(40, 40, 44, 0.95);
}

.dark-bg .close-modal-btn {
    background: rgba(255, 255, 255, 0.1);
}

.dark-bg .close-modal-btn:hover {
    background: rgba(255, 255, 255, 0.15);
}

.dark-bg .modal-textarea {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.15);
}

/* Song credits box — opposite side of the transposer on #song-row.
   Mirrors #key-display's anchor (right: 24px vs. left: 24px) so the two
   chips frame the title chip below the staff's left clef and right edge.
   Stays subtle: inherits the chassis text color, no chip background by
   default (the row chassis itself provides the colored band). When
   populated, each credit renders as one small line ("Composed by X")
   with the name uppercased via text-transform. Empty state is a single
   grey "add credits…" placeholder, matching the "pick a melody…"
   treatment on the other apps. */
#song-credits {
    position: absolute;
    right: 24px;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: center;
    gap: 2px;
    padding: 6px 12px;
    border: none;
    background: transparent;
    color: inherit;
    cursor: pointer;
    border-radius: 10px;
    font-family: inherit;
    font-size: 12px;
    line-height: 1.25;
    max-width: min(28vw, 260px);
    text-align: right;
    transition: background 0.15s;
    z-index: 2;
}
#song-credits:hover { background: var(--song-chip-bg, rgba(255, 255, 255, 0.14)); }
#song-credits:active { background: var(--song-chip-bg, rgba(255, 255, 255, 0.22)); }
#song-credits:focus-visible {
    outline: 2px solid rgba(255, 255, 255, 0.5);
    outline-offset: 2px;
}
.song-credits-placeholder {
    opacity: 0.5;
    font-style: normal;
    letter-spacing: 0.02em;
}
.song-credits-content {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 2px;
    width: 100%;
}
.song-credits-line {
    display: block;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 100%;
}
.song-credits-name {
    text-transform: uppercase;
    letter-spacing: 0.04em;
    font-weight: 600;
}
/* Empty / populated swap — the placeholder span is the only child when
   the song has no credits, and the content span takes over once any
   field is filled. Both use `hidden` so CSS doesn't need to mirror the
   JS state. */
#song-credits.is-empty .song-credits-content { display: none; }
#song-credits:not(.is-empty) .song-credits-placeholder { display: none; }

/* Credits modal — reuses the standard modal-overlay / modal-content
   shell but packs the three labeled inputs in a tight stack instead of
   the import/export textarea layout. */
.credits-modal-content { max-width: 420px; }

.confirm-modal-content {
    max-width: 320px;
    text-align: center;
}

.confirm-modal-content h2 {
    margin: 0 0 20px;
    font-size: 20px;
    font-weight: 700;
    color: var(--text);
}

.confirm-modal-actions {
    display: flex;
    gap: 12px;
}

.confirm-modal-actions .btn-big {
    flex: 1;
    margin: 0;
}

.btn-big {
    padding: 12px 24px;
    border-radius: 10px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.15s, background 0.15s;
}

.btn-big.secondary {
    background: transparent;
    border: 2px solid rgba(0, 0, 0, 0.15);
    color: var(--text);
}

.btn-big.secondary:hover {
    background: rgba(0, 0, 0, 0.05);
}

.btn-big.destructive {
    background: #ff3b30;
    border: 2px solid #ff3b30;
    color: white;
}

.btn-big.destructive:hover {
    opacity: 0.9;
}

.dark-bg .btn-big.secondary {
    border-color: rgba(255, 255, 255, 0.2);
}

.dark-bg .btn-big.secondary:hover {
    background: rgba(255, 255, 255, 0.08);
}
.credits-field {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-bottom: 14px;
}
.credits-label {
    font-size: 13px;
    font-weight: 600;
    color: var(--text-dim);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.credits-input {
    font-family: inherit;
    font-size: 15px;
    padding: 10px 12px;
    background: rgba(0, 0, 0, 0.03);
    border: 1px solid rgba(0, 0, 0, 0.1);
    border-radius: 8px;
    color: var(--text);
    box-sizing: border-box;
    width: 100%;
}
.credits-input:focus {
    outline: none;
    border-color: var(--instrument-color);
}
.dark-bg .credits-input {
    background: rgba(255, 255, 255, 0.05);
    border-color: rgba(255, 255, 255, 0.15);
}

/* Narrow viewports: #song-row switches to column layout at 600px
   (shared.css @media (max-width: 600px)), so only then should the
   credits box drop out of absolute positioning. */
@media (max-width: 600px) {
    #song-credits {
        position: static;
        transform: none;
        align-self: center;
        text-align: center;
        align-items: center;
        max-width: 100%;
    }
    .song-credits-content { align-items: center; }
}

/* Narrow viewports: shared responsive.css releases #left-chips to static.
   Scribe also clears the min-height so the compact song-row fits on screen. */
@media (max-width: 600px) {
    #song-row { min-height: unset; }
}

/* Beat-number overlay hidden for now */
.notation-row-number { display: none; }

/* Keyboard shortcuts overlay (apps/scribe/keyboard-shortcuts.js) */
.scribe-shortcuts-modal {
    max-width: 520px;
}

.scribe-shortcuts-lead {
    margin-bottom: 12px;
}

.scribe-shortcuts-body {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    margin: 0 -4px;
    padding: 0 4px 8px;
}

.scribe-shortcuts-section {
    margin-bottom: 18px;
}

.scribe-shortcuts-section:last-child {
    margin-bottom: 0;
}

.scribe-shortcuts-section-title {
    margin: 0 0 8px;
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--text-dim);
}

.scribe-shortcuts-row {
    display: grid;
    grid-template-columns: minmax(8.5rem, 42%) 1fr;
    gap: 10px 16px;
    align-items: center;
    padding: 8px 0;
    border-bottom: 1px solid rgba(0, 0, 0, 0.06);
}

.scribe-shortcuts-row:last-child {
    border-bottom: none;
}

.scribe-shortcuts-keys {
    min-width: 0;
}

.scribe-keycap-group {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px;
}

.scribe-keycap {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 1.65em;
    min-width: 1.65em;
    padding: 3px 8px;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 11px;
    font-weight: 600;
    line-height: 1.2;
    letter-spacing: 0.01em;
    color: #1d1d1f;
    background: linear-gradient(180deg, #ffffff 0%, #ececef 55%, #e2e2e7 100%);
    border: 1px solid rgba(0, 0, 0, 0.14);
    border-bottom-color: rgba(0, 0, 0, 0.22);
    border-radius: 6px;
    box-shadow:
        0 1px 0 rgba(255, 255, 255, 0.95) inset,
        0 2px 0 rgba(0, 0, 0, 0.07),
        0 3px 6px rgba(0, 0, 0, 0.1);
    white-space: nowrap;
}

.scribe-keycap-plus {
    font-size: 11px;
    font-weight: 600;
    color: var(--text-dim);
    padding: 0 1px;
    user-select: none;
}

.scribe-keycap-gap {
    width: 4px;
}

.scribe-shortcuts-desc {
    font-size: 14px;
    line-height: 1.35;
    color: var(--text);
}

.scribe-shortcuts-footnote {
    margin: 12px 0 0;
    font-size: 12px;
    line-height: 1.4;
    color: var(--text-dim);
}

.scribe-shortcuts-footnote .scribe-keycap {
    vertical-align: middle;
}

.dark-bg .scribe-shortcuts-row {
    border-bottom-color: rgba(255, 255, 255, 0.08);
}

/* Keep keycaps white on dark UI — they read as physical keys. */
.dark-bg .scribe-keycap {
    color: #1d1d1f;
    background: linear-gradient(180deg, #ffffff 0%, #ececef 55%, #e2e2e7 100%);
    border-color: rgba(0, 0, 0, 0.14);
    border-bottom-color: rgba(0, 0, 0, 0.22);
}

