91c709960a
Document the profile settings added to the launcher design and the new Start Server detail action. The settings contract now includes a persisted username and language choice, and the game detail overlay shows Start Server only for installed games that can host a dedicated server. The reference mock now includes the matching Profile controls, a server icon, server-capable sample catalog entries, and the updated detail/settings artboards so implementation can follow the selected design direction. Test Plan: - git diff --cached --check Refs: design/README.md
1186 lines
31 KiB
CSS
1186 lines
31 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); }
|
|
|
|
/* Start Server — secondary "primary" action sitting next to Play.
|
|
Uses the accent as a tinted fill + border so it reads as host-action
|
|
without competing with the green Play button. */
|
|
.act-server {
|
|
color: var(--t-1);
|
|
background: color-mix(in srgb, var(--accent) 14%, rgba(255,255,255,0.04));
|
|
border: 1px solid color-mix(in srgb, var(--accent) 55%, transparent);
|
|
box-shadow: inset 0 1px 0 rgba(255,255,255,0.06);
|
|
}
|
|
.act-server:hover {
|
|
background: color-mix(in srgb, var(--accent) 22%, rgba(255,255,255,0.04));
|
|
border-color: color-mix(in srgb, var(--accent) 75%, transparent);
|
|
filter: none;
|
|
}
|
|
.act-server svg { color: var(--accent); }
|
|
|
|
/* ─── 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: 4px;
|
|
color: var(--t-1); font-weight: 600; font-variant-numeric: tabular-nums;
|
|
white-space: nowrap;
|
|
}
|
|
.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: 320px) {
|
|
.dl-lg-secondary .dl-eta,
|
|
.dl-lg-secondary .dl-sep-eta { display: none; }
|
|
}
|
|
/* Even narrower: drop peers too, keep size + speed */
|
|
@container (max-width: 240px) {
|
|
.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);
|
|
}
|
|
|
|
/* ─── Settings: text input ─── */
|
|
.settings-text {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
background: var(--bg-3);
|
|
border: 1px solid var(--bd-1);
|
|
border-radius: 8px;
|
|
padding: 0 12px;
|
|
height: 36px;
|
|
width: 220px;
|
|
transition: border-color .15s, box-shadow .15s, background .15s;
|
|
}
|
|
.settings-text:focus-within {
|
|
background: var(--bg-2);
|
|
border-color: var(--accent, #3b82f6);
|
|
box-shadow: 0 0 0 3px color-mix(in oklab, var(--accent, #3b82f6) 22%, transparent);
|
|
}
|
|
.settings-text input {
|
|
flex: 1; min-width: 0;
|
|
background: transparent;
|
|
border: 0; outline: 0;
|
|
color: var(--t-1);
|
|
font: inherit;
|
|
font-size: 13.5px;
|
|
font-weight: 600;
|
|
letter-spacing: 0.1px;
|
|
}
|
|
.settings-text input::placeholder {
|
|
color: var(--t-3);
|
|
font-weight: 500;
|
|
}
|