/* theme.css retro-OS homage theme system webamp desktop.
 Palettes CSS custom properties set on <html>; rules consume them.
 NOTE: one-liner rules intentionally use "{ ... }" (kept on one line).
 Keep braces balanced; the chat window depends on #chat-chooser { position:fixed }.
*/
:root {
 --bg: #0a0a0a; --panel: #0a0a0a; --panel2: #141414; --fg: #b8f0d0;
 --accent: #00e0a0; --accent-fg: #0a0a0a; --titlebar: #141414; --titlebar-fg: #b8f0d0;
 --border: #3a3a3a; --bw: 1px; --bs: solid; --radius: 0px;
 --font: 11px/1 monospace; --shadow: 3px 3px 0 rgba(0, 0, 0, 0.55);
 --bevel-up: #2a2a2a; --bevel-down: #0a0a0a;
}
html, body { margin: 0; height: 100%; background: var(--bg); }
body { color: var(--fg); font: var(--font); }
#app { height: 100%; position: relative; }

/* desktop icon strip (left) */
#toggles { position: fixed; left: 8px; top: 8px; z-index: 2; display: flex; flex-direction: column; gap: 10px; }
#toggles button { color: var(--fg); border: var(--bw) var(--bs) var(--border); font: var(--font); border-radius: var(--radius); }
#toggles button.dicon {
 display: flex; flex-direction: column; align-items: center; gap: 3px;
 width: 66px; padding: 7px 4px 5px; cursor: pointer;
 background: transparent; border: 1px solid transparent;
 border-radius: var(--radius); box-shadow: none;
}
#toggles button.dicon .dicn { font-size: 22px; line-height: 1; color: #00e0a0; text-shadow: 2px 2px 0 rgba(0,0,0,0.6); }
#toggles button.dicon .dlbl { font: var(--font); color: #fff; text-shadow: 1px 1px 0 #000; background: rgba(0,0,0,0.35); padding: 1px 3px; }
#toggles button.dicon:hover { border-color: var(--accent); background: rgba(255,255,255,0.06); }
#toggles button.dicon:hover .dlbl { background: var(--accent); color: var(--accent-fg); text-shadow: none; }
#toggles button.dicon:active { box-shadow: inset 2px 2px 0 rgba(0,0,0,0.4); }

/* taskbar */
#taskbar {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 5;
  display: flex; align-items: center; gap: 6px; padding: 3px 8px;
 background: var(--titlebar); color: var(--titlebar-fg);
 border-top: var(--bw) var(--bs) var(--border);
 font: var(--font); box-shadow: 0 -2px 0 rgba(0,0,0,0.3);
}
#tb-logo { height: 15px; width: auto; display: block; }
/* START button + menu (AUTO-PLAYLISTS button is its taskbar sibling) */
#tg-start, #tg-playlists {
 background: var(--panel); color: var(--titlebar-fg);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 font: var(--font); cursor: pointer; padding: 2px 8px;
}
#tg-start.on, #tg-start:hover, #tg-playlists.on, #tg-playlists:hover { background: var(--accent); color: var(--accent-fg); }
#start-menu, #pl-menu {
 position: fixed; left: 8px; bottom: var(--tbh, 28px); z-index: 20; width: 190px;
 background: var(--panel); border: var(--bw) var(--bs) var(--border);
 box-shadow: var(--shadow); border-radius: var(--radius); padding: 3px;
 display: none;
}
.start-item {
 display: flex; align-items: center; gap: 6px; width: 100%;
 background: var(--panel2); color: var(--fg); font: var(--font);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 padding: 4px 8px; cursor: pointer; text-align: left;
}
/* the station currently on air (playlists.js marks it) */
.start-item.current { background: var(--accent); color: var(--accent-fg); }
.start-item:hover { background: var(--accent); color: var(--accent-fg); }
.start-item .start-icn { width: 14px; text-align: center; }
.start-sep { height: 0; border-top: var(--bw) var(--bs) var(--border); margin: 3px 2px; }
/* running-app taskbar buttons */
#taskbtns { display: flex; gap: 4px; flex: 0 1 auto; overflow: hidden; }
.taskbtn {
 background: var(--panel2); color: var(--fg); font: var(--font);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 cursor: pointer; padding: 2px 6px; white-space: nowrap;
 display: flex; align-items: center; gap: 3px;
}
.taskbtn.focused { background: var(--panel); box-shadow: inset 1px 1px 0 var(--bevel-up); color: var(--titlebar-fg); }
.taskbtn.minimized { opacity: 0.55; font-style: italic; }
.taskbtn:hover { border-color: var(--accent); }
.taskbtn .tbicn { font-size: 10px; }
.tbicn { font-size: 10px; }
#tg-reset {
 background: transparent; color: var(--titlebar-fg);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 font: var(--font); cursor: pointer; padding: 0 6px;
}
#tg-reset:hover { background: var(--accent); color: var(--accent-fg); }
#tbsp { flex: 1 1 auto; }
#taskbar #desktheme, #taskbar #deskclock { margin-left: 0; background: transparent; border: none; padding: 0; color: var(--titlebar-fg); }
#desktheme { color: var(--fg); font: var(--font); padding: 0 6px; margin-left: 4px; border: var(--bw) var(--bs) var(--border); background: var(--panel2); border-radius: var(--radius); }
#deskclock { color: var(--fg); font: var(--font); padding: 0 8px; }

