[style](trx-frontend-http): refine web UI design system and a11y #1

Merged
sjg merged 1 commits from style/web-ui-polish into main 2026-07-17 21:00:02 +02:00
2 changed files with 177 additions and 61 deletions
@@ -104,24 +104,24 @@ SPDX-License-Identifier: GPL-2.0-or-later
</div> </div>
</div> </div>
<!-- Auth gate (hidden by default, shown if auth is required) --> <!-- Auth gate (hidden by default, shown if auth is required) -->
<div id="auth-gate" style="display:none; max-width: 30rem; margin: 0 auto 0.9rem; padding: 1.25rem 0 1.5rem; text-align: center;"> <div id="auth-gate" class="auth-gate" style="display:none;">
<div style="margin-bottom: 1.5rem;"> <div class="auth-gate-head">
<div style="font-size: 1.1rem; font-weight: 600; margin-bottom: 0.5rem;">Access Required</div> <div class="auth-gate-title">Access Required</div>
<div style="color: var(--text-muted);">Enter passphrase to continue</div> <div class="auth-gate-sub">Enter passphrase to continue</div>
</div> </div>
<form id="auth-form" style="margin: 1rem 0 0.35rem;"> <form id="auth-form" class="auth-form">
<input type="password" id="auth-passphrase" placeholder="Passphrase" autocomplete="off" style="width: 100%; padding: 0.65rem 0.75rem; margin-bottom: 1rem; border: 1px solid var(--border-light); border-radius: 0.45rem; background: var(--input-bg); color: var(--text); font-size: 1rem; box-sizing: border-box;" /> <input type="password" id="auth-passphrase" class="auth-input" placeholder="Passphrase" autocomplete="off" />
<button type="submit" style="width: 100%; padding: 0.65rem 0.75rem; background: var(--accent-green); color: #fff; border: none; border-radius: 0.45rem; font-weight: 700; cursor: pointer; font-size: 1rem; box-sizing: border-box;">Login</button> <button type="submit" class="auth-submit">Login</button>
</form> </form>
<button id="auth-guest-btn" type="button" style="width: 100%; padding: 0.65rem 0.75rem; background: var(--btn-bg); color: var(--text); border: 1px solid var(--border-light); border-radius: 0.45rem; font-weight: 600; cursor: pointer; font-size: 1rem; box-sizing: border-box; margin-top: 0; display: none;">Continue as Guest</button> <button id="auth-guest-btn" type="button" class="auth-guest" style="display: none;">Continue as Guest</button>
<div id="auth-error" style="color: #ff6b6b; font-size: 0.9rem; margin-top: 1rem; display: none;"></div> <div id="auth-error" class="auth-error" style="display: none;"></div>
<div id="auth-role" style="margin-top: 1rem; color: var(--text-muted); font-size: 0.85rem; display: none;"></div> <div id="auth-role" class="auth-role" style="display: none;"></div>
</div> </div>
<div id="tab-main" class="tab-panel"> <div id="tab-main" class="tab-panel">
<div id="server-lost-banner" aria-live="assertive"><span class="banner-dot"></span>trx-server connection lost — waiting for reconnect</div> <div id="server-lost-banner" aria-live="assertive"><span class="banner-dot"></span>trx-server connection lost — waiting for reconnect</div>
<div id="loading" role="status" aria-live="polite" style="text-align:center; padding:2rem 0;"> <div id="loading" role="status" aria-live="polite" style="text-align:center; padding:2rem 0;">
<div id="loading-title" style="margin-bottom:0.4rem; font-size:1.1rem; font-weight:600;">Initializing (rig)…</div> <div id="loading-title" style="margin-bottom:0.4rem; font-size:1.1rem; font-weight:600;">Initializing (rig)…</div>
<div id="loading-sub" style="color:#9aa4b5;"></div> <div id="loading-sub" style="color:var(--text-muted);"></div>
</div> </div>
<div id="content" style="display:none;"> <div id="content" style="display:none;">
<div class="signal-visual-block"> <div class="signal-visual-block">
@@ -47,6 +47,50 @@ SPDX-License-Identifier: GPL-2.0-or-later
--border-hover: color-mix(in srgb, var(--border-light) 80%, var(--text) 20%); --border-hover: color-mix(in srgb, var(--border-light) 80%, var(--text) 20%);
--accent-green-hover: color-mix(in srgb, var(--accent-green) 85%, #fff 15%); --accent-green-hover: color-mix(in srgb, var(--accent-green) 85%, #fff 15%);
--accent-green-active: color-mix(in srgb, var(--accent-green) 75%, #fff 25%); --accent-green-active: color-mix(in srgb, var(--accent-green) 75%, #fff 25%);
/* Accent tuned for text/links: mixes toward the theme's text colour,
which is always the higher-contrast direction (lighter on dark
themes, darker on light). Use for accent-coloured text; keep
--accent-green for fills, indicators and meters. */
--accent-text: color-mix(in srgb, var(--accent-green) 82%, var(--text) 18%);
/* ── Design tokens ──────────────────────────────────────────────────
Derived tokens use color-mix over themed variables, so they
re-resolve per active [data-style]/[data-theme] automatically. */
/* Elevated surface, one step lighter than --card-bg. Consumed by
.controls-tray and other raised panels. */
--surface: color-mix(in srgb, var(--card-bg) 90%, var(--text) 7%);
/* Type scale */
--fs-xs: 0.75rem;
--fs-sm: 0.85rem;
--fs-base: 1rem;
--fs-md: 1.125rem;
--fs-lg: 1.25rem;
--fs-xl: 1.5rem;
--fs-2xl: 2rem;
/* Spacing scale (4px grid) */
--space-1: 0.25rem;
--space-2: 0.5rem;
--space-3: 0.75rem;
--space-4: 1rem;
--space-5: 1.25rem;
--space-6: 1.5rem;
--space-8: 2rem;
/* Corner radii */
--radius-sm: 6px;
--radius-md: 0.5rem;
--radius-lg: 1rem;
--radius-pill: 999px;
/* Motion */
--dur-fast: 100ms;
--dur-base: 180ms;
--dur-slow: 300ms;
--ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
--ease-out: cubic-bezier(0, 0, 0.2, 1);
} }
[data-theme="light"] { [data-theme="light"] {
@@ -89,6 +133,10 @@ SPDX-License-Identifier: GPL-2.0-or-later
body { body {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
font-size: var(--fs-base);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
margin: 0; margin: 0;
min-height: 100vh; min-height: 100vh;
min-height: 100dvh; min-height: 100dvh;
@@ -120,6 +168,57 @@ body {
); );
} }
} }
/* ── Auth gate ────────────────────────────────────────────────────────
Class-based; #display toggling stays inline (driven by app.js). */
.auth-gate {
max-width: 30rem;
margin: 0 auto 0.9rem;
padding: var(--space-5) 0 var(--space-6);
text-align: center;
}
.auth-gate-head { margin-bottom: var(--space-6); }
.auth-gate-title { font-size: var(--fs-md); font-weight: 600; margin-bottom: var(--space-2); }
.auth-gate-sub { color: var(--text-muted); }
.auth-form { margin: var(--space-4) 0 0.35rem; }
.auth-input {
width: 100%;
padding: 0.65rem 0.75rem;
margin-bottom: var(--space-4);
border: 1px solid var(--border-light);
border-radius: var(--radius-md);
background: var(--input-bg);
color: var(--text);
font-size: var(--fs-base);
box-sizing: border-box;
}
.auth-submit,
.auth-guest {
width: 100%;
padding: 0.65rem 0.75rem;
border-radius: var(--radius-md);
font-size: var(--fs-base);
cursor: pointer;
box-sizing: border-box;
transition: background-color var(--dur-fast) var(--ease-standard);
}
.auth-submit {
background: var(--accent-green);
color: #fff;
border: none;
font-weight: 700;
}
.auth-submit:hover:not(:disabled) { background: var(--accent-green-hover); }
.auth-guest {
background: var(--btn-bg);
color: var(--text);
border: 1px solid var(--border-light);
font-weight: 600;
margin-top: var(--space-4);
}
.auth-guest:hover:not(:disabled) { background: var(--btn-hover-bg); }
.auth-error { color: var(--accent-red); font-size: var(--fs-sm); margin-top: var(--space-4); }
.auth-role { margin-top: var(--space-4); color: var(--text-muted); font-size: var(--fs-sm); }
.label { color: var(--text-muted); font-size: 0.9rem; margin-bottom: 6px; display: block; } .label { color: var(--text-muted); font-size: 0.9rem; margin-bottom: 6px; display: block; }
#tab-main .label > span { #tab-main .label > span {
display: inline-block; display: inline-block;
@@ -220,7 +319,7 @@ input.status-input, select.status-input { width: 100%; padding: 0.45rem 0.5rem;
align-items: stretch; align-items: stretch;
gap: 0.22rem; gap: 0.22rem;
color: var(--text-muted); color: var(--text-muted);
font-size: 0.72rem; font-size: 0.75rem;
line-height: 1.1; line-height: 1.1;
white-space: nowrap; white-space: nowrap;
} }
@@ -408,7 +507,7 @@ input.status-input, select.status-input { width: 100%; padding: 0.45rem 0.5rem;
border-radius: 0; border-radius: 0;
height: 100%; height: 100%;
padding: 0 0.65rem; padding: 0 0.65rem;
font-size: 0.92rem; font-size: 0.9rem;
background: var(--input-bg); background: var(--input-bg);
color: var(--text-muted); color: var(--text-muted);
cursor: pointer; cursor: pointer;
@@ -486,7 +585,7 @@ input.status-input, select.status-input { width: 100%; padding: 0.45rem 0.5rem;
} }
.scheduler-cycle-status { .scheduler-cycle-status {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.74rem; font-size: 0.75rem;
text-align: left; text-align: left;
opacity: 0.88; opacity: 0.88;
} }
@@ -1357,7 +1456,7 @@ small { color: var(--text-muted); }
} }
.header-logo { height: 4.6em; width: auto; flex-shrink: 0; filter: drop-shadow(0 4px 12px rgba(0,0,0,0.35)); } .header-logo { height: 4.6em; width: auto; flex-shrink: 0; filter: drop-shadow(0 4px 12px rgba(0,0,0,0.35)); }
.subtitle { color: var(--text-muted); font-size: 0.95rem; } .subtitle { color: var(--text-muted); font-size: 0.95rem; }
.subtitle a { color: var(--accent-green); text-decoration: none; } .subtitle a { color: var(--accent-text); text-decoration: none; }
.subtitle a:hover { text-decoration: underline; } .subtitle a:hover { text-decoration: underline; }
.band-tag { display: inline-block; padding: 2px 6px; border-radius: 6px; background: var(--btn-bg); color: var(--text); font-size: 0.82rem; border: 1px solid var(--border-light); margin-left: 6px; } .band-tag { display: inline-block; padding: 2px 6px; border-radius: 6px; background: var(--btn-bg); color: var(--text); font-size: 0.82rem; border: 1px solid var(--border-light); margin-left: 6px; }
.signal { display: flex; gap: 0.6rem; align-items: center; } .signal { display: flex; gap: 0.6rem; align-items: center; }
@@ -1433,7 +1532,7 @@ small { color: var(--text-muted); }
font-size: 0.95rem; font-size: 0.95rem;
height: auto; height: auto;
} }
.tab.active { border-bottom-color: var(--accent-green); color: var(--accent-green); font-weight: 600; } .tab.active { border-bottom-color: var(--accent-green); color: var(--accent-text); font-weight: 600; }
.tab:hover:not(.active) { color: var(--text); } .tab:hover:not(.active) { color: var(--text); }
/* Tab icons — hidden on desktop, shown on mobile bottom nav */ /* Tab icons — hidden on desktop, shown on mobile bottom nav */
.tab-icon { .tab-icon {
@@ -1458,7 +1557,7 @@ small { color: var(--text-muted); }
.footer { display: flex; justify-content: space-between; align-items: baseline; margin-top: auto; padding-top: 1rem; flex-shrink: 0; } .footer { display: flex; justify-content: space-between; align-items: baseline; margin-top: auto; padding-top: 1rem; flex-shrink: 0; }
.full-row { grid-column: 1 / -1; } .full-row { grid-column: 1 / -1; }
.copyright { color: var(--text-muted); font-size: 0.75rem; opacity: 0.7; } .copyright { color: var(--text-muted); font-size: 0.75rem; opacity: 0.7; }
.copyright a { color: var(--accent-green); text-decoration: none; } .copyright a { color: var(--accent-text); text-decoration: none; }
.copyright a:hover { text-decoration: underline; } .copyright a:hover { text-decoration: underline; }
.gh-link-wrap { .gh-link-wrap {
display: inline-flex; display: inline-flex;
@@ -1499,7 +1598,7 @@ small { color: var(--text-muted); }
white-space: nowrap; white-space: nowrap;
} }
.vol-pct { .vol-pct {
font-size: 0.72rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--text-muted);
line-height: 1; line-height: 1;
} }
@@ -1602,7 +1701,7 @@ small { color: var(--text-muted); }
} }
.shortcut-table td { .shortcut-table td {
padding: 0.32rem 0.4rem; padding: 0.32rem 0.4rem;
font-size: 0.88rem; font-size: 0.85rem;
color: var(--text); color: var(--text);
border-bottom: 1px solid color-mix(in srgb, var(--border-light) 40%, transparent); border-bottom: 1px solid color-mix(in srgb, var(--border-light) 40%, transparent);
} }
@@ -1632,7 +1731,7 @@ small { color: var(--text-muted); }
.shortcut-overlay-hint { .shortcut-overlay-hint {
margin-top: 0.7rem; margin-top: 0.7rem;
text-align: center; text-align: center;
font-size: 0.76rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--text-muted);
} }
@@ -1706,7 +1805,7 @@ small { color: var(--text-muted); }
text-align: center; text-align: center;
} }
.decode-history-overlay-title { .decode-history-overlay-title {
font-size: 0.98rem; font-size: 1rem;
font-weight: 800; font-weight: 800;
color: var(--text-heading); color: var(--text-heading);
} }
@@ -1756,7 +1855,7 @@ small { color: var(--text-muted); }
gap: 0.75rem; gap: 0.75rem;
} }
.map-qso-summary-title { .map-qso-summary-title {
font-size: 0.88rem; font-size: 0.85rem;
font-weight: 800; font-weight: 800;
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
@@ -1841,7 +1940,7 @@ button.map-qso-card:focus-visible {
border-radius: 999px; border-radius: 999px;
background: color-mix(in srgb, var(--accent-green) 16%, transparent); background: color-mix(in srgb, var(--accent-green) 16%, transparent);
color: var(--accent-green); color: var(--accent-green);
font-size: 0.76rem; font-size: 0.75rem;
font-weight: 800; font-weight: 800;
} }
.map-qso-card-distance { .map-qso-card-distance {
@@ -1858,7 +1957,7 @@ button.map-qso-card:focus-visible {
min-width: 0; min-width: 0;
} }
.map-qso-card-pair { .map-qso-card-pair {
font-size: 0.92rem; font-size: 0.9rem;
font-weight: 700; font-weight: 700;
color: var(--text); color: var(--text);
white-space: nowrap; white-space: nowrap;
@@ -1948,7 +2047,7 @@ button.map-qso-card:focus-visible {
border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent); border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent);
background: color-mix(in srgb, var(--card-bg) 82%, transparent); background: color-mix(in srgb, var(--card-bg) 82%, transparent);
color: var(--text); color: var(--text);
font-size: 0.76rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.02em; letter-spacing: 0.02em;
cursor: pointer; cursor: pointer;
@@ -1967,7 +2066,7 @@ button.map-qso-card:focus-visible {
border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent); border: 1px solid color-mix(in srgb, var(--border-light) 74%, transparent);
background: color-mix(in srgb, var(--card-bg) 82%, transparent); background: color-mix(in srgb, var(--card-bg) 82%, transparent);
color: var(--text); color: var(--text);
font-size: 0.76rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.02em; letter-spacing: 0.02em;
cursor: pointer; cursor: pointer;
@@ -2000,7 +2099,7 @@ button.map-qso-card:focus-visible {
display: none; display: none;
} }
.map-band-legend-title { .map-band-legend-title {
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 800; font-weight: 800;
letter-spacing: 0.1em; letter-spacing: 0.1em;
text-transform: uppercase; text-transform: uppercase;
@@ -2027,7 +2126,7 @@ button.map-qso-card:focus-visible {
} }
.map-band-legend-text { .map-band-legend-text {
min-width: 0; min-width: 0;
font-size: 0.76rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
color: var(--text); color: var(--text);
white-space: nowrap; white-space: nowrap;
@@ -2084,7 +2183,7 @@ body.map-fake-fullscreen-active {
} }
.aprs-summary-label { .aprs-summary-label {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-transform: uppercase; text-transform: uppercase;
@@ -2142,7 +2241,7 @@ body.map-fake-fullscreen-active {
} }
.ais-summary-label { .ais-summary-label {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.06em; letter-spacing: 0.06em;
text-transform: uppercase; text-transform: uppercase;
@@ -2260,7 +2359,7 @@ body.map-fake-fullscreen-active {
} }
.aprs-meta-text { .aprs-meta-text {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.76rem; font-size: 0.75rem;
} }
.aprs-inline-btn { .aprs-inline-btn {
display: inline-flex; display: inline-flex;
@@ -2273,7 +2372,7 @@ body.map-fake-fullscreen-active {
background: var(--filter-bg); background: var(--filter-bg);
color: var(--filter-fg); color: var(--filter-fg);
font: inherit; font: inherit;
font-size: 0.74rem; font-size: 0.75rem;
cursor: pointer; cursor: pointer;
} }
.aprs-inline-btn:hover { .aprs-inline-btn:hover {
@@ -2286,7 +2385,7 @@ body.map-fake-fullscreen-active {
.aprs-details summary { .aprs-details summary {
cursor: pointer; cursor: pointer;
color: var(--accent-green); color: var(--accent-green);
font-size: 0.76rem; font-size: 0.75rem;
user-select: none; user-select: none;
} }
.aprs-details[open] summary { .aprs-details[open] summary {
@@ -2364,7 +2463,7 @@ body.map-fake-fullscreen-active {
} }
.ais-meta-text { .ais-meta-text {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.76rem; font-size: 0.75rem;
} }
.ais-pos-link { .ais-pos-link {
color: var(--accent-red); color: var(--accent-red);
@@ -2406,7 +2505,7 @@ body.map-fake-fullscreen-active {
} }
.vdes-raw { .vdes-raw {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.76rem; font-size: 0.75rem;
word-break: break-all; word-break: break-all;
} }
.aprs-symbol { display: inline-block; width: 24px; height: 24px; background-size: 384px 192px; vertical-align: middle; margin-right: 0.3rem; } .aprs-symbol { display: inline-block; width: 24px; height: 24px; background-size: 384px 192px; vertical-align: middle; margin-right: 0.3rem; }
@@ -2465,18 +2564,18 @@ body.map-fake-fullscreen-active {
} }
.decode-locator-tip-meta { .decode-locator-tip-meta {
margin-top: 0.12rem; margin-top: 0.12rem;
font-size: 0.74rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--text-muted);
} }
.decode-locator-tip-rx { .decode-locator-tip-rx {
margin-top: 0.12rem; margin-top: 0.12rem;
font-size: 0.72rem; font-size: 0.75rem;
color: var(--accent-yellow); color: var(--accent-yellow);
opacity: 0.85; opacity: 0.85;
} }
.decode-locator-tip-note { .decode-locator-tip-note {
margin-top: 0.2rem; margin-top: 0.2rem;
font-size: 0.76rem; font-size: 0.75rem;
line-height: 1.3; line-height: 1.3;
color: var(--text); color: var(--text);
word-break: break-word; word-break: break-word;
@@ -2503,7 +2602,7 @@ body.map-fake-fullscreen-active {
background: color-mix(in srgb, var(--card-bg) 88%, transparent); background: color-mix(in srgb, var(--card-bg) 88%, transparent);
color: color-mix(in srgb, var(--accent-green) 72%, var(--accent-yellow)); color: color-mix(in srgb, var(--accent-green) 72%, var(--accent-yellow));
box-shadow: 0 8px 18px rgba(0, 0, 0, 0.22); box-shadow: 0 8px 18px rgba(0, 0, 0, 0.22);
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.03em; letter-spacing: 0.03em;
white-space: nowrap; white-space: nowrap;
@@ -2576,7 +2675,7 @@ body.map-fake-fullscreen-active {
flex: 0 0 auto; flex: 0 0 auto;
min-width: 4.4rem; min-width: 4.4rem;
padding-top: 0.35rem; padding-top: 0.35rem;
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.03em; letter-spacing: 0.03em;
text-transform: uppercase; text-transform: uppercase;
@@ -2604,7 +2703,7 @@ body.map-fake-fullscreen-active {
border: 1px solid color-mix(in srgb, var(--border-light) 82%, transparent); border: 1px solid color-mix(in srgb, var(--border-light) 82%, transparent);
background: color-mix(in srgb, var(--input-bg) 92%, transparent); background: color-mix(in srgb, var(--input-bg) 92%, transparent);
color: var(--text-muted); color: var(--text-muted);
font-size: 0.76rem; font-size: 0.75rem;
font-weight: 700; font-weight: 700;
letter-spacing: 0.02em; letter-spacing: 0.02em;
text-transform: uppercase; text-transform: uppercase;
@@ -2621,7 +2720,7 @@ body.map-fake-fullscreen-active {
color: var(--accent-green); color: var(--accent-green);
} }
.map-locator-empty { .map-locator-empty {
font-size: 0.74rem; font-size: 0.75rem;
color: var(--text-muted); color: var(--text-muted);
opacity: 0.8; opacity: 0.8;
align-self: flex-start; align-self: flex-start;
@@ -2655,7 +2754,7 @@ body.map-fake-fullscreen-active {
background: color-mix(in srgb, var(--input-bg) 96%, transparent); background: color-mix(in srgb, var(--input-bg) 96%, transparent);
} }
.map-locator-chip-text { .map-locator-chip-text {
font-size: 0.77rem; font-size: 0.78rem;
font-weight: 600; font-weight: 600;
} }
.map-search-input { .map-search-input {
@@ -2712,7 +2811,7 @@ body.map-fake-fullscreen-active {
.rds-raw-header { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.3rem; } .rds-raw-header { display: flex; align-items: center; justify-content: space-between; gap: 0.6rem; margin-bottom: 0.3rem; }
.rds-raw-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 0.3rem; } .rds-raw-label { font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--text-muted); margin-bottom: 0.3rem; }
.rds-raw-header .rds-raw-label { margin-bottom: 0; } .rds-raw-header .rds-raw-label { margin-bottom: 0; }
#rds-raw-copy-btn { height: 1.65rem; padding: 0 0.55rem; font-size: 0.72rem; } #rds-raw-copy-btn { height: 1.65rem; padding: 0 0.55rem; font-size: 0.75rem; }
.rds-raw { background: var(--input-bg); border: 1px solid var(--border-light); border-radius: 6px; padding: 0.5rem 0.6rem; font-size: 0.8rem; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; color: var(--text); white-space: pre; overflow-x: auto; margin: 0; } .rds-raw { background: var(--input-bg); border: 1px solid var(--border-light); border-radius: 6px; padding: 0.5rem 0.6rem; font-size: 0.8rem; font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; color: var(--text); white-space: pre; overflow-x: auto; margin: 0; }
.cw-controls { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.75rem; } .cw-controls { display: flex; gap: 0.6rem; align-items: center; margin-bottom: 0.75rem; }
@@ -2733,7 +2832,9 @@ body.map-fake-fullscreen-active {
.cw-config input[type="number"][readonly] { opacity: 0.6; } .cw-config input[type="number"][readonly] { opacity: 0.6; }
.cw-config input[type="number"]:disabled { opacity: 0.58; } .cw-config input[type="number"]:disabled { opacity: 0.58; }
button:focus-visible, input:focus-visible, select:focus-visible { button:focus-visible, input:focus-visible, select:focus-visible,
textarea:focus-visible, a:focus-visible,
canvas:focus-visible, [tabindex]:focus-visible {
outline: 2px solid var(--accent-green); outline: 2px solid var(--accent-green);
outline-offset: 2px; outline-offset: 2px;
} }
@@ -2844,7 +2945,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
} }
/* Collapse verbose subtitles — the About tab has this info */ /* Collapse verbose subtitles — the About tab has this info */
.tab-bar .subtitle { display: none; } .tab-bar .subtitle { display: none; }
.tab-bar .title { font-size: 0.92rem; } .tab-bar .title { font-size: 0.9rem; }
.tab-bar-nav { .tab-bar-nav {
position: fixed; position: fixed;
left: calc(0.6rem + env(safe-area-inset-left)); left: calc(0.6rem + env(safe-area-inset-left));
@@ -3506,7 +3607,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
will-change: transform; will-change: transform;
cursor: pointer; cursor: pointer;
font-weight: 600; font-weight: 600;
font-size: 0.66rem; font-size: 0.65rem;
background: var(--bm-cat-bg, var(--accent-yellow)); background: var(--bm-cat-bg, var(--accent-yellow));
color: var(--bm-cat-fg, #1a202c); color: var(--bm-cat-fg, #1a202c);
border: 1px solid var(--bm-cat-bg, var(--accent-yellow)); border: 1px solid var(--bm-cat-bg, var(--accent-yellow));
@@ -3598,7 +3699,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
} }
.spectrum-bookmark-chip-side .spectrum-bookmark-name { .spectrum-bookmark-chip-side .spectrum-bookmark-name {
width: 100%; width: 100%;
font-size: 0.64rem; font-size: 0.65rem;
font-weight: 600; font-weight: 600;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
@@ -3662,7 +3763,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
height: 1.5rem; height: 1.5rem;
min-height: 0; min-height: 0;
padding: 0 8px; padding: 0 8px;
font-size: 0.73rem; font-size: 0.75rem;
} }
#spectrum-level-row { #spectrum-level-row {
display: flex; display: flex;
@@ -3709,7 +3810,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
height: 1.5rem; height: 1.5rem;
min-height: 0; min-height: 0;
padding: 0 8px; padding: 0 8px;
font-size: 0.73rem; font-size: 0.75rem;
} }
#spectrum-gamma-label { #spectrum-gamma-label {
display: flex; display: flex;
@@ -3724,7 +3825,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
cursor: pointer; cursor: pointer;
} }
#spectrum-gamma-value { #spectrum-gamma-value {
font-size: 0.72rem; font-size: 0.75rem;
min-width: 1.6rem; min-width: 1.6rem;
text-align: right; text-align: right;
} }
@@ -3882,7 +3983,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
.bm-label input, .bm-label input,
.bm-label select { .bm-label select {
font-size: 0.88rem; font-size: 0.85rem;
padding: 0.35rem 0.5rem; padding: 0.35rem 0.5rem;
} }
@@ -3938,7 +4039,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
align-items: center; align-items: center;
gap: 0.35rem; gap: 0.35rem;
color: var(--text); color: var(--text);
font-size: 0.84rem; font-size: 0.85rem;
} }
.bm-decoder-check input { .bm-decoder-check input {
@@ -4048,7 +4149,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
.bm-page-summary, .bm-page-summary,
.bm-page-indicator { .bm-page-indicator {
color: var(--text-muted); color: var(--text-muted);
font-size: 0.88rem; font-size: 0.85rem;
} }
.bm-page-controls { .bm-page-controls {
display: flex; display: flex;
@@ -4266,7 +4367,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
color: var(--text); color: var(--text);
border-radius: var(--radius); border-radius: var(--radius);
padding: 0.55rem 1rem; padding: 0.55rem 1rem;
font-size: 0.88rem; font-size: 0.85rem;
} }
#sch-sat-form-cancel:hover { #sch-sat-form-cancel:hover {
background: var(--border); background: var(--border);
@@ -4478,7 +4579,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
.sch-log-action { .sch-log-action {
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
font-size: 0.72rem; font-size: 0.75rem;
} }
.sch-log-bm { .sch-log-bm {
color: var(--accent); color: var(--accent);
@@ -4687,7 +4788,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
} }
.bgd-checklist-meta { .bgd-checklist-meta {
margin-left: 0; margin-left: 0;
font-size: 0.72rem; font-size: 0.75rem;
} }
} }
/* ── SAT panel ──────────────────────────────────────────────────────── */ /* ── SAT panel ──────────────────────────────────────────────────────── */
@@ -4756,7 +4857,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
gap: 0.25rem; gap: 0.25rem;
} }
.stats-control-label { .stats-control-label {
font-size: 0.72rem; font-size: 0.75rem;
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
@@ -4796,7 +4897,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
line-height: 1.1; line-height: 1.1;
} }
.stats-counter-label { .stats-counter-label {
font-size: 0.74rem; font-size: 0.75rem;
font-weight: 600; font-weight: 600;
text-transform: uppercase; text-transform: uppercase;
letter-spacing: 0.06em; letter-spacing: 0.06em;
@@ -4819,7 +4920,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
gap: 0.18rem; gap: 0.18rem;
} }
.stats-section-title { .stats-section-title {
font-size: 0.88rem; font-size: 0.85rem;
font-weight: 800; font-weight: 800;
letter-spacing: 0.08em; letter-spacing: 0.08em;
text-transform: uppercase; text-transform: uppercase;
@@ -4884,7 +4985,7 @@ button:focus-visible, input:focus-visible, select:focus-visible {
#tab-statistics { padding: 0.75rem; } #tab-statistics { padding: 0.75rem; }
.stats-counters { grid-template-columns: repeat(2, 1fr); } .stats-counters { grid-template-columns: repeat(2, 1fr); }
.stats-counter-value { font-size: 1.3rem; } .stats-counter-value { font-size: 1.3rem; }
.stats-bar-label { min-width: 4rem; font-size: 0.72rem; } .stats-bar-label { min-width: 4rem; font-size: 0.75rem; }
.stats-section { padding: 0.8rem 0.85rem 0.9rem; } .stats-section { padding: 0.8rem 0.85rem 0.9rem; }
} }
@@ -4945,3 +5046,18 @@ button:focus-visible, input:focus-visible, select:focus-visible {
-webkit-backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
} }
} }
/* ── Panel-switch fade ────────────────────────────────────────────────
Panels are shown by clearing inline display (app.js), so this fires on
every tab/sub-tab change. Opacity-only to avoid transforming canvases
and the Leaflet map. Gated so reduced-motion users get instant switches. */
@media (prefers-reduced-motion: no-preference) {
.tab-panel,
.sub-tab-panel {
animation: trx-fade-in var(--dur-base) var(--ease-out);
}
}
@keyframes trx-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}