Files
media-player-server/media_server/static/css/styles.css
T
alexei.dolgolyov 2049850180 ui: editorial styling for Library/Quick Access/Settings/Display + tab fix
Tab bar
- Was rendering with all 4 borders + bg + radius (legacy capsule).
  Override now nukes border/background/radius/padding with !important
  and leaves only a single hairline border-bottom. Tabs now read as
  an editorial nav strip, not a card.

Library (browser tab)
- Breadcrumb: italic serif with copper hover, mono separator
- Toolbar: hairline-grouped controls, no card chrome
- View-toggle: square hairline pills with copper active
- Search: underline-only input, copper underline on focus
- Items-per-page: mono uppercase label + hairline select
- Browser grid: editorial cards (serif title + mono meta), copper
  hover border, copper play-overlay
- List view: hairline table with mono headers + serif cells
- Pagination: hairline buttons, mono uppercase, copper hover

Quick Access
- Console-rail layout (1px gaps on rule background)
- Cards: serif italic label, copper hover with icon lift
- Empty state: italic serif on dashed paper card

Settings
- Each settings-section becomes a numbered editorial card with a
  CSS counter (5.01, 5.02, ...) shown as a mono prefix on the
  italic-serif summary. Open/closed chevron via :before/:after
- Tables: hairline borders, mono uppercase headers, serif name cells
- Add-card: editorial dashed border, copper-on-hover
- Audio device selector: mono labels, hairline select, status
  pills (active/available/unavailable) in jade/amber/rust
- Folder badges, action buttons, empty states all aligned to
  the editorial palette

Display
- Monitor grid: editorial paper cards
- Headings: serif, copper hover on actions
- Empty state: italic serif on dashed card

Cross-cutting
- Icon-select trigger + popup restyled to editorial
2026-04-25 02:50:51 +03:00

7978 lines
189 KiB
CSS

