/* ============================================================
   KOSIS — kosis-song.css
   Styling for the song detail page (pages/song.php): the persistent
   media player, the sheet/lyrics content panel, and the per-voice
   audio play buttons.

   Loaded AFTER kosis-brand.css / kosis-dashboard.css / kosis-brand-extensions.css,
   so all --ks-* tokens and layout variables (--kosis-sidebar-width) are available.

   Tagged with KOSIS_ASSET_VERSION cache-buster like the other stylesheets.
   ============================================================ */

/* ── Per-voice "play" button (sage circle) ─────────────────────────────── */
.ks-play-btn {
    flex: 0 0 34px;
    width: 34px; height: 34px; min-width: 34px; min-height: 34px;
    border-radius: 50%;
    border: none;
    background: var(--ks-sage);
    color: var(--ks-cream);
    cursor: pointer;
    display: flex; align-items: center; justify-content: center;
    padding: 0;
}

/* ── Content panel (sheet music / lyrics): sits ABOVE the player bar ───── */
#ksPanel {
    display: none;          /* toggled to flex by JS */
    position: fixed;
    z-index: 990;
    background: var(--ks-cream);
    border-top: 0.5px solid var(--ks-border);
    box-shadow: 0 -8px 24px rgba(31,41,82,0.18);
    flex-direction: column;
    left: var(--kosis-sidebar-width, 260px);
    right: 0;
    bottom: 0;              /* full height by default; JS sets the exact value */
    top: 0;                 /* covers the topbar for max viewing space */
}
/* The panel's bottom is set authoritatively by JS (syncPanelBottom measures the
   real player/nav position on every viewport), so we do NOT animate it — a
   transition would visibly slide through a stale value and flash a gap. */
/* When the player controls are visible, lift the panel to clear the player bar. */
#ksPanel.player-showing { bottom: 88px; }
#ksPanelHeader {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--ks-space-md);
    padding: 10px 16px;
    padding-top: calc(10px + env(safe-area-inset-top, 0px));  /* clear notch/status bar */
    border-bottom: 0.5px solid var(--ks-border);
    background: var(--ks-parchment);
    flex-shrink: 0;
}
#ksPanelTitle {
    font-family: var(--ks-font-serif);
    color: var(--ks-navy);
    font-size: 14px;
    flex: 1 1 auto; min-width: 0;   /* absorb slack + allow ellipsis truncation */
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#ksPanelClose {
    background: none; border: none; color: var(--ks-slate);
    cursor: pointer; font-size: 22px; line-height: 1; flex-shrink: 0;
}
#ksPanelBody {
    flex: 1; min-height: 0;
    overflow: auto;
    background: #1F2952;
    display: flex; align-items: flex-start; justify-content: center;
}
/* When showing a PDF, switch to a block/column layout so the zoom toolbar can
   stick to the top and the pages stack beneath it (instead of sitting in a row). */
#ksPanelBody.pdf-mode {
    display: block;
    align-items: stretch;
    text-align: center;
}

/* ── Persistent player bar ─────────────────────────────────────────────── */
#ksPlayer {
    display: none;          /* toggled to block by JS */
    position: fixed;
    z-index: 1000;
    background: var(--ks-navy);
    color: var(--ks-cream);
    border-top: 1px solid rgba(212,169,85,0.3);
    left: var(--kosis-sidebar-width, 260px);
    right: 0;
    bottom: 0;
}
#ksPlayerInner {
    max-width: 1280px; margin: 0 auto;
    padding: 10px 16px;
    display: flex; align-items: center; gap: 12px;
    flex-wrap: nowrap;
    overflow: hidden;        /* nothing can spill onto neighbours (desktop) */
}
#ksPlayerInner .ks-pl-info {
    flex: 1 1 auto; min-width: 0;
    padding-left: 14px;
    margin-left: 2px;
    border-left: 0.5px solid rgba(253, 250, 241, 0.18);
}
#ksPlayerInner > button,
#ksPlayerInner > select,
#ksPlayerInner .ks-pl-extra { flex: 0 0 auto; }

/* Transport buttons */
.ks-pl-transport {
    background: none; border: none; color: var(--ks-cream);
    cursor: pointer; opacity: 0.85; padding: 0;
}
#ksPlayPause {
    background: var(--ks-gold); border: none; color: var(--ks-navy);
    cursor: pointer;
    width: 40px; height: 40px; border-radius: 50%; flex: 0 0 40px;
    display: flex; align-items: center; justify-content: center;
}

/* Track label + voice + seek row */
.ks-pl-trackrow { display: flex; align-items: baseline; gap: 8px; margin-bottom: 7px; min-width: 0; }
#ksTrackLabel {
    font-family: var(--ks-font-sans); font-size: 12px; font-weight: 500;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    flex: 0 1 auto; min-width: 0;
}
#ksTrackVoice {
    font-family: var(--ks-font-sans); font-size: 10px; letter-spacing: 1px;
    text-transform: uppercase; color: var(--ks-gold); flex-shrink: 0;
}
.ks-pl-seekrow { display: flex; align-items: center; gap: 8px; }
#ksCur, #ksDur { font-size: 11px; color: rgba(253,250,241,0.7); width: 36px; flex-shrink: 0; }
#ksCur { text-align: right; }
#ksSeek { flex: 1; min-width: 0; accent-color: var(--ks-gold); cursor: pointer; height: 6px; }