/* chooser windows (wallpaper, themes, skins, chat) */
#wall-chooser, #theme-chooser, #chat-chooser, #skin-chooser, #nmtv-chooser, #readme-window, #stations-chooser {
 background: var(--panel); border: var(--bw) var(--bs) var(--border);
 box-shadow: var(--shadow); border-radius: var(--radius);
}
#wall-titlebar, #theme-titlebar, #chat-titlebar, #skin-titlebar, #nmtv-titlebar, #readme-titlebar, #stations-titlebar {
 background: var(--titlebar); color: var(--titlebar-fg);
 border-bottom: var(--bw) var(--bs) var(--border);
 box-shadow: inset 1px 1px 0 var(--bevel-up);
 display: flex; align-items: center; justify-content: space-between;
 padding: 3px 4px; cursor: move; user-select: none;
}
#wall-titlebar span, #theme-titlebar span, #chat-titlebar span, #skin-titlebar span, #nmtv-titlebar span, #readme-titlebar span, #stations-titlebar span {
 color: var(--titlebar-fg); font: var(--font); letter-spacing: 1px;
}
#wall-close, #theme-close, #chat-close, #skin-close, #nmtv-close, #readme-close, #stations-close {
 background: var(--panel); color: var(--fg);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 box-shadow: 2px 2px 0 var(--bevel-down);
 font: 9px/1 monospace; width: 14px; height: 14px; cursor: pointer; padding: 0;
}
#wall-close:hover, #theme-close:hover, #chat-close:hover, #skin-close:hover, #nmtv-close:hover, #readme-close:hover, #stations-close:hover {
 background: var(--accent); color: var(--accent-fg);
}
#wall-foot, #theme-foot, #chat-foot, #nmtv-foot, #stations-foot { color: var(--fg); font: var(--font); }

/* live radio chooser: roster grid, station buttons, LIVE badge (badge rules
   below are shared with #radio-badge). Failure is shown, not hidden: a
   station that never starts is dimmed and struck through, with the reason in
   its tooltip. */
#stations-chooser { position: fixed; z-index: 12; display: none; width: 300px; }
#stations-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 3px; padding: 6px; max-height: 56vh; overflow-y: auto; }
.station-btn {
 display: block; cursor: pointer; padding: 3px 5px; text-align: left; width: 100%;
 background: var(--panel2); color: var(--fg); font: var(--font);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
}
.station-btn:hover { outline: 2px solid var(--accent); }
.station-btn .st-name { display: block; font: bold 10px/1.3 var(--font); letter-spacing: 1px; }
.station-btn .st-mood { display: block; font: 9px/1.3 var(--font); opacity: 0.75; }
.station-btn.current { background: var(--accent); color: var(--accent-fg); }
.station-btn.current .st-mood { opacity: 0.85; }
.station-btn.trying { opacity: 0.7; }
.station-btn.failed { opacity: 0.45; text-decoration: line-through; }
#stations-foot { padding: 4px 6px 6px; }

/* wallpaper chooser */
#wall-chooser { position: fixed; z-index: 10; display: none; width: 240px; }
/* wallpaper swatch grid (titlebar, close and frame come from the chooser
   rules above; these three rules used to live in index.html with hardcoded
   colours, which is why the wallpaper chooser ignored the theme) */
