Files
lanspread/design/design_reference/styles.css
T
ddidderr f1e915c379 docs: document download peer count chip
Update the launcher design reference so active downloads show how many LAN
peers are currently seeding the transfer. The reference now places the peer
chip between speed and ETA, describes the singular/plural copy, and records
how the ETA and peer count collapse in narrow modal layouts.

Test Plan:
- git diff --cached --check
2026-05-21 00:30:57 +02:00

1138 lines
30 KiB
CSS

/* SoftLAN Launcher — styles
Steam-like dark UI, blue accent (configurable). System sans for UI,
Bebas Neue for cover-art display type.
*/
@import url('https://fonts.googleapis.com/css2?family=Bebas+Neue&display=swap');
:root {
--accent: #3b82f6;
--bg-0: #0a0e13;
--bg-1: #0f151c;
--bg-2: #131b25;
--bg-3: #1a2330;
--bg-4: #232f3e;
--bd-1: rgba(255,255,255,0.06);
--bd-2: rgba(255,255,255,0.10);
--bd-3: rgba(255,255,255,0.16);
--t-1: #e6edf3;
--t-2: #9aa6b4;
--t-3: #6b7785;
--t-4: #4a5663;
--ok: #22c55e;
--warn: #f59e0b;
--danger: #ef4444;
--font-ui: -apple-system, BlinkMacSystemFont, "Segoe UI Variable", "Segoe UI", Inter, system-ui, sans-serif;
--font-display: "Bebas Neue", "Oswald", Impact, "Arial Narrow Bold", sans-serif;
--radius-sm: 6px;
--radius-md: 10px;
--radius-lg: 14px;
}
* { box-sizing: border-box; }
/* ─── Launcher root ─── */
.launcher {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
background: var(--bg-0);
color: var(--t-1);
font-family: var(--font-ui);
font-size: 13px;
line-height: 1.4;
overflow: hidden;
position: relative;
isolation: isolate;
}
/* Background variants */
.bg-flat { background: var(--bg-0); }
.bg-gradient {
background:
radial-gradient(ellipse 80% 50% at 50% -10%, color-mix(in srgb, var(--accent) 22%, transparent) 0%, transparent 60%),
linear-gradient(180deg, #0c1218 0%, var(--bg-0) 100%);
}
.bg-animated {
background:
radial-gradient(ellipse 60% 40% at 20% 0%, color-mix(in srgb, var(--accent) 24%, transparent) 0%, transparent 55%),
radial-gradient(ellipse 55% 40% at 85% 8%, color-mix(in srgb, var(--accent) 16%, transparent) 0%, transparent 55%),
linear-gradient(180deg, #0c1218 0%, var(--bg-0) 100%);
background-size: 100% 100%;
animation: bgshift 18s ease-in-out infinite alternate;
}
@keyframes bgshift {
0% { background-position: 0% 0%, 0% 0%, 0% 0%; }
100% { background-position: 10% 4%, -6% 2%, 0% 0%; }
}
/* ─── Top bar — shared ─── */
.topbar {
position: relative;
z-index: 10;
background: rgba(10,14,19,0.65);
-webkit-backdrop-filter: blur(20px) saturate(140%);
backdrop-filter: blur(20px) saturate(140%);
border-bottom: 1px solid var(--bd-1);
}
/* Variant 1: single row */
.topbar-single {
display: flex;
align-items: center;
gap: 18px;
padding: 14px 24px;
flex-wrap: nowrap;
}
/* Variant 2: two row */
.topbar-two .topbar-row {
display: flex;
align-items: center;
gap: 16px;
padding: 12px 24px;
}
.topbar-two .topbar-row1 {
border-bottom: 1px solid var(--bd-1);
}
.topbar-two .topbar-row1-right { margin-left: auto; display: flex; align-items: center; gap: 16px; }
.topbar-two .topbar-row2 { padding-top: 4px; padding-bottom: 4px; }
.topbar-two .topbar-row2-right { margin-left: auto; display: flex; align-items: center; gap: 12px; }
/* ─── Brand ─── */
.brand {
display: flex;
align-items: center;
gap: 10px;
flex-shrink: 0;
}
.brand-mark {
width: 28px; height: 28px;
border-radius: 7px;
display: grid; place-items: center;
font-family: var(--font-display);
font-size: 20px;
letter-spacing: 0.02em;
color: white;
box-shadow: 0 6px 20px -6px color-mix(in srgb, var(--accent) 60%, black), inset 0 1px 0 rgba(255,255,255,0.22);
}
.brand-name {
font-weight: 700;
font-size: 15px;
letter-spacing: -0.005em;
color: var(--t-1);
}
.brand-name-soft { color: var(--t-3); font-weight: 500; margin-left: 4px; }
/* ─── Segmented filters (variant 1) ─── */
.seg {
position: relative;
display: inline-flex;
background: var(--bg-2);
border: 1px solid var(--bd-1);
border-radius: 999px;
padding: 4px;
flex-shrink: 0;
}
.seg-thumb {
position: absolute;
top: 4px; bottom: 4px;
border-radius: 999px;
transition: left .22s cubic-bezier(.4,1.2,.5,1), width .22s cubic-bezier(.4,1.2,.5,1), background .15s;
box-shadow: 0 4px 14px -4px color-mix(in srgb, var(--accent) 60%, black);
}
.seg-btn {
position: relative;
z-index: 1;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 8px 16px;
background: transparent;
color: var(--t-2);
border: 0;
border-radius: 999px;
font: inherit;
font-weight: 600;
font-size: 12.5px;
cursor: pointer;
white-space: nowrap;
transition: color .15s;
}
.seg-btn:hover { color: var(--t-1); }
.seg-btn.is-active { color: white; }
.seg-count {
font-size: 11px;
font-weight: 700;
padding: 1px 6px;
border-radius: 999px;
background: rgba(255,255,255,0.08);
color: inherit;
font-variant-numeric: tabular-nums;
}
.seg-btn.is-active .seg-count { background: rgba(0,0,0,0.25); color: white; }
/* ─── Underline filters (variant 2) ─── */
.utabs {
display: flex;
align-items: stretch;
gap: 4px;
}
.utab {
position: relative;
display: inline-flex;
align-items: center;
gap: 8px;
padding: 10px 14px 12px;
background: transparent;
border: 0;
color: var(--t-2);
font: inherit;
font-weight: 600;
font-size: 13.5px;
cursor: pointer;
transition: color .15s;
}
.utab:hover { color: var(--t-1); }
.utab.is-active { color: var(--t-1); }
.utab-count {
font-size: 11.5px;
font-weight: 600;
padding: 1px 7px;
border-radius: 999px;
background: rgba(255,255,255,0.06);
color: var(--t-3);
font-variant-numeric: tabular-nums;
}
.utab.is-active .utab-count { color: var(--t-1); background: rgba(255,255,255,0.10); }
.utab-underline {
position: absolute;
left: 12px; right: 12px;
bottom: 0;
height: 2px;
border-radius: 2px 2px 0 0;
opacity: 0;
transform: scaleX(0.4);
transform-origin: center;
transition: opacity .2s, transform .25s cubic-bezier(.4,1.2,.5,1);
}
.utab.is-active .utab-underline { opacity: 1; transform: scaleX(1); }
/* ─── Search ─── */
.search {
position: relative;
display: flex;
align-items: center;
gap: 8px;
padding: 0 12px;
background: var(--bg-2);
border: 1px solid var(--bd-1);
border-radius: 8px;
height: 36px;
min-width: 220px;
color: var(--t-3);
transition: border-color .15s, background .15s, box-shadow .15s;
}
.search-wide { min-width: 320px; flex: 0 1 380px; }
.search:focus-within {
border-color: color-mix(in srgb, var(--accent) 60%, var(--bd-2));
background: var(--bg-1);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 16%, transparent);
}
.search:focus-within { color: var(--t-1); }
.search input {
flex: 1; min-width: 0;
background: transparent; border: 0; outline: 0;
color: var(--t-1);
font: inherit;
font-size: 13px;
}
.search input::placeholder { color: var(--t-3); }
.search-kbd {
display: inline-grid; place-items: center;
min-width: 18px;
height: 18px;
padding: 0 5px;
border-radius: 4px;
background: rgba(255,255,255,0.06);
border: 1px solid var(--bd-1);
font-size: 11px;
color: var(--t-3);
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
.search:focus-within .search-kbd { opacity: 0.4; }
/* ─── Sort menu ─── */
.sort { position: relative; flex-shrink: 0; }
.sort-btn {
display: inline-flex; align-items: center; gap: 8px;
height: 36px; padding: 0 12px;
background: var(--bg-2);
border: 1px solid var(--bd-1);
border-radius: 8px;
color: var(--t-2);
font: inherit; font-size: 12.5px;
cursor: pointer;
transition: border-color .15s, color .15s;
}
.sort-btn:hover { color: var(--t-1); border-color: var(--bd-2); }
.sort-btn strong { color: var(--t-1); font-weight: 600; }
.sort-menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
z-index: 50;
min-width: 200px;
padding: 4px;
background: var(--bg-3);
border: 1px solid var(--bd-2);
border-radius: 10px;
box-shadow: 0 16px 40px -8px rgba(0,0,0,0.5), 0 0 0 1px rgba(255,255,255,0.04);
}
.sort-menu button {
display: flex; align-items: center; gap: 8px;
width: 100%;
padding: 8px 10px;
background: transparent;
border: 0;
border-radius: 6px;
color: var(--t-1);
font: inherit; font-size: 12.5px;
text-align: left;
cursor: pointer;
}
.sort-menu button:hover { background: rgba(255,255,255,0.06); }
.sort-check { width: 14px; display: inline-grid; place-items: center; color: var(--accent); }
/* ─── Directory button ─── */
.dirbtn {
display: inline-flex; align-items: center; gap: 8px;
height: 36px; padding: 0 12px;
background: var(--bg-2);
border: 1px solid var(--bd-1);
border-radius: 8px;
color: var(--t-2);
font: inherit; font-size: 12.5px;
cursor: pointer;
max-width: 360px;
transition: border-color .15s, color .15s;
flex-shrink: 1;
min-width: 0;
}
.dirbtn:hover { border-color: var(--bd-2); color: var(--t-1); }
.dirbtn-label { color: var(--t-1); font-weight: 600; flex-shrink: 0; }
.dirbtn-path {
color: var(--t-3);
font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
font-size: 11.5px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
min-width: 0;
}
/* ─── Kebab menu ─── */
.kebab { position: relative; }
.kebab-btn {
width: 36px; height: 36px;
display: grid; place-items: center;
background: var(--bg-2);
border: 1px solid var(--bd-1);
border-radius: 8px;
color: var(--t-2);
cursor: pointer;
transition: color .15s, border-color .15s;
}
.kebab-btn:hover { color: var(--t-1); border-color: var(--bd-2); }
.kebab-menu {
position: absolute;
top: calc(100% + 6px);
right: 0;
z-index: 50;
min-width: 180px;
padding: 4px;
background: var(--bg-3);
border: 1px solid var(--bd-2);
border-radius: 10px;
box-shadow: 0 16px 40px -8px rgba(0,0,0,0.5);
}
.kebab-menu button {
display: block;
width: 100%;
padding: 8px 10px;
background: transparent;
border: 0;
border-radius: 6px;
color: var(--t-1);
font: inherit; font-size: 12.5px;
text-align: left;
cursor: pointer;
}
.kebab-menu button:hover { background: rgba(255,255,255,0.06); }
.kebab-sep { height: 1px; background: var(--bd-1); margin: 4px 0; }
/* ─── Storage meter ─── */
.storage {
display: flex; flex-direction: column;
gap: 6px;
min-width: 240px;
}
.storage-compact { min-width: 200px; }
.storage-bar {
position: relative;
height: 6px;
background: rgba(255,255,255,0.06);
border-radius: 3px;
overflow: hidden;
}
.storage-i { position: absolute; top: 0; left: 0; bottom: 0; }
.storage-l {
position: absolute; top: 0; bottom: 0;
left: calc((var(--installed-pct, 15.3)) * 1%);
}
.storage-compact .storage-bar { height: 4px; }
.storage-text {
display: flex; align-items: center;
gap: 10px;
font-size: 11px;
color: var(--t-3);
font-variant-numeric: tabular-nums;
}
.storage-text > span { display: inline-flex; align-items: center; gap: 5px; }
.storage-sq {
width: 8px; height: 8px;
border-radius: 2px;
}
.storage-free { margin-left: auto; color: var(--t-2); }
/* ─── Grid wrapper / results bar ─── */
.grid-wrap {
flex: 1;
overflow: auto;
padding: 18px 24px 32px;
scrollbar-width: thin;
scrollbar-color: var(--bd-3) transparent;
}
.grid-wrap::-webkit-scrollbar { width: 10px; }
.grid-wrap::-webkit-scrollbar-thumb { background: var(--bd-3); border-radius: 5px; border: 2px solid transparent; background-clip: content-box; }
.results-bar {
display: flex; align-items: center; justify-content: space-between;
padding: 4px 4px 16px;
gap: 16px;
}
.results-count { color: var(--t-2); font-size: 12.5px; }
.results-count strong { color: var(--t-1); font-weight: 700; }
/* ─── Grid ─── */
.grid {
display: grid;
gap: var(--card-gap, 16px);
grid-template-columns: repeat(auto-fill, minmax(var(--card-min, 188px), 1fr));
}
.density-compact { --card-min: 148px; --card-gap: 12px; }
.density-normal { --card-min: 188px; --card-gap: 16px; }
.density-large { --card-min: 244px; --card-gap: 20px; }
/* ─── Card ─── */
.card {
position: relative;
display: flex;
flex-direction: column;
background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%);
border: 1px solid var(--bd-1);
border-radius: var(--radius-md);
cursor: pointer;
overflow: hidden;
transition: transform .18s cubic-bezier(.4,1.2,.5,1), border-color .18s, box-shadow .18s;
outline: 0;
}
.card:hover, .card:focus-visible {
transform: translateY(-2px);
border-color: color-mix(in srgb, var(--accent) 45%, var(--bd-2));
box-shadow:
0 14px 30px -16px color-mix(in srgb, var(--accent) 50%, black),
0 0 0 1px color-mix(in srgb, var(--accent) 30%, transparent);
}
.card:focus-visible {
box-shadow:
0 14px 30px -16px color-mix(in srgb, var(--accent) 50%, black),
0 0 0 2px var(--accent);
}
/* ─── Cover ─── */
.card-cover-wrap {
position: relative;
width: 100%;
overflow: hidden;
background: var(--bg-3);
}
.card-cover-wrap[data-aspect="box"] { aspect-ratio: 2 / 3; }
.card-cover-wrap[data-aspect="square"] { aspect-ratio: 1 / 1; }
.card-cover-wrap[data-aspect="banner"] { aspect-ratio: 16 / 9; }
.cover {
position: absolute; inset: 0;
overflow: hidden;
transition: transform .35s cubic-bezier(.4,1.2,.5,1);
}
.card:hover .cover { transform: scale(1.03); }
.cover-base, .cover-blob, .cover-grain, .cover-vignette, .cover-mark { position: absolute; inset: 0; pointer-events: none; }
.cover-grain {
background-image:
repeating-linear-gradient(0deg, rgba(255,255,255,0.018) 0 1px, transparent 1px 3px),
repeating-linear-gradient(90deg, rgba(0,0,0,0.04) 0 1px, transparent 1px 3px);
mix-blend-mode: overlay;
opacity: 0.7;
}
.cover-vignette {
background: linear-gradient(180deg, transparent 30%, rgba(0,0,0,0.62) 100%);
}
.cover-mark { width: 100%; height: 100%; }
.cover-titlewrap {
position: absolute;
left: 0; right: 0; bottom: 0;
z-index: 2;
padding: 14px 14px 14px;
}
.cover-title {
font-family: var(--font-display);
font-weight: 400;
letter-spacing: 0.018em;
line-height: 1.02;
text-transform: uppercase;
color: white;
overflow-wrap: normal;
word-break: normal;
}
.cover-sub {
font-family: var(--font-ui);
font-size: 10px;
font-weight: 700;
letter-spacing: 0.18em;
text-transform: uppercase;
opacity: 0.85;
}
/* banner mode: title centered + smaller padding */
.card-cover-wrap[data-aspect="banner"] .cover-titlewrap {
padding: 14px 18px;
}
/* ─── State chip ─── */
.state-chip {
position: absolute;
top: 10px; right: 10px;
z-index: 3;
display: inline-flex; align-items: center; gap: 6px;
padding: 4px 9px;
border-radius: 999px;
background: rgba(8,12,16,0.78);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
border: 1px solid rgba(255,255,255,0.08);
font-size: 10.5px;
font-weight: 600;
color: var(--t-1);
letter-spacing: 0.01em;
}
.state-dot { width: 6px; height: 6px; border-radius: 999px; box-shadow: 0 0 8px currentColor; }
.state-chip[data-state="installed"] .state-dot { box-shadow: 0 0 8px var(--ok); }
.state-chip[data-state="local"] .state-dot { box-shadow: 0 0 8px var(--warn); }
/* Multiplayer badge */
.card-mp {
position: absolute;
top: 10px; left: 10px;
z-index: 3;
display: inline-flex; align-items: center; gap: 4px;
padding: 4px 8px;
border-radius: 999px;
background: rgba(8,12,16,0.65);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
border: 1px solid rgba(255,255,255,0.06);
font-size: 10.5px;
font-weight: 600;
color: var(--t-1);
font-variant-numeric: tabular-nums;
}
/* ─── Card body ─── */
.card-body {
padding: 11px 12px 12px;
display: flex; flex-direction: column;
gap: 8px;
}
.card-title {
font-weight: 600;
font-size: 13.5px;
color: var(--t-1);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
letter-spacing: -0.005em;
}
.card-meta {
display: flex; align-items: center; gap: 6px;
font-size: 11.5px;
color: var(--t-3);
font-variant-numeric: tabular-nums;
}
.card-meta .card-dot { opacity: 0.5; }
.density-compact .card-body { padding: 9px 10px 10px; gap: 6px; }
.density-compact .card-title { font-size: 12.5px; }
.density-compact .card-meta { font-size: 11px; }
.density-large .card-body { padding: 14px 14px 14px; gap: 10px; }
.density-large .card-title { font-size: 15px; }
/* ─── Action buttons ─── */
.act-btn {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
height: 32px;
padding: 0 14px;
border-radius: 7px;
border: 0;
font: inherit;
font-weight: 600;
font-size: 12.5px;
letter-spacing: 0.005em;
cursor: pointer;
transition: transform .12s, filter .12s, background .15s;
white-space: nowrap;
}
.act-btn:hover { filter: brightness(1.12); }
.act-btn:active { transform: scale(0.98); }
.act-full { width: 100%; }
.act-lg { height: 44px; padding: 0 22px; font-size: 14px; gap: 8px; }
.act-lg svg { width: 14px; height: 14px; }
.act-play {
color: white;
background: linear-gradient(180deg, #2bd07f 0%, #1aa460 100%);
box-shadow: 0 6px 16px -8px #1aa460, inset 0 1px 0 rgba(255,255,255,0.25);
}
.act-install {
color: white;
background: var(--accent);
box-shadow: 0 6px 16px -8px color-mix(in srgb, var(--accent) 80%, black), inset 0 1px 0 rgba(255,255,255,0.22);
}
.act-download {
color: var(--t-1);
background: rgba(255,255,255,0.08);
border: 1px solid var(--bd-2);
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04);
}
.act-download:hover { background: rgba(255,255,255,0.12); border-color: var(--bd-3); }
/* ─── Download progress (in place of action button when state === 'downloading') ─── */
.dl {
position: relative;
overflow: hidden;
border-radius: 7px;
border: 1px solid color-mix(in srgb, var(--accent) 45%, var(--bd-2));
background: rgba(255,255,255,0.04);
color: var(--t-1);
font: inherit;
font-variant-numeric: tabular-nums;
container-type: inline-size;
isolation: isolate;
box-shadow: inset 0 1px 0 rgba(255,255,255,0.04),
0 0 0 1px color-mix(in srgb, var(--accent) 16%, transparent);
}
.dl-full { width: 100%; }
.dl-fill {
position: absolute; inset: 0 auto 0 0;
width: 0%;
background:
linear-gradient(180deg,
color-mix(in srgb, var(--accent) 38%, transparent) 0%,
color-mix(in srgb, var(--accent) 26%, transparent) 100%);
border-right: 1px solid color-mix(in srgb, var(--accent) 75%, transparent);
box-shadow: 2px 0 8px color-mix(in srgb, var(--accent) 35%, transparent);
transition: width 480ms cubic-bezier(.4,0,.2,1);
z-index: 0;
}
/* shimmering scanline on top of the fill so it reads as 'live' */
.dl-fill::after {
content: '';
position: absolute; inset: 0;
background:
repeating-linear-gradient(115deg,
transparent 0 14px,
rgba(255,255,255,0.05) 14px 22px);
background-size: 200% 100%;
animation: dl-stripe 1.4s linear infinite;
mix-blend-mode: screen;
opacity: 0.85;
}
@keyframes dl-stripe {
from { background-position: 0% 0%; }
to { background-position: -36px 0%; }
}
/* live pulse dot */
.dl-pulse {
width: 7px; height: 7px; border-radius: 99px;
background: var(--accent);
box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent);
animation: dl-pulse 1.4s ease-out infinite;
flex: 0 0 auto;
}
@keyframes dl-pulse {
0% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 70%, transparent); }
70% { box-shadow: 0 0 0 6px color-mix(in srgb, var(--accent) 0%, transparent); }
100% { box-shadow: 0 0 0 0 color-mix(in srgb, var(--accent) 0%, transparent); }
}
/* ── md (card tile) ── */
.dl-md {
height: 32px;
padding: 0 10px;
}
.dl-md-row {
position: relative; z-index: 1;
display: flex; align-items: center; justify-content: space-between;
width: 100%; height: 100%;
gap: 8px;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.005em;
}
.dl-md .dl-pct {
display: inline-flex; align-items: center;
color: var(--t-1);
}
.dl-md .dl-pulse { margin-right: 6px; }
.dl-md .dl-pct-sym { opacity: 0.55; font-weight: 600; margin-left: 1px; }
.dl-md .dl-speed {
color: var(--t-2);
font-size: 11px;
font-weight: 500;
font-variant-numeric: tabular-nums;
}
/* Container-query graceful degradation: when the tile is narrow,
drop the speed and centre the percentage so nothing truncates. */
@container (max-width: 132px) {
.dl-md .dl-speed { display: none; }
.dl-md-row { justify-content: center; gap: 6px; }
}
@container (max-width: 96px) {
.dl-md .dl-pulse { display: none; }
}
/* Density tuning — match the existing button heights */
.density-compact .dl-md { height: 30px; padding: 0 9px; }
.density-compact .dl-md-row { font-size: 11.5px; }
.density-compact .dl-md .dl-speed { font-size: 10.5px; }
.density-large .dl-md { height: 34px; padding: 0 12px; }
.density-large .dl-md-row { font-size: 13px; }
.density-large .dl-md .dl-speed { font-size: 11.5px; }
/* ── lg (detail overlay) ── */
.dl-lg {
height: 56px;
padding: 0;
border-radius: 9px;
flex: 1 1 auto;
min-width: 260px;
}
.dl-lg-grid {
position: relative; z-index: 1;
display: grid;
grid-template-columns: minmax(0, 1fr) auto auto;
grid-template-rows: auto auto;
grid-template-areas:
"primary pct cancel"
"secondary pct cancel";
align-items: center;
height: 100%;
padding: 0 14px 0 16px;
column-gap: 14px;
row-gap: 2px;
}
.dl-lg-primary {
grid-area: primary;
display: flex; align-items: center; gap: 8px;
font-size: 13px;
font-weight: 600;
letter-spacing: 0.02em;
text-transform: uppercase;
color: color-mix(in srgb, var(--accent) 80%, white);
min-width: 0;
}
.dl-lg-primary .dl-label { white-space: nowrap; }
.dl-lg-secondary {
grid-area: secondary;
display: flex; align-items: center; gap: 7px;
font-size: 12px;
font-weight: 500;
color: var(--t-2);
min-width: 0;
overflow: hidden;
}
.dl-lg-secondary .dl-bytes {
color: var(--t-1);
font-weight: 600;
white-space: nowrap;
}
.dl-lg-secondary .dl-bytes .dl-of { color: var(--t-2); font-weight: 500; }
.dl-lg-secondary .dl-speed { color: var(--t-1); font-weight: 600; white-space: nowrap; }
.dl-lg-secondary .dl-peers {
display: inline-flex; align-items: center; gap: 5px;
color: var(--t-2); white-space: nowrap;
}
.dl-lg-secondary .dl-peers strong { color: var(--t-1); font-weight: 600; font-variant-numeric: tabular-nums; }
.dl-lg-secondary .dl-peers svg { opacity: 0.7; }
.dl-lg-secondary .dl-eta { white-space: nowrap; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
.dl-sep { opacity: 0.45; }
/* Gracefully drop the ETA when the modal is narrow */
@container (max-width: 380px) {
.dl-lg-secondary .dl-eta,
.dl-lg-secondary .dl-sep-eta { display: none; }
}
/* Even narrower: drop peers too, keep size + speed */
@container (max-width: 300px) {
.dl-lg-secondary .dl-peers,
.dl-lg-secondary .dl-sep-peers { display: none; }
}
.dl-lg-pct {
grid-area: pct;
font-size: 20px;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--t-1);
font-variant-numeric: tabular-nums;
line-height: 1;
}
.dl-lg-pct .dl-pct-sym {
font-size: 12px;
font-weight: 600;
opacity: 0.55;
margin-left: 1px;
}
.dl-cancel {
grid-area: cancel;
display: inline-flex; align-items: center; justify-content: center;
width: 28px; height: 28px;
border-radius: 6px;
border: 1px solid var(--bd-2);
background: rgba(255,255,255,0.04);
color: var(--t-2);
cursor: pointer;
transition: background .15s, border-color .15s, color .15s;
}
.dl-cancel:hover {
background: rgba(239,68,68,0.12);
border-color: rgba(239,68,68,0.40);
color: #fca5a5;
}
/* Ghost / secondary */
.ghost-btn {
display: inline-flex; align-items: center; gap: 7px;
height: 44px; padding: 0 18px;
background: rgba(255,255,255,0.04);
border: 1px solid var(--bd-2);
border-radius: 8px;
color: var(--t-1);
font: inherit; font-size: 13.5px; font-weight: 600;
cursor: pointer;
transition: background .15s, border-color .15s, color .15s;
}
.ghost-btn:hover { background: rgba(255,255,255,0.08); border-color: var(--bd-3); }
.ghost-danger { color: #f87171; }
.ghost-danger:hover { background: rgba(239,68,68,0.10); border-color: rgba(239,68,68,0.40); color: #fca5a5; }
/* ─── Modal ─── */
.modal-scrim {
position: absolute;
inset: 0;
z-index: 100;
background: rgba(4,7,11,0.7);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
display: grid;
place-items: center;
padding: 32px;
animation: fadein .18s ease;
}
@keyframes fadein { from { opacity: 0 } to { opacity: 1 } }
.modal {
width: min(880px, 100%);
max-height: 100%;
background: linear-gradient(180deg, var(--bg-2) 0%, var(--bg-1) 100%);
border: 1px solid var(--bd-2);
border-radius: 14px;
overflow: hidden;
position: relative;
box-shadow: 0 30px 80px -10px rgba(0,0,0,0.7), 0 0 0 1px rgba(255,255,255,0.04);
display: flex; flex-direction: column;
animation: modalin .25s cubic-bezier(.3,1.3,.4,1);
}
@keyframes modalin { from { transform: scale(.96) translateY(8px); opacity: 0 } to { transform: scale(1) translateY(0); opacity: 1 } }
.modal-close {
position: absolute;
top: 14px; right: 14px;
z-index: 5;
width: 32px; height: 32px;
display: grid; place-items: center;
background: rgba(8,12,16,0.7);
border: 1px solid var(--bd-2);
border-radius: 8px;
color: var(--t-1);
cursor: pointer;
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
transition: background .15s, border-color .15s;
}
.modal-close:hover { background: rgba(255,255,255,0.10); border-color: var(--bd-3); }
.modal-hero {
position: relative;
aspect-ratio: 16 / 7;
overflow: hidden;
}
.modal-hero .cover { transform: none !important; }
.modal-hero-fade {
position: absolute; inset: 0;
background: linear-gradient(180deg, transparent 40%, var(--bg-2) 100%);
pointer-events: none;
}
.modal-hero-text {
position: absolute;
left: 28px; right: 28px; bottom: 22px;
z-index: 2;
}
.modal-hero-text .modal-title {
font-family: var(--font-ui);
font-size: 32px;
font-weight: 700;
letter-spacing: -0.015em;
color: white;
margin: 6px 0 0;
text-shadow: 0 4px 24px rgba(0,0,0,0.6);
}
.modal-tags { display: flex; gap: 6px; flex-wrap: wrap; }
.modal-tag {
display: inline-block;
padding: 3px 8px;
background: rgba(8,12,16,0.6);
-webkit-backdrop-filter: blur(8px);
backdrop-filter: blur(8px);
border: 1px solid var(--bd-2);
border-radius: 4px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.04em;
text-transform: uppercase;
color: var(--t-1);
}
.modal-state {
position: absolute;
top: 18px;
left: 24px;
z-index: 3;
}
.modal-state .state-chip {
position: static;
font-size: 11.5px;
padding: 5px 11px;
}
/* Banner cover treatment inside modal: hide the cover's own title (we show our own h2) */
.modal-hero .cover-titlewrap { opacity: 0.14; }
.modal-body {
padding: 22px 28px 26px;
display: flex; flex-direction: column; gap: 18px;
}
.modal-meta {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
}
.meta-cell {
padding: 10px 12px;
background: rgba(255,255,255,0.025);
border: 1px solid var(--bd-1);
border-radius: 8px;
}
.meta-label {
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--t-3);
}
.meta-value {
margin-top: 4px;
font-size: 14px;
font-weight: 600;
color: var(--t-1);
display: flex; align-items: center; gap: 6px;
}
.meta-mono { font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace; font-size: 13px; }
.modal-desc {
margin: 0;
font-size: 14px;
line-height: 1.55;
color: var(--t-2);
text-wrap: pretty;
max-width: 64ch;
}
.modal-actions {
display: flex; align-items: center; gap: 10px;
padding-top: 4px;
}
.modal-actions-spacer { flex: 1; }
/* ─── Settings dialog ─── */
.settings-modal {
width: min(640px, 100%);
background: var(--bg-2);
}
.settings-head {
position: relative;
padding: 22px 28px 18px;
border-bottom: 1px solid var(--bd-1);
}
.settings-head h2 {
margin: 0;
font-size: 20px;
font-weight: 700;
letter-spacing: -0.01em;
color: var(--t-1);
}
.settings-close {
position: absolute;
top: 18px;
right: 18px;
background: transparent;
}
.settings-close:hover { background: rgba(255,255,255,0.06); }
.settings-body {
padding: 22px 28px 26px;
display: flex; flex-direction: column;
gap: 26px;
max-height: 70vh;
overflow: auto;
}
.settings-section {
display: flex; flex-direction: column;
gap: 14px;
}
.settings-section-title {
font-size: 10.5px;
font-weight: 700;
letter-spacing: 0.12em;
text-transform: uppercase;
color: var(--t-3);
}
.settings-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 24px;
}
.settings-row-info { min-width: 0; flex: 1; }
.settings-row-label {
font-size: 14px;
font-weight: 600;
color: var(--t-1);
}
.settings-row-hint {
margin-top: 3px;
font-size: 12px;
color: var(--t-3);
}
.settings-row-control { flex-shrink: 0; }
.settings-foot {
display: flex;
justify-content: flex-end;
padding: 14px 22px 18px;
border-top: 1px solid var(--bd-1);
gap: 10px;
}
.settings-done {
height: 36px;
padding: 0 22px;
font-size: 13.5px;
}
.settings-done:hover {
filter: brightness(1.1);
border-color: transparent !important;
}
/* ─── Settings: color swatches ─── */
.swatch-row {
display: inline-flex;
gap: 8px;
}
.swatch {
position: relative;
width: 32px; height: 32px;
padding: 0;
background: transparent;
border: 0;
border-radius: 9px;
cursor: pointer;
}
.swatch-dot {
display: block;
width: 100%; height: 100%;
border-radius: 8px;
box-shadow: inset 0 0 0 1px rgba(255,255,255,0.08);
transition: transform .15s, box-shadow .15s;
}
.swatch:hover .swatch-dot { transform: scale(1.06); }
.swatch.is-active .swatch-dot {
box-shadow: 0 0 0 2px var(--bg-2), 0 0 0 4px currentColor;
}
.swatch-check {
position: absolute;
inset: 0;
display: grid;
place-items: center;
color: white;
filter: drop-shadow(0 1px 2px rgba(0,0,0,0.5));
pointer-events: none;
}
/* ─── Settings: segmented radio ─── */
.srad {
display: inline-flex;
background: var(--bg-3);
border: 1px solid var(--bd-1);
border-radius: 8px;
padding: 3px;
}
.srad-btn {
display: inline-flex; align-items: center;
height: 30px;
padding: 0 14px;
background: transparent;
border: 1px solid transparent;
border-radius: 6px;
color: var(--t-2);
font: inherit;
font-weight: 600;
font-size: 12.5px;
cursor: pointer;
transition: color .15s, background .15s;
white-space: nowrap;
}
.srad-btn:hover { color: var(--t-1); }
.srad-btn.is-active {
color: white;
box-shadow: 0 2px 8px -2px rgba(0,0,0,0.4), inset 0 1px 0 rgba(255,255,255,0.18);
}