/* Speed selector */
#ksSpeed {
    width: 72px; min-width: 72px; max-width: 72px; box-sizing: border-box;
    background: rgba(253,250,241,0.12);
    color: var(--ks-cream);
    border: 0.5px solid rgba(253,250,241,0.3);
    border-radius: 6px;
    font-size: 11px; padding: 6px 4px;
    cursor: pointer; text-align: center;
    -webkit-appearance: menulist; appearance: menulist;
}
#ksSpeed option { color: #1F2952; background: #fff; font-size: 16px; padding: 10px; }

/* Loop + A–B toggles */
.ks-pl-toggle {
    background: rgba(253,250,241,0.1);
    border: 0.5px solid rgba(253,250,241,0.3);
    color: var(--ks-cream);
    border-radius: 6px; padding: 6px 9px; cursor: pointer;
    font-size: 11px; font-family: var(--ks-font-sans); line-height: 1;
}
.ks-pl-toggle.active { background: var(--ks-gold); color: var(--ks-navy); border-color: var(--ks-gold); }

/* The loop button carries a tiny state label (Off / One / All) so the three
   loop modes are discoverable — it reads as a labelled control rather than an
   icon you must guess at. The label sits to the right of the loop glyph. */
#ksLoop { display: inline-flex; align-items: center; gap: 5px; }
.ks-pl-loopstate {
    font-size: 10px; font-weight: 600; letter-spacing: 0.4px;
    font-family: var(--ks-font-sans); line-height: 1;
}

/* Loop-help (i) popover ──────────────────────────────────────────────────
   A small info control beside the loop button (both in the player bar and the
   practice-list header) that opens a click popover explaining Off / One / All.
   One pattern, two skins: --onbar (cream on the navy bar) and --light (navy on
   a light card). The popover opens UPWARD (the bar sits at screen bottom). */
.ks-loophelp { position: relative; display: inline-flex; align-items: center; flex: 0 0 auto; }
/* While open, raise the wrapper's stacking context so the popover paints above
   following cards (which come later in the DOM and would otherwise cover it). */
.ks-loophelp.is-open { z-index: 1101; }
.ks-loophelp__btn {
    display: inline-flex; align-items: center; gap: 5px; justify-content: center;
    height: 30px; padding: 0 6px;
    background: none; border: 0.8px solid var(--ks-border); cursor: pointer;
    border-radius: 999px;
    color: var(--ks-navy);
    font-family: var(--ks-font-sans); font-size: 11px; line-height: 1;
}
.ks-loophelp__btn:hover { border-color: var(--ks-gold); color: var(--ks-gold); }
.ks-loophelp__btn svg { display: block; width: 15px; height: 15px; flex-shrink: 0; }
/* Icon-only (no text label, e.g. practice-list header): a crisp round button.
   box-sizing + an explicit flex basis + matching min-width/height force a true
   32x32 square (so border-radius:50% renders a real circle); without these the
   0.8px border and the flex row's cross-axis sizing squashed it into an oval. */
.ks-loophelp__btn--icon {
    box-sizing: border-box;
    flex: 0 0 32px;
    width: 32px; height: 32px;
    min-width: 32px; max-width: 32px;
    min-height: 32px; max-height: 32px;
    padding: 0; gap: 0;
    border-radius: 50%;
}
.ks-loophelp__btn--icon svg { width: 16px; height: 16px; }
/* With a text label (e.g. song page “Loop?”): keep comfortable pill padding. */
.ks-loophelp__btnlabel { font-weight: 600; padding-right: 4px; }

/* The popover is FIXED-positioned and JS sets its top/left on open. Fixed
   positioning takes it out of every ancestor's flow, so no card overflow or
   stacking context can clip or cover it — it always paints on top, fully
   visible, anchored just under the (i) button. */
.ks-loophelp__pop {
    position: fixed;
    z-index: 4000;
    width: 270px; max-width: calc(100vw - 24px);
    display: flex; flex-direction: column; gap: 8px;
    padding: 14px 16px;
    background: var(--ks-cream);
    color: var(--ks-navy);
    border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-md, 10px);
    box-shadow: 0 8px 28px rgba(31, 41, 82, 0.28);
    font-family: var(--ks-font-sans);
    text-align: left;
}
.ks-loophelp__pop[hidden] { display: none; }
.ks-loophelp__title {
    font-family: var(--ks-font-serif); font-size: 13px; color: var(--ks-navy);
    margin: 0 0 2px;
}
/* Each mode row is a 2-column flex: a fixed-width mode chip on the left and the
   description on the right. The description wraps within its own column instead
   of flowing back under the mode word — so “Off / Plays through…” never breaks
   into “Off” on one line and “stops.” under it. */