#wall-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px; padding: 6px; }
.wall-swatch { width: 100%; height: 48px; border: var(--bw) var(--bs) var(--border); cursor: pointer; background-color: #000; background-repeat: no-repeat; padding: 0; }
.wall-swatch:hover { border-color: var(--accent); }
#wall-foot { padding: 0 6px 6px; }

/* themes chooser */
#theme-chooser { position: fixed; z-index: 11; display: none; width: 230px; }
#theme-grid { display: grid; grid-template-columns: 1fr; gap: 3px; padding: 6px; }
.theme-swatch {
 display: flex; align-items: center; gap: 6px; cursor: pointer;
 padding: 4px 6px; background: var(--panel2); color: var(--fg);
 font: var(--font); text-align: left; width: 100%;
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
}
.theme-swatch:hover { outline: 2px solid var(--accent); }
.theme-chip { width: 14px; height: 14px; border: 1px solid var(--border); flex: 0 0 auto; }
#theme-foot { padding: 0 6px 6px; }

/* skins chooser: deal + gallery modes */
#skin-chooser { position: fixed; z-index: 11; display: none; width: 340px; }
#skin-now { color: var(--fg); font: var(--font); padding: 4px 6px 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
#skin-grid { display: grid; grid-template-columns: 1fr; gap: 3px; padding: 6px; }
.skin-btn {
 display: block; cursor: pointer; padding: 4px 6px; text-align: left;
 background: var(--panel2); color: var(--fg); font: var(--font); width: 100%;
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
 white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.skin-btn:hover { outline: 2px solid var(--accent); }
#skin-foot { display: flex; align-items: center; gap: 4px; padding: 0 6px 6px; color: var(--fg); font: var(--font); }
#skin-foot button {
 background: var(--panel2); color: var(--fg); font: var(--font); cursor: pointer;
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius); padding: 2px 6px;
}
#skin-foot button:hover { background: var(--accent); color: var(--accent-fg); }
#skin-count { margin-left: auto; color: #777; }
/* gallery mode thumb wall */
#skin-tabs { display: flex; gap: 4px; padding: 4px 6px 0; }
#skin-tabs button {
 background: var(--panel2); color: var(--fg); font: var(--font); cursor: pointer;
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius); padding: 2px 8px;
}
#skin-tabs button.on { background: var(--accent); color: var(--accent-fg); }
#skin-searchwrap { padding: 4px 6px; }
#skin-search {
 width: 100%; box-sizing: border-box; background: #0a0a0a; color: var(--fg);
 border: var(--bw) var(--bs) var(--border); font: var(--font); padding: 4px 6px;
}
#skin-grid.gal { display: grid; grid-template-columns: repeat(4, 1fr); gap: 6px; padding: 6px; overflow-y: auto; max-height: 60vh; }
.skin-thumb {
 display: flex; flex-direction: column; gap: 2px; cursor: pointer;
 padding: 3px; background: var(--panel2); color: var(--fg);
 border: var(--bw) var(--bs) var(--border); border-radius: var(--radius);
}
.skin-thumb:hover { outline: 2px solid var(--accent); }
.skin-thumb img { width: 100%; height: 58px; object-fit: contain; background: #000; image-rendering: pixelated; display: block; }
.skin-thumb span { font: var(--font); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; text-align: left; }

/* chat window (shoutbox iframe) */
#chat-chooser { position: fixed; z-index: 10; display: none; width: 322px; }
#chat-frame { display: block; width: 320px; height: 380px; border: none; border-top: var(--bw) var(--bs) var(--border); background: #1a1a1a; }
#chat-foot { padding: 0 6px 6px; }

/* nmtv window (nmtv.online iframe) */
#nmtv-chooser { position: fixed; z-index: 10; display: none; width: 522px; max-width: 92vw; }
#nmtv-frame { display: block; width: 100%; height: 420px; border: none; border-top: var(--bw) var(--bs) var(--border); background: #000; }
#nmtv-tbbtns { display: flex; align-items: center; gap: 4px; }
#nmtv-external { font: 8px/1 monospace; padding: 2px 5px; cursor: pointer;
 background: var(--panel); color: var(--fg); border: var(--bw) var(--bs) var(--border); border-radius: var(--radius); box-shadow: 2px 2px 0 var(--bevel-down); }
