:root { --bg:#0e0f13; --card:#191b22; --fg:#e8e8ee; --mut:#8a8f9c;
        --acc:#e23b54; }
* { box-sizing:border-box; }
/* `hidden` attr must always win over component display rules (the
   Columns menu / right-pane Edit tab toggle via [hidden]). */
[hidden] { display:none !important; }
body { margin:0; background:var(--bg); color:var(--fg);
       font:15px/1.5 system-ui,Segoe UI,Roboto,sans-serif; }
/* Themed scrollbars: transparent (see-through) track, accent-red thumb —
   matches the dark UI instead of the default OS bars. `scrollbar-color`
   inherits, so setting it on html themes every scroll area (Firefox);
   the ::-webkit-scrollbar pseudo-elements cover Chrome/Safari/Edge. The
   thumb's transparent border + padding-box clip lets the track show
   around it, so only the bar itself is solid red. */
html { scrollbar-width:thin; scrollbar-color:var(--acc) transparent; }
::-webkit-scrollbar { width:11px; height:11px; }
::-webkit-scrollbar-track { background:transparent; }
::-webkit-scrollbar-thumb { background:var(--acc); border-radius:7px;
   border:2px solid transparent; background-clip:padding-box; }
::-webkit-scrollbar-thumb:hover { background:#ff4d68; }
::-webkit-scrollbar-corner { background:transparent; }
a { color:var(--acc); text-decoration:none; }
a:hover { text-decoration:underline; }
/* --- Exiled network top bar — mirrors exiledshop.com so the brand, emblem,
   68px height and EXILEDHQ screen-X line up across all three sites for a
   seamless cross-site transition. Literal colors match exiledshop's. --- */
.navbar { background:rgba(13,15,20,0.95); border-bottom:1px solid #252a38;
   backdrop-filter:blur(12px); position:sticky; top:0; z-index:100; }
/* Full-width bar (no centered max-width cap) so the brand hugs the far LEFT
   edge and the menu the far right, at every screen width. */
.nav-inner { max-width:none; margin:0; padding:0 1.5rem; height:68px;
   display:flex; align-items:center; justify-content:space-between; }
/* EXILEDRADIO leads (current site), then the [emblem][EXILEDHQ] lockup (emblem
   in front, matching exiledhq.com's own .brand look). This 2px spaces
   EXILEDRADIO from the lockup; the 2px emblem<->EXILEDHQ gap inside the lockup
   comes from .exiled-brand's own gap — so all three sit at a uniform 2px. */
.nav-brand-group { display:flex; align-items:center; gap:2px; }
.exiled-brand { display:inline-flex; align-items:center; gap:2px; color:#fff;
   line-height:1; font-family:'Oswald', system-ui, sans-serif; font-weight:700;
   font-size:1.6rem; letter-spacing:.12em; text-transform:uppercase;
   text-decoration:none; transition:transform .25s ease; }
.exiled-brand:hover { text-decoration:none; transform:translateY(-1px); }
.nav-emblem { width:48px; height:48px; object-fit:contain; display:block;
   flex-shrink:0; }
.ex-accent { color:#ff0013; }                  /* logo red ("RADIO") */
/* EXILEDHQ's "HQ" is white but lights up red on hover — a continuity cue
   toward exiledhq.com's permanent red. */
.hq-glow { color:#fff; transition:color .25s ease, text-shadow .25s ease; }
.exiled-brand:hover .hq-glow { color:#ff0013;
   text-shadow:0 0 8px rgba(255,0,19,.65), 0 0 18px rgba(255,0,19,.45); }
/* "You are here" marker under the current site's wordmark. */
.exiled-brand.is-current { position:relative; }
.exiled-brand.is-current::after { content:""; position:absolute; left:0;
   right:0; bottom:-6px; height:2px; background:#ff0013; border-radius:2px;
   opacity:.85; }
.nav-links { display:flex; align-items:center; gap:4px; }
.nav-link { color:#f4f5f7; font-weight:600; font-size:.9rem;
   padding:8px 10px; border-radius:8px;
   transition:background .2s, color .2s; }
.nav-link:hover { color:#f4f5f7; background:#1a1e29; text-decoration:none; }
/* Schedule / Admin / Log out (+ Log in): white at rest, logo-red (#ff0013)
   on hover AND while you're on that page (.is-active — set server-side in
   base.html and re-toggled by admin.js on pjax since the bar persists).
   Mirrors exiledshop.com's nav-link behavior. */
.nav-schedule:hover, .nav-schedule.is-active,
.nav-admin:hover,    .nav-admin.is-active,
.nav-login:hover,
.nav-logout:hover { color:#ff0013 !important; }
.nav-links .who { color:#f4f5f7; font-weight:600; font-size:.9rem; }
@media (max-width:640px) {
  .nav-brand-group { gap:.85rem; }
  .exiled-brand { font-size:1.15rem; gap:8px; }
  .nav-emblem { width:36px; height:36px; }
}
.wrap { max-width:1000px; margin:24px auto; padding:0 20px; }
.card { background:var(--card); border:1px solid #23252e; border-radius:10px;
        padding:16px 20px; margin:16px 0; }
h1 { font-size:24px; } h3 { margin-top:0; }
.muted { color:var(--mut); }
.np-track { font-size:26px; font-weight:700; }
.np-artist { font-size:18px; color:var(--mut); }
/* Live: track title sits quietly under the "LIVE — DJ" headline. */
.np-sub { font-size:14px; opacity:.7; margin-top:2px; }
.np-show { margin-top:6px; color:var(--mut); }
.np-label { text-transform:uppercase; letter-spacing:1px; font-size:11px;
            color:var(--mut); }
audio { width:100%; margin:6px 0 14px; }

/* --- 3-column now-playing header (site-wide, under .nav) --- */
.hdr { display:grid; grid-template-columns:1fr 1fr minmax(220px,auto);
       gap:28px; align-items:start; padding:14px 24px;
       background:#11131a; border-bottom:1px solid #23252e;
       transition:transform .3s ease, opacity .3s ease; }
/* Home-only immersive mode: the player bar slides away after playback
   starts (viz.js toggles this), revealed by moving to the top / tapping.
   Other pages (incl. /admin) never get this class, so it stays static. */
.hdr.er-hide { transform:translateY(-100%); opacity:0;
       pointer-events:none; }
.hcol { min-width:0; }
/* Cover is flush to the header's left edge (negative left margin cancels
   .hdr's 24px padding) and a fixed square so it can NEVER drive the flex
   line height — an <img> has an intrinsic size and would otherwise stretch
   the whole header. The -14px top/bottom margins absorb it into the
   header's vertical padding so the band height stays exactly as before. */
/* align-self:stretch makes this column as tall as the full header row
   (column 3 — clock + Listen/transport — is the tallest), so the cover
   reaches the bottom bar instead of stopping at the text height. */
.nb-c1 { display:flex; gap:14px; align-items:stretch; align-self:stretch;
         margin:-14px 0 -14px -24px; }
.nb-c1 .nb-meta { min-width:0; flex:1; align-self:center; }
/* align-self:stretch makes the cover span the text block; min-height:0 is
   essential — without it the <img>'s intrinsic size drives the flex line
   and balloons the header. The -14px margins then carry it through the
   header's vertical padding so it touches the top & bottom bars; width is
   fixed (square-ish vs the resulting band height) so it can't grow. */
.nb-cover { align-self:stretch; height:auto; min-height:0; width:112px;
            flex:none; display:block; object-fit:cover;
            background:#23252e; border:0; border-radius:0; }
@media (max-width:720px) {
  .nb-cover { width:72px; }
}
.hcol-right { text-align:right; justify-self:end; }
.hcol-top { font-size:20px; font-weight:700; white-space:nowrap;
            overflow:hidden; text-overflow:ellipsis; color:var(--fg); }
.hcol-top.on { color:#9be8b8; }
.hcol-top.live { color:var(--acc); }
.hcol-sub { font-size:16px; color:var(--fg); margin-top:3px;
            white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.hcol-xs { font-size:12px; color:var(--mut); margin-top:3px;
           white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.nb-times { display:flex; justify-content:space-between;
            font-size:12px; color:var(--mut); }
.nb-clock { font-variant-numeric:tabular-nums; font-weight:700;
            font-size:46px; line-height:1; color:var(--fg);
            letter-spacing:1px; }
.xport { display:flex; gap:6px; align-items:center;
         justify-content:flex-end; margin-top:10px; flex-wrap:wrap; }
/* Station transport: hidden until JS marks the page as an admin one. */
.xport-tr { display:none; align-items:center; gap:6px; }
body.er-admin .xport-tr { display:inline-flex; }
.xbtn { background:#23252e; color:var(--fg); border:0; border-radius:6px;
        padding:6px 10px; cursor:pointer; font-size:14px; line-height:1; }
.xbtn:hover:not(:disabled) { background:#2f3340; }
.xbtn:disabled { opacity:.4; cursor:not-allowed; }
.nb-prog { position:relative; height:5px; background:#23252e;
           border-radius:3px; margin:6px 0 2px; }
.nb-prog-fill { border-radius:3px; }
.nb-seektip { display:none; position:absolute; bottom:9px;
              transform:translateX(-50%); background:#000; color:#fff;
              font-size:11px; padding:2px 6px; border-radius:4px;
              white-space:nowrap; pointer-events:none;
              font-variant-numeric:tabular-nums; }
.nb-prog-fill { height:100%; width:0; background:var(--acc);
                transition:width .9s linear; }
.nb-show-fill { background:#3a6ea5; }
/* **Station** paused (body.er-paused, toggled by _nowbar.html when the
   now-playing payload reports `NP.paused`): the actual server-side
   broadcast is on dead air via the admin Broadcast ⏯ transport, so the
   progress fills should freeze + dim. NOT triggered by the listen
   widget's per-listener pause — that's intentionally decoupled. The
   `transition:none` cancels the bar's normal 0.9s glide so the freeze
   is instant instead of smoothly settling toward the last-ticked width. */
body.er-paused .nb-prog-fill { opacity:.45; transition:none; }
body.er-paused .nb-times { opacity:.45; }
@media (max-width:720px) {
  .hdr { grid-template-columns:1fr; gap:10px; }
  .hcol-right { text-align:left; justify-self:start; }
  .nb-clock { font-size:34px; }
}

/* --- inline Listen widget (header col 3, admin + public) --- */
.lw { display:inline-flex; align-items:center; gap:6px; }
#lw-audio { display:none; }
.lw-pp { display:inline-flex; align-items:center; background:var(--acc);
         color:#fff; border:0; border-radius:6px; padding:6px 11px;
         cursor:pointer; font-size:13px; line-height:1; font-weight:600; }
.lw-label[hidden] { display:none; }
.lw-x { display:inline-flex; align-items:center; gap:6px; }
.lw-ic { background:#23252e; color:var(--fg); border:0; border-radius:6px;
         padding:6px 9px; cursor:pointer; font-size:13px; line-height:1; }
.lw-ic:hover { background:#2f3340; }
/* Range with exact edge-to-edge fill (no native thumb dead space). */
.lw-vsl { -webkit-appearance:none; appearance:none; width:90px; height:6px;
          border-radius:3px; cursor:pointer; vertical-align:middle;
          background:linear-gradient(to right,
            var(--acc) var(--vp,100%), #3a3d49 var(--vp,100%)); }
.lw-vsl::-webkit-slider-thumb { -webkit-appearance:none; width:12px;
          height:12px; border-radius:50%; background:#fff; border:0; }
.lw-vsl::-moz-range-thumb { width:12px; height:12px; border:0;
          border-radius:50%; background:#fff; }
.lw-vsl::-moz-range-track { background:transparent; }
.lw-sel { font-size:12px; }

/* --- admin left-nav shell (LibreTime-style) --- */
.wrap.wide { max-width:1320px; }
.adm { display:flex; gap:22px; align-items:flex-start; }
.adm-nav { flex:0 0 188px; position:sticky; top:16px;
           display:flex; flex-direction:column; gap:2px; }
.adm-nav a { display:block; padding:9px 12px; border-radius:6px;
             color:var(--fg); font-size:14px; }
.adm-nav a:hover { background:#191b22; text-decoration:none; }
.adm-nav a.active { background:var(--card); color:#fff;
                    border-left:3px solid var(--acc); }
.adm-nav .adm-upload { background:var(--acc); color:#fff;
            text-align:center; font-weight:700; margin-bottom:10px;
            border-left:0; }
.adm-nav .adm-upload:hover { filter:brightness(1.08); background:var(--acc); }
.adm-nav .adm-upload.active { border-left:0; }
.adm-nav .adm-top { font-weight:600; }
.adm-nav .adm-sub { display:flex; flex-direction:column;
            margin:2px 0 6px 10px; border-left:1px solid #23252e; }
.adm-nav .adm-sub a { font-size:13px; padding:6px 12px;
            color:var(--mut); }
.adm-nav .adm-sub a.active { color:#fff; background:transparent;
            border-left:3px solid var(--acc); }
.adm-main { flex:1; min-width:0; }
.adm-soon { color:var(--mut); }

/* --- Dashboard split screen --- */
.dash { display:flex; gap:6px; align-items:flex-start; }
.dash-left { flex:1 1 auto; min-width:0; }
/* Draggable divider between the list and the editor column. Stretches the
   full height of the row so it's grabbable anywhere; a thin line shows in
   the middle, brightening on hover/drag. */
.dash-split { flex:0 0 10px; align-self:stretch; min-height:240px;
   cursor:col-resize; position:relative; touch-action:none;
   -webkit-user-select:none; user-select:none; }
.dash-split::before { content:""; position:absolute; top:0; bottom:0;
   left:50%; width:2px; transform:translateX(-50%); background:#23252e;
   border-radius:2px; transition:background .12s, width .12s; }
.dash-split:hover::before, .dash-split.dragging::before {
   background:var(--acc); width:4px; }
.dash-right { flex:0 0 320px; position:sticky; top:16px;
              display:flex; flex-direction:column; gap:14px; }
.dash-right .card { padding:14px; }
.dr-h { font-size:12px; text-transform:uppercase; letter-spacing:1px;
        color:var(--mut); margin-bottom:8px; }
.dr-show { font-size:17px; font-weight:700; }
.dr-np { margin-top:8px; color:var(--fg); font-size:14px;
         border-top:1px solid #23252e; padding-top:8px; }
/* No inner scroll per show — every scheduled show's tracks list out in full
   so the whole Scheduled-Shows column is ONE long list scrolled by
   .dash-right (position:relative kept for the absolute .np-hl bar). */
.dr-list { list-style:none; margin:0; padding:0; position:relative; }
.dr-list li { display:flex; gap:8px; align-items:baseline;
              padding:5px 0; border-bottom:1px solid #1d1f27;
              font-size:13px; position:relative; z-index:1; }
.dr-list li.done { opacity:.45; }
/* The "now playing" highlight is ONE element that slides between rows
   (FLIP via top/height transition) instead of a per-row background
   that blinks off/on when the track changes. */
.np-hl { position:absolute; left:0; right:0; top:0; height:0;
         background:rgba(226,59,84,.14); border-left:3px solid var(--acc);
         border-radius:4px; z-index:0; opacity:0; pointer-events:none;
         transition:top .42s cubic-bezier(.4,0,.2,1),
                    height .42s cubic-bezier(.4,0,.2,1),
                    opacity .3s ease; }
.np-hl.no-anim { transition:none; }
.dr-list li.playing { font-weight:600; }
.dr-list li.playing .dr-t { color:var(--acc); }
.dr-list .np-dot { color:var(--acc); font-size:10px; line-height:1;
                   align-self:center; visibility:hidden; }
.dr-list li.playing .np-dot { visibility:visible; }
.dr-list .dr-t { flex:1; min-width:0; overflow:hidden;
                 text-overflow:ellipsis; white-space:nowrap; }
.dr-list .dr-when { flex:0 0 auto; color:var(--mut); font-size:11px;
                 font-variant-numeric:tabular-nums; }
.dr-list .dr-len { color:var(--mut); font-variant-numeric:tabular-nums; }
/* Overbooked: track runs past the show's slot end. edge = the boundary
   track (starts inside, ends after); over = entirely past the end. */
.dr-list li.edge { background:rgba(232,150,40,.20); }
.dr-list li.over { background:rgba(226,59,84,.28); }
.dr-list li.edge .dr-when, .dr-list li.over .dr-when { color:#ffd9a0; }
/* Stranded: un-aired row positioned below the highest aired row in the
   on-air block — the scheduler's position floor won't pick it, so it
   sits in the queue without ever playing. Greyed + dashed left bar so
   the user knows it needs deleting or reordering. */
.dr-list li.stranded { background:rgba(120,120,140,.18);
                       border-left:3px dashed rgba(180,180,200,.6);
                       opacity:.75; }
.dr-list li.stranded .dr-when { color:#aaa; font-style:italic; }
.dr-list li.stranded::after { content:" · won't play (above on-air)";
                              color:#aaa; font-size:11px; font-style:italic;
                              margin-left:auto; padding:0 6px; }
.db-over { color:#ffb24d; font-size:12px; font-weight:600;
           margin:2px 0 4px; display:flex; align-items:center; gap:8px; }
.dr-list li.schrow { cursor:grab; }
.dr-list li.schrow:active { cursor:grabbing; }
.dr-list .schk { flex:0 0 auto; margin:0 2px 0 0; cursor:pointer; }
.dr-list li.sch-ph { height:0; padding:0; border:0;
  border-top:2px solid var(--acc); margin:-1px 0;
  box-shadow:0 0 4px var(--acc); list-style:none; }
/* Collapse a removed row in place (max-height is driven inline by JS
   from its real height → 0 so it actually animates). */
.dr-list li.sch-removing { padding-top:0; padding-bottom:0;
  opacity:0; border-bottom-color:transparent; overflow:hidden;
  transition:max-height .3s ease, opacity .25s ease,
             padding .3s ease; }
.sch-bar { display:flex; align-items:center; gap:8px;
  margin-top:8px; padding-top:8px; border-top:1px solid #23252e; }
.sch-bar .sch-n { font-size:12px; }
.dr-next { margin-top:10px; border-top:1px solid #23252e;
           padding-top:8px; font-size:13px; }
.pill { font-size:10px; padding:2px 7px; border-radius:999px;
        vertical-align:middle; }
.pill.live { background:var(--acc); color:#fff; }

/* sub-tab strip (Settings) + two-column editors */
.subtabs { display:flex; gap:4px; margin:12px 0 18px;
           border-bottom:1px solid #23252e; }
.subtabs a { padding:8px 14px; color:var(--mut); font-size:14px; }
.subtabs a.active { color:#fff; border-bottom:2px solid var(--acc); }
.two-col { display:grid; grid-template-columns:1fr 1fr; gap:18px;
           align-items:start; }
.rowsel td { background:#1f2230; }
.pl-head { margin:6px 0 10px; gap:14px; }
.nowrap { white-space:nowrap; }
button.mini { padding:4px 9px; font-size:12px; }
button.ghost { background:#23252e; color:var(--fg); }
button.danger { background:#3a1620; color:#ffb4c0; }
.add-to { display:inline-flex; gap:4px; }
.add-to select { padding:4px 6px; font-size:12px; }

/* Upload */
.up-box { display:flex; flex-direction:column; gap:14px;
          align-items:flex-start; }
.up-drop { display:block; width:100%; box-sizing:border-box;
           border:2px dashed #2b2e3a; border-radius:10px;
           padding:34px 18px; text-align:center; cursor:pointer; }
.up-drop.over { border-color:var(--acc); background:#1b1420; }
.up-cta { font-size:16px; }
#uplist { margin-top:10px; }
.up-prog { width:100%; box-sizing:border-box; }
.up-prog-row { display:flex; justify-content:space-between; gap:10px;
               font-size:13px; margin-bottom:5px; }
.up-bar { width:100%; height:8px; border-radius:6px; background:#1b1420;
          overflow:hidden; }
.up-bar-fill { display:block; height:100%; width:0; background:var(--acc);
               transition:width .2s ease; }
#upprog-msg { margin-top:7px; color:var(--acc); font-size:13px; }
tr.up-new td { animation:upflash 1.4s ease; }
@keyframes upflash { from { background:#241826; } to { background:transparent; } }

/* Widgets */
.wdg { display:grid; grid-template-columns:1fr 1fr; gap:18px; }
.wdg-frame { width:100%; height:240px; border:1px solid #23252e;
             border-radius:8px; background:#0b0c10; }
.wdg-code { width:100%; box-sizing:border-box; margin-top:6px;
            font-family:monospace; font-size:12px; background:#0f1117;
            color:var(--fg); border:1px solid #2b2e3a; border-radius:6px;
            padding:8px; }

/* Calendar */
.cal-bar { gap:16px; margin-bottom:14px; flex-wrap:wrap; }
#cal { padding:14px; --fc-border-color:#23252e;
       --fc-page-bg-color:transparent;
       --fc-neutral-bg-color:#15171e;
       --fc-today-bg-color:#1c1f29; }
#cal a { color:var(--fg); }
#cal .fc .fc-button-primary { background:#23252e; border:0; }
#cal .fc .fc-button-primary:not(:disabled).fc-button-active,
#cal .fc .fc-button-primary:hover { background:var(--acc); }
dialog.card { color:var(--fg); border:1px solid #23252e;
              border-radius:10px; }
dialog.card label { display:block; margin:10px 0; }
dialog::backdrop { background:rgba(0,0,0,.6); }

/* --- Calendar: context menu, show/instance dialogs, event detail --- */
.ctx { position:fixed; z-index:1000; min-width:212px; background:#15171e;
       border:1px solid #2b2e3a; border-radius:8px; padding:5px;
       box-shadow:0 10px 30px rgba(0,0,0,.5); }
.ctx button { display:block; width:100%; text-align:left; background:none;
       color:var(--fg); padding:7px 10px; border-radius:5px; font-size:14px; }
.ctx button:hover { background:#23252e; }
.ctx button.danger { background:none; color:#ffb4c0; }
.ctx button.danger:hover { background:#3a1620; }
.ctx-sep { height:1px; background:#23252e; margin:4px 6px; }
.cal-dlg { width:min(560px,94vw); max-height:90vh; overflow:auto; }
.cal-dlg details { border:1px solid #23252e; border-radius:8px;
       padding:4px 12px; margin:8px 0; background:#0f1117; }
.cal-dlg summary { cursor:pointer; font-weight:600; padding:8px 0; }
.cal-dlg .form-inline { flex-wrap:wrap; }
.cal-dlg-foot { margin-top:14px; gap:12px; }
.dow-row { display:flex; gap:6px; flex-wrap:wrap; margin:8px 0; }
.dow { display:inline-flex !important; align-items:center; gap:4px;
       margin:0 !important; background:#15171e; border:1px solid #2b2e3a;
       border-radius:6px; padding:5px 8px; font-size:13px; }
.ck { display:flex !important; align-items:center; gap:7px;
      margin:8px 0 !important; }
.ck input,.dow input { width:auto; padding:0; }
.who-grid { display:grid; gap:4px 12px;
       grid-template-columns:repeat(auto-fill,minmax(120px,1fr)); }
input[type=color] { width:46px; height:34px; padding:2px; }
.fc-er-t { font-weight:700; font-size:11px; opacity:.9; }
.fc-er-n { font-weight:600; font-size:12px; line-height:1.2; }
.fc-er-m { font-size:10.5px; opacity:.85; margin-top:1px; }
/* compact one-line layout for short (≤45min) blocks so the title, time AND
   fill bar still fit instead of clipping to just the time */
.fc-er-c { font-size:11px; line-height:1.15; white-space:nowrap;
           overflow:hidden; text-overflow:ellipsis; }
.fc-er-c b { font-weight:700; }
/* Cancelled occurrence: dimmed + struck through so it reads as "won't air"
   while still visible on the calendar (it's a tombstone, not a deletion). */
.fc-er-cancelled { opacity:.5; }
.fc-er-cancelled .fc-er-n, .fc-er-cancelled .fc-er-c { text-decoration:line-through; }
.fc-event { cursor:pointer; }
/* Outlook-style accent: a red bar + soft glow down the LEFT edge of every
   scheduled block. A ::before overlay so it's independent of each show's own
   bg/border colors; the glow bleeds rightward into the block. NOTE: do NOT
   add `position:relative` to .fc-event — FullCalendar timegrid events are
   already `position:absolute` (that's what makes them fill their time slot),
   and overriding it collapses each block to content height → gaps between
   shows. The absolute event already anchors this ::before. */
#cal .fc-event::before { content:""; position:absolute; left:0; top:0;
   bottom:0; width:3px; border-radius:3px 0 0 3px; background:var(--acc);
   box-shadow:1px 0 8px 1px rgba(226,59,84,.6); pointer-events:none; }
/* give short blocks room + tighten event chrome so content isn't clipped */
#cal .fc-timegrid-slot { height:2em; }
#cal .fc-timegrid-event .fc-event-main { padding:1px 4px; }
#cal .fc-timegrid-event-harness { font-size:12px; }
.v-dl { display:grid; grid-template-columns:auto 1fr; gap:6px 14px;
        margin:6px 0; }
.v-dl dt { color:var(--mut); font-size:13px; }
.v-dl dd { margin:0; font-size:14px; }
.v-logo { max-width:120px; max-height:90px; border-radius:8px;
          float:right; margin:0 0 8px 12px; }
/* calendar event fill bar (scheduled / show length) */
.fc-er-bar { margin-top:3px; height:4px; border-radius:3px;
             background:rgba(0,0,0,.35); overflow:hidden; }
.fc-er-bar span { display:block; height:100%; background:rgba(255,255,255,.85); }
.fc-er-bar.over span { background:#ffd27f; }
/* Schedule Tracks modal */
.sched-hd { font-size:12px; color:var(--mut); margin:8px 0 4px; }
.sched-rows { list-style:none; margin:4px 0; padding:4px; max-height:32vh;
              overflow:auto; min-height:66px; border:1px dashed #2b2e3a;
              border-radius:8px; }
.sched-rows li { display:flex; align-items:center; gap:10px; padding:6px 8px;
              border-bottom:1px solid #23252e; font-size:13px; cursor:grab; }
.sched-rows li.dragging { opacity:.4; }
.sched-rows li.muted { cursor:default; border:0; justify-content:center;
              padding:20px 8px; }

/* --- Public weekly-schedule widget (/schedule + embed) --- */
.sched-embed { margin:0; background:var(--bg); }
.sw { max-width:760px; margin:0 auto; padding:14px; }
.sched-embed .sw { max-width:none; }
.sw-head { display:flex; align-items:baseline; justify-content:space-between;
           gap:10px; margin-bottom:12px; }
.sw-title { font-size:20px; font-weight:700; }
.sw-tz { font-size:12px; }
.sw-days { display:flex; gap:6px; overflow-x:auto; padding-bottom:4px; }
.sw-day { flex:1 0 auto; min-width:58px; display:flex; flex-direction:column;
          align-items:center; gap:2px; background:var(--card);
          border:1px solid #23252e; border-radius:10px; padding:8px 6px;
          color:var(--fg); cursor:pointer; position:relative; }
.sw-day:hover { border-color:#3a3d49; }
.sw-day.active { background:var(--acc); border-color:var(--acc); color:#fff; }
.sw-dow { font-size:11px; text-transform:uppercase; letter-spacing:.04em;
          opacity:.85; }
.sw-dnum { font-size:18px; font-weight:700; line-height:1; }
.sw-dn { position:absolute; top:4px; right:5px; font-size:10px; font-weight:700;
         background:rgba(0,0,0,.4); border-radius:8px; padding:0 5px; }
.sw-day.active .sw-dn { background:rgba(255,255,255,.28); }
.sw-list { margin-top:14px; display:flex; flex-direction:column; gap:8px; }
.sw-item { display:flex; gap:14px; background:var(--card); border:1px solid #23252e;
           border-left:4px solid var(--c,#3b5266); border-radius:10px;
           padding:10px 14px; }
.sw-item.live { box-shadow:0 0 0 1px var(--acc) inset; }
.sw-time { flex:0 0 84px; font-weight:700; font-size:14px; line-height:1.35; }
.sw-time span { display:block; font-weight:400; color:var(--mut); font-size:12px; }
.sw-name { font-weight:600; font-size:15px; }
.sw-on { color:var(--acc); font-style:normal; font-size:10px; font-weight:700;
         border:1px solid var(--acc); border-radius:6px; padding:1px 5px;
         margin-left:7px; vertical-align:middle; }
.sw-dj { color:var(--mut); font-size:13px; margin-top:1px; }
.sw-desc { font-size:12px; opacity:.85; margin-top:3px; }
.sw-empty { padding:26px; text-align:center; }

/* --- Settings (tabbed: General / Profile / Users / Track Types / Streams / Status) --- */
.set-wrap { display:flex; gap:20px; align-items:flex-start; }
.set-nav { flex:0 0 170px; position:sticky; top:16px; }
.set-nav h2 { margin:0 0 10px; font-size:16px; color:var(--mut); }
.set-link { display:block; padding:9px 12px; border-radius:8px; color:var(--fg);
            margin-bottom:2px; }
.set-link:hover { background:var(--card); }
.set-link.active { background:var(--acc); color:#fff; }
.set-body { flex:1; min-width:0; }
.set-body h1 { margin-top:0; }
.set-hr { border:0; border-top:1px solid #23252e; margin:20px 0; }
.set-hd { display:flex; align-items:center; gap:14px; }
.set-hd h1, .set-hd h3 { margin:0; }
.set-btn { margin-left:auto; padding:8px 14px; border-radius:6px; color:#fff; }
.set-form { max-width:560px; }
.set-form label { display:block; margin:10px 0; }
.set-form input, .set-form textarea, .set-form select { width:100%;
            box-sizing:border-box; }
.set-form label.ck, .set-form .form-inline { width:auto; }
.set-form label.ck input { width:auto; }
.set-form-2 { display:grid; grid-template-columns:1fr 1fr; gap:0 16px; }
.set-form-2 .set-span2 { grid-column:1/3; }
.set-logo-row { display:flex; gap:18px; align-items:flex-start; flex-wrap:wrap; }
.set-logo { width:160px; height:160px; object-fit:cover; border-radius:12px;
            border:1px solid #23252e; background:#0f1117; }
.set-logo.sm { width:80px; height:80px; }
/* list + detail */
.set-split { display:flex; gap:18px; align-items:flex-start; }
.set-list { flex:0 0 440px; max-width:48%; }
.set-search { width:100%; box-sizing:border-box; margin-bottom:8px; }
.set-list ul { list-style:none; margin:0; padding:0; max-height:62vh;
               overflow:auto; border:1px solid #23252e; border-radius:8px; }
.set-row { display:flex; align-items:center; gap:8px; padding:9px 12px;
           border-bottom:1px solid #23252e; color:var(--fg); }
.set-row:hover { background:var(--card); }
.set-row.active { background:var(--acc); color:#fff; }
.set-row-n { font-weight:600; }
.set-row-s { color:var(--mut); flex:1; overflow:hidden; text-overflow:ellipsis;
             white-space:nowrap; }
.set-row.active .set-row-s { color:#ffd; }
.set-row-b { margin-left:auto; flex:none; font-size:10px; font-weight:700;
             text-transform:uppercase; letter-spacing:.04em; white-space:nowrap;
             padding:2px 9px; border-radius:10px; background:#23252e;
             color:var(--mut); }
.set-row-b.role-admin { background:rgba(226,59,84,.22); color:#ff9aa8; }
.set-row.active .set-row-b { background:rgba(255,255,255,.22); color:#fff; }
.set-detail { flex:1; min-width:0; }
/* streams */
.stream-card { background:var(--card); border:1px solid #23252e;
               border-radius:10px; padding:10px 14px; margin:10px 0;
               max-width:620px; }
.stream-card .form-inline { flex-wrap:wrap; }
.stream-card label { display:block; margin:8px 0; }
/* status */
.set-status td, .set-status th { padding:8px 10px; }
.st-ok { color:#7bd88f; font-weight:600; }
.st-bad { color:#ff8a98; font-weight:600; }

/* read-only dashboard (guests / DJs): Tracks list only — hide write
   affordances + the right pane. Server already blocks mutations (PM+). */
.dash-ro .bulkbar, .dash-ro .col-cb, .dash-ro .col-act,
.dash-ro .trk-edit, .dash-ro form[action],
.dash-ro .sch-bar, .dash-ro .sch-trim, .dash-ro #dashRefresh,
.dash-ro .dash-right, .dash-ro .dash-split { display:none !important; }
.dash-ro .dash-left { flex:1 1 100%; max-width:none; }
.dash-ro .trk-row, .dash-ro .pick, .dash-ro .dr-list li,
.dash-ro [draggable] { cursor:default; }
/* guests can't preview; DJs (dash-ro but not nopreview) keep the play btn */
.dash-nopreview .trk-play { display:none !important; }
.sr-t { color:var(--mut); width:74px; flex:none; }
.sr-n { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.sr-l { color:var(--mut); flex:none; }
.sr-x { background:none; color:#ffb4c0; padding:0 8px; font-size:18px;
        line-height:1; }
.sr-x:hover { color:#fff; }
.sched-results { max-height:30vh; overflow:auto; margin:6px 0; }
.pick-tabs { display:flex; gap:4px; margin:8px 0 6px; }
.pick-tab { background:#15171e; border:1px solid #2b2e3a; color:var(--mut);
            border-radius:6px; padding:6px 12px; font-size:13px; }
.pick-tab.active { background:var(--acc); color:#fff; border-color:var(--acc); }
/* Scoped to the calendar Schedule-Tracks modal — the dashboard's
   playlist/smart-block table rows ALSO use class="pick" (a JS drag hook),
   so an unscoped .pick{display:flex} broke their table layout. */
.sched-results .pick { display:flex; align-items:center; gap:10px;
        cursor:grab; background:#15171e; border:1px solid #2b2e3a;
        border-radius:6px; margin:4px 0; padding:7px 10px; font-size:13px; }
.sched-results .pick:hover { background:#23252e; }
.sched-results .pick:active { cursor:grabbing; }
.pk-n { flex:1; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
.pk-n i { color:var(--mut); font-style:normal; font-size:11px; }
.pk-l { color:var(--mut); flex:none; }
.sched-rows li.drop-before { box-shadow:inset 0 2px 0 0 var(--acc); }

/* Analytics sparkline */
.spark { width:100%; height:120px; background:#15171e;
         border:1px solid #23252e; border-radius:8px; }
.tbl { width:100%; border-collapse:collapse; }
.tbl th,.tbl td { text-align:left; padding:7px 10px;
                  border-bottom:1px solid #23252e; font-size:14px; }
.tbl th { color:var(--mut); font-weight:600; }
.flash { padding:10px 20px; }
.flash.error { background:#3a1620; color:#ffb4c0; }
.flash.ok { background:#13301f; color:#9be8b8; }
.grid { display:flex; gap:14px; flex-wrap:wrap; }
.stat { text-align:center; min-width:120px; }
.stat b { display:block; font-size:28px; }
.stat span { color:var(--mut); font-size:13px; }
/* Analytics dashboard. KPIs are big-number cards; rank tables right-align
   their numeric columns; period selector chips up top. */
.ana-top { display:flex; align-items:baseline; gap:18px; flex-wrap:wrap;
   margin-bottom:14px; }
.ana-period { margin-left:auto; }
.ana-period a { display:inline-block; padding:3px 10px; margin:0 2px;
   border-radius:6px; border:1px solid #23252e; color:var(--mut);
   font-size:13px; }
.ana-period a:hover { color:var(--fg); text-decoration:none;
   border-color:#3a3d4a; }
.ana-period a.on { color:#fff; background:var(--acc);
   border-color:var(--acc); }
.ana-kpi .stat { flex:1 1 160px; min-width:160px; padding:14px; }
.ana-kpi .stat b { font-size:32px; line-height:1.05; }
.ana-sub { display:block; font-size:11px; margin-top:2px; }
.ana-rank td.ana-r, .ana-rank th.ana-r { text-align:right;
   font-variant-numeric:tabular-nums; white-space:nowrap; }
.ana-stale { margin:0 0 14px; padding:10px 14px; border-radius:8px;
   background:rgba(226,59,84,.08); border:1px solid rgba(226,59,84,.35);
   color:var(--fg); font-size:13px; line-height:1.5; }
.ana-stale b { color:var(--acc); }

/* Listener Stats sub-tab. */
.ana-range { display:flex; flex-wrap:wrap; gap:10px 14px;
   align-items:flex-end; margin:6px 0 16px;
   padding:10px 14px; background:#0f1117; border:1px solid #23252e;
   border-radius:8px; }
.ana-range label { display:flex; gap:6px; align-items:center;
   font-size:12px; color:var(--mut); margin:0; }
.ana-range input { width:auto; padding:4px 6px; }
.ana-chart-wrap { background:#0f1117; border:1px solid #23252e;
   border-radius:8px; padding:10px 14px 14px; margin-bottom:18px; }
.ana-chart { display:block; width:100%; height:auto; min-height:280px; }
.ana-chart-bg { fill:#0a0b10; stroke:#1c1e26; stroke-width:1; }
.ana-chart-grid { stroke:#23252e; stroke-width:1; }
.ana-chart-lab { fill:#9098a8; font-size:11px;
   font-variant-numeric:tabular-nums; }
.ana-chart-legend { display:flex; flex-wrap:wrap; gap:10px 18px;
   margin-top:8px; font-size:12px; align-items:center; }
.ana-chart-legend span { display:inline-flex; align-items:center;
   gap:6px; }
.ana-chart-legend i { display:inline-block; width:14px; height:3px;
   border-radius:2px; }
.ana-chart-meta { margin-left:auto; }

/* Stream Data Collection Status cards. */
.ana-stream b { font-size:14px; }
.ana-stream-state { display:block; font-size:12px; margin-top:4px;
   font-weight:600; }
.ana-stream-state.ok { color:#7ed957; }
.ana-stream-state.idle { color:#9098a8; }
.form label { display:block; margin:10px 0; }
.form input,.form-inline input,.form-inline select,select,input {
  background:#0f1117; color:var(--fg); border:1px solid #2b2e3a;
  border-radius:6px; padding:8px 10px; }
button { background:var(--acc); color:#fff; border:0; border-radius:6px;
         padding:9px 16px; cursor:pointer; }
.form-inline { display:inline-flex; gap:8px; align-items:center; }
/* Bottom-of-list footer (count + page nav). In the app-shell it sits below
   the scrolling .trk-wrap as a fixed column footer. */
.pager { margin:8px 0 0; padding:8px 2px 2px; display:flex; gap:14px;
   align-items:center; flex-wrap:wrap; border-top:1px solid #23252e;
   font-size:13px; }
.pg-info { color:var(--mut); }
.pg-info b { color:var(--fg); font-weight:600; }
.pg-nav { margin-left:auto; display:flex; gap:12px; align-items:center; }
.pg-cur { color:var(--mut); white-space:nowrap; }
.pg-b { color:var(--acc); white-space:nowrap; }
.pg-b:hover { text-decoration:underline; }
.err { color:#ff9aa8; font-size:12px; }

/* --- Tracks tab: configurable/sortable grid + scheduled-shows pane --- */
.dash-right { flex:0 0 380px; position:sticky; top:16px;
              max-height:calc(100vh - 120px); overflow:auto; }
.trk-bar { display:flex; align-items:center; gap:14px; flex-wrap:wrap;
           margin-bottom:10px; }
.trk-bar h1 { margin:0; }
.colmenu { position:relative; margin-left:auto; }
.colmenu-pop { position:absolute; right:0; top:30px; z-index:30;
   width:210px; max-height:60vh; overflow:auto; padding:10px;
   display:grid; grid-template-columns:1fr; gap:2px; }
.colmenu-pop label { display:flex; gap:7px; align-items:center;
   font-size:13px; padding:3px 4px; margin:0; }
/* The list scrolls WITHIN the left column (one scroll) — the search/columns
   bar + bulk bar stay fixed above it. Caps near the viewport so the page
   itself doesn't also scroll. overflow:auto = vertical for long lists +
   horizontal for wide tables. */
.trk-wrap { max-height:calc(100vh - 210px); overflow:auto;
   border:1px solid #23252e; border-radius:8px; }
table.trk { min-width:100%; }
table.trk th, table.trk td { white-space:nowrap; max-width:280px;
   overflow:hidden; text-overflow:ellipsis; }
/* Playlists / Smart Blocks have few columns — let the descriptive Name
   (and Description) columns absorb the spare width (drop the 280px cap) so
   the rows FILL the table and line up under the headers like Tracks, instead
   of bunching left with empty space. The numeric/date columns stay tight. */
#plTbl td[data-col="name"], #plTbl th[data-col="name"],
#sbTbl td[data-col="name"], #sbTbl th[data-col="name"] {
   width:45%; max-width:none; }
#plTbl td[data-col="description"], #plTbl th[data-col="description"],
#sbTbl td[data-col="description"], #sbTbl th[data-col="description"] {
   width:35%; max-width:none; white-space:normal; }
.th-sort a { color:var(--mut); display:inline-flex; gap:3px; }
.th-sort.sorted a { color:#fff; }
.th-sort .caret { font-size:10px; }
.col-act { width:54px; }
.trk-row { cursor:grab; }
.trk-row:hover { background:#1b1d25; }
.trk-row:active { cursor:grabbing; }

/* right-pane tabs + drop targets */
/* Wrap tabs onto multiple rows so EVERY open editor tab stays visible no
   matter how many are open (don't clip them behind a horizontal scroll). */
.dr-tabs { display:flex; flex-wrap:wrap; gap:2px; margin-bottom:10px;
   border-bottom:1px solid #23252e; position:sticky; top:0;
   background:var(--bg); z-index:5; }
.dr-tab { background:transparent; color:var(--mut); border:0;
   padding:8px 12px; font-size:13px; cursor:pointer; white-space:nowrap;
   border-top-left-radius:7px; border-top-right-radius:7px; }
.dr-tab:hover { color:var(--fg); }
.dr-tab.active { color:#fff; border-bottom:2px solid var(--acc); }
.dr-tab:disabled { opacity:.45; cursor:default; }
/* browser-style editor tabs: name + close button, boxed look */
.dr-edtab { display:inline-flex; align-items:center; gap:8px; max-width:200px;
   background:var(--card); border:1px solid #23252e; border-bottom:0; }
.dr-edtab.active { background:#1b1d25; }
.dr-edtab .dr-lbl { overflow:hidden; text-overflow:ellipsis;
   white-space:nowrap; }
.dr-edtab .dr-x { flex:none; width:16px; height:16px; line-height:14px;
   text-align:center; border-radius:50%; color:var(--mut); font-size:14px; }
.dr-edtab .dr-x:hover { background:#3a1620; color:#ffb4c0; }
.dr-pane { display:flex; flex-direction:column; gap:12px; }
.drop-block { padding:12px; transition:background .12s, outline .12s; }
.drop-block.on-air { box-shadow:0 0 0 1px var(--acc) inset; }
.drop-block.drop-over { outline:2px dashed var(--acc);
   background:#1b1420; }
.db-when { font-size:12px; margin:2px 0 6px; }
.db-empty { margin:6px 0 0; }

/* track edit panel */
.trk-edit-card { padding:14px; }
.te-head { display:flex; gap:12px; align-items:flex-start;
   border-bottom:1px solid #23252e; padding-bottom:10px;
   margin-bottom:10px; }
.te-art { width:72px; height:72px; border-radius:6px; background:#23252e;
   object-fit:cover; flex:0 0 auto; }
.te-artctl { margin-top:6px; gap:6px; flex-wrap:wrap; }
.te-artctl .te-artfile { max-width:150px; font-size:11px; }
.te-row { display:flex; align-items:center; gap:10px; margin:7px 0; }
.te-row span { flex:0 0 96px; color:var(--mut); font-size:12px;
   text-align:right; }
.te-row input, .te-row select { flex:1; min-width:0; }
.te-actions { margin-top:14px; }
.ok-msg { color:#9be8b8; font-size:12px; }

/* --- Admin full-bleed: nav hugs the left edge, max width for the two
   big columns (Tracks grid + Scheduled Shows). Scoped so public pages
   keep the centered .wrap. --- */
.wrap.adminfull { max-width:none; margin:0; padding:0; }
.wrap.adminfull .adm { gap:0; }
.wrap.adminfull .adm-nav { flex:0 0 168px; padding:14px 8px; top:0;
   background:#0c0d11; border-right:1px solid #23252e;
   border-radius:0; align-self:stretch; }
.wrap.adminfull .adm-main { padding:20px 20px 28px; min-width:0; }

/* --- Admin app-shell (LibreTime-style): lock the viewport so the page body
   NEVER scrolls — the top nav, now-playing player, and left admin nav stay
   STATIC and only the content column(s) scroll (one scroll each). Everything
   here is gated on body:has(main.adminfull): it applies ONLY on admin pages
   and ONLY in browsers with :has() (modern); older browsers fall through to
   the normal page-scroll layout above, so nothing breaks. The home immersive
   visualizer (public) is never matched. --- */
body:has(main.adminfull) { height:100vh; overflow:hidden;
   display:flex; flex-direction:column; }
body:has(main.adminfull) > main.adminfull { flex:1 1 auto; min-height:0; }
body:has(main.adminfull) .adm { height:100%; min-height:0;
   align-items:stretch; }
body:has(main.adminfull) .adm-nav { position:static; overflow-y:auto; }
/* Non-dashboard admin pages (Calendar, Settings, …) scroll inside .adm-main. */
body:has(main.adminfull) .adm-main { height:100%; min-height:0;
   overflow:auto; }
/* Dashboard: its two columns scroll themselves, so .adm-main must NOT add a
   third scroll — it just frames the full-height .dash. */
body:has(main.adminfull) .adm-main:has(> .dash) { overflow:hidden;
   display:flex; flex-direction:column; }
body:has(main.adminfull) .dash { flex:1 1 auto; min-height:0;
   align-items:stretch; }
body:has(main.adminfull) .dash-left { min-height:0;
   display:flex; flex-direction:column; }
body:has(main.adminfull) .dash-left .trk-wrap { flex:1 1 auto;
   min-height:0; max-height:none; }            /* the ONE left-column scroll */
body:has(main.adminfull) .dash-right { position:static; max-height:none;
   min-height:0; }                              /* the ONE right-column scroll */

/* --- multi-select bulk bar + selectable lists + search panel --- */
.bulkbar { position:sticky; top:0; z-index:6; display:flex; gap:10px;
   align-items:center; background:#1b1420; border:1px solid var(--acc);
   border-radius:8px; padding:8px 12px; margin-bottom:10px; }
.bulkbar #bulkn { color:var(--mut); margin-right:auto; font-size:13px; }
.col-cb { width:34px; text-align:center; }
/* Tracks grid: the artwork IS the play button. Hover shows a ▶ over a
   dark scrim; while playing it turns solid red, blocking the artwork,
   with a ⏸. The inline seek bar pops out to its right. */
.col-play { width:1%; white-space:nowrap; }
.trk-play { width:36px; height:36px; padding:0; border:0; border-radius:4px;
   cursor:pointer; position:relative; vertical-align:middle;
   background:#23252e var(--art) center/cover no-repeat; }
.trk-play::before { content:""; position:absolute; inset:0; border-radius:4px;
   background:rgba(0,0,0,.4); opacity:0; transition:opacity .12s; }
.trk-play .trk-ic { position:absolute; inset:0; display:flex;
   align-items:center; justify-content:center; font-size:12px; color:#fff;
   opacity:0; transition:opacity .12s;
   text-shadow:0 1px 3px rgba(0,0,0,.9); }
.trk-play:hover::before, .trk-play:hover .trk-ic { opacity:1; }
.trk-play.playing { background-image:none; background-color:var(--acc); }
.trk-play.playing::before { opacity:0; }
.trk-play.playing .trk-ic { opacity:1; }
.trk-seek { display:inline-block; vertical-align:middle; width:96px;
   height:6px; background:#23252e; border-radius:3px; margin-left:6px;
   position:relative; cursor:pointer; }
.trk-seek-fill { display:block; height:100%; width:0; background:var(--acc);
   border-radius:3px; }
.sel-row.pick { cursor:pointer; }
.sel-row.rowsel > td { background:#1f2230; }
.sel-row:hover > td { background:#1b1d25; }

.srch-pop { width:340px; }
.srch-pop label { display:flex; align-items:center; gap:8px; margin:6px 0;
   font-size:13px; }
.srch-pop label > span:first-child { flex:0 0 70px; color:var(--mut);
   text-align:right; }
.srch-pop label input, .srch-pop label select { flex:1; min-width:0; }
.srch-pop .rng { flex:1; display:flex; gap:6px; align-items:center;
   color:var(--mut); font-size:12px; }
.srch-pop .rng input { flex:1; min-width:0; }

/* drop zone inside the Edit Playlist panel */
/* Playlist contents = a compact drag-reorderable list that is itself the
   drop target (drop a track/smart-block between rows to insert there). The
   insertion line + drop-over come from the shared .dr-list / .sch-ph rules. */
.pl-list { margin:8px 0 0; min-height:48px; border:1px dashed #2b2e3a;
   border-radius:8px; padding:2px 8px; }
.pl-list.drop-over { border-color:var(--acc); border-style:solid;
   background:#1b1420; }
/* .plrow is a .dr-list li, so it inherits the Scheduled-Shows row height. */
.pl-list .plrow { cursor:grab; }
.pl-list .plrow:active { cursor:grabbing; }
.pl-list .plrow:hover { background:#1b1d25; }
.pl-list .plk { flex:0 0 auto; margin:0 2px 0 0; cursor:pointer; }
.pl-pos { flex:0 0 22px; color:var(--mut); font-size:12px;
   text-align:right; font-variant-numeric:tabular-nums; }
.pl-it { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis;
   white-space:nowrap; }
.pl-len { flex:0 0 auto; font-variant-numeric:tabular-nums; }
.pl-bar { display:flex; align-items:center; gap:8px; margin-top:8px;
   padding-top:8px; border-top:1px solid #23252e; }
.pl-bar .pl-n { font-size:12px; }
.pl-empty { padding:12px 4px; text-align:center; }
.pl-edit .pill { background:#23252e; }

/* dashboard mini toolbar (explicit Refresh — the only true reload) */
.dash-toolbar { display:flex; justify-content:flex-end; margin-bottom:6px; }
#dashRefresh { font-size:12px; }

/* --- LibreTime-style smart-block editor --- */
.sb-edit { padding:14px; }
.sb-top { display:flex; align-items:center; justify-content:space-between;
  border-bottom:1px solid #23252e; padding-bottom:8px; margin-bottom:10px; }
.sb-name { display:flex; flex-direction:column; gap:4px; font-size:12px;
  color:var(--mut); margin:8px 0; }
.sb-name input { font-size:14px; }
.sb-label { font-size:12px; text-transform:uppercase; letter-spacing:1px;
  color:var(--mut); margin:12px 0 6px; }
#sbRows { display:flex; flex-direction:column; gap:6px; }
.sb-row { display:flex; gap:6px; align-items:center; flex-wrap:wrap; }
.sb-orbadge:empty { display:none; }
.sb-orbadge { flex:0 0 auto; font-size:10px; text-transform:uppercase;
  letter-spacing:1px; color:var(--acc); font-weight:700;
  padding:1px 6px; border:1px solid var(--acc); border-radius:10px; }
.sb-row.sb-cont { margin-left:18px; }
.sb-row.sb-cont .sb-field { opacity:.5; pointer-events:none; }
.sb-or { color:var(--acc); }
.sb-row .sb-field { flex:0 0 130px; }
.sb-row .sb-modwrap { flex:0 0 140px; }
.sb-row .sb-modwrap select { width:100%; }
.sb-row .sb-valwrap { flex:1 1 130px; display:flex; gap:6px;
  align-items:center; min-width:120px; }
.sb-row .sb-valwrap .sb-val, .sb-row .sb-valwrap .sb-extra { flex:1;
  min-width:0; }
.sb-to { color:var(--mut); font-size:12px; }
.sb-add { margin:8px 0 4px; }
.sb-limit { display:flex; gap:8px; align-items:center; margin:12px 0;
  font-size:13px; }
.sb-limit input { width:80px; }
.sb-adv { margin:10px 0; border:1px solid #23252e; border-radius:8px;
  padding:8px 12px; }
.sb-adv summary { cursor:pointer; color:var(--mut); font-size:12px;
  text-transform:uppercase; letter-spacing:1px; }
.sb-arow { display:flex; align-items:center; gap:10px; margin:9px 0;
  font-size:13px; }
.sb-arow > span:first-child { flex:0 0 180px; color:var(--mut); }
.sb-arow textarea { flex:1; }
.sb-actions { display:flex; gap:8px; align-items:center; margin:10px 0; }
.sb-prevhead { display:flex; justify-content:space-between; gap:10px;
  align-items:center; margin:6px 0; font-size:12px; }
.sb-dur { color:var(--fg); font-variant-numeric:tabular-nums; }
.sb-prevlist { max-height:34vh; overflow:auto; }
.sb-save { display:flex; gap:8px; margin-top:14px;
  border-top:1px solid #23252e; padding-top:12px; }

/* smart-block preview match-count line */
.sb-match { font-size:14px; margin:8px 0 4px; }
.sb-match b { color:var(--fg); }
.sb-ok { color:#9be8b8; font-weight:700; margin-left:4px; }