.ks-loophelp__row {
    display: flex; align-items: baseline; gap: 8px;
    font-size: 12px; line-height: 1.45; color: var(--ks-slate, #5a5f68);
}
.ks-loophelp__mode {
    flex: 0 0 34px;
    font-weight: 700; color: var(--ks-navy);
}
.ks-loophelp__row span:last-child { flex: 1; min-width: 0; }
.ks-loophelp__foot {
    margin-top: 4px; padding-top: 8px;
    border-top: 0.5px solid var(--ks-border);
    font-size: 11px; line-height: 1.4; color: var(--ks-muted, #8a8f98);
}

/* “Audio by voice” heading row: title left, the loop (i) on the right. */
.ks-audio-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: var(--ks-space-sm);
}
.ks-audio-head__title { margin-bottom: 0; }

/* Sheet / Lyrics quick-open buttons */
.ks-pl-extra {
    background: rgba(253,250,241,0.1);
    border: 0.5px solid rgba(253,250,241,0.3);
    color: var(--ks-cream);
    border-radius: 6px; padding: 6px 9px; cursor: pointer;
    font-size: 11px; font-family: var(--ks-font-sans);
}
#ksClosePlayer { background: none; border: none; color: rgba(253,250,241,0.7); cursor: pointer; font-size: 18px; }
#ksCollapse { background: none; border: none; color: rgba(253,250,241,0.7); cursor: pointer; padding: 0; display: inline-flex; align-items: center; justify-content: center; }
#ksCollapse svg { transition: transform 0.15s ease; }
#ksPlayer { transition: transform 0.2s ease; }

/* Collapsed: slide the player down so only a slim tab (with the chevron + play)
   remains; the content panel/PDF then expands to full height. */
#ksPlayer.ks-collapsed .ks-pl-info,
#ksPlayer.ks-collapsed #ksControls,
#ksPlayer.ks-collapsed #ksPrev,
#ksPlayer.ks-collapsed #ksNext { display: none; }
#ksPlayer.ks-collapsed #ksPlayerInner { justify-content: center; gap: 16px; padding-top: 6px; padding-bottom: 6px; }

/* Control strip wrapper: on desktop, an inline flex group */
#ksControls { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; }

/* ── Desktop / laptop (≥640px): lift the bar off the bottom, bigger ────── */
@media (min-width: 640px) {
    #ksPlayer {
        bottom: 16px;
        left: calc(var(--kosis-sidebar-width, 260px) + 16px);
        right: 16px;
        border: 1px solid rgba(212,169,85,0.35);
        border-radius: var(--ks-radius-md);
        box-shadow: 0 10px 30px rgba(31,41,82,0.35);
    }
    #ksPlayerInner { padding: 14px 20px; gap: 14px; }
    #ksPanel.player-showing   { bottom: 92px; }   /* clear the lifted bar */
    #ksPanel.player-collapsed { bottom: 64px; }   /* clear the collapsed lifted bar */

    /* Distinguish the sheet/lyrics panel from the navy sidebar. The panel's
       PDF viewer is dark navy, the same colour as the sidebar, so without a
       gap the two read as one continuous block. Inset the panel from the
       sidebar (and the top/right) and round + shadow it so it floats as its
       own surface — matching the lifted player bar. Desktop only; on phones
       the panel is full-bleed. The inline `bottom` JS sets still wins; we only
       set top/left/right here. */
    #ksPanel {
        top: 16px;
        left: calc(var(--kosis-sidebar-width, 260px) + 16px);
        right: 16px;
        border: 1px solid var(--ks-border);
        border-radius: var(--ks-radius-md);
        overflow: hidden;            /* clip the body's navy to the rounded corners */
        box-shadow: 0 10px 30px rgba(31,41,82,0.28);
    }
    /* When no player is showing, the panel runs to a 16px bottom margin too, so
       it's evenly inset on all four sides (JS sets this bottom; this is the
       fallback for the first paint). */
    #ksPanel:not(.player-showing):not(.player-collapsed) { bottom: 16px; }
    /* Round the header's top corners to match the panel's rounding. */
    #ksPanelHeader { border-top-left-radius: var(--ks-radius-md); border-top-right-radius: var(--ks-radius-md); }
}