#nmtv-external:hover { background: var(--accent); color: var(--accent-fg); }

/* library window pinned classic colors */
#app .gen-window.window { display: flex; flex-direction: column; }
#app .gen-window.window .gen-middle { flex: 1 1 auto; overflow: hidden; min-height: 0; }
#app .gen-window.window .gen-middle-center, #app .gen-window.window .gen-middle-center div { width: 100% !important; }
#app .gen-window.window .gen-middle-center { overflow-y: auto; overflow-x: hidden; max-height: 100% !important; }
#app .gen-window.window .gen-middle-center input { width: 100% !important; box-sizing: border-box; }

/* mobile touch */
* { -webkit-tap-highlight-color: transparent; }
.window .draggable { touch-action: none; }
@media (max-width: 480px) {
 #app .gen-window.window { max-width: calc(100vw - 8px); }
 #app .gen-window.window .gen-middle { max-width: 100%; }
 #taskbar button { min-height: 26px; }
}

/* M1 (mobile audit 2026-09-19): a taskbar that fits small screens.
   #taskbtns is a flex item with overflow:hidden, so its automatic minimum
   size is 0: under width pressure it silently shrank to nothing and took all
   five window buttons with it, while the sound toggle and clock slid off the
   right edge — the page never scrolls, so they were unreachable. The bar is
   now one strip that scrolls horizontally whenever its content does not fit:
   every control keeps its natural width and the clock stays pinned. The
   scroll/flex rules are deliberately universal (M1.1, future-proofing audit
   of a5bb7a4): a breakpoint would let the same collapse return the day the
   content outgrows it, and with nothing to scroll they are a no-op on wide
   screens. */
#taskbar {
 overflow-x: auto; overflow-y: hidden; overscroll-behavior-x: contain;
 scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
#taskbar::-webkit-scrollbar { display: none; }
#taskbar > * { flex-shrink: 0; }        /* natural widths -> the strip overflows and scrolls */
#taskbar #deskclock {
 position: sticky; right: 0; padding: 0 6px;
 background: inherit;                    /* follow the bar's own surface (gradient included), never a flat colour */
}
@media (max-width: 1024px) {
 /* content slides under the pinned clock: a soft edge reads as "there is more" */
 #taskbar #deskclock { box-shadow: -6px 0 6px -6px rgba(0,0,0,0.35); }
}
@media (max-width: 560px) {
 #tb-logo { display: none; }             /* decorative, and the first thing to go on a phone */
 #taskbar { gap: 5px; padding: 3px 6px; }
}

/* M2 (mobile audit 2026-09-19): touch ergonomics.
   - manipulation = pan + pinch minus double-tap zoom, so a quick double tap on
     a control stops zooming the page (pinch-zoom stays for accessibility).
     The winamp drag handles keep their own touch-action: none.
   - a long press on the chrome must not start a text selection / iOS callout
     halfway through a tap.
   - iOS Safari zooms the whole page when an input under 16px takes focus and
     the library search is 11px: coarse pointers get 16px text inputs.
   - the skin's 9x9 window controls get the hit area the chrome actually has
     room for (neighbours sit 1-2px apart, the outer buttons 2px from the
     window edge): pads grow them to ~11x14 / 9x14 without overlapping a
     neighbour or stealing more than a sliver of drag space. */
#taskbar, #taskbar *, #toggles, #toggles *, #start-menu, #start-menu *, #pl-menu, #pl-menu * { touch-action: manipulation; }
/* the winamp chrome inside #app: the transport row, the status bar and the
   clutter buttons are where double taps land most; the drag handles and their
   contents keep touch-action: none (a drag must never be read as a gesture) */
#app .actions, #app .actions *, #app .webamp-status, #app .webamp-status *,
#app #clutter-bar, #app #clutter-bar *,
#app #close, #app #shade, #app #minimize, #app #play-pause,
#app #playlist-close-button, #app #playlist-shade-button, #app .gen-close { touch-action: manipulation; }
#taskbar, #toggles, #start-menu, #pl-menu, #app .title-bar,
#app .playlist-top, #app .gen-top, #app .gen-bottom {
 -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
}
@media (pointer: coarse) {
 #app input:not([type="range"]),
 #app .gen-window.window .gen-middle-center input { font-size: 16px; }
 #app #minimize::before, #app #shade::before, #app #close::before,
 #app #playlist-shade-button::before, #app #playlist-close-button::before,
 #app .gen-close::before { content: ""; position: absolute; inset: -3px 0 -2px 0; }
 #app #close::before, #app #playlist-close-button::before, #app .gen-close::before { inset: -3px -2px -2px 0; }
 #app #play-pause::before { content: ""; position: absolute; inset: -4px; }
}