/* ============================================================
STUDIO REFERENCE — local fonts (Fraunces · Geist · Geist Mono)
Subsets: Latin, Latin-ext, Cyrillic. WOFF2 variable, OFL.
============================================================ */
@font-face {
font-family: 'Fraunces';
font-style: italic;
font-weight: 300 900;
font-display: swap;
src: url('/static/fonts/Fraunces-italic-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Fraunces';
font-style: italic;
font-weight: 300 900;
font-display: swap;
src: url('/static/fonts/Fraunces-italic-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Fraunces';
font-style: normal;
font-weight: 300 900;
font-display: swap;
src: url('/static/fonts/Fraunces-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Fraunces';
font-style: normal;
font-weight: 300 900;
font-display: swap;
src: url('/static/fonts/Fraunces-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Geist';
font-style: normal;
font-weight: 300 700;
font-display: swap;
src: url('/static/fonts/Geist-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Geist';
font-style: normal;
font-weight: 300 700;
font-display: swap;
src: url('/static/fonts/Geist-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Geist';
font-style: normal;
font-weight: 300 700;
font-display: swap;
src: url('/static/fonts/Geist-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
font-family: 'Geist Mono';
font-style: normal;
font-weight: 300 600;
font-display: swap;
src: url('/static/fonts/GeistMono-cyrillic.woff2') format('woff2');
unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
font-family: 'Geist Mono';
font-style: normal;
font-weight: 300 600;
font-display: swap;
src: url('/static/fonts/GeistMono-latin-ext.woff2') format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
font-family: 'Geist Mono';
font-style: normal;
font-weight: 300 600;
font-display: swap;
src: url('/static/fonts/GeistMono-latin.woff2') format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* ============================================================
Studio Reference — design tokens (default = warm dark)
Light theme = Paper Edition (cream + emerald)
Old token names preserved as aliases for unmigrated components.
============================================================ */
:root {
/* Studio Reference (warm dark) */
--bg-deep: #0E0D0B;
--bg-paper: #18150F;
--bg-card: #211E18;
--bg-card-2: #26211A;
--bg-rule: #2E2820;
--ink: #F2EBDC;
--ink-soft: #D6CDB9;
--ink-mute: #9C937F;
--ink-faint: #5C5447;
--ink-ghost: #3A3528;
--copper: #E08038;
--copper-hi: #F4A064;
--copper-lo: #B0561F;
--copper-glow: rgba(224, 128, 56, 0.35);
--amber: #F5C26B;
--jade: #7AB294;
--rust: #C2553F;
--rule: rgba(242, 235, 220, 0.08);
--rule-strong: rgba(242, 235, 220, 0.18);
--serif: 'Fraunces', 'Iowan Old Style', Georgia, 'Times New Roman', serif;
--sans: 'Geist', 'Inter', 'Segoe UI', -apple-system, BlinkMacSystemFont, 'Helvetica Neue', sans-serif;
--mono: 'Geist Mono', 'JetBrains Mono', 'Cascadia Code', ui-monospace, monospace;
--ease: cubic-bezier(.2, .7, .2, 1);
--ease-out: cubic-bezier(.16, 1, .3, 1);
/* Backwards-compatible aliases — components not yet migrated */
--bg-primary: var(--bg-deep);
--bg-secondary: var(--bg-paper);
--bg-tertiary: var(--bg-card);
--text-primary: var(--ink);
--text-secondary: var(--ink-soft);
--text-muted: var(--ink-mute);
--accent: var(--copper);
--accent-hover: var(--copper-hi);
--border: var(--bg-rule);
--error: var(--rust);
--vinyl-ring: #1a1611;
--vinyl-groove: #2a241c;
--vinyl-highlight: rgba(255,255,255,0.05);
--vinyl-highlight-dim: rgba(255,255,255,0.03);
--vinyl-edge: #0a0907;
--vinyl-spindle: #050402;
--shadow-elevation: rgba(0, 0, 0, 0.5);
}
:root[data-theme="light"] {
/* Paper Edition (warm cream) */
--bg-deep: #F5F1EA;
--bg-paper: #EDE7DC;
--bg-card: #FFFFFF;
--bg-card-2: #FAF6EE;
--bg-rule: #D4CCB9;
--ink: #1A1715;
--ink-soft: #4A4540;
--ink-mute: #8A8278;
--ink-faint: #B0A89A;
--ink-ghost: #C8C0B3;
--copper: #1F4E3D; /* hunter emerald in light mode */
--copper-hi: #2D6A53;
--copper-lo: #143E2F;
--copper-glow: rgba(31, 78, 61, 0.18);
--amber: #C29D31;
--jade: #4D8C6F;
--rust: #B82F1A;
--rule: rgba(26, 23, 21, 0.08);
--rule-strong: rgba(26, 23, 21, 0.18);
/* Aliases */
--bg-primary: var(--bg-deep);
--bg-secondary: var(--bg-paper);
--bg-tertiary: var(--bg-card);
--text-primary: var(--ink);
--text-secondary: var(--ink-soft);
--text-muted: var(--ink-mute);
--accent: var(--copper);
--accent-hover: var(--copper-hi);
--border: var(--bg-rule);
--error: var(--rust);
--vinyl-ring: #C8BFA8;
--vinyl-groove: #B0A892;
--vinyl-highlight: rgba(255,255,255,0.3);
--vinyl-highlight-dim: rgba(255,255,255,0.15);
--vinyl-edge: #968D78;
--vinyl-spindle: #8A8278;
--shadow-elevation: rgba(26, 23, 21, 0.15);
}
:root[data-theme="light"] .player-container,
:root[data-theme="light"] .browser-container,
:root[data-theme="light"] .scripts-container,
:root[data-theme="light"] .script-management,
:root[data-theme="light"] .settings-section,
:root[data-theme="light"] .display-container {
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
:root[data-theme="light"] .toast {
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
:root[data-theme="light"] dialog {
box-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);
}
:root[data-theme="light"] dialog::backdrop {
background: rgba(0, 0, 0, 0.4);
}
:root[data-theme="light"] .mini-player {
box-shadow: 0 -2px 8px rgba(0, 0, 0, 0.08);
}
/* Dynamic background removed per user request — canvas stays in DOM
so JS doesn't break, but is hidden + the toggle button is hidden. */
.bg-shader-canvas { display: none !important; }
#bgToggle { display: none !important; }
body.dynamic-bg-active {
background: transparent;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
scrollbar-width: thin;
scrollbar-color: var(--border) var(--bg-primary);
}
html {
overflow-y: scroll;
}
body {
font-family: var(--sans);
font-feature-settings: 'ss01', 'cv11';
background: var(--bg-primary);
color: var(--text-primary);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
/* Film-grain overlay — adds analog warmth to the dark theme.
Disabled in light theme where it muddies cream paper. */
body::before {
content: "";
position: fixed;
inset: 0;
pointer-events: none;
z-index: 9999;
opacity: 0.05;
mix-blend-mode: overlay;
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='200' height='200'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.95 0 0 0 0 0.92 0 0 0 0 0.86 0 0 0 0.7 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
:root[data-theme="light"] body::before {
opacity: 0.04;
mix-blend-mode: multiply;
background-image: url("data:image/svg+xml;utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 0.45 0 0 0 0 0.40 0 0 0 0 0.32 0 0 0 0.5 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* Reduced-motion fallback: drop the grain entirely. */
@media (prefers-reduced-motion: reduce) {
body::before { display: none; }
}
/* Heading defaults — components may override per-element. */
h1, h2, h3, .editorial-heading {
font-family: var(--serif);
font-weight: 400;
letter-spacing: -0.015em;
}
/* Mono utility — for technical readouts (timecodes, bitrates, etc.) */
.mono, .timecode, .meta-mono {
font-family: var(--mono);
font-feature-settings: 'tnum', 'cv01';
}
/* Prevent flash of untranslated content */
body.loading-translations {
opacity: 0;
transition: opacity 0.1s ease-in;
}
body.translations-loaded {
opacity: 1;
}
/* Custom Scrollbars */
::-webkit-scrollbar {
width: 8px;
height: 8px;
}
::-webkit-scrollbar-track {
background: var(--bg-primary);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--text-muted);
}
/* Focus-visible states for keyboard accessibility */
:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(29, 185, 84, 0.2);
}
input:focus-visible,
select:focus-visible,
textarea:focus-visible {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(29, 185, 84, 0.15);
}
.tab-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: -2px;
}
/* Prevent scrolling when dialog is open */
body.dialog-open {
overflow: hidden;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 0.75rem 0.75rem 0.5rem;
}
header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
padding-bottom: 0.5rem;
}
h1 {
font-size: 1.5rem;
font-weight: 600;
}
.version-label {
font-size: 0.7rem;
color: var(--text-muted);
background: var(--bg-tertiary);
padding: 0.15rem 0.5rem;
border-radius: 1rem;
font-weight: 500;
align-self: center;
}
.status-dot {
display: inline-flex;
align-items: center;
gap: 6px;
font-size: 0.75rem;
color: var(--text-muted);
transition: color 0.3s;
}
.status-dot::before {
content: '';
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
background: var(--error);
flex-shrink: 0;
transition: background 0.3s;
}
.status-dot.connected::before,
.status-dot.status-online::before {
background: var(--accent);
}
.status-dot.status-offline::before {
background: var(--error);
}
/* Folder management */
.folder-unavailable-badge,
.folder-disabled-badge {
font-size: 0.75rem;
padding: 1px 6px;
border-radius: 4px;
vertical-align: middle;
margin-left: 4px;
}
.folder-unavailable-badge {
background: color-mix(in srgb, var(--error) 20%, transparent);
color: var(--error);
}
.folder-disabled-badge {
background: color-mix(in srgb, var(--text-secondary) 20%, transparent);
color: var(--text-secondary);
}
.browser-item.unavailable,
.browser-list-item.unavailable {
opacity: 0.5;
cursor: default;
}
.path-cell {
max-width: 250px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.header-toolbar {
display: flex;
align-items: center;
gap: 2px;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 3px 4px;
}
.header-toolbar-sep {
width: 1px;
height: 18px;
background: var(--border);
margin: 0 3px;
flex-shrink: 0;
}
.header-btn {
background: transparent;
border: none;
padding: 4px 6px;
border-radius: 5px;
cursor: pointer;
color: var(--text-secondary);
transition: color 0.2s, background 0.2s;
display: inline-flex;
align-items: center;
line-height: 1;
}
.header-btn:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}
.header-btn.active {
color: var(--accent);
}
.header-btn svg {
width: 16px;
height: 16px;
fill: currentColor;
}
.header-btn-logout:hover {
color: var(--error);
}
.header-locale {
background: transparent;
border: none;
color: var(--text-secondary);
font-size: 0.75rem;
font-weight: 600;
padding: 4px 4px 4px 8px;
border-radius: 5px;
cursor: pointer;
transition: color 0.2s, background 0.2s;
}
.header-locale:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}
.header-locale:focus {
outline: none;
}
.header-locale option {
background: var(--bg-secondary);
color: var(--text-primary);
}
/* Header Quick Links */
.header-links {
display: flex;
align-items: center;
gap: 2px;
}
.header-links:not(:empty) {
padding-right: 3px;
margin-right: 3px;
border-right: 1px solid var(--border);
}
.header-link {
display: flex;
align-items: center;
justify-content: center;
padding: 4px 6px;
border-radius: 5px;
color: var(--text-secondary);
transition: color 0.2s, background 0.2s;
text-decoration: none;
}
.header-link:hover {
color: var(--text-primary);
background: var(--bg-tertiary);
}
.header-link svg {
width: 16px;
height: 16px;
}
/* Icon Input with Preview */
.icon-input-wrapper {
display: flex;
align-items: center;
gap: 0.5rem;
}
.icon-input-wrapper input {
flex: 1;
}
.icon-preview {
display: flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
min-width: 36px;
border-radius: 6px;
background: var(--bg-tertiary);
color: var(--text-primary);
}
.icon-preview svg {
width: 20px;
height: 20px;
}
.icon-preview:empty {
display: none;
}
/* Accent Color Picker */
.accent-picker {
position: relative;
}
.accent-dot {
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--accent);
border: 2px solid var(--border);
display: block;
}
.accent-picker-dropdown {
display: none;
position: absolute;
right: 0;
top: calc(100% + 4px);
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 10px;
gap: 6px;
z-index: 100;
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
grid-template-columns: repeat(3, 28px);
}
.accent-picker-dropdown.open {
display: grid;
}
.accent-swatch {
width: 28px;
height: 28px;
border-radius: 50%;
border: 2px solid transparent;
cursor: pointer;
transition: transform 0.15s, border-color 0.15s;
}
.accent-swatch:hover {
transform: scale(1.15);
}
.accent-swatch.active {
border-color: var(--text-primary);
}
.accent-custom-row {
grid-column: 1 / -1;
display: flex;
align-items: center;
gap: 8px;
padding: 6px 2px 2px;
margin-top: 4px;
border-top: 1px solid var(--border);
cursor: pointer;
border-radius: 4px;
}
.accent-custom-row:hover .accent-custom-label {
color: var(--text-primary);
}
.accent-custom-row.active .accent-custom-swatch {
outline: 2px solid var(--text-primary);
outline-offset: 1px;
}
.accent-custom-swatch {
width: 20px;
height: 20px;
border-radius: 4px;
flex-shrink: 0;
}
.accent-custom-label {
font-size: 0.75rem;
color: var(--text-muted);
transition: color 0.15s;
}
.accent-custom-row input[type="color"] {
width: 0;
height: 0;
padding: 0;
border: none;
opacity: 0;
position: absolute;
pointer-events: none;
}
/* Tab Bar */
.tab-bar {
display: flex;
gap: 0.25rem;
margin-bottom: 1.5rem;
padding: 0.25rem;
background: var(--bg-secondary);
border-radius: 10px;
border: 1px solid var(--border);
position: relative;
}
.tab-indicator {
position: absolute;
top: 0.25rem;
bottom: 0.25rem;
left: 0;
background: var(--bg-tertiary);
border-radius: 8px;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
transition: transform 0.3s cubic-bezier(0.4, 0, 0.2, 1), width 0.3s cubic-bezier(0.4, 0, 0.2, 1);
z-index: 0;
pointer-events: none;
}
.tab-btn {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
gap: 0.4rem;
padding: 0.6rem 0.5rem;
background: transparent;
border: none;
border-radius: 8px;
color: var(--text-muted);
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
transition: color 0.2s;
width: auto;
height: auto;
position: relative;
z-index: 1;
}
.tab-btn:hover {
color: var(--text-primary);
transform: none !important;
}
.tab-btn.active {
color: var(--accent);
background: transparent;
}
.tab-btn svg {
width: 16px;
height: 16px;
flex-shrink: 0;
}
[data-tab-content] {
display: none;
opacity: 0;
}
[data-tab-content].active {
display: block;
animation: tabFadeIn 0.25s ease-out forwards;
}
@keyframes tabFadeIn {
from { opacity: 0; transform: translateY(6px); }
to { opacity: 1; transform: translateY(0); }
}
@media (max-width: 600px) {
.tab-btn span {
display: none;
}
.tab-btn {
padding: 0.6rem;
}
}
.player-container {
background: var(--bg-secondary);
border-radius: 12px;
padding: 1rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.player-layout {
display: flex;
flex-direction: column;
perspective: 800px;
}
.player-details {
flex: 1;
min-width: 0;
}
.album-art-container {
display: flex;
justify-content: center;
margin-bottom: 2rem;
position: relative;
transform-style: preserve-3d;
animation: albumArt3D 8s ease-in-out infinite;
}
@keyframes albumArt3D {
0%, 100% { transform: rotateY(-8deg) rotateX(2deg); }
50% { transform: rotateY(8deg) rotateX(-2deg); }
}
.album-art-glow {
position: absolute;
width: 300px;
height: 300px;
object-fit: cover;
border-radius: 8px;
filter: blur(40px) saturate(1.5);
opacity: 0.5;
top: 50%;
left: 50%;
transform: translate(-50%, -50%) scale(1.1);
z-index: 0;
pointer-events: none;
transition: opacity 0.5s ease, border-radius 0.6s ease;
}
#album-art {
width: 300px;
height: 300px;
object-fit: cover;
border-radius: 8px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
background: var(--bg-tertiary);
position: relative;
z-index: 1;
margin: 0;
transition: border-radius 0.6s ease, width 0.6s ease, height 0.6s ease, box-shadow 0.6s ease, margin 0.6s ease, filter 0.6s ease;
}
:root[data-theme="light"] .album-art-glow {
opacity: 0.35;
filter: blur(50px) saturate(1.8);
}
/* Vinyl Record Mode */
.album-art-container.vinyl #album-art {
border-radius: 50%;
width: 210px;
height: 210px;
margin: 45px;
filter: saturate(0.55) sepia(0.12) brightness(0.92) contrast(1.08);
box-shadow:
0 0 0 3px var(--vinyl-groove),
0 0 0 5px var(--vinyl-ring),
0 0 0 6px var(--vinyl-highlight),
0 0 0 12px var(--vinyl-ring),
0 0 0 13px var(--vinyl-highlight-dim),
0 0 0 20px var(--vinyl-ring),
0 0 0 21px var(--vinyl-highlight),
0 0 0 28px var(--vinyl-ring),
0 0 0 29px var(--vinyl-highlight-dim),
0 0 0 36px var(--vinyl-ring),
0 0 0 37px var(--vinyl-highlight),
0 0 0 42px var(--vinyl-ring),
0 0 0 43px var(--vinyl-groove),
0 0 0 45px var(--vinyl-edge),
0 4px 15px 45px var(--shadow-elevation);
}
/* Vinyl label vignette overlay */
.album-art-container.vinyl::before {
content: '';
position: absolute;
width: 210px;
height: 210px;
border-radius: 50%;
background: radial-gradient(
circle,
transparent 50%,
rgba(0,0,0,0.25) 100%
);
z-index: 2;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
opacity: 0;
transition: opacity 0.6s ease;
}
.album-art-container.vinyl.spinning::before,
.album-art-container.vinyl.paused::before {
opacity: 1;
}
.album-art-container.vinyl .album-art-glow {
border-radius: 50%;
}
/* Center spindle hole */
.album-art-container::after {
content: '';
position: absolute;
width: 14px;
height: 14px;
border-radius: 50%;
background: var(--vinyl-spindle);
border: 2px solid var(--border);
box-shadow: inset 0 1px 3px rgba(0,0,0,0.5);
z-index: 3;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
pointer-events: none;
opacity: 0;
transition: opacity 0.4s ease 0.3s;
}
.album-art-container.vinyl::after {
opacity: 1;
}
.album-art-container.vinyl.spinning #album-art {
animation: vinylSpin 12s linear infinite;
}
.album-art-container.vinyl.paused #album-art {
animation: vinylSpin 12s linear infinite;
animation-play-state: paused;
}
@keyframes vinylSpin {
from { transform: rotate(var(--vinyl-offset, 0deg)) scale(var(--vinyl-scale, 1)); }
to { transform: rotate(calc(var(--vinyl-offset, 0deg) + 360deg)) scale(var(--vinyl-scale, 1)); }
}
/* Audio Spectrogram Visualization */
.spectrogram-canvas {
position: absolute;
bottom: -4px;
left: 50%;
transform: translateX(-50%);
z-index: 2;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
border-radius: 0 0 8px 8px;
}
.visualizer-active .spectrogram-canvas {
opacity: 1;
}
.visualizer-active #album-art {
transition: transform 0.08s ease-out;
}
.visualizer-active .album-art-glow {
transition: opacity 0.08s ease-out;
}
/* Adapt spectrogram for vinyl mode */
.album-art-container.vinyl .spectrogram-canvas {
bottom: -10px;
border-radius: 0 0 50% 50%;
}
.track-info {
text-align: center;
margin-bottom: 2rem;
}
#track-title {
font-size: 1.75rem;
font-weight: 600;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
#artist {
font-size: 1.125rem;
color: var(--text-secondary);
margin-bottom: 0.25rem;
}
#album {
font-size: 0.875rem;
color: var(--text-muted);
}
.playback-state {
display: flex;
justify-content: center;
align-items: center;
gap: 0.5rem;
font-size: 0.875rem;
color: var(--text-secondary);
margin-top: 0.5rem;
}
.state-icon {
width: 16px;
height: 16px;
}
.progress-container {
margin-bottom: 2rem;
}
.time-display {
display: flex;
justify-content: space-between;
font-size: 0.75rem;
color: var(--text-secondary);
margin-bottom: 0.5rem;
}
.progress-bar {
width: 100%;
height: 6px;
background: var(--bg-tertiary);
border-radius: 3px;
cursor: pointer;
position: relative;
transition: transform 0.15s ease;
}
.progress-bar:hover {
transform: scaleY(1.4);
}
.progress-fill {
height: 100%;
background: var(--accent);
border-radius: 3px;
width: 0;
transition: width 0.1s linear;
position: relative;
}
.progress-fill::after {
content: '';
position: absolute;
right: -6px;
top: 50%;
transform: translateY(-50%) scale(0);
width: 12px;
height: 12px;
background: var(--accent);
border-radius: 50%;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
transition: transform 0.15s ease;
}
.progress-bar:hover .progress-fill::after,
.progress-bar.dragging .progress-fill::after {
transform: translateY(-50%) scale(1);
}
.progress-bar.dragging {
transform: scaleY(1.4);
}
.progress-bar.dragging .progress-fill {
transition: none;
}
.controls {
display: flex;
gap: 1rem;
justify-content: center;
align-items: center;
margin-bottom: 2rem;
}
button {
border: none;
background: none;
color: inherit;
font: inherit;
cursor: pointer;
padding: 0;
}
button:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.controls button {
background: var(--bg-tertiary);
color: var(--text-primary);
border-radius: 50%;
width: 48px;
height: 48px;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.controls button:hover:not(:disabled) {
background: var(--accent);
color: #fff;
transform: scale(1.05);
}
.controls button:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 3px;
box-shadow: 0 0 0 4px rgba(29, 185, 84, 0.25);
}
.mute-btn:focus-visible,
.mini-control-btn:focus-visible,
.vinyl-toggle-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
box-shadow: 0 0 0 4px rgba(29, 185, 84, 0.25);
}
.controls button.primary {
width: 56px;
height: 56px;
background: var(--accent);
}
.controls button.primary:hover:not(:disabled) {
background: var(--accent-hover);
color: #fff;
transform: scale(1.1);
}
.volume-container {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background: var(--bg-tertiary);
border-radius: 8px;
margin-bottom: 1rem;
}
#volume-slider {
flex: 1;
height: 6px;
-webkit-appearance: none;
appearance: none;
background: color-mix(in srgb, var(--accent) 15%, var(--border));
border-radius: 3px;
outline: none;
}
#volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 16px;
height: 16px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
#volume-slider:hover::-webkit-slider-thumb {
transform: scale(1.3);
box-shadow: 0 0 6px rgba(29, 185, 84, 0.4);
}
#volume-slider::-moz-range-thumb {
width: 16px;
height: 16px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
border: none;
transition: transform 0.15s ease, box-shadow 0.15s ease;
}
#volume-slider:hover::-moz-range-thumb {
transform: scale(1.3);
box-shadow: 0 0 6px rgba(29, 185, 84, 0.4);
}
.volume-display {
font-size: 0.875rem;
color: var(--text-secondary);
min-width: 40px;
text-align: right;
}
.mute-btn {
width: 40px;
height: 40px;
background: var(--bg-tertiary);
border-radius: 50%;
color: var(--text-primary);
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.mute-btn:hover:not(:disabled) {
background: var(--accent);
color: #fff;
transform: scale(1.05);
}
.source-info {
text-align: center;
font-size: 0.75rem;
color: var(--text-muted);
padding-top: 1rem;
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: center;
gap: 0.75rem;
min-width: 0;
}
.source-label {
display: inline-flex;
align-items: center;
gap: 0.35rem;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 200px;
}
.source-icon {
display: inline-flex;
align-items: center;
}
.source-icon svg {
width: 14px;
height: 14px;
}
.player-toggles {
display: flex;
align-items: center;
gap: 0.375rem;
margin-left: auto;
}
.vinyl-toggle-btn {
width: 28px;
height: 28px;
padding: 0;
background: transparent;
border: 1px solid var(--border);
border-radius: 50%;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
}
.vinyl-toggle-btn:hover {
color: var(--accent);
border-color: var(--accent);
background: transparent;
transform: none;
}
.vinyl-toggle-btn.active {
color: var(--accent);
border-color: var(--accent);
background: rgba(29, 185, 84, 0.1);
}
.vinyl-toggle-btn svg {
width: 16px;
height: 16px;
}
/* Scripts Section */
.scripts-container {
background: var(--bg-secondary);
border-radius: 12px;
padding: 1rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.scripts-container h2 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--text-primary);
}
.scripts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(min(180px, 100%), 1fr));
gap: 1rem;
}
.script-btn {
width: 100%;
height: auto;
min-height: 80px;
padding: 1rem;
border-radius: 8px;
background: var(--bg-tertiary);
border: 1px solid var(--border);
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: 0.5rem;
}
.script-btn:hover:not(:disabled) {
background: var(--accent);
border-color: var(--accent);
color: #fff;
transform: translateY(-2px);
}
.script-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.script-btn .script-label {
font-weight: 600;
font-size: 0.875rem;
text-align: center;
overflow-wrap: break-word;
word-break: break-word;
max-width: 100%;
}
.script-btn .script-description {
font-size: 0.75rem;
color: var(--text-secondary);
text-align: center;
transition: color 0.2s;
}
.script-btn:hover:not(:disabled) .script-description {
color: rgba(255, 255, 255, 0.85);
}
.script-btn.executing {
opacity: 0.6;
pointer-events: none;
}
.script-btn .script-icon {
color: var(--accent);
line-height: 0;
}
.script-btn .script-icon svg {
width: 24px;
height: 24px;
}
.script-btn:hover:not(:disabled) .script-icon {
color: #fff;
}
/* Inline icon in table name cells */
.name-with-icon {
display: inline-flex;
align-items: center;
gap: 0.375rem;
}
.table-icon {
display: inline-flex;
color: var(--text-secondary);
line-height: 0;
}
.table-icon svg {
width: 16px;
height: 16px;
}
/* Script Management Styles */
.script-management {
background: var(--bg-secondary);
border-radius: 12px;
padding: 2rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
overflow-x: auto;
}
.script-management h2 {
font-size: 1.25rem;
margin-bottom: 1rem;
color: var(--text-primary);
}
/* Settings Container */
.settings-container.active {
display: flex;
flex-direction: column;
gap: 1rem;
}
.settings-section {
background: var(--bg-secondary);
border-radius: 12px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
.settings-section summary {
padding: 1rem;
font-size: 1rem;
font-weight: 600;
color: var(--text-primary);
cursor: pointer;
user-select: none;
display: flex;
align-items: center;
gap: 0.5rem;
transition: background 0.2s;
list-style: none;
}
.settings-section summary::-webkit-details-marker {
display: none;
}
.settings-section summary::before {
content: '';
display: inline-block;
width: 0.5rem;
height: 0.5rem;
border-right: 2px solid var(--text-muted);
border-bottom: 2px solid var(--text-muted);
transform: rotate(-45deg);
transition: transform 0.3s ease;
flex-shrink: 0;
}
.settings-section[open] > summary::before {
transform: rotate(45deg);
}
.settings-section summary:hover {
background: var(--bg-tertiary);
}
.settings-section-content {
padding: 0 1rem 1rem;
overflow-x: auto;
animation: settingsExpand 0.3s ease-out;
}
@keyframes settingsExpand {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
.settings-section-description {
color: var(--text-secondary);
font-size: 0.875rem;
margin-bottom: 1rem;
}
.audio-device-selector {
display: flex;
flex-direction: column;
gap: 0.75rem;
}
.audio-device-selector label {
display: flex;
flex-direction: column;
gap: 0.375rem;
}
.audio-device-selector label span {
font-size: 0.8125rem;
font-weight: 500;
color: var(--text-secondary);
}
.audio-device-selector select {
width: 100%;
padding: 10px;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-tertiary);
color: var(--text-primary);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
font-size: 1rem;
cursor: pointer;
transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
.audio-device-selector select:focus {
outline: none;
border-color: var(--accent);
box-shadow: 0 0 0 3px rgba(29, 185, 84, 0.15);
}
.audio-device-status {
font-size: 0.75rem;
display: flex;
align-items: center;
gap: 0.375rem;
}
.audio-device-status::before {
content: '';
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
}
.audio-device-status.active {
color: var(--accent);
}
.audio-device-status.active::before {
background: var(--accent);
}
.audio-device-status.available {
color: var(--text-secondary);
}
.audio-device-status.available::before {
background: var(--text-muted);
}
.audio-device-status.unavailable {
color: var(--text-muted);
}
.audio-device-status.unavailable::before {
background: var(--text-muted);
opacity: 0.5;
}
/* Link card in Quick Access */
.link-card {
text-decoration: none;
color: var(--text-primary);
border: 1px dashed var(--border);
}
.link-card:hover {
border-style: solid;
}
/* Mini player nav buttons */
.mini-nav-btn {
width: 28px;
height: 28px;
}
.mini-nav-btn svg {
width: 16px;
height: 16px;
}
/* Display Control Section */
.display-container {
background: var(--bg-secondary);
border-radius: 12px;
padding: 1rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.display-monitors {
display: flex;
flex-direction: column;
gap: 1rem;
}
.display-monitor-card {
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem 1.25rem;
}
.display-monitor-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.75rem;
}
.display-monitor-icon {
color: var(--text-muted);
flex-shrink: 0;
}
.display-monitor-info {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 0.125rem;
}
.display-monitor-name {
font-weight: 500;
color: var(--text-primary);
font-size: 0.875rem;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.display-primary-badge {
display: inline-block;
background: var(--accent);
color: #fff;
font-size: 0.625rem;
font-weight: 600;
padding: 1px 6px;
border-radius: 8px;
margin-left: 6px;
vertical-align: middle;
text-transform: uppercase;
letter-spacing: 0.03em;
}
.display-monitor-details {
font-size: 0.75rem;
color: var(--text-muted);
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.display-power-btn {
width: 30px;
height: 30px;
border-radius: 6px;
border: 1px solid var(--border);
background: transparent;
color: var(--text-muted);
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
transition: all 0.2s;
}
.display-power-btn.on {
color: var(--accent);
border-color: var(--accent);
}
.display-power-btn.on:hover {
color: var(--error);
border-color: var(--error);
}
.display-power-btn.off {
color: var(--error);
border-color: var(--error);
opacity: 0.6;
}
.display-power-btn.off:hover {
color: var(--accent);
border-color: var(--accent);
opacity: 1;
}
.display-brightness-control {
display: flex;
align-items: center;
gap: 0.75rem;
}
.display-brightness-icon {
color: var(--text-muted);
flex-shrink: 0;
}
.display-brightness-slider {
flex: 1;
-webkit-appearance: none;
appearance: none;
height: 6px;
border-radius: 3px;
background: color-mix(in srgb, var(--accent) 15%, var(--border));
outline: none;
cursor: pointer;
}
.display-brightness-slider::-webkit-slider-thumb {
-webkit-appearance: none;
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent);
cursor: pointer;
transition: transform 0.15s;
}
.display-brightness-slider::-moz-range-thumb {
width: 16px;
height: 16px;
border-radius: 50%;
background: var(--accent);
cursor: pointer;
border: none;
}
.display-brightness-slider:hover::-webkit-slider-thumb {
transform: scale(1.2);
}
.display-brightness-slider:hover::-moz-range-thumb {
transform: scale(1.2);
}
.display-brightness-slider:disabled {
opacity: 0.4;
cursor: not-allowed;
}
.display-brightness-value {
font-size: 0.813rem;
color: var(--text-secondary);
min-width: 36px;
text-align: right;
font-variant-numeric: tabular-nums;
}
.add-card {
display: flex;
align-items: center;
justify-content: center;
border: 2px dashed var(--border);
border-radius: 8px;
padding: 1.5rem;
margin-top: 1rem;
cursor: pointer;
transition: border-color 0.2s, background 0.2s;
}
.add-card:hover {
border-color: var(--text-muted);
background: var(--bg-tertiary);
}
.add-card-icon {
font-size: 1.5rem;
color: var(--text-muted);
font-weight: 300;
line-height: 1;
}
.add-card-grid {
border: 2px dashed var(--border);
background: transparent;
}
.add-card-grid:hover:not(:disabled) {
border-color: var(--text-muted);
background: var(--bg-tertiary);
}
.scripts-table {
width: 100%;
min-width: 500px;
border-collapse: collapse;
font-size: 0.875rem;
}
.scripts-table th {
text-align: left;
padding: 0.75rem;
border-bottom: 2px solid var(--border);
color: var(--text-secondary);
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
}
.scripts-table td {
padding: 0.75rem;
word-break: break-word;
border-bottom: 1px solid var(--border);
}
.scripts-table tr:hover {
background: var(--bg-tertiary);
}
.scripts-table code {
background: var(--bg-tertiary);
padding: 0.25rem 0.5rem;
border-radius: 4px;
font-size: 0.75rem;
color: var(--accent);
white-space: nowrap;
}
.action-btn {
padding: 0.5rem;
border-radius: 6px;
border: 1px solid var(--border);
background: var(--bg-tertiary);
color: var(--text-primary);
cursor: pointer;
transition: all 0.2s;
width: 32px;
height: 32px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.action-btn svg {
width: 16px;
height: 16px;
fill: currentColor;
}
.action-btn:hover {
background: var(--accent);
border-color: var(--accent);
color: #fff;
transform: translateY(-1px);
}
.action-btn.delete:hover {
background: var(--error);
border-color: var(--error);
color: #fff;
}
.action-buttons {
display: flex;
gap: 0.5rem;
align-items: center;
}
.action-btn.execute:hover {
background: #3b82f6;
border-color: #3b82f6;
color: #fff;
}
/* Execution Result Dialog */
.execution-result {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background: var(--bg-primary);
border-radius: 6px;
padding: 1rem;
margin: 0.5rem 0;
max-height: 400px;
overflow-y: auto;
}
.execution-result pre {
margin: 0;
white-space: pre-wrap;
word-wrap: break-word;
font-size: 0.813rem;
line-height: 1.5;
}
.execution-status {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
flex-wrap: wrap;
}
.status-item {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.status-item label {
font-size: 0.75rem;
color: var(--text-muted);
text-transform: uppercase;
font-weight: 600;
}
.status-item value {
font-size: 0.875rem;
color: var(--text-primary);
font-weight: 500;
}
.status-item.success value {
color: var(--accent);
}
.status-item.error value {
color: var(--error);
}
.result-section {
margin-bottom: 1rem;
}
.result-section h4 {
font-size: 0.875rem;
color: var(--text-secondary);
margin-bottom: 0.5rem;
font-weight: 600;
}
.loading-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 3px solid var(--bg-tertiary);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 0.8s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
/* Dialog Styles */
dialog {
background: var(--bg-secondary);
color: var(--text-primary);
border: 1px solid var(--border);
border-radius: 12px;
padding: 0;
max-width: 500px;
width: 90%;
margin: auto;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.8);
animation: dialogIn 0.25s ease-out;
overflow: visible;
}
dialog form {
overflow: visible;
}
dialog.dialog-closing {
animation: dialogOut 0.2s ease-in forwards;
}
/* Ensure dialogs are hidden until explicitly opened */
dialog:not([open]) {
display: none;
}
dialog::backdrop {
background: rgba(0, 0, 0, 0.8);
animation: backdropIn 0.25s ease-out;
}
dialog.dialog-closing::backdrop {
animation: backdropOut 0.2s ease-in forwards;
}
@keyframes dialogIn {
from { opacity: 0; transform: scale(0.9) translateY(10px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
@keyframes dialogOut {
from { opacity: 1; transform: scale(1) translateY(0); }
to { opacity: 0; transform: scale(0.9) translateY(10px); }
}
@keyframes backdropIn {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes backdropOut {
from { opacity: 1; }
to { opacity: 0; }
}
.confirm-dialog {
max-width: 400px;
padding: 1.5rem;
}
.confirm-dialog p {
margin-bottom: 1.25rem;
font-size: 0.95rem;
line-height: 1.5;
color: var(--text-primary);
}
.confirm-dialog-actions {
display: flex;
justify-content: flex-end;
gap: 8px;
}
.confirm-dialog-actions button {
padding: 8px 20px;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 500;
transition: all 0.2s;
}
.btn-cancel {
background: var(--bg-tertiary);
color: var(--text-primary);
}
.btn-cancel:hover {
background: var(--border);
}
.btn-danger {
background: var(--error);
color: #fff;
}
.btn-danger:hover {
filter: brightness(1.15);
}
.dialog-header {
padding: 1.5rem;
background: var(--bg-secondary);
border-bottom: 1px solid var(--border);
}
.dialog-header h3 {
margin: 0;
font-size: 1.25rem;
}
.dialog-body {
padding: 1.5rem;
}
.dialog-body label {
display: block;
margin-bottom: 1rem;
color: var(--text-secondary);
font-size: 0.875rem;
}
.dialog-body input,
.dialog-body textarea,
.dialog-body select {
display: block;
width: 100%;
padding: 0.5rem;
margin-top: 0.25rem;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: inherit;
font-size: 0.875rem;
}
.dialog-body textarea {
min-height: 80px;
resize: vertical;
}
.dialog-body input:focus,
.dialog-body textarea:focus,
.dialog-body select:focus {
outline: none;
border-color: var(--accent);
}
.dialog-footer {
padding: 1.5rem;
border-top: 1px solid var(--border);
display: flex;
justify-content: flex-end;
gap: 0.5rem;
}
.dialog-footer button {
padding: 0.625rem 1.5rem;
border-radius: 6px;
border: none;
font-size: 0.875rem;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
min-width: 100px;
white-space: nowrap;
}
.dialog-footer .btn-primary {
background: var(--accent);
color: var(--text-primary);
}
.dialog-footer .btn-primary:hover {
background: var(--accent-hover);
}
.dialog-footer .btn-secondary {
background: var(--bg-tertiary);
color: var(--text-primary);
border: 1px solid var(--border);
}
.dialog-footer .btn-secondary:hover {
background: var(--border);
}
/* Parameters editor (CRUD dialog) */
.params-section {
margin-top: 0.5rem;
}
.params-header {
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 0.5rem;
color: var(--text-secondary);
font-size: 0.875rem;
}
.btn-small {
padding: 0.25rem 0.75rem;
font-size: 0.75rem;
border: 1px solid var(--border);
border-radius: 4px;
background: var(--bg-tertiary);
color: var(--text-primary);
cursor: pointer;
transition: background 0.2s;
}
.btn-small:hover {
background: var(--border);
}
.param-row {
border: 1px solid var(--border);
border-radius: 6px;
padding: 0.5rem;
margin-bottom: 0.5rem;
background: var(--bg-tertiary);
}
.param-row-header {
display: flex;
gap: 0.375rem;
align-items: center;
}
.param-row-header .param-name {
flex: 1;
min-width: 0;
}
.param-row-header .param-type {
width: 100px;
flex-shrink: 0;
}
.param-required-label {
display: flex !important;
align-items: center;
gap: 0.125rem;
margin-bottom: 0 !important;
cursor: pointer;
color: var(--accent);
font-weight: 700;
font-size: 1rem;
flex-shrink: 0;
}
.param-required-label input {
width: auto !important;
margin: 0 !important;
}
.param-remove-btn {
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
font-size: 1.25rem;
line-height: 1;
padding: 0 0.25rem;
flex-shrink: 0;
transition: color 0.2s;
}
.param-remove-btn:hover {
color: var(--error);
}
.param-row-details {
margin-top: 0.375rem;
}
.param-row-details .param-description {
width: 100%;
margin-bottom: 0.25rem;
font-size: 0.8rem;
color: var(--text-muted);
}
.param-row-extra {
display: flex;
gap: 0.375rem;
}
.param-row-extra input {
flex: 1;
min-width: 0;
}
.param-row-header input,
.param-row-header select,
.param-row-details input,
.param-row-extra input {
padding: 0.35rem 0.5rem;
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-primary);
font-family: inherit;
font-size: 0.8rem;
}
.param-row-header input:focus,
.param-row-header select:focus,
.param-row-details input:focus,
.param-row-extra input:focus {
outline: none;
border-color: var(--accent);
}
/* Parameter hint in execution dialog */
.param-hint {
display: block;
color: var(--text-muted);
font-size: 0.75rem;
margin-top: 0.125rem;
}
/* ── Icon Select ──────────────────────────────────────────── */
.icon-select-trigger {
display: flex;
align-items: center;
gap: 0.375rem;
width: 100%;
padding: 0.35rem 0.5rem;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-tertiary);
color: var(--text-primary);
font-size: 0.875rem;
cursor: pointer;
transition: border-color 0.15s;
text-align: left;
font-family: inherit;
box-sizing: border-box;
}
/* Match dialog input height when inside a dialog */
.dialog-body .icon-select-trigger {
padding: 0.5rem;
margin-top: 0.25rem;
}
/* Compact trigger inside param rows */
.param-row-header .icon-select-trigger {
padding: 0.3rem 0.4rem;
margin-top: 0;
font-size: 0.75rem;
width: 110px;
flex-shrink: 0;
}
.icon-select-trigger:hover {
border-color: var(--accent);
}
.icon-select-trigger-icon {
display: flex;
align-items: center;
flex-shrink: 0;
}
.icon-select-trigger-icon svg {
width: 16px;
height: 16px;
fill: currentColor;
}
.param-row-header .icon-select-trigger-icon svg {
width: 14px;
height: 14px;
}
.icon-select-trigger-label {
flex: 1;
min-width: 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.icon-select-trigger-arrow {
flex-shrink: 0;
font-size: 0.8rem;
opacity: 0.5;
margin-left: auto;
}
.icon-select-popup {
position: absolute;
z-index: 100;
max-height: 260px;
overflow: hidden;
opacity: 0;
transform: translateY(-4px) scale(0.97);
transition: opacity 0.12s ease-out, transform 0.12s cubic-bezier(0.16, 1, 0.3, 1);
pointer-events: none;
box-sizing: border-box;
}
.icon-select-popup.open {
opacity: 1;
transform: translateY(0) scale(1);
overflow-y: auto;
pointer-events: auto;
}
.icon-select-grid {
display: grid;
grid-auto-rows: 1fr;
gap: 6px;
padding: 6px;
border: 1px solid var(--border);
border-radius: 6px;
background: var(--bg-secondary);
}
.icon-select-cell {
display: flex;
flex-direction: column;
align-items: center;
gap: 3px;
padding: 6px 4px;
border: 2px solid transparent;
border-radius: 6px;
background: var(--bg-tertiary);
cursor: pointer;
transition: border-color 0.15s, background 0.15s, transform 0.1s;
text-align: center;
}
.icon-select-cell:hover {
border-color: var(--accent);
transform: scale(1.03);
}
.icon-select-cell.active {
border-color: var(--accent);
background: color-mix(in srgb, var(--accent) 12%, var(--bg-tertiary));
}
.icon-select-cell-icon {
display: flex;
align-items: center;
justify-content: center;
}
.icon-select-cell-icon svg {
width: 20px;
height: 20px;
fill: currentColor;
}
.icon-select-cell.active .icon-select-cell-icon svg {
fill: var(--accent);
}
.icon-select-cell-label {
font-size: 0.75rem;
font-weight: 600;
line-height: 1.2;
}
.icon-select-cell-desc {
font-size: 0.7rem;
opacity: 0.6;
line-height: 1.3;
}
/* Horizontal layout for single-column grids (e.g. audio device list) */
.icon-select-grid--horizontal .icon-select-cell {
flex-direction: row;
gap: 0.5rem;
padding: 0.4rem 0.75rem;
text-align: left;
}
.icon-select-grid--horizontal .icon-select-cell-icon svg {
width: 16px;
height: 16px;
}
.icon-select-grid--horizontal .icon-select-cell-label {
font-size: 0.8rem;
}
@media (max-width: 480px) {
.icon-select-cell-desc { display: none; }
.icon-select-cell { padding: 6px 4px; }
.icon-select-grid { gap: 4px; padding: 4px; }
}
.empty-state {
text-align: center;
padding: 2rem;
color: var(--text-muted);
}
.scripts-empty {
text-align: center;
color: var(--text-muted);
padding: 2rem;
font-size: 0.875rem;
}
.empty-state-illustration {
display: flex;
flex-direction: column;
align-items: center;
gap: 1rem;
padding: 3rem 2rem;
}
.empty-state-illustration svg {
width: 64px;
height: 64px;
fill: none;
stroke: var(--text-muted);
stroke-width: 1.5;
stroke-linecap: round;
stroke-linejoin: round;
opacity: 0.5;
}
.empty-state-illustration p {
color: var(--text-muted);
font-size: 0.875rem;
margin: 0;
}
.toast-container {
position: fixed;
bottom: 2rem;
right: 2rem;
display: flex;
flex-direction: column-reverse;
gap: 8px;
z-index: 1000;
pointer-events: none;
}
.toast {
background: var(--bg-secondary);
border: 1px solid var(--border);
border-radius: 8px;
padding: 1rem 1.5rem;
padding-left: 1.25rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
opacity: 0;
transform: translateY(20px);
transition: all 0.3s;
pointer-events: auto;
border-left: 4px solid var(--border);
}
.toast.show {
opacity: 1;
transform: translateY(0);
}
.toast.success {
border-color: var(--accent);
border-left-color: var(--accent);
}
.toast.error {
border-color: var(--error);
border-left-color: var(--error);
}
/* Auth Modal */
#auth-overlay {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.9);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
#auth-overlay.hidden {
display: none;
}
.auth-modal {
background: var(--bg-secondary);
padding: 2rem;
border-radius: 12px;
max-width: 400px;
width: 90%;
}
.auth-modal h2 {
margin-bottom: 1rem;
font-size: 1.5rem;
}
.auth-modal p {
margin-bottom: 1rem;
color: var(--text-secondary);
font-size: 0.875rem;
}
#token-input {
width: 100%;
padding: 0.75rem;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-size: 0.875rem;
margin-bottom: 1rem;
}
#token-input:focus {
outline: none;
border-color: var(--accent);
}
.btn-connect {
width: 100%;
height: auto;
padding: 0.75rem;
border-radius: 6px;
background: var(--accent);
color: var(--text-primary);
font-weight: 600;
transition: background 0.2s;
}
.btn-connect:hover {
background: var(--accent-hover);
transform: none;
}
.help-text {
background: var(--bg-tertiary);
padding: 0.75rem;
border-radius: 6px;
margin-top: 1rem;
}
.help-text code {
background: var(--bg-primary);
padding: 0.25rem 0.5rem;
border-radius: 3px;
font-family: monospace;
font-size: 0.875rem;
}
.error-message {
color: var(--error);
font-size: 0.875rem;
margin-top: 0.5rem;
display: none;
}
.error-message.visible {
display: block;
}
/* Mini Player (Sticky) */
.mini-player {
position: fixed;
bottom: 0;
left: 0;
right: 0;
background: rgba(30, 30, 30, 0.8);
-webkit-backdrop-filter: blur(20px) saturate(1.5);
backdrop-filter: blur(20px) saturate(1.5);
border-top: 1px solid rgba(255, 255, 255, 0.08);
padding: 0.75rem 1rem;
padding-top: calc(0.75rem + 2px);
display: flex;
align-items: center;
gap: 1.5rem;
z-index: 1000;
transform: translateY(0);
transition: transform 0.3s ease-in-out, opacity 0.3s ease-in-out;
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.3);
}
:root[data-theme="light"] .mini-player {
background: rgba(245, 245, 245, 0.75);
border-top: 1px solid rgba(0, 0, 0, 0.08);
box-shadow: 0 -4px 16px rgba(0, 0, 0, 0.1);
}
.mini-player::before {
content: '';
position: absolute;
top: 0;
left: 0;
height: 2px;
width: var(--mini-progress, 0%);
background: var(--accent);
transition: width 0.1s linear;
}
.mini-player.hidden {
transform: translateY(100%);
opacity: 0;
pointer-events: none;
}
.mini-player-info {
display: flex;
align-items: center;
gap: 0.75rem;
min-width: 200px;
flex-shrink: 0;
}
.mini-album-art {
width: 40px;
height: 40px;
border-radius: 4px;
object-fit: cover;
flex-shrink: 0;
}
.mini-track-details {
display: flex;
flex-direction: column;
min-width: 0;
}
.mini-track-title {
font-size: 0.875rem;
font-weight: 600;
color: var(--text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mini-artist {
font-size: 0.75rem;
color: var(--text-secondary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.mini-progress-container {
flex: 1;
display: flex;
align-items: center;
gap: 1rem;
min-width: 0;
}
.mini-time-display {
display: flex;
gap: 0.5rem;
font-size: 0.75rem;
color: var(--text-secondary);
flex-shrink: 0;
}
.mini-progress-bar {
flex: 1;
height: 4px;
background: var(--bg-tertiary);
border-radius: 2px;
cursor: pointer;
position: relative;
min-width: 100px;
}
.mini-progress-bar:hover {
height: 6px;
}
.mini-progress-fill {
height: 100%;
background: var(--accent);
border-radius: 2px;
width: 0%;
transition: width 0.1s linear;
position: relative;
}
.mini-progress-fill::after {
content: '';
position: absolute;
right: -5px;
top: 50%;
transform: translateY(-50%) scale(0);
width: 10px;
height: 10px;
background: var(--accent);
border-radius: 50%;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
transition: transform 0.15s ease;
}
.mini-progress-bar:hover .mini-progress-fill::after {
transform: translateY(-50%) scale(1);
}
.mini-controls {
display: flex;
align-items: center;
gap: 0.5rem;
flex-shrink: 0;
}
.mini-control-btn {
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 50%;
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 0.2s;
padding: 0;
}
.mini-control-btn:hover {
background: var(--accent);
border-color: var(--accent);
color: #fff;
transform: scale(1.05);
}
.mini-control-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.mini-control-btn svg {
width: 20px;
height: 20px;
fill: currentColor;
}
.mini-volume-container {
display: flex;
align-items: center;
gap: 0.75rem;
flex-shrink: 0;
min-width: 180px;
}
.mini-volume-slider {
flex: 1;
height: 4px;
-webkit-appearance: none;
appearance: none;
background: color-mix(in srgb, var(--accent) 15%, var(--border));
border-radius: 2px;
outline: none;
cursor: pointer;
min-width: 80px;
}
.mini-volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 12px;
height: 12px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
}
.mini-volume-slider::-moz-range-thumb {
width: 12px;
height: 12px;
background: var(--accent);
border-radius: 50%;
cursor: pointer;
border: none;
}
.mini-volume-slider:hover::-webkit-slider-thumb {
transform: scale(1.2);
}
.mini-volume-slider:hover::-moz-range-thumb {
transform: scale(1.2);
}
.mini-volume-display {
font-size: 0.75rem;
color: var(--text-secondary);
min-width: 36px;
text-align: right;
}
/* SVG Icons */
svg {
width: 24px;
height: 24px;
fill: currentColor;
}
button.primary svg {
width: 28px;
height: 28px;
}
@media (max-width: 600px) {
.container {
padding: 0.5rem;
}
#album-art {
width: 250px;
height: 250px;
}
.album-art-container.vinyl #album-art {
width: 170px;
height: 170px;
margin: 40px;
box-shadow:
0 0 0 3px #2a2a2a,
0 0 0 5px #1a1a1a,
0 0 0 6px rgba(255,255,255,0.05),
0 0 0 12px #1a1a1a,
0 0 0 13px rgba(255,255,255,0.03),
0 0 0 20px #1a1a1a,
0 0 0 21px rgba(255,255,255,0.05),
0 0 0 28px #1a1a1a,
0 0 0 29px rgba(255,255,255,0.03),
0 0 0 36px #1a1a1a,
0 0 0 37px rgba(255,255,255,0.04),
0 0 0 38px #2a2a2a,
0 0 0 40px #111,
0 4px 12px 40px rgba(0,0,0,0.4);
}
#track-title {
font-size: 1.5rem;
}
}
/* Footer */
footer {
text-align: center;
padding: 0.75rem 1rem;
margin-top: 0.5rem;
color: var(--text-muted);
font-size: 0.75rem;
transition: padding-bottom 0.3s ease-in-out;
}
body.mini-player-visible footer {
padding-bottom: 70px;
}
footer a {
color: var(--accent);
text-decoration: none;
transition: color 0.2s;
}
footer a:hover {
color: var(--accent-hover);
text-decoration: underline;
}
footer .separator {
margin: 0 0.5rem;
color: var(--text-muted);
}
/* ========================================
Media Browser Styles
======================================== */
.browser-container {
background: var(--bg-secondary);
border-radius: 12px;
padding: 1.25rem;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.5);
}
.browser-header-section {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1.5rem;
}
.browser-header-section h2 {
font-size: 1.25rem;
color: var(--text-primary);
margin: 0;
}
/* Breadcrumb Navigation */
.breadcrumb {
display: flex;
align-items: center;
gap: 0.25rem;
margin-bottom: 1rem;
padding: 0.5rem 0.75rem;
background: var(--bg-tertiary);
border-radius: 8px;
font-size: 0.813rem;
overflow-x: auto;
white-space: nowrap;
scrollbar-width: none;
border: 1px solid var(--border);
}
.breadcrumb::-webkit-scrollbar {
display: none;
}
.breadcrumb:empty {
display: none;
}
.breadcrumb-item {
color: var(--text-secondary);
cursor: pointer;
transition: all 0.2s;
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-weight: 500;
}
.breadcrumb-item:hover {
color: var(--accent);
background: rgba(29, 185, 84, 0.08);
text-decoration: none;
}
.breadcrumb-item:last-child {
color: var(--text-primary);
font-weight: 600;
cursor: default;
pointer-events: none;
}
.breadcrumb-home {
display: flex;
align-items: center;
padding: 0.25rem;
color: var(--text-muted);
}
.breadcrumb-home:hover {
text-decoration: none;
color: var(--accent);
}
.breadcrumb-separator {
color: var(--text-muted);
margin: 0;
opacity: 0.5;
font-size: 0.75rem;
}
/* Browser Toolbar */
.browser-toolbar {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 1rem;
gap: 1rem;
}
.browser-toolbar-left,
.browser-toolbar-right {
display: flex;
align-items: center;
gap: 0.75rem;
}
/* Browser Search */
.browser-search-wrapper {
flex: 1;
position: relative;
min-width: 0;
max-width: 300px;
}
.browser-search-icon {
position: absolute;
left: 0.6rem;
top: 50%;
transform: translateY(-50%);
color: var(--text-muted);
pointer-events: none;
}
.browser-search-input {
width: 100%;
padding: 0.4rem 2rem 0.4rem 2rem;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-size: 0.813rem;
outline: none;
transition: border-color 0.2s;
}
.browser-search-input:focus {
border-color: var(--accent);
}
.browser-search-input::placeholder {
color: var(--text-muted);
}
.browser-search-clear {
position: absolute;
right: 0.4rem;
top: 50%;
transform: translateY(-50%);
background: none;
border: none;
color: var(--text-muted);
cursor: pointer;
padding: 0.15rem;
display: flex;
align-items: center;
justify-content: center;
border-radius: 50%;
width: auto;
height: auto;
transition: color 0.15s;
}
.browser-search-clear:hover {
color: var(--text-primary);
background: transparent !important;
transform: translateY(-50%) !important;
}
.view-toggle {
display: flex;
background: var(--bg-tertiary);
border-radius: 6px;
border: 1px solid var(--border);
overflow: hidden;
}
.view-toggle-btn {
display: flex;
align-items: center;
justify-content: center;
padding: 0.4rem 0.6rem;
background: transparent;
border: none;
color: var(--text-muted);
cursor: pointer;
transition: all 0.2s;
width: auto;
height: auto;
border-radius: 0;
}
.view-toggle-btn:hover {
color: var(--text-primary);
background: transparent !important;
transform: none !important;
}
.view-toggle-btn.active {
color: var(--accent);
background: var(--bg-primary);
}
.browser-refresh-btn {
margin-left: 0.35rem;
}
.view-toggle-btn svg {
fill: currentColor;
}
.browser-play-all-btn {
display: flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.7rem;
background: var(--accent);
border: none;
border-radius: 6px;
color: #fff;
font-size: 0.75rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
width: auto;
height: auto;
margin-left: 0.5rem;
}
.browser-play-all-btn:hover {
background: var(--accent-hover);
transform: none;
}
.items-per-page-label {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.813rem;
color: var(--text-secondary);
}
.items-per-page-label select {
padding: 0.3rem 0.5rem;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-primary);
font-size: 0.813rem;
cursor: pointer;
}
.items-per-page-label select:hover {
border-color: var(--accent);
}
/* Browser Grid */
.browser-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 0.75rem;
margin-bottom: 1.5rem;
min-height: 200px;
align-items: stretch;
}
/* Root folder grid — wider cards */
.browser-grid.browser-root-grid {
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 1rem;
}
/* Compact Grid */
.browser-grid.browser-grid-compact {
grid-template-columns: repeat(auto-fill, minmax(80px, 100px));
gap: 0.5rem;
}
.browser-grid-compact .browser-item {
padding: 0.4rem;
gap: 0.3rem;
}
.browser-grid-compact .browser-icon {
font-size: 2rem;
}
.browser-grid-compact .browser-item-name {
font-size: 0.688rem;
-webkit-line-clamp: 1;
}
.browser-grid-compact .browser-item-meta {
font-size: 0.625rem;
}
.browser-grid-compact .browser-item-type {
font-size: 0.5rem;
padding: 0.15rem 0.35rem;
top: 0.25rem;
right: 0.25rem;
}
/* Browser List View */
.browser-list {
display: flex;
flex-direction: column;
gap: 1px;
margin-bottom: 1.5rem;
min-height: 200px;
}
/* List view column header */
.browser-list-header {
display: grid;
grid-template-columns: 40px 1fr auto auto auto auto;
align-items: center;
gap: 0.75rem;
padding: 0.4rem 0.75rem;
font-size: 0.688rem;
font-weight: 600;
color: var(--text-muted);
text-transform: uppercase;
letter-spacing: 0.05em;
border-bottom: 1px solid var(--border);
margin-bottom: 0.25rem;
user-select: none;
}
.browser-list-header span:nth-child(n+3) {
text-align: right;
}
.browser-list-item {
display: grid;
grid-template-columns: 40px 1fr auto auto auto auto;
align-items: center;
gap: 0.75rem;
padding: 0.5rem 0.75rem;
background: transparent;
border: 1px solid transparent;
border-radius: 6px;
cursor: pointer;
transition: all 0.15s;
animation: itemFadeIn 0.3s ease-out backwards;
animation-delay: calc(var(--item-index, 0) * 15ms);
}
.browser-list-item:hover {
background: var(--bg-tertiary);
border-color: var(--border);
}
.browser-list-item:active {
background: var(--border);
}
.browser-list-icon {
width: 36px;
height: 36px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.25rem;
border-radius: 6px;
background: var(--bg-tertiary);
flex-shrink: 0;
overflow: hidden;
position: relative;
}
.browser-list-play-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.55);
border-radius: 6px;
opacity: 0;
transition: opacity 0.15s;
pointer-events: none;
}
.browser-list-play-overlay svg {
width: 16px;
height: 16px;
color: #fff;
}
.browser-list-item:hover .browser-list-play-overlay {
opacity: 1;
}
.browser-list-thumbnail {
width: 36px;
height: 36px;
object-fit: cover;
border-radius: 6px;
}
.browser-list-thumbnail.loading {
opacity: 0;
}
.browser-list-thumbnail.loaded {
animation: fadeIn 0.3s ease-out forwards;
}
.browser-list-name {
font-size: 0.813rem;
font-weight: 500;
color: var(--text-primary);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
.browser-list-bitrate {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
min-width: 55px;
text-align: right;
font-variant-numeric: tabular-nums;
}
.browser-list-duration {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
min-width: 45px;
text-align: right;
font-variant-numeric: tabular-nums;
}
.browser-list-size {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
min-width: 60px;
text-align: right;
font-variant-numeric: tabular-nums;
}
.browser-loading {
grid-column: 1 / -1;
display: flex;
justify-content: center;
padding: 3rem;
}
.browser-loading .loading-spinner {
width: 28px;
height: 28px;
}
.browser-empty {
grid-column: 1 / -1;
text-align: center;
padding: 3rem 2rem;
color: var(--text-muted);
font-size: 0.875rem;
}
.browser-item {
background: var(--bg-tertiary);
border: 1px solid transparent;
border-radius: 10px;
padding: 0.6rem;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
flex-direction: column;
align-items: center;
gap: 0.5rem;
position: relative;
animation: itemFadeIn 0.3s ease-out backwards;
animation-delay: calc(var(--item-index, 0) * 25ms);
}
@keyframes itemFadeIn {
from { opacity: 0; transform: translateY(10px); }
to { opacity: 1; transform: translateY(0); }
}
.browser-item:hover {
border-color: var(--border);
transform: translateY(-3px);
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.25);
}
.browser-item:active {
transform: translateY(-1px);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
/* Root Folder Cards — distinctive hero style */
.browser-item.browser-root-folder {
padding: 1.25rem 1rem;
gap: 0.75rem;
border: 1px solid var(--border);
background: linear-gradient(135deg, var(--bg-tertiary) 0%, var(--bg-secondary) 100%);
min-height: 120px;
justify-content: center;
}
.browser-item.browser-root-folder .browser-thumb-wrapper {
width: auto;
height: auto;
}
.browser-item.browser-root-folder .browser-icon {
width: 56px;
height: 56px;
font-size: 1.75rem;
border-radius: 14px;
background: rgba(29, 185, 84, 0.1);
border: 1px solid rgba(29, 185, 84, 0.15);
transition: all 0.25s;
}
.browser-item.browser-root-folder:hover .browser-icon {
background: rgba(29, 185, 84, 0.18);
border-color: rgba(29, 185, 84, 0.3);
transform: scale(1.05);
}
.browser-item.browser-root-folder .browser-item-name {
font-size: 0.875rem;
font-weight: 600;
}
/* Unavailable root folder overlay */
.browser-item.browser-root-folder.unavailable .browser-icon {
background: rgba(231, 76, 60, 0.08);
border-color: rgba(231, 76, 60, 0.12);
opacity: 0.6;
}
/* Thumbnail Display */
.browser-thumbnail {
width: 100%;
aspect-ratio: 1;
object-fit: cover;
border-radius: 8px;
background: var(--bg-primary);
display: block;
}
.browser-thumbnail.loading {
background: linear-gradient(
110deg,
var(--bg-primary) 30%,
var(--bg-tertiary) 50%,
var(--bg-primary) 70%
);
background-size: 200% 100%;
animation: shimmer 1.8s ease-in-out infinite;
opacity: 1;
}
.browser-thumbnail.loaded {
animation: fadeIn 0.4s ease-out forwards;
}
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
@keyframes fadeIn {
from {
opacity: 0;
transform: scale(0.97);
}
to {
opacity: 1;
transform: scale(1);
}
}
/* File/Folder Icons */
.browser-icon {
width: 100%;
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
font-size: 2.5rem;
border-radius: 8px;
background: var(--bg-primary);
}
.browser-item-info {
width: 100%;
text-align: center;
margin-top: auto;
padding: 0 0.15rem;
}
.browser-item-name {
font-size: 0.75rem;
font-weight: 500;
color: var(--text-primary);
word-break: break-word;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
line-height: 1.3;
}
.browser-item-meta {
font-size: 0.688rem;
color: var(--text-muted);
margin-top: 0.2rem;
line-height: 1.3;
}
.browser-item-type {
position: absolute;
top: 0.35rem;
right: 0.35rem;
background: var(--bg-primary);
padding: 0.2rem;
border-radius: 4px;
color: var(--text-secondary);
z-index: 10;
line-height: 0;
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.2s;
}
.browser-item:hover .browser-item-type {
opacity: 0.85;
}
.browser-item-type.audio {
color: var(--accent);
}
.browser-item-type.video {
color: #3b82f6;
}
/* Thumbnail Wrapper & Play Overlay */
.browser-thumb-wrapper {
position: relative;
width: 100%;
aspect-ratio: 1;
flex-shrink: 0;
border-radius: 8px;
overflow: hidden;
}
.browser-thumb-wrapper .browser-thumbnail,
.browser-thumb-wrapper .browser-icon {
width: 100%;
height: 100%;
}
.browser-play-overlay {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: rgba(0, 0, 0, 0.5);
border-radius: 8px;
opacity: 0;
transition: opacity 0.2s;
pointer-events: none;
}
.browser-play-overlay svg {
width: 36px;
height: 36px;
color: #fff;
filter: drop-shadow(0 2px 6px rgba(0, 0, 0, 0.5));
transition: transform 0.15s;
}
.browser-item:hover .browser-play-overlay {
opacity: 1;
}
.browser-item:hover .browser-play-overlay svg {
transform: scale(1.1);
}
/* Compact grid overrides */
.browser-grid-compact .browser-thumb-wrapper {
width: 100%;
aspect-ratio: 1;
}
.browser-grid-compact .browser-play-overlay svg {
width: 24px;
height: 24px;
}
/* Download Button (list view only) */
.browser-list-download {
background: transparent;
border: none;
border-radius: 4px;
padding: 0.25rem;
color: var(--text-muted);
cursor: pointer;
transition: color 0.15s;
line-height: 0;
display: flex;
align-items: center;
justify-content: center;
width: auto;
height: auto;
opacity: 0;
}
.browser-list-item:hover .browser-list-download {
opacity: 1;
}
.browser-list-download:hover {
color: var(--accent);
background: transparent !important;
transform: none;
}
/* Pagination */
.pagination {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding-top: 1rem;
border-top: 1px solid var(--border);
}
.pagination button {
padding: 0.4rem 1.25rem;
border-radius: 6px;
background: var(--bg-tertiary);
border: 1px solid var(--border);
color: var(--text-primary);
cursor: pointer;
font-size: 0.813rem;
font-weight: 600;
transition: all 0.2s;
width: auto;
height: auto;
}
.pagination button:hover:not(:disabled) {
background: var(--accent);
border-color: var(--accent);
color: #fff;
transform: none;
}
.pagination button:disabled {
opacity: 0.3;
cursor: not-allowed;
}
.pagination-center {
display: flex;
align-items: center;
gap: 0.5rem;
font-size: 0.813rem;
color: var(--text-secondary);
}
.pagination-showing {
font-size: 0.75rem;
color: var(--text-muted);
white-space: nowrap;
}
.page-input {
width: 3rem;
padding: 0.25rem 0.35rem;
text-align: center;
background: var(--bg-tertiary);
border: 1px solid var(--border);
border-radius: 4px;
color: var(--text-primary);
font-size: 0.813rem;
-moz-appearance: textfield;
}
.page-input::-webkit-outer-spin-button,
.page-input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
.page-input:focus {
outline: none;
border-color: var(--accent);
}
/* Responsive Design */
@media (max-width: 600px) {
.browser-container {
padding: 0.75rem;
}
.browser-grid {
grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
gap: 0.5rem;
}
.browser-grid.browser-root-grid {
grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
gap: 0.75rem;
}
.browser-grid.browser-grid-compact {
grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
}
.browser-item {
padding: 0.5rem;
}
.browser-item.browser-root-folder {
padding: 1rem 0.75rem;
min-height: 100px;
}
.browser-header-section {
flex-direction: column;
align-items: stretch;
gap: 1rem;
}
.browser-header-section button {
width: 100%;
}
.browser-toolbar {
flex-wrap: wrap;
gap: 0.5rem;
}
.browser-toolbar-left {
gap: 0.35rem;
}
.browser-search-wrapper {
max-width: none;
flex-basis: 100%;
order: 10;
}
.browser-toolbar-right {
margin-left: auto;
}
.items-per-page-label span {
display: none;
}
.browser-list-header {
grid-template-columns: 32px 1fr auto auto;
gap: 0.5rem;
padding: 0.35rem 0.5rem;
}
.browser-list-header span:nth-child(n+3):nth-child(-n+4) {
display: none;
}
.browser-list-item {
grid-template-columns: 32px 1fr auto auto;
gap: 0.5rem;
padding: 0.4rem 0.5rem;
}
.browser-list-icon {
width: 32px;
height: 32px;
}
.browser-list-duration {
display: none;
}
.browser-list-size {
display: none;
}
.browser-list-type {
display: none;
}
.pagination {
flex-wrap: wrap;
gap: 0.5rem;
}
.pagination-showing {
flex-basis: 100%;
text-align: center;
order: -1;
}
.album-art-glow {
width: 250px;
height: 250px;
}
.mini-volume-container {
display: none;
}
.mini-player {
gap: 0.75rem;
padding: 0.5rem 0.75rem;
padding-top: calc(0.5rem + 2px);
}
.mini-nav-btn {
display: none;
}
.mini-player-info {
min-width: 120px;
}
.mini-progress-container {
gap: 0.5rem;
}
}
/* Tablet breakpoint */
@media (min-width: 601px) and (max-width: 900px) {
.mini-volume-container {
display: none;
}
.browser-list-bitrate {
display: none;
}
.browser-list-header {
grid-template-columns: 40px 1fr auto auto auto;
}
.browser-list-header span:nth-child(3) {
display: none;
}
.browser-list-item {
grid-template-columns: 40px 1fr auto auto auto;
}
}
/* Update Banner */
.update-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1001;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 10px 16px;
background: var(--accent);
color: #fff;
font-size: 0.85rem;
font-weight: 500;
text-align: center;
transition: transform 0.3s ease;
}
.update-banner:not(.hidden) {
animation: bannerSlideIn 0.4s ease-out;
}
.update-banner.hidden {
transform: translateY(-100%);
pointer-events: none;
}
.update-banner a {
color: #fff;
text-decoration: underline;
font-weight: 600;
}
.update-banner a:hover {
opacity: 0.85;
}
.update-banner-close {
background: none;
color: #fff;
font-size: 1.2rem;
padding: 0 4px;
opacity: 0.7;
cursor: pointer;
line-height: 1;
display: flex;
align-items: center;
}
.update-banner-close:hover {
opacity: 1;
}
/* Connection Banner */
.connection-banner {
position: fixed;
top: 0;
left: 0;
right: 0;
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
padding: 10px 16px;
background: var(--error);
color: #fff;
font-size: 0.85rem;
font-weight: 500;
text-align: center;
transition: transform 0.3s ease;
}
.connection-banner:not(.hidden) {
animation: bannerSlideIn 0.4s ease-out, bannerPulse 2s ease-in-out 0.4s 2;
}
.connection-banner.hidden {
transform: translateY(-100%);
pointer-events: none;
}
@keyframes bannerSlideIn {
from { transform: translateY(-100%); }
to { transform: translateY(0); }
}
@keyframes bannerPulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.connection-banner-btn {
padding: 4px 14px;
background: rgba(255, 255, 255, 0.2);
color: #fff;
border-radius: 4px;
font-size: 0.8rem;
font-weight: 600;
transition: background 0.2s;
}
.connection-banner-btn:hover {
background: rgba(255, 255, 255, 0.35);
}
/* Wide screens - horizontal player layout */
@media (min-width: 900px) {
.container {
max-width: 960px;
}
.player-layout {
flex-direction: row;
gap: 2.5rem;
align-items: flex-start;
}
.album-art-container {
margin-bottom: 0;
flex-shrink: 0;
}
.player-details .track-info {
text-align: left;
}
.player-details .playback-state {
justify-content: flex-start;
}
.player-details .controls {
justify-content: flex-start;
}
.player-details .source-info {
text-align: left;
justify-content: flex-start;
}
}
/* ========================================
PWA Standalone & Mobile Polish
======================================== */
html {
overscroll-behavior: none;
}
/* Safe area insets for notched phones (viewport-fit=cover) */
.container {
padding-left: max(0.75rem, env(safe-area-inset-left));
padding-right: max(0.75rem, env(safe-area-inset-right));
}
.mini-player {
padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
footer {
padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
}
body.mini-player-visible footer {
padding-bottom: calc(70px + env(safe-area-inset-bottom, 0px));
}
.connection-banner {
padding-top: max(10px, env(safe-area-inset-top));
}
/* Touch optimization: eliminate 300ms tap delay */
.controls button,
.mini-controls button,
.mini-control-btn,
.tab-btn,
.header-btn,
.header-link,
.mute-btn,
.vinyl-toggle-btn,
.view-toggle-btn,
.browser-item,
.browser-list-item,
.script-btn,
.action-btn {
touch-action: manipulation;
}
@media (max-width: 600px) {
.container {
padding-left: max(0.5rem, env(safe-area-inset-left));
padding-right: max(0.5rem, env(safe-area-inset-right));
}
.mini-player {
padding-bottom: max(0.5rem, env(safe-area-inset-bottom));
padding-left: max(0.75rem, env(safe-area-inset-left));
padding-right: max(0.75rem, env(safe-area-inset-right));
}
}
@media (display-mode: standalone) {
body {
overscroll-behavior-y: none;
-webkit-overflow-scrolling: touch;
}
}
/* Accessibility: reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* ════════════════════════════════════════════════════════════════
STUDIO REFERENCE — editorial overrides
Applied on top of the legacy stylesheet. Mapped to existing
selectors so no JS / DOM changes are required.
════════════════════════════════════════════════════════════════ */
/* ─── Container & header ────────────────────────────────────── */
.container {
max-width: 1280px;
padding: 56px 48px 140px;
}
@media (max-width: 720px) {
.container { padding: 48px 18px 140px; }
}
/* ─── Folio marks (page corners, all tabs) ────────────────── */
body > .folio {
position: fixed;
top: 16px;
z-index: 50;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.2em;
text-transform: uppercase;
color: var(--ink-faint);
display: inline-flex;
align-items: center;
gap: 8px;
pointer-events: none;
}
body > .folio.tl { left: 24px; }
body > .folio.tr { right: 24px; }
@media (max-width: 720px) {
body > .folio { font-size: 9px; letter-spacing: 0.16em; }
body > .folio.tl { left: 14px; }
body > .folio.tr { right: 14px; }
}
/* The status-dot now lives inside the folio */
body > .folio .status-dot {
width: 7px;
height: 7px;
background: var(--jade);
border-radius: 50%;
box-shadow: 0 0 0 0 rgba(122, 178, 148, 0.55);
animation: sr-pulse 2.4s ease-in-out infinite;
}
@keyframes sr-pulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(122, 178, 148, 0.55); }
50% { box-shadow: 0 0 0 6px rgba(122, 178, 148, 0); }
}
/* Hide the old in-header status-dot if any rendering remnants exist */
header .status-dot { display: none; }
/* The version-label now lives inside the folio.tr — remove the old badge styling */
.version-label,
body > .folio #version-label {
background: transparent;
border: 0;
padding: 0;
color: var(--copper);
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
border-radius: 0;
}
/* ─── Header (3-column: brand center, toolbar right) ─────── */
header {
padding: 0 0 22px 0;
border-bottom: 1px solid var(--rule-strong);
margin-bottom: 28px;
position: relative;
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
gap: 20px;
}
/* Brand wordmark (centered) */
header .brand {
text-align: center;
grid-column: 2;
line-height: 1;
}
header .brand-name {
font-family: var(--serif);
font-style: italic;
font-weight: 400;
font-size: 30px;
letter-spacing: -0.015em;
color: var(--ink);
font-variation-settings: 'opsz' 144;
display: block;
}
header .brand-sub {
display: block;
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.32em;
text-transform: uppercase;
color: var(--ink-mute);
margin-top: 6px;
}
@media (max-width: 720px) {
header { grid-template-columns: 1fr; gap: 14px; }
header .brand { grid-column: 1; }
header .brand-name { font-size: 24px; }
header .header-toolbar { justify-self: center; }
}
.header-toolbar {
grid-column: 3;
justify-self: end;
/* Strip the legacy dark capsule */
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
padding: 0 !important;
gap: 6px;
display: flex;
align-items: center;
}
@media (max-width: 720px) {
.header-toolbar { grid-column: 1; }
}
.header-btn,
.header-btn-logout,
.header-link {
background: transparent;
border: 1px solid transparent;
color: var(--ink-soft);
border-radius: 0;
width: 36px;
height: 36px;
/* Centre the icon inside the hit box; reset legacy padding. */
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0;
box-sizing: border-box;
transition: all 200ms var(--ease);
}
.header-btn > svg,
.header-btn-logout > svg,
.header-link > svg {
display: block;
width: 16px;
height: 16px;
}
.header-btn:hover,
.header-btn-logout:hover,
.header-link:hover {
color: var(--copper);
border-color: var(--rule-strong);
background: transparent;
}
.header-locale {
background: transparent;
border: 1px solid transparent;
color: var(--ink-soft);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
height: 36px;
padding: 0 10px 0 12px;
}
.header-locale:hover {
color: var(--copper);
border-color: var(--rule-strong);
}
.header-toolbar-sep {
background: var(--rule-strong);
height: 20px;
margin: 0 6px;
}
.accent-dot {
box-shadow: 0 0 0 1px var(--rule-strong), 0 0 12px var(--copper-glow);
}
.accent-picker-dropdown {
background: var(--bg-card);
border: 1px solid var(--rule-strong);
border-radius: 0;
box-shadow: 0 14px 40px rgba(0,0,0,0.5);
}
/* ─── Tab bar (numbered editorial) — only the bottom rule is visible */
.tab-bar {
background: transparent !important;
border: 0 !important;
border-bottom: 1px solid var(--rule-strong) !important;
padding: 0 !important;
margin: 14px 0 36px !important;
border-radius: 0 !important;
gap: 0;
position: relative;
overflow-x: auto;
scrollbar-width: none;
}
.tab-bar::-webkit-scrollbar { display: none; }
/* Hide the legacy tab-indicator entirely — we use ::after on .tab-btn.active instead */
.tab-indicator {
display: none !important;
}
.tab-btn {
background: transparent;
border: 0;
color: var(--ink-mute);
padding: 18px 26px 16px;
border-radius: 0;
font-family: var(--sans);
font-size: 13px;
font-weight: 400;
letter-spacing: 0.04em;
transition: color 180ms var(--ease);
position: relative;
display: inline-flex;
align-items: baseline;
gap: 10px;
white-space: nowrap;
cursor: pointer;
}
.tab-btn:hover { color: var(--ink-soft); background: transparent; }
.tab-btn.active {
color: var(--ink);
background: transparent;
font-family: var(--serif);
font-style: italic;
font-size: 17px;
font-weight: 400;
font-variation-settings: 'opsz' 60;
}
/* Tab number badge (replaces the icon) */
.tab-btn .tab-num {
font-family: var(--mono);
font-style: normal;
font-size: 10px;
color: var(--ink-faint);
letter-spacing: 0.15em;
font-weight: 400;
}
.tab-btn.active .tab-num {
color: var(--copper);
}
/* Hide any remaining legacy SVG icons on tabs */
.tab-btn svg {
display: none;
}
/* Active tab underline — only under the active tab */
.tab-btn.active::after {
content: "";
position: absolute;
bottom: -1px;
left: 0;
right: 0;
height: 2px;
background: var(--copper);
box-shadow: 0 0 12px var(--copper-glow);
}
/* ─── Update + connection banners (editorial) ────────────────── */
.update-banner,
.connection-banner {
/* Override legacy fixed-top + accent background */
position: fixed !important;
top: 0 !important;
left: 0 !important;
right: 0 !important;
z-index: 1001;
background: rgba(33, 30, 24, 0.94) !important;
color: var(--ink-soft) !important;
border: 0 !important;
border-bottom: 1px solid var(--copper) !important;
border-radius: 0 !important;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.4) !important;
padding: 12px 32px !important;
font-family: var(--mono) !important;
font-size: 11px !important;
letter-spacing: 0.12em !important;
text-transform: uppercase !important;
font-weight: 400 !important;
backdrop-filter: blur(20px) saturate(160%);
-webkit-backdrop-filter: blur(20px) saturate(160%);
display: flex;
align-items: center;
justify-content: center;
gap: 18px;
}
/* Tiny copper hairline accent on the bottom edge */
.update-banner::before,
.connection-banner::before {
content: "";
position: absolute;
bottom: -1px;
left: 32px;
right: 32px;
height: 1px;
background: linear-gradient(90deg, transparent, var(--copper), transparent);
opacity: 0.7;
}
/* Brand prefix */
.update-banner > span:first-child::before,
.connection-banner > span:first-child::before {
content: "● ";
color: var(--copper);
margin-right: 6px;
}
.update-banner a {
color: var(--copper) !important;
text-decoration: none !important;
font-family: var(--mono) !important;
font-size: 11px !important;
letter-spacing: 0.18em !important;
text-transform: uppercase !important;
font-weight: 500 !important;
border: 1px solid var(--copper);
padding: 6px 14px;
transition: all 180ms var(--ease);
}
.update-banner a:hover {
background: var(--copper);
color: var(--bg-deep) !important;
opacity: 1 !important;
}
.update-banner-close {
background: transparent !important;
color: var(--ink-mute) !important;
border: 0 !important;
font-size: 18px !important;
width: 24px;
height: 24px;
padding: 0 !important;
margin-left: 8px;
cursor: pointer;
transition: color 180ms var(--ease);
opacity: 1 !important;
}
.update-banner-close:hover {
color: var(--copper) !important;
}
.connection-banner-btn {
color: var(--copper) !important;
font-family: var(--mono) !important;
font-size: 11px !important;
letter-spacing: 0.18em !important;
text-transform: uppercase !important;
border: 1px solid var(--copper) !important;
border-radius: 0 !important;
background: transparent !important;
padding: 6px 14px !important;
transition: all 180ms var(--ease);
}
.connection-banner-btn:hover {
background: var(--copper) !important;
color: var(--bg-deep) !important;
}
/* ═══════════════════════════════════════════════════════════════
PLAYER VIEW — verbatim from Studio Reference mockup
═══════════════════════════════════════════════════════════════ */
.player-container {
background: transparent;
border: 0;
padding: 0;
box-shadow: none;
margin-top: 12px;
position: relative;
}
/* Visually hidden — kept in DOM for a11y/JS but invisible. */
.now-playing .visually-hidden,
.player-container .visually-hidden {
position: absolute;
width: 1px; height: 1px;
padding: 0; margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.now-playing {
display: grid;
grid-template-columns: minmax(320px, 520px) 1fr;
gap: 64px;
align-items: start;
margin-top: 28px;
position: relative;
}
.player-layout {
display: grid;
grid-template-columns: minmax(320px, 520px) 1fr;
gap: 64px;
align-items: start;
margin-top: 28px;
}
@media (max-width: 980px) {
.player-layout,
.now-playing {
grid-template-columns: 1fr;
gap: 36px;
}
}
/* ─── Vinyl stage ──────────────────────────────────────────── */
.album-art-container.vinyl-stage {
position: relative;
aspect-ratio: 1;
width: 100%;
max-width: none;
padding: 0;
background: transparent;
border: 0;
box-shadow: none;
display: flex;
align-items: center;
justify-content: center;
overflow: visible;
}
.album-art-container.vinyl-stage:hover { transform: none; }
.vinyl-stage .vinyl {
position: relative;
width: 86%;
aspect-ratio: 1;
border-radius: 50%;
background:
radial-gradient(circle at 50% 50%,
#0a0907 0%,
#0a0907 18%,
#1a1611 18.3%,
#0a0907 18.6%,
#14110c 22%,
#0a0907 22.3%,
#14110c 26%,
#0a0907 26.3%,
#14110c 30%,
#0a0907 30.3%,
#14110c 34%,
#0a0907 34.3%,
#14110c 38%,
#0a0907 38.3%,
#14110c 42%,
#0a0907 42.3%,
#14110c 46%,
#0a0907 46.3%,
#1c1812 47%,
#0a0907 100%);
box-shadow:
inset 0 0 60px rgba(0,0,0,0.7),
0 30px 80px rgba(0,0,0,0.6),
0 6px 20px rgba(0,0,0,0.5);
animation: sr-vinyl-spin 14s linear infinite;
animation-play-state: paused;
}
:root[data-playstate="playing"] .vinyl-stage .vinyl {
animation-play-state: running;
}
.vinyl-stage .vinyl::before {
content: "";
position: absolute;
inset: 12%;
border-radius: 50%;
background:
conic-gradient(from 0deg,
rgba(255,255,255,0.04) 0deg,
transparent 30deg,
rgba(255,255,255,0.06) 90deg,
transparent 150deg,
rgba(255,255,255,0.03) 210deg,
transparent 270deg,
rgba(255,255,255,0.05) 330deg,
transparent 360deg);
mix-blend-mode: screen;
pointer-events: none;
}
.vinyl-stage .vinyl-label {
position: absolute;
inset: 28%;
border-radius: 50%;
overflow: hidden;
box-shadow:
inset 0 0 24px rgba(0,0,0,0.4),
0 0 0 4px var(--bg-deep),
0 0 0 5px var(--copper-lo);
background: var(--bg-card);
z-index: 1;
}
.vinyl-stage .vinyl-label::after {
/* Spindle hole */
content: "";
position: absolute;
width: 8%; height: 8%;
top: 46%; left: 46%;
border-radius: 50%;
background: var(--bg-deep);
box-shadow: inset 0 1px 2px rgba(255,255,255,0.1);
z-index: 3;
}
.vinyl-stage #album-art-glow {
position: absolute;
inset: -8%;
width: 116%;
height: 116%;
border-radius: 50%;
filter: blur(20px) saturate(1.4);
opacity: 0.55;
z-index: 0;
object-fit: cover;
}
.vinyl-stage #album-art {
position: relative;
width: 100%;
height: 100%;
object-fit: cover;
display: block;
border-radius: 50%;
z-index: 2;
}
/* ─── Tonearm SVG ──────────────────────────────────────────── */
.vinyl-stage .tonearm {
position: absolute;
top: -6%;
right: -4%;
width: 56%;
height: 56%;
pointer-events: none;
transform-origin: 88% 12%;
transform: rotate(-22deg);
transition: transform 1s var(--ease);
z-index: 3;
filter: drop-shadow(0 4px 12px rgba(0,0,0,0.5));
}
:root[data-playstate="playing"] .vinyl-stage .tonearm {
transform: rotate(0deg);
}
@keyframes sr-vinyl-spin { to { transform: rotate(360deg); } }
/* Spectrogram canvas hidden by default — visualizer toggle reveals it */
.vinyl-stage .spectrogram-canvas {
position: absolute;
bottom: -56px;
left: 7%;
right: 7%;
width: 86%;
height: 38px;
border-radius: 0;
opacity: 0;
transition: opacity 240ms var(--ease);
pointer-events: none;
}
.vinyl-stage.visualizer-active .spectrogram-canvas,
body.visualizer-active .vinyl-stage .spectrogram-canvas {
opacity: 0.6;
}
/* ─── Player details (right column / masthead) ──────────────── */
.player-details,
.track-masthead {
gap: 0;
padding-top: 0;
display: flex;
flex-direction: column;
}
/* Kicker — copper italic mono with hairlines */
.track-masthead > .kicker {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.32em;
text-transform: uppercase;
color: var(--copper);
display: flex;
align-items: center;
gap: 14px;
margin-bottom: 22px;
}
.track-masthead > .kicker::before,
.track-masthead > .kicker::after {
content: "";
height: 1px;
background: var(--copper);
opacity: 0.6;
flex: 0 0 24px;
}
.track-masthead > .kicker::after { flex: 1 0 auto; }
.track-info {
margin-bottom: 0;
position: relative;
}
#track-title {
font-family: var(--serif);
font-weight: 400;
font-size: clamp(38px, 5vw, 68px);
line-height: 0.96;
letter-spacing: -0.02em;
color: var(--ink);
font-variation-settings: 'opsz' 144;
margin-bottom: 16px;
}
#artist {
font-family: var(--serif);
font-style: italic;
font-weight: 300;
font-size: 22px;
color: var(--copper-hi);
font-variation-settings: 'opsz' 60;
margin-bottom: 4px;
}
#album {
font-family: var(--sans);
font-size: 13px;
color: var(--ink-mute);
letter-spacing: 0.04em;
margin-bottom: 0;
}
/* Editorial metadata grid — 2 cells (State / Source); timecodes flank the timeline */
.meta-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
margin-top: 32px;
border-top: 1px solid var(--rule);
border-bottom: 1px solid var(--rule);
}
.meta-grid.meta-grid-2 {
grid-template-columns: minmax(180px, auto) 1fr;
}
.meta-cell {
padding: 16px 18px 16px 0;
border-right: 1px solid var(--rule);
min-width: 0;
}
.meta-cell:last-child { border-right: 0; padding-right: 0; }
.meta-cell .meta-label {
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--ink-faint);
margin-bottom: 8px;
}
.meta-cell .meta-value {
font-family: var(--serif);
font-style: italic;
font-weight: 400;
font-size: 18px;
color: var(--ink);
font-variation-settings: 'opsz' 30;
display: flex;
align-items: center;
gap: 8px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.meta-cell .meta-value.mono {
font-family: var(--mono);
font-style: normal;
font-size: 15px;
color: var(--ink);
font-variant-numeric: tabular-nums;
letter-spacing: 0.02em;
}
.meta-cell .meta-value .state-icon,
.meta-cell .meta-value .source-icon {
width: 14px;
height: 14px;
flex-shrink: 0;
color: var(--copper);
}
.meta-cell .source-value { font-size: 16px; }
@media (max-width: 720px) {
.meta-grid { grid-template-columns: repeat(2, 1fr); }
.meta-cell:nth-child(2) { border-right: 0; }
.meta-cell:nth-child(-n+2) { border-bottom: 1px solid var(--rule); }
}
/* Hide the legacy .playback-state container (its data is now in meta-grid) */
.track-info > .playback-state { display: none; }
/* (Legacy .spectrum + nth-child rules deleted — were capping the
row at max-width: 360px and forcing 3px-fixed bars. The
.now-playing-scoped rules below are the single source of truth.) */
/* Transport — wraps progress + controls */
.transport {
margin-top: 8px;
}
.progress-row {
display: grid;
grid-template-columns: auto 1fr auto;
gap: 18px;
align-items: center;
margin-bottom: 26px;
}
.progress-row .timecode {
font-family: var(--mono);
font-size: 12px;
color: var(--ink-mute);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
}
.progress-row .timecode.elapsed { color: var(--copper); font-weight: 500; }
/* Override the legacy .progress-container layout when inside .transport */
.transport .progress-container {
margin-top: 0;
}
/* VU cluster (replaces freestanding volume container) */
.vu-cluster {
margin-left: auto;
display: flex;
align-items: center;
gap: 14px;
}
.vu-meter {
position: relative;
width: 130px;
height: 56px;
background: linear-gradient(180deg, #1a1610 0%, #0e0c08 100%);
border: 1px solid var(--rule-strong);
border-radius: 4px 4px 0 0;
overflow: hidden;
box-shadow: inset 0 2px 6px rgba(0,0,0,0.5), inset 0 0 30px rgba(224,128,56,0.08);
}
.vu-meter::before {
content: "";
position: absolute;
inset: 0;
background: repeating-conic-gradient(from 195deg at 50% 100%,
transparent 0deg 4deg,
rgba(242, 235, 220, 0.08) 4deg 5deg,
transparent 5deg 9deg);
}
.vu-meter::after {
content: "VU";
position: absolute;
bottom: 4px; left: 50%;
transform: translateX(-50%);
font-family: var(--mono);
font-size: 8px;
letter-spacing: 0.3em;
color: var(--ink-faint);
}
.vu-needle {
position: absolute;
bottom: 0; left: 50%;
width: 1.5px;
height: 88%;
background: linear-gradient(to top, var(--copper) 0%, var(--copper-hi) 70%, var(--ink) 100%);
transform-origin: bottom center;
transform: rotate(-22deg);
transition: transform 350ms var(--ease);
box-shadow: 0 0 8px var(--copper-glow);
}
/* Volume container nested inside vu-cluster — strip legacy box & make compact */
.vu-cluster .volume-container {
background: transparent;
border: 0;
border-top: 0;
border-radius: 0;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 6px;
align-items: stretch;
min-width: 0;
width: 110px;
box-shadow: none;
}
.vu-cluster .volume-container > .mute-btn {
align-self: flex-end;
width: 28px;
height: 28px;
border-radius: 50%;
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
padding: 0;
margin: 0;
}
.vu-cluster .volume-container > .mute-btn:hover {
border-color: var(--copper);
color: var(--copper);
}
.vu-cluster .volume-container > .mute-btn svg {
width: 12px;
height: 12px;
fill: currentColor;
}
.vu-cluster .volume-container > #volume-slider {
width: 100%;
height: 2px;
flex: none;
background: var(--rule-strong);
border-radius: 0;
margin: 0;
padding: 0;
-webkit-appearance: none;
appearance: none;
}
.vu-cluster .volume-container > #volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 8px var(--copper-glow);
border: 0;
}
.vu-cluster .volume-container > .volume-display {
text-align: right;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-mute);
background: transparent;
border: 0;
padding: 0;
margin: 0;
font-variant-numeric: tabular-nums;
width: auto;
min-width: 0;
font-weight: 500;
}
.vu-cluster .volume-container > .volume-display::before {
content: "VOL · ";
color: var(--ink-faint);
font-weight: 400;
}
/* Make the player view source-info row tighter (visualizer toggle row) */
.player-details > .source-info {
margin-top: 18px;
padding-top: 14px;
border-top: 1px solid var(--rule);
display: flex;
align-items: center;
justify-content: space-between;
gap: 14px;
}
/* ─── Progress (hairline editorial) ─────────────────────────── */
.progress-container {
margin-top: 28px;
margin-bottom: 0; /* override legacy 2rem */
}
.time-display {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
letter-spacing: 0.04em;
font-variant-numeric: tabular-nums;
margin-bottom: 10px;
}
#current-time { color: var(--copper); font-weight: 500; }
.progress-bar {
height: 2px;
width: 100%;
background: var(--rule-strong);
border-radius: 0;
cursor: pointer;
overflow: visible;
position: relative;
transform: none !important; /* kill legacy :hover scaleY */
transition: background 200ms var(--ease);
min-width: 0; /* let grid shrink it */
}
.progress-bar:hover {
background: var(--rule-strong);
transform: none !important; /* defeat legacy :hover transform */
}
.progress-bar.dragging {
transform: none !important;
background: var(--rule-strong);
}
.progress-fill {
background: var(--copper);
box-shadow: 0 0 12px var(--copper-glow);
border-radius: 0;
height: 100%;
width: 0;
position: relative;
transition: width 0.1s linear;
}
.progress-fill::after {
content: "";
position: absolute;
right: -5px;
top: 50%;
transform: translateY(-50%) scale(1) !important; /* always visible, override legacy scale(0) default */
width: 10px;
height: 10px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 14px var(--copper-glow), 0 0 0 4px rgba(224, 128, 56, 0.12);
transition: none;
}
/* Progress row inside transport — grid layout for [time | bar | time] */
.transport .progress-row,
.progress-container.progress-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
gap: 18px;
align-items: center;
margin-top: 0;
margin-bottom: 26px;
}
.progress-row .timecode {
font-family: var(--mono);
font-size: 12px;
color: var(--ink-mute);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
line-height: 1;
}
.progress-row .timecode.elapsed { color: var(--copper); font-weight: 500; }
/* ─── Controls (circular transport) ─────────────────────────── */
.controls {
margin-top: 28px;
gap: 16px;
justify-content: flex-start;
}
.controls button {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
width: 48px;
height: 48px;
border-radius: 50%;
transition: all 220ms var(--ease);
}
.controls button:hover {
background: rgba(224, 128, 56, 0.06);
border-color: var(--copper);
color: var(--copper);
}
.controls button.primary {
width: 64px;
height: 64px;
background: var(--ink);
color: var(--bg-deep);
border-color: var(--ink);
box-shadow: 0 8px 28px rgba(0, 0, 0, 0.45);
}
.controls button.primary:hover {
background: var(--copper);
border-color: var(--copper);
color: var(--bg-deep);
transform: scale(1.04);
box-shadow: 0 8px 28px var(--copper-glow);
}
.controls button svg { width: 20px; height: 20px; }
.controls button.primary svg { width: 24px; height: 24px; }
/* ─── Volume container (VU-meter aesthetic) ─────────────────── */
.volume-container {
margin-top: 28px;
padding-top: 22px;
border-top: 1px solid var(--rule);
gap: 14px;
display: flex;
align-items: center;
}
.mute-btn {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
border-radius: 50%;
width: 38px;
height: 38px;
}
.mute-btn:hover {
border-color: var(--copper);
color: var(--copper);
background: rgba(224, 128, 56, 0.06);
}
#volume-slider {
height: 2px;
background: var(--rule-strong);
border-radius: 0;
flex: 1;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
#volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 14px;
height: 14px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 12px var(--copper-glow), 0 0 0 4px rgba(224, 128, 56, 0.12);
border: 0;
cursor: grab;
}
#volume-slider::-moz-range-thumb {
width: 14px;
height: 14px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 12px var(--copper-glow);
border: 0;
}
#volume-slider::-moz-range-track {
height: 2px;
background: var(--rule-strong);
}
.volume-display {
font-family: var(--mono);
font-size: 11px;
color: var(--copper);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
min-width: 44px;
text-align: right;
font-weight: 500;
}
/* ─── Source info ───────────────────────────────────────────── */
.source-info {
margin-top: 24px;
padding-top: 22px;
border-top: 1px solid var(--rule);
}
.source-label {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--ink-mute);
gap: 10px;
}
.source-icon {
width: 14px;
height: 14px;
color: var(--copper);
}
.player-toggles { gap: 8px; }
.vinyl-toggle-btn {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-mute);
border-radius: 0;
width: 30px;
height: 30px;
transition: all 180ms var(--ease);
}
.vinyl-toggle-btn:hover,
.vinyl-toggle-btn.active {
border-color: var(--copper);
color: var(--copper);
background: rgba(224, 128, 56, 0.06);
}
/* ═══════════════════════════════════════════════════════════════
MINI PLAYER — sticky console strip (3-column grid)
═══════════════════════════════════════════════════════════════ */
.mini-player {
/* Override legacy display: flex with explicit grid */
display: grid !important;
grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr) auto;
column-gap: 24px;
row-gap: 0;
align-items: center;
background: linear-gradient(180deg, rgba(14, 13, 11, 0.72) 0%, rgba(14, 13, 11, 0.96) 30%);
backdrop-filter: blur(20px) saturate(160%);
-webkit-backdrop-filter: blur(20px) saturate(160%);
border-top: 1px solid var(--rule-strong);
box-shadow: none;
padding: 12px 32px;
/* Anchor firmly to the bottom of the viewport */
position: fixed !important;
bottom: 0 !important;
left: 0 !important;
right: 0 !important;
z-index: 1000;
}
/* Top edge progress line in copper */
.mini-player::before {
background: var(--copper) !important;
height: 2px !important;
box-shadow: 0 0 8px var(--copper-glow);
}
/* Column 1: track info */
.mini-player .mini-player-info {
grid-column: 1;
grid-row: 1;
min-width: 0;
overflow: hidden;
display: flex;
align-items: center;
gap: 12px;
}
/* Column 2: transport (centered) */
.mini-player .mini-controls {
grid-column: 2;
grid-row: 1;
justify-self: center;
display: flex;
align-items: center;
gap: 12px;
flex-shrink: 0;
}
/* Column 3: progress (timecodes + bar) */
.mini-player .mini-progress-container {
grid-column: 3;
grid-row: 1;
display: flex;
flex-direction: column;
gap: 4px;
justify-self: stretch;
align-items: stretch;
min-width: 180px;
max-width: 360px;
margin: 0 auto;
}
.mini-player .mini-progress-container .mini-time-display {
display: flex;
justify-content: space-between;
}
/* Column 4: volume controls */
.mini-player .mini-volume-container {
grid-column: 4;
grid-row: 1;
justify-self: end;
display: flex;
align-items: center;
gap: 8px;
flex-shrink: 0;
}
@media (max-width: 880px) {
.mini-player {
grid-template-columns: minmax(0, 1fr) auto auto;
column-gap: 14px;
}
.mini-player .mini-progress-container { display: none; }
.mini-player .mini-volume-container { grid-column: 3; }
}
@media (max-width: 540px) {
.mini-player {
grid-template-columns: minmax(0, 1fr) auto;
padding: 10px 14px;
}
.mini-player .mini-volume-container { display: none; }
}
.mini-player::before {
content: "";
position: absolute;
top: -1px; left: 32px; right: 32px;
height: 2px;
background: linear-gradient(90deg, transparent, var(--copper), transparent);
opacity: 0.55;
}
.mini-album-art {
border-radius: 0;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
width: 48px;
height: 48px;
}
.mini-track-title {
font-family: var(--serif);
font-style: italic;
font-size: 15px;
color: var(--ink);
font-variation-settings: 'opsz' 60;
letter-spacing: 0;
}
.mini-artist {
font-family: var(--mono);
font-size: 10px;
color: var(--ink-mute);
letter-spacing: 0.1em;
text-transform: uppercase;
margin-top: 4px;
}
.mini-control-btn {
background: transparent;
border: 0;
color: var(--ink-soft);
border-radius: 50%;
width: 32px;
height: 32px;
transition: color 180ms var(--ease);
}
.mini-control-btn:hover { color: var(--copper); background: transparent; }
.mini-control-btn.primary,
#mini-btn-play-pause {
background: var(--ink);
color: var(--bg-deep);
width: 38px;
height: 38px;
box-shadow: 0 4px 14px rgba(0, 0, 0, 0.4);
}
#mini-btn-play-pause:hover {
background: var(--copper);
color: var(--bg-deep);
}
.mini-time-display {
font-family: var(--mono);
font-size: 10px;
color: var(--ink-mute);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
}
#mini-current-time { color: var(--copper); font-weight: 500; }
.mini-progress-bar {
height: 2px;
background: var(--rule-strong);
border-radius: 0;
}
.mini-progress-fill {
background: var(--copper);
box-shadow: 0 0 8px var(--copper-glow);
border-radius: 0;
}
.mini-volume-slider {
-webkit-appearance: none;
appearance: none;
height: 2px;
background: var(--rule-strong);
}
.mini-volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 8px var(--copper-glow);
border: 0;
}
.mini-volume-slider::-moz-range-thumb {
width: 10px; height: 10px;
background: var(--copper);
border-radius: 50%;
border: 0;
}
.mini-volume-display {
font-family: var(--mono);
font-size: 10px;
color: var(--copper);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
font-weight: 500;
}
/* ═══════════════════════════════════════════════════════════════
BROWSER — editorial gallery
═══════════════════════════════════════════════════════════════ */
.browser-container {
background: transparent;
border: 0;
padding: 0;
box-shadow: none;
margin-top: 12px;
}
.breadcrumb {
font-family: var(--serif);
font-style: italic;
font-size: 17px;
color: var(--ink-soft);
font-variation-settings: 'opsz' 60;
background: transparent;
border-bottom: 1px solid var(--rule);
padding: 14px 0;
margin-bottom: 22px;
border-radius: 0;
}
.breadcrumb-item, .breadcrumb-home {
color: var(--ink-soft);
font-style: italic;
}
.breadcrumb-item:hover, .breadcrumb-home:hover { color: var(--copper); }
.breadcrumb-item:last-child {
color: var(--ink);
font-weight: 400;
}
.breadcrumb-separator {
color: var(--ink-faint);
font-style: normal;
margin: 0 8px;
opacity: 1;
}
.browser-toolbar {
background: transparent;
border: 0;
border-bottom: 1px solid var(--rule);
border-radius: 0;
padding: 0 0 14px 0;
margin-bottom: 28px;
gap: 12px;
}
.view-toggle {
background: transparent;
border: 1px solid var(--rule-strong);
border-radius: 0;
padding: 0;
gap: 0;
}
.view-toggle-btn {
background: transparent;
border: 0;
border-right: 1px solid var(--rule-strong);
color: var(--ink-mute);
border-radius: 0;
width: 36px;
height: 36px;
transition: all 180ms var(--ease);
}
.view-toggle-btn:last-child { border-right: 0; }
.view-toggle-btn:hover {
color: var(--copper);
background: rgba(224, 128, 56, 0.04);
}
.view-toggle-btn.active {
background: var(--ink);
color: var(--bg-deep);
}
.browser-refresh-btn,
.browser-play-all-btn {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
border-radius: 0;
width: 36px;
height: 36px;
transition: all 180ms var(--ease);
}
.browser-refresh-btn:hover,
.browser-play-all-btn:hover {
color: var(--copper);
border-color: var(--copper);
background: transparent;
}
.browser-play-all-btn {
color: var(--copper);
border-color: var(--copper);
}
.browser-search-wrapper {
background: transparent;
border: 0;
border-bottom: 1px solid var(--rule-strong);
border-radius: 0;
padding: 0 0 4px 0;
gap: 8px;
transition: border-color 180ms var(--ease);
}
.browser-search-wrapper:focus-within {
border-bottom-color: var(--copper);
}
.browser-search-input {
background: transparent;
border: 0;
color: var(--ink);
font-family: var(--sans);
font-size: 13px;
padding: 4px 0;
}
.browser-search-input::placeholder { color: var(--ink-mute); }
.browser-search-icon { color: var(--ink-mute); }
.browser-search-clear { color: var(--ink-mute); background: transparent; border: 0; }
.browser-search-clear:hover { color: var(--copper); }
.items-per-page-label {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-mute);
gap: 8px;
}
.items-per-page-label select {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
padding: 4px 8px;
}
/* Browser grid items */
.browser-grid {
gap: 28px 22px;
}
.browser-item {
background: transparent;
border: 0;
border-radius: 0;
padding: 0;
transition: transform 280ms var(--ease);
}
.browser-item:hover {
transform: translateY(-3px);
background: transparent;
box-shadow: none;
}
.browser-thumb-wrapper,
.browser-thumbnail {
border-radius: 0;
background: var(--bg-card);
box-shadow: 0 14px 30px -10px rgba(0,0,0,0.5);
transition: box-shadow 280ms var(--ease);
}
.browser-item:hover .browser-thumb-wrapper,
.browser-item:hover .browser-thumbnail {
box-shadow: 0 22px 50px -10px rgba(0,0,0,0.65), 0 0 0 1px var(--copper);
}
.browser-icon {
color: var(--ink-mute);
}
.browser-item-name {
font-family: var(--serif);
font-size: 16px;
color: var(--ink);
font-variation-settings: 'opsz' 18;
letter-spacing: 0;
margin-top: 12px;
}
.browser-item-meta,
.browser-item-type {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--ink-mute);
margin-top: 4px;
}
.browser-play-overlay,
.browser-list-play-overlay {
background: rgba(14, 13, 11, 0.5);
}
.browser-play-overlay svg,
.browser-list-play-overlay svg {
fill: var(--ink);
filter: drop-shadow(0 4px 12px rgba(0,0,0,0.6));
}
.browser-empty {
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 16px;
font-variation-settings: 'opsz' 30;
}
/* List view */
.browser-list {
background: transparent;
border: 1px solid var(--rule);
border-radius: 0;
}
.browser-list-header {
background: var(--bg-paper);
border-bottom: 1px solid var(--rule-strong);
color: var(--ink-mute);
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.browser-list-item {
border-bottom: 1px solid var(--rule);
transition: background 180ms var(--ease);
}
.browser-list-item:hover { background: var(--bg-paper); }
.browser-list-name {
font-family: var(--serif);
font-size: 15px;
color: var(--ink);
font-variation-settings: 'opsz' 18;
}
.browser-list-bitrate,
.browser-list-duration,
.browser-list-size {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
font-variant-numeric: tabular-nums;
}
/* Pagination */
.pagination {
border-top: 1px solid var(--rule);
margin-top: 32px;
padding-top: 22px;
background: transparent;
}
.pagination button {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 8px 16px;
transition: all 180ms var(--ease);
}
.pagination button:hover:not(:disabled) {
color: var(--copper);
border-color: var(--copper);
}
.pagination button:disabled { opacity: 0.4; }
.page-input {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink);
border-radius: 0;
font-family: var(--mono);
}
.pagination-center,
.pagination-showing {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
letter-spacing: 0.04em;
}
/* ═══════════════════════════════════════════════════════════════
QUICK ACCESS — console rail
═══════════════════════════════════════════════════════════════ */
.scripts-container {
background: transparent;
border: 0;
padding: 0;
box-shadow: none;
}
.scripts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
gap: 1px;
background: var(--rule-strong);
border: 1px solid var(--rule-strong);
padding: 0;
}
.scripts-empty {
background: var(--bg-card);
padding: 60px 24px;
color: var(--ink-mute);
}
.script-btn,
.link-card {
background: var(--bg-card);
border: 0;
border-radius: 0;
padding: 24px 18px;
color: var(--ink);
transition: all 200ms var(--ease);
text-align: center;
}
.script-btn:hover,
.link-card:hover {
background: var(--bg-card-2);
color: var(--copper);
transform: none;
}
.script-btn .browser-icon,
.link-card .browser-icon {
color: var(--ink-soft);
margin-bottom: 12px;
transition: color 200ms var(--ease);
}
.script-btn:hover .browser-icon,
.link-card:hover .browser-icon { color: var(--copper); transform: translateY(-2px); }
.script-btn .browser-item-name,
.link-card .browser-item-name {
font-family: var(--serif);
font-style: italic;
font-size: 14px;
color: inherit;
font-variation-settings: 'opsz' 18;
}
/* ═══════════════════════════════════════════════════════════════
SETTINGS — numbered editorial sections
═══════════════════════════════════════════════════════════════ */
.settings-container,
.script-management {
background: transparent;
border: 0;
padding: 0;
box-shadow: none;
}
.settings-section {
background: var(--bg-card);
border: 1px solid var(--rule);
border-radius: 0;
padding: 28px 32px;
margin-bottom: 16px;
box-shadow: none;
transition: border-color 200ms var(--ease);
position: relative;
counter-increment: sr-section;
}
.settings-section:hover { border-color: var(--rule-strong); }
.settings-container { counter-reset: sr-section; }
.settings-section summary {
font-family: var(--serif);
font-weight: 400;
font-size: 26px;
letter-spacing: -0.015em;
color: var(--ink);
font-variation-settings: 'opsz' 60;
padding: 0 0 16px 0;
border: 0;
background: transparent;
cursor: pointer;
list-style: none;
position: relative;
}
.settings-section summary::-webkit-details-marker { display: none; }
.settings-section summary::before {
content: "5." counter(sr-section, decimal-leading-zero);
font-family: var(--mono);
font-style: normal;
font-size: 10px;
letter-spacing: 0.22em;
color: var(--copper);
margin-right: 14px;
vertical-align: middle;
}
.settings-section summary::after {
content: "↓";
position: absolute;
right: 0;
top: 0;
font-family: var(--sans);
font-size: 16px;
color: var(--ink-mute);
transition: transform 240ms var(--ease);
}
.settings-section[open] summary::after { transform: rotate(180deg); }
.settings-section-content {
padding-top: 18px;
border-top: 1px solid var(--rule);
}
.settings-section-description {
font-family: var(--serif);
font-style: italic;
font-size: 14px;
color: var(--ink-soft);
line-height: 1.5;
font-variation-settings: 'opsz' 18;
margin-bottom: 18px;
}
.scripts-table {
border: 1px solid var(--rule);
border-collapse: collapse;
width: 100%;
background: transparent;
}
.scripts-table thead {
background: var(--bg-paper);
}
.scripts-table th {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
padding: 12px 14px;
text-align: left;
border-bottom: 1px solid var(--rule-strong);
font-weight: 400;
}
.scripts-table td {
padding: 12px 14px;
border-bottom: 1px solid var(--rule);
color: var(--ink-soft);
font-family: var(--sans);
font-size: 13px;
vertical-align: middle;
}
.scripts-table tr:last-child td { border-bottom: 0; }
.scripts-table .name-with-icon {
color: var(--ink);
font-family: var(--serif);
font-style: italic;
font-size: 15px;
font-variation-settings: 'opsz' 18;
}
.scripts-table .path-cell,
.scripts-table .mono {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
}
.add-card {
background: transparent;
border: 1px dashed var(--rule-strong);
border-radius: 0;
padding: 16px;
margin-top: 16px;
transition: all 200ms var(--ease);
color: var(--ink-mute);
cursor: pointer;
}
.add-card:hover {
border-color: var(--copper);
border-style: solid;
color: var(--copper);
background: rgba(224, 128, 56, 0.04);
}
.add-card-icon {
font-family: var(--serif);
font-weight: 300;
font-size: 24px;
color: inherit;
}
.add-card-grid {
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
}
.audio-device-selector {
display: flex;
flex-direction: column;
gap: 12px;
}
.audio-device-selector label {
display: flex;
flex-direction: column;
gap: 8px;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
}
.audio-device-selector select {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink);
border-radius: 0;
font-family: var(--sans);
font-size: 13px;
padding: 10px 12px;
}
.audio-device-status {
font-family: var(--mono);
font-size: 11px;
color: var(--jade);
letter-spacing: 0.1em;
text-transform: uppercase;
}
.folder-disabled-badge,
.folder-unavailable-badge {
background: transparent;
border: 1px solid currentColor;
border-radius: 0;
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 3px 8px;
color: var(--amber);
}
.folder-unavailable-badge { color: var(--rust); }
.empty-state-illustration {
color: var(--ink-faint);
}
.empty-state {
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 14px;
font-variation-settings: 'opsz' 18;
padding: 40px 20px;
text-align: center;
}
/* ═══════════════════════════════════════════════════════════════
DIALOGS — paper card
═══════════════════════════════════════════════════════════════ */
dialog {
background: var(--bg-card);
border: 1px solid var(--rule-strong);
border-radius: 0;
color: var(--ink);
box-shadow: 0 24px 60px rgba(0, 0, 0, 0.6);
padding: 0;
max-width: 560px;
width: 90%;
}
dialog::backdrop {
background: rgba(14, 13, 11, 0.7);
backdrop-filter: blur(4px);
-webkit-backdrop-filter: blur(4px);
}
.dialog-header {
padding: 24px 28px 18px;
border-bottom: 1px solid var(--rule);
background: transparent;
}
.dialog-header h3 {
font-family: var(--serif);
font-weight: 400;
font-style: italic;
font-size: 24px;
color: var(--ink);
font-variation-settings: 'opsz' 60;
letter-spacing: -0.01em;
}
.dialog-body {
padding: 22px 28px;
}
.dialog-body label {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
}
.dialog-body label > span {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-mute);
}
.dialog-body input,
.dialog-body textarea,
.dialog-body select {
background: transparent;
border: 0;
border-bottom: 1px solid var(--rule-strong);
border-radius: 0;
color: var(--ink);
font-family: var(--sans);
font-size: 14px;
padding: 8px 0;
transition: border-color 180ms var(--ease);
}
.dialog-body input:focus,
.dialog-body textarea:focus,
.dialog-body select:focus {
outline: 0;
border-bottom-color: var(--copper);
}
.dialog-body textarea {
border: 1px solid var(--rule-strong);
padding: 10px 12px;
resize: vertical;
min-height: 60px;
font-family: var(--mono);
font-size: 12px;
}
.dialog-footer {
padding: 16px 28px 22px;
border-top: 1px solid var(--rule);
background: transparent;
gap: 10px;
}
.btn-primary {
background: var(--ink);
color: var(--bg-deep);
border: 1px solid var(--ink);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 10px 18px;
transition: all 200ms var(--ease);
}
.btn-primary:hover {
background: var(--copper);
border-color: var(--copper);
color: var(--bg-deep);
}
.btn-secondary, .btn-cancel {
background: transparent;
color: var(--ink-soft);
border: 1px solid var(--rule-strong);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 10px 18px;
transition: all 200ms var(--ease);
}
.btn-secondary:hover, .btn-cancel:hover {
color: var(--copper);
border-color: var(--copper);
}
.btn-danger {
background: var(--rust);
color: var(--bg-deep);
border: 1px solid var(--rust);
border-radius: 0;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 10px 18px;
}
.btn-danger:hover { background: transparent; color: var(--rust); }
.btn-small {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
border-radius: 0;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
padding: 6px 12px;
}
.btn-small:hover { border-color: var(--copper); color: var(--copper); }
.confirm-dialog {
padding: 28px;
max-width: 460px;
}
.confirm-dialog p {
font-family: var(--serif);
font-style: italic;
font-size: 17px;
color: var(--ink-soft);
line-height: 1.5;
margin-bottom: 22px;
font-variation-settings: 'opsz' 30;
}
.confirm-dialog-actions {
display: flex;
justify-content: flex-end;
gap: 10px;
}
.execution-status {
font-family: var(--mono);
font-size: 12px;
letter-spacing: 0.1em;
text-transform: uppercase;
color: var(--copper);
padding: 10px 14px;
border: 1px solid var(--rule-strong);
background: var(--bg-paper);
margin-bottom: 14px;
}
.execution-result {
background: var(--bg-paper);
border: 1px solid var(--rule);
border-radius: 0;
}
.execution-result pre {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-soft);
padding: 14px;
}
.result-section h4 {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
margin-bottom: 8px;
font-weight: 400;
}
.icon-input-wrapper {
display: flex;
align-items: center;
gap: 10px;
}
.icon-preview {
background: var(--bg-paper);
border: 1px solid var(--rule-strong);
border-radius: 0;
width: 36px;
height: 36px;
color: var(--copper);
}
.params-section {
margin-top: 18px;
padding-top: 14px;
border-top: 1px solid var(--rule);
}
.params-header {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
}
.param-row {
background: var(--bg-paper);
border: 1px solid var(--rule);
border-radius: 0;
padding: 12px;
margin-top: 10px;
}
.param-row-header {
font-family: var(--mono);
font-size: 11px;
color: var(--copper);
letter-spacing: 0.08em;
}
.param-required-label {
color: var(--rust);
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.18em;
text-transform: uppercase;
}
.param-hint {
font-family: var(--serif);
font-style: italic;
font-size: 12px;
color: var(--ink-mute);
font-variation-settings: 'opsz' 18;
}
.param-remove-btn {
color: var(--rust);
background: transparent;
border: 1px solid var(--rule-strong);
border-radius: 0;
}
.param-remove-btn:hover { border-color: var(--rust); }
/* Icon select popup */
.icon-select-popup {
background: var(--bg-card);
border: 1px solid var(--rule-strong);
border-radius: 0;
box-shadow: 0 14px 40px rgba(0,0,0,0.5);
}
.icon-select-trigger {
background: transparent;
border: 1px solid var(--rule-strong);
border-radius: 0;
color: var(--ink);
font-family: var(--mono);
font-size: 12px;
padding: 8px 12px;
}
.icon-select-trigger:hover { border-color: var(--copper); color: var(--copper); }
.icon-select-cell {
border-radius: 0;
color: var(--ink-soft);
font-family: var(--mono);
font-size: 10px;
}
.icon-select-cell:hover {
background: rgba(224, 128, 56, 0.06);
color: var(--copper);
}
/* ═══════════════════════════════════════════════════════════════
AUTH MODAL — paper card
═══════════════════════════════════════════════════════════════ */
#auth-overlay {
background: rgba(14, 13, 11, 0.85);
backdrop-filter: blur(8px);
-webkit-backdrop-filter: blur(8px);
}
.auth-modal {
background: var(--bg-card);
border: 1px solid var(--rule-strong);
border-radius: 0;
padding: 40px 36px;
max-width: 440px;
box-shadow: 0 30px 80px rgba(0, 0, 0, 0.6);
position: relative;
}
.auth-modal h2 {
font-family: var(--serif);
font-weight: 400;
font-style: italic;
font-size: 36px;
line-height: 1;
margin-bottom: 12px;
font-variation-settings: 'opsz' 144;
letter-spacing: -0.02em;
color: var(--ink);
}
.auth-modal p {
font-family: var(--serif);
font-style: italic;
font-size: 15px;
color: var(--ink-soft);
line-height: 1.5;
margin-bottom: 18px;
font-variation-settings: 'opsz' 18;
}
.auth-modal input {
background: transparent;
border: 0;
border-bottom: 1px solid var(--rule-strong);
border-radius: 0;
color: var(--ink);
font-family: var(--mono);
font-size: 14px;
padding: 10px 0;
width: 100%;
margin-bottom: 18px;
}
.auth-modal input:focus {
outline: 0;
border-bottom-color: var(--copper);
}
.btn-connect {
background: var(--ink);
color: var(--bg-deep);
border: 1px solid var(--ink);
border-radius: 0;
width: 100%;
padding: 14px;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.22em;
text-transform: uppercase;
transition: all 200ms var(--ease);
cursor: pointer;
}
.btn-connect:hover {
background: var(--copper);
border-color: var(--copper);
}
.help-text {
margin-top: 22px;
padding-top: 18px;
border-top: 1px solid var(--rule);
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
letter-spacing: 0.04em;
}
.help-text code {
background: var(--bg-paper);
color: var(--copper);
border: 1px solid var(--rule);
padding: 2px 6px;
font-family: var(--mono);
font-size: 11px;
}
.error-message {
color: var(--rust);
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.1em;
text-transform: uppercase;
margin-top: 14px;
}
/* ═══════════════════════════════════════════════════════════════
TOAST NOTIFICATIONS
═══════════════════════════════════════════════════════════════ */
.toast {
background: var(--bg-card);
border: 1px solid var(--copper);
border-radius: 0;
color: var(--ink);
font-family: var(--sans);
font-size: 13px;
padding: 14px 18px;
box-shadow: 0 14px 40px rgba(0,0,0,0.5), 0 0 24px var(--copper-glow);
}
.toast.success { border-color: var(--jade); box-shadow: 0 14px 40px rgba(0,0,0,0.5); }
.toast.error { border-color: var(--rust); box-shadow: 0 14px 40px rgba(0,0,0,0.5); }
.toast.info { border-color: var(--rule-strong); box-shadow: 0 14px 40px rgba(0,0,0,0.5); }
/* ═══════════════════════════════════════════════════════════════
FOOTER (colophon)
═══════════════════════════════════════════════════════════════ */
footer {
margin-top: 80px;
padding: 28px 0 0;
border-top: 1px solid var(--rule-strong);
background: transparent;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.16em;
text-transform: uppercase;
color: var(--ink-faint);
text-align: center;
}
footer a {
color: var(--copper);
text-decoration: none;
border-bottom: 1px solid transparent;
transition: border-color 200ms var(--ease);
}
footer a:hover { border-bottom-color: var(--copper); }
footer strong {
font-family: var(--serif);
font-style: italic;
font-weight: 400;
font-size: 14px;
color: var(--ink-soft);
letter-spacing: 0.01em;
text-transform: none;
font-variation-settings: 'opsz' 30;
}
footer .separator { color: var(--ink-ghost); margin: 0 8px; }
/* ═══════════════════════════════════════════════════════════════
DISPLAY container (monitors tab)
═══════════════════════════════════════════════════════════════ */
.display-container {
background: transparent;
border: 0;
padding: 0;
box-shadow: none;
}
/* ─── Light theme overrides for SR overrides ──────────────── */
:root[data-theme="light"] .album-art-container {
box-shadow:
0 1px 0 var(--bg-paper),
0 28px 60px -20px rgba(26, 23, 21, 0.18),
0 8px 20px -8px rgba(26, 23, 21, 0.12);
}
:root[data-theme="light"] .mini-player {
background: linear-gradient(180deg, rgba(245, 241, 234, 0.7) 0%, rgba(245, 241, 234, 0.96) 30%);
}
:root[data-theme="light"] dialog::backdrop {
background: rgba(26, 23, 21, 0.5);
}
:root[data-theme="light"] #auth-overlay {
background: rgba(245, 241, 234, 0.85);
}
:root[data-theme="light"] .toast {
box-shadow: 0 14px 40px rgba(26,23,21,0.18), 0 0 24px var(--copper-glow);
}
/* ─── Mobile breakpoint refinements ──────────────────────── */
@media (max-width: 720px) {
#track-title,
.now-playing .track-title { font-size: 38px; }
.player-layout, .now-playing { gap: 28px; grid-template-columns: 1fr; }
.controls { gap: 12px; }
.now-playing .controls .btn-trans { width: 42px; height: 42px; }
.now-playing .controls .btn-trans.primary { width: 56px; height: 56px; }
.mini-player { padding: 12px 16px; gap: 16px; }
.tab-btn { padding: 14px 12px 12px; font-size: 12px; }
.tab-btn.active { font-size: 15px; }
.breadcrumb { font-size: 14px; }
.browser-toolbar { flex-wrap: wrap; }
.auth-modal { padding: 28px 22px; }
.auth-modal h2 { font-size: 28px; }
.settings-section { padding: 20px; }
.settings-section summary { font-size: 22px; }
footer { font-size: 9px; }
}
/* ════════════════════════════════════════════════════════════════
STUDIO REFERENCE — verbatim mockup snap for the player view.
Scoped to `.now-playing` so other tabs are unaffected. Wins over
earlier overrides through declaration order at equal specificity.
════════════════════════════════════════════════════════════════ */
.now-playing {
display: grid;
grid-template-columns: minmax(320px, 520px) 1fr;
gap: 64px;
align-items: start;
margin-top: 28px;
position: relative;
}
@media (max-width: 980px) {
.now-playing { grid-template-columns: 1fr; gap: 40px; }
}
/* ─── Vinyl + tonearm ─────────────────────────────────────── */
.now-playing .vinyl-stage {
position: relative;
aspect-ratio: 1;
width: 100%;
display: flex;
align-items: center;
justify-content: center;
background: transparent;
border: 0;
box-shadow: none;
padding: 0;
overflow: visible;
transform: none !important;
}
.now-playing .vinyl {
position: relative;
width: 86%;
aspect-ratio: 1;
border-radius: 50%;
background:
radial-gradient(circle at 50% 50%,
#0a0907 0%,
#0a0907 18%,
#1a1611 18.3%,
#0a0907 18.6%,
#14110c 22%,
#0a0907 22.3%,
#14110c 26%,
#0a0907 26.3%,
#14110c 30%,
#0a0907 30.3%,
#14110c 34%,
#0a0907 34.3%,
#14110c 38%,
#0a0907 38.3%,
#14110c 42%,
#0a0907 42.3%,
#14110c 46%,
#0a0907 46.3%,
#1c1812 47%,
#0a0907 100%);
box-shadow:
inset 0 0 60px rgba(0,0,0,0.7),
0 30px 80px rgba(0,0,0,0.6),
0 6px 20px rgba(0,0,0,0.5);
animation: sr-snap-spin 14s linear infinite;
animation-play-state: paused;
}
:root[data-playstate="playing"] .now-playing .vinyl {
animation-play-state: running;
}
.now-playing .vinyl::before {
content: "";
position: absolute; inset: 12%;
border-radius: 50%;
background:
conic-gradient(from 0deg,
rgba(255,255,255,0.04) 0deg,
transparent 30deg,
rgba(255,255,255,0.06) 90deg,
transparent 150deg,
rgba(255,255,255,0.03) 210deg,
transparent 270deg,
rgba(255,255,255,0.05) 330deg,
transparent 360deg);
mix-blend-mode: screen;
pointer-events: none;
}
/* Vinyl label = circular clip holding the actual album art */
.now-playing .vinyl-label {
position: absolute;
inset: 28%;
border-radius: 50%;
overflow: hidden;
background: var(--bg-card);
box-shadow:
inset 0 0 24px rgba(0,0,0,0.4),
0 0 0 4px var(--bg-deep),
0 0 0 5px var(--copper-lo);
z-index: 1;
}
.now-playing .vinyl-label::before {
/* Spindle hole */
content: "";
position: absolute;
width: 8%; height: 8%;
top: 46%; left: 46%;
border-radius: 50%;
background: var(--bg-deep);
box-shadow: inset 0 1px 2px rgba(255,255,255,0.1);
z-index: 3;
}
.now-playing .vinyl-label #album-art-glow {
position: absolute;
inset: -10%;
width: 120%;
height: 120%;
border-radius: 50%;
filter: blur(22px) saturate(1.4);
opacity: 0.5;
z-index: 0;
object-fit: cover;
}
.now-playing .vinyl-label #album-art {
position: relative;
width: 100%;
height: 100%;
object-fit: cover;
display: block;
border-radius: 50%;
z-index: 2;
/* Heavy vinyl-consistent tint: deeper sepia + lower saturation
so vibrant covers blend with the copper grooves. */
filter:
sepia(0.6)
saturate(0.7)
contrast(1.12)
brightness(0.88)
hue-rotate(-8deg);
transition: filter 480ms var(--ease), -webkit-mask-image 480ms var(--ease);
/* Soft radial fade — the outer ~12% of the art fades to black so
the album image dissolves into the vinyl surface rather than
cutting hard at the circular clip edge. */
-webkit-mask-image: radial-gradient(circle at 50% 50%,
black 0%,
black 78%,
rgba(0,0,0,0.85) 88%,
rgba(0,0,0,0.4) 96%,
transparent 100%);
mask-image: radial-gradient(circle at 50% 50%,
black 0%,
black 78%,
rgba(0,0,0,0.85) 88%,
rgba(0,0,0,0.4) 96%,
transparent 100%);
}
.now-playing:hover .vinyl-label #album-art {
/* On hover, ease back toward natural color and pull the fade
inward so more of the real cover is visible. */
filter:
sepia(0.25)
saturate(0.92)
contrast(1.05)
brightness(0.98)
hue-rotate(-4deg);
-webkit-mask-image: radial-gradient(circle at 50% 50%,
black 0%,
black 88%,
rgba(0,0,0,0.9) 95%,
rgba(0,0,0,0.5) 99%,
transparent 100%);
mask-image: radial-gradient(circle at 50% 50%,
black 0%,
black 88%,
rgba(0,0,0,0.9) 95%,
rgba(0,0,0,0.5) 99%,
transparent 100%);
}
/* Match the glow tint and soft edge to the album art treatment */
.now-playing .vinyl-label #album-art-glow {
filter: blur(22px) saturate(1.1) sepia(0.5) hue-rotate(-8deg);
opacity: 0.4;
}
/* Tonearm */
.now-playing .tonearm {
position: absolute;
top: -8%; right: -4%;
width: 58%; height: 58%;
pointer-events: none;
transform-origin: 88% 12%;
transform: rotate(-22deg);
transition: transform 1s var(--ease);
z-index: 3;
filter: drop-shadow(0 4px 12px rgba(0,0,0,0.5));
}
:root[data-playstate="playing"] .now-playing .tonearm {
transform: rotate(0deg);
}
@keyframes sr-snap-spin { to { transform: rotate(360deg); } }
/* Spectrogram canvas: hidden — the editorial .spectrum row in the
track-masthead already shows the audio spectrum. The canvas
element stays in the DOM so the visualizer JS keeps rendering
(drives the album-art bass-pulse + dynamic background). */
.now-playing .spectrogram-canvas {
display: none !important;
}
/* ─── Track masthead ──────────────────────────────────────── */
.now-playing .track-masthead {
display: flex;
flex-direction: column;
justify-content: center;
padding-top: 0;
gap: 0;
}
.now-playing .kicker {
display: flex;
align-items: center;
gap: 14px;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.32em;
text-transform: uppercase;
color: var(--copper);
margin-bottom: 22px;
}
.now-playing .kicker::before,
.now-playing .kicker::after {
content: "";
height: 1px;
background: var(--copper);
opacity: 0.6;
flex: 0 0 24px;
}
.now-playing .kicker::after { flex: 1 0 auto; }
.now-playing .track-title,
.now-playing #track-title {
font-family: var(--serif);
font-weight: 400;
font-size: clamp(34px, 4.4vw, 64px);
line-height: 0.98;
letter-spacing: -0.02em;
font-variation-settings: 'opsz' 144;
margin-bottom: 18px;
color: var(--ink);
margin-top: 0;
/* Long titles get clamped to 3 lines with ellipsis */
display: -webkit-box;
-webkit-line-clamp: 3;
line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
word-break: break-word;
overflow-wrap: anywhere;
hyphens: auto;
}
.now-playing .track-title em {
font-style: italic;
color: var(--copper-hi);
}
.now-playing .track-byline,
.now-playing #artist {
font-family: var(--serif);
font-style: italic;
font-size: 22px;
font-weight: 300;
color: var(--ink-soft);
font-variation-settings: 'opsz' 60;
margin-bottom: 4px;
margin-top: 0;
}
.now-playing .track-album,
.now-playing #album {
font-family: var(--sans);
font-size: 13px;
letter-spacing: 0.04em;
color: var(--ink-mute);
font-style: normal;
font-weight: 400;
margin-top: 0;
}
/* Hide byline/album rows when their content is empty so they
don't leave a stretched blank gap. JS leaves them empty when
the source provides no metadata. */
.now-playing #artist:empty,
.now-playing #album:empty {
display: none;
}
/* ─── 2-cell metadata grid ────────────────────────────────── */
.now-playing .meta-grid {
display: grid;
grid-template-columns: minmax(180px, auto) 1fr;
gap: 0;
margin-top: 36px;
border-top: 1px solid var(--rule);
border-bottom: 1px solid var(--rule);
}
.now-playing .meta-cell {
padding: 16px 24px 16px 0;
border-right: 1px solid var(--rule);
min-width: 0;
}
.now-playing .meta-cell:last-child {
border-right: 0;
padding-left: 24px;
padding-right: 0;
}
.now-playing .meta-cell .label {
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.22em;
text-transform: uppercase;
color: var(--ink-faint);
margin-bottom: 8px;
}
.now-playing .meta-cell .value {
font-family: var(--serif);
font-style: italic;
font-weight: 400;
font-size: 18px;
color: var(--ink);
font-variation-settings: 'opsz' 30;
display: flex;
align-items: center;
gap: 10px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
line-height: 1.2;
}
.now-playing .meta-cell .value .state-icon,
.now-playing .meta-cell .value .source-icon {
width: 16px;
height: 16px;
flex-shrink: 0;
color: var(--copper);
fill: currentColor;
}
/* ─── Spectrum bars (JS-injected; real audio from backend FFT) ── */
.now-playing .spectrum {
/* grid-template-columns is set from JS to repeat(N, minmax(0, 1fr))
because CSS repeat() does NOT accept a CSS variable as its count.
Falling back to a 40-column default ensures something sane renders
even if JS hasn't executed yet. */
display: grid !important;
grid-template-columns: repeat(40, minmax(0, 1fr));
align-items: end;
column-gap: 4px;
height: 70px;
margin: 36px 0 24px;
width: 100% !important;
box-sizing: border-box;
min-width: 0;
}
.now-playing .spectrum > span {
display: block;
width: 100%;
min-width: 0;
background: linear-gradient(to top, var(--copper-lo) 0%, var(--copper) 60%, var(--copper-hi) 100%);
opacity: 0.92;
transform-origin: bottom;
border-radius: 99px 99px 0 0;
height: var(--bar-h, 40%);
animation: sr-snap-bar 1.1s ease-in-out infinite;
animation-delay: var(--bar-delay, 0s);
animation-play-state: paused;
transition: height 60ms linear;
will-change: height;
}
:root[data-playstate="playing"] .now-playing .spectrum span {
animation-play-state: running;
}
/* When real audio data is driving heights, freeze the CSS animation
so JS-set heights aren't overridden by the keyframe. */
body.audio-spectrum-live .now-playing .spectrum span {
animation: none !important;
transition: height 50ms linear;
}
@keyframes sr-snap-bar {
0%, 100% { transform: scaleY(0.4); }
50% { transform: scaleY(1); }
}
/* ─── Transport ───────────────────────────────────────────── */
.now-playing .transport { margin-top: 0; }
.now-playing .progress-row {
display: grid;
grid-template-columns: auto minmax(0, 1fr) auto;
align-items: center;
gap: 18px;
margin-bottom: 28px;
}
.now-playing .timecode {
font-family: var(--mono);
font-size: 12px;
color: var(--ink-mute);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
line-height: 1;
}
.now-playing .timecode.elapsed { color: var(--copper); font-weight: 500; }
.now-playing .progress-track,
.now-playing .progress-bar {
height: 2px;
width: 100%;
background: var(--rule-strong);
position: relative;
cursor: pointer;
border-radius: 0;
overflow: visible;
transform: none !important;
transition: background 200ms var(--ease);
min-width: 0;
margin: 0;
}
.now-playing .progress-bar:hover,
.now-playing .progress-bar.dragging {
transform: none !important;
background: var(--rule-strong);
}
.now-playing .progress-fill {
position: absolute;
left: 0; top: 0;
height: 100%;
background: var(--copper);
box-shadow: 0 0 12px var(--copper-glow);
border-radius: 0;
width: 0;
transition: width 0.1s linear;
}
.now-playing .progress-fill::after {
content: "";
position: absolute;
right: -5px;
top: 50%;
transform: translateY(-50%) scale(1) !important;
width: 10px; height: 10px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 14px var(--copper-glow), 0 0 0 4px rgba(224, 128, 56, 0.12);
transition: none;
}
/* ─── Controls + VU cluster ───────────────────────────────── */
.now-playing .controls {
display: flex;
align-items: center;
gap: 18px;
margin-top: 0;
justify-content: flex-start;
}
.now-playing .btn-trans {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
width: 48px; height: 48px;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
border-radius: 50%;
padding: 0;
transition: all 200ms var(--ease);
}
.now-playing .btn-trans:hover {
border-color: var(--copper);
color: var(--copper);
background: rgba(224, 128, 56, 0.06);
}
.now-playing .btn-trans:disabled {
opacity: 0.35;
cursor: not-allowed;
border-color: var(--rule-strong);
color: var(--ink-mute);
background: transparent;
}
.now-playing .btn-trans.primary {
width: 64px; height: 64px;
background: var(--ink);
color: var(--bg-deep);
border-color: var(--ink);
box-shadow: 0 8px 28px rgba(0,0,0,0.45);
}
.now-playing .btn-trans.primary:hover {
background: var(--copper);
border-color: var(--copper);
color: var(--bg-deep);
transform: scale(1.04);
box-shadow: 0 8px 28px var(--copper-glow);
}
.now-playing .btn-trans svg {
width: 20px; height: 20px;
fill: currentColor;
}
.now-playing .btn-trans.primary svg {
width: 24px; height: 24px;
}
/* VU cluster — volume left, readout center, VU meter right (reversed) */
.now-playing .vu-cluster {
margin-left: auto;
display: flex;
flex-direction: row-reverse;
align-items: center;
gap: 16px;
user-select: none;
}
.now-playing .vu-cluster.muted .vu-needle {
background: linear-gradient(to top, var(--rust) 0%, var(--ink-mute) 100%);
box-shadow: 0 0 8px rgba(194, 85, 63, 0.4);
}
.now-playing .vu-cluster.muted .vu-readout strong { color: var(--rust); }
/* Integrated volume control: tiny mute icon + slim copper slider.
Lives on the LEFT of the cluster (row-reverse), so its divider
sits on its RIGHT to separate it from the readout. */
.now-playing .vu-volume {
display: flex;
align-items: center;
gap: 10px;
padding-right: 12px;
border-right: 1px solid var(--rule);
margin-right: 4px;
}
.now-playing .vu-volume .mute-btn {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
width: 30px;
height: 30px;
border-radius: 50%;
padding: 0;
margin: 0;
display: inline-flex;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 180ms var(--ease);
flex-shrink: 0;
}
.now-playing .vu-volume .mute-btn:hover {
border-color: var(--copper);
color: var(--copper);
background: rgba(224, 128, 56, 0.06);
}
.now-playing .vu-volume .mute-btn svg {
width: 14px;
height: 14px;
fill: currentColor;
}
.now-playing .vu-volume #volume-slider {
-webkit-appearance: none;
appearance: none;
width: 80px;
height: 2px;
background: var(--rule-strong);
border-radius: 0;
margin: 0;
padding: 0;
cursor: pointer;
flex: none;
}
.now-playing .vu-volume #volume-slider::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 10px;
height: 10px;
background: var(--copper);
border-radius: 50%;
box-shadow: 0 0 8px var(--copper-glow);
border: 0;
cursor: grab;
}
.now-playing .vu-volume #volume-slider::-moz-range-thumb {
width: 10px;
height: 10px;
background: var(--copper);
border-radius: 50%;
border: 0;
cursor: grab;
}
.now-playing .vu-volume #volume-slider::-moz-range-track {
height: 2px;
background: var(--rule-strong);
border-radius: 0;
}
.now-playing .vu-meter {
position: relative;
width: 140px;
height: 60px;
background: linear-gradient(180deg, #1a1610 0%, #0e0c08 100%);
border: 1px solid var(--rule-strong);
border-radius: 4px 4px 0 0;
overflow: hidden;
box-shadow: inset 0 2px 6px rgba(0,0,0,0.5), inset 0 0 30px rgba(224,128,56,0.08);
flex-shrink: 0;
}
.now-playing .vu-meter::before {
content: "";
position: absolute;
inset: 0;
/* 11 grid lines (every 9°) drawn ONLY in the needle's -45°..+45°
swing range. No mask — the conic-gradient is explicitly transparent
outside the 90° active wedge so the leftmost line aligns with the
needle's rest position (proper zero). */
background: conic-gradient(from 315deg at 50% 100%,
rgba(242, 235, 220, 0.18) 0deg 0.5deg,
transparent 0.5deg 9deg,
rgba(242, 235, 220, 0.18) 9deg 9.5deg,
transparent 9.5deg 18deg,
rgba(242, 235, 220, 0.18) 18deg 18.5deg,
transparent 18.5deg 27deg,
rgba(242, 235, 220, 0.18) 27deg 27.5deg,
transparent 27.5deg 36deg,
rgba(242, 235, 220, 0.18) 36deg 36.5deg,
transparent 36.5deg 45deg,
rgba(242, 235, 220, 0.25) 45deg 45.5deg, /* slightly brighter centre line at 0 */
transparent 45.5deg 54deg,
rgba(242, 235, 220, 0.18) 54deg 54.5deg,
transparent 54.5deg 63deg,
rgba(242, 235, 220, 0.18) 63deg 63.5deg,
transparent 63.5deg 72deg,
rgba(242, 235, 220, 0.18) 72deg 72.5deg,
transparent 72.5deg 81deg,
rgba(242, 235, 220, 0.18) 81deg 81.5deg,
transparent 81.5deg 90deg,
rgba(242, 235, 220, 0.18) 90deg 90.5deg,
transparent 90.5deg 360deg);
}
.now-playing .vu-meter::after {
content: "VU";
position: absolute;
bottom: 4px;
left: 50%;
transform: translateX(-50%);
font-family: var(--mono);
font-size: 8px;
letter-spacing: 0.3em;
color: var(--ink-faint);
}
.now-playing .vu-needle {
position: absolute;
bottom: 0;
left: 50%;
width: 1.5px;
height: 88%;
background: linear-gradient(to top, var(--copper) 0%, var(--copper-hi) 70%, var(--ink) 100%);
transform-origin: bottom center;
/* Rest at full-left like a real VU meter at silence (-∞ dB) */
transform: rotate(-45deg);
transition: transform 350ms var(--ease);
box-shadow: 0 0 8px var(--copper-glow);
}
.now-playing .vu-readout {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
letter-spacing: 0.06em;
font-variant-numeric: tabular-nums;
display: flex;
flex-direction: column;
gap: 4px;
line-height: 1.2;
white-space: nowrap;
}
.now-playing .vu-readout strong {
color: var(--copper);
font-weight: 400;
}
/* Mobile VU cluster: stack below controls */
@media (max-width: 720px) {
.now-playing .controls { flex-wrap: wrap; }
.now-playing .vu-cluster {
margin-left: 0;
width: 100%;
justify-content: space-between;
margin-top: 12px;
}
.now-playing .vu-meter { width: 110px; height: 50px; }
.now-playing .meta-grid {
grid-template-columns: 1fr;
}
.now-playing .meta-cell {
border-right: 0;
border-bottom: 1px solid var(--rule);
padding: 12px 0;
}
.now-playing .meta-cell:last-child {
border-bottom: 0;
padding-left: 0;
}
}
/* ════════════════════════════════════════════════════════════════
STUDIO REFERENCE — editorial styling for non-player tabs
(Library, Quick Access, Settings, Display)
════════════════════════════════════════════════════════════════ */
/* Common: each tab container is a flat editorial canvas (no card chrome) */
.browser-container,
.scripts-container,
.settings-container,
.display-container,
.script-management {
background: transparent !important;
border: 0 !important;
padding: 0 !important;
box-shadow: none !important;
margin-top: 14px;
}
/* ─── LIBRARY (browser) ───────────────────────────────────── */
/* Breadcrumb — italic serif, copper terminal */
.browser-container .breadcrumb {
background: transparent !important;
border: 0 !important;
border-bottom: 1px solid var(--rule) !important;
border-radius: 0 !important;
padding: 14px 0 !important;
margin-bottom: 24px;
font-family: var(--serif);
font-style: italic;
font-size: 18px;
font-variation-settings: 'opsz' 30;
color: var(--ink-soft);
display: flex;
align-items: center;
gap: 4px;
flex-wrap: wrap;
}
.browser-container .breadcrumb-home,
.browser-container .breadcrumb-item {
color: var(--ink-soft);
text-decoration: none;
cursor: pointer;
transition: color 180ms var(--ease);
background: transparent;
border: 0;
padding: 0;
font-family: inherit;
font-style: italic;
font-size: inherit;
}
.browser-container .breadcrumb-home:hover,
.browser-container .breadcrumb-item:hover { color: var(--copper); }
.browser-container .breadcrumb-item:last-of-type {
color: var(--ink);
font-weight: 500;
}
.browser-container .breadcrumb-separator {
color: var(--ink-faint);
margin: 0 8px;
font-style: normal;
opacity: 1;
font-family: var(--mono);
font-size: 14px;
}
/* Toolbar — hairline groups, no card */
.browser-container .browser-toolbar {
background: transparent !important;
border: 0 !important;
border-bottom: 1px solid var(--rule) !important;
border-radius: 0 !important;
padding: 0 0 16px 0 !important;
margin-bottom: 28px;
gap: 14px;
display: flex;
align-items: center;
flex-wrap: wrap;
}
.browser-container .browser-toolbar-left {
display: flex;
align-items: center;
gap: 10px;
}
.browser-container .browser-toolbar-right {
margin-left: auto;
display: flex;
align-items: center;
gap: 10px;
}
/* View-toggle: square hairline pills with copper active */
.browser-container .view-toggle {
display: flex;
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
border-radius: 0 !important;
padding: 0 !important;
overflow: hidden;
}
.browser-container .view-toggle-btn,
.browser-container .browser-refresh-btn,
.browser-container .browser-play-all-btn {
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
color: var(--ink-mute) !important;
width: 36px !important;
height: 36px !important;
padding: 0 !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 180ms var(--ease);
box-sizing: border-box;
}
.browser-container .view-toggle .view-toggle-btn {
border-right: 1px solid var(--rule-strong) !important;
}
.browser-container .view-toggle .view-toggle-btn:last-child {
border-right: 0 !important;
}
.browser-container .view-toggle-btn:hover,
.browser-container .browser-refresh-btn:hover,
.browser-container .browser-play-all-btn:hover {
color: var(--copper) !important;
background: rgba(224, 128, 56, 0.06) !important;
}
.browser-container .view-toggle-btn.active {
background: var(--ink) !important;
color: var(--bg-deep) !important;
}
.browser-container .browser-refresh-btn,
.browser-container .browser-play-all-btn {
border: 1px solid var(--rule-strong) !important;
}
.browser-container .browser-play-all-btn {
color: var(--copper) !important;
border-color: var(--copper) !important;
}
/* Search — underline-only editorial input */
.browser-container .browser-search-wrapper {
background: transparent !important;
border: 0 !important;
border-bottom: 1px solid var(--rule-strong) !important;
border-radius: 0 !important;
padding: 4px 0 !important;
display: inline-flex;
align-items: center;
gap: 8px;
transition: border-color 180ms var(--ease);
min-width: 220px;
}
.browser-container .browser-search-wrapper:focus-within {
border-bottom-color: var(--copper) !important;
}
.browser-container .browser-search-input {
background: transparent !important;
border: 0 !important;
color: var(--ink) !important;
font-family: var(--sans);
font-size: 14px;
padding: 4px 0 !important;
outline: none;
flex: 1;
min-width: 0;
}
.browser-container .browser-search-input::placeholder { color: var(--ink-mute); }
.browser-container .browser-search-icon { color: var(--ink-mute); flex-shrink: 0; }
.browser-container .browser-search-clear {
background: transparent !important;
border: 0 !important;
color: var(--ink-mute);
cursor: pointer;
padding: 0 !important;
}
.browser-container .browser-search-clear:hover { color: var(--copper); }
/* Items per page label + select */
.browser-container .items-per-page-label {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
display: inline-flex;
align-items: center;
gap: 8px;
}
.browser-container .items-per-page-label select {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
color: var(--ink) !important;
border-radius: 0 !important;
font-family: var(--mono);
font-size: 11px;
padding: 6px 10px !important;
cursor: pointer;
}
/* Browser grid — editorial cards */
.browser-container .browser-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 32px 24px;
padding: 0 !important;
}
.browser-container .browser-item {
background: transparent !important;
border: 0 !important;
border-radius: 0 !important;
padding: 0 !important;
cursor: pointer;
transition: transform 280ms var(--ease);
}
.browser-container .browser-item:hover {
transform: translateY(-3px);
background: transparent !important;
box-shadow: none !important;
}
.browser-container .browser-thumb-wrapper {
position: relative;
aspect-ratio: 1;
background: var(--bg-card);
border: 1px solid var(--rule);
border-radius: 0 !important;
overflow: hidden;
box-shadow: 0 14px 30px -10px rgba(0,0,0,0.5);
transition: all 280ms var(--ease);
margin-bottom: 14px;
}
.browser-container .browser-item:hover .browser-thumb-wrapper {
border-color: var(--copper);
box-shadow: 0 20px 40px -10px rgba(0,0,0,0.65);
}
.browser-container .browser-thumbnail {
width: 100%;
height: 100%;
object-fit: cover;
border-radius: 0 !important;
}
.browser-container .browser-icon {
color: var(--ink-mute);
}
.browser-container .browser-item-info { padding: 0; }
.browser-container .browser-item-name {
font-family: var(--serif);
font-style: normal;
font-weight: 400;
font-size: 16px;
color: var(--ink);
font-variation-settings: 'opsz' 18;
letter-spacing: 0;
line-height: 1.25;
margin-bottom: 4px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.browser-container .browser-item-meta,
.browser-container .browser-item-type {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--ink-mute);
}
.browser-container .browser-play-overlay {
background: rgba(14, 13, 11, 0.55);
}
.browser-container .browser-play-overlay svg {
fill: var(--ink);
filter: drop-shadow(0 4px 12px rgba(0,0,0,0.6));
}
.browser-container .browser-empty {
grid-column: 1 / -1;
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 16px;
text-align: center;
padding: 60px 20px;
font-variation-settings: 'opsz' 30;
}
/* List view — editorial table */
.browser-container .browser-list {
background: transparent !important;
border: 1px solid var(--rule);
border-radius: 0 !important;
}
.browser-container .browser-list-header {
background: var(--bg-paper) !important;
border-bottom: 1px solid var(--rule-strong) !important;
color: var(--ink-mute) !important;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 12px 16px;
}
.browser-container .browser-list-item {
border-bottom: 1px solid var(--rule);
transition: background 180ms var(--ease);
padding: 10px 16px;
}
.browser-container .browser-list-item:hover { background: var(--bg-paper); }
.browser-container .browser-list-name {
font-family: var(--serif);
font-style: normal;
font-size: 15px;
color: var(--ink);
font-variation-settings: 'opsz' 18;
}
.browser-container .browser-list-bitrate,
.browser-container .browser-list-duration,
.browser-container .browser-list-size {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
font-variant-numeric: tabular-nums;
}
/* Pagination — hairline buttons */
.browser-container .pagination {
background: transparent !important;
border: 0 !important;
border-top: 1px solid var(--rule) !important;
margin-top: 36px;
padding-top: 22px !important;
display: flex;
align-items: center;
gap: 18px;
}
.browser-container .pagination button {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
color: var(--ink-soft) !important;
border-radius: 0 !important;
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 8px 16px !important;
transition: all 180ms var(--ease);
cursor: pointer;
}
.browser-container .pagination button:hover:not(:disabled) {
color: var(--copper) !important;
border-color: var(--copper) !important;
}
.browser-container .pagination button:disabled { opacity: 0.35; cursor: not-allowed; }
.browser-container .pagination-center {
display: inline-flex;
align-items: center;
gap: 8px;
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
}
.browser-container .page-input {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
color: var(--ink) !important;
border-radius: 0 !important;
font-family: var(--mono);
font-size: 11px;
padding: 6px 8px !important;
width: 60px;
text-align: center;
}
.browser-container .pagination-showing {
margin-left: auto;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--ink-faint);
}
/* ─── QUICK ACCESS — console rail ─────────────────────────── */
.scripts-container .scripts-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
gap: 1px;
background: var(--rule);
border: 1px solid var(--rule-strong);
padding: 0;
margin: 0;
}
.scripts-container .script-btn,
.scripts-container .link-card {
background: var(--bg-card) !important;
border: 0 !important;
border-radius: 0 !important;
padding: 26px 18px !important;
color: var(--ink) !important;
transition: all 200ms var(--ease) !important;
text-align: center;
display: flex !important;
flex-direction: column !important;
align-items: center !important;
justify-content: center !important;
cursor: pointer;
min-height: 120px;
}
.scripts-container .script-btn:hover,
.scripts-container .link-card:hover {
background: var(--bg-card-2) !important;
color: var(--copper) !important;
transform: none !important;
}
.scripts-container .script-btn .browser-icon,
.scripts-container .link-card .browser-icon {
color: var(--ink-soft);
margin-bottom: 14px;
font-size: 22px;
width: 32px;
height: 32px;
display: flex;
align-items: center;
justify-content: center;
transition: all 200ms var(--ease);
}
.scripts-container .script-btn:hover .browser-icon,
.scripts-container .link-card:hover .browser-icon {
color: var(--copper);
transform: translateY(-2px);
}
.scripts-container .script-btn .browser-item-name,
.scripts-container .link-card .browser-item-name {
font-family: var(--serif);
font-style: italic;
font-weight: 400;
font-size: 15px;
color: inherit;
font-variation-settings: 'opsz' 18;
letter-spacing: 0;
line-height: 1.2;
margin: 0;
}
.scripts-container .scripts-empty {
grid-column: 1 / -1;
background: var(--bg-card);
padding: 80px 24px;
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 16px;
text-align: center;
font-variation-settings: 'opsz' 30;
border: 1px dashed var(--rule-strong);
}
.scripts-container .scripts-empty p { color: inherit; }
/* ─── SETTINGS — numbered editorial cards ─────────────────── */
.settings-container { counter-reset: sr-section; }
.settings-container .settings-section {
background: var(--bg-card) !important;
border: 1px solid var(--rule) !important;
border-radius: 0 !important;
padding: 28px 32px !important;
margin-bottom: 16px;
box-shadow: none !important;
transition: border-color 200ms var(--ease);
position: relative;
counter-increment: sr-section;
}
.settings-container .settings-section:hover {
border-color: var(--rule-strong) !important;
}
.settings-container .settings-section summary {
font-family: var(--serif);
font-weight: 400;
font-style: normal;
font-size: 24px;
letter-spacing: -0.015em;
color: var(--ink);
font-variation-settings: 'opsz' 60;
padding: 0 0 14px 0 !important;
border: 0 !important;
background: transparent !important;
cursor: pointer;
list-style: none;
position: relative;
display: flex;
align-items: baseline;
gap: 14px;
}
.settings-container .settings-section summary::-webkit-details-marker { display: none; }
.settings-container .settings-section summary::before {
content: "5." counter(sr-section, decimal-leading-zero);
font-family: var(--mono);
font-style: normal;
font-size: 10px;
letter-spacing: 0.22em;
color: var(--copper);
flex-shrink: 0;
line-height: 2.2;
}
.settings-container .settings-section summary::after {
content: "↓";
margin-left: auto;
font-family: var(--sans);
font-size: 16px;
color: var(--ink-mute);
transition: transform 240ms var(--ease);
font-weight: 400;
}
.settings-container .settings-section[open] summary::after {
transform: rotate(180deg);
}
.settings-container .settings-section-content {
padding-top: 18px;
border-top: 1px solid var(--rule);
}
.settings-container .settings-section-description {
font-family: var(--serif);
font-style: italic;
font-size: 14px;
color: var(--ink-soft);
line-height: 1.55;
font-variation-settings: 'opsz' 18;
margin-bottom: 22px;
}
/* Settings tables */
.settings-container .scripts-table {
border: 1px solid var(--rule);
border-collapse: collapse;
width: 100%;
background: transparent;
font-family: var(--sans);
}
.settings-container .scripts-table thead {
background: var(--bg-paper);
}
.settings-container .scripts-table th {
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
padding: 12px 14px;
text-align: left;
border-bottom: 1px solid var(--rule-strong);
font-weight: 400;
}
.settings-container .scripts-table td {
padding: 14px;
border-bottom: 1px solid var(--rule);
color: var(--ink-soft);
font-size: 13px;
vertical-align: middle;
}
.settings-container .scripts-table tr:last-child td { border-bottom: 0; }
.settings-container .scripts-table tr:hover td { background: rgba(255,255,255,0.02); }
.settings-container .scripts-table .name-with-icon {
color: var(--ink);
font-family: var(--serif);
font-style: normal;
font-size: 15px;
font-variation-settings: 'opsz' 18;
}
.settings-container .scripts-table .path-cell,
.settings-container .scripts-table .mono {
font-family: var(--mono);
font-size: 11px;
color: var(--ink-mute);
}
/* Add card — editorial dashed border */
.settings-container .add-card {
background: transparent !important;
border: 1px dashed var(--rule-strong) !important;
border-radius: 0 !important;
padding: 16px !important;
margin-top: 16px;
transition: all 200ms var(--ease);
color: var(--ink-mute) !important;
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
}
.settings-container .add-card:hover {
border-color: var(--copper) !important;
border-style: solid !important;
color: var(--copper) !important;
background: rgba(224, 128, 56, 0.04) !important;
}
.settings-container .add-card-icon {
font-family: var(--serif);
font-weight: 300;
font-size: 24px;
color: inherit;
line-height: 1;
}
/* Audio device selector inside settings */
.settings-container .audio-device-selector {
display: flex;
flex-direction: column;
gap: 14px;
}
.settings-container .audio-device-selector label {
display: flex;
flex-direction: column;
gap: 8px;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
color: var(--ink-mute);
}
.settings-container .audio-device-selector select {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
color: var(--ink) !important;
border-radius: 0 !important;
font-family: var(--sans);
font-size: 13px;
padding: 10px 12px !important;
cursor: pointer;
}
.settings-container .audio-device-status {
font-family: var(--mono);
font-size: 11px;
letter-spacing: 0.12em;
text-transform: uppercase;
padding: 8px 12px;
border: 1px solid var(--rule);
background: var(--bg-paper);
display: inline-flex;
align-items: center;
gap: 8px;
}
.settings-container .audio-device-status.active { color: var(--jade); border-color: var(--jade); }
.settings-container .audio-device-status.available { color: var(--amber); border-color: var(--amber); }
.settings-container .audio-device-status.unavailable { color: var(--rust); border-color: var(--rust); }
.settings-container .audio-device-status::before {
content: "●";
font-size: 10px;
color: currentColor;
}
/* Folder badges */
.settings-container .folder-disabled-badge,
.settings-container .folder-unavailable-badge {
background: transparent !important;
border: 1px solid currentColor !important;
border-radius: 0 !important;
font-family: var(--mono);
font-size: 9px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 3px 8px !important;
color: var(--amber);
}
.settings-container .folder-unavailable-badge { color: var(--rust); }
/* Empty state */
.settings-container .empty-state {
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 14px;
font-variation-settings: 'opsz' 18;
padding: 40px 20px;
text-align: center;
}
.settings-container .empty-state-illustration {
color: var(--ink-faint);
}
.settings-container .empty-state-illustration svg {
width: 48px;
height: 48px;
margin-bottom: 14px;
fill: none;
stroke: currentColor;
stroke-width: 1.5;
}
/* Action buttons (edit/delete inside table rows) */
.settings-container .action-btn,
.settings-container .action-buttons button {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
color: var(--ink-soft) !important;
border-radius: 0 !important;
width: 30px;
height: 30px;
padding: 0 !important;
display: inline-flex !important;
align-items: center;
justify-content: center;
cursor: pointer;
transition: all 180ms var(--ease);
}
.settings-container .action-btn:hover,
.settings-container .action-buttons button:hover {
color: var(--copper) !important;
border-color: var(--copper) !important;
}
.settings-container .action-btn.danger:hover,
.settings-container .action-buttons button.danger:hover {
color: var(--rust) !important;
border-color: var(--rust) !important;
}
/* ─── DISPLAY tab ─────────────────────────────────────────── */
.display-container .display-monitors {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 18px;
}
.display-container .display-monitors > .empty-state-illustration {
grid-column: 1 / -1;
text-align: center;
padding: 80px 24px;
color: var(--ink-mute);
font-family: var(--serif);
font-style: italic;
font-size: 16px;
font-variation-settings: 'opsz' 30;
border: 1px dashed var(--rule);
}
.display-container .display-monitors > .empty-state-illustration svg {
width: 56px;
height: 56px;
margin-bottom: 14px;
color: var(--ink-faint);
}
/* Monitor card (rendered by JS — accept any direct children as cards) */
.display-container .display-monitors > div:not(.empty-state-illustration) {
background: var(--bg-card);
border: 1px solid var(--rule);
padding: 22px 24px;
transition: border-color 200ms var(--ease);
border-radius: 0;
}
.display-container .display-monitors > div:not(.empty-state-illustration):hover {
border-color: var(--rule-strong);
}
/* Headings inside any monitor card */
.display-container .display-monitors h3 {
font-family: var(--serif);
font-style: normal;
font-weight: 400;
font-size: 18px;
color: var(--ink);
font-variation-settings: 'opsz' 30;
letter-spacing: -0.01em;
margin-bottom: 8px;
}
.display-container .display-monitors button {
background: transparent;
border: 1px solid var(--rule-strong);
color: var(--ink-soft);
border-radius: 0;
font-family: var(--mono);
font-size: 10px;
letter-spacing: 0.18em;
text-transform: uppercase;
padding: 8px 14px;
cursor: pointer;
transition: all 180ms var(--ease);
}
.display-container .display-monitors button:hover {
color: var(--copper);
border-color: var(--copper);
}
/* ─── ICON SELECT POPUP & TRIGGER (used by settings dialogs) ─── */
.icon-select-trigger {
background: transparent !important;
border: 1px solid var(--rule-strong) !important;
border-radius: 0 !important;
color: var(--ink) !important;
font-family: var(--mono);
font-size: 12px;
padding: 8px 12px !important;
cursor: pointer;
transition: border-color 180ms var(--ease);
}
.icon-select-trigger:hover {
border-color: var(--copper) !important;
color: var(--copper) !important;
}
.icon-select-popup {
background: var(--bg-card) !important;
border: 1px solid var(--rule-strong) !important;
border-radius: 0 !important;
box-shadow: 0 14px 40px rgba(0,0,0,0.5) !important;
}
.icon-select-cell {
border-radius: 0 !important;
color: var(--ink-soft) !important;
font-family: var(--mono);
font-size: 10px;
}
.icon-select-cell:hover {
background: rgba(224, 128, 56, 0.06) !important;
color: var(--copper) !important;
}
/* Mobile: tighten padding for non-player tabs */
@media (max-width: 720px) {
.browser-container .browser-grid { gap: 22px 16px; }
.scripts-container .scripts-grid { grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); }
.scripts-container .script-btn,
.scripts-container .link-card { padding: 18px 12px !important; min-height: 100px; }
.settings-container .settings-section { padding: 20px !important; }
.settings-container .settings-section summary { font-size: 20px; }
.browser-container .breadcrumb { font-size: 15px; }
}