/* ── Mobile (<640px): pinned above the mobile nav, controls scroll strip ─ */
@media (max-width: 639px) {
    /* The player sits directly on top of the mobile bottom-nav. The nav is
       56px of link height PLUS the safe-area inset (home indicator), so match
       that exactly here instead of a flat 64px — a flat value left an 8px navy
       gap between the player and the nav on devices with an inset. */
    #ksPlayer { bottom: calc(56px + env(safe-area-inset-bottom, 0px)); left: 0; right: 0; }
    #ksPanel  { top: 0; }
    #ksPanel.player-showing   { bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 92px); }
    #ksPanel.player-collapsed { bottom: calc(56px + env(safe-area-inset-bottom, 0px) + 52px); }

    #ksPlayerInner {
        flex-wrap: wrap;
        overflow: visible;
        gap: 6px;
        padding: 10px 12px;
        row-gap: 10px;
        justify-content: center;
        position: relative;             /* anchor for the absolute close button */
    }
    #ksPlayerInner .ks-pl-info { order: 2; flex-basis: 100%; box-sizing: border-box; }
    #ksPrev, #ksPlayPause, #ksNext { order: 1; }

    /* On mobile the info block is a full-width row beneath the centred play
       controls, so the desktop left-divider/padding would look misplaced.
       Drop them and centre the title + time rows to match the layout. */
    #ksPlayerInner .ks-pl-info {
        padding-left: 0;
        margin-left: 0;
        border-left: none;
        text-align: center;
    }
    #ksPlayerInner .ks-pl-trackrow { justify-content: center; }

    /* Control strip: full width, ONE line, scrolls sideways if it overflows. */
    #ksControls {
        order: 3;
        flex-basis: 100%;
        flex-wrap: nowrap;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        gap: 6px;
        padding-bottom: 2px;
        scrollbar-width: none;          /* hide scrollbar (Firefox) */
    }
    /* Auto-margins centre the strip when it fits, collapse to 0 when it overflows. */
    #ksControls > :first-child { margin-left: auto; }
    #ksControls > :last-child  { margin-right: auto; }
    #ksControls::-webkit-scrollbar { display: none; }   /* hide scrollbar (WebKit) */
    #ksControls > * { flex: 0 0 auto; }

    /* Close (×) and Hide (chevron) ALWAYS top-right, side by side */
    #ksClosePlayer {
        position: absolute;
        top: 8px; right: 10px;
        width: 32px; height: 32px; padding: 0; margin: 0;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 20px; z-index: 2;
    }
    #ksCollapse {
        position: absolute;
        top: 8px; right: 46px;          /* just left of the × */
        width: 32px; height: 32px; padding: 0; margin: 0;
        display: inline-flex; align-items: center; justify-content: center;
        z-index: 2;
    }
    /* The info block is a full-width row BELOW the centred transport buttons.
       The ×/collapse buttons are pinned to the player's top-right corner (over
       the transport row), so the info row only needs a little side padding to
       breathe — not the wide reserve that was strangling the title + seek bar. */
    #ksPlayerInner .ks-pl-info { padding-left: 14px; padding-right: 14px; }

    #ksSpeed {
        width: 70px !important; min-width: 70px !important; max-width: 70px !important;
        font-size: 12px !important; padding: 7px 3px !important; height: 36px;
    }
    /* A and B stay square; the loop button now carries a text label
       (Off/One/All) so it sizes to its content instead of a fixed 38px —
       a fixed width squashed the icon + label together. */
    #ksSetA, #ksSetB {
        width: 38px; height: 36px; padding: 0;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 13px;
    }
    #ksLoop {
        height: 36px; width: auto; padding: 0 12px; gap: 6px;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 13px; white-space: nowrap;
    }
    #ksLoop .ks-pl-loopstate { font-size: 11px; }
    #ksOpenSheetBtn, #ksOpenLyricsBtn {
        height: 36px; padding: 0 12px;
        display: inline-flex; align-items: center; justify-content: center;
        font-size: 12px; white-space: nowrap;
    }

    /* Collapsed on mobile: a slim bar — just the play button, with the
       chevron + × pinned top-right. No wrapped rows, no empty space. */
    #ksPlayer.ks-collapsed #ksPlayerInner {
        flex-wrap: nowrap;
        justify-content: center;
        padding: 8px 12px;
        min-height: 0;
    }
    #ksPlayer.ks-collapsed .ks-pl-info { padding-right: 0; }
    #ksPlayer.ks-collapsed #ksCollapse,
    #ksPlayer.ks-collapsed #ksClosePlayer { top: 50%; transform: translateY(-50%); }
}

/* ════════════════════════════════════════════════════════════════════════
   MOBILE/PHONE SHEET VIEWER — reclaim vertical space
   ------------------------------------------------------------------------
   Applies to phones in BOTH orientations: portrait (narrow width) AND
   landscape (short height). A landscape phone is ~932px WIDE, so a plain
   max-width:639px query would NOT catch it — that was the bug where landscape
   showed the old full-width zoom bar and no immersive/hint. We therefore key
   off "narrow OR short" so the phone case is caught either way, while a real
   laptop/desktop (wide AND tall) keeps the untouched desktop viewer.

   Three space-savers:
   (1) Slimmer title bar — smaller padding + font.
   (2) Floating zoom pill — the zoom toolbar (.ks-pdf-bar) becomes a compact
       pill ANCHORED to the panel's own bottom-right (position:absolute inside
       #ksPanelBody), so it always sits just above the panel's real bottom edge
       — no hand-computed player-height math that broke when the player wraps.
   (3) Immersive mode — tapping the sheet (JS in player-bar.php) hides the
       title bar + player bar so the PDF fills the screen. Tap again to restore.
   ════════════════════════════════════════════════════════════════════════ */