/* boot splash (T0-2) */
#boot-splash {
 position: fixed; inset: 0; z-index: 100; background: #000; cursor: pointer;
 display: flex; align-items: center; justify-content: center;
 transition: opacity 0.45s ease;
}
#boot-box { width: 420px; max-width: 90vw; font: 12px/1.7 monospace; color: #00e08c; }
#boot-logo {
 font: bold 28px/1 monospace; color: #b8f0d0; letter-spacing: 4px;
 margin-bottom: 14px; text-shadow: 3px 3px 0 rgba(0,224,160,0.25);
}
.boot-line { opacity: 0; animation: bootline 0.25s ease forwards; }
@keyframes bootline { to { opacity: 1; } }
.boot-ok { color: #9fe8c8; margin-right: 6px; }
#boot-bar { height: 14px; border: 1px solid #3a3a3a; margin: 14px 0 4px; background: #0a0a0a; }
#boot-fill { height: 100%; width: 0; background: #00e0a0; transition: width 0.06s linear; }
#boot-pct { float: right; color: #9fe8c8; }
#boot-hint { clear: both; color: #555; font-size: 10px; margin-top: 8px; text-align: center; }

/* desktop right-click menu (T1-2) — same items as START */
#ctx-menu {
 position: fixed; z-index: 30; width: 190px; display: none;
 background: var(--panel); border: var(--bw) var(--bs) var(--border);
 box-shadow: var(--shadow); border-radius: var(--radius); padding: 3px;
}
#ctx-menu .start-item { background: var(--panel2); color: var(--fg); }
#ctx-menu .start-item:hover { background: var(--accent); color: var(--accent-fg); }

/* focused window titlebar brightening (T1-4)
   (#main-window.focused-win .window-shade was dropped: the bundle only ever
   emits the id "playlist-window-shade", never a .window-shade class, so that
   selector clause could not match) */
#main-window.focused-win #title-bar {
 filter: brightness(1.25);
}
#playlist-window.focused-win .playlist-top,
#equalizer-window.focused-win,
.gen-window.window.focused-win { outline: 1px solid var(--accent); outline-offset: -1px; }

/* readme window */
#readme-window { position: fixed; z-index: 10; display: none; width: 440px; max-width: 92vw; }
#readme-titlebar { width: 100%; display: flex; justify-content: space-between; align-items: center; padding: 4px 6px; box-sizing: border-box; cursor: move; }
#readme-close { background: none; color: inherit; border: none; font: bold 11px/1 monospace; cursor: pointer; padding: 0 2px; }
#readme-close:hover { color: var(--accent); }
#readme-body { margin: 0; padding: 8px 10px; font: 11px/1.5 monospace; color: var(--fg); white-space: pre-wrap; max-height: 60vh; overflow-y: auto; }
#readme-foot { color: #777; font: 10px/1 monospace; padding: 4px 8px; border-top: var(--bw) var(--bs) var(--border); }

/* radio taskbar badge (T0-1) */
#radio-badge, #live-badge {
 height: 24px; padding: 0 10px; border: var(--bw) var(--bs) var(--border);
 background: var(--accent); color: var(--accent-fg);
 font: bold 10px/24px var(--font); border-radius: var(--radius);
 cursor: pointer; animation: radio-pulse 2s ease-in-out infinite;
}
#radio-badge:hover, #live-badge:hover { filter: brightness(1.2); }
@keyframes radio-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.65; } }


/* swipe (2026-09-21): touch scrolling for the playlist — see swipe.js.
   Classic Winamp scrolls the playlist with an 8px-wide rail and two 8x5px
   arrow buttons: mouse-sized, thumb-hostile. On coarse pointers the rail and
   the arrows get fat hit zones (the skin's pixels are untouched) and the
   track list becomes a drag surface: swipe.js turns a vertical drag into
   SET_PLAYLIST_SCROLL_POSITION, with momentum and a position chip. */
