/* ==========================================================================
   ZEUS — "Neon Terminal" design system
   Bloomberg-terminal-meets-cyberpunk: glass panels, neon data, mono numerals.
   No framework, no build step. Fonts are self-hosted (see fonts/, OFL).
   Every animation is gated behind prefers-reduced-motion at the bottom.
   ========================================================================== */

/* ---- fonts ---------------------------------------------------------------- */
@font-face{
  font-family:"Space Grotesk";
  src:url("fonts/SpaceGrotesk-var.0c62a8f36c27.woff2") format("woff2");
  font-weight:300 700; font-display:swap;
}
@font-face{
  font-family:"JetBrains Mono";
  src:url("fonts/JetBrainsMono-Regular.4e0581ae831b.woff2") format("woff2");
  font-weight:400; font-display:swap;
}
@font-face{
  font-family:"JetBrains Mono";
  src:url("fonts/JetBrainsMono-Bold.f3651b6798df.woff2") format("woff2");
  font-weight:700; font-display:swap;
}

/* ---- tokens ---------------------------------------------------------------- */
:root{
  --bg:#030508; --panel:#0a1120; --panel2:#0c1424; --line:#182742;
  --up:#19f0a8; --down:#ff4d6d; --blue:#5b8cff; --violet:#9b6bff; --gold:#ffcf6b;
  --text:#dbe5f2; --muted:#6d7d9c; --dim:#46546f;
  --glass:rgba(12,20,38,.55); --glass2:rgba(8,13,26,.72); --glass-brd:rgba(72,110,190,.28);
  --glow:0 0 22px rgba(91,140,255,.35);
  --glow-up:0 0 20px rgba(25,240,168,.35);
  --glow-down:0 0 18px rgba(255,77,109,.35);
  --r-sm:9px; --r-md:14px; --r-lg:18px;
  --font-display:"Space Grotesk",ui-sans-serif,"Segoe UI",sans-serif;
  --font-mono:"JetBrains Mono",ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  --ease-out:cubic-bezier(.22,1,.36,1);
}
*{box-sizing:border-box}
/* Edge-fade hint lengths for scrollable table cards (see the mobile media
   query). Registered so the scroll-driven animation can interpolate them;
   initial 0px = no fade, which is what non-scrollable cards and browsers
   without animation-timeline get. */
@property --fade-l{syntax:"<length>"; initial-value:0px; inherits:false}
@property --fade-r{syntax:"<length>"; initial-value:0px; inherits:false}

/* ---- cross-document view transitions ---------------------------------------
   Same-origin navigations (Terminal -> Trade -> ...) animate instead of
   hard-flashing: the browser snapshots the old page, swaps, and blends — no
   JS, no SPA. Primary effect: a DIRECTIONAL 200px slide+fade following the
   header-nav order (base.html stamps data-nav fwd/back from the referrer);
   unknown direction (login, refresh, external) plays the lift/rise instead.
   The sticky header gets its own named snapshot group so it stays rock-still
   while only the page content moves. Chrome 126+/Safari 18.2+; Firefox
   (flagged) simply navigates instantly. */
@view-transition{navigation:auto}
header{view-transition-name:zeus-header}
@keyframes vt-lift{to{opacity:0; transform:translateY(-10px)}}
@keyframes vt-rise{from{opacity:0; transform:translateY(10px)}}
::view-transition-old(root){animation:vt-lift .3s var(--ease-out) both}
::view-transition-new(root){animation:vt-rise .3s var(--ease-out) both}
/* Directional slide when base.html stamped data-nav (fwd = rightward in the
   header nav order): only the animation NAME changes — duration/easing come
   from the shorthand above. Direction unknown -> lift/rise fallback. */
@keyframes vt-out-l{to{opacity:0; transform:translateX(-200px)}}
@keyframes vt-in-r{from{opacity:0; transform:translateX(200px)}}
@keyframes vt-out-r{to{opacity:0; transform:translateX(200px)}}
@keyframes vt-in-l{from{opacity:0; transform:translateX(-200px)}}
:root[data-nav="fwd"]::view-transition-old(root){animation-name:vt-out-l}
:root[data-nav="fwd"]::view-transition-new(root){animation-name:vt-in-r}
:root[data-nav="back"]::view-transition-old(root){animation-name:vt-out-r}
:root[data-nav="back"]::view-transition-new(root){animation-name:vt-in-l}

html,body{margin:0}
body{
  font-family:ui-sans-serif,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg); color:var(--text); min-height:100vh; position:relative;
  -webkit-font-smoothing:antialiased; overflow-x:hidden;
}

