/* * fee[dB]ack v0.3.0 — non-Tailwind bits for the v3 shell. * Body radial-gradient background + custom scrollbars. Tokens mirror the * `fb` palette in tailwind.config.js. */ /* The v3 tuner card replaces the tuner plugin's floating launcher — hide it. */ #tuner-toggle-btn { display: none !important; } /* The navy radial wash lives on the SIDEBAR (the content area is the solid darker tone). Brighter toward the top. */ #v3-sidebar { background-image: radial-gradient(circle at top, #1e293b 0%, #0f172a 100%); background-attachment: fixed; } /* Custom 6px scrollbars on the scroll regions (WebKit/Blink). */ #v3-main::-webkit-scrollbar, #v3-nav::-webkit-scrollbar, .v3-scroll::-webkit-scrollbar { width: 6px; height: 6px; } #v3-main::-webkit-scrollbar-track, #v3-nav::-webkit-scrollbar-track, .v3-scroll::-webkit-scrollbar-track { background: transparent; } #v3-main::-webkit-scrollbar-thumb, #v3-nav::-webkit-scrollbar-thumb, .v3-scroll::-webkit-scrollbar-thumb { background: #334155; border-radius: 3px; } #v3-main::-webkit-scrollbar-thumb:hover, #v3-nav::-webkit-scrollbar-thumb:hover, .v3-scroll::-webkit-scrollbar-thumb:hover { background: #475569; } /* Firefox scrollbars. */ #v3-main, #v3-nav, .v3-scroll { scrollbar-width: thin; scrollbar-color: #334155 transparent; } /* ══ v3 player chrome (P22) ════════════════════════════════════════════════ Persistent top HUD + Up-Next pill, hover-reveal left rail with feature popovers, and an auto-hiding bottom transport. Scoped under #player; this markup only exists in static/v3/index.html, so the legacy player is unaffected. Behavior: static/v3/player-chrome.js. */ #player { background: #050508; position: relative; } #player #highway { position: relative; z-index: 1; } /* — Venue Mood FX — Phase 1: bottom strip disabled; real scene ships in 3D bg — */ .venue-mood-fx { display: none !important; pointer-events: none; } /* Edge-only wash above 3D canvas, below HUD/transport (z-index 3) */ #player .v3-venue-scene-wash { position: absolute; inset: 0; z-index: 3; pointer-events: none; background: linear-gradient(180deg, rgba(34, 211, 238, .16) 0%, transparent 14%), linear-gradient(0deg, rgba(30, 64, 110, .2) 0%, transparent 16%), linear-gradient(90deg, rgba(34, 211, 238, .1) 0%, transparent 10%), linear-gradient(270deg, rgba(34, 211, 238, .1) 0%, transparent 10%); } /* Non-blocking Venue mode label — below HUD, above canvas */ #player .v3-venue-mode-badge { position: absolute; top: 4.75rem; left: 1.25rem; z-index: 18; pointer-events: none; max-width: min(22rem, calc(100% - 2.5rem)); padding: .35rem .65rem; font-size: .7rem; line-height: 1.35; letter-spacing: .02em; color: rgba(165, 243, 252, .95); background: rgba(8, 47, 73, .78); border: 1px solid rgba(34, 211, 238, .38); border-radius: .375rem; box-shadow: 0 2px 10px rgba(2, 8, 23, .35); backdrop-filter: blur(4px); } #player .v3-venue-scene-wash.hidden, #player .v3-venue-mode-badge.hidden { display: none; } /* Legacy ::before wash retained for tests; superseded by .v3-venue-scene-wash */ #player.is-venue-visualization.venue-scene-pending::before { content: none; } /* Legacy strip rules retained for when STRIP_OVERLAY_ENABLED returns */ .venue-mood-fx:not(.hidden) { opacity: 1; } .venue-mood-fx.hidden { display: none; } .venue-mood-lights, .venue-mood-crowd, .venue-mood-haze { position: absolute; inset: 0; pointer-events: none; } /* Stage wash — original gradients only */ .venue-mood-lights { background: radial-gradient(ellipse 55% 85% at 10% 100%, rgba(251, 191, 36, .22) 0%, transparent 58%), radial-gradient(ellipse 55% 85% at 90% 100%, rgba(56, 189, 248, .2) 0%, transparent 58%), radial-gradient(ellipse 90% 120% at 50% 110%, rgba(30, 58, 95, .55) 0%, transparent 68%), linear-gradient(180deg, transparent 0%, rgba(8, 12, 22, .35) 55%, rgba(4, 6, 12, .82) 100%); opacity: .75; } /* Crowd silhouettes — CSS shapes, no external assets */ .venue-mood-crowd { bottom: 0; top: auto; height: 72%; background: radial-gradient(ellipse 8% 42% at 6% 100%, rgba(48, 72, 118, .96) 0%, rgba(36, 56, 92, .96) 58%, transparent 59%), radial-gradient(ellipse 7% 38% at 14% 100%, rgba(52, 78, 124, .94) 0%, rgba(40, 62, 98, .94) 56%, transparent 57%), radial-gradient(ellipse 9% 44% at 24% 100%, rgba(44, 68, 110, .95) 0%, rgba(34, 54, 88, .95) 58%, transparent 59%), radial-gradient(ellipse 8% 40% at 34% 100%, rgba(50, 74, 120, .94) 0%, rgba(38, 58, 94, .94) 57%, transparent 58%), radial-gradient(ellipse 10% 46% at 46% 100%, rgba(42, 66, 108, .96) 0%, rgba(32, 52, 86, .96) 60%, transparent 61%), radial-gradient(ellipse 9% 42% at 58% 100%, rgba(48, 72, 116, .95) 0%, rgba(36, 56, 90, .95) 58%, transparent 59%), radial-gradient(ellipse 8% 40% at 68% 100%, rgba(52, 78, 122, .93) 0%, rgba(40, 62, 96, .93) 56%, transparent 57%), radial-gradient(ellipse 9% 44% at 78% 100%, rgba(44, 68, 112, .95) 0%, rgba(34, 54, 88, .95) 58%, transparent 59%), radial-gradient(ellipse 8% 38% at 88% 100%, rgba(50, 74, 118, .94) 0%, rgba(38, 58, 92, .94) 56%, transparent 57%), radial-gradient(ellipse 7% 36% at 96% 100%, rgba(46, 70, 114, .93) 0%, rgba(36, 56, 90, .93) 55%, transparent 56%); opacity: .55; transform: translateY(0); } .venue-mood-haze { background: linear-gradient(180deg, transparent 0%, rgba(15, 23, 42, .12) 40%, rgba(30, 41, 59, .28) 100%); opacity: 0; transition: opacity .6s ease; } /* Player shell atmosphere when venue enabled */ #player.venue-mood-subtle::before, #player.venue-mood-full::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none; background: radial-gradient(ellipse 120% 80% at 50% 100%, rgba(30, 64, 110, .12) 0%, transparent 55%); transition: background .6s ease, opacity .6s ease; } #player.venue-mood-full::before { background: radial-gradient(ellipse 90% 55% at 50% 0%, rgba(34, 211, 238, .06) 0%, transparent 60%), radial-gradient(ellipse 120% 80% at 50% 100%, rgba(30, 64, 110, .18) 0%, transparent 55%); } /* Subtle vs full intensity */ #player.venue-mood-subtle .venue-mood-lights { opacity: .65; } #player.venue-mood-subtle .venue-mood-crowd { opacity: .48; } #player.venue-mood-full .venue-mood-lights { background: radial-gradient(ellipse 52% 95% at 8% 100%, rgba(251, 191, 36, .42) 0%, transparent 58%), radial-gradient(ellipse 52% 95% at 92% 100%, rgba(56, 189, 248, .38) 0%, transparent 58%), radial-gradient(ellipse 95% 130% at 50% 115%, rgba(59, 130, 246, .48) 0%, transparent 72%), linear-gradient(180deg, transparent 0%, rgba(15, 23, 42, .45) 42%, rgba(8, 12, 24, .94) 100%); opacity: .92; } #player.venue-mood-full .venue-mood-crowd { opacity: .78; } /* Full idle baseline — visible before any notes are judged */ #player.venue-mood-full .venue-mood-fx .venue-mood-lights { opacity: .88; } #player.venue-mood-full .venue-mood-fx .venue-mood-crowd { opacity: .72; } #player.venue-mood-full .venue-mood-fx .venue-mood-haze { opacity: .28; background: linear-gradient(180deg, transparent 0%, rgba(56, 189, 248, .08) 35%, rgba(30, 64, 110, .22) 100%); } /* Performance state visuals */ .venue-mood-fx.venue-mood-state-idle .venue-mood-lights { opacity: .45; } .venue-mood-fx.venue-mood-state-idle .venue-mood-crowd { opacity: .32; } #player.venue-mood-full .venue-mood-fx.venue-mood-state-idle .venue-mood-lights { opacity: .88; } #player.venue-mood-full .venue-mood-fx.venue-mood-state-idle .venue-mood-crowd { opacity: .72; } .venue-mood-fx.venue-mood-state-steady .venue-mood-lights { background: radial-gradient(ellipse 85% 110% at 50% 108%, rgba(51, 85, 120, .5) 0%, transparent 66%), linear-gradient(180deg, transparent 0%, rgba(10, 16, 28, .4) 60%, rgba(4, 6, 12, .85) 100%); } .venue-mood-fx.venue-mood-state-strong .venue-mood-lights { background: radial-gradient(ellipse 70% 95% at 50% 105%, rgba(34, 211, 238, .28) 0%, transparent 62%), radial-gradient(ellipse 90% 115% at 50% 110%, rgba(51, 85, 120, .58) 0%, transparent 68%), linear-gradient(180deg, transparent 0%, rgba(8, 14, 26, .35) 55%, rgba(4, 6, 12, .88) 100%); } .venue-mood-fx.venue-mood-state-strong .venue-mood-crowd { opacity: .62; } .venue-mood-fx.venue-mood-state-fire .venue-mood-lights { background: radial-gradient(ellipse 55% 80% at 50% 95%, rgba(251, 146, 60, .42) 0%, transparent 58%), radial-gradient(ellipse 85% 110% at 50% 108%, rgba(180, 70, 20, .35) 0%, transparent 65%), linear-gradient(180deg, transparent 0%, rgba(20, 10, 6, .3) 50%, rgba(4, 6, 12, .9) 100%); } .venue-mood-fx.venue-mood-state-fire .venue-mood-crowd { opacity: .78; } .venue-mood-fx.venue-mood-state-recovery .venue-mood-lights { background: radial-gradient(ellipse 90% 105% at 50% 110%, rgba(120, 90, 30, .32) 0%, transparent 66%), linear-gradient(180deg, transparent 0%, rgba(18, 14, 8, .42) 58%, rgba(4, 6, 12, .86) 100%); } .venue-mood-fx.venue-mood-state-recovery .venue-mood-crowd { opacity: .38; } .venue-mood-fx.venue-mood-state-smoke .venue-mood-lights { opacity: .35; } .venue-mood-fx.venue-mood-state-smoke .venue-mood-crowd { opacity: .22; transform: translateY(6%); } .venue-mood-fx.venue-mood-state-smoke .venue-mood-haze { opacity: .72; background: linear-gradient(180deg, transparent 0%, rgba(71, 85, 105, .22) 35%, rgba(51, 65, 85, .45) 100%), radial-gradient(ellipse 100% 80% at 50% 100%, rgba(100, 116, 139, .25) 0%, transparent 70%); } @media (prefers-reduced-motion: no-preference) { .venue-mood-fx.venue-mood-state-steady .venue-mood-crowd, #player.venue-mood-full .venue-mood-fx.venue-mood-state-steady .venue-mood-crowd { animation: v3-venue-crowd-sway 4.8s ease-in-out infinite; } .venue-mood-fx.venue-mood-state-strong .venue-mood-crowd, #player.venue-mood-full .venue-mood-fx.venue-mood-state-strong .venue-mood-crowd { animation: v3-venue-crowd-sway 3.6s ease-in-out infinite; } .venue-mood-fx.venue-mood-state-fire .venue-mood-crowd, #player.venue-mood-full .venue-mood-fx.venue-mood-state-fire .venue-mood-crowd { animation: v3-venue-crowd-bounce 2.2s ease-in-out infinite; } .venue-mood-fx.venue-mood-state-fire .venue-mood-lights { animation: v3-venue-fire-glow 2.8s ease-in-out infinite; } .venue-mood-fx.venue-mood-state-smoke .venue-mood-haze { animation: v3-venue-smoke-drift 5.5s ease-in-out infinite; } } @keyframes v3-venue-crowd-sway { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-2px); } } @keyframes v3-venue-crowd-bounce { 0%, 100% { transform: translateY(0) scaleY(1); } 35% { transform: translateY(-4px) scaleY(1.02); } 65% { transform: translateY(-1px) scaleY(1); } } @keyframes v3-venue-fire-glow { 0%, 100% { filter: brightness(1); } 50% { filter: brightness(1.12); } } @keyframes v3-venue-smoke-drift { 0%, 100% { opacity: .65; transform: translateY(0); } 50% { opacity: .78; transform: translateY(-3px); } } @media (prefers-reduced-motion: reduce) { .venue-mood-fx .venue-mood-crowd, .venue-mood-fx .venue-mood-lights, .venue-mood-fx .venue-mood-haze { animation: none !important; } } /* — Up Next pill (top-right, persistent) — */ #player-hud .v3-upnext { display: flex; align-items: center; gap: .5rem; padding: .45rem .9rem; border-radius: .75rem; background: rgba(15, 23, 42, .7); border: 1px solid rgba(51, 65, 85, .5); backdrop-filter: blur(6px); font-size: .85rem; pointer-events: auto; } #player-hud .v3-upnext.hidden { display: none; } /* — Live performance HUD (top-right, read-only) — */ .v3-live-performance-hud { display: flex; flex-direction: column; align-items: flex-end; gap: .2rem; min-width: 9.5rem; padding: .55rem .85rem; border-radius: .85rem; background: rgba(15, 23, 42, .78); border: 1px solid rgba(71, 85, 105, .55); backdrop-filter: blur(8px); box-shadow: 0 8px 24px rgba(0, 0, 0, .35); pointer-events: none; transition: border-color .35s ease, box-shadow .35s ease, background .35s ease; } .v3-live-performance-hud.hidden { display: none; } .v3-live-performance-heading { display: flex; align-items: baseline; gap: .45rem; line-height: 1; } .v3-live-performance-tag { font-size: .68rem; font-weight: 800; letter-spacing: .14em; color: #94a3b8; } .v3-live-performance-percent { font-size: 2rem; font-weight: 900; letter-spacing: -.03em; color: #f8fafc; font-variant-numeric: tabular-nums; } .v3-live-performance-hits, .v3-live-performance-streak { font-size: .78rem; font-weight: 600; color: #cbd5e1; font-variant-numeric: tabular-nums; } .v3-live-performance-state { font-size: .72rem; font-weight: 700; color: #e2e8f0; min-height: 1rem; } .v3-live-performance-hud.is-idle .v3-live-performance-percent { color: #94a3b8; } .v3-live-performance-hud.is-fire { border-color: rgba(251, 146, 60, .75); background: linear-gradient(145deg, rgba(67, 20, 7, .82), rgba(15, 23, 42, .88)); box-shadow: 0 0 22px rgba(251, 146, 60, .28); animation: v3-live-fire-pulse 2.4s ease-in-out infinite; } .v3-live-performance-hud.is-fire .v3-live-performance-percent { color: #fdba74; text-shadow: 0 0 12px rgba(251, 146, 60, .45); } .v3-live-performance-hud.is-fire .v3-live-performance-state { color: #fb923c; } .v3-live-performance-hud.is-strong { border-color: rgba(34, 211, 238, .55); box-shadow: 0 0 16px rgba(34, 211, 238, .18); } .v3-live-performance-hud.is-strong .v3-live-performance-percent { color: #67e8f9; } .v3-live-performance-hud.is-steady { border-color: rgba(100, 116, 139, .55); } .v3-live-performance-hud.is-recovery { border-color: rgba(250, 204, 21, .45); background: rgba(30, 27, 12, .72); } .v3-live-performance-hud.is-recovery .v3-live-performance-percent { color: #fde68a; } .v3-live-performance-hud.is-smoke { border-color: rgba(100, 116, 139, .35); background: rgba(15, 23, 42, .62); opacity: .92; animation: v3-live-smoke-haze 3.2s ease-in-out infinite; } .v3-live-performance-hud.is-smoke .v3-live-performance-percent { color: #94a3b8; } .v3-live-performance-hud.is-smoke .v3-live-performance-state { color: #cbd5e1; } @keyframes v3-live-fire-pulse { 0%, 100% { box-shadow: 0 0 18px rgba(251, 146, 60, .22); } 50% { box-shadow: 0 0 26px rgba(251, 146, 60, .38); } } @keyframes v3-live-smoke-haze { 0%, 100% { transform: translateY(0); opacity: .92; } 50% { transform: translateY(-1px); opacity: .84; } } .v3-upnext-name { font-weight: 800; background: linear-gradient(90deg, #22d3ee, #a855f7, #f472b6); -webkit-background-clip: text; background-clip: text; color: transparent; } /* — Left rail hover-zone — */ .v3-railzone { position: absolute; left: 0; top: 0; bottom: 0; z-index: 30; display: flex; align-items: center; pointer-events: none; /* only the catcher + rail take pointer events */ } .v3-railzone::before { /* invisible left-edge strip that reveals the rail */ content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 96px; pointer-events: auto; } .v3-rail { position: relative; display: flex; flex-direction: column; align-items: center; gap: .25rem; padding: 1.5rem .75rem; pointer-events: auto; opacity: 0; transform: translateX(-12px); transition: opacity .25s ease, transform .25s ease; } .v3-railzone:hover .v3-rail, .v3-railzone:focus-within .v3-rail, #player.pop-open .v3-rail { opacity: 1; transform: none; } .v3-rail-icon { position: relative; width: 70px; height: 70px; display: flex; align-items: center; justify-content: center; background: transparent; border: 0; cursor: pointer; color: #8ba3ac; transition: transform .18s ease, color .18s ease; } .v3-rail-border { position: absolute; inset: 0; border: 2px solid rgba(139, 163, 172, .45); border-radius: 50%; transition: border-color .18s ease; } .v3-rail-border-gear { border-color: rgba(139, 163, 172, .45); } .v3-rail-svg { width: 32px; height: 32px; fill: currentcolor; z-index: 1; } .v3-rail-dot { width: 6px; height: 6px; background: #4a5d6e; border-radius: 2px; margin: 1rem 0; } /* pop-out + active state */ .v3-rail-icon:hover, .v3-rail-icon:focus-visible { color: #e8eef1; } .v3-rail-icon:hover .v3-rail-border, .v3-rail-icon:focus-visible .v3-rail-border { border-color: rgba(203, 213, 225, .85); } .v3-rail-icon.is-active { color: #e2e8f0; } .v3-rail-icon.is-active .v3-rail-border { border-color: #22d3ee; } @media (prefers-reduced-motion: no-preference) { .v3-rail-icon:hover, .v3-rail-icon:focus-visible { transform: translateX(6px) scale(1.12); } } /* — Section Practice circular rail icon (v3 chrome) — */ #v3-player-rail .section-practice-control--v3 { padding: 0; margin: 0; width: auto; display: flex; justify-content: center; flex-shrink: 0; } #v3-player-rail .section-practice-control--v3 .section-practice-pill { position: relative; width: 70px; height: 70px; display: flex; align-items: center; justify-content: center; padding: 0; gap: 0; min-width: 0; color: #8ba3ac; background: transparent; border: 0; border-radius: 0; box-shadow: none; cursor: pointer; transition: transform .18s ease, color .18s ease; } #v3-player-rail .section-practice-control--v3 .section-practice-pill-text, #v3-player-rail .section-practice-control--v3 .section-practice-pill-caret { display: none !important; } #v3-player-rail .section-practice-control--v3 .section-practice-pill-icon { display: flex; align-items: center; justify-content: center; z-index: 1; font-size: 32px; line-height: 1; } #v3-player-rail .section-practice-control--v3 .section-practice-pill-icon .v3-rail-svg, #v3-player-rail .section-practice-control--v3 .section-practice-pill-svg { width: 32px; height: 32px; fill: currentcolor; } #v3-player-rail .section-practice-control--v3 .section-practice-pill:hover, #v3-player-rail .section-practice-control--v3 .section-practice-pill:focus-visible { color: #e8eef1; background: transparent; box-shadow: none; } #v3-player-rail .section-practice-control--v3 .section-practice-pill:hover .v3-rail-border, #v3-player-rail .section-practice-control--v3 .section-practice-pill:focus-visible .v3-rail-border { border-color: rgba(203, 213, 225, .85); } #v3-player-rail .section-practice-control--v3 .section-practice-pill[aria-expanded="true"], #v3-player-rail .section-practice-control--v3 .section-practice-pill.section-practice-pill--active { color: #e2e8f0; background: transparent; box-shadow: none; } #v3-player-rail .section-practice-control--v3 .section-practice-pill[aria-expanded="true"] .v3-rail-border, #v3-player-rail .section-practice-control--v3 .section-practice-pill.section-practice-pill--active .v3-rail-border { border-color: #22d3ee; } @media (prefers-reduced-motion: no-preference) { #v3-player-rail .section-practice-control--v3 .section-practice-pill:hover, #v3-player-rail .section-practice-control--v3 .section-practice-pill:focus-visible { transform: translateX(6px) scale(1.12); } } #v3-player-rail .section-practice-control--v3 #section-practice-bar { left: calc(100% + 10px); right: auto; bottom: auto; top: 0; min-width: 230px; max-width: min(340px, calc(100vw - 120px)); padding: .9rem; border-radius: .9rem; border: 1px solid rgba(51, 65, 85, .6); background: rgba(15, 23, 42, .96); box-shadow: 0 12px 40px rgba(0, 0, 0, .5); } /* — Rail feature popovers — */ .v3-rail-pop { position: absolute; left: 92px; top: 50%; transform: translateY(-50%); min-width: 230px; max-width: 340px; pointer-events: auto; background: rgba(15, 23, 42, .96); border: 1px solid rgba(51, 65, 85, .6); border-radius: .9rem; box-shadow: 0 12px 40px rgba(0, 0, 0, .5); padding: .9rem; display: flex; flex-direction: column; gap: .6rem; z-index: 40; } .v3-rail-pop.hidden { display: none; } .v3-pop-row { display: flex; align-items: center; justify-content: space-between; gap: .75rem; font-size: .8rem; color: #cbd5e1; } .v3-pop-label { color: #94a3b8; font-size: .72rem; text-transform: uppercase; letter-spacing: .04em; white-space: nowrap; } .v3-pop-select, .v3-pop-btn { background: #1e293b; border: 1px solid #334155; color: #e2e8f0; border-radius: .5rem; padding: .35rem .6rem; font-size: .8rem; outline: none; cursor: pointer; } .v3-pop-btn:hover { background: #334155; } .v3-pop-pin { background: #1e293b; border: 1px solid #334155; color: #94a3b8; border-radius: .5rem; width: 2rem; height: 2rem; cursor: pointer; } .v3-pop-val { color: #94a3b8; font-size: .75rem; min-width: 3rem; text-align: right; } .v3-pop-close { margin-top: .25rem; background: #1e293b; border: 1px solid #334155; color: #94a3b8; border-radius: .5rem; padding: .4rem; font-size: .8rem; cursor: pointer; } .v3-pop-close:hover { background: rgba(127, 29, 29, .5); color: #fca5a5; } /* — Bottom transport (auto-hide) — */ #player .v3-transport { position: absolute; left: 0; right: 0; bottom: 0; z-index: 20; display: flex; align-items: center; justify-content: center; gap: 1.25rem; padding: 1rem; background: transparent; opacity: 0; transform: translateY(12px); transition: opacity .25s ease, transform .25s ease; } #player.chrome-active .v3-transport, #player.pop-open .v3-transport, #player .v3-transport:hover { opacity: 1; transform: none; } #player.chrome-idle { cursor: none; } .v3-transport-mid { display: flex; align-items: center; gap: .75rem; } .v3-seek { width: 2.5rem; height: 2.5rem; display: flex; align-items: center; justify-content: center; background: rgba(30, 41, 59, .7); border: 1px solid rgba(51, 65, 85, .6); border-radius: 999px; color: #cbd5e1; cursor: pointer; transition: background .15s; } .v3-seek:hover { background: rgba(51, 65, 85, .9); } .v3-play { width: 4rem; height: 2.6rem; display: flex; align-items: center; justify-content: center; background: linear-gradient(180deg, #475569, #334155); border: 1px solid rgba(100, 116, 139, .6); border-radius: 999px; cursor: pointer; box-shadow: 0 4px 14px rgba(0, 0, 0, .4); } .v3-play:hover { filter: brightness(1.15); } /* speed widget (bars + slider + label + presets) */ .v3-speed-cluster { display: flex; align-items: center; gap: .5rem; flex-shrink: 1; min-width: 0; max-width: min(52vw, 28rem); } .v3-speed { display: flex; align-items: center; gap: .5rem; flex-shrink: 0; } .v3-speed-presets { display: flex; flex-wrap: nowrap; align-items: center; gap: .2rem; min-width: 0; overflow-x: auto; scrollbar-width: none; } .v3-speed-presets::-webkit-scrollbar { display: none; } .v3-speed-preset-btn { flex: 0 0 auto; padding: .15rem .45rem; min-width: 1.75rem; font-size: .7rem; font-weight: 700; line-height: 1.25; color: #cbd5e1; background: rgba(30, 41, 59, .9); border: 1px solid rgba(71, 85, 105, .85); border-radius: 999px; cursor: pointer; transition: background .15s, border-color .15s, color .15s, box-shadow .15s; } .v3-speed-preset-btn:hover { color: #e2e8f0; background: rgba(51, 65, 85, .9); border-color: rgba(100, 116, 139, .8); } .v3-speed-preset-btn[data-sweet-spot="1"]:not(.v3-speed-preset-active) { border-color: rgba(34, 211, 238, .35); } .v3-speed-preset-active { color: #0f172a; background: #22d3ee; border-color: #22d3ee; } .v3-speed-preset-btn[data-sweet-spot="1"].v3-speed-preset-active { box-shadow: 0 0 8px rgba(34, 211, 238, .45); } .v3-speed-bars { display: inline-flex; align-items: flex-end; gap: 2px; height: 22px; } .v3-speed-bars i { width: 3px; background: #475569; border-radius: 1px; transition: background .15s, height .15s; } .v3-speed-bars i:nth-child(1) { height: 5px; } .v3-speed-bars i:nth-child(2) { height: 7px; } .v3-speed-bars i:nth-child(3) { height: 9px; } .v3-speed-bars i:nth-child(4) { height: 11px; } .v3-speed-bars i:nth-child(5) { height: 13px; } .v3-speed-bars i:nth-child(6) { height: 16px; } .v3-speed-bars i:nth-child(7) { height: 19px; } .v3-speed-bars i:nth-child(8) { height: 22px; } .v3-speed-bars i.on { background: #22d3ee; } .v3-speed-slider { width: 90px; } .v3-speed-label { color: #94a3b8; font-size: .8rem; min-width: 2.4rem; } @media (max-width: 720px) { .v3-speed-cluster { flex-wrap: wrap; max-width: min(62vw, 18rem); } .v3-speed-presets { flex-wrap: wrap; overflow-x: visible; } } /* rainbow chevrons (speed-level indicator) */ .v3-chevrons { display: inline-flex; align-items: center; gap: 1px; flex-shrink: 0; } .v3-chevrons i { width: 10px; height: 14px; background: #475569; opacity: .35; transition: opacity .15s; clip-path: polygon(0 0, 55% 50%, 0 100%, 45% 100%, 100% 50%, 45% 0); } .v3-chevrons i.on { opacity: 1; } .v3-chevrons i:nth-child(1).on { background: #f87171; } .v3-chevrons i:nth-child(2).on { background: #fb923c; } .v3-chevrons i:nth-child(3).on { background: #facc15; } .v3-chevrons i:nth-child(4).on { background: #4ade80; } .v3-chevrons i:nth-child(5).on { background: #22d3ee; } /* — Plugin-control slot (host re-homes plugin controls here from the transport) — */ .v3-plugin-slot { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; } .v3-plugin-slot > * { margin: 0 !important; } /* neutralize legacy ml-1/ml-auto spacing */ .v3-pop-empty { color: #64748b; font-size: .75rem; font-style: italic; } /* small count badge on the Plugins rail icon */ .v3-rail-badge { position: absolute; top: 6px; right: 6px; min-width: 16px; height: 16px; padding: 0 4px; display: flex; align-items: center; justify-content: center; background: #22d3ee; color: #0f172a; font-size: 10px; font-weight: 800; line-height: 1; border-radius: 999px; z-index: 2; } .v3-rail-badge[hidden] { display: none; } /* ── v3 UI font: Rubik ────────────────────────────────────────────────────── `font-display` is a SHARED Tailwind token (Inter, used by the v2 body too), so it can't be repointed in tailwind.config without changing v2. v3.css is loaded only by the v3 page, so scope Rubik here. `body.font-display` (element+class) outranks Tailwind's `.font-display` (class) by specificity. The Rubik webfont is loaded via a in static/v3/index.html. */ body.font-display { font-family: Rubik, system-ui, sans-serif; } /* ── v3 Plugins page — Pedalboard ──────────────────────────────────────────── Plugins grouped onto category "pedalboards"; each plugin is a draggable stompbox pedal with decorative patch cables (static/v3/pedal-cables.js) sagging between them. Custom CSS (not Tailwind utilities) so the prebuilt stylesheet needn't be regenerated. Palette mirrors the fb-* tokens. */ /* The title sits on the board's top-right as a browser-style tab; it also doubles as the collapse toggle. The section reserves a row of height for it. */ .v3-board-section { position: relative; padding-top: 30px; margin-bottom: 2rem; } .v3-board-title { position: absolute; top: 0; right: 22px; z-index: 3; display: flex; align-items: center; gap: .4rem; height: 31px; box-sizing: border-box; padding: 0 .75rem; cursor: pointer; text-align: left; font-family: inherit; font-size: .72rem; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: #cbd5e1; /* tab body: matches the board's top gradient stop, rounded only on top, and its bottom overlaps the board's top edge so they read as one piece. */ background: #1c2740; border: 1px solid rgba(51, 65, 85, .55); border-bottom: none; border-radius: .55rem .55rem 0 0; } .v3-board-title:hover { color: #fff; background: #243150; } .v3-board-title:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 1px; } /* When collapsed there's no board below, so close the tab into a full pill. */ .v3-board-section.collapsed .v3-board-title { border-bottom: 1px solid rgba(51, 65, 85, .55); border-radius: .55rem; } .v3-board-chevron { width: 14px; height: 14px; flex: none; color: #64748b; transition: transform .15s ease; } .v3-board-title:hover .v3-board-chevron { color: #94a3b8; } .v3-board-section.collapsed .v3-board-chevron { transform: rotate(-90deg); } .v3-board-section.collapsed .v3-pedalboard { display: none; } .v3-board-count { font-size: .65rem; font-weight: 700; color: #cbd5e1; background: rgba(51, 65, 85, .5); border-radius: 999px; padding: .05rem .45rem; } /* The board surface: a dark, subtly textured panel the pedals sit on. */ .v3-pedalboard { position: relative; border-radius: 1rem; border: 1px solid rgba(51, 65, 85, .5); /* fb-border */ background: repeating-linear-gradient(45deg, rgba(255, 255, 255, .012) 0 2px, transparent 2px 9px), radial-gradient(120% 140% at 50% 0%, #1c2740 0%, #131b2e 60%, #0d1422 100%); box-shadow: inset 0 1px 0 rgba(255, 255, 255, .03), inset 0 -18px 40px rgba(0, 0, 0, .35); min-height: 220px; overflow: hidden; } /* Decorative patch-cable overlay — never blocks pedal clicks. */ .v3-cable-layer { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 1; } .v3-cable { fill: none; stroke: #e2683a; /* warm 1/4" cable */ stroke-width: 4; stroke-linecap: round; opacity: .85; filter: drop-shadow(0 2px 2px rgba(0, 0, 0, .45)); } /* Stompbox pedal — a transparent pedal photo "skin" (static/v3/pedals/*) set as the card background; the plugin's name + description overlay in a label panel. The skin is random-per-plugin and persisted (see plugins-page.js). The card dimensions must match PEDAL_W/PEDAL_H in plugins-page.js. */ .v3-pedal { position: absolute; /* width/height are set responsively per board in plugins-page.js so a fixed number of pedals fit per row. */ box-sizing: border-box; color: #f8fafc; cursor: grab; user-select: none; touch-action: none; /* let pointer-drag own the gesture */ z-index: 2; transition: filter .12s ease; } /* The skin photo lives on ::before so the disabled-dim filter only touches it, not the glow ring / label / badges (which must stay full-colour). */ .v3-pedal::before { content: ''; position: absolute; inset: 0; z-index: 0; background-image: var(--skin); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; } .v3-pedal:hover { filter: brightness(1.06); } .v3-pedal:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 3px; border-radius: .8rem; } .v3-pedal-dragging { cursor: grabbing; z-index: 5; } /* Footswitch status glow: green when the plugin is active, red when disabled. Full-pedal overlay (same crop+pad as the skins) so the ring sits on the footswitch and scales with the pedal. */ .v3-pedal-glow { position: absolute; inset: 0; z-index: 1; pointer-events: none; background-image: url('/static/v3/overlay-active.png'); background-size: 100% 100%; background-position: center; background-repeat: no-repeat; } .v3-pedal-off .v3-pedal-glow { background-image: url('/static/v3/overlay-inactive.png'); } /* Footswitch click hotspot over the photo's stomp button (toggles on/off). */ .v3-pedal-foot { position: absolute; left: 50%; bottom: 16%; transform: translate(-50%, -2px); width: 16%; aspect-ratio: 1 / 1; border-radius: 50%; /* scales with pedal */ background: transparent; border: 0; padding: 0; cursor: pointer; z-index: 5; } .v3-pedal-foot:focus-visible { outline: 2px solid #0ea5e9; outline-offset: 2px; border-radius: 50%; } /* Disabled plugin: dim + desaturate only the SKIN (so the red glow stays vivid), and show an "off" badge. */ .v3-pedal-off::before { filter: grayscale(.85) brightness(.5); } .v3-pedal-offbadge { position: absolute; top: 5px; left: 5px; z-index: 6; display: none; font-size: .55rem; font-weight: 800; letter-spacing: .08em; text-transform: uppercase; color: #fecaca; background: rgba(60, 10, 10, .8); border: 1px solid rgba(239, 68, 68, .6); border-radius: .3rem; padding: .05rem .35rem; } .v3-pedal-off .v3-pedal-offbadge { display: block; } /* The drawn cable plug picks up a soft drop shadow so it lifts off the cable. */ .v3-cable-plug { filter: drop-shadow(0 1px 1.5px rgba(0, 0, 0, .55)); } /* Overlay label on the pedal face — over the artwork band between the photo's knobs (top) and footswitch (bottom). Translucent so the skin still reads. */ .v3-pedal-label { position: absolute; left: 9%; right: 9%; top: 31%; bottom: calc(28% + 4px); z-index: 2; transform: translateY(-10px); /* nudge up */ display: flex; flex-direction: column; align-items: center; gap: .3rem; padding: .55rem .7rem; background: rgba(7, 10, 16, .74); border: 1px solid rgba(255, 255, 255, .1); border-radius: .5rem; backdrop-filter: blur(3px); -webkit-backdrop-filter: blur(3px); box-shadow: 0 4px 14px rgba(0, 0, 0, .5); overflow: hidden; text-align: center; } /* Thumbnail fills the panel (description is now a hover tooltip, not on the face). */ .v3-pedal-thumb { flex: 1 1 auto; min-height: 0; width: 100%; height: auto; object-fit: contain; border-radius: .35rem; display: block; -webkit-user-drag: none; } .v3-pedal-name { flex: none; font-size: .86rem; font-weight: 700; line-height: 1.15; max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } .v3-pedal-err { font-size: .6rem; color: #fca5a5; overflow-wrap: break-word; } .v3-pedal-pill { display: inline-block; font-size: .58rem; font-weight: 700; padding: .08rem .4rem; border-radius: 999px; } .v3-pill-bad { background: rgba(239, 68, 68, .25); color: #fca5a5; } .v3-pill-wait { background: rgba(234, 179, 8, .25); color: #fde68a; } .v3-pedal-bundled { position: absolute; top: 4px; right: 4px; z-index: 4; font-size: .52rem; font-weight: 700; text-transform: uppercase; letter-spacing: .04em; color: #ddd6fe; background: rgba(76, 29, 149, .6); border: 1px solid rgba(139, 92, 246, .4); border-radius: .3rem; padding: .04rem .28rem; }