.pl-swipe-chip {
  position: absolute; right: 26px; top: 30px; z-index: 6;
  max-width: 210px; padding: 3px 8px; overflow: hidden;
  text-overflow: ellipsis; white-space: nowrap; pointer-events: none;
  background: var(--panel, #111); color: var(--accent, #00e08c);
  border: var(--bw, 1px) var(--bs, solid) var(--border, #444);
  border-radius: 3px; font: 10px/1.4 var(--font, monospace);
  opacity: 0; transition: opacity .12s linear;
}
.pl-swipe-chip.on { opacity: 1; }

@media (pointer: coarse) {
  /* the row list is a touch surface: no native panning/zoom there, the
     module owns the gesture (a drag scrolls the playlist instead) */
  #app #playlist-window .playlist-tracks { touch-action: none; }

  /* fat rail: the 8px rail gets a ~26px hit zone, centred on it */
  #app #playlist-window .playlist-scrollbar { position: relative; touch-action: none; }
  #app #playlist-window .playlist-scrollbar::before {
    content: ""; position: absolute; top: 0; bottom: 0; left: -9px; right: -9px;
  }
  /* and a slim hint that this rail is grabbable (skins draw only the 8px bar) */
  #app #playlist-window .playlist-scrollbar::after {
    content: ""; position: absolute; top: 4px; bottom: 4px; left: 50%;
    width: 2px; margin-left: -1px; background: rgba(255, 255, 255, .10);
    pointer-events: none;
  }

  /* the arrow buttons keep their 8x5px glyphs; their expanded tap zones are
     transparent divs placed by swipe.js (.pl-tapzone), because the strip is
     crowded (rail above, resize handle below, menu buttons to the left) and a
     CSS-expanded hit area would steal from its neighbours */
}
.pl-tapzone {
  position: absolute; z-index: 5; background: transparent;
  touch-action: none; -webkit-tap-highlight-color: transparent;
}

/* M4 (mobile audit 2026-09-19): the 8-icon strip is 528px tall — it covers the
   playlist's left edge on a phone, and the last three icons fall off a
   landscape viewport (measured 2026-09-21: 5/8 reachable at 844x390). On
   phone-like viewports the strip becomes a drawer behind the taskbar's ICONS
   button: hidden until asked for, internally scrollable so all eight stay
   reachable when the viewport is short, and always one tap from closing. */
#tg-drawer { display: none; }
@media (max-width: 560px), (pointer: coarse) and (max-height: 520px) {
  #tg-drawer { display: inline-block; }
  #toggles { display: none; }
  body.drawer-open #toggles {
    display: flex; position: fixed; left: 0; top: 0; bottom: var(--tbh, 44px); z-index: 40;
    width: 88px; padding: 8px 6px; gap: 8px;
    background: var(--panel); border-right: var(--bw) var(--bs) var(--border);
    overflow-y: auto; -webkit-overflow-scrolling: touch;
  }
  body.drawer-open::after {
    content: ""; position: fixed; inset: 0 0 var(--tbh, 44px) 88px; z-index: 39;
    background: rgba(0, 0, 0, .35);
  }
}
/* a short viewport (a landscape phone) cannot stack eight icons: two columns
   of four, still 88px wide each, so every target keeps its size */
@media (pointer: coarse) and (max-height: 520px) {
  body.drawer-open #toggles {
    display: grid; grid-template-columns: 1fr 1fr; grid-auto-rows: minmax(44px, auto);
    width: 176px; gap: 6px;
  }
  body.drawer-open::after { inset: 0 0 var(--tbh, 44px) 176px; }
}

/* M6 (touch rows, 2026-09-21): phone-like viewports run the playlist at 2x —
   26px rows and 13px type instead of the skin's mouse-sized 13px rows with
   9px type, so a thumb can read, hit and fling the list. `pl-touch` is set
   from index.html by the SAME gate as the phone layout (isPhone(): narrow,
   or a coarse pointer with no vertical room) and it is JS-driven rather than
   a media query on purpose — the gate cannot be expressed as one CSS query
   without drifting from isPhone(), and the bundle's row math plus swipe.js
   both read window.__plRow, so CSS and JS must flip together (see M6 in
   docs/improvements-roadmap.md). Titles and durations are both .track-cell
   rows. */
.pl-touch #webamp .playlist-tracks .track-cell {
 height: 26px; line-height: 26px; font-size: 13px;
}


