3226 lines
83 KiB
CSS
3226 lines
83 KiB
CSS
/* ============================================================
|
||
Trump Alpha — Design System
|
||
============================================================ */
|
||
|
||
:root {
|
||
/* Surfaces — warm off-whites */
|
||
--bg: oklch(99% 0.004 85);
|
||
--bg-sunk: oklch(97.8% 0.006 85);
|
||
--bg-elev: #ffffff;
|
||
--surface: #ffffff;
|
||
--surface-2: oklch(97.2% 0.006 85);
|
||
--surface-3: oklch(94% 0.008 85);
|
||
|
||
/* Text */
|
||
--ink: oklch(18% 0.008 85);
|
||
--ink-2: oklch(38% 0.008 85);
|
||
--ink-3: oklch(55% 0.008 85);
|
||
--ink-4: oklch(70% 0.006 85);
|
||
|
||
/* Borders */
|
||
--line: oklch(93% 0.008 85);
|
||
--line-2: oklch(88% 0.01 85);
|
||
|
||
/* Amber accent */
|
||
--amber: oklch(78% 0.17 75);
|
||
--amber-ink: oklch(45% 0.16 70);
|
||
--amber-soft: oklch(96% 0.05 85);
|
||
--amber-ring: oklch(88% 0.12 80);
|
||
|
||
/* Signal colors */
|
||
--up: oklch(62% 0.17 148);
|
||
--up-soft: oklch(95% 0.05 148);
|
||
--down: oklch(58% 0.22 25);
|
||
--down-soft: oklch(95% 0.05 25);
|
||
--violet: oklch(55% 0.17 280);
|
||
--violet-soft: oklch(96% 0.04 280);
|
||
|
||
/* Radii */
|
||
--r-xs: 8px;
|
||
--r-sm: 10px;
|
||
--r-md: 14px;
|
||
--r-lg: 20px;
|
||
--r-xl: 28px;
|
||
--r-pill: 999px;
|
||
|
||
/* Shadow */
|
||
--shadow-1: 0 1px 3px rgba(20, 18, 14, 0.07), 0 1px 2px rgba(20, 18, 14, 0.04);
|
||
--shadow-2: 0 4px 20px rgba(20, 18, 14, 0.09), 0 1px 4px rgba(20, 18, 14, 0.05);
|
||
--shadow-3: 0 16px 48px rgba(20, 18, 14, 0.12), 0 2px 6px rgba(20, 18, 14, 0.06);
|
||
|
||
--sans: 'Geist', ui-sans-serif, system-ui, -apple-system, 'Helvetica Neue', sans-serif;
|
||
--mono: 'Geist Mono', ui-monospace, 'SF Mono', Menlo, monospace;
|
||
}
|
||
|
||
html[data-theme="dark"] {
|
||
--bg: oklch(15% 0.008 85);
|
||
--bg-sunk: oklch(12% 0.008 85);
|
||
--bg-elev: oklch(20% 0.008 85);
|
||
--surface: oklch(18% 0.008 85);
|
||
--surface-2: oklch(21% 0.008 85);
|
||
--surface-3: oklch(25% 0.01 85);
|
||
|
||
--ink: oklch(97% 0.005 85);
|
||
--ink-2: oklch(82% 0.006 85);
|
||
--ink-3: oklch(62% 0.006 85);
|
||
--ink-4: oklch(45% 0.006 85);
|
||
|
||
--line: oklch(24% 0.008 85);
|
||
--line-2: oklch(30% 0.01 85);
|
||
|
||
--amber: oklch(78% 0.17 75);
|
||
--amber-ink: oklch(82% 0.16 75);
|
||
--amber-soft: oklch(25% 0.05 75);
|
||
--amber-ring: oklch(38% 0.12 75);
|
||
|
||
--up: oklch(70% 0.18 148);
|
||
--up-soft: oklch(24% 0.06 148);
|
||
--down: oklch(68% 0.22 25);
|
||
--down-soft: oklch(24% 0.08 25);
|
||
--violet: oklch(70% 0.17 280);
|
||
--violet-soft: oklch(24% 0.06 280);
|
||
|
||
--shadow-1: 0 1px 3px rgba(0, 0, 0, 0.4);
|
||
--shadow-2: 0 4px 20px rgba(0, 0, 0, 0.45);
|
||
--shadow-3: 0 16px 48px rgba(0, 0, 0, 0.6);
|
||
|
||
color-scheme: dark;
|
||
}
|
||
|
||
html[data-theme="dark"] .src-ico.x { background: oklch(92% 0.005 85); color: oklch(15% 0.008 85); }
|
||
|
||
html[data-theme="dark"] .kpi.accent {
|
||
background: linear-gradient(135deg, oklch(28% 0.05 75), oklch(24% 0.07 70));
|
||
}
|
||
|
||
/* Dashboard Performance card uses the same "amber accent" treatment as
|
||
.kpi.accent — without a dark-mode override the cream background floats
|
||
on the dark grid as a glaring out-of-theme block. Mirror the kpi dark
|
||
gradient so the card stays visually grouped with everything else. */
|
||
html[data-theme="dark"] .overview-stat-card.accent {
|
||
background: var(--surface);
|
||
border-color: var(--line);
|
||
border-left: 3px solid var(--amber);
|
||
}
|
||
|
||
html[data-theme="dark"] .landing-nav {
|
||
background: oklch(15% 0.008 85 / 0.8);
|
||
}
|
||
|
||
html[data-theme="dark"] .src-ico.truth {
|
||
background: oklch(28% 0.10 25); color: oklch(82% 0.18 25); font-weight: 700;
|
||
}
|
||
|
||
html[data-theme="dark"] .post-row.selected {
|
||
background: oklch(22% 0.03 75);
|
||
}
|
||
|
||
html, body {
|
||
margin: 0;
|
||
padding: 0;
|
||
background: var(--bg);
|
||
color: var(--ink);
|
||
font-family: var(--sans);
|
||
-webkit-font-smoothing: antialiased;
|
||
-moz-osx-font-smoothing: grayscale;
|
||
font-feature-settings: 'ss01', 'cv11';
|
||
transition: background 200ms, color 200ms;
|
||
}
|
||
|
||
* { box-sizing: border-box; }
|
||
|
||
/* Global focus ring — amber for brand consistency, only on keyboard nav */
|
||
:focus-visible {
|
||
outline: 2px solid var(--amber);
|
||
outline-offset: 2px;
|
||
border-radius: 4px;
|
||
}
|
||
|
||
button { font-family: inherit; cursor: pointer; border: 0; background: transparent; color: inherit; }
|
||
input, textarea { font-family: inherit; }
|
||
a { color: inherit; text-decoration: none; }
|
||
|
||
.mono { font-family: var(--mono); font-feature-settings: 'tnum', 'zero'; }
|
||
.tnum { font-variant-numeric: tabular-nums; }
|
||
|
||
/* ============================================================
|
||
App scaffold
|
||
============================================================ */
|
||
|
||
.app {
|
||
min-height: 100vh;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
/* ---------- Top navbar ---------- */
|
||
.nav {
|
||
height: 60px;
|
||
padding: 0 28px;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 28px;
|
||
background: color-mix(in oklab, var(--bg) 88%, transparent);
|
||
backdrop-filter: blur(16px);
|
||
-webkit-backdrop-filter: blur(16px);
|
||
border-bottom: 1px solid var(--line);
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 40;
|
||
box-shadow: 0 1px 0 color-mix(in oklab, var(--line) 50%, transparent),
|
||
0 4px 16px rgba(0,0,0,0.04);
|
||
}
|
||
|
||
.wallet-anchor {
|
||
position: relative;
|
||
display: flex;
|
||
align-items: center;
|
||
}
|
||
|
||
.wallet-connect-error {
|
||
position: absolute;
|
||
right: 0;
|
||
top: calc(100% + 10px);
|
||
margin: 0;
|
||
width: min(320px, calc(100vw - 28px));
|
||
padding: 10px 12px;
|
||
border-radius: 10px;
|
||
border: 1px solid color-mix(in oklab, var(--down) 24%, var(--line));
|
||
background: color-mix(in oklab, var(--down-soft) 72%, var(--surface));
|
||
color: var(--down);
|
||
box-shadow: var(--shadow-2);
|
||
font-size: 12px;
|
||
line-height: 1.45;
|
||
z-index: 50;
|
||
transform-origin: top right;
|
||
animation: walletErrorIn 160ms ease-out;
|
||
}
|
||
|
||
.wallet-connect-error::before {
|
||
content: '';
|
||
position: absolute;
|
||
right: 26px;
|
||
top: -7px;
|
||
width: 12px;
|
||
height: 12px;
|
||
background: inherit;
|
||
border-left: 1px solid color-mix(in oklab, var(--down) 24%, var(--line));
|
||
border-top: 1px solid color-mix(in oklab, var(--down) 24%, var(--line));
|
||
transform: rotate(45deg);
|
||
}
|
||
|
||
@keyframes walletErrorIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-6px) scale(0.98);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0) scale(1);
|
||
}
|
||
}
|
||
|
||
.brand {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
font-weight: 700;
|
||
font-size: 15px;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.brand-mark {
|
||
width: 30px;
|
||
height: 30px;
|
||
border-radius: 9px;
|
||
background: linear-gradient(145deg, oklch(26% 0.015 75) 0%, oklch(13% 0.006 85) 100%);
|
||
color: oklch(96% 0.006 85);
|
||
display: grid;
|
||
place-items: center;
|
||
font-family: var(--mono);
|
||
font-size: 15px;
|
||
font-weight: 600;
|
||
position: relative;
|
||
box-shadow: 0 2px 8px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.08);
|
||
}
|
||
.brand-mark::after {
|
||
content: '';
|
||
position: absolute;
|
||
right: -3px;
|
||
bottom: -3px;
|
||
width: 10px;
|
||
height: 10px;
|
||
border-radius: 999px;
|
||
background: var(--amber);
|
||
border: 2px solid var(--bg);
|
||
box-shadow: 0 1px 4px color-mix(in oklab, var(--amber) 50%, transparent);
|
||
}
|
||
|
||
.nav-tabs {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 3px;
|
||
padding: 4px;
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-pill);
|
||
}
|
||
.nav-tab {
|
||
padding: 7px 15px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--ink-3);
|
||
transition: color 120ms, background 120ms;
|
||
}
|
||
.nav-tab:hover { color: var(--ink-2); }
|
||
.nav-tab.active {
|
||
background: color-mix(in oklab, var(--amber) 7%, var(--surface));
|
||
color: var(--ink);
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.7);
|
||
border: 1px solid color-mix(in oklab, var(--amber) 22%, transparent);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.nav-spacer { flex: 1; }
|
||
|
||
.nav-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
}
|
||
|
||
.icon-btn {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: var(--r-pill);
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
display: grid;
|
||
place-items: center;
|
||
color: var(--ink-2);
|
||
transition: background 120ms, color 120ms;
|
||
}
|
||
.icon-btn:hover { background: var(--surface-3); color: var(--ink); }
|
||
|
||
.connect-btn {
|
||
padding: 12px 22px;
|
||
border-radius: var(--r-pill);
|
||
background: linear-gradient(135deg, oklch(24% 0.012 80) 0%, oklch(14% 0.006 85) 100%);
|
||
color: oklch(97% 0.005 85);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.005em;
|
||
transition: opacity 120ms, transform 120ms, box-shadow 120ms;
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.07);
|
||
}
|
||
.connect-btn:hover { opacity: 0.88; box-shadow: var(--shadow-2); }
|
||
.connect-btn:active { transform: scale(0.98); }
|
||
.connect-btn.lg { padding: 13px 26px; font-size: 14px; }
|
||
html[data-theme="dark"] .connect-btn {
|
||
background: linear-gradient(135deg, var(--amber) 0%, oklch(73% 0.18 70) 100%);
|
||
color: oklch(18% 0.04 75);
|
||
box-shadow: 0 2px 10px color-mix(in oklab, var(--amber) 40%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.25);
|
||
}
|
||
html[data-theme="dark"] .connect-btn:hover { opacity: 0.9; }
|
||
|
||
.theme-toggle { width: 40px; height: 40px; }
|
||
html[data-theme="dark"] .icon-btn { background: var(--surface-2); border-color: var(--line); }
|
||
html[data-theme="dark"] .icon-btn:hover { background: var(--surface-3); }
|
||
html[data-theme="dark"] .card {
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.04);
|
||
}
|
||
html[data-theme="dark"] .overview-market-card,
|
||
html[data-theme="dark"] .overview-side-card,
|
||
html[data-theme="dark"] .overview-stats-bar {
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.03);
|
||
}
|
||
html[data-theme="dark"] .nav-tab.active {
|
||
background: color-mix(in oklab, var(--amber) 10%, var(--surface-2));
|
||
border-color: color-mix(in oklab, var(--amber) 28%, transparent);
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
html[data-theme="dark"] .asset-switch button.on { background: var(--surface-2); }
|
||
|
||
.wallet-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
padding: 6px 12px 6px 6px;
|
||
border-radius: var(--r-pill);
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
font-size: 13px;
|
||
}
|
||
.wallet-chip .ava {
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 999px;
|
||
background: linear-gradient(135deg, var(--amber), oklch(65% 0.2 35));
|
||
}
|
||
|
||
.wallet-menu {
|
||
display: none;
|
||
position: absolute;
|
||
right: 0;
|
||
top: calc(100% + 6px);
|
||
min-width: 180px;
|
||
padding: 6px;
|
||
z-index: 1000;
|
||
background: var(--bg-elev);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-sm);
|
||
box-shadow: var(--shadow-2);
|
||
}
|
||
.wallet-menu.open { display: block; }
|
||
.wallet-menu button {
|
||
width: 100%;
|
||
padding: 8px 10px;
|
||
font-size: 13px;
|
||
text-align: left;
|
||
border-radius: 6px;
|
||
color: var(--ink);
|
||
}
|
||
.wallet-menu button:hover { background: var(--bg-sunk); }
|
||
.wallet-menu button.danger { color: var(--down); }
|
||
|
||
/* ============================================================
|
||
Page shell
|
||
============================================================ */
|
||
|
||
.page {
|
||
max-width: 1360px;
|
||
margin: 0 auto;
|
||
padding: 28px 28px 64px;
|
||
width: 100%;
|
||
}
|
||
.page.wide { max-width: 1600px; }
|
||
|
||
.page-head {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
margin-bottom: 28px;
|
||
gap: 24px;
|
||
}
|
||
.page-title {
|
||
font-size: 32px;
|
||
letter-spacing: -0.035em;
|
||
font-weight: 800;
|
||
line-height: 1.05;
|
||
margin: 0;
|
||
color: var(--ink);
|
||
}
|
||
.page-sub {
|
||
color: var(--ink-3);
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
margin-top: 5px;
|
||
margin-bottom: 0;
|
||
}
|
||
|
||
/* PageHint — the prominent "what is this page" tagline directly under
|
||
.page-title. Stronger contrast + bigger than .page-sub so it actually
|
||
gets read (page-sub was so faint it functioned as decoration).
|
||
Use via <PageHint>One sentence about the page.</PageHint>. */
|
||
.page-hint {
|
||
color: var(--ink-3);
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
margin: 6px 0 0;
|
||
max-width: 64ch;
|
||
}
|
||
.page-hint-count {
|
||
color: var(--amber-ink);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
margin-left: 10px;
|
||
padding-left: 10px;
|
||
border-left: 1px solid var(--line);
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* SectionHint — always-visible explanation block. Pairs with a section/tab
|
||
to tell the user "what does this view actually do" in 1–3 sentences.
|
||
More detailed than PageHint, less detail-y than an InfoTip. Spans the
|
||
full content width on purpose — narrow boxes inside a wide page looked
|
||
like accidentally-floating callouts. */
|
||
.section-hint {
|
||
background: color-mix(in oklab, var(--amber) 4%, var(--bg-sunk));
|
||
border: 1px solid color-mix(in oklab, var(--amber) 18%, var(--line));
|
||
border-left: 3px solid color-mix(in oklab, var(--amber) 60%, transparent);
|
||
border-radius: 8px;
|
||
padding: 12px 16px;
|
||
margin-bottom: 14px;
|
||
color: var(--ink-2);
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
}
|
||
.section-hint strong {
|
||
color: var(--ink);
|
||
font-weight: 600;
|
||
}
|
||
|
||
/* InfoTip — small "?" pill that reveals a one-line tooltip on hover/focus.
|
||
No JS, pure CSS. Pattern mimics the (i) dots in Linear/Hyperliquid:
|
||
subtle until needed, never blocks the underlying content. */
|
||
.infotip {
|
||
position: relative;
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
vertical-align: middle;
|
||
margin-left: 6px;
|
||
cursor: help;
|
||
outline: none;
|
||
/* The icon should sit on the text baseline without nudging line-height. */
|
||
line-height: 1;
|
||
}
|
||
.infotip-icon {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 50%;
|
||
background: var(--bg-sunk);
|
||
color: var(--ink-3);
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
border: 1px solid var(--line);
|
||
transition: background 0.12s, color 0.12s, border-color 0.12s;
|
||
user-select: none;
|
||
}
|
||
.infotip:hover .infotip-icon,
|
||
.infotip:focus-visible .infotip-icon {
|
||
background: var(--ink);
|
||
color: var(--bg);
|
||
border-color: var(--ink);
|
||
}
|
||
.infotip-bubble {
|
||
position: absolute;
|
||
z-index: 50;
|
||
width: var(--tip-w, 240px);
|
||
padding: 8px 10px;
|
||
/* Always-dark bubble — common pattern (Linear/Stripe/GitHub) — but needs
|
||
a visible border in dark mode so it doesn't blend into the page bg. */
|
||
background: #0f0d0a;
|
||
color: #f5f2ea;
|
||
border: 1px solid transparent;
|
||
border-radius: 6px;
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
line-height: 1.5;
|
||
letter-spacing: 0;
|
||
text-transform: none;
|
||
text-align: left;
|
||
box-shadow: 0 6px 24px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.2);
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
transform: translateY(2px);
|
||
transition: opacity 0.12s, transform 0.12s;
|
||
white-space: normal;
|
||
}
|
||
/* Dark mode: page bg is ~oklch(15%), bubble is #0f0d0a — visually identical.
|
||
Lighten the bubble slightly and add a 1px ring so the shape stays defined. */
|
||
html[data-theme="dark"] .infotip-bubble {
|
||
background: oklch(28% 0.008 85);
|
||
border-color: oklch(38% 0.01 85);
|
||
box-shadow: 0 6px 24px rgba(0,0,0,0.6), 0 1px 2px rgba(0,0,0,0.4);
|
||
}
|
||
|
||
/* MacroPanel cell — subtle hover so the grid feels alive without becoming
|
||
a giant heat-map of click affordances. Just a tiny background lift. */
|
||
.macro-cell:hover {
|
||
background: var(--bg-sunk) !important;
|
||
}
|
||
|
||
.macro-panel {
|
||
padding: 0;
|
||
margin-bottom: 12px;
|
||
overflow: hidden;
|
||
}
|
||
|
||
.macro-panel-head {
|
||
padding: 20px 22px 18px;
|
||
border-bottom: 1px solid var(--line);
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
background: color-mix(in oklab, var(--amber) 3%, var(--surface));
|
||
}
|
||
|
||
.macro-panel-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.01em;
|
||
}
|
||
|
||
.macro-panel-dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 999px;
|
||
background: var(--up);
|
||
display: inline-block;
|
||
position: relative;
|
||
box-shadow: 0 0 5px color-mix(in oklab, var(--up) 60%, transparent);
|
||
animation: macro-dot-pulse 2.4s ease-out infinite;
|
||
}
|
||
@keyframes macro-dot-pulse {
|
||
0%, 60% { box-shadow: 0 0 5px color-mix(in oklab, var(--up) 60%, transparent); }
|
||
30% { box-shadow: 0 0 10px color-mix(in oklab, var(--up) 80%, transparent); }
|
||
100% { box-shadow: 0 0 5px color-mix(in oklab, var(--up) 60%, transparent); }
|
||
}
|
||
|
||
.macro-panel-subtitle {
|
||
margin-top: 6px;
|
||
font-size: 12px;
|
||
line-height: 1.45;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.macro-panel-meta {
|
||
text-align: right;
|
||
font-size: 11px;
|
||
line-height: 1.45;
|
||
color: var(--ink-4);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.macro-section {
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
|
||
.macro-section-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 14px 22px 12px;
|
||
/* Was 10px / ink-3 / weight 700 — too quiet, users couldn't see the
|
||
section structure. Bumped to 12px / ink-2 / weight 800. Still uppercase
|
||
+ tracked so it reads as a label, not a heading that competes with the
|
||
metric values. */
|
||
font-size: 12px;
|
||
color: var(--ink-2);
|
||
letter-spacing: 0.10em;
|
||
text-transform: uppercase;
|
||
font-weight: 800;
|
||
background: var(--bg-sunk);
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
/* Tiny dot anchor on the left — visual signal that "this is a section
|
||
header" without using a heavy colored bar. */
|
||
.macro-section-title::before {
|
||
content: '';
|
||
width: 5px;
|
||
height: 5px;
|
||
border-radius: 50%;
|
||
background: var(--amber);
|
||
flex-shrink: 0;
|
||
box-shadow: 0 0 5px color-mix(in oklab, var(--amber) 50%, transparent);
|
||
opacity: 0.8;
|
||
}
|
||
|
||
.macro-grid {
|
||
display: grid;
|
||
gap: 14px;
|
||
padding: 14px;
|
||
}
|
||
|
||
.macro-grid.one {
|
||
grid-template-columns: minmax(0, 1fr);
|
||
}
|
||
|
||
.macro-grid.two {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.macro-metric-card,
|
||
.macro-guide-card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: 12px;
|
||
padding: 18px;
|
||
min-width: 0;
|
||
min-height: 248px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
}
|
||
|
||
.macro-metric-card {
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.6);
|
||
}
|
||
|
||
.macro-metric-card.tone-up {
|
||
border-color: color-mix(in oklab, var(--up) 28%, var(--line));
|
||
}
|
||
|
||
.macro-metric-card.tone-down {
|
||
border-color: color-mix(in oklab, var(--down) 28%, var(--line));
|
||
}
|
||
|
||
/* Stat card layout — label STACKED ABOVE the big number, not side-by-side.
|
||
Previous side-by-side layout pushed the title to the far left and the
|
||
value to the far right with too much air between them on wide screens.
|
||
The eye now reads top→bottom: label → value → summary → chips → button. */
|
||
.macro-metric-head {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 6px;
|
||
}
|
||
|
||
.macro-metric-title {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
/* Slightly larger + bolder so "AHR999" doesn't disappear next to the
|
||
big number below. Treated as a label, not a heading. */
|
||
font-size: 15px;
|
||
font-weight: 650;
|
||
color: var(--ink-2);
|
||
}
|
||
|
||
.macro-rank {
|
||
font-size: 11px;
|
||
color: var(--ink-4);
|
||
letter-spacing: 0.08em;
|
||
font-weight: 700;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.macro-metric-value {
|
||
/* Same size as before but sits directly under the label now, so the
|
||
eye-distance between "AHR999" and "0.4663" is ~6px instead of the
|
||
full card width. */
|
||
font-size: 34px;
|
||
line-height: 1;
|
||
letter-spacing: -0.03em;
|
||
font-weight: 800;
|
||
color: var(--ink);
|
||
text-align: left;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.macro-guide-title {
|
||
font-size: 20px;
|
||
line-height: 1.15;
|
||
letter-spacing: -0.02em;
|
||
font-weight: 700;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.macro-summary {
|
||
margin-top: 12px;
|
||
font-size: 14px;
|
||
line-height: 1.55;
|
||
color: var(--ink-2);
|
||
min-height: 66px;
|
||
}
|
||
|
||
/* Hero variant — for a section with a SINGLE headline card (Valuation/AHR999).
|
||
The stacked card layout stretched full-width left a huge dead middle; the
|
||
hero lays out horizontally: value block left, summary + chips filling the
|
||
middle, chart button right. Wraps back to stacked on narrow screens. */
|
||
.macro-metric-card.hero {
|
||
flex-direction: row;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: clamp(16px, 3vw, 40px);
|
||
min-height: 0;
|
||
}
|
||
.macro-metric-card.hero .macro-hero-body {
|
||
flex: 1 1 300px;
|
||
min-width: 0;
|
||
}
|
||
.macro-metric-card.hero .macro-summary {
|
||
margin-top: 0;
|
||
min-height: 0;
|
||
}
|
||
.macro-metric-card.hero .macro-thresholds {
|
||
margin-top: 10px;
|
||
}
|
||
.macro-metric-card.hero .macro-actions {
|
||
margin-top: 0;
|
||
padding-top: 0;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.macro-thresholds {
|
||
display: flex;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-top: 14px;
|
||
}
|
||
|
||
/* THRESHOLD CHIPS — "you are here" treatment
|
||
─────────────────────────────────────────────────────────
|
||
Design goal: the chip that the CURRENT value falls into must be the
|
||
single most-eye-catching element in the cell. Everything else fades back.
|
||
|
||
Two states:
|
||
base (inactive) — flat, outlined, muted gray. Tone is suppressed
|
||
so a "down (red)" inactive chip doesn't visually
|
||
outshout an active "neutral" chip. Stripping
|
||
tone here is intentional.
|
||
.active — filled pill with the tone colour, larger, raised
|
||
on shadow, scale 1.05. The eye can't miss it.
|
||
|
||
Hover the row → all chips bump to 0.8 opacity so you can read the
|
||
other bands' rules without losing the active one. */
|
||
|
||
.macro-threshold-chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 28px;
|
||
padding: 5px 12px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--line);
|
||
background: transparent;
|
||
font-size: 11.5px;
|
||
line-height: 1.35;
|
||
color: var(--ink-4);
|
||
font-weight: 500;
|
||
opacity: 0.45;
|
||
transition: opacity 160ms, transform 180ms cubic-bezier(.2,.8,.2,1),
|
||
box-shadow 180ms, background 180ms, color 180ms;
|
||
}
|
||
.macro-thresholds:hover .macro-threshold-chip { opacity: 0.8; }
|
||
|
||
/* When INACTIVE, suppress tone colors. They'd compete with the active chip
|
||
for attention. Tone returns the moment the chip becomes .active below. */
|
||
.macro-threshold-chip:not(.active) {
|
||
color: var(--ink-4) !important;
|
||
background: transparent !important;
|
||
border-color: var(--line) !important;
|
||
}
|
||
|
||
/* ACTIVE — the band the current value falls into. */
|
||
.macro-threshold-chip.active {
|
||
opacity: 1;
|
||
font-weight: 700;
|
||
font-size: 12px;
|
||
padding: 6px 14px;
|
||
transform: scale(1.06);
|
||
letter-spacing: 0.01em;
|
||
}
|
||
.macro-threshold-chip.up.active {
|
||
background: linear-gradient(135deg, var(--up) 0%, oklch(66% 0.19 155) 100%);
|
||
color: #fff;
|
||
border-color: var(--up);
|
||
box-shadow:
|
||
0 6px 18px color-mix(in oklab, var(--up) 40%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.28);
|
||
}
|
||
.macro-threshold-chip.down.active {
|
||
background: linear-gradient(135deg, var(--down) 0%, oklch(55% 0.24 18) 100%);
|
||
color: #fff;
|
||
border-color: var(--down);
|
||
box-shadow:
|
||
0 6px 18px color-mix(in oklab, var(--down) 40%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.22);
|
||
}
|
||
.macro-threshold-chip.neutral.active {
|
||
background: linear-gradient(135deg, var(--amber) 0%, oklch(70% 0.19 65) 100%);
|
||
color: oklch(20% 0.04 75);
|
||
border-color: var(--amber);
|
||
box-shadow:
|
||
0 6px 18px color-mix(in oklab, var(--amber) 40%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.45);
|
||
}
|
||
|
||
/* Dark mode tweaks — the soft white-shimmer inset doesn't read on dark cards,
|
||
so swap to a subtle darker outline. */
|
||
html[data-theme="dark"] .macro-threshold-chip.up.active,
|
||
html[data-theme="dark"] .macro-threshold-chip.down.active,
|
||
html[data-theme="dark"] .macro-threshold-chip.neutral.active {
|
||
box-shadow:
|
||
0 8px 24px color-mix(in oklab, currentColor 30%, transparent),
|
||
0 0 0 1px rgba(0,0,0,0.25) inset;
|
||
}
|
||
|
||
/* Section variants — reference cards (rules-only, no live number) get a
|
||
muted treatment so users instantly see they're explanatory, not live.
|
||
We REPLACE the dot anchor with a 📐 emoji (overriding the .macro-section-
|
||
title::before above) and dim the text color. */
|
||
.macro-section.reference .macro-section-title {
|
||
color: var(--ink-3);
|
||
}
|
||
.macro-section.reference .macro-section-title::before {
|
||
content: '📐';
|
||
width: auto;
|
||
height: auto;
|
||
background: none;
|
||
border-radius: 0;
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
filter: grayscale(0.3);
|
||
}
|
||
.macro-guide-card {
|
||
background: color-mix(in oklab, var(--bg-sunk) 60%, var(--surface));
|
||
border-style: dashed;
|
||
}
|
||
.macro-guide-card .macro-guide-title::before {
|
||
content: 'RULES ';
|
||
font-size: 9px;
|
||
font-weight: 800;
|
||
letter-spacing: 0.12em;
|
||
padding: 2px 6px;
|
||
border-radius: 4px;
|
||
background: color-mix(in oklab, var(--ink) 8%, transparent);
|
||
color: var(--ink-3);
|
||
margin-right: 8px;
|
||
vertical-align: middle;
|
||
}
|
||
|
||
/* Action row — single small button, aligned to the bottom-right of the card.
|
||
Was previously a full-width dual-button group; pinning a compact button to
|
||
the corner keeps the card's eye-flow on the value + thresholds, with the
|
||
"go look at history" affordance present but quiet. */
|
||
.macro-actions {
|
||
display: flex;
|
||
justify-content: flex-end;
|
||
margin-top: auto;
|
||
padding-top: 14px;
|
||
}
|
||
|
||
.macro-action-btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
/* Compact natural width — fits "Open chart CoinGlass ↗" comfortably */
|
||
padding: 7px 13px;
|
||
border-radius: 9px;
|
||
border: 1px solid var(--line);
|
||
background: color-mix(in oklab, var(--ink) 4%, var(--surface));
|
||
color: var(--ink);
|
||
text-decoration: none;
|
||
transition: background 120ms, border-color 120ms, transform 120ms, box-shadow 120ms;
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.5), var(--shadow-1);
|
||
}
|
||
|
||
.macro-action-btn:hover {
|
||
background: color-mix(in oklab, var(--ink) 8%, var(--surface));
|
||
border-color: color-mix(in oklab, var(--ink) 14%, var(--line));
|
||
transform: translateY(-1px);
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.5), var(--shadow-2);
|
||
}
|
||
|
||
.macro-action-btn.chart {
|
||
background: color-mix(in oklab, var(--amber) 12%, var(--surface));
|
||
border-color: color-mix(in oklab, var(--amber) 22%, var(--line));
|
||
}
|
||
|
||
/* The kicker ("OPEN CHART" uppercase eyebrow) used to sit ABOVE the label
|
||
in a 2-row layout. With the new compact button it lives inline next to
|
||
the label as a tiny prefix tag — same words, less vertical space. */
|
||
.macro-action-copy {
|
||
display: inline-flex;
|
||
align-items: baseline;
|
||
gap: 8px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.macro-action-kicker {
|
||
font-size: 9.5px;
|
||
line-height: 1;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
font-weight: 700;
|
||
}
|
||
|
||
.macro-action-label {
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
color: var(--ink);
|
||
font-weight: 600;
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.macro-action-arrow {
|
||
font-size: 13px;
|
||
line-height: 1;
|
||
color: var(--ink-3);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.macro-disclosure {
|
||
margin-top: 14px;
|
||
border-top: 1px dashed var(--line);
|
||
padding-top: 12px;
|
||
}
|
||
|
||
.macro-disclosure summary {
|
||
list-style: none;
|
||
cursor: pointer;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--ink-2);
|
||
}
|
||
|
||
.macro-disclosure summary::-webkit-details-marker {
|
||
display: none;
|
||
}
|
||
|
||
.macro-disclosure-body {
|
||
margin-top: 8px;
|
||
font-size: 12px;
|
||
line-height: 1.55;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.macro-composite {
|
||
/* Aligned to the indicator-card grid above (.macro-grid uses 14px gutters
|
||
and metric cards have 12px radius / 1px border / surface bg). The
|
||
composite reads as a "summary card" sitting at the same indent as the
|
||
metric cards rather than a full-bleed banner. */
|
||
margin: 14px;
|
||
padding: 20px 22px 22px;
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.5);
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: 12px;
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
|
||
.macro-composite-head {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.macro-composite-label {
|
||
font-size: 11px;
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
color: var(--amber-ink);
|
||
font-weight: 700;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.macro-composite-right {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
justify-content: flex-end;
|
||
}
|
||
|
||
.macro-composite-value {
|
||
font-size: 32px;
|
||
line-height: 0.95;
|
||
font-weight: 800;
|
||
letter-spacing: -0.03em;
|
||
}
|
||
|
||
.macro-regime-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
min-height: 28px;
|
||
padding: 0 12px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--line);
|
||
font-size: 11px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.07em;
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.35);
|
||
}
|
||
|
||
.macro-composite-track {
|
||
position: relative;
|
||
height: 18px;
|
||
/* No `overflow: hidden` — the 24px needle is taller than the track and
|
||
gets clipped top/bottom otherwise. The gradient is naturally rounded
|
||
by border-radius, so clipping isn't needed. */
|
||
border-radius: 999px;
|
||
border: 1px solid color-mix(in oklab, var(--line) 78%, transparent);
|
||
box-shadow: inset 0 1px 2px rgba(0,0,0,0.08);
|
||
margin: 6px 0;
|
||
}
|
||
|
||
.macro-composite-track::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 2px;
|
||
bottom: 2px;
|
||
left: 50%;
|
||
width: 1px;
|
||
background: color-mix(in oklab, var(--ink) 14%, transparent);
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
.macro-composite-needle {
|
||
position: absolute;
|
||
top: 50%;
|
||
width: 24px;
|
||
height: 24px;
|
||
border-radius: 50%;
|
||
border: 3px solid var(--ink);
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-2);
|
||
transform: translateY(-50%);
|
||
transition: left 0.4s cubic-bezier(.2,.8,.2,1);
|
||
/* React re-mounts this element via `key={composite_score}` whenever the
|
||
score changes, which re-triggers the pulse animation below — a brief
|
||
attention cue for users tracking how the macro tilt shifts day to day. */
|
||
animation: macro-needle-pulse 0.9s ease-out 1;
|
||
}
|
||
@keyframes macro-needle-pulse {
|
||
0% { transform: translateY(-50%) scale(0.85); box-shadow: 0 0 0 0 currentColor; }
|
||
40% { transform: translateY(-50%) scale(1.18); box-shadow: 0 0 0 8px color-mix(in oklab, currentColor 18%, transparent); }
|
||
100% { transform: translateY(-50%) scale(1); box-shadow: var(--shadow-2); }
|
||
}
|
||
|
||
.macro-composite-scale {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 8px;
|
||
margin-top: 8px;
|
||
font-size: 10px;
|
||
letter-spacing: 0.04em;
|
||
color: var(--ink-4);
|
||
text-transform: uppercase;
|
||
}
|
||
.infotip:hover .infotip-bubble,
|
||
.infotip:focus-visible .infotip-bubble {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
/* Placement variants (default = top).
|
||
--tip-shift is set by InfoTip.tsx on reveal: it nudges a bubble that would
|
||
hang past the viewport edge back on-screen (icons near the screen margin). */
|
||
.infotip-top .infotip-bubble {
|
||
bottom: calc(100% + 8px);
|
||
left: 50%; transform: translate(calc(-50% + var(--tip-shift, 0px)), 2px);
|
||
}
|
||
.infotip-top:hover .infotip-bubble,
|
||
.infotip-top:focus-visible .infotip-bubble {
|
||
transform: translate(calc(-50% + var(--tip-shift, 0px)), 0);
|
||
}
|
||
.infotip-bottom .infotip-bubble {
|
||
top: calc(100% + 8px);
|
||
left: 50%; transform: translate(calc(-50% + var(--tip-shift, 0px)), -2px);
|
||
}
|
||
.infotip-bottom:hover .infotip-bubble,
|
||
.infotip-bottom:focus-visible .infotip-bubble {
|
||
transform: translate(calc(-50% + var(--tip-shift, 0px)), 0);
|
||
}
|
||
.infotip-left .infotip-bubble {
|
||
right: calc(100% + 8px);
|
||
top: 50%; transform: translate(2px, -50%);
|
||
}
|
||
.infotip-left:hover .infotip-bubble,
|
||
.infotip-left:focus-visible .infotip-bubble {
|
||
transform: translate(0, -50%);
|
||
}
|
||
.infotip-right .infotip-bubble {
|
||
left: calc(100% + 8px);
|
||
top: 50%; transform: translate(-2px, -50%);
|
||
}
|
||
.infotip-right:hover .infotip-bubble,
|
||
.infotip-right:focus-visible .infotip-bubble {
|
||
transform: translate(0, -50%);
|
||
}
|
||
|
||
/* ============================================================
|
||
Cards + primitives
|
||
============================================================ */
|
||
|
||
.card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-md);
|
||
padding: 20px;
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.55);
|
||
}
|
||
.card.flush { padding: 0; }
|
||
.card.soft { background: var(--bg-sunk); }
|
||
.card.raise { box-shadow: var(--shadow-1); }
|
||
|
||
.section-title {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
margin-bottom: 14px;
|
||
}
|
||
.section-title h2 {
|
||
margin: 0;
|
||
font-size: 17px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
.section-title .hint {
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.chip {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 4px 10px;
|
||
border-radius: var(--r-pill);
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
font-size: 12px;
|
||
color: var(--ink-2);
|
||
font-weight: 500;
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.45);
|
||
}
|
||
.chip .dot { width: 6px; height: 6px; border-radius: 999px; background: currentColor; }
|
||
/* Text darkened to clear WCAG AA 4.5:1 on the soft tint (was 3.4:1). */
|
||
.chip.up { color: oklch(33% 0.17 150); background: var(--up-soft); border-color: oklch(84% 0.10 148); font-weight: 600; }
|
||
.chip.down { color: oklch(36% 0.20 27); background: var(--down-soft); border-color: oklch(86% 0.10 25); font-weight: 600; }
|
||
/* Dark mode: soft tint is dark, so the text must go light to keep contrast. */
|
||
html[data-theme="dark"] .chip.up { color: oklch(83% 0.15 150); }
|
||
html[data-theme="dark"] .chip.down { color: oklch(80% 0.16 27); }
|
||
.chip.amber { color: var(--amber-ink); background: var(--amber-soft); border-color: var(--amber-ring); font-weight: 600; }
|
||
.chip.violet { color: oklch(36% 0.17 280); background: var(--violet-soft); border-color: oklch(84% 0.10 280); font-weight: 600; }
|
||
.chip.neutral { color: var(--ink-2); }
|
||
|
||
.live-dot {
|
||
width: 7px;
|
||
height: 7px;
|
||
border-radius: 999px;
|
||
background: var(--up);
|
||
position: relative;
|
||
display: inline-block;
|
||
box-shadow: 0 0 6px color-mix(in oklab, var(--up) 60%, transparent);
|
||
}
|
||
.live-dot::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: -4px;
|
||
border-radius: 999px;
|
||
background: var(--up);
|
||
opacity: 0.35;
|
||
animation: pulse 1.8s ease-out infinite;
|
||
}
|
||
@keyframes pulse {
|
||
0% { transform: scale(0.5); opacity: 0.6; }
|
||
100% { transform: scale(2.6); opacity: 0; }
|
||
}
|
||
|
||
.btn {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
gap: 8px;
|
||
padding: 10px 16px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
transition: background 120ms, transform 120ms;
|
||
border: 1px solid transparent;
|
||
}
|
||
.btn.primary {
|
||
background: linear-gradient(135deg, oklch(24% 0.012 80) 0%, oklch(14% 0.006 85) 100%);
|
||
color: oklch(97% 0.005 85);
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.07);
|
||
}
|
||
.btn.primary:hover { opacity: 0.88; }
|
||
.btn.amber {
|
||
background: linear-gradient(135deg, var(--amber) 0%, oklch(73% 0.18 70) 100%);
|
||
color: oklch(20% 0.04 75);
|
||
font-weight: 700;
|
||
box-shadow: 0 2px 8px color-mix(in oklab, var(--amber) 40%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.35);
|
||
}
|
||
.btn.amber:hover {
|
||
background: linear-gradient(135deg, oklch(82% 0.17 75) 0%, oklch(76% 0.19 68) 100%);
|
||
box-shadow: 0 4px 14px color-mix(in oklab, var(--amber) 45%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.35);
|
||
}
|
||
.btn.ghost { background: var(--bg-sunk); color: var(--ink); border-color: var(--line); }
|
||
.btn.ghost:hover { background: var(--surface-3); }
|
||
.btn.lg { padding: 14px 22px; font-size: 15px; }
|
||
.btn:active { transform: scale(0.98); }
|
||
|
||
.delta { font-family: var(--mono); font-weight: 600; }
|
||
.delta.up { color: oklch(40% 0.18 148); }
|
||
.delta.down { color: oklch(44% 0.22 25); }
|
||
|
||
/* ── iOS-style toggle switch ──────────────────────────────── */
|
||
.switch {
|
||
position: relative;
|
||
display: inline-block;
|
||
width: 34px;
|
||
height: 20px;
|
||
flex-shrink: 0;
|
||
}
|
||
.switch input {
|
||
opacity: 0;
|
||
width: 0;
|
||
height: 0;
|
||
}
|
||
.switch-track {
|
||
position: absolute;
|
||
cursor: pointer;
|
||
top: 0; left: 0; right: 0; bottom: 0;
|
||
background: var(--line-2);
|
||
border-radius: 999px;
|
||
transition: background 160ms;
|
||
}
|
||
.switch-track::before {
|
||
content: '';
|
||
position: absolute;
|
||
height: 16px;
|
||
width: 16px;
|
||
left: 2px;
|
||
top: 2px;
|
||
background: #fff;
|
||
border-radius: 50%;
|
||
transition: transform 160ms;
|
||
box-shadow: 0 1px 2px rgba(0,0,0,0.15);
|
||
}
|
||
.switch input:checked + .switch-track {
|
||
background: linear-gradient(135deg, var(--amber) 0%, oklch(73% 0.18 70) 100%);
|
||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--amber) 18%, transparent);
|
||
}
|
||
.switch input:checked + .switch-track::before { transform: translateX(14px); }
|
||
.switch.up input:checked + .switch-track {
|
||
background: linear-gradient(135deg, var(--up) 0%, oklch(66% 0.19 155) 100%);
|
||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--up) 18%, transparent);
|
||
}
|
||
.switch.down input:checked + .switch-track { background: var(--down); }
|
||
|
||
/* ── Form row: label | control, strict-aligned ─────────────── */
|
||
.form-row {
|
||
display: grid;
|
||
grid-template-columns: minmax(220px, 260px) minmax(0, 1fr);
|
||
align-items: start;
|
||
gap: 24px;
|
||
padding: 16px 0;
|
||
}
|
||
.form-row + .form-row { border-top: 1px solid var(--line); }
|
||
.form-row-label {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
color: var(--ink);
|
||
line-height: 1.35;
|
||
}
|
||
.form-row-label .hint {
|
||
display: block;
|
||
font-size: 12px;
|
||
font-weight: 400;
|
||
color: var(--ink-3);
|
||
margin-top: 5px;
|
||
line-height: 1.5;
|
||
max-width: 28ch;
|
||
}
|
||
.form-row-control {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
min-width: 0;
|
||
}
|
||
|
||
/* ── Section divider with label ────────────────────────────── */
|
||
.section-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
margin: 10px 0 2px;
|
||
padding-top: 18px;
|
||
border-top: 1px solid var(--line);
|
||
}
|
||
.section-head:first-child { border-top: 0; padding-top: 0; }
|
||
.section-head-label {
|
||
font-size: 10.5px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--amber-ink);
|
||
opacity: 0.75;
|
||
}
|
||
|
||
/* ── Settings legacy classes (removed from HTML 2026-06) ──────────────── */
|
||
/* These are kept as empty stubs so any cached HTML from CDN doesn't break. */
|
||
.settings-scope-intro,
|
||
.settings-control-center {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1.4fr) minmax(320px, 1fr);
|
||
gap: 16px;
|
||
padding: 18px 20px;
|
||
margin-bottom: 16px;
|
||
border: 1px solid var(--line);
|
||
border-radius: 14px;
|
||
background: linear-gradient(135deg, color-mix(in oklab, var(--amber) 7%, var(--surface)) 0%, var(--surface) 48%, color-mix(in oklab, var(--up) 6%, var(--surface)) 100%);
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
|
||
.settings-control-kicker,
|
||
.settings-section-kicker {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.settings-control-title,
|
||
.settings-section-title {
|
||
font-size: 20px;
|
||
line-height: 1.2;
|
||
font-weight: 700;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.settings-control-copy {
|
||
margin-top: 8px;
|
||
font-size: 13px;
|
||
line-height: 1.6;
|
||
color: var(--ink-3);
|
||
max-width: 58ch;
|
||
}
|
||
|
||
.settings-control-meta {
|
||
display: grid;
|
||
grid-template-columns: 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
.settings-meta-card {
|
||
padding: 12px 14px;
|
||
border: 1px solid var(--line);
|
||
border-radius: 12px;
|
||
background: color-mix(in oklab, var(--surface) 92%, transparent);
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
|
||
.settings-meta-card strong {
|
||
display: block;
|
||
font-size: 13px;
|
||
line-height: 1.4;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.settings-meta-label {
|
||
display: block;
|
||
margin-bottom: 4px;
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
}
|
||
|
||
.settings-scope-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, minmax(0, 1fr));
|
||
gap: 12px;
|
||
}
|
||
|
||
.settings-scope-card {
|
||
padding: 16px;
|
||
border-radius: 12px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
|
||
.settings-scope-card.trump {
|
||
background: color-mix(in oklab, var(--amber) 8%, var(--surface));
|
||
}
|
||
|
||
.settings-scope-card.btc {
|
||
background: color-mix(in oklab, var(--up) 8%, var(--surface));
|
||
}
|
||
|
||
.settings-scope-card.global {
|
||
background: color-mix(in oklab, var(--ink) 3%, var(--surface));
|
||
}
|
||
|
||
.settings-scope-eyebrow {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
margin-bottom: 8px;
|
||
}
|
||
|
||
.settings-scope-title {
|
||
font-size: 15px;
|
||
font-weight: 700;
|
||
color: var(--ink);
|
||
margin-bottom: 6px;
|
||
}
|
||
|
||
.settings-scope-copy {
|
||
font-size: 12px;
|
||
line-height: 1.6;
|
||
color: var(--ink-3);
|
||
margin-bottom: 14px;
|
||
}
|
||
|
||
.settings-scope-link {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 7px 12px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
color: var(--ink);
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
|
||
.settings-section-shell {
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.settings-section-head {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
justify-content: space-between;
|
||
gap: 12px;
|
||
margin-bottom: 10px;
|
||
}
|
||
|
||
.settings-section-note {
|
||
font-size: 12px;
|
||
line-height: 1.5;
|
||
color: var(--ink-3);
|
||
text-align: right;
|
||
}
|
||
|
||
/* ── Inline $ prefix input ─────────────────────────────────── */
|
||
.num-field {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-sm);
|
||
padding: 0 10px;
|
||
transition: border-color 120ms, background 120ms;
|
||
}
|
||
.num-field:focus-within { border-color: var(--amber-ring); background: var(--bg); }
|
||
.num-field[data-disabled='true'] { opacity: 0.4; pointer-events: none; }
|
||
.num-field .prefix, .num-field .suffix {
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
font-family: var(--mono);
|
||
}
|
||
.num-field input {
|
||
border: 0;
|
||
background: transparent;
|
||
font-family: var(--mono);
|
||
font-size: 13px;
|
||
padding: 8px 6px;
|
||
width: 80px;
|
||
outline: none;
|
||
color: var(--ink);
|
||
}
|
||
.num-field input::-webkit-inner-spin-button,
|
||
.num-field input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
|
||
|
||
/* ── Slider: unified look ──────────────────────────────────── */
|
||
.slider-field { flex: 1; display: flex; flex-direction: column; gap: 4px; }
|
||
.slider-field input[type=range] {
|
||
-webkit-appearance: none;
|
||
width: 100%;
|
||
height: 4px;
|
||
background: var(--line-2);
|
||
border-radius: 999px;
|
||
outline: none;
|
||
}
|
||
.slider-field input[type=range]::-webkit-slider-thumb {
|
||
-webkit-appearance: none;
|
||
appearance: none;
|
||
width: 16px;
|
||
height: 16px;
|
||
background: var(--amber);
|
||
border: 2px solid var(--bg);
|
||
border-radius: 50%;
|
||
box-shadow: 0 1px 3px rgba(0,0,0,0.18);
|
||
cursor: pointer;
|
||
}
|
||
.slider-field .ticks {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
font-size: 10px;
|
||
color: var(--ink-4);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
.slider-readout {
|
||
font-family: var(--mono);
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
min-width: 56px;
|
||
text-align: right;
|
||
color: var(--ink);
|
||
font-variant-numeric: tabular-nums;
|
||
}
|
||
|
||
.settings-note {
|
||
width: 100%;
|
||
padding: 10px 12px;
|
||
border-radius: 8px;
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
font-size: 12px;
|
||
line-height: 1.55;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.settings-note.warn {
|
||
color: var(--down);
|
||
border-color: color-mix(in oklab, var(--down) 18%, var(--line));
|
||
background: var(--down-soft);
|
||
}
|
||
|
||
/* ============================================================
|
||
Dashboard specific
|
||
============================================================ */
|
||
|
||
.dash-grid {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 360px;
|
||
gap: 20px;
|
||
align-items: start;
|
||
}
|
||
/* Grid items default to min-width:auto, so an intrinsically-wide child (the
|
||
lightweight-charts canvas, a long URL) blows the column past the viewport
|
||
on phones — the whole page then scrolls sideways. Let columns shrink. */
|
||
.dash-grid > * { min-width: 0; }
|
||
|
||
.hero-value {
|
||
font-size: 44px;
|
||
font-weight: 600;
|
||
letter-spacing: -0.03em;
|
||
line-height: 1;
|
||
font-family: var(--mono);
|
||
font-feature-settings: 'tnum';
|
||
}
|
||
.hero-value .cents { color: var(--ink-3); font-size: 0.6em; }
|
||
|
||
.asset-switch {
|
||
display: inline-flex;
|
||
padding: 4px;
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-pill);
|
||
gap: 2px;
|
||
}
|
||
.asset-switch button {
|
||
padding: 7px 14px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
color: var(--ink-3);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.asset-switch button.on {
|
||
background: color-mix(in oklab, var(--amber) 6%, var(--surface));
|
||
color: var(--ink);
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.6);
|
||
border: 1px solid color-mix(in oklab, var(--amber) 20%, transparent);
|
||
}
|
||
.asset-dot {
|
||
width: 14px;
|
||
height: 14px;
|
||
border-radius: 999px;
|
||
}
|
||
.asset-dot.btc { background: linear-gradient(135deg, #f7931a, #f2a93b); }
|
||
.asset-dot.eth { background: linear-gradient(135deg, #627eea, #8fa2ff); }
|
||
|
||
.tf-bar {
|
||
display: inline-flex;
|
||
gap: 2px;
|
||
padding: 3px;
|
||
background: var(--bg-sunk);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-pill);
|
||
}
|
||
.tf-bar button {
|
||
padding: 5px 10px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 12px;
|
||
font-weight: 500;
|
||
color: var(--ink-3);
|
||
font-family: var(--mono);
|
||
}
|
||
.tf-bar button.on {
|
||
background: linear-gradient(135deg, oklch(24% 0.012 80) 0%, oklch(14% 0.006 85) 100%);
|
||
color: oklch(97% 0.005 85);
|
||
box-shadow: 0 1px 4px rgba(0,0,0,0.2), inset 0 1px 0 rgba(255,255,255,0.07);
|
||
}
|
||
|
||
.chart-wrap {
|
||
margin-top: 8px;
|
||
position: relative;
|
||
height: 360px;
|
||
}
|
||
|
||
.chart-footnote {
|
||
display: flex;
|
||
gap: 18px;
|
||
font-size: 11.5px;
|
||
color: var(--ink-3);
|
||
border-top: 1px dashed var(--line);
|
||
padding-top: 14px;
|
||
margin-top: 4px;
|
||
letter-spacing: 0.01em;
|
||
}
|
||
.chart-footnote .item { display: flex; align-items: center; gap: 6px; }
|
||
.legend-dot { width: 8px; height: 8px; border-radius: 3px; box-shadow: 0 1px 3px rgba(0,0,0,0.12); }
|
||
|
||
/* KPI tiles */
|
||
.kpi-row {
|
||
display: grid;
|
||
grid-template-columns: repeat(4, 1fr);
|
||
gap: 12px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.kpi {
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-md);
|
||
padding: 16px 18px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
position: relative;
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.5);
|
||
}
|
||
.kpi .label {
|
||
font-size: 11px;
|
||
color: var(--ink-3);
|
||
font-weight: 600;
|
||
letter-spacing: 0.05em;
|
||
text-transform: uppercase;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.kpi .value {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.02em;
|
||
font-family: var(--mono);
|
||
}
|
||
.kpi .foot {
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.kpi.accent {
|
||
background: linear-gradient(135deg, oklch(97% 0.05 82), oklch(95% 0.09 76));
|
||
border-color: var(--amber-ring);
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.7);
|
||
}
|
||
.kpi.accent .label { color: var(--amber-ink); }
|
||
|
||
/* Overview */
|
||
.overview-shell {
|
||
display: grid;
|
||
grid-template-columns: minmax(0, 1fr) 300px;
|
||
gap: 14px;
|
||
margin-bottom: 20px;
|
||
align-items: start;
|
||
}
|
||
|
||
.overview-main {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
min-width: 0;
|
||
}
|
||
|
||
.overview-side {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 16px;
|
||
}
|
||
|
||
.overview-market-card,
|
||
.overview-side-card,
|
||
.overview-stat-card {
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: 16px;
|
||
padding: 20px;
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.55);
|
||
min-width: 0;
|
||
}
|
||
|
||
.overview-market-card {
|
||
background:
|
||
linear-gradient(135deg,
|
||
color-mix(in oklab, var(--amber) 12%, var(--surface)) 0%,
|
||
var(--surface) 48%,
|
||
color-mix(in oklab, var(--up) 8%, var(--surface)) 100%);
|
||
box-shadow: var(--shadow-2), inset 0 1px 0 rgba(255,255,255,0.65);
|
||
}
|
||
|
||
.overview-kicker {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
color: var(--amber-ink);
|
||
margin-bottom: 10px;
|
||
opacity: 0.85;
|
||
}
|
||
|
||
.overview-card-head {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
margin-bottom: 18px;
|
||
}
|
||
|
||
.overview-headline-row {
|
||
display: flex;
|
||
align-items: flex-end;
|
||
gap: 12px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.overview-market-subtitle {
|
||
margin-top: 8px;
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.overview-controls {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: flex-end;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* ── Macro composite — unified card (band + track + scale together) ── */
|
||
|
||
/* Outer wrapper so band / track / scale read as ONE component.
|
||
Tone-coloured rim hints at the regime without competing with the big
|
||
number; it only kicks in for bull / bear so a neutral day stays calm. */
|
||
.overview-macro-card {
|
||
margin-top: 4px;
|
||
padding: 16px 18px 14px;
|
||
border-radius: 14px;
|
||
border: 1px solid var(--line);
|
||
background: color-mix(in oklab, var(--bg-sunk) 72%, var(--surface));
|
||
box-shadow: var(--shadow-1);
|
||
transition: border-color 200ms ease;
|
||
}
|
||
.overview-macro-card.bull {
|
||
border-color: color-mix(in oklab, var(--up) 30%, var(--line));
|
||
background: color-mix(in oklab, var(--up) 5%, color-mix(in oklab, var(--bg-sunk) 72%, var(--surface)));
|
||
}
|
||
.overview-macro-card.bear {
|
||
border-color: color-mix(in oklab, var(--down) 30%, var(--line));
|
||
background: color-mix(in oklab, var(--down) 5%, color-mix(in oklab, var(--bg-sunk) 72%, var(--surface)));
|
||
}
|
||
|
||
/* Band = title-row + summary (left) | big score + pill (right).
|
||
No own border any more — the card around it is the visual edge. */
|
||
.overview-macro-band {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
gap: 18px;
|
||
}
|
||
|
||
.overview-macro-copy {
|
||
min-width: 0;
|
||
flex: 1 1 0;
|
||
}
|
||
|
||
.overview-macro-title-row {
|
||
display: flex;
|
||
align-items: baseline;
|
||
gap: 10px;
|
||
flex-wrap: wrap;
|
||
margin-bottom: 4px;
|
||
}
|
||
|
||
.overview-macro-title {
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.02em;
|
||
color: var(--ink);
|
||
}
|
||
|
||
/* Small dim caption next to the title — gives the user a quick "what is
|
||
this and when did it update" anchor without crowding the headline. */
|
||
.overview-macro-stamp {
|
||
font-size: 11px;
|
||
letter-spacing: 0.04em;
|
||
color: var(--ink-4);
|
||
text-transform: uppercase;
|
||
}
|
||
|
||
.overview-macro-text,
|
||
.overview-side-copy,
|
||
.overview-stat-label {
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.overview-macro-score {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-end;
|
||
gap: 6px;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
.overview-score-value {
|
||
font-family: var(--mono);
|
||
font-size: 38px;
|
||
line-height: 1;
|
||
font-weight: 800;
|
||
letter-spacing: -0.03em;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.overview-score-value.bull { color: var(--up); }
|
||
.overview-score-value.bear { color: var(--down); }
|
||
.overview-score-value.neutral { color: var(--ink-2); }
|
||
|
||
.overview-score-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
height: 24px;
|
||
padding: 0 11px;
|
||
border-radius: 999px;
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
font-size: 10.5px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.1em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-3);
|
||
box-shadow: inset 0 1px 0 rgba(255,255,255,0.5);
|
||
}
|
||
|
||
.overview-score-pill.bull {
|
||
/* Darkened from var(--up) (62% → 3.0:1) to clear AA 4.5:1 on the 12% tint. */
|
||
color: oklch(40% 0.17 150);
|
||
border-color: color-mix(in oklab, var(--up) 32%, var(--line));
|
||
background: color-mix(in oklab, var(--up) 12%, var(--surface));
|
||
}
|
||
|
||
.overview-score-pill.bear {
|
||
color: oklch(42% 0.20 27);
|
||
border-color: color-mix(in oklab, var(--down) 32%, var(--line));
|
||
background: color-mix(in oklab, var(--down) 12%, var(--surface));
|
||
}
|
||
|
||
/* Dark mode: tint background is dark, so revert to the bright tone tokens. */
|
||
html[data-theme="dark"] .overview-score-pill.bull { color: var(--up); }
|
||
html[data-theme="dark"] .overview-score-pill.bear { color: var(--down); }
|
||
|
||
/* Gradient track. Removed the .overview-score-fill overlay — the gradient
|
||
already encodes "where am I on the spectrum"; layering an opaque fill
|
||
only obscured the gradient at scores near 0. */
|
||
.overview-score-track {
|
||
position: relative;
|
||
height: 16px;
|
||
margin-top: 14px;
|
||
border-radius: 999px;
|
||
overflow: visible;
|
||
border: 1px solid color-mix(in oklab, var(--line) 78%, transparent);
|
||
box-shadow: inset 0 1px 3px rgba(15, 23, 42, 0.1), inset 0 -1px 0 rgba(255,255,255,0.3);
|
||
background: linear-gradient(90deg,
|
||
color-mix(in oklab, var(--down) 70%, transparent) 0%,
|
||
color-mix(in oklab, var(--down) 20%, transparent) 35%,
|
||
color-mix(in oklab, var(--bg-sunk) 90%, transparent) 50%,
|
||
color-mix(in oklab, var(--up) 20%, transparent) 65%,
|
||
color-mix(in oklab, var(--up) 70%, transparent) 100%);
|
||
}
|
||
|
||
/* Vertical centerline tick so 0 is visually obvious. */
|
||
.overview-score-track::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: -3px;
|
||
bottom: -3px;
|
||
left: 50%;
|
||
width: 1px;
|
||
background: color-mix(in oklab, var(--ink) 18%, transparent);
|
||
transform: translateX(-50%);
|
||
}
|
||
|
||
/* SOLID needle (was a hollow ring before — looked like a placeholder).
|
||
Tone-coloured fill + white ring so it stands out against any gradient
|
||
position. Two-layer shadow for depth on light AND dark themes. */
|
||
.overview-score-needle {
|
||
position: absolute;
|
||
top: 50%;
|
||
width: 22px;
|
||
height: 22px;
|
||
border-radius: 999px;
|
||
background: var(--ink-2);
|
||
border: 3px solid var(--surface);
|
||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.25),
|
||
0 0 0 1px color-mix(in oklab, var(--ink) 18%, transparent);
|
||
transform: translateY(-50%);
|
||
transition: left 400ms cubic-bezier(0.4, 0, 0.2, 1);
|
||
}
|
||
|
||
.overview-score-needle.bull { background: var(--up); }
|
||
.overview-score-needle.bear { background: var(--down); }
|
||
.overview-score-needle.neutral { background: var(--ink-3); }
|
||
|
||
.overview-score-scale {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
gap: 10px;
|
||
margin-top: 8px;
|
||
font-size: 10.5px;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
}
|
||
|
||
.overview-system-strip {
|
||
display: none; /* replaced by .overview-stats-bar */
|
||
}
|
||
|
||
.overview-system-chip {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: 2px;
|
||
flex: 1;
|
||
padding: 10px 16px;
|
||
border-right: 1px solid var(--line);
|
||
border-radius: 0;
|
||
border-top: none;
|
||
border-bottom: none;
|
||
border-left: none;
|
||
background: transparent;
|
||
box-shadow: none;
|
||
transition: background 100ms;
|
||
}
|
||
|
||
.overview-system-chip:last-child {
|
||
border-right: none;
|
||
}
|
||
|
||
.overview-system-chip:hover {
|
||
transform: none;
|
||
box-shadow: none;
|
||
background: color-mix(in oklab, var(--amber) 5%, transparent);
|
||
}
|
||
|
||
.overview-system-chip.passive {
|
||
cursor: default;
|
||
}
|
||
.overview-system-chip.passive:hover {
|
||
background: transparent;
|
||
}
|
||
|
||
.overview-system-chip-name {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
}
|
||
|
||
.overview-system-chip strong {
|
||
font-family: var(--mono);
|
||
font-size: 20px;
|
||
line-height: 1.1;
|
||
font-weight: 700;
|
||
color: var(--ink);
|
||
}
|
||
|
||
/* ── Unified stats bar (replaces system strip + secondary grid) ─── */
|
||
.overview-stats-bar {
|
||
display: flex;
|
||
align-items: stretch;
|
||
border: 1px solid var(--line);
|
||
border-radius: 14px;
|
||
overflow: hidden;
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.55);
|
||
}
|
||
|
||
.stats-bar-item {
|
||
display: flex;
|
||
flex-direction: column;
|
||
justify-content: center;
|
||
gap: 3px;
|
||
flex: 1;
|
||
padding: 12px 16px;
|
||
border-right: 1px solid var(--line);
|
||
background: transparent;
|
||
border-top: none;
|
||
border-bottom: none;
|
||
border-left: none;
|
||
transition: background 100ms;
|
||
text-decoration: none;
|
||
color: inherit;
|
||
}
|
||
|
||
.stats-bar-item:not(.passive):hover {
|
||
background: color-mix(in oklab, var(--amber) 5%, transparent);
|
||
}
|
||
|
||
.stats-bar-item.passive {
|
||
cursor: default;
|
||
}
|
||
|
||
/* Thin vertical separator between signal counts and personal stats */
|
||
.stats-bar-divider {
|
||
width: 1px;
|
||
background: var(--line);
|
||
flex-shrink: 0;
|
||
align-self: stretch;
|
||
margin: 10px 0;
|
||
}
|
||
|
||
.stats-bar-label {
|
||
font-size: 10px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.08em;
|
||
text-transform: uppercase;
|
||
color: var(--ink-4);
|
||
white-space: nowrap;
|
||
}
|
||
|
||
.stats-bar-value {
|
||
font-family: var(--mono);
|
||
font-size: 22px;
|
||
font-weight: 800;
|
||
line-height: 1.1;
|
||
letter-spacing: -0.025em;
|
||
}
|
||
|
||
/* Keep old classes so nothing else breaks */
|
||
.overview-secondary-grid { display: none; }
|
||
.overview-stat-card { display: none; }
|
||
.overview-stat-value {
|
||
font-family: var(--mono);
|
||
font-size: 32px;
|
||
line-height: 1;
|
||
font-weight: 800;
|
||
letter-spacing: -0.03em;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.overview-side-card.compact {
|
||
min-height: 112px;
|
||
}
|
||
|
||
.overview-account-list {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 0;
|
||
}
|
||
|
||
.overview-account-item {
|
||
display: flex;
|
||
align-items: baseline;
|
||
justify-content: space-between;
|
||
gap: 16px;
|
||
padding: 10px 0;
|
||
border-bottom: 1px solid var(--line);
|
||
font-size: 13px;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.overview-account-item:last-child {
|
||
border-bottom: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.overview-account-item strong {
|
||
color: var(--ink);
|
||
font-size: 14px;
|
||
text-align: right;
|
||
}
|
||
|
||
/* Right rail */
|
||
.rail { display: flex; flex-direction: column; gap: 20px; }
|
||
|
||
.confidence-bar {
|
||
height: 6px;
|
||
background: var(--surface-3);
|
||
border-radius: 999px;
|
||
overflow: hidden;
|
||
position: relative;
|
||
margin-top: 6px;
|
||
}
|
||
.confidence-bar > div {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, var(--amber) 0%, oklch(68% 0.2 45) 100%);
|
||
border-radius: 999px;
|
||
transition: width 600ms ease-out;
|
||
}
|
||
|
||
.ai-metric-head {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: baseline;
|
||
gap: 12px;
|
||
margin-bottom: 8px;
|
||
font-size: 13px;
|
||
color: var(--ink-3);
|
||
}
|
||
|
||
.ai-metric-head strong {
|
||
font-size: 18px;
|
||
line-height: 1;
|
||
color: var(--ink);
|
||
font-family: var(--mono);
|
||
font-weight: 600;
|
||
letter-spacing: -0.02em;
|
||
}
|
||
|
||
.ai-reasoning-label {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 8px;
|
||
margin-bottom: 10px;
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
letter-spacing: 0.12em;
|
||
text-transform: uppercase;
|
||
color: var(--amber-ink);
|
||
}
|
||
|
||
.ai-reasoning-label::before {
|
||
content: '';
|
||
width: 8px;
|
||
height: 8px;
|
||
border-radius: 999px;
|
||
background: linear-gradient(135deg, var(--amber), oklch(68% 0.2 45));
|
||
box-shadow: 0 0 0 4px color-mix(in oklab, var(--amber) 18%, transparent);
|
||
}
|
||
|
||
.ai-reasoning-card {
|
||
padding: 16px 18px;
|
||
background:
|
||
linear-gradient(180deg, color-mix(in oklab, var(--amber-soft) 55%, var(--surface)) 0%, var(--bg-sunk) 100%);
|
||
border-radius: 18px;
|
||
border: 1px solid color-mix(in oklab, var(--amber-ring) 55%, var(--line));
|
||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.7), var(--shadow-1);
|
||
font-size: 15px;
|
||
line-height: 1.78;
|
||
color: var(--ink);
|
||
}
|
||
|
||
.ai-reasoning-card.scroll {
|
||
max-height: 180px;
|
||
overflow-y: auto;
|
||
padding-right: 14px;
|
||
}
|
||
|
||
html[data-theme="dark"] .ai-reasoning-card {
|
||
background:
|
||
linear-gradient(180deg, color-mix(in oklab, var(--amber-soft) 30%, var(--surface-2)) 0%, var(--surface) 100%);
|
||
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.03), var(--shadow-1);
|
||
}
|
||
|
||
/* Post list (stream) */
|
||
.post-stream {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
}
|
||
.post-row {
|
||
display: flex;
|
||
flex-direction: column;
|
||
background: var(--surface);
|
||
border: 1px solid var(--line);
|
||
border-radius: var(--r-md);
|
||
transition: border-color 150ms, background 150ms, box-shadow 150ms;
|
||
cursor: pointer;
|
||
overflow: hidden;
|
||
box-shadow: var(--shadow-1);
|
||
}
|
||
.post-row:hover {
|
||
border-color: color-mix(in oklab, var(--amber) 25%, var(--line));
|
||
box-shadow: var(--shadow-2);
|
||
transform: translateY(-1px);
|
||
}
|
||
.post-row.selected {
|
||
border-color: color-mix(in oklab, var(--amber) 55%, var(--line));
|
||
background: color-mix(in oklab, var(--amber) 4%, var(--surface));
|
||
box-shadow: var(--shadow-2), 0 0 0 1px color-mix(in oklab, var(--amber) 20%, transparent);
|
||
}
|
||
/* Buy signal: green left accent */
|
||
.post-row.signal-buy {
|
||
border-left: 4px solid var(--up);
|
||
background: linear-gradient(90deg, color-mix(in oklab, var(--up) 5%, var(--surface)) 0%, var(--surface) 160px);
|
||
}
|
||
/* Short signal: red left accent */
|
||
.post-row.signal-short {
|
||
border-left: 4px solid var(--down);
|
||
background: linear-gradient(90deg, color-mix(in oklab, var(--down) 5%, var(--surface)) 0%, var(--surface) 160px);
|
||
}
|
||
html[data-theme="dark"] .post-row.signal-buy {
|
||
background: linear-gradient(90deg, color-mix(in oklab, var(--up) 10%, var(--surface)) 0%, var(--surface) 160px);
|
||
}
|
||
html[data-theme="dark"] .post-row.signal-short {
|
||
background: linear-gradient(90deg, color-mix(in oklab, var(--down) 10%, var(--surface)) 0%, var(--surface) 160px);
|
||
}
|
||
|
||
/* Off-topic / noise posts: compact, recessed, low-emphasis. They're the bulk
|
||
of the Trump feed but carry no signal — make them read as skippable filler
|
||
so the eye lands on the real signals. */
|
||
.post-row.noise {
|
||
background: var(--bg-sunk);
|
||
border-color: transparent;
|
||
opacity: 0.82;
|
||
}
|
||
.post-row.noise:hover {
|
||
opacity: 1;
|
||
}
|
||
.post-row.noise:hover { border-color: var(--line); }
|
||
.post-row.noise .post-row-main {
|
||
grid-template-columns: 22px 1fr; /* drop the aside column */
|
||
gap: 10px;
|
||
padding: 8px 14px;
|
||
align-items: center;
|
||
}
|
||
.post-row.noise .src-ico {
|
||
width: 22px; height: 22px;
|
||
font-size: 11px; border-radius: 6px;
|
||
opacity: 0.45;
|
||
align-self: center;
|
||
}
|
||
.post-row.noise .post-body .meta { margin-bottom: 2px; }
|
||
.post-row.noise .post-body .text { margin: 0; font-size: 13px; }
|
||
.post-row-main {
|
||
display: grid;
|
||
grid-template-columns: 36px 1fr auto;
|
||
gap: 14px;
|
||
padding: 14px 16px;
|
||
align-items: flex-start;
|
||
}
|
||
.post-row-detail {
|
||
border-top: 1px solid var(--line);
|
||
padding: 14px 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 14px;
|
||
}
|
||
.src-ico {
|
||
width: 36px;
|
||
height: 36px;
|
||
border-radius: 10px;
|
||
display: grid;
|
||
place-items: center;
|
||
font-family: var(--mono);
|
||
font-weight: 600;
|
||
font-size: 15px;
|
||
flex-shrink: 0;
|
||
}
|
||
.src-ico.x { background: #111; color: #fff; }
|
||
.src-ico.truth { background: oklch(92% 0.08 28); color: oklch(40% 0.22 25); font-weight: 700; }
|
||
/* Non-Trump sources — distinct hues so the feed reads at a glance. */
|
||
.src-ico.breakout { background: oklch(94% 0.08 200); color: oklch(40% 0.15 220); }
|
||
.src-ico.reversal { background: oklch(94% 0.08 300); color: oklch(40% 0.15 300); }
|
||
.src-ico.whale { background: oklch(94% 0.08 150); color: oklch(40% 0.15 150); font-size: 13px; }
|
||
.src-ico.manual { background: oklch(94% 0.05 60); color: oklch(45% 0.15 60); font-size: 13px; }
|
||
.src-ico.external { background: var(--bg-sunk); color: var(--ink-2); }
|
||
/* min-width:0 — without it a long unbreakable URL in the text widens the 1fr
|
||
grid column past the card and the right edge (meta tag included) is clipped. */
|
||
.post-body { min-width: 0; }
|
||
.post-body .meta {
|
||
display: flex;
|
||
align-items: center;
|
||
flex-wrap: wrap;
|
||
gap: 8px;
|
||
margin-bottom: 6px;
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
}
|
||
.post-body .text {
|
||
font-size: 14px;
|
||
line-height: 1.5;
|
||
color: var(--ink);
|
||
margin: 0 0 10px;
|
||
overflow-wrap: anywhere;
|
||
}
|
||
.post-aside {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 8px;
|
||
align-items: flex-end;
|
||
min-width: 120px;
|
||
}
|
||
|
||
/* Signal pill */
|
||
.sig {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 4px 10px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 11px;
|
||
font-weight: 800;
|
||
letter-spacing: 0.06em;
|
||
}
|
||
.sig.buy {
|
||
background: linear-gradient(135deg, var(--up) 0%, oklch(66% 0.19 155) 100%);
|
||
color: #fff;
|
||
box-shadow: 0 2px 8px color-mix(in oklab, var(--up) 45%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.2);
|
||
}
|
||
.sig.sell, .sig.short {
|
||
background: linear-gradient(135deg, var(--down) 0%, oklch(55% 0.24 18) 100%);
|
||
color: #fff;
|
||
box-shadow: 0 2px 8px color-mix(in oklab, var(--down) 45%, transparent),
|
||
inset 0 1px 0 rgba(255,255,255,0.15);
|
||
}
|
||
.sig.hold {
|
||
background: var(--bg-sunk);
|
||
color: var(--ink-3);
|
||
border: 1px solid var(--line);
|
||
font-weight: 600;
|
||
}
|
||
|
||
.impact-mini {
|
||
display: flex;
|
||
gap: 8px;
|
||
align-items: center;
|
||
font-family: var(--mono);
|
||
font-size: 12px;
|
||
}
|
||
.impact-mini .tf { color: var(--ink-4); font-size: 11px; }
|
||
|
||
/* Trades table */
|
||
.table {
|
||
width: 100%;
|
||
border-collapse: separate;
|
||
border-spacing: 0;
|
||
font-size: 13px;
|
||
}
|
||
.table th {
|
||
text-align: left;
|
||
font-weight: 700;
|
||
color: var(--ink-3);
|
||
padding: 12px 18px;
|
||
border-bottom: 1px solid var(--line);
|
||
font-size: 11px;
|
||
letter-spacing: 0.06em;
|
||
text-transform: uppercase;
|
||
background: var(--bg-sunk);
|
||
}
|
||
.table th:first-child { border-top-left-radius: var(--r-md); }
|
||
.table th:last-child { border-top-right-radius: var(--r-md); text-align: right; }
|
||
.table td {
|
||
padding: 14px 18px;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
.table td:last-child { text-align: right; }
|
||
.table tr:last-child td { border-bottom: 0; }
|
||
.table tr:hover td { background: var(--bg-sunk); }
|
||
|
||
.side-pill {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
padding: 3px 9px;
|
||
border-radius: var(--r-pill);
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
}
|
||
.side-pill.long { background: var(--up-soft); color: oklch(38% 0.16 148); }
|
||
.side-pill.short { background: var(--down-soft); color: oklch(42% 0.2 25); }
|
||
|
||
/* Settings */
|
||
.settings-grid {
|
||
display: grid;
|
||
grid-template-columns: 260px 1fr;
|
||
gap: 32px;
|
||
align-items: start;
|
||
}
|
||
.settings-side {
|
||
position: sticky;
|
||
top: 84px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 2px;
|
||
}
|
||
.settings-side button {
|
||
text-align: left;
|
||
padding: 10px 14px;
|
||
border-radius: var(--r-sm);
|
||
font-size: 13px;
|
||
color: var(--ink-2);
|
||
font-weight: 500;
|
||
}
|
||
.settings-side button.on { background: var(--bg-sunk); color: var(--ink); }
|
||
.settings-side button:hover { background: var(--bg-sunk); color: var(--ink); }
|
||
|
||
.field {
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 6px;
|
||
margin-bottom: 20px;
|
||
}
|
||
.field label {
|
||
font-size: 13px;
|
||
font-weight: 500;
|
||
}
|
||
.field .hint {
|
||
font-size: 12px;
|
||
color: var(--ink-3);
|
||
}
|
||
.field input, .field select, .field textarea {
|
||
border: 1px solid var(--line);
|
||
background: var(--surface);
|
||
border-radius: var(--r-sm);
|
||
padding: 11px 14px;
|
||
font-size: 14px;
|
||
width: 100%;
|
||
outline: none;
|
||
transition: border-color 120ms, box-shadow 120ms;
|
||
color: var(--ink);
|
||
}
|
||
.field input:focus, .field textarea:focus {
|
||
border-color: var(--amber-ring);
|
||
box-shadow: 0 0 0 3px oklch(88% 0.12 80 / 0.4);
|
||
}
|
||
|
||
.settings-switch {
|
||
--w: 40px;
|
||
width: var(--w);
|
||
height: 24px;
|
||
border-radius: 999px;
|
||
background: var(--surface-3);
|
||
position: relative;
|
||
cursor: pointer;
|
||
transition: background 150ms;
|
||
border: 1px solid var(--line);
|
||
flex-shrink: 0;
|
||
}
|
||
.settings-switch::after {
|
||
content: '';
|
||
position: absolute;
|
||
top: 2px;
|
||
left: 2px;
|
||
width: 18px;
|
||
height: 18px;
|
||
border-radius: 999px;
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-1);
|
||
transition: transform 180ms;
|
||
}
|
||
.settings-switch.on {
|
||
background: linear-gradient(135deg, var(--amber) 0%, oklch(73% 0.18 70) 100%);
|
||
border-color: var(--amber);
|
||
box-shadow: 0 0 0 2px color-mix(in oklab, var(--amber) 20%, transparent);
|
||
}
|
||
.settings-switch.on::after { transform: translateX(16px); }
|
||
|
||
.setting-row {
|
||
display: flex;
|
||
align-items: flex-start;
|
||
justify-content: space-between;
|
||
gap: 24px;
|
||
padding: 16px 0;
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
.setting-row:last-child { border-bottom: 0; }
|
||
.setting-row .desc { font-size: 12px; color: var(--ink-3); margin-top: 4px; max-width: 440px; line-height: 1.5; }
|
||
|
||
/* Analytics */
|
||
.metric-grid {
|
||
display: grid;
|
||
grid-template-columns: repeat(3, 1fr);
|
||
gap: 16px;
|
||
}
|
||
|
||
@media (max-width: 1180px) {
|
||
.overview-shell {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.overview-side {
|
||
order: -1;
|
||
}
|
||
|
||
/* Stats bar: 2 columns on tablet/narrow desktop */
|
||
.overview-stats-bar {
|
||
flex-wrap: wrap;
|
||
}
|
||
.stats-bar-item {
|
||
flex: 0 0 calc(50% - 1px);
|
||
border-right: 1px solid var(--line);
|
||
border-bottom: 1px solid var(--line);
|
||
}
|
||
.stats-bar-item:nth-child(2n) {
|
||
border-right: none;
|
||
}
|
||
.stats-bar-item:nth-last-child(-n+2) {
|
||
border-bottom: none;
|
||
}
|
||
.stats-bar-divider { display: none; }
|
||
|
||
.dash-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.rail {
|
||
order: -1;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.nav {
|
||
height: auto;
|
||
min-height: 64px;
|
||
padding: 12px 18px;
|
||
flex-wrap: wrap;
|
||
gap: 12px;
|
||
}
|
||
|
||
.brand {
|
||
flex: 1;
|
||
}
|
||
|
||
.nav-tabs {
|
||
order: 3;
|
||
width: 100%;
|
||
overflow-x: auto;
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.nav-right {
|
||
margin-left: auto;
|
||
}
|
||
|
||
.page {
|
||
padding: 24px 18px 64px;
|
||
}
|
||
|
||
.page-head {
|
||
align-items: flex-start;
|
||
flex-direction: column;
|
||
gap: 12px;
|
||
}
|
||
|
||
.page-title {
|
||
font-size: 28px;
|
||
}
|
||
|
||
.kpi-row,
|
||
.metric-grid {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.overview-secondary-grid {
|
||
grid-template-columns: repeat(2, minmax(0, 1fr));
|
||
}
|
||
|
||
.settings-grid,
|
||
.form-row {
|
||
grid-template-columns: 1fr;
|
||
gap: 10px;
|
||
}
|
||
|
||
.settings-side {
|
||
position: static;
|
||
}
|
||
|
||
.chart-footnote {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
.chart-footnote > div:last-child {
|
||
margin-left: 0 !important;
|
||
width: 100%;
|
||
}
|
||
|
||
.table {
|
||
min-width: 760px;
|
||
}
|
||
|
||
.card.flush {
|
||
overflow-x: auto !important;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 900px) {
|
||
.nav-tabs {
|
||
/* Edge-to-edge horizontal scroll with snap on mobile */
|
||
margin: 0 -18px;
|
||
padding: 0 18px;
|
||
gap: 4px;
|
||
scroll-snap-type: x proximity;
|
||
-webkit-overflow-scrolling: touch;
|
||
scrollbar-width: none;
|
||
}
|
||
.nav-tabs::-webkit-scrollbar { display: none; }
|
||
.nav-tab {
|
||
flex: 0 0 auto;
|
||
scroll-snap-align: start;
|
||
padding: 8px 12px;
|
||
font-size: 13px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
.nav {
|
||
padding: 10px 14px;
|
||
}
|
||
|
||
.nav-tabs {
|
||
margin: 0 -14px;
|
||
padding: 0 14px;
|
||
}
|
||
|
||
.brand span:last-child {
|
||
display: none;
|
||
}
|
||
|
||
.connect-btn.lg {
|
||
padding: 9px 12px;
|
||
font-size: 13px;
|
||
}
|
||
.wallet-chip {
|
||
padding: 6px 10px !important;
|
||
font-size: 12px;
|
||
}
|
||
|
||
.page {
|
||
padding: 20px 14px 56px;
|
||
}
|
||
|
||
.kpi-row,
|
||
.metric-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.overview-card-head,
|
||
.overview-controls,
|
||
.overview-macro-band,
|
||
.overview-account-item {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.overview-score-value {
|
||
font-size: 34px;
|
||
}
|
||
|
||
.overview-account-item strong {
|
||
text-align: left;
|
||
}
|
||
|
||
.overview-secondary-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.overview-system-strip {
|
||
flex-wrap: wrap;
|
||
}
|
||
|
||
/* Guest onboarding strip: 3-col → 1-col on mobile */
|
||
.guest-strip { grid-template-columns: 1fr !important; }
|
||
|
||
.macro-panel-head,
|
||
.macro-composite-head {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.macro-panel-meta {
|
||
text-align: left;
|
||
}
|
||
|
||
.macro-grid.two {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.macro-grid {
|
||
padding: 12px;
|
||
gap: 12px;
|
||
}
|
||
|
||
.macro-metric-card,
|
||
.macro-guide-card {
|
||
padding: 16px;
|
||
min-height: 0;
|
||
}
|
||
|
||
.macro-metric-head {
|
||
/* Desktop is now also flex-direction: column. Just override the gap
|
||
for mobile to keep label-to-value spacing comfortable on small fonts. */
|
||
gap: 8px;
|
||
}
|
||
|
||
.macro-metric-value {
|
||
font-size: 30px;
|
||
}
|
||
|
||
.macro-guide-title {
|
||
font-size: 18px;
|
||
}
|
||
|
||
.macro-summary {
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
min-height: 0;
|
||
}
|
||
|
||
.macro-threshold-chip {
|
||
font-size: 11.5px;
|
||
/* Bump tap target on mobile — iOS HIG asks for ≥44pt, this is the
|
||
inline-flex bubble so we go a bit smaller but still comfortable. */
|
||
min-height: 36px;
|
||
padding: 7px 12px;
|
||
}
|
||
.macro-threshold-chip.active {
|
||
font-size: 12px;
|
||
padding: 8px 14px;
|
||
/* Stronger scale on mobile — small screens lose subtle differences. */
|
||
transform: scale(1.08);
|
||
}
|
||
|
||
.macro-action-btn {
|
||
/* Stays compact on mobile too — bottom-right corner pill, not full-width. */
|
||
padding: 8px 12px;
|
||
}
|
||
|
||
.settings-scope-grid {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.settings-control-center {
|
||
grid-template-columns: 1fr;
|
||
}
|
||
|
||
.settings-section-head {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.settings-section-note {
|
||
text-align: left;
|
||
}
|
||
|
||
/* Composite scale labels — "BEAR / NEUTRAL / BULL" letters crowd at narrow
|
||
widths. Shorten them. */
|
||
.macro-composite-scale {
|
||
font-size: 9.5px;
|
||
letter-spacing: 0.02em;
|
||
}
|
||
|
||
/* InfoTip — boost tap area and clamp bubble inside viewport */
|
||
.infotip {
|
||
/* Pad outside the visible icon to enlarge the hit zone without making
|
||
the icon itself look bloated. */
|
||
padding: 8px;
|
||
margin: -8px -2px -8px 4px;
|
||
}
|
||
.infotip-icon {
|
||
width: 18px;
|
||
height: 18px;
|
||
font-size: 11px;
|
||
}
|
||
.infotip-bubble {
|
||
/* On small viewports a 280px-wide bubble can hang off the edge when
|
||
the tip sits near the right margin. Clamp to viewport width minus
|
||
a 16px breathing room each side. */
|
||
max-width: calc(100vw - 32px) !important;
|
||
}
|
||
/* Touch-only browsers fire :active on tap. Combined with :hover, this
|
||
ensures bubble shows on first tap (not the doubled-tap that some
|
||
CSS-hover-only tooltips require). */
|
||
.infotip:active .infotip-bubble {
|
||
opacity: 1;
|
||
}
|
||
/* Keep the viewport-clamp shift on tap — `transform: none` here used to
|
||
discard it and re-centre the bubble off-screen. */
|
||
.infotip-top:active .infotip-bubble,
|
||
.infotip-bottom:active .infotip-bubble {
|
||
transform: translate(calc(-50% + var(--tip-shift, 0px)), 0);
|
||
}
|
||
.infotip-left:active .infotip-bubble { transform: translate(0, -50%); }
|
||
.infotip-right:active .infotip-bubble { transform: translate(0, -50%); }
|
||
|
||
.macro-action-label {
|
||
font-size: 12px;
|
||
white-space: normal;
|
||
}
|
||
|
||
.macro-composite {
|
||
padding: 18px 16px 20px;
|
||
}
|
||
|
||
.macro-composite-right {
|
||
justify-content: flex-start;
|
||
}
|
||
|
||
.row.between {
|
||
align-items: flex-start;
|
||
}
|
||
|
||
.post-row-main {
|
||
grid-template-columns: 32px 1fr;
|
||
}
|
||
|
||
.post-aside {
|
||
grid-column: 2;
|
||
align-items: flex-start;
|
||
min-width: 0;
|
||
}
|
||
|
||
.src-ico {
|
||
width: 32px;
|
||
height: 32px;
|
||
}
|
||
|
||
.chart-wrap,
|
||
.chart-wrap > div {
|
||
height: 300px !important;
|
||
}
|
||
|
||
.hero-value {
|
||
font-size: 34px;
|
||
}
|
||
|
||
.asset-switch,
|
||
.tf-bar {
|
||
max-width: 100%;
|
||
overflow-x: auto;
|
||
}
|
||
|
||
footer {
|
||
flex-wrap: wrap;
|
||
padding: 18px 14px !important;
|
||
}
|
||
|
||
.card[style*='grid-template-columns: 1fr auto'] {
|
||
grid-template-columns: 1fr !important;
|
||
}
|
||
|
||
/* Tables: horizontal-scroll with subtle hint rather than page overflow */
|
||
.card.flush { border-radius: 10px; }
|
||
.table { font-size: 12px; }
|
||
.table th, .table td { padding: 10px 12px !important; }
|
||
|
||
/* Modals / dialogs on small screens */
|
||
.modal, .dialog { width: calc(100vw - 24px) !important; max-width: calc(100vw - 24px) !important; }
|
||
}
|
||
|
||
/* Ultra-narrow screens — drop the regime descriptive words on the composite
|
||
scale so it doesn't wrap. Keep just the numeric anchors. The .word spans
|
||
inside each label are set in MacroPanel.tsx so this hide works cleanly. */
|
||
@media (max-width: 420px) {
|
||
.macro-composite-scale .word { display: none; }
|
||
}
|
||
|
||
@media (max-width: 380px) {
|
||
.nav { padding: 8px 12px; }
|
||
.page { padding: 16px 12px 48px; }
|
||
.page-title { font-size: 24px; }
|
||
.hero-value { font-size: 28px; }
|
||
.connect-btn.lg { padding: 8px 10px; font-size: 12px; }
|
||
}
|
||
|
||
/* Global safety: no page-level horizontal scroll.
|
||
Only set overflow-x on html (the real viewport scroll container).
|
||
Setting it on body would make body a secondary scroll container and
|
||
silently break `position: sticky` on the navbar. */
|
||
html { max-width: 100%; overflow-x: hidden; }
|
||
body { max-width: 100%; }
|
||
|
||
/* Misc utilities */
|
||
.stack { display: flex; flex-direction: column; }
|
||
.row { display: flex; align-items: center; }
|
||
.between { justify-content: space-between; }
|
||
.gap-s { gap: 8px; }
|
||
.gap-m { gap: 14px; }
|
||
.gap-l { gap: 20px; }
|
||
.grow { flex: 1; }
|
||
.mono-num { font-family: var(--mono); font-variant-numeric: tabular-nums; }
|
||
.muted { color: var(--ink-3); }
|
||
.tiny { font-size: 11px; text-transform: uppercase; letter-spacing: 0.09em; color: var(--ink-3); font-weight: 600; }
|
||
|
||
/* Scrollbar */
|
||
::-webkit-scrollbar { width: 8px; height: 8px; }
|
||
::-webkit-scrollbar-track { background: transparent; }
|
||
::-webkit-scrollbar-thumb { background: var(--line-2); border-radius: 999px; border: 2px solid var(--bg); }
|
||
::-webkit-scrollbar-thumb:hover { background: color-mix(in oklab, var(--amber) 25%, var(--line-2)); }
|
||
|
||
/* ── Skeleton / shimmer loading ─────────────────────────────────────────────
|
||
Use .skeleton on any block element to get a shimmer placeholder.
|
||
Combine with explicit width/height or min-height to shape the placeholder.
|
||
.skeleton-card wraps a card-shaped block. */
|
||
@keyframes shimmer {
|
||
0% { background-position: -600px 0; }
|
||
100% { background-position: 600px 0; }
|
||
}
|
||
.skeleton {
|
||
border-radius: 6px;
|
||
background: linear-gradient(
|
||
90deg,
|
||
var(--bg-sunk) 25%,
|
||
color-mix(in srgb, var(--bg-sunk) 60%, var(--line)) 50%,
|
||
var(--bg-sunk) 75%
|
||
);
|
||
background-size: 1200px 100%;
|
||
animation: shimmer 1.4s ease-in-out infinite;
|
||
}
|
||
.skeleton-card {
|
||
border-radius: var(--r-md);
|
||
border: 1px solid var(--line);
|
||
padding: 20px;
|
||
background: var(--surface);
|
||
box-shadow: var(--shadow-1), inset 0 1px 0 rgba(255,255,255,0.5);
|
||
display: flex;
|
||
flex-direction: column;
|
||
gap: 10px;
|
||
}
|
||
/* Convenience shorthands */
|
||
.sk-line { height: 14px; }
|
||
.sk-line-sm { height: 11px; }
|
||
.sk-title { height: 20px; }
|
||
.sk-w-full { width: 100%; }
|
||
.sk-w-3q { width: 75%; }
|
||
.sk-w-half { width: 50%; }
|
||
.sk-w-q { width: 25%; }
|
||
|
||
/* ============================================================
|
||
Live "terminal" motion layer (A-tier + ticker)
|
||
All effects degrade to static under prefers-reduced-motion
|
||
(see the media query at the very end of this block).
|
||
============================================================ */
|
||
|
||
/* ── Tick flash: a value that changed pulses green/red briefly ─────────────── */
|
||
@keyframes tick-flash-up {
|
||
0% { color: var(--up); text-shadow: 0 0 10px color-mix(in oklab, var(--up) 55%, transparent); }
|
||
100% { color: inherit; text-shadow: none; }
|
||
}
|
||
@keyframes tick-flash-down {
|
||
0% { color: var(--down); text-shadow: 0 0 10px color-mix(in oklab, var(--down) 55%, transparent); }
|
||
100% { color: inherit; text-shadow: none; }
|
||
}
|
||
.tick-num { transition: color 120ms; }
|
||
.tick-flash-up { animation: tick-flash-up 0.6s ease-out 1; }
|
||
.tick-flash-down { animation: tick-flash-down 0.6s ease-out 1; }
|
||
|
||
/* ── New signal row: slide in from the top + an amber sweep across it ──────── */
|
||
@keyframes signal-slide-in {
|
||
0% { opacity: 0; transform: translateY(-10px); }
|
||
100% { opacity: 1; transform: translateY(0); }
|
||
}
|
||
@keyframes signal-sweep {
|
||
0% { background-position: -150% 0; }
|
||
100% { background-position: 250% 0; }
|
||
}
|
||
.signal-enter { animation: signal-slide-in 0.32s cubic-bezier(.2,.8,.2,1) 1; }
|
||
.signal-enter > * { position: relative; }
|
||
.signal-enter > *::after {
|
||
content: '';
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: var(--r-md);
|
||
pointer-events: none;
|
||
background: linear-gradient(
|
||
100deg,
|
||
transparent 0%,
|
||
color-mix(in oklab, var(--amber) 26%, transparent) 50%,
|
||
transparent 100%
|
||
);
|
||
background-size: 60% 100%;
|
||
background-repeat: no-repeat;
|
||
animation: signal-sweep 1.1s ease-out 1;
|
||
}
|
||
|
||
/* ── Card / chip hover glow — subtle amber ring lift on interactive cards ──── */
|
||
.overview-system-chip,
|
||
.overview-stat-card {
|
||
transition: border-color 160ms, box-shadow 220ms, transform 160ms;
|
||
}
|
||
.overview-system-chip:hover,
|
||
.overview-stat-card:hover {
|
||
box-shadow: 0 0 0 1px var(--amber-ring),
|
||
0 0 18px color-mix(in oklab, var(--amber) 22%, transparent);
|
||
transform: translateY(-1px);
|
||
}
|
||
|
||
/* ── Macro needle afterglow — a soft trailing pulse when it slides ─────────── */
|
||
.overview-score-needle {
|
||
box-shadow: 0 0 0 0 color-mix(in oklab, currentColor 45%, transparent);
|
||
transition: left 0.4s cubic-bezier(.2,.8,.2,1), box-shadow 0.6s ease-out;
|
||
}
|
||
.overview-score-needle.bull,
|
||
.overview-score-needle.bear { box-shadow: 0 0 14px 2px color-mix(in oklab, currentColor 40%, transparent); }
|
||
|
||
/* ============================================================
|
||
Ticker tape (B-#6)
|
||
============================================================ */
|
||
@keyframes ticker-marquee {
|
||
0% { transform: translateX(0); }
|
||
100% { transform: translateX(-50%); }
|
||
}
|
||
.ticker {
|
||
position: sticky;
|
||
top: 0;
|
||
z-index: 90;
|
||
overflow: hidden;
|
||
border-bottom: 1px solid var(--line);
|
||
background: color-mix(in oklab, var(--amber) 2%, var(--bg-sunk));
|
||
/* fade the two edges so cells appear/vanish instead of hard-cutting */
|
||
-webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
|
||
mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
|
||
}
|
||
.ticker-track {
|
||
display: inline-flex;
|
||
align-items: center;
|
||
white-space: nowrap;
|
||
will-change: transform;
|
||
animation: ticker-marquee 40s linear infinite;
|
||
}
|
||
.ticker:hover .ticker-track { animation-play-state: paused; }
|
||
.ticker-cell {
|
||
display: inline-flex;
|
||
align-items: baseline;
|
||
gap: 7px;
|
||
padding: 7px 22px;
|
||
font-size: 12px;
|
||
font-family: var(--mono);
|
||
font-variant-numeric: tabular-nums;
|
||
border-right: 1px solid var(--line);
|
||
}
|
||
.ticker-sym { color: var(--amber-ink); font-weight: 700; letter-spacing: 0.05em; opacity: 0.8; }
|
||
.ticker-px { color: var(--ink); font-weight: 500; transition: color 120ms; }
|
||
.ticker-arrow { font-size: 9px; width: 9px; display: inline-block; }
|
||
.ticker-arrow.up { color: var(--up); }
|
||
.ticker-arrow.down { color: var(--down); }
|
||
/* reuse the tick-flash keyframes on a whole ticker cell */
|
||
.ticker-cell.tick-flash-up .ticker-px { animation: tick-flash-up 0.6s ease-out 1; }
|
||
.ticker-cell.tick-flash-down .ticker-px { animation: tick-flash-down 0.6s ease-out 1; }
|
||
html[data-theme="dark"] .ticker {
|
||
background: color-mix(in oklab, var(--amber) 4%, var(--bg-sunk));
|
||
}
|
||
|
||
/* ============================================================
|
||
Mobile wallet sheet
|
||
============================================================ */
|
||
@keyframes sheet-slide-up {
|
||
from { transform: translateY(100%); }
|
||
to { transform: translateY(0); }
|
||
}
|
||
.mobile-sheet-enter {
|
||
animation: sheet-slide-up 0.28s cubic-bezier(0.2, 0.8, 0.2, 1) both;
|
||
}
|
||
|
||
/* ── Accessibility: honour reduced-motion. Kill all the looping/entrance
|
||
motion above; keep static, readable end-states. ───────────────────────── */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
/* Catch-all: neutralise every animation/transition (incl. infinite ones —
|
||
macro-dot-pulse, live-dot pulse, shimmer, needle pulse — and any added
|
||
later). 0.01ms instead of 0 so JS onAnimationEnd handlers still fire. */
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
/* Layout side-effects the duration reset alone can't undo: */
|
||
.ticker-track { transform: none; white-space: normal; flex-wrap: wrap; }
|
||
.signal-enter > *::after { display: none; }
|
||
.overview-system-chip:hover,
|
||
.overview-stat-card:hover { transform: none; }
|
||
}
|
||
|
||
/* ============================================================
|
||
Ticker tape — mobile overrides
|
||
============================================================ */
|
||
@media (max-width: 900px) {
|
||
.ticker {
|
||
/* On tablet/mobile the mask edges would eat too much of the narrow strip.
|
||
Tighten to 4% so content is visible closer to the edges. */
|
||
-webkit-mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
|
||
mask-image: linear-gradient(90deg, transparent, #000 4%, #000 96%, transparent);
|
||
}
|
||
.ticker-cell {
|
||
padding: 6px 14px;
|
||
gap: 5px;
|
||
}
|
||
.ticker-sym { font-size: 11px; }
|
||
.ticker-px { font-size: 11px; }
|
||
}
|
||
|
||
@media (max-width: 640px) {
|
||
/* Slow the tape a touch on mobile so it's readable while scrolling */
|
||
.ticker-track { animation-duration: 55s; }
|
||
|
||
.ticker-cell {
|
||
padding: 5px 12px;
|
||
font-size: 11px;
|
||
}
|
||
|
||
/* On very small screens, hide the direction arrow to save space */
|
||
.ticker-arrow { display: none; }
|
||
|
||
/* Overview hero price — keep it from bumping into the chip on mobile */
|
||
.overview-headline-row {
|
||
flex-wrap: wrap;
|
||
gap: 6px;
|
||
}
|
||
|
||
/* Prevent the overview market card controls from stacking awkwardly */
|
||
.overview-controls {
|
||
width: 100%;
|
||
align-items: flex-start;
|
||
}
|
||
|
||
/* Chart: reduce height on phones so it doesn't eat the full viewport */
|
||
.chart-wrap,
|
||
.chart-wrap > div {
|
||
height: 240px !important;
|
||
}
|
||
|
||
/* overview-side cards are low priority on mobile — compress them */
|
||
.overview-side-card.compact {
|
||
display: none;
|
||
}
|
||
|
||
/* system strip: wrap to 2-per-row on small phones */
|
||
.overview-system-strip {
|
||
flex-wrap: wrap;
|
||
}
|
||
.overview-system-chip {
|
||
flex: 0 0 calc(50% - 1px);
|
||
}
|
||
|
||
/* Post row: remove the aside column on very small screens */
|
||
.post-row-main {
|
||
grid-template-columns: 28px 1fr;
|
||
gap: 10px;
|
||
padding: 12px 14px;
|
||
}
|
||
}
|
||
|
||
@media (max-width: 420px) {
|
||
/* Ultra-narrow: hide ticker entirely — the price display in the overview
|
||
card covers the same information without crowding the header */
|
||
.ticker { display: none; }
|
||
}
|