/* ---- layered animated backdrop: aurora + drifting grid + #fx particles ---- */
body::before{
  content:""; position:fixed; inset:-20%; z-index:-3; pointer-events:none;
  background:
    radial-gradient(50% 40% at 85% 0%, rgba(91,140,255,.20), transparent 60%),
    radial-gradient(45% 45% at 10% 10%, rgba(25,240,168,.13), transparent 55%),
    radial-gradient(50% 50% at 60% 100%, rgba(155,107,255,.12), transparent 60%);
  filter:blur(10px); animation:aurora 26s ease-in-out infinite alternate;
}
@keyframes aurora{
  0%{transform:translate3d(0,0,0) scale(1)}
  50%{transform:translate3d(-3%,2%,0) scale(1.07)}
  100%{transform:translate3d(3%,-2%,0) scale(1.04)}
}
body::after{
  content:""; position:fixed; inset:0; z-index:-2; opacity:.38; pointer-events:none;
  background-image:linear-gradient(rgba(91,140,255,.055) 1px,transparent 1px),
                   linear-gradient(90deg,rgba(91,140,255,.055) 1px,transparent 1px);
  background-size:44px 44px; animation:drift 22s linear infinite;
  mask-image:linear-gradient(180deg,transparent,#000 10%,#000 88%,transparent);
}
@keyframes drift{to{background-position:44px 44px,44px 44px}}
#fx{position:fixed; inset:0; z-index:-1; pointer-events:none; opacity:.5}

::-webkit-scrollbar{width:10px;height:10px}
::-webkit-scrollbar-thumb{background:#1d2c49;border-radius:6px}
::-webkit-scrollbar-thumb:hover{background:#273a60}
::selection{background:rgba(91,140,255,.35)}

.mono{font-family:var(--font-mono); font-variant-numeric:tabular-nums}
/* long details (timestamps, error strings) may break anywhere rather than
   force the table wider than a phone screen */
.wrap{white-space:normal; word-break:break-word; overflow-wrap:anywhere}
/* gateway card: fixed layout so the table can NEVER exceed the card width,
   regardless of device font rendering (iOS made the auto-layout table wider
   than the viewport — the card "faded over the edge") */
.gwtable{table-layout:fixed; width:100%}

/* ---- header ---------------------------------------------------------------- */
header{
  position:sticky; top:0; z-index:20; display:flex; align-items:center; gap:4px;
  padding:.7rem 1.1rem; backdrop-filter:blur(16px) saturate(150%);
  background:linear-gradient(180deg,rgba(6,10,19,.94),rgba(6,10,19,.55));
  border-bottom:1px solid var(--line);
}
header::after{content:"";position:absolute;left:0;right:0;bottom:-1px;height:1px;
  background:linear-gradient(90deg,transparent,rgba(91,140,255,.7),rgba(25,240,168,.7),transparent);
  background-size:200% 100%; animation:scan 6s linear infinite}
@keyframes scan{to{background-position:200% 0}}
.brand{font-family:var(--font-display); font-weight:700; letter-spacing:.6px; font-size:1.22rem; margin-right:1rem;
  background:linear-gradient(90deg,var(--blue),var(--up),var(--violet),var(--blue));
  background-size:300% 100%; -webkit-background-clip:text; background-clip:text;
  color:transparent; text-shadow:var(--glow); white-space:nowrap; animation:hue 8s linear infinite}
@keyframes hue{to{background-position:300% 0}}
nav a{position:relative; color:#aec0dd; text-decoration:none; font-size:.85rem; font-weight:600;
  padding:.45rem .7rem; border-radius:8px; transition:.18s}
nav a::after{content:"";position:absolute;left:.7rem;right:.7rem;bottom:.18rem;height:2px;
  background:linear-gradient(90deg,var(--blue),var(--up));transform:scaleX(0);transform-origin:left;
  transition:transform .22s var(--ease-out); border-radius:2px}
nav a:hover{color:#fff; background:rgba(91,140,255,.10)}
nav a:hover::after{transform:scaleX(1)}
nav a.live::before{content:"●"; color:var(--up); font-size:.6rem; margin-right:.35rem;
  vertical-align:middle; animation:pulse 1.6s ease-in-out infinite; filter:drop-shadow(0 0 4px var(--up))}
@keyframes pulse{0%,100%{opacity:.3}50%{opacity:1}}
.spacer{flex:1}
.who{font-size:.76rem; color:var(--muted); margin-right:.5rem}

/* market-session chip: REGULAR pulses green; PRE/POST gold; CLOSED dim */
.session{display:inline-flex; align-items:center; gap:.4rem; margin-right:.6rem;
  font-family:var(--font-mono); font-size:.66rem; letter-spacing:1.4px; text-transform:uppercase;
  padding:.28rem .6rem; border-radius:999px; border:1px solid var(--line); background:var(--glass2);
  color:var(--muted); white-space:nowrap}
.session .sdot{width:7px;height:7px;border-radius:50%;background:var(--dim)}
.session.regular{color:var(--up); border-color:rgba(25,240,168,.4)}
.session.regular .sdot{background:var(--up); box-shadow:0 0 8px var(--up); animation:pulse 1.6s ease-in-out infinite}
.session.pre,.session.post{color:var(--gold); border-color:rgba(255,207,107,.35)}
.session.pre .sdot,.session.post .sdot{background:var(--gold); box-shadow:0 0 7px rgba(255,207,107,.6)}

.build{font-size:.66rem; color:#8493b3; text-decoration:none; padding:.22rem .6rem;
  border:1px solid var(--line); border-radius:10px; margin-right:.65rem; background:#0b1322;
  display:inline-flex; align-items:center; gap:.4rem; transition:.16s}
.build:hover{border-color:var(--blue); color:#cfe0ff; box-shadow:var(--glow)}
.build .dot{color:var(--up); animation:pulse 1.6s ease-in-out infinite}
.build .bld{display:inline-flex; flex-direction:column; line-height:1.25; text-align:left; max-width:190px}
.build .bld span{overflow:hidden; text-overflow:ellipsis; white-space:nowrap}

/* mobile-only account menu */
.acct-desktop{display:contents}
details.acctMenu{display:none}
.acctMenu summary{list-style:none; cursor:pointer; width:38px; height:38px; border-radius:50%;
  background:linear-gradient(180deg,#1a2742,#121d33); border:1px solid #2b3d63; color:#cfe0ff;
  display:flex; align-items:center; justify-content:center; font-size:.8rem; font-weight:700}
.acctMenu summary::-webkit-details-marker{display:none}
.acctMenu summary::marker{content:""}
.acctMenu[open] summary{border-color:var(--blue); box-shadow:var(--glow)}
.acctPanel{position:absolute; right:0; top:calc(100% + 8px); min-width:190px; z-index:30;
  background:linear-gradient(180deg,#101a2e,#0a1120); border:1px solid #2c4570; border-radius:12px;
  padding:.4rem; box-shadow:0 16px 40px rgba(0,0,0,.5); animation:dpop .2s var(--ease-out) both}
.acctPanel a,.acctPanel button{display:flex; align-items:center; gap:.5rem; width:100%;
  color:var(--text); text-decoration:none; background:none; border:none; text-align:left;
  font-size:.84rem; font-weight:600; padding:.55rem .6rem; border-radius:8px; cursor:pointer}
.acctPanel a:hover,.acctPanel button:hover{background:rgba(91,140,255,.10)}
.acctPanel .acctBuild{font-size:.72rem; color:var(--muted); padding:.4rem .6rem; line-height:1.3}
.acctPanel .divider{height:1px; background:var(--line); margin:.3rem 0}

/* ---- controls ---------------------------------------------------------------- */
button,input,select{font:inherit}
.btn{position:relative; overflow:hidden; background:linear-gradient(180deg,#1a2742,#121d33);
  color:#cfe0ff; border:1px solid #2b3d63; border-radius:var(--r-sm); padding:.5rem .9rem; cursor:pointer;
  font-size:.82rem; font-weight:600; transition:.16s}
.btn:hover{border-color:var(--blue); box-shadow:var(--glow); transform:translateY(-1px)}
.btn::before{content:"";position:absolute;top:0;left:-120%;width:60%;height:100%;
  background:linear-gradient(100deg,transparent,rgba(255,255,255,.18),transparent);transition:left .5s}
.btn:hover::before{left:140%}
.btn.go{background:linear-gradient(180deg,#10b981,#0c8f66); border-color:#16d49a; color:#04130d}
.btn.go:hover{box-shadow:0 0 26px rgba(25,240,168,.55)}
.btn.danger{background:linear-gradient(180deg,#3a1622,#2a0f18);border-color:#5c2333;color:#ffb3c0}
.btn.danger:hover{border-color:var(--down);box-shadow:var(--glow-down)}
.btn.icon{width:2.1rem; height:2.1rem; padding:0; display:inline-flex;
  align-items:center; justify-content:center; line-height:1; flex:none}
.rowacts{display:flex; flex-wrap:wrap; gap:.4rem; justify-content:flex-end; align-items:center}
.rowacts .btn{margin:0; white-space:nowrap}
:is(a,button,input,select,summary):focus-visible{outline:2px solid var(--blue); outline-offset:2px;
  border-radius:6px; box-shadow:var(--glow)}

input[type=text],input[type=password],input[type=number],select{background:#0b1322; color:var(--text); border:1px solid #26375a;
  border-radius:var(--r-sm); padding:.5rem .7rem; transition:.16s}
input[type=number]{font-family:var(--font-mono); font-variant-numeric:tabular-nums}
input[type=text]:focus,input[type=password]:focus,input[type=number]:focus,select:focus{outline:none; border-color:var(--blue); box-shadow:var(--glow)}
form.inline{display:inline-flex; gap:.5rem; flex-wrap:wrap; align-items:center}
code{background:#0b1322; border:1px solid #1c2a44; padding:.05rem .35rem; border-radius:5px;
  font-size:.82em; font-family:var(--font-mono)}
select{cursor:pointer}
input[type=range]{accent-color:var(--blue); vertical-align:middle}
input[type=checkbox]{accent-color:var(--blue); width:16px; height:16px; vertical-align:middle}

/* ---- ticker tape ---------------------------------------------------------------- */
.tape{overflow:hidden; border-bottom:1px solid var(--line); background:rgba(4,7,14,.72);
  position:relative; z-index:5}
.tape::before,.tape::after{content:""; position:absolute; top:0; bottom:0; width:56px; z-index:2; pointer-events:none}
.tape::before{left:0; background:linear-gradient(90deg,var(--bg),transparent)}
.tape::after{right:0; background:linear-gradient(-90deg,var(--bg),transparent)}
.tape .row{display:inline-flex; gap:2.4rem; padding:.44rem 0; white-space:nowrap; animation:scroll 40s linear infinite}
.tape:hover .row{animation-play-state:paused}
.tk{font-size:.8rem; font-weight:700; font-family:var(--font-mono); font-variant-numeric:tabular-nums}
.tk .sym{color:#c8d6ef; margin-right:.45rem; letter-spacing:.5px}
.tk .up{color:var(--up); text-shadow:0 0 10px rgba(25,240,168,.35)}
.tk .down{color:var(--down); text-shadow:0 0 10px rgba(255,77,109,.3)}
.tk .up::before{content:"▲ "} .tk .down::before{content:"▼ "}
@keyframes scroll{to{transform:translateX(-50%)}}

/* ---- layout / typography ---------------------------------------------------------------- */
main{padding:1.4rem; max-width:1180px; margin:0 auto; position:relative; z-index:1}
h1{font-family:var(--font-display); font-size:clamp(1.15rem,2.6vw,1.45rem); font-weight:600;
   letter-spacing:.3px; margin:.2rem 0 1rem}
h2{font-family:var(--font-display); font-size:.92rem; font-weight:600; text-transform:uppercase;
   letter-spacing:2px; color:#9fb6dd; margin:1.8rem 0 .7rem; position:relative; padding-left:.7rem}
h2::before{content:"";position:absolute;left:0;top:.1em;bottom:.1em;width:3px;border-radius:2px;
  background:linear-gradient(180deg,var(--blue),var(--up)); box-shadow:0 0 8px rgba(91,140,255,.5)}
a{color:#7fa6ff}

/* ---- glass cards ---------------------------------------------------------------- */
.card{position:relative; background:linear-gradient(180deg,var(--glass),var(--glass2));
  backdrop-filter:blur(12px) saturate(130%);
  border:1px solid var(--glass-brd); border-radius:var(--r-md); padding:1rem 1.1rem;
  box-shadow:0 10px 30px rgba(0,0,0,.42);
  transition:transform .22s var(--ease-out), box-shadow .22s, border-color .22s;
  animation:rise .55s var(--ease-out) both}
.card::before{content:""; position:absolute; inset:0 0 auto 0; height:1px; border-radius:inherit;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.16),transparent); pointer-events:none}
.card:hover{transform:translateY(-3px); border-color:#33507f;
  box-shadow:0 18px 48px rgba(0,0,0,.55),var(--glow)}
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.grid{display:grid; grid-template-columns:repeat(auto-fit,minmax(170px,1fr)); gap:.9rem}
.grid .card:nth-child(2){animation-delay:.05s}.grid .card:nth-child(3){animation-delay:.1s}
.grid .card:nth-child(4){animation-delay:.15s}.grid .card:nth-child(5){animation-delay:.2s}
.grid .card:nth-child(6){animation-delay:.25s}

/* hero recommendation card: richer gradient + slow ambient sheen */
.card.hero{border-color:#2a3a5e; overflow:hidden;
  background:linear-gradient(135deg,rgba(91,140,255,.16),rgba(25,240,168,.06)),
             linear-gradient(180deg,var(--glass),var(--glass2))}
.card.hero::after{content:""; position:absolute; inset:-60% -30%; pointer-events:none;
  background:conic-gradient(from 180deg,transparent 60%,rgba(91,140,255,.10),rgba(25,240,168,.08),transparent 90%);
  animation:herospin 14s linear infinite}
@keyframes herospin{to{transform:rotate(1turn)}}
.card.hero > *{position:relative; z-index:1}
.rec-headline{font-family:var(--font-display); font-size:clamp(1.15rem,2.4vw,1.5rem); font-weight:700;
  margin:.5rem 0 .2rem; color:#fff}
.rec-headline .hl{color:var(--up); text-shadow:0 0 16px rgba(25,240,168,.35)}
.rec-sub{color:var(--muted); font-size:.9rem}
.card.tight{padding:.4rem .6rem}
.card.sub{margin-top:1rem; background:#0b1120; backdrop-filter:none}
.kpi-grid{margin-top:1rem; grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}
.kpi.pad{padding:.7rem .9rem}
.kpi .v.small{font-size:1.15rem}
.footnote{color:var(--dim); font-size:.78rem; margin-top:.4rem}

.kpi .k{font-size:.68rem; letter-spacing:1.6px; text-transform:uppercase; color:var(--muted)}
.kpi .v{font-family:var(--font-mono); font-size:1.7rem; font-weight:700; margin-top:.25rem;
  font-variant-numeric:tabular-nums}
.kpi .v.green{color:var(--up); text-shadow:0 0 18px rgba(25,240,168,.4)}
.kpi .v.blue{color:var(--blue); text-shadow:0 0 18px rgba(91,140,255,.4)}

/* ---- tables ---------------------------------------------------------------- */
table{width:100%; border-collapse:collapse; font-size:.84rem}
th{position:sticky; top:0; text-align:left; color:#8fa2c6; font-size:.66rem; letter-spacing:1.2px;
  text-transform:uppercase; padding:.55rem .6rem; border-bottom:1px solid #26375a;
  background:rgba(10,17,32,.92); backdrop-filter:blur(8px); z-index:1;
  font-family:var(--font-display); font-weight:600}
td{padding:.5rem .6rem; border-bottom:1px solid #141f38}
tbody tr{transition:background .15s; position:relative}
tbody tr:hover td{background:rgba(91,140,255,.07)}
tbody tr:hover td:first-child{box-shadow:inset 3px 0 0 var(--blue)}
.num{font-family:var(--font-mono); font-variant-numeric:tabular-nums}
.pos{color:var(--up); font-weight:700; font-family:var(--font-mono); font-variant-numeric:tabular-nums}
.neg{color:var(--down); font-weight:700; font-family:var(--font-mono); font-variant-numeric:tabular-nums}
/* one-shot live-tape flash on load (zeus.js adds .zflash to body) */
.zflash .pos{animation:flashUp 1.1s var(--ease-out) 1}
.zflash .neg{animation:flashDown 1.1s var(--ease-out) 1}
@keyframes flashUp{0%{background:rgba(25,240,168,.28); box-shadow:0 0 14px rgba(25,240,168,.28)}100%{background:transparent}}
@keyframes flashDown{0%{background:rgba(255,77,109,.24); box-shadow:0 0 12px rgba(255,77,109,.24)}100%{background:transparent}}

.pill{display:inline-block; padding:.08rem .5rem; border-radius:999px; font-size:.68rem; font-weight:700;
  font-family:var(--font-mono)}
.pill.ok{background:rgba(25,240,168,.14); color:var(--up); border:1px solid rgba(25,240,168,.4);
  box-shadow:0 0 10px rgba(25,240,168,.18)}
.pill.no{background:rgba(255,77,109,.12); color:var(--down); border:1px solid rgba(255,77,109,.35)}
.pill.info{background:rgba(91,140,255,.14); color:var(--blue); border:1px solid rgba(91,140,255,.4)}
.pill.gold{background:rgba(255,207,107,.14); color:var(--gold); border:1px solid rgba(255,207,107,.4)}

/* news page: symbol headline + ticker-metadata popover (native <details>) */
.newsym{font-weight:700; font-size:1.05rem; letter-spacing:.5px; color:#fff;
  text-shadow:0 0 12px rgba(91,140,255,.35)}
.tickmeta{display:inline-block; position:relative}
.tickmeta summary{list-style:none; cursor:pointer; color:var(--muted); font-size:.85rem; padding:0 .15rem}
.tickmeta summary::-webkit-details-marker{display:none}
.tickmeta[open] summary{color:var(--blue)}
.tickmeta .panel{position:absolute; left:0; top:1.4rem; z-index:5; min-width:230px;
  background:#131b2e; border:1px solid #2a3346; border-radius:8px; padding:.55rem .7rem;
  font-size:.78rem; box-shadow:0 6px 18px rgba(0,0,0,.45); animation:dpop .2s var(--ease-out) both}
.tickmeta .panel div{display:flex; justify-content:space-between; gap:1rem; padding:.12rem 0}
.tickmeta .panel .k{color:var(--muted)}
.pagehead{display:flex; align-items:center; gap:.8rem; flex-wrap:wrap}
.pagehead h1{margin-bottom:0}
.scrolly{max-height:60vh; overflow-y:auto}

/* empty states */
.empty{color:var(--muted); font-size:.85rem; padding:1.1rem .4rem; text-align:center}
.empty::before{content:"◇ "; color:var(--dim)}

/* recurring form/table utilities (replace per-template inline styles) */
.chk{display:flex; align-items:center; gap:.5rem}
.frow{display:flex; align-items:center; gap:.5rem}
.frow > :first-child{flex:1}
.vform{display:flex; flex-direction:column; gap:.7rem}
.vlabel input{display:block; margin-top:.4rem}
.full{width:100%}
td.sym{font-family:var(--font-mono); font-weight:700; letter-spacing:.4px}
td.tmuted{font-family:var(--font-mono); color:var(--muted); font-variant-numeric:tabular-nums}
.pill.dim{background:rgba(93,107,134,.15); color:var(--muted); border:1px solid rgba(93,107,134,.4)}

/* trade page: summary scope chips (Today / 7d / All) */
.shead{display:flex; align-items:center; gap:.9rem; margin:1.6rem 0 .7rem; flex-wrap:wrap}
.shead h2{margin:0}
.chips{display:flex; align-items:center; gap:.35rem; flex-wrap:wrap}
.chips a.pill{text-decoration:none; cursor:pointer}
.chips a.pill.dim:hover{color:var(--blue); border-color:rgba(91,140,255,.4)}
/* 2×2 always — auto-fit made a 3+1 orphan row on narrow screens */
#summaryCards{grid-template-columns:1fr 1fr}
/* popover text must not inherit the KPI label's uppercase styling */
.tickmeta .panel{text-transform:none; letter-spacing:normal; font-weight:400}
/* the commissions ⓘ sits in the grid's right column — grow the panel leftward
   and cap its width so it can't run off a phone screen */
#summaryCards .tickmeta .panel{left:auto; right:0; min-width:0; width:max-content;
  max-width:min(240px, 60vw)}
/* "NET P&L ⇄" must not wrap in the narrow table column — the table already
   scrolls horizontally on small screens */
th.pnl-toggle{white-space:nowrap}
.grid.g130{grid-template-columns:repeat(auto-fit,minmax(130px,1fr))}
.grid.g300{grid-template-columns:repeat(auto-fit,minmax(300px,1fr)); align-items:start}
.note{color:var(--muted); font-size:.82rem; margin:.5rem 0 0}
.note.none{margin:0}

/* ---- flash messages ---------------------------------------------------------------- */
.msgs{margin:0 0 1rem; padding:0; list-style:none; display:flex; flex-direction:column; gap:.5rem}
.msg{padding:.55rem .8rem; border-radius:10px; font-size:.82rem; border:1px solid var(--line);
  background:#0c1322; animation:rise .35s var(--ease-out) both}
.msg.success{border-color:rgba(25,240,168,.4); color:var(--up); background:rgba(25,240,168,.08)}
.msg.error{border-color:rgba(255,77,109,.4); color:#ffb3c0; background:rgba(255,77,109,.08)}
.msg.info{border-color:rgba(91,140,255,.4); color:#bcd0ff; background:rgba(91,140,255,.08)}

/* ---- dialogs ----------------------------------------------------------------
   Open/close are transition-driven (not keyframes): @starting-style supplies
   the entry "from" state, and `display`/`overlay` with allow-discrete keep the
   dialog (and its ::backdrop) rendered while the EXIT transition plays — the
   part keyframes could never do; closing used to snap. Supported Chrome 117+/
   Safari 17.4+/Firefox 129+.
   Dialogs grow out of the TAP POINT: zeus.js aims transform-origin at the
   last pointerdown right after showModal(), so the scale below expands from
   under the finger. Keyboard opens keep the default center origin.
   Closing plays the same animation REVERSED: WebKit (no `overlay` support)
   drops a closed dialog from the top layer instantly, so zeus.js first adds
   .closing (the mirror state below), lets the transition play, and only then
   calls the native close(). Keep .closing AFTER [open]: equal specificity,
   order decides. Durations here and DUR in zeus.js move together. */
dialog{background:linear-gradient(180deg,#101a2e,#0a1120); color:var(--text);
  border:1px solid #2c4570; border-radius:var(--r-md); padding:0; width:min(560px,94vw);
  box-shadow:0 24px 70px rgba(0,0,0,.6),var(--glow);
  opacity:0; transform:scale(.25);
  transition:opacity .5s ease, transform .5s var(--ease-out),
             overlay .5s allow-discrete, display .5s allow-discrete}
dialog[open]{opacity:1; transform:none}
@starting-style{dialog[open]{opacity:0; transform:scale(.25)}}
dialog.closing{opacity:0; transform:scale(.25)}
dialog::backdrop{background:rgba(2,4,9,0); backdrop-filter:blur(0px);
  transition:background .5s ease, backdrop-filter .5s ease,
             overlay .5s allow-discrete, display .5s allow-discrete}
dialog[open]::backdrop{background:rgba(2,4,9,.7); backdrop-filter:blur(4px)}
@starting-style{dialog[open]::backdrop{background:rgba(2,4,9,0); backdrop-filter:blur(0px)}}
dialog.closing::backdrop{background:rgba(2,4,9,0); backdrop-filter:blur(0px)}
dialog .dhead,dialog .dbody,dialog .dfoot{padding:.9rem 1.1rem}
dialog .dhead{border-bottom:1px solid var(--line); font-family:var(--font-display)}
dialog .dfoot{border-top:1px solid var(--line); display:flex; gap:.6rem; align-items:center; justify-content:flex-end}
.hlist{list-style:none; margin:.4rem 0 0; padding:0; max-height:46vh; overflow:auto}
.hrow{display:flex; align-items:center; gap:.6rem; padding:.35rem .15rem; border-bottom:1px solid #15203a;
  overflow:hidden; transition:max-height .28s ease,opacity .28s ease,padding .28s ease; max-height:46px; opacity:1}
.hrow.out{max-height:0; opacity:0; padding-top:0; padding-bottom:0; border-bottom:0}
.hrow .rank{color:var(--muted); width:1.6rem; text-align:right; font-size:.74rem; font-family:var(--font-mono)}
.hrow .sym{font-weight:700; font-family:var(--font-mono)}
.hrow .nm{color:var(--muted); flex:1; min-width:0; white-space:nowrap;
  overflow:hidden; text-overflow:ellipsis; font-size:.78rem}
.hrow .wt{font-variant-numeric:tabular-nums; color:#bcd0ff; font-size:.78rem; font-family:var(--font-mono)}
.hrow .dup{font-size:.62rem; color:var(--gold)}

/* ---- charts (SVG from core/charts.py; hooks are web-only, PDFs ignore) -------
   Bars grow away from the zero line: gains (zup) scale from their own bottom
   (which sits on the baseline), losses (zdn) from their top. transform-box
   makes transform-origin relative to each rect, not the whole SVG. */
.zspark .zline{stroke-dasharray:300; stroke-dashoffset:300; animation:sparkdraw 1.1s var(--ease-out) .15s forwards}
@keyframes sparkdraw{to{stroke-dashoffset:0}}
.zbar .zgrow{transform-box:fill-box; transform:scaleY(0); animation:bargrow .55s var(--ease-out) forwards}
.zbar .zgrow.zup{transform-origin:center bottom}
.zbar .zgrow.zdn{transform-origin:center top}
.zbar .zgrow:nth-of-type(2n){animation-delay:.06s}
.zbar .zgrow:nth-of-type(3n){animation-delay:.12s}
@keyframes bargrow{to{transform:scaleY(1)}}

/* ---- auth pages (login / 2FA) ---------------------------------------------- */
body.auth{display:grid; place-items:center; padding:1.2rem; overflow:hidden}
.auth .panel{position:relative; background:linear-gradient(180deg,var(--glass),var(--glass2));
  backdrop-filter:blur(14px) saturate(130%);
  border:1px solid var(--glass-brd); border-radius:var(--r-lg); padding:2rem 1.8rem; width:min(420px,100%);
  box-shadow:0 24px 70px rgba(0,0,0,.55),0 0 40px rgba(91,140,255,.12);
  animation:rise .55s var(--ease-out) both}
.auth .panel::before{content:""; position:absolute; inset:0 0 auto 0; height:1px;
  background:linear-gradient(90deg,transparent,rgba(255,255,255,.18),transparent)}
.auth .brand{font-size:1.5rem; margin:0 0 .15rem}
.auth .sub{color:var(--muted); font-size:.72rem; letter-spacing:3px; text-transform:uppercase; margin-bottom:1.2rem;
  font-family:var(--font-mono)}
.auth label{display:block; font-size:.72rem; letter-spacing:1px; text-transform:uppercase; color:#8fa2c6; margin:.9rem 0 .3rem}
.auth input[type=text],.auth input[type=password]{width:100%; background:#0b1322; color:var(--text);
  border:1px solid #26375a; border-radius:var(--r-sm); padding:.6rem .7rem; font-size:1.1rem;
  letter-spacing:.25rem; text-align:center; font-family:var(--font-mono); transition:.16s}
.auth input:focus{outline:none; border-color:var(--blue); box-shadow:0 0 22px rgba(91,140,255,.3)}
.auth button,.auth .btnlink{margin-top:1.2rem; width:100%; display:block; text-align:center; text-decoration:none;
  cursor:pointer; font-weight:800; letter-spacing:.5px; background:linear-gradient(180deg,#10b981,#0c8f66);
  color:#04130d; border:1px solid #16d49a; border-radius:10px; padding:.7rem; font-size:.95rem; transition:.16s}
.auth button:hover,.auth .btnlink:hover{box-shadow:0 0 26px rgba(25,240,168,.5); transform:translateY(-1px)}
.auth .err{color:var(--down); font-size:.8rem; margin-top:.8rem}
.auth .hint{color:var(--muted); font-size:.8rem; margin:.6rem 0 0; line-height:1.5}
/* login form (.lform): plain left-aligned inputs, unlike the centered TOTP field */
.auth .lform input[type=text],.auth .lform input[type=password]{
  letter-spacing:normal; text-align:left; font-size:.95rem; font-family:inherit}
.pw-wrap{position:relative}
.pw-wrap input{padding-right:2.6rem; width:100%}
/* .pw-wrap .eye (0,2,0) — must OUT-SPECIFY .auth button (0,1,1): a bare .eye
   loses and the login page's eye renders as the giant green submit button
   (regression shipped 2026-07-10 when these were unscoped from .auth). */
.pw-wrap .eye{position:absolute; top:0; right:0; height:100%; width:auto; margin:0; padding:0 .6rem;
  display:flex; align-items:center; background:none; border:none; border-radius:0; box-shadow:none;
  color:#5b7099; cursor:pointer; transition:color .16s,filter .16s}
.pw-wrap .eye:hover{background:none; box-shadow:none; transform:none; color:var(--blue);
  filter:drop-shadow(0 0 6px rgba(91,140,255,.7))}
.pw-wrap .eye svg{display:block}
.auth .qr{background:#fff; border-radius:14px; padding:.7rem; width:208px; height:208px; margin:.6rem auto; display:flex;
  border:1px solid #2c4570; box-shadow:0 0 0 4px rgba(91,140,255,.10),0 10px 30px rgba(0,0,0,.45),0 0 22px rgba(91,140,255,.22)}
.auth .qr svg{width:100%; height:100%; display:block}
.secret{font-family:var(--font-mono); font-size:.8rem; color:#bcd0ff; word-break:break-all;
  background:#0b1322; border:1px solid #1c2a44; border-radius:8px; padding:.45rem .55rem; text-align:center}
.codes{list-style:none; padding:0; margin:.7rem 0 0; display:grid; grid-template-columns:1fr 1fr; gap:.4rem}
.codes li{font-family:var(--font-mono); background:#0b1322; border:1px solid #1c2a44; border-radius:8px;
  padding:.45rem; text-align:center; letter-spacing:.08rem; color:#cfe0ff}

/* ---- mobile / narrow ---------------------------------------------------------- */
@media (max-width: 680px){
  /* Sticky blurred table headers over long tables are a mobile-WebKit
     GPU/memory killer (Safari "a problem repeatedly occurred", 2026-07-10).
     Near-opaque background replaces the blur; desktop keeps it. */
  th{backdrop-filter:none; background:rgba(10,17,32,.97)}
  header{flex-wrap:wrap; gap:.35rem .5rem; padding:.55rem .7rem; backdrop-filter:blur(10px)}
  .brand{font-size:1.05rem; margin-right:.3rem}
  .spacer{display:none}
  .session{margin-left:auto; margin-right:.4rem}
  nav{order:3; width:100%; display:flex; gap:6px; padding-top:2px;
      overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none}
  nav::-webkit-scrollbar{display:none}
  nav a{flex:1 0 auto; text-align:center; white-space:nowrap; font-size:.8rem; padding:.6rem .55rem;
        min-height:44px; display:inline-flex; align-items:center; justify-content:center;
        border:1px solid var(--line); border-radius:9px; background:rgba(91,140,255,.05)}
  nav a::after{display:none}
  nav a:hover{background:rgba(91,140,255,.12)}

  .acct-desktop{display:none}
  details.acctMenu{display:inline-block; position:relative}

  main{padding:1rem .8rem}
  h1{font-size:1.15rem}
  h2{font-size:.82rem; margin:1.3rem 0 .6rem}

  /* Wide tables scroll within their card; edge fades hint at off-screen
     content, driven PURELY by scroll position (CSS scroll-driven animation,
     Safari 26+/Chrome 115+ — Firefox degrades to no fade). Semantics:
       - table fits          -> timeline inactive -> vars stay 0px -> no mask
       - scrolled from start -> left fade ramps IN over the first 80px
       - approaching the end -> right fade ramps OUT over the last 80px
         (raw distance, not % — constant ramp even on barely-overflowing
         tables, so the edge reveal never pops)
     fill:both holds each ramp's from/to value outside its range, keeping
     fades at full strength through the middle of the scroll. */
  .card:has(> table){
    overflow-x:auto; -webkit-overflow-scrolling:touch;
    mask-image:linear-gradient(90deg, transparent, #000 var(--fade-l),
               #000 calc(100% - var(--fade-r)), transparent);
    animation:edge-hint-l linear both, edge-hint-r linear both;
    animation-timeline:scroll(self inline), scroll(self inline);
    animation-range:0 80px, calc(100% - 80px) 100%;
  }
  @keyframes edge-hint-l{from{--fade-l:0px}  to{--fade-l:28px}}
  @keyframes edge-hint-r{from{--fade-r:28px} to{--fade-r:0px}}
  table{font-size:.8rem}
  th{position:static}
  td,th{padding:.55rem .55rem}
  .btn{min-height:44px}
  .btn.icon{width:44px; height:44px}  /* keep the touch target square, not a tall pill */

  /* glass blur is the one costly effect on weak GPUs -- tone it down */
  .card{backdrop-filter:none; background:linear-gradient(180deg,rgba(13,21,39,.94),rgba(8,13,26,.92))}

  .grid{grid-template-columns:repeat(auto-fit,minmax(135px,1fr)); gap:.6rem}
  .kpi .v{font-size:1.45rem}
  dialog{width:min(560px,96vw)}
  form.inline{width:100%}
  form.inline input[type=text]{flex:1 1 60%}
}
@media (max-width: 480px){
  .grid{grid-template-columns:1fr 1fr}
}

/* ---- reduced motion: kill every animation ---------------------------------- */

/* --- P&L unit toggle (trade page): click the card/column to flip % <-> $ --- */
.pnl-toggle{cursor:pointer; user-select:none}
.pnl-swap{display:inline-block; transition:transform .13s ease-in; transform-origin:50% 50%; backface-visibility:hidden}
.pnl-swap.flipping{transform:rotateX(90deg)}

@media (prefers-reduced-motion: reduce){
  *,*::before,*::after{animation:none!important; transition:none!important}
  /* the * selectors above don't match view-transition pseudos — gate the
     page cross-fade explicitly so navigation is instant under reduced motion */
  ::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}
  .zspark .zline{stroke-dasharray:none; stroke-dashoffset:0}
  .zbar .zgrow{transform:none}
}