/* M7 (2026-09-22) phone taskbar + menu chrome — portrait touch revamp.
   Gate: html.tb-touch set by index.html's isPhone() (width < 480 && coarse),
   same one-gate discipline as html.pl-touch (M6: JS gate, CSS follows the
   class). --tbh mirrors the taskbar's LIVE height (set by index.html from
   getBoundingClientRect on boot + resize), so the menus, the drawer panel
   and its scrim anchor to the real bar instead of hard-coded 28px/44px.
   Menu rows scale on coarse pointers (landscape phones included); no JS
   reads these sizes back. */
html { --tbh: 28px; }
html.tb-touch { --tbh: 92px; } /* fallback if the JS measure never runs */
html.tb-touch #taskbar {
  flex-wrap: wrap;             /* row 1 nav, row 2 window chips + clock */
  align-content: flex-start;
  min-height: 44px;
  padding: 3px 6px calc(3px + env(safe-area-inset-bottom, 0px));
  gap: 4px 6px;
}
html.tb-touch #taskbar > button {
  height: 44px;
  min-height: 44px;
  padding: 0 12px;
  font-size: 13px;
}
html.tb-touch #taskbar .tbicn { font-size: 14px; }
html.tb-touch #tg-drawer { width: 44px; padding: 0; font-size: 17px; }
/* narrow phones: the nav row must keep all four buttons on one line */
@media (max-width: 360px) {
  html.tb-touch #taskbar > button { padding: 0 8px; letter-spacing: -0.3px; }
}
html.tb-touch #taskbtns {
  flex: 1 1 auto;             /* row 2: chips strip, clock + mute tuck into the tail */
  order: 3;
  min-height: 38px;
  min-width: 0;                /* beat the M1 universal flex-shrink:0 so the
                                  strip can shrink and scroll within its row */
  overflow-x: auto;            /* 5 chips at full labels overflow 390px — scroll */
  scrollbar-width: none;
  max-width: calc(100% - 104px); /* never push the mute toggle or the clock
                                  off row 2 (sound 40 + clock 48 + 3 gaps 12
                                  = 100px reserved + 4px slack) */
}
html.tb-touch #taskbtns::-webkit-scrollbar { display: none; }
html.tb-touch .taskbtn {
  height: 38px; min-height: 38px; min-width: 40px;
  font: 12px/1 monospace;      /* the bar's 11px var is mouse-sized; 12 mono reads */
  gap: 4px;
}
html.tb-touch .taskbtn .tb-lbl { padding-right: 4px; }
html.tb-touch #deskclock {
  order: 4;
  min-height: 38px;
  font: 12px/1 monospace;    /* keep digits tabular and row-consistent */
  display: flex; align-items: center;  /* center the time in its 38px slot */
  margin-left: auto;         /* pinned to the row end, chips keep the strip */
  padding: 0 calc(8px + env(safe-area-inset-right, 0px)) 0 8px;
}
html.tb-touch #tg-reset, html.tb-touch #desktheme { display: none; }
html.tb-touch #tbsp { display: none; }   /* spacer steals row-1 slack: no */

/* the sounds.js mute toggle: desktop keeps its inline-era look via the class */
#tg-sound.tb-sound {
  background: transparent; color: var(--titlebar-fg);
  border: var(--bw) var(--bs) var(--border);
  font: 10px/1 monospace; cursor: pointer;
  padding: 2px 6px; border-radius: var(--radius);
}
/* phone: the mute toggle joins the chip row, icon-only; the chips strip
   scrolls within the space that remains */
html.tb-touch #tg-sound {
  order: 2; height: 38px; min-height: 38px; min-width: 40px; padding: 0 10px;
  display: flex; align-items: center; justify-content: center; /* glyph dead-center */
}
html.tb-touch #tg-sound .sndlbl { display: none; }
html.tb-touch #tg-sound .sndicn { font-size: 14px; }

/* a landscape phone (short viewport) cannot afford two rows: the bar stays
   ONE 40px row and the chips strip scrolls, M1-style */
@media (pointer: coarse) and (max-height: 520px) {
  html.tb-touch #taskbar { flex-wrap: nowrap; min-height: 40px; }
  html.tb-touch #taskbar > button { height: 40px; min-height: 40px; padding: 0 10px; }
  html.tb-touch #taskbtns { flex: 0 1 auto; order: 0; overflow-x: auto; }
  html.tb-touch .taskbtn { height: 36px; min-height: 36px; }
  html.tb-touch #deskclock { order: 0; min-height: 36px; }
}