@media (max-width: 639px), (max-height: 600px) and (orientation: landscape) {
    /* (1) Slimmer title bar. */
    #ksPanelHeader {
        padding: 6px 12px;
        padding-top: calc(6px + env(safe-area-inset-top, 0px));
    }
    #ksPanelTitle { font-size: 12px; }
    #ksPanelClose { font-size: 20px; }

    /* (2) Zoom controls now live INSIDE the panel header (built in
       player-bar.php), to the left of the ×. This keeps one clean header row
       — Title … [− % +] [×] — so the controls never cover the close button,
       never scroll away with the sheet, and need no JS positioning. The header
       gets .has-pdf-zoom while a PDF is shown. */
    #ksPanelHeader.has-pdf-zoom { gap: 8px; }
    #ksPanelHeader .ks-pdf-bar {
        position: static;
        display: inline-flex; align-items: center; gap: 4px;
        flex: 0 0 auto;
        padding: 3px 4px;
        background: var(--ks-navy);
        border-radius: 999px;
        box-shadow: none; backdrop-filter: none;
    }
    #ksPanelHeader .ks-pdf-zoom {
        width: 28px; height: 28px; border-radius: 50%;
        font-size: 16px;
        border: 0.5px solid rgba(253,250,241,0.3);
        background: rgba(253,250,241,0.12); color: var(--ks-cream);
        display: inline-flex; align-items: center; justify-content: center;
        line-height: 1; cursor: pointer; padding: 0;
    }
    #ksPanelHeader .ks-pdf-zoomlbl {
        color: var(--ks-cream); font-size: 11px; min-width: 36px; text-align: center;
    }
    /* No top padding needed now that there's no sticky toolbar in the body. */
    #ksPanelBody.pdf-mode .ks-pdf-pages { padding-top: 6px; }

    /* (3) Immersive mode (toggled by tapping the sheet). */
    /* No bottom transition on phones: JS sets the panel bottom to the player's
       measured top, and an animation would visibly slide through a wrong value
       (showing a momentary gap). Keep it instant + exact. */
    #ksPanel { transition: none; }
    /* Collapse the title bar to zero height (not just translate it — translate
       left an empty gap). It's removed from flow and the body grows to fill. */
    #ksPanel.ks-immersive #ksPanelHeader {
        height: 0; min-height: 0; padding: 0; margin: 0;
        overflow: hidden; border: none;
    }
    /* Player bar hidden by JS (.ks-immersive-hide), so the panel can drop all
       the way to the mobile nav (portrait) or screen bottom (landscape). */
    #ksPlayer.ks-immersive-hide { display: none !important; }
    #ksPanel.ks-immersive.player-showing,
    #ksPanel.ks-immersive.player-collapsed { bottom: 64px; }

    /* Discoverability cue: a brief "Tap to hide controls" hint, FIXED to the
       viewport (not absolute inside the scrolling body) so it doesn't scroll
       away and isn't covered by the player. JS sets its bottom to sit just
       above the panel's real bottom edge; this is the no-JS fallback position.
       Fades out on its own (pure CSS). */
    #ksPanelBody.pdf-mode .ks-pdf-pages::after {
        content: "Tap the sheet to hide controls";
        position: fixed;
        left: 50%; transform: translateX(-50%);
        top: 60px;
        background: rgba(31,41,82,0.92);
        color: var(--ks-cream);
        font-family: var(--ks-font-sans); font-size: 11px;
        padding: 6px 12px; border-radius: 999px;
        border: 0.5px solid rgba(253,250,241,0.25);
        box-shadow: 0 4px 16px rgba(0,0,0,0.3);
        pointer-events: none; z-index: 996;
        opacity: 0;
        animation: ksSheetHint 4s ease forwards;
    }
    #ksPanel.ks-immersive #ksPanelBody.pdf-mode .ks-pdf-pages::after { display: none; }
    @keyframes ksSheetHint {
        0%   { opacity: 0; }
        12%  { opacity: 1; }
        75%  { opacity: 1; }
        100% { opacity: 0; }
    }
    @media (prefers-reduced-motion: reduce) {
        #ksPanelBody.pdf-mode .ks-pdf-pages::after { animation: none; opacity: 0; }
    }
}

/* ── Landscape phone: tighten the reserved bottom space ──────────────────
   In landscape a phone is WIDE, so the player controls fit on fewer rows and
   the bar is shorter than the ~92px portrait stack. The portrait reservation
   (#ksPanel.player-showing { bottom: 64px + 92px }) then leaves a tall empty
   navy band below the sheet. Here we (a) drop the player to the very bottom
   (no mobile-nav offset — in landscape the bottom nav is not the constraint),
   and (b) shrink the panel's reserved bottom to just the real (shorter) bar
   height, so the PDF area extends down to meet the player with no dead gap.
   Immersive still hides the bar entirely for a full-screen sheet. */
@media (max-height: 600px) and (orientation: landscape) {
    #ksPlayer { bottom: 0; left: 0; right: 0; border-radius: 0; }
    #ksPanel  { left: 0; }
    #ksPanel.player-showing   { bottom: 84px; }
    #ksPanel.player-collapsed { bottom: 52px; }
    #ksPanel.ks-immersive.player-showing,
    #ksPanel.ks-immersive.player-collapsed { bottom: 0; }
}

/* ── PDF.js canvas viewer (inside #ksPanelBody) ─────────────────────────── */
.ks-pdf-bar {
    display: inline-flex; align-items: center; gap: 6px;
    flex: 0 0 auto;            /* never shrink: a long title truncates instead */
    padding: 4px 6px;
    background: var(--ks-navy);
    border-radius: 999px;
}
#ksPanelHeader.has-pdf-zoom { gap: 10px; }
.ks-pdf-zoom {
    width: 30px; height: 30px; border-radius: 50%;
    border: 0.5px solid rgba(253,250,241,0.3);
    background: rgba(253,250,241,0.12); color: var(--ks-cream);
    font-size: 16px; line-height: 1; cursor: pointer; padding: 0;
    display: inline-flex; align-items: center; justify-content: center;
}
.ks-pdf-zoomlbl { color: var(--ks-cream); font-family: var(--ks-font-sans); font-size: 11px; min-width: 38px; text-align: center; }
.ks-pdf-pages {
    display: block;
    padding: 12px;
    text-align: center;
    min-height: 100%;
    box-sizing: border-box;
}
.ks-pdf-canvas {
    display: block;
    margin: 0 auto 12px;
    max-width: 100%;            /* fill the panel width by default (looks full-screen) */
    height: auto;
    box-shadow: 0 4px 16px rgba(0,0,0,0.35); background: #fff;
}
/* When zoomed in beyond the panel, the canvas may exceed 100% — allow that and scroll */
#ksPanelBody.pdf-mode.zoomed .ks-pdf-canvas { max-width: none; }
.ks-pdf-loading { color: var(--ks-cream); font-family: var(--ks-font-sans); font-size: 13px; padding: 24px; text-align: center; }

/* ═══════════════════════════════════════════════════════════════════════
   PRACTICE LISTS · SHARING · AUDIO 3-DOTS MENU  (Piece D)
   Extracted from inline styles (Stage 4 cleanup).
   ═══════════════════════════════════════════════════════════════════════ */

