diff --git a/media_server/static/css/styles.css b/media_server/static/css/styles.css index c7ac6d8..189484e 100644 --- a/media_server/static/css/styles.css +++ b/media_server/static/css/styles.css @@ -4375,6 +4375,18 @@ header .brand-sub { box-shadow: 0 0 12px var(--copper-glow); } +/* Tablet range: editorial top-tabs but compressed so all 5 labels fit. */ +@media (min-width: 721px) and (max-width: 980px) { + .tab-btn { + padding: 14px 12px 12px; + font-size: 12px; + gap: 8px; + } + .tab-btn.active { font-size: 15px; } + .tab-btn .tab-num { font-size: 9px; letter-spacing: 0.12em; } + .container { padding-left: 28px; padding-right: 28px; } +} + /* ─── Update + connection banners (editorial) ────────────────── */ .update-banner, .connection-banner { @@ -4512,7 +4524,7 @@ header .brand-sub { margin-top: 28px; } -@media (max-width: 980px) { +@media (max-width: 1240px) { .player-layout, .now-playing { grid-template-columns: 1fr; @@ -5982,6 +5994,25 @@ dialog { padding: 0; max-width: 560px; width: 90%; + max-height: 90vh; +} +dialog[open] { + display: flex; + flex-direction: column; +} +dialog form { + display: flex; + flex-direction: column; + min-height: 0; + flex: 1 1 auto; +} +.dialog-header { flex: 0 0 auto; } +.dialog-footer { flex: 0 0 auto; } +.dialog-body { + flex: 1 1 auto; + min-height: 0; + overflow-y: auto; + overscroll-behavior: contain; } dialog::backdrop { background: rgba(14, 13, 11, 0.7); @@ -6442,6 +6473,17 @@ footer .separator { color: var(--ink-ghost); margin: 0 8px; } .mini-player { padding: 12px 16px; gap: 16px; } .tab-btn { padding: 14px 12px 12px; font-size: 12px; } .tab-btn.active { font-size: 15px; } + /* Override legacy mobile rule that hid every .tab-btn span (numbers + labels) */ + .tab-btn span { display: inline; } + .tab-btn .tab-num { display: none; } + .tab-bar { + flex-wrap: nowrap; + overflow-x: auto; + overscroll-behavior-x: contain; + scrollbar-width: none; + } + .tab-bar::-webkit-scrollbar { display: none; } + .tab-btn { flex: 0 0 auto; } .breadcrumb { font-size: 14px; } .browser-toolbar { flex-wrap: wrap; } .auth-modal { padding: 28px 22px; } @@ -6914,6 +6956,8 @@ body.audio-spectrum-live .now-playing .spectrum span { gap: 18px; margin-top: 0; justify-content: flex-start; + flex-wrap: wrap; + row-gap: 16px; } .now-playing .btn-trans { @@ -8176,3 +8220,581 @@ select option { .settings-container .settings-section summary { font-size: 20px; } .browser-container .breadcrumb { font-size: 15px; } } + +/* ════════════════════════════════════════════════════════════════════ + STUDIO REFERENCE — POCKET EDITION + Dedicated mobile layout. Bottom-nav, single-column hero player, + compact chrome. Last in the cascade so it overrides all preceding + legacy + editorial rules. + ════════════════════════════════════════════════════════════════════ */ + +@media (max-width: 720px) { + :root { + --pocket-nav-h: 62px; + --pocket-mini-h: 60px; + } + + /* ─── Top folio strip ─────────────────────────────────── + Collapse the two corner folios into a single hairline strip at + the very top. Right folio (volume / version) is redundant on + phones — tuck it behind the nav into the version label only. + */ + body > .folio.tl { + top: 0 !important; + left: 0 !important; + right: auto !important; + width: auto; + padding: 7px 12px 7px max(12px, env(safe-area-inset-left)); + font-size: 8.5px !important; + letter-spacing: 0.18em !important; + background: linear-gradient(180deg, rgba(14, 13, 11, 0.7) 30%, transparent 100%); + -webkit-backdrop-filter: blur(8px); + backdrop-filter: blur(8px); + } + :root[data-theme="light"] body > .folio.tl { + background: linear-gradient(180deg, rgba(245, 241, 234, 0.85) 30%, transparent 100%); + } + /* Right folio (volume / version) is redundant on phones — hide it. + Version is still discoverable via Settings / About in the API. */ + body > .folio.tr { display: none !important; } + + /* ─── Container: leave room for top folio + bottom nav + mini-player ─── */ + .container { + padding-top: 40px !important; + padding-bottom: calc(var(--pocket-nav-h) + 24px + env(safe-area-inset-bottom)) !important; + } + body.mini-player-visible .container { + padding-bottom: calc(var(--pocket-nav-h) + var(--pocket-mini-h) + 16px + env(safe-area-inset-bottom)) !important; + } + + /* ─── Header: tight 2-row layout ───────────────────────── */ + header { + grid-template-columns: 1fr !important; + gap: 8px !important; + margin-bottom: 18px !important; + padding-bottom: 14px !important; + } + header .brand-name { font-size: 22px !important; } + header .brand-sub { + font-size: 8px !important; + letter-spacing: 0.4em !important; + margin-top: 4px !important; + } + .header-toolbar { + grid-column: 1 !important; + justify-self: center !important; + flex-wrap: wrap; + justify-content: center; + gap: 0 !important; + } + .header-btn, + .header-btn-logout, + .header-link { + width: 34px !important; + height: 34px !important; + } + .header-toolbar-sep { display: none !important; } + /* Header links preserve their distinctive look but shrink */ + .header-locale { + height: 34px !important; + padding: 0 8px !important; + font-size: 10px !important; + } + + /* ─── Bottom Tab Bar (replaces top tab bar) ────────────── */ + .tab-bar { + position: fixed !important; + bottom: 0 !important; + left: 0 !important; + right: 0 !important; + margin: 0 !important; + padding: 0 max(8px, env(safe-area-inset-left)) env(safe-area-inset-bottom) max(8px, env(safe-area-inset-right)) !important; + background: rgba(14, 13, 11, 0.94) !important; + -webkit-backdrop-filter: blur(20px) saturate(180%); + backdrop-filter: blur(20px) saturate(180%); + border: 0 !important; + border-top: 1px solid var(--rule-strong) !important; + z-index: 999; + overflow: visible !important; + display: grid; + grid-template-columns: repeat(5, 1fr); + gap: 0; + box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.35); + } + :root[data-theme="light"] .tab-bar { + background: rgba(245, 241, 234, 0.92) !important; + box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.10); + } + /* Hairline copper accent strip floating above active tab */ + .tab-bar::before { + content: ""; + position: absolute; + top: -1px; + left: 16px; + right: 16px; + height: 1px; + background: linear-gradient(90deg, + transparent 0%, + var(--copper) 30%, + var(--copper-hi) 50%, + var(--copper) 70%, + transparent 100%); + opacity: 0.35; + pointer-events: none; + } + + /* Re-enable labels (legacy mobile rule hid all spans inside .tab-btn) */ + .tab-btn span, + .tab-btn span:not(.tab-num) { + display: inline-block !important; + } + + .tab-btn { + height: var(--pocket-nav-h) !important; + padding: 10px 4px !important; + display: flex !important; + flex-direction: column !important; + align-items: center !important; + justify-content: center !important; + gap: 4px !important; + font-family: var(--mono) !important; + font-style: normal !important; + font-size: 9.5px !important; + font-weight: 400 !important; + letter-spacing: 0.12em !important; + text-transform: uppercase; + color: var(--ink-faint) !important; + line-height: 1 !important; + } + .tab-btn .tab-num { + font-size: 11px !important; + letter-spacing: 0.2em !important; + color: var(--ink-mute) !important; + } + .tab-btn span:not(.tab-num) { + font-family: var(--mono) !important; + font-size: 9px !important; + letter-spacing: 0.1em !important; + max-width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .tab-btn:hover { + color: var(--ink-soft) !important; + } + .tab-btn.active { + color: var(--copper) !important; + font-family: var(--mono) !important; + font-style: normal !important; + font-size: 9.5px !important; + } + .tab-btn.active .tab-num, + .tab-btn.active span:not(.tab-num) { + color: var(--copper) !important; + } + /* Active marker: copper bar at TOP of tab (hairline + glow) */ + .tab-btn.active::after { + top: -1px !important; + bottom: auto !important; + left: 14% !important; + right: 14% !important; + height: 2px !important; + background: var(--copper) !important; + box-shadow: + 0 0 12px var(--copper-glow), + 0 0 28px var(--copper-glow) !important; + } + + /* ─── Mini-player: float above bottom nav ─────────────── */ + .mini-player { + bottom: calc(var(--pocket-nav-h) + env(safe-area-inset-bottom)) !important; + padding: 9px 14px !important; + gap: 12px !important; + border-top: 1px solid var(--rule); + border-bottom: 1px solid var(--rule); + background: rgba(33, 30, 24, 0.92) !important; + -webkit-backdrop-filter: blur(24px) saturate(160%); + backdrop-filter: blur(24px) saturate(160%); + box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.25); + } + :root[data-theme="light"] .mini-player { + background: rgba(255, 252, 246, 0.94) !important; + } + .mini-player::before { + height: 1px !important; + } + .mini-album-art { + width: 38px !important; + height: 38px !important; + border-radius: 2px; + } + .mini-player-info { + min-width: 0 !important; + flex: 1; + gap: 10px !important; + } + .mini-track-title { + font-family: var(--serif); + font-style: italic; + font-weight: 400; + font-size: 13px !important; + color: var(--ink) !important; + font-variation-settings: 'opsz' 30; + } + .mini-artist { + font-family: var(--mono); + font-size: 9.5px !important; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--ink-mute) !important; + } + .mini-progress-container { + display: none !important; /* progress lives on the ::before line */ + } + .mini-volume-container { display: none !important; } + .mini-controls { gap: 4px !important; } + .mini-nav-btn { display: none !important; } + .mini-control-btn { + width: 38px !important; + height: 38px !important; + background: transparent !important; + border: 1px solid var(--rule-strong) !important; + border-radius: 50%; + } + .mini-control-btn:hover { + border-color: var(--copper) !important; + background: rgba(224, 128, 56, 0.08) !important; + color: var(--copper) !important; + } + .mini-control-btn svg { + width: 16px !important; + height: 16px !important; + } + + /* ─── Player tab — single column hero ─────────────────── */ + .player-layout, + .now-playing { + grid-template-columns: 1fr !important; + gap: 28px !important; + margin-top: 4px !important; + } + + /* Vinyl stage: centered, capped at sensible touch size */ + .album-art-container.vinyl-stage { + max-width: 320px; + width: 78%; + margin: 0 auto !important; + } + .vinyl-stage .vinyl { width: 92%; } + .vinyl-stage .vinyl-label { + box-shadow: + inset 0 0 24px rgba(0, 0, 0, 0.4), + 0 0 0 3px var(--bg-deep), + 0 0 0 4px var(--copper-lo); + } + .vinyl-stage .tonearm { + top: -8% !important; + right: -6% !important; + width: 60% !important; + height: 60% !important; + } + + /* Track masthead text: centered, condensed cadence */ + .track-masthead { text-align: center; } + .track-masthead > .kicker { + margin-bottom: 14px !important; + gap: 10px !important; + justify-content: center; + font-size: 9px !important; + letter-spacing: 0.36em !important; + } + .track-masthead > .kicker::before { flex-basis: 18px !important; } + .track-masthead > .kicker::after { flex-basis: 18px !important; flex-grow: 0 !important; } + + .now-playing #track-title, + .player-layout #track-title { + font-size: clamp(28px, 8vw, 38px) !important; + line-height: 1 !important; + margin-bottom: 10px !important; + letter-spacing: -0.02em !important; + } + .now-playing #artist, + .player-layout #artist { + font-size: 17px !important; + margin-bottom: 4px !important; + } + .now-playing #album, + .player-layout #album { + font-size: 10px !important; + letter-spacing: 0.18em !important; + text-transform: uppercase; + color: var(--ink-mute) !important; + } + + /* Meta-grid: 2 columns side-by-side with hairline divider */ + .now-playing .meta-grid, + .meta-grid.meta-grid-2, + .player-layout .meta-grid { + grid-template-columns: 1fr 1fr !important; + margin-top: 22px !important; + } + .now-playing .meta-cell, + .meta-grid .meta-cell, + .player-layout .meta-cell { + border-right: 1px solid var(--rule) !important; + border-bottom: 0 !important; + padding: 12px 14px !important; + text-align: left; + min-width: 0; + } + .now-playing .meta-cell:nth-child(2n), + .meta-grid .meta-cell:nth-child(2n), + .player-layout .meta-cell:nth-child(2n) { + border-right: 0 !important; + padding-right: 0 !important; + } + .now-playing .meta-cell:first-child, + .meta-grid .meta-cell:first-child, + .player-layout .meta-cell:first-child { + padding-left: 0 !important; + } + .meta-cell .label, + .meta-cell .meta-label { + font-size: 8.5px !important; + letter-spacing: 0.28em !important; + } + .meta-cell .value, + .meta-cell .meta-value { + font-size: 14px !important; + } + + /* Spectrum: shrink so it doesn't dominate */ + .now-playing .spectrum, + .player-layout .spectrum { + height: 26px !important; + margin: 18px 0 4px 0 !important; + } + + /* Transport: bigger touch targets, centered, no wrap */ + .transport { margin-top: 14px !important; } + .progress-row { + gap: 12px !important; + margin-bottom: 22px !important; + } + .progress-row .timecode { font-size: 11px !important; } + + .now-playing .controls, + .player-layout .controls { + justify-content: center !important; + gap: 28px !important; + flex-wrap: nowrap !important; + } + .now-playing .controls .btn-trans, + .player-layout .controls .btn-trans { + width: 50px !important; + height: 50px !important; + } + .now-playing .controls .btn-trans.primary, + .player-layout .controls .btn-trans.primary { + width: 68px !important; + height: 68px !important; + } + .now-playing .controls .btn-trans svg { width: 20px !important; height: 20px !important; } + .now-playing .controls .btn-trans.primary svg { width: 26px !important; height: 26px !important; } + + /* VU meter is decorative on a phone — hide it. Volume becomes + its own full-width hairline row beneath the controls. */ + .now-playing .vu-cluster, + .player-layout .vu-cluster { + display: flex !important; + flex-direction: row !important; + align-items: center; + justify-content: space-between; + gap: 14px !important; + width: 100% !important; + margin: 18px 0 0 0 !important; + padding-top: 16px !important; + border-top: 1px solid var(--rule); + } + .now-playing .vu-meter, + .player-layout .vu-meter { display: none !important; } + .now-playing .vu-readout, + .player-layout .vu-readout { + flex-direction: row !important; + gap: 14px !important; + font-size: 9.5px !important; + letter-spacing: 0.12em !important; + white-space: nowrap; + } + .now-playing .vu-volume, + .player-layout .vu-volume { + flex: 1 1 auto !important; + min-width: 0 !important; + border-right: 0 !important; + margin-right: 0 !important; + padding-right: 0 !important; + justify-content: flex-end; + gap: 12px !important; + } + .now-playing .vu-volume #volume-slider, + .player-layout .vu-volume #volume-slider { + flex: 1 1 auto !important; + width: 100% !important; + max-width: 200px; + height: 3px !important; + } + .now-playing .vu-volume #volume-slider::-webkit-slider-thumb, + .player-layout .vu-volume #volume-slider::-webkit-slider-thumb { + width: 14px !important; + height: 14px !important; + } + .now-playing .vu-volume .mute-btn, + .player-layout .vu-volume .mute-btn { + width: 36px !important; + height: 36px !important; + } + .now-playing .vu-volume .mute-btn svg, + .player-layout .vu-volume .mute-btn svg { + width: 16px !important; + height: 16px !important; + } + + /* ─── Library / Browser polish ────────────────────────── */ + .browser-container .browser-toolbar { + flex-wrap: wrap !important; + gap: 10px !important; + } + .browser-container .browser-toolbar-right { + margin-left: 0 !important; + } + .browser-search-wrapper { + flex-basis: 100% !important; + order: 10; + max-width: none !important; + } + /* Pagination: column stack, big tap targets */ + .pagination { + flex-direction: column !important; + align-items: stretch !important; + gap: 10px !important; + padding: 18px 0 !important; + border-top: 1px solid var(--rule); + margin-top: 20px; + } + .pagination button { + width: 100% !important; + min-height: 42px; + font-family: var(--mono); + font-size: 11px; + letter-spacing: 0.16em; + text-transform: uppercase; + } + .pagination .pagination-center { + justify-content: center; + order: -1; + } + .pagination-showing { + text-align: center !important; + font-family: var(--mono); + font-size: 10px; + letter-spacing: 0.12em; + color: var(--ink-faint); + } + + /* ─── Settings: card-like rows for tables ─────────────── */ + .settings-container .scripts-table thead { display: none; } + .settings-container .scripts-table, + .settings-container .scripts-table tbody, + .settings-container .scripts-table tr, + .settings-container .scripts-table td { + display: block !important; + width: 100% !important; + } + .settings-container .scripts-table tr { + border: 1px solid var(--rule) !important; + padding: 14px !important; + margin-bottom: 12px !important; + background: rgba(33, 30, 24, 0.32); + } + :root[data-theme="light"] .settings-container .scripts-table tr { + background: rgba(255, 252, 246, 0.6); + } + .settings-container .scripts-table td { + padding: 4px 0 !important; + border: 0 !important; + font-family: var(--sans); + font-size: 13px; + } + .settings-container .scripts-table td:not(:last-child) { + border-bottom: 1px dashed var(--rule) !important; + padding-bottom: 8px !important; + margin-bottom: 8px !important; + } + /* Empty-state row keeps its own block layout */ + .settings-container .scripts-table tr:has(.empty-state), + .settings-container .scripts-table tr td.empty-state { + background: transparent; + border: 0 !important; + padding: 0 !important; + } + + /* ─── Footer: ultra-compact ───────────────────────────── */ + footer { + font-size: 10px !important; + padding: 12px 12px !important; + letter-spacing: 0.04em; + } + footer .separator { margin: 0 4px !important; } + + /* Auth modal: full-bleed feel on phones */ + .auth-modal { + width: 92% !important; + padding: 28px 22px !important; + } +} + +/* ─── Tighter breakpoint for compact phones (<= 420px) ─── */ +@media (max-width: 420px) { + .tab-btn span:not(.tab-num) { font-size: 8px !important; } + .tab-btn .tab-num { font-size: 10px !important; } + + /* Fewest icons in header — surface only critical chrome */ + header .brand-sub { display: none !important; } + header .brand-name { font-size: 20px !important; } + .header-btn[title="API Documentation"], + .header-btn[title="Dynamic background"] { + display: none !important; + } + + /* Tonearm + vinyl tighter still */ + .album-art-container.vinyl-stage { width: 84%; } + .vinyl-stage .tonearm { + top: -10% !important; + right: -8% !important; + width: 64% !important; + height: 64% !important; + } + + .now-playing #track-title, + .player-layout #track-title { + font-size: clamp(24px, 8.5vw, 32px) !important; + } + + /* Transport: keep readable but shrink the gap */ + .now-playing .controls, + .player-layout .controls { gap: 22px !important; } + .now-playing .controls .btn-trans, + .player-layout .controls .btn-trans { width: 46px !important; height: 46px !important; } + .now-playing .controls .btn-trans.primary, + .player-layout .controls .btn-trans.primary { width: 60px !important; height: 60px !important; } + + /* Folio strip text shrinks */ + body > .folio.tl, + body > .folio.tr { font-size: 7.5px !important; letter-spacing: 0.14em !important; } + + /* Mini-player: shave one icon */ + .mini-player { padding: 8px 12px !important; gap: 10px !important; } + .mini-album-art { width: 34px !important; height: 34px !important; } + .mini-control-btn { width: 36px !important; height: 36px !important; } +}