/* menus sit flush above the (taller) taskbar; big touch rows on any coarse
   pointer (portrait via tb-touch, landscape via the coarse media) */
html.tb-touch #start-menu, html.tb-touch #pl-menu, html.tb-touch #ctx-menu {
  width: min(320px, calc(100vw - 16px));
  max-height: calc(100vh - var(--tbh) - 12px);
  overflow-y: auto;
  overscroll-behavior: contain;
}
@media (pointer: coarse) {
  .start-item { min-height: 40px; font-size: 13px; padding: 0 12px; }
  .start-icn { width: 18px; font-size: 15px; }
  .start-sep { margin: 4px 2px; }
}


/* T0 (2026-09-22) NeXTSTEP homage: tab titlebars for the generic windows.
   Gate: html.theme-next, off by default — the classic Winamp chrome stays the
   reference look. One CSS block, no fork changes, no markup change: win.js
   already renders <div id="*-titlebar"><span>TITLE</span><button>x</button>.
   The NeXT look: a raised tab sitting on a bevelled body, the title centred in
   the tab, a squarish close widget on the right, and the 1px light/dark bevel
   pair that reads as moulded plastic. */
html.theme-next #wall-titlebar,
html.theme-next #theme-titlebar,
html.theme-next #skin-titlebar,
html.theme-next #chat-titlebar,
html.theme-next #nmtv-titlebar,
html.theme-next #readme-titlebar {
  display: flex; align-items: center; gap: 8px;
  box-sizing: border-box;           /* all six compute the same 30px */
  height: 30px; min-height: 30px;
  padding: 3px 4px 3px 10px;
  background: linear-gradient(180deg, var(--panel) 0%, var(--panel2) 100%);
  border: 1px solid var(--border);
  border-bottom: 0;
  font: 11px/1.2 var(--font);
  letter-spacing: 0.04em;
  cursor: move;              /* the whole tab is the drag handle */
}
html.theme-next #wall-titlebar > span,
html.theme-next #theme-titlebar > span,
html.theme-next #skin-titlebar > span,
html.theme-next #chat-titlebar > span,
html.theme-next #nmtv-titlebar > span,
html.theme-next #readme-titlebar > span {
  flex: 1 1 auto;
  text-align: center;         /* NeXT centred the title in the tab */
  color: var(--fg);
  padding: 1px 8px 2px;
  background: linear-gradient(180deg, var(--panel2), var(--panel));
  border: 1px solid var(--border);
  border-top-color: var(--bevel-up);
  border-left-color: var(--bevel-up);
  border-bottom-color: var(--border);
  border-right-color: var(--border);
  box-shadow: inset 1px 1px 0 rgba(255, 255, 255, 0.06);
}
html.theme-next #wall-titlebar > button,
html.theme-next #theme-titlebar > button,
html.theme-next #skin-titlebar > button,
html.theme-next #chat-titlebar > button,
html.theme-next #nmtv-titlebar > button,
html.theme-next #readme-titlebar > button {
  appearance: none;
  flex: 0 0 auto;
  width: 18px; height: 18px;
  padding: 0; margin: 0;
  font: 12px/16px var(--font);
  color: var(--fg);
  background: linear-gradient(135deg, var(--panel2), var(--panel));
  border: 1px solid var(--border);
  border-top-color: var(--bevel-up);
  border-left-color: var(--bevel-up);
  cursor: pointer;
}
html.theme-next #wall-titlebar > button:active,
html.theme-next #theme-titlebar > button:active,
html.theme-next #skin-titlebar > button:active,
html.theme-next #chat-titlebar > button:active,
html.theme-next #nmtv-titlebar > button:active,
html.theme-next #readme-titlebar > button:active {
  border-top-color: var(--border);
  border-left-color: var(--border);
  border-bottom-color: var(--bevel-up);
  border-right-color: var(--bevel-up);
}
/* the body sits under the tab: pull it up so the tab reads as sitting ON it */
html.theme-next #wall-chooser,
html.theme-next #theme-chooser,
html.theme-next #skin-chooser,
html.theme-next #chat-chooser,
html.theme-next #nmtv-chooser,
html.theme-next #readme-window {
  border-top: 0;
}