/* Breadcrumb trail (song page + practice pages) ──────────────────────────
   A visible, branded trail: a parchment pill that sits apart from the page,
   navy links that read as clickable (gold on hover — the brand interaction
   colour), a clear chevron separator, and the current page in steady navy.
   Replaces the old faint 12px sage-on-cream text that was nearly invisible. */
.ks-breadcrumb {
    display: inline-flex; align-items: center; flex-wrap: wrap; gap: 4px;
    font-family: var(--ks-font-sans);
    font-size: 13px; line-height: 1.2;
    margin-bottom: var(--ks-space-md);
    padding: 7px 14px;
    background: var(--ks-parchment);
    border: 0.5px solid var(--ks-border);
    border-radius: 999px;
    max-width: 100%;
}
.ks-breadcrumb a {
    display: inline-flex; align-items: center; gap: 4px;
    color: var(--ks-navy);
    font-weight: 500;
    text-decoration: none;
    padding: 2px 4px;
    border-radius: 5px;
    transition: color .12s ease, background .12s ease;
}
.ks-breadcrumb a:hover {
    color: var(--ks-gold);
    background: rgba(212, 169, 85, 0.12);
    text-decoration: none;
}
/* A small back-arrow on the FIRST crumb signals “return” at a glance. */
.ks-breadcrumb a:first-of-type::before {
    content: "\2039";
    font-size: 15px;
    line-height: 1;
    color: var(--ks-gold);
    margin-right: 1px;
}
.ks-breadcrumb .sep {
    color: var(--ks-muted);
    font-size: 12px;
    margin: 0 1px;
    user-select: none;
}
.ks-breadcrumb .cur,
.ks-breadcrumb .cur-list {
    color: var(--ks-navy);
    font-weight: 500;
    max-width: 38ch;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ── Audio 3-dots menu ─────────────────────────────────────────────── */
.ks-audio-menu { position: relative; flex-shrink: 0; }
.ks-audio-dots {
    background: none; border: none; color: var(--ks-slate); cursor: pointer;
    padding: 4px; width: 30px; height: 30px;
    display: inline-flex; align-items: center; justify-content: center;
    border-radius: 6px;
}
.ks-audio-dots:hover { background: var(--ks-parchment); }
.ks-audio-pop {
    display: none; position: absolute; right: 0; top: 100%; z-index: 50;
    background: var(--ks-cream); border: 0.5px solid var(--ks-border);
    border-radius: var(--ks-radius-sm); box-shadow: 0 8px 24px rgba(31,41,82,0.18);
    min-width: 220px; padding: 8px;
}
.ks-pop-label {
    font-size: 10px; letter-spacing: 1px; text-transform: uppercase;
    color: var(--ks-slate); padding: 4px 8px 6px;
}
.ks-pop-divider { border-top: 0.5px solid var(--ks-border); margin: 6px 0 0; padding-top: 6px; }
.ks-pop-item {
    display: block; width: 100%; text-align: left; box-sizing: border-box;
    background: none; border: none; cursor: pointer;
    padding: 6px 8px; border-radius: 6px; font-size: 12px;
    color: var(--ks-navy); text-decoration: none; font-family: var(--ks-font-sans);
}
.ks-pop-item:hover { background: var(--ks-parchment); }
.ks-pop-item--danger { color: #8B2E2E; }
.ks-pop-toggle {
    display: flex; align-items: center; gap: 8px; width: 100%;
    background: none; border: none; cursor: pointer; text-align: left;
    padding: 6px 8px; border-radius: 6px; font-size: 12px; color: var(--ks-navy);
}
.ks-pop-toggle:hover { background: var(--ks-parchment); }
.ks-pop-check {
    width: 16px; height: 16px; border: 1.5px solid var(--ks-border);
    border-radius: 4px; display: inline-flex; align-items: center;
    justify-content: center; flex-shrink: 0;
}
.ks-pop-check.on { border-color: var(--ks-sage); background: var(--ks-sage); }
.ks-pop-text { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ── Audio track row ───────────────────────────────────────────────── */
.ks-audio-row {
    padding: 8px 0; border-bottom: 0.5px solid var(--ks-border);
}
.ks-audio-row__inner { display: flex; align-items: center; gap: var(--ks-space-sm); }
.ks-audio-row__label {
    color: var(--ks-navy); font-size: 12px; flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ks-audio-badge {
    flex-shrink: 0; color: var(--ks-slate); font-size: 10px;
    display: inline-flex; align-items: center; gap: 3px; white-space: nowrap;
}
.ks-inlist-badge {
    flex-shrink: 0; display: inline-flex; align-items: center; gap: 3px;
    color: var(--ks-sage); font-size: 10px;
}

/* ── Edit panel (inside the 3-dots menu) ───────────────────────────── */
.ks-edit-field-label { display: block; font-size: 10px; color: var(--ks-slate); margin-bottom: 3px; }
.ks-edit-radio {
    display: flex; align-items: center; gap: 6px; font-size: 12px;
    color: var(--ks-navy); padding: 2px 0; cursor: pointer;
}
.ks-edit-voices { padding: 4px 0 4px 18px; }
.ks-edit-meta { font-size: 10px; color: var(--ks-slate); margin: 6px 0 8px; }

/* ── Practice-list cards (overview + setlists card) ────────────────── */
.ks-pl-grid {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: var(--ks-space-md);
}
.ks-pl-card {
    text-decoration: none; display: flex; align-items: center; gap: var(--ks-space-md);
    padding: var(--ks-space-md);   /* tighter than the default card padding */
}
.ks-pl-icon {
    width: 44px; height: 44px; border-radius: 10px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--ks-navy); color: var(--ks-gold);
}
.ks-pl-icon--shared { background: var(--ks-shared); color: var(--ks-gold); }
.ks-pl-card__title {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    font-family: var(--ks-font-serif); font-size: 14px; line-height: 1.3;
    color: var(--ks-navy); overflow: hidden; word-break: break-word;
}
.ks-pl-card__meta { color: var(--ks-slate); font-size: 11px; }

/* Compact list-row variant (setlists "Your practice lists" card) */
.ks-pl-row {
    display: flex; align-items: center; gap: 10px; padding: 8px 10px;
    border: 0.5px solid var(--ks-border); border-radius: var(--ks-radius-sm);
    text-decoration: none;
}
.ks-pl-row__icon {
    width: 32px; height: 32px; border-radius: 8px; flex-shrink: 0;
    display: flex; align-items: center; justify-content: center;
    background: var(--ks-sage); color: var(--ks-cream);
}
.ks-pl-row__icon--navy { background: var(--ks-navy); color: var(--ks-gold); }
.ks-pl-row__icon--shared { background: var(--ks-shared); color: var(--ks-gold); }

/* "Shared with N" pill — small status chip on practice-list boxes */
.ks-shared-pill {
    display: inline-flex; align-items: center; gap: 4px;
    background: var(--ks-shared-soft); color: var(--ks-shared);
    font-family: var(--ks-font-sans); font-size: 10px; font-weight: 600;
    letter-spacing: 0.3px; padding: 2px 8px; border-radius: 999px;
    white-space: nowrap;
}
.ks-shared-pill svg { width: 11px; height: 11px; }
.ks-pl-row__body { flex: 1; min-width: 0; }
.ks-pl-row__title {
    display: block; font-family: var(--ks-font-serif); font-size: 13px;
    color: var(--ks-navy); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ks-pl-row__chev { color: var(--ks-slate); flex-shrink: 0; }

/* List detail header */
.ks-pl-head { display: flex; align-items: center; gap: var(--ks-space-md); margin-bottom: var(--ks-space-md); }
.ks-pl-head__body { flex: 1; min-width: 0; }

/* Practice-list DETAIL header (icon + title block + control cluster) ──────
   Desktop: one aligned row — icon, the flexible title body, then the controls
   (Play-all, loop pill, (i) help, 3-dots menu) pinned to the right. The body
   has flex:1 so it eats the slack and pushes the controls to the edge.
   Mobile: the controls wrap to their OWN row beneath the icon+title instead of
   crowding them. We do that by letting the row wrap and forcing the body to a
   full-width basis at the narrow breakpoint (see the @media block below). */
.ks-pl-detail-head {
    display: flex; align-items: center; flex-wrap: wrap;
    gap: var(--ks-space-sm) var(--ks-space-md);
    margin-bottom: var(--ks-space-md);
}
.ks-pl-detail-head > .ks-pl-icon { flex: 0 0 auto; }
.ks-pl-detail-head .ks-pl-head__body { flex: 1 1 200px; min-width: 0; }
/* The control cluster members keep their natural size and never shrink. */
.ks-pl-detail-head > #ksPlayAll,
.ks-pl-detail-head > #ksPlLoop,
.ks-pl-detail-head > .ks-loophelp,
.ks-pl-detail-head > .ks-audio-menu { flex: 0 0 auto; }

.ks-play-all {
    flex-shrink: 0; width: 44px; height: 44px; border-radius: 50%;
    border: none; background: var(--ks-sage); color: var(--ks-cream);
    cursor: pointer; display: flex; align-items: center; justify-content: center;
}

/* Header loop toggle (practice-list detail) ──────────────────────────
   A second loop control beside “Play all” that drives the SAME loop state as
   the player-bar button (via KosisPlayer.cycleLoop). On this light card it uses
   a navy outline; when active (loop one/all) it fills gold, matching the
   player-bar toggle's active cue. The Off/One/All label makes the mode clear. */
.ks-pl-looptoggle {
    flex-shrink: 0;
    display: inline-flex; align-items: center; gap: 5px;
    height: 30px; padding: 0 10px;
    border: 0.8px solid var(--ks-border);
    background: transparent; color: var(--ks-navy);
    border-radius: 999px; cursor: pointer;
    font-family: var(--ks-font-sans); font-size: 11px; line-height: 1;
}
.ks-pl-looptoggle:hover { border-color: var(--ks-gold); }
.ks-pl-looptoggle.active {
    background: var(--ks-gold); color: var(--ks-navy); border-color: var(--ks-gold);
}
.ks-pl-looptoggle__state { font-weight: 600; letter-spacing: 0.3px; }
.ks-pl-looptoggle svg { flex-shrink: 0; width: 14px; height: 14px; display: block; }

/* Mobile: the detail-header controls drop to their own row under the title.
   Giving the title body a 100% basis forces a wrap after it, so the icon+title
   sit on line 1 and Play-all / loop / (i) / menu flow onto line 2, left-aligned
   and roomy instead of crammed against the title. */
@media (max-width: 639px) {
    .ks-pl-detail-head .ks-pl-head__body { flex-basis: calc(100% - 44px - var(--ks-space-md)); }
    .ks-pl-detail-head > #ksPlayAll { order: 3; }
    .ks-pl-detail-head > #ksPlLoop { order: 4; }
    .ks-pl-detail-head > .ks-loophelp { order: 5; }
    .ks-pl-detail-head > .ks-audio-menu { order: 6; margin-left: auto; }
}

/* ── Share page ────────────────────────────────────────────────────── */
.ks-voice-chips { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: var(--ks-space-md); }
.ks-voice-chip {
    border: 0.8px solid var(--ks-border); background: transparent; color: var(--ks-navy);
    border-radius: 999px; padding: 5px 14px; font-size: 12px; cursor: pointer;
    font-family: var(--ks-font-sans);
}
.ks-voice-chip.active { border-color: var(--ks-sage); background: var(--ks-sage); color: var(--ks-cream); }
.ks-member-list {
    display: flex; flex-direction: column; gap: 4px;
    max-height: 420px; overflow-y: scroll; scrollbar-gutter: stable;
}
.ks-share-member {
    display: flex; align-items: center; gap: 10px; padding: 8px 10px;
    border: 0.5px solid var(--ks-border); border-radius: var(--ks-radius-sm); cursor: pointer;
}
.ks-share-member__avatar {
    width: 34px; height: 34px; border-radius: 50%; flex: 0 0 34px;
    background: var(--ks-sage); color: var(--ks-cream);
    display: flex; align-items: center; justify-content: center;
    font-size: 12px; font-weight: 600;
}
.ks-share-member__body { flex: 1 1 auto; min-width: 0; }
.ks-share-member__name {
    display: block; font-size: 13px; color: var(--ks-navy);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.ks-share-member__sub { color: var(--ks-slate); font-size: 11px; }
.ks-share-member__check { width: 18px; height: 18px; flex: 0 0 18px; accent-color: var(--ks-sage); margin: 0; }

/* ═══════════════════════════════════════════════════════════════════════
   NOW-PLAYING HIGHLIGHT  (Session 74)
   Marks the track currently loaded in the shared player (includes/player-bar.php).
   The player JS adds .ks-playing to the play button AND its enclosing row
   (.ks-audio-row on the song page, .ks-track-row on practice lists), plus
   .ks-playing--paused while paused so the equalizer freezes. No markup change
   on the pages — purely class-driven, so it works on both surfaces.
   ═══════════════════════════════════════════════════════════════════════ */

/* Tinted row + gold left accent bar. Both row types get a relative position so
   the ::before accent can anchor to the left edge. */
.ks-audio-row.ks-playing,
.ks-track-row.ks-playing {
    position: relative;
    background: var(--ks-shared-soft, rgba(74,111,92,0.08));
    border-radius: var(--ks-radius-sm);
}
.ks-audio-row.ks-playing { padding-left: 10px; }
.ks-audio-row.ks-playing::before,
.ks-track-row.ks-playing::before {
    content: "";
    position: absolute;
    left: 0; top: 50%; transform: translateY(-50%);
    width: 3px; height: 70%;
    background: var(--ks-gold);
    border-radius: 0 3px 3px 0;
}

/* The active play button: keep the sage circle but lift it with a soft ring so
   it reads as "this one". */
.ks-play-btn.ks-playing {
    background: var(--ks-gold);
    color: var(--ks-navy);
    box-shadow: 0 0 0 3px rgba(212,169,85,0.28);
    position: relative;
}

/* Animated equalizer overlay on the active play button. Three bars built from a
   repeating-linear-gradient (no extra markup); each "bar" is a gold column and
   the whole strip bounces via background-position. Hidden behind the play icon
   normally; shown only while playing. We render it as a ::after that sits over
   the button, dimming the play triangle so the equalizer is the focal point. */
.ks-play-btn.ks-playing::after {
    content: "";
    position: absolute;
    inset: 0;
    border-radius: 50%;
    background: var(--ks-navy);
    -webkit-mask: repeating-linear-gradient(90deg,
        #000 0, #000 3px, transparent 3px, transparent 6px);
            mask: repeating-linear-gradient(90deg,
        #000 0, #000 3px, transparent 3px, transparent 6px);
    /* three bars centred in the circle */
    -webkit-mask-size: 6px 100%;
            mask-size: 6px 100%;
    -webkit-mask-position: center;
            mask-position: center;
    display: none;
}
/* While actively playing, reveal the equalizer and animate the bar heights via
   a clip-path that bounces. We animate three pseudo-bars by scaling the mask
   vertically with a keyframe on the element's clip-path. */
.ks-play-btn.ks-playing:not(.ks-playing--paused)::after {
    display: block;
    animation: ksEqBounce 0.9s ease-in-out infinite;
}
@keyframes ksEqBounce {
    0%, 100% { clip-path: inset(35% 0 0 0); }
    25%      { clip-path: inset(10% 0 0 0); }
    50%      { clip-path: inset(50% 0 0 0); }
    75%      { clip-path: inset(20% 0 0 0); }
}
/* Paused: keep the gold button + ring, but no equalizer motion (already hidden
   by the :not(.ks-playing--paused) guard above). Nothing extra needed. */

/* Respect reduced-motion: show a static equalizer rather than animating. */
@media (prefers-reduced-motion: reduce) {
    .ks-play-btn.ks-playing:not(.ks-playing--paused)::after {
        animation: none;
        clip-path: inset(25% 0 0 0);
    }
}
