/* ============================================================
   Edge — Trading Journal · Apple-grade dashboard
   ============================================================ */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

:root {
  /* Surfaces */
  --bg: #F3F4F6;
  --bg-grain: #F2F2F4;
  --surface: #FFFFFF;
  --surface-soft: #FAFAFB;
  --surface-sunken: #F0F0F2;
  --surface-elevated: rgba(255, 255, 255, 0.82);
  --surface-veil: rgba(255, 255, 255, 0.58);

  /* Borders */
  --border: rgba(0, 0, 0, 0.06);
  --border-strong: rgba(0, 0, 0, 0.10);
  --border-hair: rgba(0, 0, 0, 0.04);

  /* Text */
  --text: #1D1D1F;
  --text-2: #515154;
  --text-3: #86868B;
  --text-4: #B6B6BB;

  /* Semantic — positive uses Apple's light blue / sky as requested */
  --pos: #1298D8;
  --pos-light: #5CC8FF;
  --mint: #38C99A;
  --violet: #7C68EE;
  --pos-soft: rgba(10, 132, 255, 0.10);
  --pos-soft-2: rgba(90, 200, 250, 0.16);
  --pos-bg: linear-gradient(135deg, rgba(92, 200, 255, 0.24) 0%, rgba(56, 201, 154, 0.14) 62%, rgba(124, 104, 238, 0.10) 100%);

  /* Semantic — negative dark red */
  --neg: #B91C1C;
  --neg-deep: #7F1D1D;
  --neg-soft: rgba(185, 28, 28, 0.10);
  --neg-bg: linear-gradient(135deg, rgba(185, 28, 28, 0.10) 0%, rgba(127, 29, 29, 0.05) 100%);

  /* Neutral accents */
  --accent: #0071E3;
  --warn: #FF9F0A;
  --purple: var(--violet);

  /* Shadows — sharp, premium */
  --shadow-1: 0 1px 1px rgba(15, 17, 21, 0.035), 0 1px 2px rgba(15, 17, 21, 0.035);
  --shadow-2: 0 1px 2px rgba(15, 17, 21, 0.04), 0 8px 22px rgba(15, 17, 21, 0.045);
  --shadow-3: 0 2px 6px rgba(15, 17, 21, 0.045), 0 18px 44px rgba(15, 17, 21, 0.075);
  --shadow-hover: 0 2px 6px rgba(15, 17, 21, 0.06), 0 24px 58px rgba(15, 17, 21, 0.10);
  --shadow-focus: 0 0 0 1px rgba(92, 200, 255, 0.16), 0 0 0 4px rgba(92, 200, 255, 0.10);

  /* Radii */
  --r-sm: 8px;
  --r-md: 13px;
  --r-lg: 16px;
  --r-xl: 20px;

  /* Dashboard spacing scale — single source for the grid/card rhythm so the
     whole dashboard breathes from one set of tokens (the bottom cards reclaim
     a touch of run for the extra Recent Trades row without ever scrolling the
     page). */
  --dash-gap-row: 10px;
  --dash-card-pad-y: 12px;
  --dash-card-pad-x: 14px;
  --dash-gap-tight: 8px;
  --dash-gap-stack: 6px;

  /* Content measure — the single module width every page (and the topbar) is
     centred within on large screens. A PROGRESSIVE clamp instead of a hard cap so
     the measure adapts across desktop sizes rather than freezing at one ceiling:
       • floor 1760px  — laptops (≤1760px viewport) are non-binding here (the stage
         is bounded by viewport−40px first), so 13"–15" stays edge-to-edge unchanged.
       • ramp 792px+55vw — crosses 1760 exactly at a 1760px viewport, then grows with
         the screen so 1080p sits near-full and QHD reclaims its width instead of
         leaving ~800px dead (the "normal desktop feels boxed-in" case).
       • ceiling 2200px — hit at a 2560px viewport; QHD lands here and ultrawides stay
         CONTAINED for readability instead of stretching edge-to-edge.
     Monotonic vs the old fixed 1760: every viewport gets ≥ the old width, more on
     desktops — so no laptop regression and ultrawide protection is preserved. */
  --content-max: clamp(1760px, calc(792px + 55vw), 2200px);

  /* Type */
  --font: 'Inter', -apple-system, BlinkMacSystemFont, "SF Pro Display", "SF Pro Text", system-ui, sans-serif;
  --mono: 'JetBrains Mono', ui-monospace, "SF Mono", Menlo, monospace;

  /* Easing — ONE motion language. Four intentional curves, used consistently:
       --ease-out        snappy decelerate for small/fast UI (hovers, buttons, toggles)
       --ease-emphasized calmer decelerate for larger surfaces (modals, trays, panels)
       --ease-in-out     symmetric, for moves that travel and settle
       --page-reveal-ease the page-level reveal (below) */
  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  --ease-emphasized: cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* Page transition — single source of truth for the cross-page reveal timing.
     The incoming page sweeps in from the top while the outgoing page is hidden
     instantly underneath it (no bleed-through). Tune the feel from here only.
     `--page-reveal-ease` is a smooth ease-out-cubic: distributed deceleration so
     the downward slide is *watched* the whole way in (an ease-out-expo here was
     ~93% travelled before the fade finished, so the reveal read as an instant
     snap — the exact "there is no transition" complaint we are fixing). */
  --page-transition-duration: 260ms;
  --page-reveal-ease: cubic-bezier(0.33, 1, 0.68, 1);

  /* Chart-only theme values — drive Chart.js tick / grid colors so they
     adapt with the rest of the system. Component-level CSS uses the regular
     surface tokens. */
  --chart-axis: rgba(120, 128, 142, 0.85);
  --chart-grid: rgba(20, 26, 36, 0.06);
  --sidebar-bg-top: rgba(255, 255, 255, 0.85);
  --sidebar-bg-bot: rgba(245, 245, 247, 0.6);
}

/* Page-transition speed hooks (read by the .page enter/leave animations below).
   These only retune --page-transition-duration; the motion design is unchanged.
     • [data-fast-anim]      → the snappy, clearly-visible 190ms top-to-bottom
                               reveal. Set when the Settings "page animations"
                               toggle is ON (its default), so out of the box the
                               transition is plainly perceptible yet fast. NOTE:
                               this is the EFFECTIVE out-of-box duration — the
                               :root base (260ms) only applies before settings
                               run or if neither hook is set.
     • .reduced-page-motion  → near-instant (toggled when that setting is OFF, for
                               a deliberately static, no-motion feel).
     • prefers-reduced-motion → near-instant, OS-level. */
:root[data-fast-anim] { --page-transition-duration: 190ms; }
:root.reduced-page-motion { --page-transition-duration: 1ms; }

/* Instant theme swap. While <html> carries .theme-swapping, EVERY transition is
   killed so flipping the palette (light ↔ dark ↔ grey) doesn't fire a
   hundreds-of-elements colour/shadow transition all at once — that simultaneous
   repaint was the theme-switch "lag". applyTheme adds this for the flip and
   removes it on the next frame, so normal hover/UI transitions are unaffected. */
:root.theme-swapping,
:root.theme-swapping *,
:root.theme-swapping *::before,
:root.theme-swapping *::after {
  transition: none !important;
}

:root[data-theme="dark"] {
  /* Material ladder — a deliberately stepped luminance scale so each level reads
     as a distinct surface above the one below (deeper floor → cards float →
     wells recess → modals sit highest). The big lever on a near-black UI is the
     floor: dropping --bg well below the card surface is what gives the depth,
     rather than brightening the cards (which would grey-wash the whole app). */
  --bg: #08090C;            /* floor — deepest, so cards visibly lift off it */
  --bg-grain: #0B0E13;
  --surface: #161A21;       /* cards — clearly above the floor */
  --surface-soft: #1C212B;  /* hover / elevated step above a card */
  --surface-sunken: #0D1015;/* recessed wells (table bodies, inputs) — below cards */
  --surface-elevated: rgba(31, 37, 47, 0.93);  /* popovers / menus — highest, opaque */
  --surface-veil: rgba(24, 28, 36, 0.62);

  /* Slightly firmer hairlines so a card edge reads against the deeper floor
     without resorting to heavy borders. */
  --border: rgba(255, 255, 255, 0.10);
  --border-strong: rgba(255, 255, 255, 0.16);
  --border-hair: rgba(255, 255, 255, 0.06);

  --text: #ECEEF2;
  --text-2: #B5BAC4;
  --text-3: #767D88;
  --text-4: #4A5059;

  /* Accents stay legible on dark — slightly brighter blues, less saturated red */
  --pos: #5CC8FF;
  --pos-light: #93DFFF;
  --mint: #4FE2A8;
  --violet: #A691F5;
  --pos-soft: rgba(92, 200, 255, 0.16);
  --pos-soft-2: rgba(92, 200, 255, 0.22);
  --pos-bg: linear-gradient(135deg, rgba(92, 200, 255, 0.18) 0%, rgba(79, 226, 168, 0.10) 62%, rgba(166, 145, 245, 0.08) 100%);

  --neg: #FF6B6B;
  --neg-deep: #D04A4A;
  --neg-soft: rgba(255, 107, 107, 0.16);
  --neg-bg: linear-gradient(135deg, rgba(255, 107, 107, 0.12) 0%, rgba(208, 74, 74, 0.06) 100%);

  --shadow-1: 0 1px 1px rgba(0, 0, 0, 0.28), 0 1px 2px rgba(0, 0, 0, 0.22);
  --shadow-2: 0 1px 2px rgba(0, 0, 0, 0.28), 0 10px 28px rgba(0, 0, 0, 0.30);
  --shadow-3: 0 2px 6px rgba(0, 0, 0, 0.32), 0 22px 56px rgba(0, 0, 0, 0.42);
  --shadow-hover: 0 4px 10px rgba(0, 0, 0, 0.34), 0 30px 72px rgba(0, 0, 0, 0.50);
  --shadow-focus: 0 0 0 1px rgba(92, 200, 255, 0.22), 0 0 0 4px rgba(92, 200, 255, 0.12);

  --chart-axis: rgba(150, 158, 172, 0.78);
  --chart-grid: rgba(255, 255, 255, 0.05);
  --sidebar-bg-top: rgba(20, 23, 29, 0.85);
  --sidebar-bg-bot: rgba(11, 13, 17, 0.6);
}

:root[data-theme="dark"] body::before {
  background:
    radial-gradient(circle at 52% -10%, rgba(92, 200, 255, 0.10), transparent 34%),
    radial-gradient(circle at 82% 4%, rgba(166, 145, 245, 0.06), transparent 28%),
    linear-gradient(180deg, rgba(28, 34, 46, 0.58) 0%, rgba(11, 13, 17, 0.42) 230px, rgba(11, 13, 17, 0) 520px);
}

/* GREY ("dim") theme — a third shade. It is a member of the dark FAMILY: it keeps
   data-theme="dark" (so every dark component rule + JS `dataset.theme === 'dark'`
   check applies, and the accents/shadows/chart tokens are inherited), and only
   overrides the PALETTE tokens to a neutral slate grey. Set together with
   data-shade="grey" by applyResolvedTheme(). The same stepped material ladder as
   dark (floor → wells → cards → soft), just lighter and greyer. */
:root[data-shade="grey"] {
  --bg: #22262E;
  --bg-grain: #272B33;
  --surface: #2F343D;
  --surface-soft: #3A3F49;
  --surface-sunken: #292E36;
  --surface-elevated: rgba(70, 76, 87, 0.96);
  --surface-veil: rgba(50, 55, 63, 0.64);

  --border: rgba(255, 255, 255, 0.12);
  --border-strong: rgba(255, 255, 255, 0.18);
  --border-hair: rgba(255, 255, 255, 0.07);

  --sidebar-bg-top: rgba(58, 63, 73, 0.85);
  --sidebar-bg-bot: rgba(34, 38, 46, 0.6);
}
/* Grey gets its own ambient wash — the dark one dips to near-black ~230px down,
   which would print a dark band across the lighter grey floor. */
:root[data-shade="grey"] body::before {
  background:
    radial-gradient(circle at 52% -10%, rgba(92, 200, 255, 0.07), transparent 34%),
    radial-gradient(circle at 82% 4%, rgba(166, 145, 245, 0.05), transparent 28%),
    linear-gradient(180deg, rgba(80, 86, 98, 0.40) 0%, rgba(34, 38, 46, 0) 360px);
}

html, body {
  height: 100%;
}

body {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 400;
  color: var(--text);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: "cv11", "ss01", "ss03", "calt";
  letter-spacing: 0;
  overflow: hidden;
}

.kpi-value,
.chart-hero-amount,
.chart-hero-currency,
.chart-hero-sign,
.tp-overview-card strong,
.tp-pnl-cell,
.tp-r-cell,
.perf-score-card strong,
.perf-diag-table td.num,
.perf-diag-bar-row strong,
.perf-diag-metrics strong,
.perf-execution-strip strong,
.settings-input {
  font-feature-settings: "tnum" 1, "ss01" 1, "cv11" 1;
  font-variant-numeric: tabular-nums;
}

/* Subtle neutral lift from top */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background:
    radial-gradient(circle at 50% -12%, rgba(92, 200, 255, 0.14), transparent 32%),
    linear-gradient(180deg, rgba(226, 232, 240, 0.78) 0%, rgba(243, 244, 246, 0.72) 230px, rgba(243, 244, 246, 0) 520px);
  pointer-events: none;
  z-index: 0;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
  user-select: none;
}

a { color: inherit; text-decoration: none; -webkit-tap-highlight-color: transparent; user-select: none; }

/* ============================================================
   Layout
   ============================================================ */

.app {
  position: relative;
  display: block;
  min-height: 100vh;
  z-index: 1;
}

/* ============================================================
   Top hover navigation
   ============================================================ */

.top-nav {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 80;
  width: 100%;
  height: 82px;
  display: flex;
  flex-direction: column;
  align-items: center;
  pointer-events: none;
}

.top-nav-trigger {
  position: absolute;
  top: 12px;
  left: 50%;
  z-index: 2;
  width: 118px;
  height: 34px;
  display: inline-grid;
  place-items: center;
  gap: 4px;
  transform: translateX(-50%);
  pointer-events: auto;
  border: 1px solid var(--border);
  border-radius: 999px;
  color: var(--text-2);
  /* Opaque surface (no backdrop-filter): this pill is fixed, animates on open
     and transitions box-shadow — blurring the backdrop behind it every frame
     was pure GPU cost for no visible gain over a solid fill. */
  background: var(--surface);
  box-shadow: var(--shadow-2);
  transition: opacity 180ms var(--ease-out), transform 220ms var(--ease-out), box-shadow 220ms var(--ease-out), color 220ms var(--ease-out);
}

.top-nav-trigger span {
  width: 76px;
  height: 2px;
  border-radius: 999px;
  background: currentColor;
  opacity: 0.72;
  transition: width 220ms var(--ease-out), opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}

.top-nav.is-open .top-nav-trigger,
.top-nav:focus-within .top-nav-trigger {
  color: var(--text);
  opacity: 0;
  transform: translateX(-50%);
  box-shadow: var(--shadow-3);
}

.top-nav.is-open .top-nav-trigger span:nth-child(1),
.top-nav:focus-within .top-nav-trigger span:nth-child(1) { width: 88px; }
.top-nav.is-open .top-nav-trigger span:nth-child(2),
.top-nav:focus-within .top-nav-trigger span:nth-child(2) { width: 68px; opacity: 0.52; }
.top-nav.is-open .top-nav-trigger span:nth-child(3),
.top-nav:focus-within .top-nav-trigger span:nth-child(3) { width: 88px; }

.top-nav-panel {
  position: absolute;
  top: 0;
  left: 50%;
  /* Bumped width so the four nav items have breathing room — Settings was
     getting visually clipped by the right-hand toolset on smaller laptops. */
  width: min(1240px, calc(100vw - 24px));
  min-height: 58px;
  margin-top: 0;
  padding: 8px 14px;
  pointer-events: auto;
  display: grid;
  /* Bumped nav min-width so 4 pill items (with active outline) all fit. */
  grid-template-columns: minmax(150px, auto) minmax(420px, 1fr) minmax(300px, auto);
  align-items: center;
  gap: 14px;
  background: linear-gradient(180deg, var(--sidebar-bg-top) 0%, var(--sidebar-bg-bot) 100%);
  border: 1px solid var(--border);
  border-top: 0;
  border-radius: 0 0 20px 20px;
  box-shadow: var(--shadow-3);
  opacity: 0;
  visibility: hidden;
  transform: translateX(-50%) translateY(-110%);
  transform-origin: top center;
  /* IMPORTANT: must sit ABOVE the trigger (z-index: 2) so clicks on the
     nav items in the centre column (Performance / Settings) land on the
     link, not on the invisible-but-still-hit-testing trigger button that
     overlaps that exact area. */
  z-index: 3;
  /* No backdrop-filter: this large panel slides via transform on open/close;
     its gradient background is already opaque, so the blur only added paint
     cost during the slide. */
  /* CLOSING transition (panel returns to this base state) — kept short so the
     panel snaps back up promptly once the cursor leaves the safe zone. The
     visibility flip is delayed until the transform finishes so the panel
     doesn't vanish mid-retract. */
  transition: opacity 130ms var(--ease-out), visibility 0ms linear 190ms, transform 190ms cubic-bezier(0.4, 0, 0.2, 1);
}

.top-nav.is-open .top-nav-panel,
.top-nav:focus-within .top-nav-panel {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(8px);
  /* OPENING transition — a touch slower + softer easing so the drop-in feels
     smooth and deliberate, not abrupt. */
  transition: opacity 180ms var(--ease-out), visibility 0ms, transform 300ms cubic-bezier(0.16, 1, 0.3, 1);
}

.nav-panel-head {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 14px;
  min-width: 0;
  padding: 0 0 0 8px;
  border-bottom: 0;
}

.brand { display: flex; align-items: center; gap: 22px; padding: 0; }

.brand::after {
  content: '';
  display: block;
  width: 1px;
  height: 16px;
  background: var(--border);
  flex-shrink: 0;
}

.brand-mark { display: none; }
.brand-text { display: contents; }
.brand-sub { display: none; }

.brand-name {
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text);
}

/* ── Resting wordmark ─────────────────────────────────────────────────────────
   Fixed-position LUCRA visible when the nav panel is collapsed. Exact pixel
   coordinates match .brand-name inside the open nav panel at all viewport
   widths — zero movement, pure crossfade as the nav assembles around it.
   formula: left = 50% − min(620px, 50vw − 12px) + 23px (panel-left + 23px)
   ─────────────────────────────────────────────────────────────────────────── */
/* Resting wordmark — visible in the page header zone when nav is collapsed.
   Positioned above the topbar (which starts at ~58px) so it reads as the
   page-level brand anchor. JS (wireLucraFly) animates the shared transition;
   the CSS rule below is a no-JS fallback only. */
#lucra-resting {
  position: fixed;
  top: 38px;
  left: 20px;
  font-family: var(--font);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.10em;
  line-height: 20px;
  text-transform: uppercase;
  color: var(--text);
  pointer-events: none;
  user-select: none;
  z-index: 79;
  /* opacity + transform driven entirely by wireLucraFly JS */
}

/* No-JS/failure fallback: hide when nav is open */
.top-nav.is-open ~ #lucra-resting,
.top-nav:focus-within ~ #lucra-resting {
  opacity: 0;
}

/* Flying clone — position fully encoded in transform at animation time.
   Base is viewport origin (0,0); JS writes translate(srcRect.left, srcRect.top)
   and animates to translate(dstRect.left, dstRect.top) from live getBoundingClientRect()
   measurements. No hardcoded offsets. */
#lucra-fly {
  position: fixed;
  top: 0;
  left: 0;
  font-family: var(--font);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: 0.10em;
  line-height: 20px;
  text-transform: uppercase;
  color: var(--text);
  pointer-events: none;
  user-select: none;
  z-index: 100;
  opacity: 0;
  will-change: transform, opacity;
}

@media (prefers-reduced-motion: reduce) {
  #lucra-fly { display: none; }
}

.nav-account-mini {
  min-width: 132px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.15;
  padding: 4px 8px;
  border-radius: 10px;
  color: var(--text);
  text-align: left;
  transition: background 160ms var(--ease-out), box-shadow 160ms var(--ease-out), transform 160ms var(--ease-out);
}

.nav-account-mini:hover,
.top-nav-panel.account-menu-open .nav-account-mini {
  background: var(--surface);
  box-shadow: var(--shadow-1);
  transform: translateY(-1px);
}

.nav-account-label {
  font-size: 8px;
  color: var(--text-4);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.nav-account-mini strong {
  margin-top: 2px;
  max-width: 140px;
  overflow: hidden;
  font-size: 11px;
  font-weight: 500;
  color: var(--text-3);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav {
  display: flex;
  align-items: center;
  justify-content: center;
  /* Slightly larger gap so the active pill's outline can't visually
     bleed into the adjacent label — fixes the "Settings" overlap. */
  gap: 6px;
  min-width: 0;
  padding: 0;
}

.nav-group { display: contents; }

.nav-label {
  display: none;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-4);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 0 10px 6px;
}

.nav-item {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 38px;
  /* Slightly tighter horizontal padding lets each pill stay roomy without
     the labels (esp. "Performance" + "Settings") elbowing the neighbor. */
  padding: 8px 14px;
  border-radius: 999px;
  color: var(--text-2);
  font-weight: 500;
  font-size: 13.5px;
  white-space: nowrap;
  flex-shrink: 0;
  transition: background 180ms var(--ease-out), color 180ms var(--ease-out), transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.nav-item:hover {
  background: var(--surface);
  color: var(--text);
  transform: translateY(-1px);
  box-shadow: var(--shadow-1);
}

.nav-item.active {
  background: linear-gradient(180deg, rgba(10,132,255,0.10) 0%, rgba(10,132,255,0.06) 100%);
  color: var(--pos);
  box-shadow: inset 0 0 0 1px rgba(10,132,255,0.10);
}

/* Press — settle the hover-lift and squeeze slightly so the app's most frequent
   click (page navigation) is acknowledged in the same frame as mousedown, before
   any JS runs. Mirrors the pill/chip :active idiom; rides the existing transform
   transition so the press starts moving instantly without feeling twitchy. */
.nav-item:active { transform: translateY(0) scale(0.97); }

.nav-item svg { flex-shrink: 0; opacity: 0.9; }

.nav-panel-tools {
  display: flex;
  justify-content: center;
  gap: 8px;
  align-items: center;
  min-width: 0;
  padding: 0;
  border-top: 0;
}

.theme-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 3px;
  /* A touch more inset so the active (highlighted) segment always floats clearly
     INSIDE the track with even margin on every side, rather than its edge hugging
     the box border — which read as the active chip being "cut off" from the box. */
  padding: 4px;
  background: var(--surface-sunken);
  border-radius: 11px;
  border: 1px solid var(--border-hair);
}

.top-nav .theme-toggle {
  /* Icon-only in the top bar (the full Light/Dark/Grey labels live in Settings):
     a compact 3-icon control that sizes to its content, so it sits cleanly
     CENTRED in the nav tools column instead of stretching across it. */
  flex: 0 0 auto;
  grid-template-columns: repeat(3, 1fr);
}
.top-nav .theme-seg { gap: 0; padding: 7px 11px; }
.top-nav .theme-seg span { display: none; }

.theme-seg {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  padding: 6px 8px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
  border-radius: 7px;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.theme-seg:hover { color: var(--text-2); }
.theme-seg.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.theme-seg svg { flex-shrink: 0; }

.settings-field-head {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  gap: 10px;
}

.risk-unit-toggle {
  display: inline-grid;
  grid-template-columns: 1fr 1fr;
  gap: 2px;
  padding: 2px;
  background: var(--surface-sunken);
  border-radius: 8px;
  border: 1px solid var(--border-hair);
}

.risk-unit-seg {
  min-width: 30px;
  padding: 3px 9px;
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--text-3);
  border-radius: 6px;
  cursor: pointer;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}

.risk-unit-seg:hover { color: var(--text-2); }

.risk-unit-seg.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.settings-risk-readout {
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.account-add-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  min-height: 34px;
  padding: 7px 12px;
  border-radius: 999px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  font-size: 12.5px;
  font-weight: 700;
  white-space: nowrap;
  transition: transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out), border-color 180ms var(--ease-out);
}

.account-add-btn:hover {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-2);
}

.top-nav .account-add-btn {
  flex: 0 0 auto;
}

.account-switcher {
  position: absolute;
  top: 60px;
  left: 144px;
  width: min(360px, calc(100vw - 40px));
  display: block;
  padding: 10px;
  border: 1px solid var(--border);
  border-radius: 16px;
  /* Opaque popover (spec: popovers must be opaque). It also sits inside the
     translateX(-50%) nav panel — a transformed ancestor — so backdrop-filter
     was re-evaluated against a moving reference and animated on open. */
  background: var(--surface);
  box-shadow: var(--shadow-3);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-8px) scale(0.98);
  transform-origin: top left;
  transition: opacity 160ms var(--ease-out), visibility 160ms var(--ease-out), transform 190ms var(--ease-out);
}

.top-nav-panel.account-menu-open .account-switcher {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.account-switcher-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 8px;
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.account-switcher-head small {
  color: var(--text-4);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: none;
  letter-spacing: 0;
}

.account-list,
.settings-account-list {
  display: grid;
  gap: 7px;
}

.account-row {
  position: relative;
}

.account-row:has(.account-del) .account-option {
  padding-right: 42px;
}

.account-del {
  position: absolute;
  top: 50%;
  right: 7px;
  transform: translateY(-50%);
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 8px;
  color: var(--text-4);
  background: transparent;
  opacity: 0.4;
  cursor: pointer;
  transition: opacity 160ms var(--ease-out), color 160ms var(--ease-out), background 160ms var(--ease-out), border-color 160ms var(--ease-out);
}

.account-row:hover .account-del {
  opacity: 0.78;
}

.account-del:hover {
  opacity: 1;
  color: var(--neg);
  background: var(--neg-soft);
  border-color: color-mix(in srgb, var(--neg) 28%, transparent);
}

.account-option {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 9px 10px;
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text-2);
  background: color-mix(in srgb, var(--surface) 72%, transparent);
  text-align: left;
  transition: transform 180ms var(--ease-out), background 180ms var(--ease-out), border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.account-option:hover {
  transform: translateY(-1px);
  color: var(--text);
  background: var(--surface);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-1);
}

.account-option.active {
  color: var(--text);
  border-color: rgba(18, 152, 216, 0.22);
  background: var(--pos-soft);
}

.account-dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: var(--text-4);
}

.account-option.active .account-dot { background: var(--pos); }

.account-copy {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.account-copy strong {
  overflow: hidden;
  color: inherit;
  font-size: 12.5px;
  font-weight: 750;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.account-copy small,
.account-balance {
  color: var(--text-3);
  font-size: 11px;
  font-weight: 600;
}

.user {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-radius: var(--r-md);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
}

.avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  font-size: 11px;
  font-weight: 700;
  color: #fff;
  background: linear-gradient(135deg, #1D1D1F 0%, #515154 100%);
  letter-spacing: 0.02em;
}

.user-info { display: flex; flex-direction: column; line-height: 1.15; min-width: 0; }
.user-name { font-size: 13px; font-weight: 600; }
.user-plan {
  font-size: 11px;
  color: var(--text-3);
  margin-top: 2px;
}

/* ============================================================
   Main
   ============================================================ */

.main {
  height: 100vh;
  /* Bottom padding minimised so the dashboard-grid reclaims that vertical
     run for the Recent Trades preview — the bottom row gains the room
     needed to surface 6 trade rows without crushing the Net P&L chart. */
  padding: clamp(58px, 6vh, 72px) 20px 2px;
  display: flex;
  flex-direction: column;
  gap: var(--dash-gap-row);
  min-width: 0;
  overflow: hidden;
}

/* Page stage — only one page is active at a time. Crossfade via animation on
   activation (works reliably across browsers; transitions on display-toggled
   elements can get into a stuck-interpolation state). */
.page-stage {
  position: relative;
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
  /* All pages live here, so capping + centring the stage once contains every
     page (Dashboard/Trades/Performance/Settings) at one shared measure — no
     edge-to-edge stretch on large monitors, and identical alignment per page.
     Settings' own internal cap simply becomes a no-op under this tighter bound.*/
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  /* Clip (not hidden) so the incoming page's -18px downward-reveal start can
     never paint up under the topbar. `clip` does not create a scroll
     container/scrollbar, and the in-page trades filter dropdowns open downward
     (outside this stage's top edge), so nothing legitimate is cut off. */
  overflow: clip;
}

.page {
  position: relative;
  display: none;
  flex-direction: column;
  gap: clamp(10px, 1vh, 14px);
  min-height: 0;
  flex: 1;
  /* No persistent will-change here. Permanently promoting a page this large to
     its own compositor layer wastes GPU memory and actually slowed scrolling;
     the browser promotes it just for the duration of the enter/leave animation. */
}
.page.is-active {
  display: flex;
  z-index: 2;
}

.page.is-entering {
  /* Premium top-to-bottom reveal. The incoming page settles DOWN into place
     (translateY from −34px → 0) while it fades in across the first ~58% of the
     timeline, so the eye tracks a short, controlled descent from the top edge —
     subtle and expensive, never a large or exaggerated slide. Paired
     with the per-item stagger
     below (.page.is-entering .card …) the cards cascade in top→bottom, so the
     whole move reads as one elegant downward reveal. Opacity + transform only →
     fully GPU-composited (no clip-path, which used to re-rasterise the 187-row
     trades table every frame and felt laggy). Duration is centralised in
     --page-transition-duration (retuned by the fast-anim / reduced-motion hooks
     near :root). */
  animation: page-slide-in var(--page-transition-duration, 480ms) var(--page-reveal-ease, cubic-bezier(0.16, 1, 0.3, 1)) both;
  will-change: opacity, transform;
  z-index: 3;
}

.page.is-leaving {
  /* The outgoing page is pulled out of the active flow and hidden INSTANTLY
     beneath the incoming page (opacity:0 + visibility:hidden, applied on frame 0
     by page-fade-out). It never fades slowly in place, so the old KPI numbers /
     content can never bleed through behind or in front of the reveal — only one
     page is ever painted. It sits a layer below (z-index:1) purely as a safety
     net while the class lingers the ~one frame it takes to swap. */
  position: absolute;
  inset: 0;
  display: flex;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: hidden;
  z-index: 1;
  animation: page-fade-out var(--page-transition-duration, 480ms) linear both;
}

/* Park the inactive Trades page WITHOUT keeping it in the layout tree. Plain
   visibility:hidden still lays the subtree out, so the ~188-row ledger (sticky
   thead inside an overflow:auto scroller) was re-laid-out on EVERY style/layout
   recalc on EVERY page — measured at 13.8ms vs 0.1ms per forced relayout (138×,
   in Chromium; Safari Stable's main-thread sticky scroller pays far more). That
   permanent global tax was the Safari-only "navigate around and it degrades and
   stays degraded" lag. content-visibility:hidden skips the subtree's layout AND
   paint while PRESERVING its rendered state, so re-show on switch-in is still
   the cheap flip the old keep-warm bought (no ~33ms display:none→flex rebuild).
   It needs a rendered display (so we override .page's display:none) and must be
   out of flow — an in-flow content-visibility box collapses to a 0-height flex
   sibling and would split height with the active page; position:absolute keeps
   it inert behind everything. Class added by renderTradesPage() (never an empty
   shell). */
.page[data-page="trades"].tp-keep-warm:not(.is-active):not(.is-leaving) {
  display: flex;
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* visibility:hidden is the non-paint fallback for engines without
     content-visibility (Safari <18); it does NOT reintroduce the layout cost —
     content-visibility:hidden still skips the subtree's layout where supported. */
  visibility: hidden;
  content-visibility: hidden;
}

/* Deliberately NO per-card will-change. Promoting every card to its own GPU
   layer on page-enter is a Safari/WebKit performance cliff: it must allocate one
   layer per card and paint each card's box-shadow into it all at once, dropping
   frames on EVERY page switch (measured in WebKit: dashboard-enter 8 dropped
   frames → 0 once removed; Chrome was smooth either way, which is why this only
   showed up in Safari). The page-level will-change on .page.is-entering already
   gives the slide ONE composited layer, and each card's staggered
   transform/opacity cascade (page-item-in) auto-composites only while it is
   actually animating, then releases — far cheaper for WebKit's compositor. */

@keyframes page-slide-in {
  from {
    opacity: 0;
    transform: translate3d(0, -34px, 0);
  }
  58% {
    opacity: 1;
  }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

/* Outgoing page: invisible from the very first frame and stays invisible.
   Guarantees zero bleed-through of the previous page's content. */
@keyframes page-fade-out {
  from { opacity: 0; visibility: hidden; }
  to   { opacity: 0; visibility: hidden; }
}

/* ============================================================
   Trades page
   ============================================================ */

.page-trades {
  padding-top: 2px;
}

.tp-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 2px 0;
}

.tp-sub {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.005em;
}
.tp-sub strong { color: var(--text-2); font-weight: 700; }
.tp-sub .pos { color: var(--pos); font-weight: 700; }
.tp-sub .neg { color: var(--neg); font-weight: 700; }

.tp-search {
  position: relative;
  display: flex;
  align-items: center;
  gap: 9px;
  background: color-mix(in srgb, var(--surface) 76%, var(--surface-sunken));
  border: 1px solid var(--border-hair);
  border-radius: 14px;
  padding: 9px 14px;
  width: min(340px, 40vw);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03);
  transition: border-color 160ms var(--ease-out), background 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.tp-search:hover {
  background: var(--surface);
  border-color: var(--border);
}
.tp-search:focus-within {
  border-color: color-mix(in srgb, var(--text) 30%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 8%, transparent);
}
.tp-search svg { color: var(--text-3); flex-shrink: 0; }
.tp-search input {
  font: inherit;
  font-size: 13px;
  background: transparent;
  border: 0;
  outline: 0;
  color: var(--text);
  width: 100%;
}
.tp-search input::placeholder { color: var(--text-4); }

/* ============================================================
   Trades filter bar — labeled segmented controls + dropdowns,
   gathered into one calm card. Strictly monochrome: nothing in
   here carries semantic colour. Colour is reserved for the
   Net P&L column alone.
   ============================================================ */
.tp-filters {
  display: flex;
  flex-direction: column;
  gap: 13px;
  padding: 13px 15px 14px;
  margin: 2px 2px 0;
  /* Sits above the trades table card so the Symbol/Setup popovers (which drop
     below this card) aren't painted under the table. */
  position: relative;
  z-index: 20;
  border: 1px solid var(--border-hair);
  border-radius: 16px;
  background: color-mix(in srgb, var(--surface) 93%, var(--surface-sunken));
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.30),
    0 1px 0 rgba(15,17,21,0.02);
}
:root[data-theme="dark"] .tp-filters {
  background: color-mix(in srgb, var(--surface) 88%, var(--surface-sunken));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.03);
}
.tp-filters-top {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Search is a deliberately compact field, not a full-width bar — it reads as
   one control among several. Sort/Filter/Reset are pushed to the right edge
   (margin-left:auto on the first of them), leaving a calm gap in between. */
.tp-filters-top .tp-search {
  flex: 0 1 auto;
  width: min(390px, 52vw);
  min-width: 0;
}
/* Newest-first / Filter / Reset travel together as one cluster pinned to the
   right edge: margin-left:auto on the first of them opens a single gap after
   the search field; Reset must NOT get its own auto-margin or it floats off,
   leaving Sort+Filter stranded mid-bar. */
.tp-filters-top .tp-sort { margin-left: auto; }
.tp-filters-top .tp-chip-reset { margin-left: 0; }
/* Sort trigger — same dropdown chrome as Symbol/Setup, plus a leading sort
   glyph so its purpose (ordering, not narrowing) reads instantly. */
.tp-sort-trigger { min-width: 0; }
.tp-sort-lead {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  overflow: hidden;
}
.tp-sort-lead svg { color: var(--text-3); flex-shrink: 0; }
.tp-sort .tp-dd-trigger:hover .tp-sort-lead svg { color: var(--text-2); }
/* The sort options now live in an in-flow tray (see .tp-sort-tray) rather than a
   floating popover, so the trigger only needs to signal "open" — firm the border
   and flip the caret while the tray is expanded, mirroring the dropdown-open look. */
.tp-sort-trigger[aria-expanded="true"] {
  border-color: color-mix(in srgb, var(--text) 30%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 7%, transparent);
}
.tp-sort-trigger[aria-expanded="true"] .tp-dd-caret { transform: rotate(180deg); color: var(--text-3); }

/* "Filter" toggle — opens the slide-in tray. Sits between the search field
   and Reset. Carries a count badge so applied filters stay visible while the
   tray is collapsed. */
.tp-filter-toggle {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  flex-shrink: 0;
  height: 34px;
  padding: 0 13px;
  border: 1px solid var(--border-hair);
  border-radius: 11px;
  background: var(--surface);
  color: var(--text-2);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    border-color 150ms var(--ease-out),
    background 150ms var(--ease-out),
    color 150ms var(--ease-out),
    box-shadow 150ms var(--ease-out);
}
.tp-filter-toggle svg {
  color: var(--text-3);
  transition: color 150ms var(--ease-out);
}
.tp-filter-toggle:hover {
  border-color: var(--border-strong);
  color: var(--text);
}
.tp-filter-toggle:hover svg { color: var(--text-2); }
.tp-filter-toggle[aria-expanded="true"] {
  color: var(--text);
  border-color: color-mix(in srgb, var(--text) 26%, var(--border));
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 5%, transparent);
}
.tp-filter-toggle[aria-expanded="true"] svg { color: var(--text); }
.tp-filter-toggle-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 17px;
  height: 17px;
  padding: 0 5px;
  border-radius: 999px;
  background: var(--text);
  color: var(--surface);
  font-size: 10px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.tp-filter-toggle-count[hidden] { display: none; }

/* Slide-in filter tray — collapsed to zero height until the Filter toggle
   opens it. The grid-template-rows 0fr→1fr trick gives an auto-height reveal
   (no magic max-height), while the inner translates in from the left so the
   panel reads as sliding in. Mirrors the calendar week-drawer motion. */
.tp-filter-tray {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 340ms var(--ease-emphasized);
}
.tp-filter-tray.is-open { grid-template-rows: 1fr; }
/* Reveal is just height + a fade — no extra translate across the full-width
   content (animating a transform over the whole tray on top of the height
   relayout was making the expand stutter). */
.tp-filter-tray-inner {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  transition: opacity 240ms var(--ease-out);
}
.tp-filter-tray.is-open .tp-filter-tray-inner {
  opacity: 1;
}
/* Once the open transition has settled, JS flips this to `visible` so the
   Symbol/Setup popovers aren't clipped by the reveal's overflow. */
.tp-filter-tray-inner.is-overflowing { overflow: visible; }

/* Sort tray — the row's HEIGHT still slides open (grid-template-rows 0fr→1fr)
   so choosing an order "creates a new row" and pushes the ledger down instead
   of floating a menu over it. But the panel itself now "ausfährt und verblasst"
   exactly like a single calendar Kästchen: the expand + fade is lifted from the
   dashboard day-cell modal (.day-modal-panel) — the panel scales up from 0.965
   and settles down into place while fading in, on the modal's own
   cubic-bezier(0.22,1,0.36,1) ease. The close is quick but still eased (the
   modal's accelerating curve), never the old sharp snap. Every animated value
   lives on .is-open, so it plays on the very first open regardless of the
   page-load count-up. Mutually exclusive with the filter tray. */
.tp-sort-tray {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 320ms var(--ease-emphasized);
}
.tp-sort-tray.is-open { grid-template-rows: 1fr; }
.tp-sort-tray-inner {
  overflow: hidden;
  min-height: 0;
}
.tp-sort-tray-row {
  display: flex;
  padding-top: 14px;
  border-top: 1px solid var(--border-hair);
  /* Scales from the top edge so it grows downward with the height reveal. */
  transform-origin: top center;
  opacity: 0;
  transform: translateY(-12px) scale(0.965);
  /* CLOSE (fires when .is-open is removed): quick, accelerating — but eased. */
  transition:
    opacity 150ms ease,
    transform 170ms cubic-bezier(0.4, 0, 1, 1);
}
.tp-sort-tray.is-open .tp-sort-tray-row {
  opacity: 1;
  transform: translateY(0) scale(1);
  /* OPEN: the calendar day-modal's eased rise/scale-in. */
  transition:
    opacity 220ms var(--ease-emphasized),
    transform 320ms var(--ease-emphasized);
}

/* Invisible click-catcher for the open sort tray. The page behind stays fully
   sharp (no tint, no blur) — only pointer-events flip on so an outside click on
   the page still collapses the tray (caught by the #tp-filters outside-click
   handler), exactly as before. Sits at z-index 10, below the toolbar (z-index
   20), so the sort controls stay interactive. */
.tp-sort-scrim {
  position: fixed;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}
.tp-sort-scrim.is-open {
  pointer-events: auto;
}

/* All six filter modules in a single full-width row — Outcome · Side · Period
   · Plan · Symbol · Setup. The two dropdowns sit last (they carry a different
   control design from the four segmented groups). */
.tp-filters-grid {
  display: flex;
  flex-wrap: nowrap;
  align-items: flex-end;
  gap: 22px;
  padding-top: 14px;
  border-top: 1px solid var(--border-hair);
}
.tp-fmod {
  display: flex;
  flex-direction: column;
  gap: 7px;
  min-width: 0;
  flex: 0 0 auto;
}
/* The two dropdown modules anchor the right end of the row and shouldn't be
   squeezed by the segmented groups to their left. */
.tp-fmod--dd { margin-left: auto; }
.tp-fmod--dd + .tp-fmod--dd { margin-left: 0; }
.tp-fmod-label {
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-3);
  padding-left: 2px;
}

/* Segmented control track — quiet sunken rail holding the chips. */
.tp-filter-group {
  display: inline-flex;
  gap: 2px;
  padding: 3px;
  border: 1px solid var(--border-hair);
  border-radius: 11px;
  background: color-mix(in srgb, var(--surface-sunken) 75%, transparent);
}
:root[data-theme="dark"] .tp-filter-group {
  background: color-mix(in srgb, var(--surface-sunken) 85%, transparent);
}

.tp-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 11px;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: -0.003em;
  color: var(--text-3);
  border-radius: 9px;
  transition:
    background 140ms var(--ease-out),
    color 140ms var(--ease-out),
    box-shadow 140ms var(--ease-out),
    transform 140ms var(--ease-out);
}
.tp-chip:active { transform: scale(0.97); }
.tp-chip:hover {
  color: var(--text-2);
  background: color-mix(in srgb, var(--surface) 65%, transparent);
}
.tp-chip.active {
  background: var(--surface);
  color: var(--text);
  font-weight: 750;
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--text) 5%, transparent),
    0 1px 0 rgba(15,17,21,0.04),
    0 4px 12px -8px rgba(15,17,21,0.18);
}
:root[data-theme="dark"] .tp-chip.active {
  background: color-mix(in srgb, var(--surface) 95%, var(--surface-soft));
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.06),
    0 1px 0 rgba(0,0,0,0.30),
    0 4px 14px -8px rgba(0,0,0,0.50);
}
.tp-chip-count {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-4);
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  padding: 1px 6px;
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}
.tp-chip.active .tp-chip-count {
  color: var(--text-2);
  background: color-mix(in srgb, var(--text-3) 14%, transparent);
}

/* ----------------------------------------------------------------
   Dropdown filters (Symbol, Setup) — a trigger button that opens a
   compact popover list. Keeps the high-cardinality filters from
   sprawling into a wall of chips. Monochrome throughout.
   ---------------------------------------------------------------- */
.tp-filter-dd { position: relative; }
.tp-dd-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  min-width: 150px;
  height: 34px;
  padding: 0 11px 0 13px;
  border: 1px solid var(--border-hair);
  border-radius: 11px;
  background: var(--surface);
  color: var(--text);
  font-size: 12.5px;
  font-weight: 650;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    border-color 150ms var(--ease-out),
    background 150ms var(--ease-out),
    box-shadow 150ms var(--ease-out);
}
.tp-dd-trigger:hover { border-color: var(--border-strong); }
.tp-dd-trigger .tp-dd-value {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tp-dd-trigger .tp-dd-caret {
  flex-shrink: 0;
  color: var(--text-4);
  transition: transform 180ms var(--ease-out), color 150ms var(--ease-out);
}
.tp-dd-trigger:hover .tp-dd-caret { color: var(--text-3); }
/* Active narrowing filter — the trigger firms up (ink border + bold) so
   the user can see at a glance that this dropdown is constraining. */
.tp-filter-dd.has-active .tp-dd-trigger {
  border-color: color-mix(in srgb, var(--text) 22%, var(--border));
  font-weight: 750;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 4%, transparent);
}
.tp-filter-dd.is-open .tp-dd-trigger {
  border-color: color-mix(in srgb, var(--text) 30%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 7%, transparent);
}
.tp-filter-dd.is-open .tp-dd-caret { transform: rotate(180deg); }
/* The sort dropdown deliberately does NOT use .tp-filter-dd.is-open — its menu
   is an in-flow tray below the toolbar, not a floating popover, so it must not
   pick up the absolute-popover reveal rules in this block. */

.tp-dd-menu {
  position: absolute;
  z-index: 40;
  top: calc(100% + 7px);
  left: 0;
  /* Generous cap so every option shows at once — the user wants no scrolling
     inside either menu. Only an unusually long list would ever scroll. */
  max-height: min(62vh, 540px);
  overflow-y: auto;
  padding: 7px;
  border: 1px solid var(--border);
  border-radius: 14px;
  /* Solid, fully opaque surface. This menu has no backdrop-filter, so the old
     --surface-elevated (82% alpha) just let the trades behind bleed through and
     read as a cheap "see-through" panel. A solid fill + the shadow below give
     it clean, premium elevation instead. */
  background: var(--surface);
  box-shadow:
    0 1px 0 rgba(15,17,21,0.02),
    0 22px 52px -18px rgba(15,17,21,0.34);
  opacity: 0;
  transform: translateY(-5px) scale(0.985);
  transform-origin: top left;
  transition: opacity 150ms var(--ease-out), transform 180ms var(--ease-out);
  pointer-events: none;
  scrollbar-width: thin;
}
/* Symbol menu — compact responsive grid so a wide symbol set stays tidy and
   fully visible. The "All symbols" reset spans the full width as a header. */
.tp-dd-menu--grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(74px, 1fr));
  gap: 4px;
  min-width: 248px;
  align-content: start;
}
/* Setup menu — single full-width column (labels run long), every row visible
   without scrolling, anchored to the trigger's right edge so it never spills
   past the card. */
.tp-dd-menu--list {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 240px;
  left: auto;
  right: 0;
  transform-origin: top right;
}
:root[data-theme="dark"] .tp-dd-menu {
  box-shadow: 0 22px 56px -18px rgba(0,0,0,0.62);
}
.tp-dd-menu[hidden] { display: none; }
.tp-filter-dd.is-open .tp-dd-menu {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
.tp-dd-opt {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  height: 33px;
  padding: 0 11px;
  border-radius: 9px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: -0.003em;
  color: var(--text-2);
  white-space: nowrap;
  cursor: pointer;
  transition: background 120ms var(--ease-out), color 120ms var(--ease-out);
}
.tp-dd-opt .tp-dd-opt-label {
  overflow: hidden;
  text-overflow: ellipsis;
}
.tp-dd-opt:hover { background: var(--surface-soft); color: var(--text); }
.tp-dd-opt .tp-dd-check {
  width: 14px;
  height: 14px;
  flex-shrink: 0;
  opacity: 0;
  color: var(--text);
}
.tp-dd-opt.active {
  color: var(--text);
  font-weight: 750;
  background: var(--surface-sunken);
}
.tp-dd-opt.active .tp-dd-check { opacity: 1; }

/* The "All / Any" reset option spans the full grid width as a header row,
   separated from the choices below by a hairline. */
.tp-dd-menu--grid .tp-dd-opt.tp-dd-opt-all {
  grid-column: 1 / -1;
  margin-bottom: 3px;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--border-hair);
  border-radius: 9px 9px 0 0;
}
.tp-dd-menu--list .tp-dd-opt.tp-dd-opt-all {
  margin-bottom: 3px;
  padding-bottom: 3px;
  border-bottom: 1px solid var(--border-hair);
}
/* In the grid, symbol cells centre their label and signal selection with the
   active fill rather than a check (cells are too narrow for a tick). */
.tp-dd-menu--grid .tp-dd-opt:not(.tp-dd-opt-all) { justify-content: center; }
.tp-dd-menu--grid .tp-dd-opt:not(.tp-dd-opt-all) .tp-dd-check { display: none; }

/* Context bar — shows when navigating to Trades from Performance page.
   Slightly more prominent now: a soft tinted panel with an inline icon, a
   "drill-down" label, and a dismiss button positioned to invite removal. */
.tp-context-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 9px 12px 9px 14px;
  margin-bottom: 6px;
  border-radius: 11px;
  background: color-mix(in srgb, var(--pos) 7%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--pos) 24%, transparent);
  box-shadow: 0 4px 18px -14px color-mix(in srgb, var(--pos) 60%, transparent);
}
.tp-context-bar[hidden] { display: none; }
.tp-context-label {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
  flex: 1;
  min-width: 0;
}
.tp-context-label::before {
  content: 'Drill-down';
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 15%, transparent);
  border-radius: 5px;
  flex-shrink: 0;
}
.tp-context-label strong { font-weight: 750; color: var(--text); }
.tp-context-label svg { display: none; }

/* The clear button inside the context bar overrides the .tp-chip-reset
   margin-left auto so it stays tight to the label rather than drifting right. */
.tp-context-bar .tp-chip-reset {
  margin-left: 0;
  padding: 6px 11px;
  font-size: 11px;
  border-color: color-mix(in srgb, var(--pos) 22%, transparent);
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 8%, transparent);
}
.tp-context-bar .tp-chip-reset:hover {
  background: color-mix(in srgb, var(--pos) 14%, transparent);
  color: var(--pos);
}

/* Reset button — soft ghost chip that lives outside the filter pills. Stays
   muted when no filters are active, becomes a confident pill when there is
   actually state to clear. */
.tp-chip-reset {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: -0.003em;
  color: var(--text-3);
  border: 1px solid var(--border-hair);
  border-radius: 10px;
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  transition:
    color 180ms var(--ease-out),
    background 180ms var(--ease-out),
    border-color 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    transform 180ms var(--ease-out);
  margin-left: auto;
}
.tp-chip-reset:hover {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
  box-shadow: 0 4px 14px rgba(15,17,21,0.06);
}
.tp-chip-reset:active { transform: scale(0.96); }
.tp-chip-reset svg { opacity: 0.7; }
.tp-chip-reset.is-active {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--text) 5%, transparent);
}
.tp-chip-reset.is-active svg { opacity: 0.95; }
.tp-chip-reset .tp-chip-reset-count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 16px;
  padding: 0 5px;
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0;
  color: var(--text);
  background: color-mix(in srgb, var(--text-3) 14%, transparent);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}

.tp-overview {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
  padding: 2px 2px 0;
}

.tp-overview-card {
  position: relative;
  min-width: 0;
  padding: 16px 18px 15px 20px;
  border: 1px solid var(--border-hair);
  border-radius: 14px;
  background: var(--surface);
  box-shadow: 0 1px 0 rgba(15,17,21,0.02);
  overflow: hidden;
  transition:
    transform 200ms var(--ease-out),
    border-color 200ms var(--ease-out),
    box-shadow 220ms var(--ease-out);
}
:root[data-theme="dark"] .tp-overview-card {
  background: color-mix(in srgb, var(--surface) 94%, var(--surface-sunken));
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.025);
}

.tp-overview-card:hover,
.tp-overview-card.is-hovered {
  transform: translateY(-1px);
  border-color: var(--border);
  box-shadow:
    0 1px 0 rgba(15,17,21,0.03),
    0 12px 26px -16px rgba(8, 12, 22, 0.18);
}
:root[data-theme="dark"] .tp-overview-card:hover,
:root[data-theme="dark"] .tp-overview-card.is-hovered {
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.04),
    0 14px 28px -18px rgba(0, 0, 0, 0.55);
}

/* Left accent stripe — quiet by default, tone-coloured per .accent-* tag */
.tp-overview-card::before {
  content: '';
  position: absolute;
  inset: 16px auto 16px 0;
  width: 2px;
  border-radius: 99px;
  background: color-mix(in srgb, var(--text-3) 30%, transparent);
  transition: background 200ms var(--ease-out), inset 200ms var(--ease-out);
}
.tp-overview-card:hover::before { inset: 14px auto 14px 0; }
.tp-overview-card.pos::before,
.tp-overview-card.accent-pos::before,
.tp-overview-card.accent-mint::before { background: var(--pos); }
.tp-overview-card.neg::before,
.tp-overview-card.accent-neg::before  { background: var(--neg); }
.tp-overview-card.accent-amber::before { background: #f59e0b; }
.tp-overview-card.accent-neutral::before {
  background: color-mix(in srgb, var(--text-3) 30%, transparent);
}

/* Eyebrow label — refined institutional treatment */
.tp-overview-card .tp-ov-label {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--text-3);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
/* Filtered-state pill — only renders when filters narrow the dataset */
.tp-overview-card .tp-ov-flag {
  display: inline-flex;
  align-items: center;
  padding: 1px 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.05em;
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 13%, transparent);
  border-radius: 4px;
  text-transform: uppercase;
}

/* Big number — the eye anchor */
.tp-overview-card .tp-ov-value {
  display: block;
  margin-top: 9px;
  color: var(--text);
  font-size: 24px;
  font-weight: 850;
  letter-spacing: -0.022em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
/* Net P&L card carries slightly more visual weight — it's the lead metric */
.tp-overview-card.is-lead .tp-ov-value { font-size: 26px; letter-spacing: -0.025em; }
.tp-overview-card.pos .tp-ov-value { color: var(--pos); }
.tp-overview-card.neg .tp-ov-value { color: var(--neg); }

/* Sub-line — structured context with W/L split or coverage */
.tp-overview-card .tp-ov-sub {
  display: flex;
  align-items: center;
  gap: 6px;
  margin-top: 9px;
  color: var(--text-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: -0.003em;
  font-variant-numeric: tabular-nums;
  min-height: 14px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.tp-overview-card .tp-ov-sub .ov-w { color: var(--pos); }
.tp-overview-card .tp-ov-sub .ov-l { color: var(--neg); }
.tp-overview-card .tp-ov-sub .ov-sep {
  width: 3px; height: 3px;
  border-radius: 50%;
  background: var(--text-4);
  flex-shrink: 0;
}

/* Legacy span/strong/small fallback selectors — kept to avoid breaking any
   markup paths that still emit the old structure. Inherit refined typography
   so the cards never regress to the v1 sizing. */
.tp-overview-card > span {
  display: block;
  color: var(--text-3);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.tp-overview-card > strong {
  display: block;
  margin-top: 9px;
  color: var(--text);
  font-size: 24px;
  font-weight: 850;
  letter-spacing: -0.022em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.tp-overview-card.pos > strong { color: var(--pos); }
.tp-overview-card.neg > strong { color: var(--neg); }
.tp-overview-card > small {
  display: block;
  margin-top: 9px;
  color: var(--text-3);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: -0.003em;
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tp-table-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 6px 8px 8px;
  overflow: hidden;
  min-height: 0;
  border-radius: 18px;
  background: color-mix(in srgb, var(--surface) 90%, var(--surface-sunken));
}

.tp-table-wrap {
  flex: 1;
  overflow-y: auto;
  overflow-x: auto;
  min-height: 0;
  overscroll-behavior: contain;
}
/* During an active scroll, suppress row hit-testing so rows passing under the
   cursor don't each fire their hover background/border transition — that
   repaint storm was a big part of why the list scrolled janky. JS adds
   .is-scrolling on scroll and removes it ~100ms after the last scroll event. */
.tp-table-wrap.is-scrolling tbody { pointer-events: none; }

.tp-table {
  width: 100%;
  border-collapse: separate;
  /* Tight inter-row gap so the table reads as a continuous institutional
     ledger, not a stack of widely-spaced cards. */
  border-spacing: 0 4px;
  font-variant-numeric: tabular-nums;
}

.tp-table thead th {
  position: sticky;
  top: 0;
  background: color-mix(in srgb, var(--surface) 86%, var(--surface-sunken));
  z-index: 2;
  text-align: left;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-3);
  padding: 11px 16px 9px;
  border-bottom: 0;
  /* No backdrop-filter here. The header background is already fully opaque, and
     a blur on a sticky element forces the browser to re-blur every row that
     scrolls underneath it on every frame — that was the cause of the janky
     (~5 FPS) trades-list scroll. A solid header scrolls perfectly smoothly. */
}
.tp-table thead th.num { text-align: right; }
/* Column header for the leading status dot — narrow and unlabeled. */
.tp-table thead th.tp-col-status {
  width: 22px;
  padding-left: 14px;
  padding-right: 0;
}
/* Tighten the size column header to match the data alignment. */
.tp-table thead th.tp-col-size { width: 60px; }
.tp-table thead th.tp-col-after { width: 28px; padding-left: 0; padding-right: 14px; }

.tp-table tbody tr {
  cursor: pointer;
  /* Off-screen rows skip layout + paint — the key win for smooth scrolling of a
     long ledger on high-DPI displays (187 rows × 2× pixels is a lot to paint).
     Rows are a uniform 56px, so the intrinsic-size placeholder matches exactly
     and the scrollbar never jumps. */
  content-visibility: auto;
  contain-intrinsic-size: auto 56px;
}

/* Staggered "load-in" for the trade list. Driven by animateTradesList(), which
   adds .tp-anim-in to the tbody after sort / filter / reset changes and on the
   list's first render. The per-row --row-delay (set inline in renderTradesTable)
   cascades the cells so rows ripple in rather than popping in unison. Cells
   (not the <tr>) carry the transform — table rows transform unreliably with
   collapsed borders, table cells do not. renderTradesTable strips the class on
   every rebuild so plain search keystrokes never replay the cascade. */
@keyframes tp-row-in {
  from { opacity: 0; transform: translateY(9px); }
  to   { opacity: 1; transform: translateY(0); }
}
#tp-body.tp-anim-in td {
  animation: tp-row-in 300ms var(--ease-out) both;
  animation-delay: var(--row-delay, 0ms);
}
:root.reduced-page-motion #tp-body.tp-anim-in td { animation: none; }

/* Scroll-reveal: each row fades in as it scrolls into view, so the list "loads
   in" piece by piece while scrolling rather than being flatly present. This is
   a COMPOSITOR-driven scroll-timeline animation (animation-timeline: view()) —
   zero main-thread cost, so it never adds scroll jank — and because it's bound
   to scroll position (not a one-shot timer) it never re-flashes already-visible
   rows on a search/filter re-render. Opacity only: the <tr> animates opacity
   reliably, whereas transforms on table rows don't (the sort cascade keeps its
   rise on the <td>s). Chrome-only; elsewhere rows simply show with no reveal. */
@keyframes tp-row-reveal {
  from { opacity: 0; }
  to   { opacity: 1; }
}
@supports (animation-timeline: view()) {
  /* Gated to :root:not(.reduced-page-motion) — the in-app "Short fade and slide
     transitions" setting — so the scroll-reveal follows the in-app toggle and still
     replays under OS Reduce Motion. Armed via ONE ancestor class on the tbody
     (#tp-body.reveal-armed), added once by armTradesReveal after the overview
     count-up settles. Every current AND future <tr> inherits the reveal, so
     re-sorting/filtering and page revisits need no per-row class changes. The old
     per-row .reveal-armed pass re-toggled the class on all ~187 rows every Trades
     revisit (disarm + re-arm = 374 DOM mutations) — the measured storm a Safari
     content-blocker's MutationObserver re-scanned on the main thread (the
     AdBlocker-only Trades lag). Gated to :not(.tpv-on) so virtualized ledgers (which
     recycle rows) keep their .tpv-on opacity:1 with no reveal. Rows already on screen
     are opacity:1 whether armed or not, so the deferred arm only delays the reveal for
     rows you scroll down to, which is necessarily after the count-up has finished. */
  /* Gated to the ACTIVE Trades page. The table is kept warm (always in the DOM
     after first visit via .tp-keep-warm), and content-visibility:hidden skips its
     paint but does NOT drop these 187 view()-timeline row animations from the
     document's running set — they stay live on every other page and get
     re-evaluated on that page's layout recalc, stealing a frame on entry (measured:
     187 phantom animations spiked the Performance reveal to a dropped frame, the
     residual "Trades table taxes every page" cost). Requiring .is-active sheds all
     187 whenever Trades isn't the page you're on — including the ~540ms it spends
     .is-leaving, which overlaps the next page's enter. Rides the .is-active class
     switchPage already toggles: zero extra DOM mutations (no per-row arm storm).
     Re-arms for free on Trades activation; on-screen rows are opacity:1 regardless. */
  :root:not(.reduced-page-motion) .page[data-page="trades"].is-active .tp-table:not(.tpv-on) #tp-body.reveal-armed tr {
    animation: tp-row-reveal linear both;
    animation-timeline: view(block);
    /* Fade across the row's full entry (~one row-height of scroll) so the
       reveal is clearly visible — rows materialise as they rise into view. */
    animation-range: entry 0% entry 100%;
  }
}

/* Default cell — clean white surface. Top + bottom hairlines form the
   perceived row border; no vertical column borders, no per-cell tints.
   Slightly tighter vertical padding than v1 (12px vs 14px) so the row
   reads as a denser ledger entry, closer to the Bloomberg / TT terminal
   visual rhythm than a roomy card. */
.tp-table tbody td {
  font-size: 13px;
  font-weight: 500;
  padding: 12px 16px;
  border-top: 1px solid var(--border-hair);
  border-bottom: 1px solid var(--border-hair);
  color: var(--text);
  background-color: var(--surface);
  transition:
    background-color 140ms var(--ease-out),
    border-color 140ms var(--ease-out);
}
.tp-table tbody td.num { text-align: right; font-weight: 600; }
.tp-table tbody td:first-child {
  border-left: 1px solid var(--border-hair);
  border-radius: 10px 0 0 10px;
  position: relative;
}
.tp-table tbody td:last-child {
  border-right: 1px solid var(--border-hair);
  border-radius: 0 10px 10px 0;
  padding-right: 14px;
}

/* Leading-edge accent — neutral hairline. Originally tinted by P&L, but the
   design direction is "only P&L carries color" so the stripe is now a quiet
   gray that signals "row exists" without competing with the actual P&L
   cell on the right. The hover state firms it up slightly, never tints. */
.tp-table tbody tr td:first-child::before {
  content: '';
  position: absolute;
  inset: 10px auto 10px 0;
  width: 2px;
  border-radius: 99px;
  opacity: 0.4;
  pointer-events: none;
  background: color-mix(in srgb, var(--text-4) 70%, transparent);
  transition: opacity 140ms var(--ease-out), inset 140ms var(--ease-out);
}
.tp-table tbody tr:hover td:first-child::before { opacity: 0.85; inset: 8px auto 8px 0; }

/* Row highlight is purely CSS-driven. Hover paints the WHOLE row with one
   uniform subtle gray + a hairline-darker border so the row reads as a single
   lifted card. Releasing the click or moving the cursor away restores the
   clean white surface immediately. No JS-managed is-hovered / is-active. */
.tp-table tbody tr:hover td {
  background-color: var(--surface-soft);
  border-top-color: color-mix(in srgb, var(--border) 70%, transparent);
  border-bottom-color: color-mix(in srgb, var(--border) 70%, transparent);
}
.tp-table tbody tr:hover td:first-child { border-left-color: color-mix(in srgb, var(--border) 70%, transparent); }
.tp-table tbody tr:hover td:last-child  { border-right-color: color-mix(in srgb, var(--border) 70%, transparent); }

/* Click — quick press feedback (no sticky background). */
.tp-table tbody tr:active td {
  background-color: var(--surface-sunken);
}

/* Opened/focused row — applied while the modal is open for this trade. Uses
   a neutral sunken background and a hairline-darker border so the user never
   loses track of which trade they were inspecting, without introducing any
   colour (only the P&L cell is ever tinted). The class is added on row click
   and removed on modal close / on a different row click. */
.tp-table tbody tr.is-opened td {
  background-color: var(--surface-sunken);
  border-top-color: var(--border-strong);
  border-bottom-color: var(--border-strong);
}
.tp-table tbody tr.is-opened td:first-child {
  border-left-color: var(--border-strong);
}
.tp-table tbody tr.is-opened td:last-child {
  border-right-color: var(--border-strong);
}
.tp-table tbody tr.is-opened td:first-child::before {
  opacity: 1;
  inset: 8px auto 8px 0;
  width: 3px;
}

/* ── Trades table virtualization (.tpv-on) ──────────────────────────────────
   Engaged only above TPV_THRESHOLD trades. tpvPinColumns() freezes the column
   widths to a <colgroup> + table-layout:fixed so swapping the mounted row window
   never shifts a column; data rows keep the look, hover, is-opened and (via the
   base rule) content-visibility exactly as in full-render mode. */

/* Spacer rows reserve the scroll height of the rows outside the mounted window.
   They MUST opt out of the row content-visibility placeholder — otherwise a tall
   spacer collapses to the ~56px intrinsic size and the scroll length is wrong —
   and out of every interactive/decorative row style (accent stripe, hover). */
.tp-table tbody tr.tpv-spacer {
  content-visibility: visible;
  contain-intrinsic-size: auto;
  cursor: default;
}
.tp-table tbody tr.tpv-spacer td {
  padding: 0;
  border: 0;
  background: transparent;
  transition: none;
}
.tp-table tbody tr.tpv-spacer td::before { content: none; }
.tp-table tbody tr.tpv-spacer:hover td { background: transparent; border-color: transparent; }

/* Reserve the vertical scrollbar gutter while virtualized so the client width is
   the same when columns are measured (single measure row, no scrollbar) as when
   the window renders (tall spacer → scrollbar present). Without this the frozen
   columns end up one scrollbar-width too wide and a phantom horizontal scrollbar
   appears. Scoped to .tpv-wrap so small, full-render accounts are untouched. */
.tp-table-wrap.tpv-wrap { scrollbar-gutter: stable; }

/* The transient one-row measure pass (worst-case content, used to size the
   columns before freezing) is read synchronously and replaced before paint;
   keep it inert — visibility:hidden still lays out, so widths stay accurate. */
.tp-table tbody tr.tpv-measure { visibility: hidden; }

/* Review-status dot — a single legible signal: "have I journaled this trade?"
   FILLED dot = reviewed (rating + setup done) · faint RING = partially started ·
   EMPTY = untouched. The one exception is the amber ring, a genuine data-quality
   warning (rated/planned but the setup tag is missing, which breaks Performance
   grouping). Tooltip carries the exact word. Filled-vs-empty is the whole story. */
.tp-status-cell {
  display: inline-flex;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: transparent;
  box-shadow: none;
  vertical-align: middle;
  position: relative;
  transition: box-shadow 160ms var(--ease-out), background 160ms var(--ease-out);
}
.tp-status-cell[data-status="reviewed"] {
  background: var(--text);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 9%, transparent);
}
.tp-status-cell[data-status="partial"] {
  background: transparent;
  box-shadow: inset 0 0 0 1.5px color-mix(in srgb, var(--text-3) 85%, transparent);
}
.tp-status-cell[data-status="unreviewed"] {
  /* Untouched — show nothing, so a filled dot unmistakably means "reviewed". */
  background: transparent;
  box-shadow: none;
}
.tp-status-cell[data-status="unreviewed"][data-seen="true"] {
  /* Opened but not yet reviewed: a quiet, low-contrast dot so you can tell which
     untouched trades you've already eyeballed — clearly weaker than the solid
     "reviewed" dot, and distinct from the hollow "partly done" ring. Orthogonal
     to review status: it never upgrades a row to "reviewed". */
  background: color-mix(in srgb, var(--text-4) 62%, transparent);
  box-shadow: none;
}
.tp-status-cell[data-status="missing"] {
  /* Rated/planned but the setup tag is missing — the lone warning state. */
  background: transparent;
  box-shadow:
    inset 0 0 0 1.5px color-mix(in srgb, var(--warn) 75%, transparent),
    0 0 0 3px color-mix(in srgb, var(--warn) 12%, transparent);
}
.tp-table tbody td.tp-status-col {
  padding-left: 14px;
  padding-right: 0;
  width: 14px;
}

/* Review-status legend — decodes the leading status dot. Previously the only
   explanation was a hover tooltip, which the user never discovered; this quiet
   strip makes the four states self-evident at the top of the table card. */
.tp-table-legend {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 9px 18px;
  padding: 11px 16px 12px;
  border-bottom: 1px solid var(--border-hair);
}
.tp-legend-title {
  margin-right: auto;
  font-size: 10px;
  font-weight: 750;
  letter-spacing: 0.085em;
  text-transform: uppercase;
  color: var(--text-3);
}
.tp-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  font-weight: 600;
  color: var(--text-2);
  white-space: nowrap;
}
.tp-legend-item .tp-status-cell { flex-shrink: 0; }
.tp-legend-item--warn { color: color-mix(in srgb, var(--warn) 58%, var(--text-2)); }
.tp-legend-item--muted { color: var(--text-4); }
.tp-legend-empty {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
  border: 1px dashed color-mix(in srgb, var(--text-4) 70%, transparent);
}

.tp-time-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.2;
}
.tp-time-cell .tp-date {
  font-weight: 650;
  color: var(--text);
  font-size: 12.5px;
  letter-spacing: -0.005em;
}
.tp-time-cell .tp-clock {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 550;
  letter-spacing: 0;
}

/* Symbol cell — ticker on top, the trade's tagged setup as a quiet second
   line beneath (when present). Mirrors the date/time stack so the two columns
   share a vertical rhythm. The setup line stays neutral grey; only P&L is
   ever tinted. */
.tp-sym-stack {
  display: flex;
  flex-direction: column;
  gap: 2px;
  line-height: 1.2;
}
.tp-sym-cell {
  font-family: var(--mono);
  font-weight: 700;
  letter-spacing: 0.015em;
  color: var(--text);
  font-size: 13px;
}
.tp-sym-setup {
  font-size: 10.5px;
  font-weight: 550;
  color: var(--text-3);
  letter-spacing: -0.002em;
  max-width: 168px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Side cell — neutral institutional pill. Only the P&L column carries
   tone; Long/Short reads as a quiet category tag, not a colored badge.
   The leading dot stays so the visual rhythm of [dot][SIDE] is preserved,
   but it uses text color (neutral) instead of pos/neg. */
.tp-side-cell {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 750;
  padding: 3px 8px 3px 7px;
  border-radius: 6px;
  letter-spacing: 0.025em;
  text-transform: uppercase;
  color: var(--text);
  background: color-mix(in srgb, var(--text-3) 8%, transparent);
}
.tp-side-cell.long,
.tp-side-cell.short {
  /* Long/Short variants intentionally share the same neutral treatment.
     The .long / .short class is preserved for potential future use, but
     no longer carries semantic color. */
  color: var(--text);
  background: color-mix(in srgb, var(--text-3) 8%, transparent);
}
.tp-side-cell::before {
  content: '';
  width: 4px; height: 4px;
  border-radius: 50%;
  background: var(--text-3);
}

/* R-multiple cell — neutral. Was previously pos/neg colored; now reads as
   pure mono numeric data. The +/- sign provides the directional cue. */
.tp-r-cell {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--text);
}
.tp-r-cell.pos,
.tp-r-cell.neg { color: var(--text); }

/* P&L — the strongest cell in the row. Tabular nums + slightly bigger size
   so the eye lands here first regardless of where it enters the row. */
.tp-pnl-cell {
  font-weight: 750;
  font-size: 13.5px;
  letter-spacing: -0.012em;
}
.tp-pnl-cell.pos { color: var(--pos); }
.tp-pnl-cell.neg { color: var(--neg); }

.tp-hold-cell {
  color: var(--text-3);
  font-weight: 550;
  font-size: 11.5px;
  letter-spacing: -0.003em;
}

.tp-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: flex-end;
  width: 16px;
  color: var(--text-4);
  opacity: 0.7;
  transition: transform 140ms var(--ease-out), color 140ms var(--ease-out), opacity 140ms var(--ease-out);
}
/* CSS-drawn chevron (a rotated border corner) instead of a per-row inline SVG —
   187 fewer SVG/path nodes in the table, lighter to build and paint. */
.tp-chevron::after {
  content: '';
  width: 6px;
  height: 6px;
  border-right: 2px solid currentColor;
  border-top: 2px solid currentColor;
  border-radius: 1px;
  transform: rotate(45deg);
}
.tp-table tbody tr:hover .tp-chevron {
  transform: translateX(2px);
  color: var(--text-2);
  opacity: 1;
}
.tp-table tbody tr.is-opened .tp-chevron {
  color: var(--pos);
  opacity: 1;
}

.tp-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 60px 20px;
  color: var(--text-3);
  font-size: 13px;
}
.tp-empty-icon {
  display: grid;
  place-items: center;
  width: 44px; height: 44px;
  border-radius: 12px;
  background: var(--surface-sunken);
  color: var(--text-4);
}

/* Zero-state activation block — reuses .tp-empty centering + .pill buttons. */
.tp-empty-cta-title {
  margin: 4px 0 0;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.tp-empty-cta-sub {
  margin: 0;
  max-width: 360px;
  text-align: center;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-3);
}
.tp-empty-cta-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 8px;
}

/* Brief "you landed here" cue when the Import CTA jumps to Settings → Data. */
.settings-section-flash { animation: settingsSectionFlash 1.5s var(--ease-out); }
@keyframes settingsSectionFlash {
  0%   { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 55%, transparent); }
  100% { box-shadow: 0 0 0 3px transparent; }
}
:root.reduced-page-motion .settings-section-flash { animation: none; }

/* ------------------------------------------------------------------
   Onboarding → Settings import spotlight.
   When the Getting Started "Import trades" step routes here, briefly
   frame the Data & Backup card and tint the Import & Sync zone so the
   eye lands on the exact area. Single in→hold→out fade (runs once, no
   flashing); box-shadow / background only, so there is no layout shift.
   JS clears the classes after the cue; reduced-motion shows a static
   highlight that the same timeout still removes.
   ------------------------------------------------------------------ */
.settings-attention { position: relative; }
.settings-attention::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  /* The card is overflow:hidden, so an INSET ring is never clipped
     (an outward one would be). Frames "Data & Backup" gently. */
  box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--accent) 40%, transparent);
  opacity: 0;
  animation: settingsAttnCard 3.2s var(--ease-out);
}
@keyframes settingsAttnCard {
  0%   { opacity: 0; }
  12%  { opacity: 1; }
  70%  { opacity: 1; }
  100% { opacity: 0; }
}
.settings-attention-zone {
  border-radius: var(--r-md);
  /* ≤6px outward halo stays inside the card's 24px padding (its
     overflow:hidden would clip anything wider). The whole cue is
     box-shadow + background only → no box-model change → no CLS. */
  animation: settingsAttnZone 3.2s var(--ease-out);
}
@keyframes settingsAttnZone {
  0%, 100% {
    background: transparent;
    box-shadow: 0 0 0 1px transparent, 0 0 0 6px transparent;
  }
  12%, 70% {
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--accent) 42%, transparent),
      0 0 0 6px color-mix(in srgb, var(--accent) 11%, transparent);
  }
}
@media (prefers-reduced-motion: reduce) {
  .settings-attention::after { animation: none; opacity: 1; }
  .settings-attention-zone {
    animation: none;
    background: color-mix(in srgb, var(--accent) 8%, transparent);
    box-shadow:
      0 0 0 1px color-mix(in srgb, var(--accent) 42%, transparent),
      0 0 0 6px color-mix(in srgb, var(--accent) 11%, transparent);
  }
}

/* ============================================================
   First-run onboarding checklist (dashboard) — reuses .card surface.
   In-flow, non-blocking, dismissible. No new modal / overlay.
   ============================================================ */
/* ---- Demo workspace ribbon (FTUE) — slim strip above the topbar, aligned to
   the same content measure. Accent-tinted while viewing the demo; a softer
   neutral "is-nudge" variant once the user is in their own account. ---- */
.demo-ribbon {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  padding: 10px 14px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--accent) 8%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--accent) 22%, var(--border-hair));
  font-size: 13px;
  color: var(--text-2);
}
.demo-ribbon[hidden] { display: none; }
.demo-ribbon-badge {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  padding: 3px 9px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--accent) 16%, transparent);
  color: var(--accent);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.demo-ribbon-badge[hidden] { display: none; }
.demo-ribbon-text { min-width: 0; flex: 1 1 auto; line-height: 1.4; }
.demo-ribbon-actions { flex-shrink: 0; display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }
.demo-ribbon-cta {
  appearance: none;
  border: none;
  cursor: pointer;
  padding: 6px 14px;
  border-radius: var(--r-sm);
  background: var(--accent);
  color: #fff;
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  transition: filter 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.demo-ribbon-cta:hover { filter: brightness(1.06); }
.demo-ribbon-cta:active { transform: translateY(1px); }
.demo-ribbon-cta[hidden] { display: none; }
.demo-ribbon-remove {
  appearance: none;
  cursor: pointer;
  padding: 6px 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-hair);
  background: transparent;
  color: var(--text-3);
  font-size: 12.5px;
  font-weight: 600;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out), border-color 160ms var(--ease-out);
}
.demo-ribbon-remove:hover { background: var(--surface-sunken); color: var(--text); border-color: var(--border); }
.demo-ribbon-remove[hidden] { display: none; }
.demo-ribbon-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.demo-ribbon-dismiss:hover { background: var(--surface-sunken); color: var(--text); }
.demo-ribbon-dismiss[hidden] { display: none; }
.demo-ribbon.is-nudge {
  background: var(--surface-soft);
  border-color: var(--border-hair);
}
@media (max-width: 640px) {
  .demo-ribbon { padding: 9px 12px; gap: 10px; }
  .demo-ribbon-text { flex-basis: 100%; order: 3; }
  .demo-ribbon-actions { margin-left: 0; }
}

/* ---- Cloud screenshot storage warning ribbon — amber, informational. Shown
   only when verifyScreenshotStorage() fails (bucket/policies not live). Images
   still save locally on the device, so this flags a degraded state, not data
   loss. ---- */
.storage-warning {
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 14px;
  border-radius: var(--r-md);
  background: color-mix(in srgb, var(--warn) 9%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--warn) 30%, var(--border-hair));
  font-size: 13px;
  color: var(--text-2);
}
.storage-warning[hidden] { display: none; }
.storage-warning-icon { flex-shrink: 0; display: inline-flex; color: var(--warn); }
.storage-warning-text { min-width: 0; flex: 1 1 auto; line-height: 1.4; }
.storage-warning-dismiss {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px; height: 24px;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.storage-warning-dismiss:hover { background: var(--surface-sunken); color: var(--text); }
@media (max-width: 640px) {
  .storage-warning { padding: 9px 12px; gap: 10px; }
}

/* Inline error under the Manage-subscription button (portal open failed). */
.settings-manage-error { font-size: 12.5px; color: var(--neg); margin: 8px 0 0; line-height: 1.4; }
.settings-manage-error[hidden] { display: none; }

/* Manage-subscription button loading state — instant spinner on click while the
   Billing Portal session is minted server-side. ID-scoped so it never affects
   other .settings-action buttons (which have no label/spinner spans). Mirrors the
   access-upgrade-btn pattern: the label fades and a centered spinner appears. */
#settings-manage-sub-btn { position: relative; }
#settings-manage-sub-btn .settings-action-label { transition: opacity 130ms var(--ease-out); }
#settings-manage-sub-btn.is-busy .settings-action-label { opacity: 0; }
#settings-manage-sub-btn .settings-action-spinner {
  position: absolute;
  top: 50%; left: 50%;
  width: 15px; height: 15px;
  margin: -7.5px 0 0 -7.5px;
  border-radius: 50%;
  border: 2px solid color-mix(in srgb, var(--text) 22%, transparent);
  border-top-color: var(--text);
  opacity: 0;
  transition: opacity 130ms var(--ease-out);
}
#settings-manage-sub-btn.is-busy .settings-action-spinner { opacity: 1; animation: auth-spin 720ms linear infinite; }
@media (prefers-reduced-motion: reduce) {
  #settings-manage-sub-btn.is-busy .settings-action-spinner { animation: none; }
}

/* ---- FTUE toast — brief, centered, auto-dismiss confirmation (first trade,
   demo removal). High-contrast pill; no celebration. ---- */
.ftue-toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  transform: translateX(-50%) translateY(8px);
  z-index: 4000;
  padding: 10px 18px;
  border-radius: 999px;
  background: var(--text);
  color: var(--surface);
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.005em;
  box-shadow: var(--shadow-3);
  opacity: 0;
  pointer-events: none;
  transition: opacity 220ms var(--ease-out), transform 220ms var(--ease-out);
}
.ftue-toast.is-visible { opacity: 1; transform: translateX(-50%) translateY(0); }
@media (prefers-reduced-motion: reduce) {
  .ftue-toast { transition: opacity 140ms linear; }
  .ftue-toast.is-visible { transform: translateX(-50%) translateY(0); }
}

.onboarding-card {
  padding: 18px 20px 16px;
  margin-bottom: 18px;
}
.onboarding-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.onboarding-head-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.onboarding-eyebrow {
  margin: 0;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}
.onboarding-title {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
.onboarding-complete-badge {
  display: none;
  font-size: 13px;
  font-weight: 700;
  color: var(--pos);
  letter-spacing: -0.005em;
}
.onboarding-card.is-complete .onboarding-title { display: none; }
.onboarding-card.is-complete .onboarding-complete-badge { display: inline; }
.onboarding-head-right { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }
.onboarding-progress {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.onboarding-card.is-complete .onboarding-progress { display: none; }
.onboarding-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.onboarding-dismiss:hover { background: var(--surface-sunken); color: var(--text); }

.onboarding-progress-track {
  height: 4px;
  margin: 12px 0 6px;
  border-radius: 999px;
  background: var(--surface-sunken);
  overflow: hidden;
}
.onboarding-progress-fill {
  display: block;
  height: 100%;
  width: 0%;
  border-radius: 999px;
  background: var(--accent);
  transition: width 320ms var(--ease-out);
}

/* First-run language choice — a slim segmented control so a brand-new user can
   set their language before working the checklist. Reuses the existing language
   system (the Settings select handler); no new infrastructure. */
.onboarding-lang {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px;
  margin: 6px 0 12px;
}
.onboarding-lang-label {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}
.onboarding-lang-options {
  display: inline-flex;
  gap: 4px;
  padding: 3px;
  border-radius: var(--r-md);
  background: var(--surface-sunken);
}
.onboarding-lang-btn {
  appearance: none;
  border: none;
  background: transparent;
  color: var(--text-3);
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: -0.005em;
  padding: 5px 12px;
  border-radius: var(--r-sm);
  cursor: pointer;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.onboarding-lang-btn:hover { color: var(--text); }
.onboarding-lang-btn.is-active { background: var(--accent); color: #fff; }

.onboarding-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.onboarding-item-btn {
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  padding: 10px 10px;
  border: none;
  border-radius: var(--r-md);
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 160ms var(--ease-out);
}
.onboarding-item-btn:hover { background: var(--surface-sunken); }
.onboarding-check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  flex-shrink: 0;
  border-radius: 50%;
  border: 2px solid var(--border-strong);
  color: #fff;
  transition: background 200ms var(--ease-out), border-color 200ms var(--ease-out);
}
.onboarding-check svg { opacity: 0; transition: opacity 160ms var(--ease-out); }
.onboarding-item.is-done .onboarding-check {
  background: var(--accent);
  border-color: var(--accent);
}
.onboarding-item.is-done .onboarding-check svg { opacity: 1; }
.onboarding-item-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; flex: 1; }
.onboarding-item-title {
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.005em;
}
.onboarding-item-sub { font-size: 12px; color: var(--text-3); line-height: 1.35; }
.onboarding-item.is-done .onboarding-item-title { color: var(--text-3); }
.onboarding-item-go {
  display: inline-flex;
  align-items: center;
  color: var(--text-3);
  flex-shrink: 0;
  opacity: 0.6;
  transition: transform 160ms var(--ease-out), opacity 160ms var(--ease-out);
}
.onboarding-item-btn:hover .onboarding-item-go { transform: translateX(2px); opacity: 1; }

@media (max-width: 600px) {
  .onboarding-card { padding: 16px 16px 14px; margin-bottom: 14px; }
  .onboarding-item-sub { display: none; }
  .onboarding-item-btn { padding: 11px 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .onboarding-progress-fill,
  .onboarding-check,
  .onboarding-check svg,
  .onboarding-lang-btn,
  .onboarding-item-go { transition: none; }
}

/* Desktop integration with the height-locked dashboard. Above 1180px the stage
   is one non-scrolling screen (.page-stage{overflow:clip}) and .dashboard-grid
   {flex:1 1 auto;min-height:0} absorbs all leftover height. The ~280px onboarding
   card would otherwise squeeze that grid below its internal floors — the
   edge-stack (hourly 141 + weekday 178) overflows its cell and the
   calendar/recent-trades fall off the clipped stage (the "squashed / unfinished"
   look). While the card is present we let THIS page scroll (never the shared
   stage) and hold the grid at a comfortable height, so every card keeps its real
   proportions and you simply scroll past the checklist to a normal dashboard.
   Grid rows stay minmax(0,fr) of a definite height — never content-sized — so the
   recent-trades ResizeObserver can't enter the row-grow feedback loop. Reverts
   the instant the card is dismissed (:has stops matching) → back to the locked
   single-screen layout. scrollbar-gutter keeps width stable (no CLS) on classic
   scrollbars; a no-op under macOS overlay scrollbars. ≤1180px already scrolls
   with a content-height grid, so this is desktop-only and never touches it. */
@media (min-width: 1181px) {
  .page-dashboard:has(#onboarding-card:not([hidden])) {
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-gutter: stable;
  }
  /* The card is a flex child of the height-locked column; holding the grid at
     720px creates a height deficit that the flex algorithm would otherwise
     absorb by shrinking THIS card (default flex-shrink:1) — and .card{overflow
     :hidden} would then clip the checklist. Pin it so it keeps full height and
     the deficit becomes scroll instead. */
  .page-dashboard:has(#onboarding-card:not([hidden])) .onboarding-card {
    flex-shrink: 0;
  }
  .page-dashboard:has(#onboarding-card:not([hidden])) .dashboard-grid {
    min-height: 720px;
  }
  /* fitDashboard's zoom has a 0.5 readability floor. On very short desktop
     viewports (≈1280×720) even the floor can't fit everything — scroll the
     few leftover px instead of clipping them. Class applied by fitDashboard. */
  .page-dashboard.is-fit-overflow {
    overflow-y: auto;
    overflow-x: hidden;
    scrollbar-gutter: stable;
  }
}

/* ============================================================
   Retention prompts — daily review / weekly review / risk limit
   ============================================================ */

.retention-prompt {
  padding: 12px 16px;
  margin-bottom: 12px;
  /* Flex child of the height-locked dashboard column. Without this pin the flex
     algorithm absorbs any height deficit (onboarding card + 720px grid floor) by
     crushing THESE banners first — the daily prompt collapsed to ~26px and its
     content visually bled into the "Getting started" card below. Same reasoning
     as the .onboarding-card pin: keep natural height, let the page scroll. */
  flex-shrink: 0;
}
.retention-prompt[hidden] { display: none; }

.rp-body {
  display: flex;
  align-items: center;
  gap: 12px;
}

.rp-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--r-sm);
  background: var(--accent-faint, rgba(23,136,201,.10));
  color: var(--accent);
  flex-shrink: 0;
}
.rp-icon-warn {
  background: rgba(201, 120, 30, .12);
  color: var(--warn, #c97820);
}
:root[data-theme="dark"] .rp-icon-warn {
  background: rgba(230, 155, 60, .14);
  color: #e69b3c;
}
:root[data-theme="dark"] .rp-risk .rp-title {
  color: #e69b3c;
}

.rp-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  flex: 1 1 0;
  min-width: 0;
}
.rp-title {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.005em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.rp-risk .rp-title { color: var(--warn, #c97820); }
.rp-sub {
  font-size: 12px;
  color: var(--text-3);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.rp-cta {
  flex-shrink: 0;
}
/* pill-sm size variant used only here */
.pill.pill-sm {
  padding: 5px 12px;
  font-size: 12px;
  height: auto;
}

.rp-dismiss {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  padding: 0;
  border: none;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  flex-shrink: 0;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.rp-dismiss:hover { background: var(--surface-sunken); color: var(--text); }

@media (max-width: 600px) {
  .retention-prompt { padding: 10px 12px; margin-bottom: 10px; }
  .rp-cta { display: none; }
  .rp-sub { display: none; }
  .rp-title { white-space: normal; }
}

/* ============================================================
   Journal page
   ============================================================ */

.page-journal {
  padding-top: 2px;
}

.jp-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 4px 2px 2px;
}

.jp-sub {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.005em;
}
.jp-sub strong { color: var(--text-2); font-weight: 700; }

.jp-new-btn {
  padding: 8px 14px;
  border-radius: 11px;
}

.jp-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(248px, 1fr));
  gap: 12px;
  overflow-y: auto;
  flex: 1;
  min-height: 0;
  padding: 2px 0 4px;
  align-content: start;
  scrollbar-gutter: stable;
}

.jp-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 16px;
  padding: 14px 16px 12px;
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: 9px;
  transition:
    transform 200ms var(--ease-out),
    box-shadow 200ms var(--ease-out),
    border-color 200ms var(--ease-out);
}
.jp-card:hover {
  transform: translateY(-2px);
  box-shadow: 0 6px 24px rgba(15, 17, 21, 0.08), 0 2px 4px rgba(15, 17, 21, 0.04);
  border-color: var(--border-strong);
}
:root[data-theme="dark"] .jp-card:hover {
  box-shadow: 0 6px 24px rgba(0, 0, 0, 0.35), 0 2px 4px rgba(0, 0, 0, 0.20);
}

.jp-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.jp-card-date {
  font-size: 13px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.005em;
}
.jp-card-weekday {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.jp-card-pnl {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  margin-top: 1px;
}
.jp-card-pnl.pos { color: var(--pos); }
.jp-card-pnl.neg { color: var(--neg); }
.jp-card-pnl.flat { color: var(--text-3); }

.jp-card-stats {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: var(--text-3);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.jp-card-stats .dot { width: 3px; height: 3px; border-radius: 50%; background: var(--text-4); }

.jp-card-tfs {
  display: flex;
  gap: 4px;
  margin-top: 2px;
}
.jp-card-tf {
  flex: 1;
  height: 28px;
  border-radius: 7px;
  background: var(--surface-sunken);
  display: grid;
  place-items: center;
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-4);
  letter-spacing: 0.04em;
  position: relative;
  overflow: hidden;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out);
}
.jp-card-tf.filled {
  background: var(--pos-soft);
  color: var(--pos);
}
.jp-card-tf.filled::after {
  content: '';
  position: absolute;
  top: 5px;
  right: 5px;
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: var(--pos);
}

.jp-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 80px 20px;
  color: var(--text-3);
  font-size: 13px;
}
.jp-empty[hidden] { display: none; }
.tp-empty[hidden] { display: none; }
.jp-empty-icon {
  display: grid;
  place-items: center;
  width: 48px; height: 48px;
  border-radius: 14px;
  background: var(--surface-sunken);
  color: var(--text-4);
}
/* Premium zero-state — mirrors the Trades activation block (.tp-empty-cta). */
.jp-empty-title {
  margin: 6px 0 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.jp-empty-sub {
  margin: 0;
  max-width: 380px;
  text-align: center;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text-3);
}
.jp-empty-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 10px;
}

/* Journal entry modal */
.je-panel { width: min(820px, 94vw); }

.je-head { padding: 18px 22px 14px; }
.je-head-left { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.je-meta {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.je-body {
  padding: 4px 22px 12px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  overflow-y: auto;
  max-height: 70vh;
}

.je-section { display: flex; flex-direction: column; gap: 8px; }
.je-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.je-section-label {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.je-section-meta {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.je-section-meta.saved { color: var(--pos); }

/* Timeframe screenshot slots */
.je-slots {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
}

.je-slot {
  position: relative;
  border-radius: 12px;
  background: var(--surface-sunken);
  border: 1.5px dashed var(--border-strong);
  aspect-ratio: 4 / 3;
  display: flex;
  flex-direction: column;
  align-items: stretch;
  cursor: pointer;
  overflow: hidden;
  transition: border-color 160ms var(--ease-out), background 160ms var(--ease-out), transform 160ms var(--ease-out);
}
.je-slot:hover {
  border-color: var(--pos);
  background: var(--pos-soft);
}
.je-slot.is-dragover {
  border-color: var(--pos);
  background: var(--pos-soft);
  transform: scale(1.02);
}
.je-slot.has-image {
  border-style: solid;
  border-color: var(--border);
  background: var(--surface);
}
.je-slot.has-image:hover {
  border-color: var(--pos);
}

.je-slot-label {
  position: absolute;
  top: 6px;
  left: 8px;
  padding: 2px 7px;
  border-radius: 6px;
  background: rgba(15, 17, 21, 0.55);
  color: #FFFFFF;
  font-family: var(--mono);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  z-index: 2;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.je-slot-empty {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 600;
  text-align: center;
  padding: 14px 8px 8px;
}
.je-slot-empty svg { color: var(--text-4); }
.je-slot:hover .je-slot-empty,
.je-slot:hover .je-slot-empty svg { color: var(--pos); }

.je-slot-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.je-slot-actions {
  position: absolute;
  top: 6px;
  right: 6px;
  display: flex;
  gap: 4px;
  opacity: 0;
  transition: opacity 160ms var(--ease-out);
  z-index: 2;
}
.je-slot.has-image:hover .je-slot-actions { opacity: 1; }
.je-slot-btn {
  width: 24px;
  height: 24px;
  border-radius: 6px;
  background: rgba(15, 17, 21, 0.65);
  color: #FFFFFF;
  display: grid;
  place-items: center;
  cursor: pointer;
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  transition: background 140ms var(--ease-out);
}
.je-slot-btn:hover { background: rgba(15, 17, 21, 0.85); }

.je-notes {
  width: 100%;
  resize: vertical;
  min-height: 100px;
  max-height: 260px;
  font: inherit;
  font-family: var(--font);
  font-size: 13px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 11px 13px;
  transition: border-color 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
.je-notes:focus {
  outline: none;
  border-color: var(--pos);
  box-shadow: var(--shadow-focus);
}

/* ============================================================
   Trade detail modal
   ============================================================ */

/* Trade modal backdrop — keeps the same smooth ramp animation as the
   day modal but ends at a stronger blur for the bigger panel. */
.td-modal .day-modal-backdrop {
  background: rgba(10, 13, 18, 0.0);
}
/* Trade-detail scrim — the Trades ledger dims + blurs behind the panel like the
   day modal. The tint lives here on the backdrop (snaps in on open); the blur
   lives on the ::after below and fades in via opacity — a cheap composite of the
   cached blur, never an animated radius. Both engage at open so the page behind
   goes dim+blurred immediately. Keeping tint and blur on separate layers lets the
   blur snap OFF instantly on close (its base rule carries no transition), with no
   "screen stays blurred for a beat" lag. The .td-modal selector's extra class
   beats the generic .day-modal rule (whose blur would otherwise double up here). */
.day-modal.td-modal.is-open .day-modal-backdrop {
  background: rgba(10, 13, 18, 0.42);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  transition: none;
}
:root[data-theme="dark"] .day-modal.td-modal.is-open .day-modal-backdrop {
  background: rgba(5, 8, 14, 0.62);
}
/* Blur layer. backdrop-filter lives on this overlay so we can fade it via
   opacity (cheap composite of the cached blur) rather than animating the blur
   radius (expensive). Inert until .td-blur-armed is set — openTradeDetail arms it
   on the frame after open, so the blur fades in with the panel's rise. */
.td-modal .day-modal-backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  /* No transition on the base state → the blur snaps OFF instantly on close
     (no "screen stays blurred for a beat" lag). The fade-in transition lives on
     the armed rule below, so it only eases the blur IN, never out. */
}
.day-modal.td-modal.is-open.td-blur-armed .day-modal-backdrop::after {
  opacity: 1;
  transition: opacity 260ms var(--ease-out);
}

.td-modal .day-modal-panel {
  transform: translateY(32px) scale(0.955);
  transform-origin: center 62%;
  /* Fast CLOSE so the review panel snaps away and the rows return at once; the
     eased OPEN is inherited from the generic .is-open panel rule (~300ms). */
  transition:
    transform 185ms cubic-bezier(0.4, 0, 1, 1),
    opacity 140ms ease;
}

.td-modal.is-open .day-modal-panel {
  transform: translateY(0) scale(1);
  /* Keep the panel on its own compositor layer for as long as the modal is open
     (not just during the open transform). The hero count-ups repaint the panel
     every frame for ~1s; an independent panel layer means those repaints never
     invalidate the backdrop-filter layer behind it, so the blur rasters once and
     stays cached instead of re-sampling the ledger each frame. */
  will-change: transform;
}

.td-panel {
  width: min(1220px, 96vw);
  border-radius: 24px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 96%, var(--surface-sunken)), var(--surface));
}

.td-body {
  display: block;
  overflow-y: auto;
  max-height: 87vh;
  background:
    linear-gradient(180deg, var(--surface-sunken) 0%, color-mix(in srgb, var(--surface-sunken) 92%, var(--surface)) 100%);
}
/* DARK: keep the body a hair below the panel/cards as a COHESIVE recess — not the
   raw --surface-sunken, which on the deepened dark palette is near the page bg and
   read like the background bleeding through, fracturing the modal into separate
   floating cards. This restores one continuous elevated surface (mirrors the
   light theme, where surface-sunken already sits just under the surface). */
:root[data-theme="dark"] .td-body {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--surface) 80%, var(--surface-sunken)) 0%,
    color-mix(in srgb, var(--surface) 92%, var(--surface-sunken)) 100%);
}

.td-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(360px, 0.78fr);
  gap: 14px;
  padding: 13px 14px;
}

.td-main,
.td-aside {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
}

.td-section-pad {
  padding: 18px 20px;
  border: 1px solid var(--border-hair);
  border-radius: 18px;
  background: var(--surface);
}
.td-section-pad + .td-section-pad { border-top: 1px solid var(--border-hair); }

/* Trade modal screenshot slots — refined empty/selected/has-image states.
   Visually distinct from journal slots: thinner dashed border, smaller TF
   badge, calmer hover, and a more confident "selected, ready for paste"
   state. The behaviour (single-click selects, CMD+V pastes, double-click
   opens picker) is unchanged. */
.td-slots {
  gap: 10px;
}
.td-slots .je-slot {
  aspect-ratio: 4 / 3;
  border-radius: 13px;
  border: 1px dashed color-mix(in srgb, var(--border-strong) 70%, transparent);
  background: color-mix(in srgb, var(--surface-sunken) 55%, var(--surface));
  transition:
    border-color 180ms var(--ease-out),
    background 180ms var(--ease-out),
    transform 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
}
.td-slots .je-slot:hover {
  border-color: var(--border-strong);
  background: color-mix(in srgb, var(--text) 4%, var(--surface));
  transform: translateY(-1px);
}
.td-slots .je-slot.has-image {
  border-style: solid;
  border-color: var(--border);
  background: var(--surface);
  box-shadow: 0 4px 14px -10px rgba(15,17,21,0.12);
}
.td-slots .je-slot.has-image:hover {
  border-color: var(--border-strong);
  box-shadow: 0 8px 22px -12px rgba(15,17,21,0.20);
}
.td-slots .je-slot.is-selected {
  border-color: var(--text);
  border-style: solid;
  background: color-mix(in srgb, var(--text) 5%, var(--surface));
  box-shadow:
    0 0 0 3px color-mix(in srgb, var(--text) 10%, transparent),
    0 4px 12px -8px color-mix(in srgb, var(--text) 18%, transparent);
}
.td-slots .je-slot-label {
  top: 7px;
  left: 8px;
  padding: 2px 7px;
  font-size: 9px;
  font-weight: 800;
  letter-spacing: 0.06em;
  background: rgba(15, 17, 21, 0.6);
  border-radius: 5px;
  text-transform: uppercase;
}
/* Empty-state — quieter, more intentional. No "drop here" implication; the
   slot reads as a placeholder waiting to be filled rather than an upload
   widget. Hover bumps the icon to pos to invite the click. */
.td-slots .je-slot-empty {
  gap: 9px;
  padding: 0;
  color: var(--text-4);
}
/* Empty trade slots show the timeframe centred, so suppress the dark overlay
   badge — it only reads well sitting over a filled screenshot. */
.td-slots .je-slot:not(.has-image) .je-slot-label { display: none; }
/* The content box must fill the slot so the empty-state +/timeframe pair sits
   dead-centre. Without this it collapses to its own height and clings to the
   top edge, leaving a dead gap below (the off-centre look the user flagged). */
.td-slots .je-slot-content {
  flex: 1;
  display: flex;
  min-height: 0;
}
.td-slots .td-slot-add {
  display: grid;
  place-items: center;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: color-mix(in srgb, var(--text) 5%, transparent);
  color: var(--text-3);
  transition:
    background 180ms var(--ease-out),
    color 180ms var(--ease-out),
    transform 180ms var(--ease-out);
}
.td-slots .td-slot-tf {
  font-family: var(--mono);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  color: var(--text-3);
  transition: color 180ms var(--ease-out);
}
.td-slots .je-slot:hover .td-slot-add {
  background: color-mix(in srgb, var(--text) 9%, transparent);
  color: var(--text);
  transform: translateY(-1px);
}
.td-slots .je-slot:hover .td-slot-tf { color: var(--text-2); }
.td-slots .je-slot.is-selected .td-slot-add {
  background: color-mix(in srgb, var(--text) 12%, transparent);
  color: var(--text);
}
.td-slots .je-slot.is-selected .td-slot-tf { color: var(--text); }
/* Filled-slot fullscreen affordance — a clear, clickable zoom button centered
   over the preview. A single click opens the fullscreen viewer (double-click
   and ✕/Escape still work too). Only the button intercepts clicks, so selecting
   the slot for paste elsewhere on it still works. */
.td-slots .je-slot .td-slot-zoom {
  position: absolute;
  left: 50%;
  top: 50%;
  transform: translate(-50%, -50%) scale(0.9);
  z-index: 2;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  color: #fff;
  background: rgba(12, 14, 19, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.28);
  backdrop-filter: blur(2px);
  -webkit-backdrop-filter: blur(2px);
  opacity: 0;
  pointer-events: auto;
  cursor: zoom-in;
  transition:
    opacity 160ms var(--ease-out),
    transform 200ms cubic-bezier(.34, 1.56, .64, 1),
    background 160ms var(--ease-out);
}
.td-slots .je-slot.has-image:hover .td-slot-zoom { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.td-slots .je-slot .td-slot-zoom:hover { background: rgba(12, 14, 19, 0.85); }
.td-slots .je-slot .td-slot-zoom:active { transform: translate(-50%, -50%) scale(0.92); }
.td-slots .je-slot .td-slot-zoom svg { filter: drop-shadow(0 2px 6px rgba(0,0,0,0.55)); pointer-events: none; }

/* ============================================================
   Trade screenshot lightbox — fullscreen viewer with zoom + nav.
   Sits above the trade modal (z 100). Monochrome chrome on a dark
   scrim so the chart image is the only focus. Opened by double-
   clicking a filled slot; closes on scrim click / ✕ / Escape.
   ============================================================ */
.td-lightbox {
  position: fixed;
  inset: 0;
  z-index: 400;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 56px 72px;
  background: rgba(8, 10, 14, 0.86);
  backdrop-filter: blur(7px) saturate(118%);
  -webkit-backdrop-filter: blur(7px) saturate(118%);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 220ms var(--ease-out), visibility 0ms linear 220ms;
}
.td-lightbox.is-open {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition: opacity 220ms var(--ease-out), visibility 0ms linear 0ms;
}
.td-lb-stage {
  position: relative;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  border-radius: 12px;
}
.td-lb-img {
  display: block;
  /* Show the image at full available size (was capped at 1400px, which threw
     away the new high-resolution uploads). The stage padding bounds it, and
     zoom now reveals real detail because the stored image is sharp. */
  max-width: 100%;
  max-height: calc(100vh - 112px);
  width: auto;
  height: auto;
  object-fit: contain;
  border-radius: 12px;
  box-shadow: 0 30px 80px -28px rgba(0,0,0,0.7);
  transform: scale(1);
  transform-origin: center center;
  transition: transform 160ms var(--ease-out);
  cursor: zoom-in;
  user-select: none;
  -webkit-user-drag: none;
}
.td-lightbox.is-zoomed .td-lb-img {
  cursor: grab;
  transition: none;
}
/* While sliding between frames or following a swipe, the transform is driven
   directly (WAAPI / inline) — the 160ms ease would smear the finger-follow. */
.td-lightbox.is-sliding .td-lb-img {
  transition: none;
  cursor: grabbing;
}
/* Floating control chrome — glass pills, monochrome. */
.td-lb-nav,
.td-lb-close,
.td-lb-fullscreen,
.td-lb-zoom {
  position: absolute;
  z-index: 2;
  background: rgba(20, 23, 30, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.12);
  color: rgba(255, 255, 255, 0.92);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  transition: background 160ms var(--ease-out), border-color 160ms var(--ease-out), transform 160ms var(--ease-out), opacity 160ms var(--ease-out);
}
.td-lb-nav {
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.td-lb-prev { left: 18px; }
.td-lb-next { right: 18px; }
.td-lb-nav:hover {
  background: rgba(32, 36, 46, 0.92);
  border-color: rgba(255, 255, 255, 0.22);
  transform: translateY(-50%) scale(1.06);
}
.td-lb-nav:active { transform: translateY(-50%) scale(0.96); }
.td-lb-close {
  top: 18px;
  right: 18px;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.td-lb-close:hover {
  background: rgba(32, 36, 46, 0.92);
  border-color: rgba(255, 255, 255, 0.22);
  transform: rotate(90deg);
}
/* Fullscreen toggle — top-right, just left of the close button. */
.td-lb-fullscreen {
  top: 18px;
  right: 66px;
  width: 40px;
  height: 40px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  cursor: pointer;
}
.td-lb-fullscreen:hover {
  background: rgba(32, 36, 46, 0.92);
  border-color: rgba(255, 255, 255, 0.22);
  transform: scale(1.07);
}
.td-lb-fullscreen:active { transform: scale(0.95); }
/* Timeframe + position readout, top-left. */
.td-lb-bar {
  position: absolute;
  top: 18px;
  left: 18px;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 7px 13px;
  border-radius: 11px;
  background: rgba(20, 23, 30, 0.62);
  border: 1px solid rgba(255, 255, 255, 0.12);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.td-lb-tf {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.06em;
  color: #fff;
}
.td-lb-count {
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: rgba(255, 255, 255, 0.6);
  font-variant-numeric: tabular-nums;
}
/* Zoom cluster, bottom-center. */
.td-lb-zoom {
  bottom: 18px;
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: 2px;
  padding: 4px;
  border-radius: 12px;
}
.td-lb-zoom button {
  height: 32px;
  min-width: 36px;
  padding: 0 8px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  color: rgba(255, 255, 255, 0.9);
  font-size: 11.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.01em;
  cursor: pointer;
  transition: background 140ms var(--ease-out);
}
.td-lb-zoom button:hover { background: rgba(255, 255, 255, 0.12); }
.td-lb-zoom button:active { background: rgba(255, 255, 255, 0.18); }
#td-lb-zoom-level { min-width: 50px; }
/* Hide nav arrows when there's only one screenshot to page through. */
.td-lightbox.is-single .td-lb-nav { display: none; }

.td-head {
  padding: 15px 26px 13px;
  gap: 16px;
  background:
    radial-gradient(circle at 14% 0%, rgba(92, 200, 255, 0.08), transparent 42%),
    linear-gradient(180deg, var(--surface) 0%, color-mix(in srgb, var(--surface) 97%, var(--surface-sunken)) 100%);
  border-bottom: 1px solid var(--border-hair);
}
.td-head-left { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.td-head-right {
  display: flex;
  align-items: stretch;
  gap: 12px;
}

.td-title {
  display: flex;
  align-items: center;
  gap: 11px;
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.015em;
}
.td-sym {
  font-family: inherit;
  font-size: 19px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.td-side-tag {
  font-size: 10.5px;
  font-weight: 750;
  padding: 3px 9px;
  border-radius: 6px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}
/* Side tag is neutral — Long/Short reads as a quiet category, never colour.
   Only the P&L hero carries tone. */
.td-side-tag.long,
.td-side-tag.short {
  background: color-mix(in srgb, var(--text-3) 8%, transparent);
  color: var(--text);
}
.td-side-tag::before {
  content: '';
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: currentColor;
}

.td-meta {
  font-size: 12px;
  font-weight: 550;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.003em;
}

/* ------------------------------------------------------------------
   Result hero band — the emotional centerpiece of the trade detail.
   Spans the full width at the top of the left column so the outcome is
   the first thing the eye lands on: a large tone-coloured Net P&L on the
   left, an R-multiple meter on the right. Tone (pos/neg) fills the band's
   gradient, border and accents.
   ------------------------------------------------------------------ */
.td-result {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding: 12px 22px 13px;
  border: 1px solid var(--border-hair);
  border-radius: 16px;
  background: linear-gradient(180deg, var(--surface-elevated, var(--surface)), var(--surface-soft));
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.35),
    0 10px 28px -18px rgba(15, 17, 21, 0.20);
  position: relative;
  overflow: hidden;
}
:root[data-theme="dark"] .td-result {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.05),
    0 14px 34px -18px rgba(0, 0, 0, 0.6);
}
/* A soft tone glow bleeds in from the right so the band feels lit by the
   result without washing the numbers out. */
.td-result::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 200ms var(--ease-out);
}
.td-result.pos {
  border-color: color-mix(in srgb, var(--pos) 26%, transparent);
  background: linear-gradient(110deg, color-mix(in srgb, var(--pos-soft) 30%, var(--surface)) 0%, color-mix(in srgb, var(--pos-soft) 9%, var(--surface-soft)) 62%, var(--surface-soft) 100%);
}
.td-result.neg {
  border-color: color-mix(in srgb, var(--neg) 26%, transparent);
  background: linear-gradient(110deg, color-mix(in srgb, var(--neg-soft) 30%, var(--surface)) 0%, color-mix(in srgb, var(--neg-soft) 9%, var(--surface-soft)) 62%, var(--surface-soft) 100%);
}
.td-result.pos::after {
  opacity: 1;
  background: radial-gradient(120% 140% at 100% 50%, color-mix(in srgb, var(--pos) 12%, transparent), transparent 60%);
}
.td-result.neg::after {
  opacity: 1;
  background: radial-gradient(120% 140% at 100% 50%, color-mix(in srgb, var(--neg) 12%, transparent), transparent 60%);
}
.td-result-lead { position: relative; z-index: 1; display: flex; flex-direction: column; gap: 4px; }
.td-result-cap {
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-3);
}
.td-result-amount-row { display: flex; align-items: center; gap: 12px; }
.td-hero-amount {
  font-size: 35px;
  font-weight: 850;
  letter-spacing: -0.03em;
  line-height: 0.95;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.td-hero-amount.pos { color: var(--pos); }
.td-hero-amount.neg { color: var(--neg); }
.td-result-verdict {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: 7px;
  align-self: center;
}
.td-result.pos .td-result-verdict {
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 14%, transparent);
}
.td-result.neg .td-result-verdict {
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 14%, transparent);
}
.td-result-rmeter {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 190px;
}
.td-result-rhead { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.td-hero-r {
  font-family: var(--mono);
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.01em;
  line-height: 1;
  color: var(--text-2);
}
.td-result.pos .td-hero-r { color: var(--pos); }
.td-result.neg .td-hero-r { color: var(--neg); }
/* Pin each count-up onto its own compositor layer with contained paint. The
   Net-P&L and R-multiple tally up over ~1s, rewriting their text every frame;
   isolating them keeps that repaint on a tiny private layer so it never dirties
   the panel or the backdrop blur behind it (which would otherwise re-sample the
   ledger each frame). tabular-nums already fixes the glyph box so the layer
   never resizes mid-count. */
.td-hero-amount,
.td-hero-r {
  transform: translateZ(0);
  contain: paint;
}
.td-result-rbar {
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text) 8%, transparent);
  overflow: hidden;
}
.td-result-rfill {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  border-radius: 999px;
  background: var(--text-3);
  transition: transform 900ms var(--ease-emphasized);
}
.td-result.pos .td-result-rfill { background: var(--pos); }
.td-result.neg .td-result-rfill { background: var(--neg); }

/* Premium stats grid — the trade story at a glance. Border-grid trick keeps
   cells visually unified (single 1px hairline matrix, no doubled borders);
   the top row (Opened/Closed/Duration/Contracts) is timing, the bottom row
   (Entry/Exit/Stop/Risk) is pricing. A horizontal accent rule between the
   two rows reinforces that grouping. Cell padding is intentionally generous
   so the values read as institutional terminal data, not a form readout. */
.td-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 1px;
  padding: 1px;
  border: 1px solid var(--border-hair);
  border-radius: 14px;
  background: var(--border-hair);
  overflow: hidden;
  position: relative;
}
/* Stronger separator between the timing row (top 4) and the pricing row
   (bottom 4) so the eye reads two semantic blocks instead of an 8-cell
   undifferentiated grid. Pure CSS, no DOM change. */
.td-grid::after {
  content: '';
  position: absolute;
  left: 8%;
  right: 8%;
  top: calc(50% - 1px);
  height: 2px;
  background: var(--border-hair);
  pointer-events: none;
}
.td-stat {
  padding: 9px 14px 8px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  border: 0;
  border-radius: 0;
  background: var(--surface);
  transition: background 180ms var(--ease-out);
  position: relative;
}
/* Override the legacy nth-of-type borders — the new grid uses a single
   border-grid trick so the cells form a continuous matrix without visible
   double-lines. */
.td-stat:nth-child(even) { border-right: 0; }
.td-stat:nth-last-child(-n+2) { border-bottom: 0; }
.td-stat:hover {
  background: color-mix(in srgb, var(--surface-soft) 75%, var(--surface));
}

.td-stat-label {
  font-size: 9px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  /* Subtle leading dot for label rhythm — quiet at default, more visible
     on hover. Reads like a terminal field marker. */
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.td-stat-label::before {
  content: '';
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--text-4);
  flex-shrink: 0;
  opacity: 0.6;
  transition: opacity 160ms var(--ease-out), background 160ms var(--ease-out);
}
.td-stat:hover .td-stat-label::before {
  opacity: 1;
  background: var(--text-3);
}
.td-stat-value {
  font-size: 15px;
  font-weight: 750;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.012em;
  color: var(--text);
  line-height: 1.15;
}
/* Every stat value shares ONE typeface. The price cells used to switch to a
   monospace face, which read as a jarring second font next to Duration /
   Contracts. tabular-nums on .td-stat-value already keeps the digits aligned. */

/* Entry / Stop are editable: the input is styled to read exactly like the
   read-only stat values, with a quiet dashed underline that solidifies to the
   accent on focus so the field is discoverable without shouting. */
.td-stat-input {
  width: 100%;
  margin: 0;
  padding: 1px 0;
  font-family: inherit;
  background: transparent;
  border: 0;
  border-bottom: 1px dashed transparent;
  border-radius: 0;
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: textfield;
  outline: none;
  transition: border-color 150ms var(--ease-out);
}
.td-stat-input::-webkit-outer-spin-button,
.td-stat-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.td-stat-input::placeholder { color: var(--text-3); opacity: 1; font-weight: 600; }
.td-stat-edit:hover .td-stat-input { border-bottom-color: var(--border-hair); }
.td-stat-input:focus { border-bottom-color: var(--accent); }

.td-section { padding: 14px 22px 6px; }
/* Right panel — Execution review surface. Subtle horizontal gradient gives
   the panel a real "journal page" feel rather than an info-card grey. */
.td-review-panel {
  height: 100%;
  padding: 14px 16px 16px;
  border: 1px solid var(--border-hair);
  border-radius: 16px;
  /* White page. The review is structured by light-grey sub-cards (overview +
     the three sections) sitting on this white with white gaps between them, so
     each block is clearly its own compartment and the page never reads grey. */
  background: var(--surface);
}
.td-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
  padding-bottom: 7px;
  border-bottom: 1px solid var(--border-hair);
}
.td-section-label {
  font-size: 11px;
  font-weight: 800;
  color: var(--text);
  text-transform: uppercase;
  letter-spacing: 0.085em;
}
.td-section-meta {
  font-size: 10px;
  font-weight: 650;
  color: var(--text-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.td-section-meta.saved { color: var(--text-2); }
/* Tighten the gap below the "Execution review" header so the overview pills sit
   closer up under it (scoped to the review panel so the left-column section
   heads — Chart screenshots, Notes & review — keep their original spacing). */
.td-review-panel .td-section-head { margin-bottom: 4px; }

/* At-a-glance review overview — compact status pills (Rating · Confidence ·
   Plan · Main mistake) sitting above the form so the panel reads as a summary
   first. Values are wired live from the fields below via updateReviewOverview(). */
.td-rv-overview {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 6px;
  /* The at-a-glance summary is its own light-grey card too (the "Execution
     review" block), matching the three sections below it. */
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 13px;
  background: color-mix(in srgb, var(--surface-sunken) 62%, var(--surface));
  border: 1px solid var(--border-hair);
}
.td-rv-pill {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 6px 10px;
  border: 1px solid var(--border-hair);
  border-radius: 11px;
  /* White tile on the grey panel. */
  background: var(--surface);
  min-width: 0;
}
.td-rv-pill-k {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
}
.td-rv-pill-v {
  display: flex;
  align-items: center;
  gap: 4px;
  font-size: 12.5px;
  font-weight: 750;
  letter-spacing: -0.01em;
  color: var(--text);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
}
.td-rv-pill-star { color: var(--warn); flex-shrink: 0; }
.td-rv-pill.is-empty .td-rv-pill-v { color: var(--text-4); }
.td-rv-pill.is-empty .td-rv-pill-star { color: var(--text-4); }

/* Three semantic sections (Execution / Context / Psychology), each its own
   soft light-grey card on the white page. A clear white gap (margin) between
   cards keeps the blocks visually separated so the panel never reads as one
   busy field. The controls inside stay white, so they sit a step above the
   card. */
.td-review-group {
  position: relative;
  margin-top: 12px;
  padding: 11px 12px 12px;
  border-radius: 13px;
  background: color-mix(in srgb, var(--surface-sunken) 62%, var(--surface));
  border: 1px solid var(--border-hair);
}
.td-review-group:first-of-type { margin-top: 12px; }

/* Section header — a quiet label sitting at the top-left of its card. */
.td-review-group-label {
  display: flex;
  align-items: center;
  gap: 7px;
  margin: 1px 0 10px;
  padding: 0;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
  background: none;
  border: 0;
  border-radius: 0;
  line-height: 1;
}
.td-review-group-label::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--text-4);
  flex: 0 0 auto;
}
.td-review-group-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* The Execution group puts Rating and Confidence side-by-side when there's
   room — they're paired controls and read as one ratings cluster. */
.td-review-group--execution .td-review-group-body {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: start;
  gap: 9px 12px;
}

/* In-group 2-column row — used for Setup + Plan (short selects). */
.td-review-row {
  display: grid;
  gap: 10px;
  min-width: 0;
}
.td-review-row-2 { grid-template-columns: 1fr 1fr; }

.td-review-field {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

.td-review-label {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0.085em;
  text-transform: uppercase;
}

.td-review-label strong {
  color: var(--text-2);
  font-size: 11.5px;
  font-weight: 850;
  letter-spacing: -0.005em;
  text-transform: none;
  font-variant-numeric: tabular-nums;
}

/* Inline hint inside the label — used for "multi-select" annotation on
   Emotional state. Stays quiet and small so it doesn't compete. */
.td-review-hint {
  font-size: 9px;
  font-weight: 650;
  letter-spacing: 0.04em;
  color: var(--text-4);
  text-transform: uppercase;
  margin-left: 6px;
  padding: 1px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--text-3) 8%, transparent);
}

/* Per-field "customize options" gear. A quiet affordance sitting at the right
   edge of each review-field label (Strategy, Setup, Plan, Main mistake,
   Emotional state, Entry quality). Tapping it jumps to Settings → Trading where
   that field's option list is managed, so the choices grow with the trader's
   own playbook and are kept forever. Injected by injectReviewGears(). */
.td-review-label-text {
  display: inline-flex;
  align-items: baseline;
  min-width: 0;
}
.td-opt-gear {
  align-self: center;
  flex: 0 0 auto;
  display: inline-grid;
  place-items: center;
  width: 18px;
  height: 18px;
  margin: -3px -4px -3px 8px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 6px;
  background: transparent;
  /* --text-3 (not --text-4) so the gear stays legible on the dark theme's near
     black panel while remaining quiet on light. */
  color: var(--text-3);
  cursor: pointer;
  opacity: 0.6;
  transition:
    color 140ms var(--ease-out),
    background 140ms var(--ease-out),
    opacity 140ms var(--ease-out),
    transform 260ms cubic-bezier(.34, 1.56, .64, 1);
}
.td-opt-gear svg { width: 12px; height: 12px; display: block; }
/* Brighten the gear when the field is hovered/focused so it stays discoverable
   without ever shouting for attention. */
.td-review-field:hover .td-opt-gear,
.td-review-field:focus-within .td-opt-gear { opacity: 0.9; }
.td-opt-gear:hover {
  color: var(--text);
  background: var(--surface-sunken);
  opacity: 1;
  transform: rotate(40deg) scale(1.06);
}
.td-opt-gear:active { transform: rotate(40deg) scale(0.92); }
.td-opt-gear:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent);
  outline-offset: 1px;
  opacity: 1;
}
/* Section-level gear — one per review card, pinned to the card's top-right
   corner (reuses the .td-opt-gear look). Brighter at rest than the old
   field-level gears since there's now just one per section. */
.td-sec-gear {
  position: absolute;
  top: 9px;
  right: 10px;
  margin: 0;
  opacity: 0.7;
}
.td-review-group:hover .td-sec-gear { opacity: 1; }

.td-stars {
  display: flex;
  align-items: center;
  gap: 4px;
  min-height: 34px;
  padding: 3px 5px;
  border: 1px solid var(--border-hair);
  border-radius: 11px;
  background: var(--surface);
  transition: background .35s ease, border-color .35s ease;
}

.td-stars button {
  flex: 1;
  min-width: 0;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 8px;
  color: var(--text-4);
  font-size: 16px;
  position: relative;
  transition: color 180ms var(--ease-out), background 180ms var(--ease-out), transform 180ms var(--ease-out), text-shadow 180ms var(--ease-out);
}

.td-stars button:hover,
.td-stars button.active,
.td-confidence-stars button:hover,
.td-confidence-stars button.active {
  color: var(--text);
  background: color-mix(in srgb, var(--text) 7%, transparent);
  transform: translateY(-1px);
  text-shadow: none;
}

/* Pulse feedback when a star is clicked — the star scales + glows
   briefly so the user *feels* the selection landed. JS toggles the
   `is-pulsing` class for ~420ms. */
@keyframes star-pulse {
  0%   { transform: translateY(-1px) scale(1);   }
  35%  { transform: translateY(-2px) scale(1.30); }
  70%  { transform: translateY(-1px) scale(0.96); }
  100% { transform: translateY(-1px) scale(1.10); }
}
/* The glow rides on a GPU-composited pseudo-element (opacity + transform only)
   instead of an animated box-shadow. Animating box-shadow spread repaints a
   large blurred region every frame, which is what made the stars feel like
   ~10 FPS; a transform/opacity ring is handed straight to the compositor and
   stays perfectly smooth. */
@keyframes star-glow {
  0%   { opacity: 0.85; transform: translate(-50%, -50%) scale(0.45); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(2.1); }
}
.td-stars button::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: radial-gradient(circle, var(--star-glow, color-mix(in srgb, var(--text) 26%, transparent)) 0%, transparent 70%);
  transform: translate(-50%, -50%) scale(0.45);
  opacity: 0;
  pointer-events: none;
}
.td-stars button.is-pulsing {
  animation: star-pulse 420ms cubic-bezier(.34, 1.56, .64, 1);
}
.td-stars button.is-pulsing::after {
  animation: star-glow 520ms ease-out;
}

/* Subtle wash on the whole row when any star inside is clicked — tinted
   with the current level's valence colour so the cluster reads as a single
   tactile control that *agrees* with the verdict. */
.td-stars.is-flash,
.td-confidence-stars.is-flash {
  background: color-mix(in srgb, var(--surface) 86%, var(--star-c, var(--text)));
  transition: background .35s ease;
}

/* Graduated rating feedback — the active stars take on a valence colour that
   climbs from "bad" (red) through "mediocre" (amber) to "intense" (brand
   blue), so the rating *feels* like a verdict, not just a count. The level is
   read from data-rating / data-confidence (set by setRatingUI / setConfidenceUI)
   and exposed to the glyphs + glow + flash via the --star-c custom property. */
.td-stars[data-rating="1"],  .td-stars[data-confidence="1"] { --star-c: var(--neg); }
.td-stars[data-rating="2"],  .td-stars[data-confidence="2"] { --star-c: color-mix(in srgb, var(--neg) 55%, var(--warn)); }
.td-stars[data-rating="3"],  .td-stars[data-confidence="3"] { --star-c: var(--warn); }
.td-stars[data-rating="4"],  .td-stars[data-confidence="4"] { --star-c: color-mix(in srgb, var(--pos) 80%, var(--text-3)); }
.td-stars[data-rating="5"],  .td-stars[data-confidence="5"] { --star-c: var(--pos); }
.td-stars[data-rating],      .td-stars[data-confidence]     { --star-glow: color-mix(in srgb, var(--star-c, var(--text)) 48%, transparent); }

.td-stars[data-rating] button.active,
.td-stars[data-confidence] button.active {
  color: var(--star-c, var(--text));
  background: color-mix(in srgb, var(--star-c, var(--text)) 13%, transparent);
}
/* Level 5 — "krass": the glyphs glow so a perfect rating reads as a flourish. */
.td-stars[data-rating="5"] button.active,
.td-stars[data-confidence="5"] button.active {
  text-shadow: 0 0 11px color-mix(in srgb, var(--pos) 60%, transparent);
}

.td-review-input {
  width: 100%;
  min-height: 32px;
  padding: 6px 11px;
  border: 1px solid var(--border-hair);
  border-radius: 9px;
  color: var(--text);
  background: var(--surface);
  font: inherit;
  font-size: 12.5px;
  font-weight: 620;
  letter-spacing: -0.005em;
  transition:
    border-color 160ms var(--ease-out),
    background 160ms var(--ease-out),
    box-shadow 160ms var(--ease-out);
}
.td-review-input:hover {
  background: var(--surface);
  border-color: var(--border);
}

.td-review-input:focus {
  outline: none;
  border-color: color-mix(in srgb, var(--text) 30%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 8%, transparent);
}
/* Select arrow alignment — Safari's native chevron is misaligned in tight
   selects; reduce the right padding burden so the value stays centered. */
select.td-review-input {
  padding-right: 28px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position:
    calc(100% - 14px) 50%,
    calc(100% - 10px) 50%;
  background-size: 4px 4px;
  background-repeat: no-repeat;
  -webkit-appearance: none;
  appearance: none;
}

.td-notes {
  width: 100%;
  resize: vertical;
  min-height: 132px;
  max-height: 320px;
  font: inherit;
  font-size: 13.5px;
  line-height: 1.65;
  font-family: var(--font);
  color: var(--text);
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 4px 2px;
  box-shadow: none;
  transition: none;
  caret-color: var(--text);
}
.td-notes::placeholder {
  color: var(--text-4);
  font-style: italic;
  letter-spacing: -0.003em;
  font-weight: 450;
  line-height: 1.55;
}
.td-notes:focus {
  outline: none;
  border: 0;
  box-shadow: none;
  background: transparent;
}

/* Editorial wrapper — the notes section becomes a writing surface, not a
   form field. The textarea itself is borderless and lives inside this card,
   which carries the border + focus state. Gives a more journal-like feel. */
/* Notes is ONE box — the outer .td-section-pad card. The inner shell used to
   carry its own border + background + margin-top, which stacked a second
   rounded box inside the first and left a thin strip of the outer card peeking
   above it (the "white bit above Notes" the user kept flagging). The shell is
   now a transparent flex passthrough; the card itself owns padding + focus. */
.td-notes-wrap {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 0;
  padding: 14px 22px 16px;
}
.td-notes-wrap:focus-within {
  border-color: color-mix(in srgb, var(--text) 26%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 7%, transparent);
}
.td-notes-shell {
  flex: 1;
  display: flex;
  flex-direction: column;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}
.td-notes-head {
  margin-bottom: 10px;
  padding-bottom: 0;
  border-bottom: none;
}
.td-notes-wrap .td-notes {
  flex: 1;
  max-height: none;
  min-height: 132px;
}

/* Trade review chip selectors (Emotional State, Entry Type) — premium
   semantic pills, not buttons. Each chip wears its psychological category:
   stable behaviour reads mint, variance-prone reads amber, destructive reads
   red. Idle state is a quiet 1px hairline; active state lifts into a
   tone-tinted surface with a matching inner border + a subtle "logged" dot. */
.td-review-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
/* Emotional state — a 4×2 mood grid sharing one sunken track (same light-grey
   frame the user liked on Entry quality). Multi-select; active cells light up in
   their psychological valence — good reads hellblau, variance-prone reads amber,
   destructive reads red — so the trader's headspace is legible at a glance. */
.td-review-chips--emotion {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 6px;
  /* No inner track — the section card is the grey container now; the chips ride
     on it as white tiles so each option is clearly legible (not grey-on-grey). */
  padding: 0;
  border: 0;
  background: transparent;
}
.td-review-chips--emotion .td-rv-chip {
  background: var(--surface);
  border: 1px solid var(--border-hair);
}
.td-review-chips--emotion .td-rv-chip:hover {
  background: var(--surface);
  border-color: var(--border-strong);
}
.td-rv-chip {
  min-width: 0;
  height: 28px;
  padding: 0 9px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 9px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
  background: var(--surface);
  border: 1px solid var(--border-hair);
  cursor: pointer;
  white-space: nowrap;
  user-select: none;
  letter-spacing: -0.003em;
  transition:
    color 160ms var(--ease-out),
    background 160ms var(--ease-out),
    border-color 160ms var(--ease-out),
    box-shadow 160ms var(--ease-out),
    transform 100ms var(--ease-out);
}
.td-rv-chip:hover {
  color: var(--text);
  border-color: var(--border-strong);
}
.td-rv-chip:active { transform: scale(0.97); }
/* Active — a solid ink pill. Monochrome but unmistakable: the selected
   state reads as a filled tag, never as colour-coded valence. */
.td-rv-chip.active {
  font-weight: 700;
  color: var(--surface);
  background: var(--text);
  border-color: var(--text);
  box-shadow: 0 1px 2px rgba(15,17,21,0.12);
}
.td-rv-chip.active:hover {
  color: var(--surface);
  background: color-mix(in srgb, var(--text) 88%, var(--surface));
  border-color: color-mix(in srgb, var(--text) 88%, var(--surface));
}

/* Entry quality — a single-select segmented control. Chips share one sunken
   track and stretch to equal segments; the active segment fills with ink. */
.td-review-chips--entry {
  gap: 6px;
  padding: 0;
  border: 0;
  background: transparent;
  flex-wrap: nowrap;
}
.td-review-chips--entry .td-rv-chip {
  flex: 1 1 0;
  height: 30px;
  background: var(--surface);
  border: 1px solid var(--border-hair);
}
.td-review-chips--entry .td-rv-chip:hover {
  background: var(--surface);
  border-color: var(--border-strong);
}
.td-review-chips--entry .td-rv-chip.active,
.td-review-chips--entry .td-rv-chip.active:hover {
  color: var(--surface);
  background: var(--text);
  border-color: var(--text);
}

/* Semantic valence — restores "the best part": active psychology chips wear
   their meaning. Good = hellblau, variance-prone = amber, destructive = red.
   Applies to BOTH Emotional state and Entry quality. Placed after the generic
   + entry rules so it wins on source order at equal specificity. */
.td-rv-chip.active[data-value="Calm"],
.td-rv-chip.active[data-value="Focused"],
.td-rv-chip.active[data-value="Confirmed"],
.td-review-chips--entry .td-rv-chip.active[data-value="Confirmed"] {
  color: color-mix(in srgb, var(--pos) 62%, var(--text));
  background: color-mix(in srgb, var(--pos) 15%, var(--surface));
  border-color: color-mix(in srgb, var(--pos) 40%, transparent);
}
.td-rv-chip.active[data-value="Impatient"],
.td-rv-chip.active[data-value="Tired"],
.td-rv-chip.active[data-value="Early"],
.td-rv-chip.active[data-value="Late"],
.td-review-chips--entry .td-rv-chip.active[data-value="Early"],
.td-review-chips--entry .td-rv-chip.active[data-value="Late"] {
  color: color-mix(in srgb, var(--warn) 52%, var(--text));
  background: color-mix(in srgb, var(--warn) 17%, var(--surface));
  border-color: color-mix(in srgb, var(--warn) 42%, transparent);
}
.td-rv-chip.active[data-value="FOMO"],
.td-rv-chip.active[data-value="Greedy"],
.td-rv-chip.active[data-value="Angry"],
.td-rv-chip.active[data-value="Revenge"],
.td-rv-chip.active[data-value="Forced"],
.td-review-chips--entry .td-rv-chip.active[data-value="Forced"] {
  color: color-mix(in srgb, var(--neg) 64%, var(--text));
  background: color-mix(in srgb, var(--neg) 13%, var(--surface));
  border-color: color-mix(in srgb, var(--neg) 40%, transparent);
}

/* Valence key — names the colour coding the mood + entry-quality chips use,
   the same way the table legend decodes the status dots. A selected chip
   reads instantly once the trader knows positive = composed, amber = caution,
   negative = tilt. Quiet, right-aligned, sits above the grid. */
.td-psych-key {
  /* Rides on the Psychology card's header row, just left of the section gear
     (which sits at the very top-right), so it reads as part of the heading and
     doesn't push "Emotional state" down. */
  position: absolute;
  top: 11px;
  right: 38px;
  height: 13px;
  max-width: 56%;
  display: flex;
  flex-wrap: nowrap;
  justify-content: flex-end;
  align-items: center;
  gap: 4px 12px;
  margin: 0;
}
.td-psych-key-item {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-4);
  white-space: nowrap;
}
.td-psych-key-item::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  flex: 0 0 auto;
}
.td-psych-key--good::before { background: color-mix(in srgb, var(--pos) 72%, var(--text-3)); }
.td-psych-key--warn::before { background: color-mix(in srgb, var(--warn) 78%, var(--text-3)); }
.td-psych-key--bad::before  { background: color-mix(in srgb, var(--neg) 74%, var(--text-3)); }

/* Topbar */
.topbar {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 16px;
  padding-bottom: 2px;
  /* Centred to the shared content measure so the page title + Add Trade button
     line up exactly with the capped page content below on large screens. */
  width: 100%;
  max-width: var(--content-max);
  margin-inline: auto;
}

.topbar-left { display: flex; flex-direction: column; gap: 6px; }

.page-title {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--text);
}

.last-sync {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  color: var(--text-3);
  font-weight: 500;
}

.sync-dot {
  position: relative;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #30D158;
}

/* Breathing halo via a GPU-composited pseudo-element (transform + opacity)
   instead of an infinitely-animated box-shadow spread, which repainted a
   blurred region every frame for the whole session. z-index:-1 keeps the
   halo behind the dot so only the ring shows. Visually identical pulse. */
.sync-dot::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 12px;
  height: 12px;
  border-radius: 50%;
  background: rgba(48, 209, 88, 0.18);
  transform: translate(-50%, -50%) scale(1);
  pointer-events: none;
  z-index: -1;
  animation: sync-pulse 2.4s ease-in-out infinite;
}

@keyframes sync-pulse {
  0%, 100% { opacity: 1;    transform: translate(-50%, -50%) scale(1); }
  50%      { opacity: 0.33; transform: translate(-50%, -50%) scale(1.4); }
}

/* Failed local save (e.g. localStorage quota) — a lost save must never look
   successful. Recolours the existing dot + text to the negative tone; no banner,
   no toast, just an unmistakable but calm state on the same indicator. */
.last-sync.is-error { color: var(--neg); font-weight: 600; }
.last-sync.is-error .sync-dot { background: var(--neg); }
.last-sync.is-error .sync-dot::after { background: color-mix(in srgb, var(--neg) 22%, transparent); }

.topbar-right {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* ── Backtest account chrome ──────────────────────────────────────────────
   When the active account is a backtest / replay account, the slide-out nav
   panel wears an amber "practice — not live" treatment so the context is clear
   when you open it. Amber (--warn) is deliberately distinct from the live blue
   accent. Keyed on :root[data-account-type="backtesting"], so switching back to
   a real account clears it instantly. */
.nav-backtest-badge {
  display: none;
  align-items: center;
  gap: 5px;
  margin-top: 6px;
  align-self: flex-start;
  padding: 3px 9px 3px 7px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--warn);
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--warn) 32%, transparent);
  white-space: nowrap;
}
.nav-backtest-badge::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--warn);
  flex: none;
}

:root[data-account-type="backtesting"] .nav-backtest-badge { display: inline-flex; }

/* The nav active-account block carries a matching amber edge. */
:root[data-account-type="backtesting"] .nav-account-mini {
  background: color-mix(in srgb, var(--warn) 10%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 26%, transparent);
}
:root[data-account-type="backtesting"] .nav-account-mini:hover,
:root[data-account-type="backtesting"] .top-nav-panel.account-menu-open .nav-account-mini {
  background: color-mix(in srgb, var(--warn) 14%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--warn) 32%, transparent), var(--shadow-1);
}
:root[data-account-type="backtesting"] .nav-account-label { color: var(--warn); }

.pill {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-1);
  transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out), background 160ms var(--ease-out);
}

.pill:hover {
  transform: translateY(-1px);
  box-shadow: var(--shadow-2);
}

/* Primary pill — modern light-gray treatment in light mode (was previously
   near-black which felt heavy and dated). The new light-mode look matches
   Linear / Notion / modern SaaS primary buttons: a soft light-gray
   surface with dark text and a subtle inner-shadow tactile lift, no
   gradient noise. Dark mode keeps its inverted white-on-dark treatment. */
.pill-primary {
  position: relative;
  padding: 8px 14px;
  color: var(--text);
  border: 1px solid color-mix(in srgb, var(--text) 12%, transparent);
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--surface) 70%, var(--surface-sunken)) 0%,
      color-mix(in srgb, var(--surface-sunken) 75%, var(--surface)) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(15, 17, 21, 0.04),
    0 1px 2px rgba(15, 17, 21, 0.06),
    0 4px 12px -4px rgba(15, 17, 21, 0.10);
  overflow: hidden;
  font-weight: 700;
  letter-spacing: -0.003em;
}
/* Subtle inner highlight at the top so the button reads as a tactile control,
   not a flat shape. Replaces the old white-shine sweep which only made
   sense on a dark base. */
.pill-primary::before {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: linear-gradient(180deg, rgba(255,255,255,0.45), transparent 40%);
  pointer-events: none;
  opacity: 0.7;
  transition: opacity 180ms var(--ease-out);
}
.pill-primary svg { position: relative; z-index: 1; color: var(--text); }
.pill-primary > * { position: relative; z-index: 1; }

.pill-primary:hover {
  border-color: color-mix(in srgb, var(--text) 18%, transparent);
  background:
    linear-gradient(180deg,
      var(--surface) 0%,
      color-mix(in srgb, var(--surface-sunken) 60%, var(--surface)) 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.65),
    inset 0 -1px 0 rgba(15, 17, 21, 0.05),
    0 2px 4px rgba(15, 17, 21, 0.08),
    0 8px 18px -6px rgba(15, 17, 21, 0.14);
}
.pill-primary:hover::before { opacity: 0.85; }
.pill-primary:active { transform: translateY(0); }

/* Dark-mode primary pill — keeps the high-contrast inverted treatment
   because on dark surfaces a light pill IS the most modern primary
   pattern (mirror of light-mode logic). */
:root[data-theme="dark"] .pill-primary {
  color: #0B0F18;
  border-color: rgba(0,0,0,0.18);
  background:
    linear-gradient(180deg, #F4F6FA 0%, #DFE4EC 55%, #C5CCD9 100%);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    inset 0 -1px 0 rgba(0, 0, 0, 0.10),
    0 1px 2px rgba(0, 0, 0, 0.30),
    0 6px 18px rgba(0, 0, 0, 0.35);
}
:root[data-theme="dark"] .pill-primary svg { color: #0B0F18; }
:root[data-theme="dark"] .pill-primary:hover {
  background:
    linear-gradient(180deg, #FFFFFF 0%, #ECF0F5 55%, #D2D9E3 100%);
}
:root[data-theme="dark"] .pill-primary::before {
  background: linear-gradient(180deg, rgba(255,255,255,0.55), transparent 40%);
}

.pill-disabled,
.pill-disabled:hover {
  transform: none;
  color: var(--text-3);
  background: var(--surface-sunken);
  border-color: var(--border-hair);
  box-shadow: none;
  cursor: not-allowed;
}

/* ============================================================
   Cards · base
   ============================================================ */

.card {
  background:
    linear-gradient(170deg, var(--surface), color-mix(in srgb, var(--surface) 91%, var(--surface-sunken)));
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.55),
    0 1px 4px rgba(15, 17, 21, 0.07),
    0 8px 20px rgba(15, 17, 21, 0.07);
  position: relative;
  overflow: hidden;
  opacity: 1;
  transform: translateY(0);
  /* box-shadow NOT transitioned — animating a blurred drop-shadow re-rasters it
     every frame (a WebKit paint cliff); it snaps with the transform lift instead. */
  transition: transform 220ms var(--ease-out), border-color 220ms var(--ease-out), background 220ms var(--ease-out);
  /* No permanent will-change: promoting ~110 cards to their own compositor
     layers for the whole session wastes GPU memory and can slow the very
     scroll/transition it aims to help (the same reason .page isn't promoted).
     It's hinted transiently on hover (.is-hovered). */
}

:root[data-theme="dark"] .card {
  /* A slightly brighter lit top edge + a deeper drop now that the floor is
     darker — together they make each card read as a raised material, not a
     same-tone rectangle. */
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.06),
    0 1px 5px rgba(0, 0, 0, 0.55),
    0 10px 22px rgba(0, 0, 0, 0.52);
}

.card:hover,
.card.is-hovered {
  transform: translateY(-2px);
  border-color: var(--border-strong);
  will-change: transform;
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.70),
    0 2px 8px rgba(15, 17, 21, 0.09),
    0 16px 32px rgba(15, 17, 21, 0.09);
}

:root[data-theme="dark"] .card:hover,
:root[data-theme="dark"] .card.is-hovered {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.08),
    0 2px 10px rgba(0, 0, 0, 0.62),
    0 18px 36px rgba(0, 0, 0, 0.60);
}

/* ============================================================
   KPI Row
   ============================================================ */

.kpi-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: var(--dash-gap-row);
  flex: 0 0 auto;
}

.kpi {
  padding: clamp(12px, 1.2vh, 16px) 16px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: clamp(112px, 12vh, 150px);
}

.kpi-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.kpi-label {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.kpi-meta {
  font-size: 10.5px;
  color: var(--text-4);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.kpi-chip {
  padding: 3px 7px;
  font-size: 11px;
  font-weight: 600;
  border-radius: 999px;
  background: var(--pos-soft);
  color: var(--pos);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
}

.kpi[data-sign="negative"] .kpi-chip {
  background: var(--neg-soft);
  color: var(--neg);
}

.kpi-value-wrap {
  display: flex;
  align-items: baseline;
  gap: 4px;
  font-variant-numeric: tabular-nums;
}

.kpi-currency {
  font-size: 16px;
  font-weight: 750;
  color: var(--text-2);
  letter-spacing: -0.01em;
}

.kpi-value {
  font-size: 27px;
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.05;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Hero P&L card */
.kpi-hero {
  background: var(--surface);
  border-color: var(--border);
}

/* Hero number is the largest on the row so Net P&L clearly leads the
   supporting KPIs (which stay at 27px) — hierarchy, not just colour. */
.kpi-hero .kpi-value {
  color: var(--pos);
  font-size: clamp(30px, 3.1vh, 34px);
  font-weight: 820;
}
.kpi-hero .kpi-currency { color: var(--pos); font-size: 18px; }

.kpi-hero[data-sign="negative"] {
  background: var(--surface);
  border-color: var(--border);
}

.kpi-hero[data-sign="negative"] .kpi-value,
.kpi-hero[data-sign="negative"] .kpi-currency { color: var(--neg); }

.kpi-spark {
  margin-top: auto;
  width: min(74%, 180px);
  height: 16px;
  position: relative;
  opacity: 0.82;
}

.pnl-split {
  margin-top: auto;
  display: flex;
  width: 100%;
  height: 7px;
  border-radius: 999px;
  overflow: hidden;
  background: var(--surface-sunken);
  gap: 2px;
}
.pnl-split-win,
.pnl-split-loss {
  height: 100%;
  display: block;
  width: 0;
  transition: width 1400ms var(--ease-out);
  border-radius: 999px;
}
.pnl-split-win  { background: linear-gradient(90deg, var(--pos-light), var(--pos)); }
.pnl-split-loss { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }

.pnl-months {
  margin-top: auto;
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(0, 1fr);
  gap: 5px;
  align-items: end;
  height: 34px;
}

.pnl-months .pm-col {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  height: 100%;
  justify-content: flex-end;
}

.pnl-months .pm-bar {
  width: 100%;
  border-radius: 3px;
  min-height: 3px;
  transition: height 1200ms var(--ease-out);
}
.pnl-months .pm-bar.pos { background: linear-gradient(180deg, var(--pos-light), var(--pos)); }
.pnl-months .pm-bar.neg { background: linear-gradient(180deg, var(--neg), var(--neg-deep)); }
.pnl-months .pm-bar.peak { box-shadow: 0 0 0 1.5px rgba(18, 152, 216, 0.25); }

.pnl-months .pm-label {
  font-size: 8.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.pnl-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  margin-top: 4px;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.pnl-foot-sep { opacity: 0.45; }
.pnl-foot #pnl-month-best strong, .pnl-foot #pnl-month-worst strong { font-weight: 800; }
.pnl-foot .pos { color: var(--pos); }
.pnl-foot .neg { color: var(--neg); }

.kpi-spark canvas { width: 100% !important; height: 100% !important; }

/* Winrate bar */
.winrate-bar {
  position: relative;
  height: 6px;
  background: var(--surface-sunken);
  border-radius: 999px;
  overflow: hidden;
  margin-top: auto;
}

.winrate-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  border-radius: 999px;
  transition: transform 1400ms var(--ease-emphasized);
  box-shadow: 0 0 12px color-mix(in srgb, var(--pos) 35%, transparent);
}
/* While this class is on the KPI row, all fills snap with no transition. Used
   for one frame to reset bars/ring/expectancy to zero before replaying the
   load-in animation on every return to the dashboard (see replayDashboardIntro). */
.kpi-row.kpi-replay-reset,
.kpi-row.kpi-replay-reset *,
.kpi-row.kpi-replay-reset *::before,
.kpi-row.kpi-replay-reset *::after { transition: none !important; }
.winrate-marker {
  position: absolute;
  top: -2px;
  bottom: -2px;
  left: 50%;
  width: 1px;
  background: rgba(0,0,0,0.20);
}

.kpi-foot {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11.5px;
  color: var(--text-3);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}
.kpi-foot-muted { color: var(--text-3); margin-top: auto; }

.kpi-delta {
  display: flex;
  align-items: baseline;
  gap: 3px;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  line-height: 1.3;
}
.kpi-delta-arrow {
  font-weight: 700;
  font-size: 10px;
  flex-shrink: 0;
  color: var(--text-4);
}
.kpi-delta[data-dir="pos"] .kpi-delta-arrow { color: var(--pos); }
.kpi-delta[data-dir="neg"] .kpi-delta-arrow { color: var(--neg); }
.kpi-delta-val {
  font-weight: 600;
  color: var(--text-2);
  flex-shrink: 0;
}
.kpi-delta-lbl {
  color: var(--text-4);
  overflow: hidden;
  text-overflow: ellipsis;
}

.dot {
  display: inline-block;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  margin-left: 4px;
  margin-right: 2px;
}
.dot:first-child { margin-left: 0; }
.dot-pos { background: var(--pos); }
.dot-neg { background: var(--neg); }

/* Ring (profit factor) */
.ring-wrap {
  display: grid;
  grid-template-columns: 50px 1fr;
  gap: 9px;
  align-items: center;
  margin-top: auto;
}

.ring {
  width: 50px;
  height: 50px;
  transform: rotate(-90deg);
}

.ring-track {
  fill: none;
  stroke: var(--surface-sunken);
  stroke-width: 8;
}

.ring-progress {
  fill: none;
  stroke: url(#ring-grad);
  stroke: var(--pos);
  stroke-width: 8;
  stroke-linecap: round;
  stroke-dasharray: 213.6;
  stroke-dashoffset: 213.6;
  transition: stroke-dashoffset 1600ms var(--ease-out);
}

.ring-legend {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.ring-legend > div {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.ring-legend small {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 500;
  font-variant-numeric: tabular-nums;
}

.bar-mini {
  display: block;
  height: 4px;
  border-radius: 999px;
  background: var(--text-3);
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 1200ms var(--ease-out) 300ms;
}
.bar-pos { background: linear-gradient(90deg, var(--pos-light), var(--pos)); }
.bar-neg { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }

/* Win/Loss pair — two tinted "tiles" inside the Avg Trade KPI card.
   The previous divider was a 1px hairline that didn't read against
   either light or dark surfaces; this version uses subtle tinted
   backgrounds + a gradient divider so the split is immediately legible. */
.winloss-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  gap: 6px;
}

.wl-block {
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  padding: 8px 6px;
  position: relative;
  text-align: center;
  border-radius: 9px;
  background: color-mix(in srgb, var(--surface-soft) 55%, transparent);
  border: 1px solid var(--border-hair);
  transition: background 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.wl-block.wl-win {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--pos-soft) 75%, transparent),
      color-mix(in srgb, var(--pos-soft) 25%, transparent));
  border-color: color-mix(in srgb, var(--pos) 22%, transparent);
}
.wl-block.wl-loss {
  background:
    linear-gradient(180deg,
      color-mix(in srgb, var(--neg-soft) 75%, transparent),
      color-mix(in srgb, var(--neg-soft) 25%, transparent));
  border-color: color-mix(in srgb, var(--neg) 22%, transparent);
}
/* Center divider that bridges the two tiles — a stronger vertical line
   with a subtle gradient so it reads even on tinted backgrounds. */
.winloss-pair::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 14%;
  bottom: 14%;
  width: 1px;
  margin-left: -0.5px;
  background: linear-gradient(180deg,
    transparent,
    color-mix(in srgb, var(--text-3) 55%, transparent) 30%,
    color-mix(in srgb, var(--text-3) 55%, transparent) 70%,
    transparent);
  pointer-events: none;
  z-index: 2;
}
/* Wrapper needs position context so the divider knows where to anchor. */
.kpi-payoff .winloss-pair { position: relative; }
.wl-label {
  font-size: 9.5px;
  color: var(--text-3);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.wl-value {
  font-size: 20px;
  font-weight: 800;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  line-height: 1;
}
.wl-win .wl-value { color: var(--pos); }
.wl-loss .wl-value { color: var(--neg); }

.risk-ratio-line {
  display: flex;
  align-items: baseline;
  justify-content: center;
  gap: 8px;
  margin-top: auto;
  padding: 6px 0 0;
  border-top: 1px solid var(--border-hair);
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-variant-numeric: tabular-nums;
}

.risk-ratio-line strong {
  color: var(--text);
  font-size: 14px;
  font-weight: 800;
  letter-spacing: -0.01em;
  text-transform: none;
}

.kpi-expectancy .kpi-value { color: var(--pos); }
.kpi-expectancy.is-neg .kpi-value { color: var(--neg); }

/* Expectancy widget — colored bar + animated dot that reflects how far
   the expectancy is from zero. The intensity (--exp-strength, 0..1)
   drives both the bar saturation and the dot's glow so a high-edge
   trader gets a bright premium-feeling indicator instead of a flat bar.
   --exp-pos: 0..100 — horizontal placement of the dot (50 = zero).

   Both custom properties are registered as <number> so the calc()-derived
   width, left and box-shadow values actually interpolate — otherwise the
   bar snaps to its final value instead of load-filling like the win-rate /
   profit-factor bars. */
@property --exp-pos {
  syntax: '<number>';
  inherits: true;
  initial-value: 50;
}
@property --exp-strength {
  syntax: '<number>';
  inherits: true;
  initial-value: 0;
}
.expectancy-scale {
  position: relative;
  height: 18px;
  margin-top: auto;
  --exp-pos: 50;
  --exp-strength: 0.4;
  --exp-color: var(--pos);
  --exp-color-rgb: 18, 152, 216;
}

.expectancy-track {
  position: absolute;
  left: 0;
  right: 0;
  top: 7px;
  height: 5px;
  border-radius: 999px;
  background:
    linear-gradient(90deg,
      rgba(201, 80, 80, calc(0.22 + var(--exp-strength) * 0.42)),
      rgba(120, 130, 145, 0.10) 50%,
      rgba(23, 136, 201, calc(0.22 + var(--exp-strength) * 0.42)));
  overflow: hidden;
}
.expectancy-track::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: calc(abs(var(--exp-pos) - 50) * 1%);
  transform: translateX(var(--exp-pos-sign, 0%));
  background: linear-gradient(90deg,
    rgba(var(--exp-color-rgb), 0) 0%,
    rgba(var(--exp-color-rgb), calc(0.35 + var(--exp-strength) * 0.45)) 100%);
  border-radius: 999px;
  pointer-events: none;
  /* Load-fill in lockstep with the dot (same easing) so the Expectancy
     indicator animates like the win-rate / profit-factor bars. */
  transition: width .42s cubic-bezier(.22,.61,.36,1),
              transform .42s cubic-bezier(.22,.61,.36,1);
}
.expectancy-scale.is-neg .expectancy-track::after {
  transform: translateX(-100%);
  background: linear-gradient(90deg,
    rgba(var(--exp-color-rgb), calc(0.35 + var(--exp-strength) * 0.45)) 0%,
    rgba(var(--exp-color-rgb), 0) 100%);
}
:root[data-theme="dark"] .expectancy-track {
  background:
    linear-gradient(90deg,
      rgba(239, 106, 112, calc(0.28 + var(--exp-strength) * 0.48)),
      rgba(160, 174, 192, 0.10) 50%,
      rgba(85, 199, 247, calc(0.28 + var(--exp-strength) * 0.48)));
}

.expectancy-zero {
  position: absolute;
  top: 3px;
  bottom: 3px;
  left: 50%;
  width: 1px;
  background: rgba(120, 130, 145, 0.35);
  z-index: 1;
}
:root[data-theme="dark"] .expectancy-zero { background: rgba(220, 230, 244, 0.30); }

.expectancy-dot {
  position: absolute;
  top: 3px;
  left: calc(var(--exp-pos) * 1%);
  width: 13px;
  height: 13px;
  margin-left: -6.5px;
  border-radius: 50%;
  background: radial-gradient(circle at 35% 30%,
    color-mix(in srgb, var(--exp-color) 85%, white),
    var(--exp-color) 70%);
  border: 2px solid #fff;
  z-index: 2;
  box-shadow:
    0 0 0 calc(2px + var(--exp-strength) * 3px) rgba(var(--exp-color-rgb), calc(0.10 + var(--exp-strength) * 0.18)),
    0 2px 10px rgba(var(--exp-color-rgb), calc(0.30 + var(--exp-strength) * 0.45)),
    0 0 calc(8px + var(--exp-strength) * 18px) rgba(var(--exp-color-rgb), calc(0.20 + var(--exp-strength) * 0.50));
  transition: left .42s cubic-bezier(.22,.61,.36,1),
              box-shadow .42s ease;
}
:root[data-theme="dark"] .expectancy-dot { border-color: rgba(20, 26, 36, 0.85); }

/* ============================================================
   Dashboard grid
   ============================================================ */

.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  /* Row 1 (Net P&L chart + edge-stack) leads at ~55%. Row 1 must clear the
     edge-stack's hourly + weekday floors (141 + 178 + gaps) plus a sliver for
     the stats-pair; the earlier 0.520 split starved it, so the Weekday card
     overflowed its cell and slid down over the calendar. 0.550 restores enough
     row-1 height that the stack fits and the Weekday→calendar gap returns.
     sizeRecentTradesRows() still splits row 2 into exactly five rows (they ride
     ~4px shorter than at 0.520, well clear of compact mode); extra trade rows
     scroll INSIDE the card, never the page — no page scroll is introduced. */
  grid-template-rows: minmax(0, 0.550fr) minmax(0, 0.450fr);
  gap: var(--dash-gap-row);
  flex: 1 1 auto;
  min-height: 0;
}

.chart-card {
  padding: 14px 17px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}

.chart-balance {
  grid-column: 1 / span 3;
  grid-row: 1;
}

.trades-card {
  grid-column: 1 / span 3;
  grid-row: 2;
}

.edge-stack {
  grid-column: 4 / span 2;
  grid-row: 1;
  display: grid;
  /* Three vertical sections. Hourly + Weekday carry hard px floors so .card's
     overflow:hidden never clips their rows; the stats-pair row stays ELASTIC
     (auto + mini-stat min-height:0) so it — not the Weekday card — absorbs any
     vertical deficit on shorter desktops. Reserving the stats-pair at its full
     min-content height (the previous behaviour) pushed the stack past its grid
     cell and slid the Weekday card down over the calendar; letting it compress
     keeps Mon–Fri whole and preserves the gap to the calendar below.
       row 1 — stats-pair (auto, compresses first)
       row 2 — hourly  (min 141px → fits 4 rows × 24px + head + padding)
       row 3 — weekday (min 178px → fits 5 rows × 24px + head + padding +
                        cushion so Friday always renders fully) */
  grid-template-rows: auto minmax(141px, 0.86fr) minmax(178px, 1.14fr);
  gap: var(--dash-gap-stack);
  min-width: 0;
  min-height: 0;
}

.stats-pair {
  display: grid;
  /* minmax(0,1fr) instead of bare 1fr: a bare 1fr track carries a min-content
     floor, so an unbreakable wide value (long currency / German label) could
     push the pair past the edge-stack cell on a narrow desktop. minmax(0,1fr)
     lets each column shrink below its content width; the mini-stat internals
     (min-width:0 + value nowrap + label wrap) keep text legible, never clipped. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--dash-gap-tight);
  min-width: 0;
  min-height: 0;
}

.mini-stat {
  /* Tightened bottom padding (12→9) keeps the mini-stat compact. min-height:0
     lets the stats-pair row compress under tight desktop heights so the Weekday
     card keeps its full height instead of sliding over the calendar — the stat
     values stay readable; only the sub-line trims first when space is scarce. */
  padding: 11px 14px 9px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-width: 0;
  min-height: 0;
}

.mini-stat .ms-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 6px;
  min-width: 0;
}

.mini-stat .ms-label {
  font-size: 9px;
  font-weight: 800;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  /* Label is the flexible side: it may shrink and wrap (incl. mid-word as a last
     resort) so the value beside it is never pushed out and clipped. */
  min-width: 0;
  overflow-wrap: anywhere;
}

.mini-stat .ms-value {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1;
  /* The number must always render in full — hold its natural width, never shrink
     or wrap. Pairs with the label's shrink/wrap above. */
  flex: 0 0 auto;
  white-space: nowrap;
}
.mini-stat .ms-value small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.mini-stat .ms-value.pos { color: var(--pos); }
.mini-stat .ms-value.neg { color: var(--neg); }

.mini-stat .ms-sub {
  font-size: 9.5px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  margin-top: -2px;
}

.mini-stat .ms-divider {
  height: 1px;
  background: var(--border-hair);
  margin: 5px 0 2px;
}

.left-bottom-stack {
  grid-column: 1 / span 3;
  grid-row: 2;
  display: grid;
  /* Instruments hug their content (auto). Recent Trades takes the elastic
     row (1fr) and stretches to fill — its table-wrap is also elastic, so
     the row count shown matches whatever vertical space the dashboard-grid
     hands down. A tight stack gap butts the two cards together as one
     connected ledger. */
  grid-template-rows: auto minmax(0, 1fr);
  gap: var(--dash-gap-stack);
  min-height: 0;
  min-width: 0;
}

.left-bottom-stack .instruments-card,
.left-bottom-stack .trades-card {
  grid-column: auto;
  grid-row: auto;
}

.instruments-pair {
  display: grid;
  /* Same shrink-safe floor as .stats-pair: minmax(0,1fr) so neither column can
     impose a min-content width and overflow the cell on a narrow desktop. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--dash-gap-tight);
  min-width: 0;
  min-height: 0;
}

.instruments-card {
  padding: var(--dash-card-pad-y) var(--dash-card-pad-x);
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  min-width: 0;
}

.instruments-card h2 { font-size: 13px; }
.instruments-card .ic-sub { font-size: 10px; margin-top: 1px; }

.instruments-list {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-content: start;
}

.left-bottom-stack .ic-row { min-height: 0; }

.instruments-card .ic-sym {
  font-size: 11px;
  min-width: 30px;
  padding: 2px 5px;
}
.instruments-card .ic-name { font-size: 11.5px; }
.instruments-card .ic-share { font-size: 9.5px; }
.instruments-card .ic-bar-track { height: 4px; }
.instruments-card .ic-amount { font-size: 12px; }
.instruments-card .ic-amount small { font-size: 8.5px; }

.trades-head-compact {
  align-items: center;
  padding-bottom: 2px !important;
}
.trades-head-compact .chart-title { font-size: 14px; }

/* ------------------------------------------------------------
   Instruments + Recent Trades — denser, more "connected" read.
   Scoped to .left-bottom-stack so the Performance page's own
   .trades-card (and the Trades page) are never affected.
   ------------------------------------------------------------ */

/* Instrument rows read as a contiguous ledger: a near-invisible row separator
   gives the eye a grid lock, the body has tight vertical rhythm, the bar is
   thin but visible against the theme-aware track. */
/* The instruments pair is compressed to a single-line-per-row ledger so the
   whole block lands near ~100px, freeing the rest of the 231px stack for at
   least five Recent Trades rows. Heads collapse to one line (subtitle hidden),
   and each row becomes: [sym chip] [name · share] [strength bar →] [amount]. */
.left-bottom-stack .instruments-card { padding: var(--dash-card-pad-y) var(--dash-card-pad-x); gap: 0; }
/* The aggregated card total lives in the head; a hairline rule under the head
   fences it off from the per-instrument rows so the sum never reads as just
   another row sitting on top of the list. */
.left-bottom-stack .instruments-card .ic-head {
  align-items: center;
  padding-bottom: 4px;
  margin-bottom: 4px;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 70%, transparent);
}
.left-bottom-stack .instruments-card h2 { font-size: 12px; }
.left-bottom-stack .instruments-card .ic-sub { display: none; }
/* The aggregate is the headline number of the card: noticeably larger and
   heavier than the per-row amounts so the eye lands on it as THE total, not
   on the first symbol's figure sitting just below it. */
.left-bottom-stack .instruments-card .ic-total {
  font-size: 14px;
  font-weight: 900;
  letter-spacing: -0.015em;
}

/* Symbols sit directly under the head as one tight group (small inter-row gap
   so they breathe without un-grouping). Only a minimal gap separates them from
   the head total — just enough to read the top-right figure as the card sum.
   flex-start keeps that gap fixed; any spare card height falls below the group
   instead of inflating the head→symbols gap. */
.left-bottom-stack .instruments-list { gap: 8px; justify-content: center; }
.left-bottom-stack .ic-row {
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 9px;
  padding: 0;
  line-height: 1.25;
}
/* The symbol is the ROW HEADING — it must read as a title, not a quiet tag.
   Larger + heaviest mono weight + a touch more chip, and optically lifted a
   hair above the supporting name/bar so it sits like a heading. */
.left-bottom-stack .ic-sym {
  font-size: 13px;
  font-weight: 800;
  min-width: 31px;
  padding: 2px 6px;
  letter-spacing: 0.01em;
  align-self: center;
  transform: translateY(-1px);
}
/* Collapse the 2-row body (name-row over bar) into one horizontal line:
   the label group sizes to content, the bar flexes to fill what's left. */
.left-bottom-stack .ic-body {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 9px;
}
.left-bottom-stack .ic-name-row {
  flex: 0 1 auto;
  min-width: 0;
  gap: 6px;
}
.left-bottom-stack .ic-name {
  font-size: 11.5px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.left-bottom-stack .ic-share { font-size: 9.5px; flex: 0 0 auto; }
.left-bottom-stack .ic-bar-track {
  flex: 1 1 auto;
  min-width: 22px;
  height: 4px;
  background: color-mix(in srgb, var(--border-strong) 60%, transparent);
}
/* The P&L figure is the row's other heading — give it the same heading weight
   as the symbol so the eye reads [symbol] … [amount] as the two anchors of the
   row, lifted a hair above the supporting middle. */
.left-bottom-stack .ic-amount {
  font-size: 14px;
  font-weight: 900;
  letter-spacing: -0.02em;
  transform: translateY(-1px);
}

/* ------------------------------------------------------------
   Recent Trades — a premium, roomy preview ledger. Exactly FIVE
   trades are sized to fill the card (each row height = the scroll
   viewport's height ÷ 5, written to --rt-row-h by
   sizeRecentTradesRows()), so the list always ends flush on the
   fifth row no matter the screen. Older trades scroll WITHIN the
   card — never the page. Each row is a two-line record: symbol +
   side + context chip on top, the date / hold / size meta beneath,
   with P&L and R-multiple stacked at the right edge.
   ------------------------------------------------------------ */
.left-bottom-stack .trades-card { padding: var(--dash-card-pad-y) var(--dash-card-pad-x); gap: var(--dash-gap-stack); }
.left-bottom-stack .trades-head-compact { padding-bottom: 2px !important; }
.left-bottom-stack .trades-head-compact .chart-title { font-size: 13.5px; }

/* The scroll viewport. Its measured height is divided by five to set the
   per-row height, so five roomy rows always land flush with the card's
   bottom edge regardless of the screen the dashboard renders on. */
.left-bottom-stack .table-wrap {
  /* Shared 8-column ledger grid — referenced by BOTH the sticky header row and
     every data row so their columns line up exactly, on any width. */
  --rt-grid:
    minmax(116px, 1.7fr)        /* instrument: symbol + side + strategy */
    repeat(6, minmax(0, 1fr))   /* date · open · close · duration · R:R · lots */
    minmax(66px, 1.15fr);       /* P&L outcome */
  padding-right: 4px;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  overflow-x: hidden;
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, var(--border-strong) 70%, transparent) transparent;
}
.left-bottom-stack .table-wrap::-webkit-scrollbar { width: 6px; }
.left-bottom-stack .table-wrap::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, var(--border-strong) 60%, transparent);
  border-radius: 6px;
}

.rt-list {
  /* Fallback until JS measures the wrap; ~52px reads well on a typical
     desktop and keeps rows from collapsing before first layout. */
  --rt-row-h: 52px;
  display: flex;
  flex-direction: column;
}

/* Sticky column-header row. Labelled once, it sits inside the scroll wrap so
   it shares the rows' exact width + grid; it sticks to the top as older trades
   scroll underneath. This is what turns the list into a clean professional
   ledger instead of repeating a label on every row. */
.rt-head-row {
  position: sticky;
  top: 0;
  z-index: 2;
  display: grid;
  grid-template-columns: var(--rt-grid);
  align-items: center;
  column-gap: 8px;
  padding: 1px 12px 6px 16px;
  background: var(--surface);
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 90%, transparent);
}
.rt-hk {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
  white-space: nowrap;
  text-align: center;
}
.rt-hk-inst { text-align: left; }
.rt-hk-pnl  { text-align: right; }

/* One trade = one full LEDGER ROW. The fields are spread across the shared grid
   — instrument anchor, then date · open · close · duration · R:R · lots, then
   the P&L outcome on the right edge — so the row never leaves a dead gap in the
   middle. height is the elastic fifth-share so five rows always fill the
   viewport exactly; .rt-compact (toggled by sizeRecentTradesRows) shrinks the
   cells so five rows still fit on short screens. */
.rt-row {
  position: relative;
  display: grid;
  grid-template-columns: var(--rt-grid);
  align-items: center;
  column-gap: 9px;
  height: var(--rt-row-h);
  min-height: 0;
  padding: 0 12px 0 16px;
  /* Full-strength hairline (was 75%) so the rows read as a crisp ruled ledger
     now that the card hosts five comfortable rows. */
  border-bottom: 1px solid var(--border-hair);
  cursor: pointer;
  overflow: hidden;
  transition: background 160ms var(--ease-out);
}
.rt-row:last-child { border-bottom: 0; }
/* Subtle zebra banding keys the eye across the wide 8-column ledger. Kept
   barely-there so the card stays calm; hover/active are declared AFTER this so
   they always win at equal specificity. */
.rt-row:nth-child(even) { background: color-mix(in srgb, var(--surface-sunken) 28%, transparent); }
.rt-row:hover  { background: color-mix(in srgb, var(--surface-sunken) 55%, transparent); }
.rt-row:active { background: color-mix(in srgb, var(--surface-sunken) 80%, transparent); }

/* Outcome accent — a soft vertical bar on the leading edge. Gradient + rounded
   cap so it reads as a premium status marker, not a hard table border. */
.rt-accent {
  position: absolute;
  left: 0;
  top: 18%;
  bottom: 18%;
  width: 3px;
  border-radius: 0 3px 3px 0;
  transition: top 160ms var(--ease-out), bottom 160ms var(--ease-out), width 160ms var(--ease-out);
}
.rt-win  .rt-accent { background: linear-gradient(180deg, var(--pos), color-mix(in srgb, var(--pos) 32%, transparent)); }
.rt-loss .rt-accent { background: linear-gradient(180deg, var(--neg), color-mix(in srgb, var(--neg) 32%, transparent)); }
.rt-row:hover .rt-accent { top: 12%; bottom: 12%; width: 3.5px; }

/* Instrument anchor — symbol + side on top, strategy / context chip beneath.
   Stays on the left exactly where it was. */
.rt-inst { display: flex; flex-direction: column; align-items: flex-start; gap: 2px; min-width: 0; }
.rt-inst-top { display: flex; align-items: center; gap: 7px; min-width: 0; }
.rt-sym {
  font-size: 14.5px;
  font-weight: 800;
  letter-spacing: -0.012em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.rt-side {
  font-family: var(--mono);
  font-size: 7.5px;
  font-weight: 750;
  letter-spacing: 0.06em;
  padding: 1.5px 5px;
  border-radius: 4px;
  line-height: 1;
  flex: 0 0 auto;
  /* Quiet outline tag rather than a loud filled badge — the saturated pill was
     the single loudest element on the dashboard and made this card read as a
     foreign component. Semantic colour now lives in the text + a hairline ring,
     so the ledger sits in the same calm family as the sibling instrument /
     edge cards. */
  background: transparent;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, currentColor 18%, transparent);
}
.rt-side.is-long  { color: color-mix(in srgb, var(--pos) 80%, var(--text-3)); }
.rt-side.is-short { color: color-mix(in srgb, var(--neg) 80%, var(--text-3)); }

/* Context chip — the trade's strategy / setup when reviewed, otherwise the
   session it opened in. Quiet by design so it informs without shouting. */
.rt-tag {
  font-size: 8.5px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-4);
  background: color-mix(in srgb, var(--surface-sunken) 90%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 80%, transparent);
  padding: 1px 6px;
  border-radius: 5px;
  line-height: 1.35;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Data cell — a single value, centred under its header column so the six
   middle columns distribute evenly and the row reads as one balanced ledger. */
.rt-cell {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 0;
}
.rt-v {
  font-size: 12.5px;
  /* Supporting cells (entry, size, R, etc.) are demoted to a quieter weight
     and tone so the bold symbol + P&L headings clearly lead the row. The
     P&L cell re-overrides colour below (.pl-pos/.pl-neg win on specificity),
     so only the neutral metric cells recede. */
  font-weight: 550;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.rt-v.pl-pos { color: var(--pos); }
.rt-v.pl-neg { color: var(--neg); }

/* P&L is the row's outcome — anchored to the right edge, larger + heavier than
   the supporting cells so the eye lands on it as the result. */
.rt-cell-pnl { align-items: flex-end; }
.rt-pnl {
  font-size: 15px;
  font-weight: 820;
  letter-spacing: -0.02em;
}

/* Compact fallback for short viewports — drop the strategy chip and tighten
   type so the instrument anchor collapses to one line and five rows still fit;
   symbol, side and every value stay readable. Toggled on #trades-body by
   sizeRecentTradesRows() when the computed row height is too short. The zebra
   banding and full hairline separator carry over from the base .rt-row rules —
   compact only changes type, never the ledger ruling. */
.rt-compact .rt-tag { display: none; }
.rt-compact .rt-inst { gap: 0; }
/* The two headings stay assertive even in compact so the row still reads as
   [symbol] … [P&L]; only the supporting cells shrink. Each is held exactly 1px
   below its new desktop base (sym 14.5 → 13.5, P&L 15 → 14). */
.rt-compact .rt-sym { font-size: 13.5px; }
.rt-compact .rt-pnl { font-size: 14px; }
.rt-compact .rt-v   { font-size: 11.5px; }

/* Compact keeps the column header — just slimmer — so the ledger never loses
   its labels on common laptop heights. sizeRecentTradesRows() only removes it
   (via .rt-compact-headless + an inline display:none) when even this slim strip
   would crush the rows below ~26px. */
.rt-compact .rt-head-row { padding: 0 12px 3px 16px; }
.rt-compact .rt-hk { font-size: 7.5px; }
.rt-compact-headless .rt-head-row { display: none; }

/* Calendar card */
.calendar-card {
  grid-column: 4 / span 2;
  grid-row: 2;
  padding: var(--dash-card-pad-y) var(--dash-card-pad-x);
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
  /* Required so the absolutely-positioned weekly-summary drawer anchors
     to the card's right edge. */
  position: relative;
  /* Allow the drawer to slide outside the card boundary on hover, which is
     the whole point of the hover-expand interaction. The card's normal
     overflow:hidden (from .card) would clip the drawer. */
  overflow: visible;
}

.cal-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}
.cal-head h2 {
  font-size: 14px;
  font-weight: 750;
  letter-spacing: -0.008em;
  color: var(--text);
}
.cal-sub {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 500;
  margin-top: 2px;
  letter-spacing: 0;
}

/* Month nav chip — same surface convention as Performance's segmented filters
   so the dashboard reads as one system. Hairline border + sunken fill, not a
   floating chip. */
.cal-nav {
  display: flex;
  align-items: center;
  gap: 2px;
  background: var(--surface-sunken);
  border: 1px solid color-mix(in srgb, var(--border-hair) 80%, transparent);
  border-radius: 8px;
  padding: 2px;
}
.cal-nav-btn {
  width: 22px;
  height: 22px;
  border-radius: 5px;
  display: grid;
  place-items: center;
  color: var(--text-3);
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.cal-nav-btn:hover { background: var(--surface); color: var(--text); }
.cal-month-label {
  font-size: 11.5px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: 0.01em;
  padding: 0 8px;
  min-width: 96px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  font-variant-numeric: tabular-nums;
}

.cal-weekdays {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 3px;
  margin-top: 2px;
}
.cal-weekdays span {
  font-size: 9px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  text-align: center;
  padding: 2px 0;
}

.cal-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  gap: 3px;
  flex: 1;
  min-height: 0;
}

.cal-cell {
  background: rgba(0, 0, 0, 0.03);
  border-radius: 6px;
  padding: 4px 5px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  cursor: pointer;
  position: relative;
  transition: transform 160ms var(--ease-out), background 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  min-height: 0;
}
.cal-cell.outside {
  background: transparent;
  cursor: default;
  opacity: 0.3;
}
.cal-cell.outside .cal-day { color: var(--text-4); }
.cal-cell.outside:hover { transform: none; box-shadow: none; }

.cal-cell.has-trades:hover {
  transform: translateY(-1.5px);
  /* Premium glow on hover — subtle but distinctly more refined than a
     plain drop shadow. Uses the cell's tone (pos/neg) for the halo so
     positive days bloom blue, negative days bloom red. */
  box-shadow:
    0 6px 18px rgba(15, 17, 21, 0.10),
    0 0 0 1px color-mix(in srgb, var(--border) 50%, transparent),
    inset 0 1px 0 rgba(255,255,255,0.10);
  z-index: 1;
}
.cal-cell.pos.has-trades:hover {
  box-shadow:
    0 6px 22px rgba(18, 152, 216, 0.22),
    0 0 0 1px rgba(18, 152, 216, 0.20),
    inset 0 1px 0 rgba(255,255,255,0.12);
}
.cal-cell.neg.has-trades:hover {
  box-shadow:
    0 6px 22px rgba(201, 80, 80, 0.22),
    0 0 0 1px rgba(201, 80, 80, 0.22),
    inset 0 1px 0 rgba(255,255,255,0.10);
}

.cal-cell.pos {
  background:
    radial-gradient(circle at 30% 0%, rgba(92, 200, 255, 0.10), transparent 70%),
    linear-gradient(135deg, rgba(92, 200, 255, 0.18), rgba(18, 152, 216, 0.12));
}
.cal-cell.neg {
  background:
    radial-gradient(circle at 30% 0%, rgba(255, 120, 120, 0.10), transparent 70%),
    linear-gradient(135deg, rgba(185, 28, 28, 0.16), rgba(127, 29, 29, 0.10));
}
.cal-cell.pos.heavy {
  background:
    radial-gradient(circle at 30% 0%, rgba(92, 200, 255, 0.18), transparent 70%),
    linear-gradient(135deg, rgba(92, 200, 255, 0.32), rgba(18, 152, 216, 0.26));
  box-shadow: inset 0 0 0 1px rgba(18, 152, 216, 0.18);
}
.cal-cell.neg.heavy {
  background:
    radial-gradient(circle at 30% 0%, rgba(255, 120, 120, 0.16), transparent 70%),
    linear-gradient(135deg, rgba(185, 28, 28, 0.30), rgba(127, 29, 29, 0.20));
  box-shadow: inset 0 0 0 1px rgba(201, 80, 80, 0.18);
}
.cal-cell.future {
  background: transparent;
  border: 1px dashed var(--border-strong);
}

/* Today — no special marker. The cell renders identically to any other
   day. Selection state (.selected, set only during active interaction)
   is the sole visual highlight on the calendar. */
.cal-cell.today { /* no decoration */ }

.cal-day {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text);
  line-height: 1;
}

.cal-pnl {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: -0.01em;
}
.cal-pnl.pos { color: var(--pos); }
.cal-pnl.neg { color: var(--neg); }

.cal-marker {
  position: absolute;
  bottom: 3px;
  right: 4px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--mint);
  box-shadow: 0 0 0 2px var(--surface);
}

/* ============================================================
   Dashboard Trade Calendar — institutional refinement.
   Every rule here is scoped to .calendar-card so the Performance
   page's re-used .cal-* tokens are never affected.
   ============================================================ */

/* Calendar is now a clean 7-column grid (Mon-Sun). The weekly summary lives
   in a hover-expand drawer (.cal-week-drawer below) — see the trigger strip
   on the right edge of the calendar card. */
.calendar-card .cal-weekdays,
.calendar-card .cal-grid {
  grid-template-columns: repeat(7, 1fr);
}

/* Day-cell hierarchy: the day number recedes to a quiet anchor so the
   P&L outcome reads as the cell's primary signal. */
.calendar-card .cal-day {
  font-size: 9.5px;
  font-weight: 650;
  color: var(--text-3);
  letter-spacing: 0.01em;
}
.calendar-card .cal-cell.has-trades .cal-day { color: var(--text-2); }
/* No special color treatment for the today day-number either — keep the cell
   visually anonymous so it never reads as "permanently selected". */
.calendar-card .cal-pnl {
  font-size: 11.5px;
  font-weight: 800;
  letter-spacing: -0.015em;
}

/* Continuous blue(win)/red(loss) intensity — a true heatmap driven by
   --cal-i (0..1 = the day's |P&L| vs the month's peak day), replacing the
   old binary base/heavy steps. Theme-aware via --pos / --neg. */
.calendar-card .cal-cell.pos {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--pos) calc(9% + var(--cal-i, 0.4) * 27%), transparent),
    color-mix(in srgb, var(--pos) calc(4% + var(--cal-i, 0.4) * 15%), transparent));
}
.calendar-card .cal-cell.neg {
  background: linear-gradient(135deg,
    color-mix(in srgb, var(--neg) calc(9% + var(--cal-i, 0.4) * 27%), transparent),
    color-mix(in srgb, var(--neg) calc(4% + var(--cal-i, 0.4) * 15%), transparent));
}
/* Top-intensity days get a hairline tone ring for extra weight. */
.calendar-card .cal-cell.heavy.pos { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--pos) 30%, transparent); }
.calendar-card .cal-cell.heavy.neg { box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--neg) 30%, transparent); }

/* Empty day cells — NEUTRAL (no trades) and FUTURE — outlined as distinct tiles.
   Outline every empty cell with the card's own border colour (the same hairline as
   the KPI cards) + a faint recessed fill, so each day reads as a clean tile with a
   subtle dividing line rather than a floating faint square. Trade days are excluded —
   they already separate via their P&L colour. Theme-agnostic: --border-strong /
   --surface-soft are theme-aware, so light, dark and grey all share the same look.
   (Previously dark-scoped; light's bare rgba(0,0,0,.03) fill with gaps and no border
   read as a "dotted" grid, so it now gets the same bordered-tile treatment.) This
   also overrides .cal-cell.future's dashed border to a solid hairline in every theme. */
.calendar-card .cal-cell:not(.has-trades):not(.outside) {
  border: 1px solid var(--border-strong);
  background: color-mix(in srgb, var(--surface-soft) 45%, transparent);
}

/* No today marker at all — cells render identically whether or not the
   day matches the hardcoded demo TODAY. (The .today class is still added
   in the renderer in case future features need to target it without
   touching the renderer.) */

/* Hover — calmer and more "connected" than the old neon bloom: a tighter
   lift plus a tone-matched hairline border and soft shadow. */
.calendar-card .cal-cell.has-trades:hover {
  transform: translateY(-1.5px);
  box-shadow:
    0 5px 16px rgba(15, 17, 21, 0.10),
    inset 0 0 0 1px color-mix(in srgb, var(--border) 60%, transparent);
}
.calendar-card .cal-cell.pos.has-trades:hover {
  box-shadow:
    0 6px 18px color-mix(in srgb, var(--pos) 20%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--pos) 36%, transparent);
}
.calendar-card .cal-cell.neg.has-trades:hover {
  box-shadow:
    0 6px 18px color-mix(in srgb, var(--neg) 20%, transparent),
    inset 0 0 0 1px color-mix(in srgb, var(--neg) 36%, transparent);
}

/* Selected (last-opened) day — a crisp focus ring layered on top of
   today/pos/neg. Additive only; click-to-open-modal behavior is unchanged. */
.calendar-card .cal-cell.selected {
  box-shadow:
    inset 0 0 0 1.5px var(--text-2),
    0 0 0 3px color-mix(in srgb, var(--text-2) 13%, transparent);
}
.calendar-card .cal-cell.selected.pos {
  box-shadow:
    inset 0 0 0 1.5px var(--pos),
    0 0 0 3px color-mix(in srgb, var(--pos) 18%, transparent);
}
.calendar-card .cal-cell.selected.neg {
  box-shadow:
    inset 0 0 0 1.5px var(--neg),
    0 0 0 3px color-mix(in srgb, var(--neg) 18%, transparent);
}

/* Weekly-net summary cell (8th column). Reads as the margin-total ledger row,
   not another trading day: tinted "sunken paper" background, a single hairline
   left rule, and a bolder net value so the eye picks up the weekly result at
   a glance. Not interactive. */
.calendar-card .cal-week-cell {
  border-radius: 6px;
  padding: 5px 5px 6px 7px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  align-items: flex-start;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  border-left: 1px solid color-mix(in srgb, var(--border-strong) 70%, transparent);
  font-variant-numeric: tabular-nums;
  overflow: hidden;
  min-height: 0;
  cursor: default;
}
.calendar-card .cal-week-cell .cal-wk-label {
  font-size: 8.5px;
  font-weight: 800;
  color: var(--text-4);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  line-height: 1;
}
.calendar-card .cal-week-cell .cal-wk-net {
  font-size: 10.5px;
  font-weight: 850;
  letter-spacing: -0.02em;
  color: var(--text-4);
  line-height: 1.05;
}
.calendar-card .cal-week-cell .cal-wk-net.pos { color: var(--pos); }
.calendar-card .cal-week-cell .cal-wk-net.neg { color: var(--neg); }
/* Empty week: dim everything except the W-label so the column still reads as
   a continuous ledger; the dash is replaced by a thinner, quieter glyph. */
.calendar-card .cal-week-cell.empty { opacity: 0.45; }
.calendar-card .cal-week-cell.empty .cal-wk-net { font-weight: 500; opacity: 0.7; }

/* ============================================================
   Weekly summary drawer — replaces the old static "Wk" column. The
   trigger sits in the gap between the Sunday column and the card's
   right edge, with three slim vertical indicator bars spanning the
   full grid height. On hover the calendar grid cells compress
   slightly (CSS transition on the cal-grid + cal-weekdays containers)
   and the weekly summary panel slides INTO the cleared space — a
   "drawer eats space from the grid" interaction, not "drawer escapes
   outside the card".

   Geometry, anchored from the card's right edge:
     | 14px card padding | 156px panel + 6px gap | 16px trigger zone |
   Total reserved on hover = 16 (trigger) + 6 (gap) + 156 (panel) = 178px
   The grid + weekdays get padding-right: 178px at the same time so the
   cells animate to a slightly narrower width to make room.
   ============================================================ */

/* The grid + weekdays row reserve their compressed width via a class
   toggled on the calendar-card. Smooth transition gives the cells a
   subtle "make room" animation when the drawer opens. */
.calendar-card .cal-weekdays,
.calendar-card .cal-grid {
  transition: padding-right 400ms var(--ease-emphasized);
  padding-right: 22px;
  will-change: padding-right;
}
.calendar-card.is-week-open .cal-weekdays,
.calendar-card.is-week-open .cal-grid {
  padding-right: 92px;
}

/* Drawer container — anchored to the card's right edge, spans full
   weekday-header + grid height. The drawer is the hover boundary; the
   trigger and panel live inside it. */
.cal-week-drawer {
  position: absolute;
  /* Spans exactly from the weekday-header row down to the calendar grid's
     bottom edge (measured geometry), so the panel's "Weekly" label aligns
     with Mon–Sun and each weekly net aligns with its grid row. */
  top: 52px;
  bottom: 13px;
  right: 14px;
  pointer-events: none;
  z-index: 4;
}

/* Trigger — a compact, vertically-centered grip handle that mirrors the
   top-nav hamburger's design language (pill surface, hairline border, soft
   shadow) but oriented for a side drawer: three short vertical bars sitting
   side by side. Reads as a real "pull me" affordance instead of the old
   full-height hairline that looked like a single stray line. */
.cal-week-trigger {
  position: absolute;
  top: 50%;
  right: 0;
  transform: translateY(-50%);
  width: 19px;
  height: 46px;
  pointer-events: auto;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: 2.5px;
  cursor: pointer;
  color: var(--text-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  /* Fully opaque (no backdrop-filter): this pill animates on open/close, so a
     backdrop blur would force a per-frame recomposite of what's behind it. */
  background: var(--surface);
  box-shadow: var(--shadow-2);
  transition:
    box-shadow 300ms var(--ease-out),
    background 300ms var(--ease-out);
}
.cal-week-trigger:hover,
.calendar-card.is-week-open .cal-week-trigger {
  box-shadow: var(--shadow-3);
  background: color-mix(in srgb, var(--surface) 88%, var(--surface-sunken));
}
.cal-week-trigger span {
  display: block;
  width: 2px;
  height: 13px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--text-4) 62%, transparent);
  transition:
    background 240ms var(--ease-out),
    height 240ms var(--ease-out);
}
.cal-week-trigger:hover span,
.calendar-card.is-week-open .cal-week-trigger span {
  background: color-mix(in srgb, var(--text-2) 88%, transparent);
  height: 17px;
}

/* Summary panel — sits LEFT of the trigger (16px reserved for the
   trigger + 6px gap). Hidden by default, slides in horizontally when
   the calendar grid compresses to make room. */
.cal-week-panel {
  position: absolute;
  top: 0;
  bottom: 0;
  right: 26px;
  width: 60px;
  padding: 0;
  display: flex;
  flex-direction: column;
  /* Same vertical rhythm as the calendar column: the head occupies the
     weekday-row band, then a 6px gap (matching the card's flex gap) before
     the grid-aligned body. */
  gap: 6px;
  border: 1px solid var(--border-hair);
  border-radius: 12px;
  overflow: hidden;
  /* Fully opaque (no backdrop-filter): the panel slides via transform on
     open/close, and a backdrop blur would recomposite the calendar grid
     behind it every frame of that slide. The subtle top-light gradient is
     preserved using opaque surface tokens. */
  background:
    linear-gradient(180deg, var(--surface), color-mix(in srgb, var(--surface) 92%, var(--surface-sunken)));
  box-shadow:
    0 20px 50px -22px rgba(15, 17, 21, 0.28),
    0 6px 18px -10px rgba(15, 17, 21, 0.14);
  pointer-events: none;
  opacity: 0;
  transform: translateX(14px);
  visibility: hidden;
  /* Slower, fully matched easing on open AND close so the slide reads as one
     smooth motion instead of the old fast/choppy snap. */
  transition:
    opacity 300ms var(--ease-out),
    transform 420ms var(--ease-emphasized),
    visibility 0ms linear 420ms;
}
.calendar-card.is-week-open .cal-week-panel {
  pointer-events: auto;
  opacity: 1;
  transform: translateX(0);
  visibility: visible;
  transition:
    opacity 300ms var(--ease-out),
    transform 420ms var(--ease-emphasized),
    visibility 0ms linear 0ms;
}

/* "Weekly" label — occupies the same vertical band as the Mon–Sun weekday
   header row (15px) so it reads as that row's counterpart, then a 6px gap
   (the panel's flex gap) separates it from the first week so it clearly
   begins a new section. */
.cal-week-panel-head {
  flex: 0 0 15px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 6px;
}
.cal-week-panel-eyebrow {
  font-size: 8px;
  font-weight: 800;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-3);
}

/* Body mirrors the calendar grid exactly — same row count, same minmax(0,1fr)
   auto-rows, same 3px gap — and fills the same height (panel head+gap match
   the weekday row+gap), so every weekly net lands at its grid row's height. */
.cal-week-panel-body {
  flex: 1;
  min-height: 0;
  display: grid;
  grid-auto-rows: minmax(0, 1fr);
  gap: 3px;
}
.cal-wk-item {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 0;
  padding: 0 6px;
}
.cal-wk-item-net {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.cal-wk-item-net.pos { color: var(--pos); }
.cal-wk-item-net.neg { color: var(--neg); }
.cal-wk-item-net.flat { color: var(--text-3); }
.cal-wk-item.empty .cal-wk-item-net { color: var(--text-4); }

/* Mobile: hide the weekly hover drawer entirely — there's no hover surface
   to reach for on touch devices, and the 7-day grid stays full-width. */
@media (max-width: 760px) {
  .calendar-card .cal-week-drawer { display: none; }
}

/* Day modal — wrapper still controls visibility, but opacity/blur on the
   backdrop are now transitioned separately so the blur eases in instead
   of snapping in instantly when the modal opens. */
.day-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  display: grid;
  place-items: center;
  visibility: hidden;
  pointer-events: none;
  /* Hide shortly after the (now fast) close animation finishes, so the modal
     doesn't sit invisibly capturing nothing — and the rows are back quickly. */
  transition: visibility 0ms linear 190ms;
}
.day-modal.is-open {
  visibility: visible;
  pointer-events: auto;
  transition: visibility 0ms linear 0ms;
}

.day-modal-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 24, 32, 0.0);
  /* Tint fades on a short ease-out for the CLOSE (the open tint is eased longer
     on .is-open below). */
  transition: background 160ms var(--ease-out);
}
/* The blur lives on this ::after layer so it can fade via OPACITY — a cheap
   composite of the cached blur — both IN on open and OUT on close, instead of
   the filter snapping off and "popping" the page sharp before the panel has
   finished leaving. The base carries the OUT timing, synced with the panel exit
   (~160-185ms) and finishing before the wrapper hides at 190ms, so tint + blur +
   panel all clear together: no lingering blur, no sharpness pop. */
.day-modal-backdrop::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: 0;
  transition: opacity 170ms var(--ease-out);
}
/* Generic modals carry the blur here. The trade-detail modal keeps its OWN
   ::after blur (it arms the fade-in a frame after open), so it is excluded to
   avoid stacking two filters — but it still inherits the OUT transition above. */
.day-modal:not(.td-modal) .day-modal-backdrop::after {
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
}
.day-modal.is-open .day-modal-backdrop {
  /* Eased OPEN tint; the blur (::after) eases in alongside it. */
  background: rgba(20, 24, 32, 0.34);
  transition: background 300ms var(--ease-emphasized);
}
.day-modal:not(.td-modal).is-open .day-modal-backdrop::after {
  opacity: 1;
  transition: opacity 240ms var(--ease-emphasized);
}
:root[data-theme="dark"] .day-modal.is-open .day-modal-backdrop {
  background: rgba(8, 12, 22, 0.55);
}

.day-modal-panel {
  position: relative;
  width: min(640px, 92vw);
  max-height: 88vh;
  background: var(--surface);
  border-radius: 20px;
  box-shadow:
    0 40px 90px rgba(15, 17, 21, 0.32),
    0 16px 40px rgba(15, 17, 21, 0.14),
    0 1px 3px rgba(15, 17, 21, 0.06),
    inset 0 1px 0 rgba(255, 255, 255, 0.04);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateY(18px) scale(0.965);
  opacity: 0;
  /* Fast CLOSE (runs when .is-open is removed) so the panel clears quickly. */
  transition:
    transform 160ms cubic-bezier(0.4, 0, 1, 1),
    opacity 140ms ease;
}
.day-modal.is-open .day-modal-panel {
  transform: translateY(0) scale(1);
  opacity: 1;
  /* Eased OPEN — smooth rise/scale in. */
  transition:
    transform 300ms var(--ease-emphasized),
    opacity 190ms var(--ease-emphasized);
}

/* In dark mode a modal is the HIGHEST material — lift its panel one step above
   the card surface so, over the dimmed/blurred page, it clearly reads as
   floating rather than sharing the cards' tone. */
:root[data-theme="dark"] .day-modal-panel:not(.td-panel) {
  background: var(--surface-soft);
}

.day-modal-panel.td-panel {
  width: min(1220px, 96vw);
  /* Taller cap than the shared 88vh so the whole review fits without an inner
     scroll on typical laptop heights — the body content is compressed to match. */
  max-height: 95vh;
}

/* Add Trade is a two-column landscape form (trade facts + execution review) — give
   its panel room so both columns sit side by side instead of one tall scroll. */
.day-modal-panel.at-panel {
  width: min(960px, 94vw);
}

.dm-head {
  padding: 20px 22px 16px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  border-bottom: 1px solid var(--border-hair);
}
.dm-eyebrow {
  display: block;
  font-size: 9.5px;
  font-weight: 750;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  margin-bottom: 5px;
}
.dm-title {
  font-size: 19px;
  font-weight: 750;
  letter-spacing: -0.018em;
  color: var(--text);
  line-height: 1.2;
}

.dm-close {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  color: var(--text-2);
  background: var(--surface-sunken);
  border: 1px solid transparent;
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    border-color 160ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1);
}
/* Subtle hover "pop" — a slight overshoot scale on hover (not on click) so the
   close affordance feels alive when the cursor brushes over it. */
.dm-close:hover {
  background: var(--surface-soft);
  color: var(--text);
  border-color: var(--border-hair);
  transform: scale(1.1);
}
.dm-close:active { transform: scale(0.94); }

/* Prev/Next trade navigation in the detail-modal header — shares the .dm-close
   look so the trio reads as one control cluster. Disabled at the list ends. */
.td-nav-group { display: flex; align-items: stretch; gap: 6px; }
.td-nav {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  color: var(--text-2);
  background: var(--surface-sunken);
  border: 1px solid transparent;
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    border-color 160ms var(--ease-out),
    opacity 160ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1);
}
.td-nav:not(:disabled):hover {
  background: var(--surface-soft);
  color: var(--text);
  border-color: var(--border-hair);
  transform: scale(1.1);
}
.td-nav:not(:disabled):active { transform: scale(0.94); }
.td-nav:disabled { opacity: .3; cursor: default; }
.dm-head-right {
  display: flex;
  align-items: center;
  gap: 10px;
}
/* Weekly context chip — small pill in the day modal header that anchors the
   open day inside its week. Tone follows the week's net P&L sign. */
.dm-week-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 6px 9px;
  border: 1px solid var(--border-hair);
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
  font-variant-numeric: tabular-nums;
}
.dm-week-chip[hidden] { display: none; }
.dm-week-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
  padding: 1px 6px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--text-3) 10%, transparent);
}
.dm-week-pnl {
  font-size: 12px;
  font-weight: 800;
  letter-spacing: -0.005em;
  color: var(--text-2);
}
.dm-week-chip.pos .dm-week-pnl,
.dm-week-chip.pos .dm-week-label { color: var(--pos); }
.dm-week-chip.pos .dm-week-label { background: color-mix(in srgb, var(--pos) 14%, transparent); }
.dm-week-chip.neg .dm-week-pnl,
.dm-week-chip.neg .dm-week-label { color: var(--neg); }
.dm-week-chip.neg .dm-week-label { background: color-mix(in srgb, var(--neg) 14%, transparent); }
.dm-week-chip.pos { border-color: color-mix(in srgb, var(--pos) 22%, transparent); }
.dm-week-chip.neg { border-color: color-mix(in srgb, var(--neg) 22%, transparent); }

.dm-summary {
  padding: 18px 22px 16px;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 16px 22px;
  border-bottom: 1px solid var(--border-hair);
  /* Theme-aware tint — was a hardcoded near-white gradient that left
     dark mode looking like half the panel was painted grey. Now uses
     a surface-mixed value so both themes get the same subtle wash. */
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--surface-soft) 70%, transparent),
    color-mix(in srgb, var(--surface-soft) 25%, transparent));
}
:root[data-theme="dark"] .dm-summary {
  background: linear-gradient(180deg,
    color-mix(in srgb, var(--surface-sunken) 85%, transparent),
    color-mix(in srgb, var(--surface-sunken) 30%, transparent));
}
.dm-summary .dm-stat:nth-child(n+4) {
  padding-top: 14px;
  border-top: 1px solid var(--border-hair);
}
.dm-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.dm-stat-label {
  font-size: 9.5px;
  font-weight: 750;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.075em;
}
.dm-stat-value {
  font-size: 17px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.018em;
  line-height: 1.1;
}
.dm-stat-value.pos { color: var(--pos); }
.dm-stat-value.neg { color: var(--neg); }

.dm-section {
  padding: 14px 22px 12px;
  border-bottom: 1px solid var(--border-hair);
}
.dm-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.dm-section-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.dm-section-meta {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.dm-trades {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 180px;
  overflow-y: auto;
  font-variant-numeric: tabular-nums;
  padding-right: 4px;
}
.dm-trade-row {
  display: grid;
  grid-template-columns: 54px 44px minmax(60px, 1fr) 56px auto;
  gap: 10px;
  align-items: center;
  font-size: 12px;
  padding: 8px 10px;
  border-radius: 8px;
  border: 1px solid transparent;
  transition:
    background 160ms var(--ease-out),
    border-color 160ms var(--ease-out);
}
.dm-trade-row:hover {
  background: var(--surface-soft);
  border-color: var(--border-hair);
}
.dm-trade-time {
  color: var(--text-3);
  font-weight: 600;
  font-size: 11.5px;
  letter-spacing: -0.003em;
}
.dm-trade-side {
  font-size: 10px;
  font-weight: 750;
  color: var(--text-2);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.dm-trade-side.short { color: var(--neg); }
.dm-trade-side.long  { color: var(--pos); }
.dm-trade-r {
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 700;
  text-align: right;
  letter-spacing: -0.005em;
}
.dm-trade-r.pos { color: var(--pos); }
.dm-trade-r.neg { color: var(--neg); }
.dm-trade-pnl {
  font-weight: 800;
  text-align: right;
  font-size: 13px;
  letter-spacing: -0.012em;
}
.dm-trade-pnl.pos { color: var(--pos); }
.dm-trade-pnl.neg { color: var(--neg); }
.dm-empty {
  padding: 22px 0 18px;
  font-size: 12px;
  color: var(--text-3);
  text-align: center;
  font-style: italic;
}

.dm-bias-block {
  padding: 16px 22px 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.dm-bias-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-size: 10px;
  font-weight: 750;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.075em;
}
.dm-bias-hint {
  font-size: 10.5px;
  font-weight: 550;
  color: var(--text-3);
  text-transform: none;
  letter-spacing: -0.003em;
}
.dm-bias {
  width: 100%;
  resize: vertical;
  border: 1px solid var(--border-hair);
  border-radius: 12px;
  padding: 12px 14px;
  font: inherit;
  font-size: 13px;
  line-height: 1.55;
  color: var(--text);
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 98%, transparent), color-mix(in srgb, var(--surface) 99%, var(--surface-soft)));
  transition:
    border-color 180ms var(--ease-out),
    background 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
  font-family: var(--font);
  min-height: 84px;
}
.dm-bias::placeholder {
  color: var(--text-4);
  font-style: italic;
  letter-spacing: -0.003em;
}
.dm-bias:focus {
  outline: none;
  border-color: var(--pos);
  background: var(--surface);
  box-shadow: var(--shadow-focus);
}

.dm-foot {
  padding: 14px 22px 18px;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 10px;
  border-top: 1px solid var(--border-hair);
  background: color-mix(in srgb, var(--surface-soft) 35%, transparent);
}
/* Trade modal footer has a delete button on the far left, regular actions
   on the right — space-between layout, never compete visually. */
.td-foot {
  justify-content: space-between;
}
.td-foot-actions {
  display: flex;
  align-items: center;
  gap: 10px;
}

/* Subtle delete-trade affordance. Quiet text+icon by default so it never
   reads as a primary action. Hover surfaces a red tint. Two-stage delete
   (arm → confirm) prevents accidental clicks. */
.td-delete-btn {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 7px 10px;
  border-radius: 8px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-3);
  font: inherit;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: -0.003em;
  cursor: pointer;
  transition:
    color 140ms var(--ease-out),
    background 140ms var(--ease-out),
    border-color 140ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1);
}
.td-delete-btn svg {
  width: 14px;
  height: 14px;
  opacity: 0.85;
  transition: opacity 140ms var(--ease-out);
}
.td-delete-btn:hover {
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 7%, transparent);
  border-color: color-mix(in srgb, var(--neg) 22%, transparent);
  transform: translateY(-1px) scale(1.03);
}
.td-delete-btn:active { transform: translateY(0) scale(0.98); }
.td-delete-btn:hover svg { opacity: 1; }
.td-delete-btn:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--neg) 50%, transparent);
  outline-offset: 2px;
}
/* Confirm state — clicking once arms; the label flips to "Click again to
   confirm" and the button takes on a clear destructive tone. The arm state
   auto-clears after 4 seconds (handled in JS). */
.td-delete-btn.is-armed {
  color: #fff;
  background: linear-gradient(135deg, var(--neg-deep), var(--neg));
  border-color: var(--neg);
  box-shadow: 0 4px 14px -8px color-mix(in srgb, var(--neg) 65%, transparent);
}
.td-delete-btn.is-armed svg { opacity: 1; }
.td-delete-btn.is-armed .td-delete-label { display: none; }
.td-delete-btn.is-armed .td-delete-confirm { display: inline; }
.td-delete-btn .td-delete-confirm { display: none; }
.dm-btn {
  padding: 9px 16px;
  border-radius: 10px;
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    transform 160ms var(--ease-out),
    box-shadow 160ms var(--ease-out),
    border-color 160ms var(--ease-out);
}
.dm-btn-ghost {
  background: transparent;
  color: var(--text-3);
  border: 1px solid var(--border-hair);
}
.dm-btn-ghost:hover {
  background: var(--surface-soft);
  color: var(--text);
  border-color: var(--border);
}
.dm-btn-primary {
  background: linear-gradient(135deg, var(--pos-light), var(--pos));
  color: #fff;
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--pos) 34%, transparent);
  /* Bouncy transform easing so the hover lift reads as a gentle "pop". */
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1),
    box-shadow 220ms var(--ease-out),
    border-color 160ms var(--ease-out);
}
.dm-btn-primary:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 12px 24px -4px color-mix(in srgb, var(--pos) 46%, transparent);
}
.dm-btn-primary:active { transform: translateY(0) scale(0.99); }
.dm-btn.is-saved {
  background: linear-gradient(135deg, #5EE38C, #2BAA60);
  box-shadow: 0 4px 12px -2px rgba(43, 170, 96, 0.34);
  transform: none;
}
/* Destructive action button (delete / reset) — same weight/pop as the primary,
   toned in the loss colour. */
.dm-btn-danger {
  background: linear-gradient(135deg, color-mix(in srgb, var(--neg) 84%, #fff 16%), var(--neg));
  color: #fff;
  box-shadow: 0 4px 12px -2px color-mix(in srgb, var(--neg) 38%, transparent);
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1),
    box-shadow 220ms var(--ease-out),
    border-color 160ms var(--ease-out);
}
.dm-btn-danger:hover {
  transform: translateY(-2px) scale(1.03);
  box-shadow: 0 12px 24px -4px color-mix(in srgb, var(--neg) 50%, transparent);
}
.dm-btn-danger:active { transform: translateY(0) scale(0.99); }

/* Confirmation dialog — compact, centred (inherits .day-modal centring + the
   premium backdrop/panel). Used for destructive confirmations (delete / reset). */
.confirm-panel { width: min(424px, 92vw); }
.confirm-body {
  padding: 30px 28px 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}
.confirm-icon {
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  margin-bottom: 15px;
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 13%, transparent);
}
.confirm-icon svg { width: 23px; height: 23px; display: block; }
.confirm-panel .dm-eyebrow { color: var(--neg); margin-bottom: 7px; }
.confirm-title { font-size: 18px; line-height: 1.25; }
.confirm-message {
  margin-top: 10px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text-3);
  max-width: 34ch;
}
.confirm-foot {
  justify-content: center;
  gap: 10px;
  padding: 18px 22px 22px;
}
.confirm-foot .dm-btn { min-width: 120px; }
.gdpr-delete-panel { width: min(440px, 92vw); }
.gdpr-delete-panel .confirm-body { padding-bottom: 16px; }
.gdpr-confirm-label {
  margin: 16px 0 6px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
  letter-spacing: 0.01em;
  text-align: left;
  align-self: flex-start;
}
.gdpr-confirm-input {
  width: 100%;
  padding: 9px 12px;
  border: 1.5px solid var(--border);
  border-radius: 7px;
  background: var(--surface-2);
  color: var(--text);
  font-size: 14px;
  font-family: inherit;
  text-align: center;
  letter-spacing: 0.08em;
  outline: none;
  transition: border-color 120ms var(--ease-out);
}
.gdpr-confirm-input:focus { border-color: var(--neg); }
.gdpr-confirm-input::placeholder { color: var(--text-4); letter-spacing: 0.04em; }
.gdpr-delete-error {
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--neg);
  line-height: 1.4;
  align-self: flex-start;
}

/* Add Trade form */
.at-form {
  padding: 16px 22px 8px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
/* The Add-Trade form now carries the full Execution Review, so it can exceed the
   panel height. Let it scroll inside the fixed header/footer instead of clipping
   (the panel is overflow:hidden, max-height 88vh). min-height:0 lets a flex item
   shrink below its content so the scroll actually engages. Scoped to #at-form so
   the (short) account form keeps its natural sizing. */
#at-form {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  /* Wide landscape layout: trade facts in the left column, execution review in the
     right — reads as a modern card instead of one tall scroll. Collapses to a single
     column on narrow viewports (media query below). */
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  align-items: stretch;
  gap: 28px;
}
.at-col-main {
  display: flex;
  flex-direction: column;
  gap: 12px;
  min-width: 0;
}
/* Notes is the last field in the facts column — let it grow to fill the column so
   its bottom lines up with the taller execution-review column (balanced proportions
   instead of a stubby box with dead space beneath it). */
.at-col-main > .at-field {
  flex: 1 1 auto;
  min-height: 0;
}
.at-col-main > .at-field .at-textarea {
  flex: 1 1 auto;
  min-height: 120px;
  max-height: none;
}
/* Chart screenshots — the same 5-timeframe capture the Journal / trade-detail
   modal uses, so a trade can be logged with its charts in one pass. The slots
   reuse the .td-slots tiles verbatim; this wrapper only supplies section rhythm. */
.at-screenshots {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.at-row {
  display: grid;
  gap: 10px;
}

/* Execution Review block appended to Add Trade — separated from the trade-fact
   fields by a hairline, then it reuses the .td-review-group/.td-stars/.td-rv-chip
   styling verbatim (no per-control CSS needed). */
.at-review {
  /* Right column in the wide layout — a vertical hairline gutter separates it from
     the trade-fact column. (Reverts to a horizontal divider when the form stacks to
     one column; see the narrow-viewport media query below.) */
  padding-left: 28px;
  border-left: 1px solid var(--border-hair);
}
.at-review-head {
  display: flex;
  align-items: baseline;
  gap: 6px;
}
.at-review-head-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-2);
}
.at-review-head small {
  font-size: 9.5px;
  font-weight: 500;
  color: var(--text-4);
  text-transform: none;
  letter-spacing: 0;
}
/* The first review group sits right under the block header — trim its default
   top margin so the gap reads as one consistent step, not a double space. */
.at-review .td-review-group:first-of-type { margin-top: 10px; }
.at-row-2 { grid-template-columns: 1fr 1fr; }
/* Date · Time · Side — Side is the least-important field, so it sits last and a
   touch narrower than the two equal date/time inputs. */
.at-row-dts { grid-template-columns: 1fr 1fr 0.9fr; }
/* Symbol · Contracts — Symbol (combobox) gets the room; Contracts is a small int. */
.at-row-sym { grid-template-columns: 1.7fr 1fr; }

/* Date-entry mode switch — Picker (native control) vs Manual (clearable numeric
   text). Remembered across sessions; mirrors the dashboard weekday-range toggle. */
.at-entry-mode-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
}
.at-entry-mode-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-3);
}
.at-entry-mode-toggle {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 2px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  border: 1px solid var(--border-hair);
}
.at-entry-mode-seg {
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0.04em;
  padding: 2px 8px;
  border-radius: 4px;
  color: var(--text-3);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.at-entry-mode-seg:hover { color: var(--text-2); }
.at-entry-mode-seg.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 0 rgba(15,17,21,0.05);
}
.at-entry-mode-seg:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent);
  outline-offset: 1px;
}
.at-manual-input { font-variant-numeric: tabular-nums; }

/* Narrow viewports: stack the two Add-Trade columns back into one and swap the
   vertical gutter for the original horizontal divider above the review. */
@media (max-width: 720px) {
  #at-form {
    grid-template-columns: 1fr;
    gap: 14px;
  }
  .at-review {
    padding-left: 0;
    border-left: none;
    margin-top: 4px;
    padding-top: 14px;
    border-top: 1px solid var(--border-hair);
  }
}

/* Phones: native date/time inputs carry a min intrinsic width (their spinner UI)
   that won't shrink to a 3-up grid, so the Date·Time·Side row overflows and the
   Side toggle's "Short" button gets clipped at the modal edge. Keep Date + Time
   2-up and drop Side onto its own full-width line — both Long/Short buttons get
   room and nothing clips. */
@media (max-width: 520px) {
  .at-row-dts { grid-template-columns: 1fr 1fr; }
  .at-row-dts > .at-field:last-child { grid-column: 1 / -1; }
}

.at-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.at-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  display: flex;
  align-items: baseline;
  gap: 4px;
}
.at-label small {
  font-size: 9.5px;
  font-weight: 500;
  color: var(--text-4);
  text-transform: none;
  letter-spacing: 0;
}

.at-input {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border);
  border-radius: 9px;
  font: inherit;
  font-size: 13px;
  font-weight: 500;
  color: var(--text);
  background: var(--surface);
  transition: border-color 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
  font-variant-numeric: tabular-nums;
  font-family: var(--font);
  appearance: none;
  -webkit-appearance: none;
}
.at-input:focus {
  outline: none;
  border-color: var(--pos);
  box-shadow: var(--shadow-focus);
}
.at-textarea {
  resize: vertical;
  min-height: 60px;
  max-height: 180px;
  font-family: var(--font);
  font-weight: 400;
}

.at-provider-custom {
  margin-top: 4px;
}
.at-provider-custom[hidden] {
  display: none;
}

.at-fxreplay {
  margin-top: 2px;
  padding: 12px 13px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  background: var(--surface-sunken);
  display: flex;
  flex-direction: column;
  gap: 7px;
  animation: at-fxreplay-in 220ms var(--ease-out);
}
.at-fxreplay[hidden] { display: none; }
.at-fxreplay-head {
  display: flex;
  align-items: center;
  gap: 8px;
}
.at-fxreplay-title {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
}
.at-fxreplay-soon {
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--accent);
  background: color-mix(in srgb, var(--accent) 13%, transparent);
  border-radius: 999px;
  padding: 2px 7px;
}
.at-fxreplay-desc {
  margin: 0;
  font-size: 11px;
  line-height: 1.5;
  color: var(--text-3);
}
.at-fxreplay-btn {
  align-self: flex-start;
  padding: 6px 12px;
  border: 1px solid var(--border-strong);
  border-radius: 8px;
  background: var(--surface);
  font: inherit;
  font-size: 11.5px;
  font-weight: 640;
  color: var(--text);
  cursor: pointer;
  transition: background 140ms var(--ease-out), border-color 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.at-fxreplay-btn:hover { background: var(--surface-soft); border-color: var(--text-4); transform: translateY(-1px); }
.at-fxreplay-btn:active { transform: translateY(0); }
.at-fxreplay-ready {
  display: inline-flex; align-items: center; gap: 6px; margin-top: 8px;
  font-size: 11px; font-weight: 620; color: var(--mint);
}
.at-fxreplay-ready[hidden] { display: none; }
@keyframes at-fxreplay-in {
  from { opacity: 0; transform: translateY(-3px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Settings → import target hint + post-import result card */
.settings-import-target {
  margin: 9px 2px 0; font-size: 11px; font-weight: 540; color: var(--text-3);
}
.settings-import-result {
  margin-top: 12px; padding: 13px 15px; border-radius: 12px;
  display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap;
  background: color-mix(in srgb, var(--mint) 8%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--mint) 26%, var(--border));
  animation: at-fxreplay-in 220ms var(--ease-out);
}
.settings-import-result[hidden] { display: none; }
.settings-import-result-main { display: flex; align-items: center; gap: 11px; min-width: 0; }
.settings-import-result-icon {
  width: 30px; height: 30px; flex: none; border-radius: 50%; display: grid; place-items: center;
  font-size: 15px; color: var(--mint);
  background: color-mix(in srgb, var(--mint) 16%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--mint) 30%, var(--border));
}
.settings-import-result-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.settings-import-result-text strong { font-size: 13px; font-weight: 740; color: var(--text); }
.settings-import-result-text span { font-size: 11.5px; font-weight: 560; color: var(--text-3); }
.settings-import-result-actions { display: flex; align-items: center; gap: 8px; }
.settings-import-dismiss {
  appearance: none; border: 1px solid var(--border); background: var(--surface);
  border-radius: 8px; padding: 7px 13px; font: inherit; font-size: 11.5px; font-weight: 620;
  color: var(--text-3); cursor: pointer; transition: background 140ms, border-color 140ms, color 140ms;
}
.settings-import-dismiss:hover { background: var(--surface-soft); color: var(--text-2); border-color: var(--border-strong); }
.settings-import-review {
  appearance: none; border: 0; border-radius: 8px; padding: 7px 15px;
  font: inherit; font-size: 11.5px; font-weight: 700; color: #fff; background: var(--pos); cursor: pointer;
  transition: transform 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
.settings-import-review:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.settings-import-review:active { transform: translateY(0); }

/* CSV import history — one row per past upload, with a delete that removes the
   trades that import added. Mirrors the restrained card language above. */
.settings-history-list { display: flex; flex-direction: column; gap: 8px; }
.settings-history-empty {
  margin: 0; padding: 13px 2px; font-size: 12px; font-weight: 540; color: var(--text-3);
}
.settings-history-row {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 10px 13px; border-radius: 11px;
  background: var(--surface); border: 1px solid var(--border-hair);
  transition: background 140ms, border-color 140ms;
}
.settings-history-row:hover { background: var(--surface-soft); border-color: var(--border); }
.settings-history-row.is-reviewable { cursor: pointer; }
.settings-history-row.is-reviewable:hover { border-color: color-mix(in srgb, var(--pos) 32%, var(--border)); }
.settings-history-row.is-reviewable:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent); outline-offset: 2px;
}
.settings-history-main { display: flex; align-items: center; gap: 11px; min-width: 0; }
.settings-history-actions { display: flex; align-items: center; gap: 6px; flex: none; }
.settings-history-go {
  display: grid; place-items: center; width: 20px; height: 30px; color: var(--text-3);
  opacity: 0.5; transition: opacity 140ms, transform 140ms, color 140ms;
}
.settings-history-row.is-reviewable:hover .settings-history-go { opacity: 1; color: var(--pos); transform: translateX(2px); }
.settings-history-go svg { width: 16px; height: 16px; }
.settings-history-badge {
  flex: none; padding: 4px 8px; border-radius: 6px;
  font-size: 9px; font-weight: 720; letter-spacing: 0.06em; text-transform: uppercase;
  color: var(--text-3); background: var(--surface-soft); border: 1px solid var(--border-hair);
}
.settings-history-badge--fxr {
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 10%, var(--surface));
  border-color: color-mix(in srgb, var(--pos) 24%, var(--border));
}
.settings-history-text { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.settings-history-text strong {
  font-size: 12.5px; font-weight: 680; color: var(--text);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 34ch;
}
.settings-history-text span { font-size: 11px; font-weight: 540; color: var(--text-3); }
.settings-history-del {
  appearance: none; flex: none; width: 30px; height: 30px; display: grid; place-items: center;
  border-radius: 8px; border: 1px solid var(--border); background: var(--surface);
  color: var(--text-3); cursor: pointer;
  transition: color 140ms, border-color 140ms, background 140ms;
}
.settings-history-del:hover {
  color: var(--neg);
  border-color: color-mix(in srgb, var(--neg) 40%, var(--border));
  background: color-mix(in srgb, var(--neg) 8%, var(--surface));
}
.settings-history-del svg { width: 15px; height: 15px; }

select.at-input {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none'><path d='M6 9L12 15L18 9' stroke='%23515154' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  padding-right: 28px;
}
:root[data-theme="dark"] select.at-input {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 24 24' fill='none'><path d='M6 9L12 15L18 9' stroke='%23A0A8B8' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
}

.at-side-toggle {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--surface-sunken);
  border-radius: 9px;
  padding: 3px;
  gap: 2px;
  height: 36px;
}
.at-side-btn {
  padding: 6px 8px;
  border-radius: 7px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-3);
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
.at-side-btn:hover { color: var(--text); }
.at-side-btn.active[data-side="Long"] {
  background: linear-gradient(135deg, rgba(92,200,255,0.20), rgba(18,152,216,0.14));
  color: var(--pos);
  box-shadow: 0 1px 2px rgba(18,152,216,0.18);
}
.at-side-btn.active[data-side="Short"] {
  background: linear-gradient(135deg, rgba(185,28,28,0.16), rgba(127,29,29,0.12));
  color: var(--neg);
  box-shadow: 0 1px 2px rgba(185,28,28,0.16);
}

.side-stat-card {
  display: flex;
  align-items: stretch;
  justify-content: space-between;
  gap: 6px;
  padding: 12px 16px;
  min-height: 0;
}

.ssc-item {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  min-width: 0;
}

.ssc-label {
  font-size: 9px;
  font-weight: 800;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.ssc-value {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.ssc-value small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  margin-left: 1px;
}
.ssc-value.pos { color: var(--pos); }
.ssc-value.neg { color: var(--neg); }

.ssc-sub {
  font-size: 9.5px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}

.ssc-divider {
  width: 1px;
  background: var(--border-hair);
  margin: 2px 0;
}

.instruments-card .ic-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
}

.instruments-card h2 {
  font-size: 14px;
  font-weight: 700;
  letter-spacing: -0.005em;
}

.instruments-card .ic-sub {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 500;
  margin-top: 1px;
}

.instruments-card .ic-total {
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.instruments-card .ic-total.pos { color: var(--pos); }
.instruments-card .ic-total.neg { color: var(--neg); }

.instruments-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
  flex: 1;
  align-content: start;
}

.ic-row {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) auto;
  align-items: center;
  gap: 9px;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
}
.ic-row:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Neutral symbol display — single uniform style, no per-symbol colors */
.ic-sym {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: 0.02em;
  flex-shrink: 0;
  min-width: 32px;
  padding: 2px 6px;
  border-radius: 5px;
  background: var(--surface-sunken);
  text-align: center;
}

.trades-sym {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.02em;
}

.dm-trade-sym {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: 0.02em;
}

.ic-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 4px;
  min-width: 0;
}
.ic-name-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  min-width: 0;
}
.ic-name {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
}
.ic-share {
  font-size: 10px;
  color: var(--text-3);
  font-weight: 600;
}
.ic-bar-track {
  height: 4px;
  border-radius: 999px;
  background: rgba(0,0,0,0.05);
  overflow: hidden;
}
.ic-bar-fill {
  display: block;
  height: 100%;
  width: 100%;
  transform: scaleX(0);
  transform-origin: left center;
  border-radius: inherit;
  transition: transform 1200ms var(--ease-out);
}
.ic-bar-fill.pos { background: linear-gradient(90deg, var(--pos-light), var(--pos)); }
.ic-bar-fill.neg { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }

.ic-amount {
  text-align: right;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.ic-amount.pos { color: var(--pos); }
.ic-amount.neg { color: var(--neg); }
.ic-amount small {
  display: block;
  font-size: 9px;
  color: var(--text-3);
  font-weight: 600;
}

.chart-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}

.chart-title {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.005em;
  color: var(--text);
}

.chart-sub {
  font-size: 11.5px;
  color: var(--text-3);
  font-weight: 500;
  margin-top: 2px;
}

.chart-stats {
  display: flex;
  align-items: center;
  gap: 10px;
}

.cstat { display: flex; flex-direction: column; gap: 2px; align-items: flex-end; }
.cstat-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.cstat-value {
  font-size: 13.5px;
  font-weight: 750;
  letter-spacing: -0.01em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.cstat-pos { color: var(--pos); }
.cstat-neg { color: var(--neg); }

.chart-toggle {
  display: flex;
  background: var(--surface-sunken);
  border-radius: 8px;
  padding: 3px;
  gap: 2px;
}
.chart-actions {
  display: flex;
  align-items: center;
  gap: 8px;
}
.seg {
  padding: 5px 8px;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
  border-radius: 6px;
  transition: background 160ms var(--ease-out), color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.seg.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0,0,0,0.08);
}
.seg:not(.active):hover { color: var(--text-2); }

.chart-zoom-controls {
  display: flex;
  align-items: center;
  gap: 3px;
}

.chart-icon-btn {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  border-radius: 7px;
  color: var(--text-3);
  background: var(--surface);
  border: 1px solid var(--border);
  transition: color 160ms var(--ease-out), background 160ms var(--ease-out);
}

.chart-icon-btn:hover {
  color: var(--text);
  background: var(--surface-soft);
}

.chart-canvas-wrap {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  height: auto;
  width: 100%;
}
.chart-canvas-md { min-height: 158px; flex: 0 0 auto; height: 168px; }
.chart-canvas-wrap canvas { width: 100% !important; height: 100% !important; }

/* Equity card — perfectly flat institutional surface. No background gradient,
   no blue glow, no decorative overlay: the area above the curve must read as
   clean white (light) / clean slate (dark) so the only colour in the chart is
   the diverging fill BETWEEN the line and the X-axis. */
.chart-balance {
  background: var(--surface);
  overflow: hidden;
  position: relative;
  /* The equity curve is the page's emotional #1, so its card physically sits
     forward of every peer: a deeper, wider ambient shadow lifts it off the
     dashboard plane while the mini-stat / edge / calendar cards stay on the
     base elevation. Hierarchy through depth, not by dimming the rest. */
  border-color: var(--border-strong);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.62),
    0 2px 10px rgba(15, 17, 21, 0.085),
    0 24px 60px rgba(15, 17, 21, 0.115);
}
:root[data-theme="dark"] .chart-balance {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.07),
    0 2px 12px rgba(0, 0, 0, 0.55),
    0 26px 66px rgba(0, 0, 0, 0.58);
}
.chart-balance:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.72),
    0 3px 12px rgba(15, 17, 21, 0.10),
    0 30px 72px rgba(15, 17, 21, 0.14);
}
:root[data-theme="dark"] .chart-balance:hover {
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.09),
    0 3px 14px rgba(0, 0, 0, 0.62),
    0 32px 80px rgba(0, 0, 0, 0.64);
}

/* Chart hero header — FTMO-style */
.chart-head-hero {
  align-items: flex-start;
  padding: 2px 2px 4px;
}

.chart-head-left {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}

.chart-eyebrow {
  font-size: 10.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.chart-hero {
  display: flex;
  align-items: baseline;
  gap: 2px;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.chart-hero-sign {
  font-size: 22px;
  font-weight: 750;
  color: var(--pos);
  margin-right: 2px;
}
.chart-hero-sign.neg { color: var(--neg); }
.chart-hero-currency {
  font-size: 20px;
  font-weight: 700;
  color: var(--text-2);
  margin-right: 1px;
  letter-spacing: -0.01em;
}
.chart-hero-amount {
  font-size: 32px;
  font-weight: 800;
  letter-spacing: -0.022em;
  color: var(--text);
}
:root[data-theme="dark"] .chart-hero-amount { color: #F4F6FA; }
.chart-hero.is-neg .chart-hero-amount { color: var(--neg); }

.chart-hero-meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-3);
  flex-wrap: wrap;
}
.chart-delta {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  padding: 2px 7px;
  border-radius: 6px;
  background: var(--pos-soft);
  color: var(--pos);
}
.chart-delta.neg {
  background: var(--neg-soft);
  color: var(--neg);
}
.chart-meta-dot { opacity: 0.5; }
.chart-meta-text strong { font-weight: 700; }
.chart-meta-text strong.pos { color: var(--pos); }
.chart-meta-text strong.neg { color: var(--neg); }

/* START label + end marker removed — chart stays clean, TradeZella-style.
   Reference baseline ($100k) is drawn as a dotted line by the chart plugin. */

.chart-end-pulse {
  position: absolute;
  width: 13px;
  height: 13px;
  margin: -6.5px;
  border-radius: 50%;
  background: linear-gradient(135deg, var(--pos-light), var(--pos));
  border: 2px solid #FFFFFF;
  box-shadow: 0 4px 12px rgba(18, 152, 216, 0.42);
  opacity: 0;
  pointer-events: none;
  transition: opacity 600ms 800ms var(--ease-out);
  z-index: 2;
}

/* Radar "ping" on a GPU-composited pseudo-element (transform + opacity) rather
   than an infinitely-animated box-shadow spread, which repainted a large
   blurred region every frame for the whole time the dashboard stayed open. */
.chart-end-pulse::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 13px;
  height: 13px;
  border-radius: 50%;
  background: rgba(92, 200, 255, 0.55);
  transform: translate(-50%, -50%) scale(1);
  z-index: -1;
  pointer-events: none;
  animation: chart-pulse 2.4s ease-out infinite;
  animation-delay: 1.2s;
}

@keyframes chart-pulse {
  0%   { opacity: 0.55; transform: translate(-50%, -50%) scale(1); }
  70%  { opacity: 0;    transform: translate(-50%, -50%) scale(3.4); }
  100% { opacity: 0;    transform: translate(-50%, -50%) scale(1); }
}

.chart-end-tag {
  position: absolute;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 1px;
  padding: 6px 9px;
  background: var(--surface);
  border: 1px solid rgba(18, 152, 216, 0.20);
  border-radius: 9px;
  box-shadow: 0 8px 20px rgba(18, 152, 216, 0.16), 0 1px 2px rgba(0, 0, 0, 0.04);
  opacity: 0;
  transform: translate(12px, -110%);
  pointer-events: none;
  z-index: 3;
  transition: opacity 600ms 1000ms var(--ease-out), transform 600ms 1000ms var(--ease-out);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.chart-end-tag .tag-label {
  font-size: 8.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}
.chart-end-tag .tag-value {
  font-size: 11.5px;
  font-weight: 800;
  color: var(--pos);
  letter-spacing: 0;
}

.chart-end-pulse.is-ready,
.chart-end-tag.is-ready {
  opacity: 1;
}
.chart-end-tag.is-ready { transform: translate(12px, -125%); }

.edge-list-card {
  padding: 10px 12px 8px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-height: 0;
}

.hourly-card,
.weekday-card {
  align-self: stretch;
  min-height: 0;
}

.weekday-card .edge-rank-list,
.hourly-card .edge-rank-list {
  display: flex;
  flex-direction: column;
  flex: 1;
  min-height: 0;
}
/* Weekday rows are a fixed set of 5 — pack them tightly with the
   hairline separators doing the visual rhythm work instead of gaps.
   Hourly has 4 active hours from the data; same treatment. */
.weekday-card .edge-rank-list { gap: 0; }
.hourly-card .edge-rank-list { gap: 0; overflow: hidden; }

/* Refined edge row — restored 28-30px min so they read as proper data rows,
   not crushed strips. Hairline bottom-border provides the visual rhythm
   instead of gap; padding-block inside each row gives the breathing space. */
.weekday-card .edge-row,
.hourly-card .edge-row {
  flex: 1 1 0;
  min-height: 0;
  padding: 4px 0;
  align-items: center;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 80%, transparent);
  cursor: pointer;
  transition: background 140ms var(--ease-out);
}
.weekday-card .edge-row:hover,
.hourly-card .edge-row:hover {
  background: color-mix(in srgb, var(--surface-soft) 60%, transparent);
}
.weekday-card .edge-row:focus-visible,
.hourly-card .edge-row:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent);
  outline-offset: -2px;
  border-radius: 6px;
}
/* Min-height: pixel-tight floor so the 5 weekday rows are guaranteed visible
   inside the 178px grid slot, and the 4 hourly rows inside 144px. */
.hourly-card .edge-row { min-height: 26px; }
.weekday-card .edge-row { min-height: 24px; }
.weekday-card .edge-row:last-child,
.hourly-card .edge-row:last-child { border-bottom: 0; }

.weekday-card .edge-row > .edge-name,
.hourly-card .edge-row > .edge-name {
  font-size: 12px;
  /* Single-line layout: label and trade-count inline, with a dot separator.
     Reads like an institutional list row instead of a stacked card. */
  display: inline-flex;
  align-items: baseline;
  gap: 7px;
}
.weekday-card .edge-row > .edge-amount,
.hourly-card .edge-row > .edge-amount { font-size: 12px; }

.edge-list-card .edge-row .edge-name small {
  font-size: 10px;
  font-weight: 550;
  line-height: 1;
  margin: 0;
  color: var(--text-3);
  letter-spacing: -0.003em;
  /* Dot separator carried by the small element so the JS doesn't need to
     change. The dot is rendered before the count text. */
  position: relative;
  padding-left: 11px;
}
.edge-list-card .edge-row .edge-name small::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--text-4);
}

.edge-list-card .edge-amount small {
  display: none;
}

.weekday-card .edge-row .edge-bar-track,
.hourly-card .edge-row .edge-bar-track {
  height: 6px;
}

.edge-card-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 10px;
  flex-shrink: 0;
}
.edge-card-head-right {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/* Weekday range toggle — tiny segmented control. M–F is the default (most
   traders); S–F is for forex/futures users who run Sunday-evening sessions.
   Stays quiet at rest, becomes a clear pill once a non-default range is
   chosen. */
.weekday-range-toggle {
  display: inline-flex;
  align-items: center;
  gap: 1px;
  padding: 2px;
  border-radius: 6px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  border: 1px solid var(--border-hair);
}
.weekday-range-seg {
  font-size: 9px;
  font-weight: 750;
  letter-spacing: 0.04em;
  padding: 2px 6px;
  border-radius: 4px;
  color: var(--text-3);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
  font-variant-numeric: tabular-nums;
}
.weekday-range-seg:hover { color: var(--text-2); }
.weekday-range-seg.active {
  background: var(--surface);
  color: var(--text);
  box-shadow: 0 1px 0 rgba(15,17,21,0.05);
}
.weekday-range-seg:focus-visible {
  outline: 2px solid color-mix(in srgb, var(--pos) 50%, transparent);
  outline-offset: 1px;
}

.edge-card-head h2 {
  font-size: 12.5px;
  font-weight: 750;
  letter-spacing: -0.005em;
  margin: 0;
}

.edge-card-sub {
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.edge-card-head .stat-label { font-size: 10px; }

.edge-total {
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}
.edge-total.pos { color: var(--pos); }
.edge-total.neg { color: var(--neg); }

.edge-rank-list {
  display: grid;
  gap: 0;
  flex: 1;
  align-content: stretch;
}

.edge-row {
  display: grid;
  /* Label column gets more room now that label + trade-count live on one
     line ("Monday · 23 trades"). Bar gets a flexible middle slot; amount
     keeps its fixed-width slot so the right-edge digits align tidily. */
  grid-template-columns: minmax(96px, auto) minmax(50px, 1fr) 78px;
  align-items: center;
  gap: 12px;
  min-height: 24px;
  padding: 4px 0;
  font-variant-numeric: tabular-nums;
}

.edge-name {
  color: var(--text);
  font-size: 11.5px;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.005em;
  white-space: nowrap;
}

.edge-bar-track {
  position: relative;
  height: 6px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(0, 0, 0, 0.055);
}

.edge-bar {
  position: absolute;
  top: 0;
  bottom: 0;
  border-radius: inherit;
  transform-origin: left center;
  animation: edge-grow 900ms var(--ease-out) both;
}

.edge-row.pos .edge-bar {
  left: 50%;
  background: linear-gradient(90deg, var(--pos-light), var(--mint));
}

.edge-row.neg .edge-bar {
  right: 50%;
  background: linear-gradient(90deg, var(--neg-deep), var(--neg));
  transform-origin: right center;
}

.edge-amount {
  text-align: right;
  font-size: 11.5px;
  font-weight: 800;
  line-height: 1.15;
}
.edge-row.pos .edge-amount { color: var(--pos); }
.edge-row.neg .edge-amount { color: var(--neg); }

.edge-row small {
  display: block;
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 600;
  margin-top: 1px;
}

.grid-row.performance-row {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: stretch;
  gap: 10px;
}

.performance-row .trades-card { grid-column: span 3; }
.performance-row .weekday-card { grid-column: span 2; }

.risk-card {
  min-height: auto;
}

@keyframes edge-grow {
  from { transform: scaleX(0); opacity: 0.35; }
  to { transform: scaleX(1); opacity: 1; }
}

.legend {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}

.leg-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 2px;
  margin-right: 6px;
  vertical-align: middle;
}
.leg-pos { background: var(--pos); }
.leg-neg { background: var(--neg); }

.legend-scale { gap: 8px; font-size: 11px; }
.scale-min, .scale-max { font-variant-numeric: tabular-nums; }
.scale-bar {
  width: 100px;
  height: 6px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--neg), var(--neg-deep) 30%, #E5E5E7 50%, var(--pos-light) 70%, var(--pos));
}

/* ============================================================
   Grid rows
   ============================================================ */

.grid-row {
  display: grid;
  grid-template-columns: 1.7fr 1fr;
  gap: 10px;
}

.grid-row-2 {
  grid-template-columns: 1fr;
}

.stat-stack {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.stat-card {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 10px;
  padding: 13px 14px;
  align-items: flex-start;
}

.stat-icon {
  width: 34px;
  height: 34px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: var(--pos-soft);
  color: var(--pos);
}
.stat-icon-pos { background: var(--pos-soft-2); color: var(--pos); }
.stat-icon-neutral {
  background: linear-gradient(135deg, rgba(175, 82, 222, 0.12) 0%, rgba(175, 82, 222, 0.04) 100%);
  color: var(--purple);
}

.stat-body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.stat-label {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.stat-value-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
}
.stat-value {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.stat-value small {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}
.stat-delta {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.stat-delta.pos { color: var(--pos); }
.stat-delta.neg { color: var(--neg); }
.stat-delta.neutral { color: var(--purple); }

/* Discipline row */
.discipline-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: 7px;
  padding: 7px 0 0;
  border-top: 1px solid var(--border-hair);
}
.dis-item { display: flex; flex-direction: column; gap: 1px; }
.dis-num {
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.dis-num small {
  font-size: 10px;
  font-weight: 500;
  color: var(--text-3);
}
.dis-label {
  font-size: 10px;
  font-weight: 500;
  color: var(--text-3);
}

.discipline-strip {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding: 8px 4px 0;
  border-top: 1px solid var(--border-hair);
}
.discipline-strip .dis-item { flex-direction: column; gap: 1px; }
.dis-divider {
  width: 1px;
  height: 18px;
  background: var(--border);
}

/* ============================================================
   Trades table
   ============================================================ */

.trades-card {
  padding: 12px 4px 4px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 0;
}

.trades-card .chart-head { padding-right: 14px; padding-bottom: 4px; }

.link-more {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--pos);
  padding: 4px 8px;
  border-radius: 6px;
  transition: background 160ms var(--ease-out);
}
.link-more:hover { background: var(--pos-soft); }

/* Dashboard Recent Trades "View all" — demoted from a loud blue text-link to a
   quiet uppercase action that matches the muted card subs (.edge-card-sub /
   .ic-sub) elsewhere on the dashboard. It only lights up on hover, so at rest
   the header reads as calmly as every sibling card head. */
.trades-head-compact .link-more {
  font-size: 9.5px;
  font-weight: 800;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-3);
  padding: 3px 7px;
  gap: 3px;
}
.trades-head-compact .link-more svg { width: 9px; height: 9px; opacity: 0.85; }
.trades-head-compact .link-more:hover { color: var(--pos); background: var(--pos-soft); }

.table-wrap {
  overflow: auto;
  padding-right: 14px;
  flex: 1;
}

.trades {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.trades th {
  text-align: left;
  font-size: 10px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--text-3);
  padding: 4px 8px 6px;
  border-bottom: 1px solid var(--border-hair);
}

.trades th.num { text-align: right; }

.trades td {
  font-size: 12px;
  font-weight: 500;
  padding: 5px 8px;
  border-bottom: 1px solid var(--border-hair);
  color: var(--text);
}

.trades tbody tr {
  transition: background 160ms var(--ease-out), transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.trades tbody tr:hover {
  background: var(--surface-soft);
  transform: translateY(-1px);
  box-shadow: inset 3px 0 0 var(--pos-soft-2);
}

.trades tbody tr:last-child td { border-bottom: 0; }

.trades td.num { text-align: right; font-weight: 600; }

.symbol-cell {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  color: var(--text);
  font-weight: 650;
}
.side-tag {
  font-size: 11px;
  font-weight: 600;
  padding: 0;
  border-radius: 0;
  letter-spacing: 0.01em;
  color: var(--text);
}

.trades td.pl-pos { color: var(--pos); }
.trades td.pl-neg { color: var(--neg); }

.r-tag {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}

/* ============================================================
   Performance / Settings pages
   ============================================================ */

.performance-grid,
.settings-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  flex: 1;
  min-height: 0;
}

.performance-grid {
  grid-template-columns: repeat(6, minmax(0, 1fr));
  grid-auto-rows: minmax(128px, auto);
  overflow-y: auto;
  padding: 2px 2px 12px;
  align-content: start;
}

.perf-card,
.settings-card {
  padding: 18px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 150px;
  overflow: hidden;
}

.perf-card-wide {
  grid-column: span 3;
  min-height: 178px;
}

.perf-card-table {
  grid-column: span 2;
  min-height: 230px;
}

.perf-card-compact { grid-column: span 1; min-height: 128px; }
.perf-card-medium { grid-column: span 2; min-height: 170px; }
.perf-card-large { grid-column: span 3; min-height: 250px; }
.perf-card-full { grid-column: 1 / -1; min-height: 230px; }

.perf-command-card {
  min-height: 190px;
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(360px, 1fr);
  align-items: stretch;
  gap: 14px;
  background:
    radial-gradient(circle at 8% 0%, rgba(92, 200, 255, 0.10), transparent 34%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 94%, var(--surface-sunken)), var(--surface));
}

.perf-command-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}

.perf-command-card .perf-hero-row {
  flex-direction: column;
  align-items: flex-start;
  gap: 8px;
}

.perf-command-card .perf-hero-row strong {
  font-size: clamp(42px, 5vw, 72px);
  letter-spacing: 0;
}

.perf-command-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.perf-command-metrics .perf-metric {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: 72px;
  border-radius: 16px;
  background: color-mix(in srgb, var(--surface-soft) 78%, transparent);
}

.perf-focus-card {
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 92%, var(--surface-sunken)), var(--surface));
}

.perf-mini {
  min-height: 118px;
  background: var(--surface);
}

.perf-hero-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}

.perf-hero-row strong.pos,
.perf-card strong.pos,
.perf-row small.pos,
.perf-metric-value.pos { color: var(--pos); }
.perf-hero-row strong.neg,
.perf-card strong.neg,
.perf-row small.neg,
.perf-metric-value.neg { color: var(--neg); }

.perf-metric-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  margin-top: auto;
}

.perf-metric-grid-wide {
  grid-template-columns: repeat(6, minmax(0, 1fr));
}

.perf-metric {
  min-width: 0;
  padding: 10px;
  border-radius: 12px;
  background: var(--surface-soft);
  border: 1px solid var(--border-hair);
}

.perf-metric-label {
  display: block;
  color: var(--text-3);
  font-size: 10px;
  font-weight: 750;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.perf-metric-value {
  display: block;
  margin-top: 4px;
  color: var(--text);
  font-size: 18px;
  font-weight: 850;
  font-variant-numeric: tabular-nums;
}

.perf-section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.perf-section-head strong {
  font-size: 16px;
  font-weight: 800;
}

.perf-label,
.settings-label {
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 750;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.perf-card strong {
  color: var(--text);
  font-size: clamp(28px, 3vw, 44px);
  font-weight: 800;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.perf-card small {
  color: var(--text-3);
  font-size: 12px;
  font-weight: 600;
}

.perf-list {
  display: grid;
  gap: 8px;
  margin-top: 4px;
}

.perf-row {
  display: grid;
  grid-template-columns: minmax(72px, 1fr) minmax(90px, 1.2fr) auto;
  align-items: center;
  gap: 10px;
  padding: 10px;
  border-radius: 12px;
  background: var(--surface-soft);
  border: 1px solid var(--border-hair);
}

.perf-row strong {
  font-size: 13px;
  font-weight: 800;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.perf-row span {
  min-width: 0;
  color: var(--text-2);
  font-size: 12px;
  font-weight: 650;
}

.perf-row small {
  color: var(--text-3);
  font-family: var(--mono);
  font-size: 11px;
  font-weight: 650;
}

.perf-table {
  width: 100%;
  border-collapse: collapse;
  font-variant-numeric: tabular-nums;
}

.perf-table th {
  padding: 7px 6px;
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 750;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  border-bottom: 1px solid var(--border-hair);
}

.perf-table td {
  padding: 8px 6px;
  color: var(--text);
  font-size: 12px;
  font-weight: 650;
  border-bottom: 1px solid var(--border-hair);
}

.perf-table td.num,
.perf-table th.num {
  text-align: right;
}

.perf-table tr:last-child td { border-bottom: 0; }

.perf-bar {
  height: 6px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--surface-sunken);
}

.perf-bar span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--mint));
}

.perf-bar.is-neg span {
  background: linear-gradient(90deg, var(--neg-soft-2), var(--neg));
}

.perf-empty {
  min-height: 82px;
  display: grid;
  place-items: center;
  border: 1px dashed var(--border);
  border-radius: 12px;
  color: var(--text-3);
  font-size: 12px;
  font-weight: 650;
  text-align: center;
}

.settings-card {
  grid-column: span 2;
}

.settings-card-compact {
  grid-column: span 1;
  min-height: 150px;
}

.settings-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--border-hair);
}

.settings-card h2 {
  margin-top: 3px;
  color: var(--text);
  font-size: 24px;
  font-weight: 800;
  letter-spacing: 0;
}

.settings-theme-toggle {
  max-width: 280px;
}

.settings-form {
  display: grid;
  /* Auto-fit so a lone visible control never strands at half/third width when
     siblings are [hidden] (e.g. Trading "Defaults" grid). The -2/-3 variants
     below keep the same recipe; the column count adapts to available width. */
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: 12px;
}

.settings-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.settings-field small {
  color: var(--text-3);
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.35;
}

.settings-field span,
.settings-toggle-row strong {
  color: var(--text);
  font-size: 12.5px;
  font-weight: 750;
}

.settings-input {
  min-height: 38px;
  padding: 8px 10px;
  border: 1px solid var(--border);
  border-radius: 11px;
  color: var(--text);
  background: color-mix(in srgb, var(--surface) 88%, var(--surface-sunken));
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  transition: border-color 160ms var(--ease-out), background 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}

.settings-input:focus {
  outline: none;
  border-color: var(--pos);
  background: var(--surface);
  box-shadow: var(--shadow-focus);
}

.settings-toggle-row {
  min-height: 54px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px;
  border: 1px solid var(--border);
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface) 72%, var(--surface-sunken));
  transition: transform 160ms var(--ease-out), border-color 160ms var(--ease-out), background 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}

.settings-toggle-row:hover,
.settings-toggle-row.is-hovered {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  background: var(--surface);
  box-shadow: var(--shadow-1);
}

.settings-toggle-row span {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.settings-toggle-row small {
  color: var(--text-3);
  font-size: 11.5px;
  font-weight: 600;
}

.settings-toggle-row input[type="checkbox"] {
  position: relative;
  width: 42px;
  height: 24px;
  flex: 0 0 auto;
  appearance: none;
  -webkit-appearance: none;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  background: var(--surface-sunken);
  cursor: pointer;
  box-shadow: inset 0 1px 2px rgba(0,0,0,0.08);
  transition: background 180ms var(--ease-out), border-color 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}

.settings-toggle-row input[type="checkbox"]::after {
  content: '';
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: var(--surface);
  box-shadow: 0 2px 7px rgba(0,0,0,0.22);
  transition: transform 200ms var(--ease-out), background 200ms var(--ease-out);
}

.settings-toggle-row input[type="checkbox"]:checked {
  border-color: color-mix(in srgb, var(--pos) 68%, transparent);
  background: color-mix(in srgb, var(--pos) 76%, #111827);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pos) 13%, transparent);
}

.settings-toggle-row input[type="checkbox"]:checked::after {
  transform: translateX(18px);
}

.page.is-entering .kpi-row > .card,
.page.is-entering .dashboard-grid > .card,
.page.is-entering .dashboard-grid > aside > .card,
.page.is-entering .tp-header,
.page.is-entering .tp-overview-card,
.page.is-entering .tp-filters,
.page.is-entering .tp-table-card,
.page.is-entering .perf-status,
.page.is-entering .perf-behavior-bar,
.page.is-entering .perf-block,
.page.is-entering .settings-toggle-row,
.page.is-entering .settings-field,
.page.is-entering .settings-action,
.page.is-entering .settings-setups-block {
  /* Secondary cascade layered on the page-level reveal: each item settles up a
     few px, staggered top→bottom via --enter-delay (set in restartPageEnter).
     Duration tracks the page reveal (~58% of it) so the cascade finishes in
     step with the slide instead of trailing it. */
  animation: page-item-in calc(var(--page-transition-duration, 480ms) * 0.58) cubic-bezier(0.16, 1, 0.3, 1) both;
  animation-delay: var(--enter-delay, 0ms);
}

:root.reduced-page-motion .page.is-entering .kpi-row > .card,
:root.reduced-page-motion .page.is-entering .dashboard-grid > .card,
:root.reduced-page-motion .page.is-entering .dashboard-grid > aside > .card,
:root.reduced-page-motion .page.is-entering .tp-header,
:root.reduced-page-motion .page.is-entering .tp-overview-card,
:root.reduced-page-motion .page.is-entering .tp-filters,
:root.reduced-page-motion .page.is-entering .tp-table-card,
:root.reduced-page-motion .page.is-entering .perf-status,
:root.reduced-page-motion .page.is-entering .perf-block,
:root.reduced-page-motion .page.is-entering .settings-toggle-row,
:root.reduced-page-motion .page.is-entering .settings-field,
:root.reduced-page-motion .page.is-entering .settings-action {
  animation-duration: 1ms;
  animation-delay: 0ms;
}

:root.reduced-page-motion .page.is-entering,
:root.reduced-page-motion .page.is-leaving {
  animation-duration: 1ms;
}

@keyframes page-item-in {
  from {
    opacity: 0;
    transform: translate3d(0, -32px, 0);
  }
  60% { opacity: 1; }
  to {
    opacity: 1;
    transform: translate3d(0, 0, 0);
  }
}

/* ============================================================
   Responsive
   ============================================================ */

@media (max-width: 1400px) {
  .kpi-row { grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 10px; }
  .kpi { min-height: 112px; }
  .kpi-value { font-size: 25px; }
  .wl-value { font-size: 15.5px; }
}

@media (max-width: 1180px) {
  body { overflow: auto; }
  .main {
    height: auto;
    min-height: 100vh;
    overflow: visible;
    padding: 68px 18px 26px;
  }
  .kpi-row { grid-template-columns: repeat(5, 1fr); }
  .kpi { min-height: 118px; }
  .dashboard-grid {
    flex: 0 0 auto;
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }
  /* Reset ALL explicit grid placements — without this, .left-bottom-stack
     (grid-column: 1/span 3) and .calendar-card (grid-column: 4/span 2) create
     implicit columns in the 1-col grid, collapsing it back to ~5 cols on tablet. */
  .chart-balance,
  .edge-stack,
  .trades-card,
  .left-bottom-stack,
  .calendar-card { grid-column: auto; grid-row: auto; }
  .edge-stack {
    display: grid;
    /* Single column: stats-pair → hourly → weekday stack cleanly at full width.
       The previous 1fr 1fr caused weekday to be orphaned in col-1 of row 2. */
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }
  /* left-bottom-stack: both rows auto so trades-card is not stuck at minmax(0,1fr)
     which collapses to 0 in a height-less flex parent on scrollable tablet pages. */
  .left-bottom-stack { grid-template-rows: auto auto; }
  /* Fixed height (not min-height) so .table-wrap{flex:1} gets a definite container
     height — prevents the ResizeObserver→row-grow→observer feedback loop that
     inflates the card to 33M px when the grid row is auto-sized. */
  .left-bottom-stack .trades-card { height: 320px; }
  .chart-canvas-wrap { height: 220px; }
  .chart-canvas-md { height: 166px; }
  .grid-row { grid-template-columns: 1fr; }
  .grid-row-2 { grid-template-columns: 1fr; }
  .tp-overview { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .td-layout { grid-template-columns: 1fr; }
  .td-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .perf-command-card { grid-template-columns: 1fr; }
  .performance-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .settings-grid { grid-template-columns: 1fr 1fr; }
  .perf-card-wide,
  .perf-card-table,
  .perf-card-large,
  .perf-card-full,
  .settings-card { grid-column: 1 / -1; }
  .perf-card-compact,
  .settings-card-compact { grid-column: span 1; }
  .perf-metric-grid-wide { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (max-width: 900px) {
  .top-nav { width: 100%; }
  .top-nav-panel {
    width: calc(100vw - 18px);
    padding: 10px;
    grid-template-columns: 1fr;
  }
  .account-switcher {
    left: 10px;
    top: 182px;
  }
  .nav { flex-wrap: wrap; justify-content: center; }
  .nav-panel-tools { display: grid; grid-template-columns: 1fr; justify-items: center; gap: 10px; }
  .nav-panel-head { align-items: flex-start; }
  .nav-account-mini { min-width: 0; }
  .kpi-row { grid-template-columns: repeat(2, 1fr); }
  .topbar { flex-direction: column; align-items: flex-start; }
  .tp-header { flex-direction: column; align-items: stretch; }
  .tp-filters-top { flex-wrap: wrap; }
  .tp-search,
  .tp-filters-top .tp-search { width: 100%; }
  .tp-filters-top .tp-sort { margin-left: 0; }
  .tp-overview { grid-template-columns: 1fr; }
  .td-grid { grid-template-columns: 1fr; }
  .td-panel { width: min(96vw, 720px); }
  .performance-grid,
  .settings-grid { grid-template-columns: 1fr; }
  .perf-card-wide,
  .perf-card-table,
  .perf-card-large,
  .perf-card-full,
  .perf-card-compact,
  .settings-card,
  .settings-card-compact { grid-column: auto; }
  .perf-metric-grid,
  .perf-metric-grid-wide,
  .settings-form,
  .td-review-grid { grid-template-columns: 1fr; }
}

/* Touch devices (iPad, iPhone): minimum 44px tap targets (Apple HIG).
   Hover-only UI (nav via pointermove) is replaced by click/tap via JS;
   this ensures all interactive nav elements are comfortably tappable. */
@media (pointer: coarse) {
  .top-nav-trigger { height: 44px; }
  .nav-item { min-height: 44px; padding-block: 10px; }
  .nav-account-mini { min-height: 44px; }
  /* Wider panel tap targets on touch */
  .nav-panel-tools .btn { min-height: 44px; }
}

/* ─── Touch-primary tablet: compact-desktop density ────────────────────────
   iPads with "Request Desktop Website" report a large CSS viewport
   (e.g. 2540 px wide, dpr 1), bypassing all max-width breakpoints and
   landing on the full desktop CSS — which clamps the layout to 100vh with
   overflow:hidden, making cards enormous and clipping content.

   This block preserves the DESKTOP STRUCTURE (5-col dashboard, multi-col
   pages, same card identity) but scales DENSITY down so everything fits the
   physical screen: smaller padding, tighter gaps, pinned chart heights, and
   a scroll-safe main container.  No one-column mobile stacking.
   ─────────────────────────────────────────────────────────────────────────── */
@media (pointer: coarse) and (hover: none) {
  /* Allow body to scroll — releases the desktop overflow:hidden clipping */
  body { overflow: auto; }

  /* Main: auto-height so content is never clipped; dvh accounts for browser
     chrome on Safari (avoids the 100vh = too-tall trap on iOS/iPadOS) */
  .main {
    height: auto;
    min-height: 100vh;
    min-height: 100dvh;
    overflow: visible;
    padding-top: 56px;
    padding-bottom: 12px;
    padding-inline: 10px;
    gap: 6px;
  }

  /* Dashboard grid: KEEP 5-column desktop structure.
     Switch rows from fraction-of-100vh (which creates 1000+ px rows on large
     viewports) to auto so cards size to their content + pinned canvas heights. */
  .dashboard-grid {
    flex: 0 0 auto;
    grid-template-rows: auto auto;
    gap: 6px;
  }

  /* KPI strip: keep 5-col, reduce height */
  .kpi-row { gap: 6px; }
  .kpi { min-height: 80px; padding: 8px 10px 6px; }

  /* Pin chart canvas heights — with auto row heights the canvas has no
     definite container to resolve flex:1 against */
  .chart-canvas-wrap { flex: 0 0 auto; height: 180px; }
  .chart-canvas-md   { flex: 0 0 auto; height: 140px; }

  /* Edge / left-bottom stacks: tighter gaps */
  .edge-stack { gap: 6px; }
  .left-bottom-stack { gap: 6px; }
  .left-bottom-stack .trades-card { height: 260px; }

  /* Card padding — compact but still readable */
  .card { padding: 10px 12px; }

  /* Touch nav targets (keep desktop nav structure) */
  .top-nav-trigger { height: 44px; }
  .nav-item { min-height: 44px; padding-block: 10px; }
  .nav-account-mini { min-height: 44px; }

  /* Trade detail panel: cap width to viewport */
  .td-panel { width: min(94vw, 860px); }

  /* Performance page: 2-col grid (same as ≤1180 px breakpoint) */
  .performance-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .perf-card-wide, .perf-card-table, .perf-card-large,
  .perf-card-full { grid-column: 1 / -1; }
  .perf-metric-grid-wide { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* Settings: 2-col grid */
  .settings-grid { grid-template-columns: 1fr 1fr; }
  .settings-card { grid-column: 1 / -1; }

  /* Trades overview: 3-col */
  .tp-overview { grid-template-columns: repeat(3, minmax(0, 1fr)); }

  /* ── No fixed overlays on tablet ──────────────────────────────────────────
     The nav, the LUCRA wordmark, and the account avatar/menu must NOT pin to
     the viewport on touch — they belong to the page and should scroll away
     with it. .app is position:relative and grows to full document height, so
     switching these from fixed → absolute anchors them to the document (not
     the viewport): they scroll naturally with content. Desktop is unaffected
     (this is scoped to the touch media query, where desktop keeps fixed). */
  .top-nav         { position: absolute; }
  /* avatar + menu base rules sit LATER in the source than this media block, so a
     same-specificity override would lose the source-order tiebreak and stay fixed.
     The body prefix lifts specificity (1,0,1 > 1,0,0) so the tablet rule wins. */
  body #user-avatar-btn { position: absolute; }
  body #user-menu-panel { position: absolute; }

  /* LUCRA: in the page flow above the title, scrolls with content. top:34 sits
     ~22px above the topbar title (main padding-top:56); left:10 matches the
     tablet content inset → renders as  LUCRA / <PageTitle>, scrolling together. */
  #lucra-resting {
    position: absolute;
    top: 34px;
    left: 10px;
  }

  /* Flying LUCRA clone: never render on touch — JS early-return handles the
     primary case, this ensures no flash if JS fires late or is delayed. */
  #lucra-fly { display: none !important; }
}

/* Desktop dashboard — scale-to-fit ONE non-scrolling screen (no per-monitor tuning).
   ------------------------------------------------------------------------------
   The cockpit is a single screen that NEVER scrolls and NEVER clips. On monitors
   TALL enough for the cards' content the base grid (flex:1 1 auto) just fills the
   stage, so big / tall screens feel spacious — the boxes grow. On screens too
   SHORT for the cards' hard content floors — the edge-stack clears ~430px (hourly
   141 + weekday 178 + stats-pair + gaps), the calendar + recent-trades clear the
   rest, so the grid wants ~800px — we must NOT scroll, crush or clip. Instead
   fitDashboard() (js/app.js) measures the available height and zooms the KPI row
   AND the grid down by ONE shared factor (--dash-zoom), so every box just gets
   proportionally smaller TOGETHER and the full cockpit still fits. That is the
   "boxes adapt to the monitor" model the user asked for: bigger monitor → bigger
   boxes; smaller monitor → all boxes smaller together. No reflow, no scrollbar,
   no overlap. (The gap between the two boxes lives on .page, not on either box,
   so it does not scale — fitDashboard holds it out of the scaled height budget.)

   • zoom (not transform): text AND the Chart.js canvas re-rasterise crisp at the
     reduced size, and zoom shrinks the layout box itself so nothing can overflow
     → no scrollbar, no clip. (A transform would keep the full-size layout box,
     re-introducing overflow, and soften text.)
   • NO width override: a width:auto box already fills its parent visually under
     zoom, because the browser perceives the containing block at 1/zoom. An explicit
     width:calc(100%/--dash-zoom) would apply the factor a SECOND time and overflow
     the stage by (1/zoom − 1) — clipped invisibly by .page-stage{overflow:clip},
     so it hid most of the right rail. Plain zoom fills the stage exactly (sideGap 0).
   • height is pinned to the 800px design floor so the cards' internal px floors
     stay fully satisfied BEFORE the uniform zoom — that is what guarantees no clip.
     The grid's intrinsic height is width-independent (edge-stack floors are fixed
     px; the calendar fills its row via flex; recent-trades rows are fixed px).
   The .is-fit-scaled class + factor are applied by JS only when the screen is
   genuinely too short (zoom < 1); at/above the floor the class is removed and the
   base flex-fill grows the boxes. While the onboarding checklist is present its own
   block scrolls the page, so the grid is left un-zoomed there. .main / body /
   .page-stage are untouched (every other page keeps its own scrolling). ≤1180px
   keeps its single-column reflow below. */
@media (min-width: 1181px) {
  .kpi-row.is-fit-scaled,
  .dashboard-grid.is-fit-scaled {
    /* zoom (not transform) re-rasterises text + canvas crisp at the reduced size
       and shrinks the layout box itself, so nothing overflows. NO width override:
       a width:auto box already fills its parent visually under zoom (the browser
       perceives the containing block at 1/zoom), so dividing the width by the zoom
       would apply the factor twice and overflow the stage by (1/zoom − 1). */
    zoom: var(--dash-zoom, 1);
  }
  .dashboard-grid.is-fit-scaled {
    /* pinned to the design floor so the cards' internal px floors stay satisfied
       BEFORE the uniform zoom — that is what guarantees no clip. */
    flex: 0 0 auto;
    height: 800px;
  }
}

/* ============================================================
   Performance page — institutional analytics surface
   ============================================================ */

.page-performance {
  padding: 4px 2px 6px;
  gap: clamp(10px, 1vh, 14px);
  overflow-y: auto;
  scrollbar-gutter: stable;
}
.page-performance > * { flex-shrink: 0; }

/* --- 1. KPI hero row --- */
.perf-kpis {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 8px;
}
.perf-kpi {
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  transition: transform 180ms var(--ease-out), box-shadow 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.perf-kpi:hover {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  box-shadow: 0 4px 14px rgba(15, 17, 21, 0.08);
}
:root[data-theme="dark"] .perf-kpi:hover {
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.38);
}
.perf-kpi-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.07em;
}
.perf-kpi-value {
  font-size: 22px;
  font-weight: 800;
  letter-spacing: -0.02em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
  margin-top: 2px;
}
.perf-kpi-value.pos { color: var(--pos); }
.perf-kpi-value.neg { color: var(--neg); }
.perf-kpi-value small {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-3);
  margin-left: 1px;
}
.perf-kpi-foot {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.perf-kpi-foot.pos { color: var(--pos); }
.perf-kpi-foot.neg { color: var(--neg); }

/* --- 2. Equity + drawdown chart --- */
.perf-equity-card {
  padding: 14px 16px 12px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  flex-shrink: 0;
  min-height: 320px;
}
.perf-equity-head {
  align-items: center;
  flex-wrap: wrap;
}
.perf-equity-head .chart-actions { gap: 8px; flex-wrap: wrap; }
.perf-equity-main {
  position: relative;
  height: 220px;
  width: 100%;
  margin-top: 2px;
}
.perf-equity-dd {
  position: relative;
  height: 56px;
  width: 100%;
  margin-top: 2px;
}
.perf-equity-main canvas,
.perf-equity-dd canvas {
  width: 100% !important;
  height: 100% !important;
}

/* --- 3. Performance breakdown row --- */
.perf-grid-4 {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
.perf-breakdown {
  padding: 13px 15px 12px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
.perf-card-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.perf-card-head h3 {
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
.perf-card-meta {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
  letter-spacing: 0.02em;
}

/* Horizontal bar primitive — reused across breakdown cards */
.perf-hbar {
  height: 5px;
  background: var(--surface-sunken);
  border-radius: 999px;
  overflow: hidden;
}
.perf-hbar-fill {
  display: block;
  height: 100%;
  width: 0;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  transition: width 800ms var(--ease-out);
}
.perf-hbar-fill.pos { background: linear-gradient(90deg, var(--pos-light), var(--pos)); }
.perf-hbar-fill.neg { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }

/* Long vs Short */
.perf-ls-rows { display: flex; flex-direction: column; gap: 12px; }
.perf-ls-row { display: flex; flex-direction: column; gap: 6px; }
.perf-ls-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.perf-ls-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: 10.5px;
  font-weight: 800;
  padding: 3px 8px;
  border-radius: 6px;
  letter-spacing: 0.04em;
}
.perf-ls-tag.long { background: var(--pos-soft); color: var(--pos); }
.perf-ls-tag.short { background: var(--neg-soft); color: var(--neg); }
.perf-ls-tag::before {
  content: '';
  width: 5px; height: 5px;
  border-radius: 50%;
  background: currentColor;
}
.perf-ls-pnl {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
}
.perf-ls-row[data-side="long"] .perf-ls-pnl { color: var(--pos); }
.perf-ls-row[data-side="short"] .perf-ls-pnl { color: var(--neg); }
.perf-ls-row[data-side="short"] .perf-hbar-fill { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }

.perf-ls-stats {
  display: flex;
  justify-content: space-between;
  gap: 8px;
  font-size: 10.5px;
  font-weight: 500;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.perf-ls-stats strong {
  font-weight: 700;
  color: var(--text-2);
}

/* Generic rows (Sessions) */
.perf-rows { display: flex; flex-direction: column; gap: 10px; flex: 1; }
.perf-row {
  display: grid;
  grid-template-columns: 64px 1fr auto;
  align-items: center;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}
.perf-row-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.005em;
}
.perf-row-label small {
  display: block;
  font-size: 10px;
  font-weight: 500;
  color: var(--text-3);
  letter-spacing: 0;
  margin-top: 1px;
}
.perf-row-value {
  font-size: 12.5px;
  font-weight: 800;
  text-align: right;
  letter-spacing: -0.01em;
}
.perf-row-value.pos { color: var(--pos); }
.perf-row-value.neg { color: var(--neg); }

/* Weekday vertical bars */
.perf-weekday-bars {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 8px;
  flex: 1;
  align-items: end;
  padding-top: 6px;
}
.perf-wd {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  height: 100%;
  justify-content: flex-end;
}
.perf-wd-bar {
  width: 100%;
  border-radius: 4px 4px 2px 2px;
  min-height: 3px;
  transition: height 800ms var(--ease-out);
}
.perf-wd-bar.pos { background: linear-gradient(180deg, var(--pos-light), var(--pos)); }
.perf-wd-bar.neg { background: linear-gradient(180deg, var(--neg), var(--neg-deep)); }
.perf-wd-amount {
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.perf-wd-amount.pos { color: var(--pos); }
.perf-wd-amount.neg { color: var(--neg); }
.perf-wd-label {
  font-size: 9.5px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

/* Records grid */
.perf-records {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 16px;
  flex: 1;
}
.perf-record {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.perf-record-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.perf-record-value {
  font-size: 15px;
  font-weight: 800;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.perf-record-value.pos { color: var(--pos); }
.perf-record-value.neg { color: var(--neg); }
.perf-record-sub {
  font-size: 10px;
  font-weight: 500;
  color: var(--text-3);
}

/* --- 4. Instruments + Time heatmap row --- */
.perf-grid-mid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 10px;
}

/* Instruments table */
.perf-instruments-card {
  padding: 13px 15px 12px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}
.perf-inst-table {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 1;
}
.perf-inst-head,
.perf-inst-row {
  display: grid;
  grid-template-columns: 60px minmax(80px, 1fr) 56px 56px 56px 88px;
  align-items: center;
  gap: 10px;
  padding: 6px 4px;
  font-variant-numeric: tabular-nums;
}
.perf-inst-head {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  border-bottom: 1px solid var(--border-hair);
  padding-bottom: 8px;
}
.perf-inst-col-count,
.perf-inst-col-wr,
.perf-inst-col-rr,
.perf-inst-col-pnl { text-align: right; }

.perf-inst-row {
  font-size: 12.5px;
  font-weight: 600;
  border-radius: 8px;
  transition: background 140ms var(--ease-out);
  cursor: default;
}
.perf-inst-row:hover { background: var(--surface-soft); }
.perf-inst-sym {
  font-family: var(--mono);
  font-size: 11.5px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: 0.02em;
  padding: 2px 7px;
  border-radius: 5px;
  background: var(--surface-sunken);
  display: inline-block;
  text-align: center;
}
.perf-inst-bar {
  position: relative;
  display: flex;
  align-items: center;
  height: 10px;
}
.perf-inst-bar-track {
  width: 100%;
  height: 5px;
  background: var(--surface-sunken);
  border-radius: 999px;
  overflow: hidden;
}
.perf-inst-bar-fill {
  display: block;
  height: 100%;
  border-radius: inherit;
  transition: width 800ms var(--ease-out);
}
.perf-inst-bar-fill.pos { background: linear-gradient(90deg, var(--pos-light), var(--pos)); }
.perf-inst-bar-fill.neg { background: linear-gradient(90deg, var(--neg), var(--neg-deep)); }
.perf-inst-pnl { text-align: right; font-weight: 800; letter-spacing: -0.01em; }
.perf-inst-pnl.pos { color: var(--pos); }
.perf-inst-pnl.neg { color: var(--neg); }
.perf-inst-count,
.perf-inst-wr,
.perf-inst-rr {
  text-align: right;
  color: var(--text-2);
  font-weight: 600;
}

/* Time heatmap */
.perf-heatmap-card {
  padding: 13px 15px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
.perf-heat-legend {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
}
.perf-heat-scale {
  width: 56px;
  height: 5px;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--neg), var(--neg-deep) 25%, var(--surface-sunken) 50%, var(--pos-light) 75%, var(--pos));
}
.perf-heatmap {
  display: grid;
  grid-template-columns: 38px repeat(5, 1fr);
  grid-auto-rows: minmax(0, 1fr);
  gap: 3px;
  flex: 1;
  min-height: 200px;
}
.perf-heat-cell {
  border-radius: 5px;
  background: var(--surface-sunken);
  display: grid;
  place-items: center;
  font-size: 10px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: rgba(0,0,0,0.0);
  transition: transform 160ms var(--ease-out), box-shadow 160ms var(--ease-out), color 160ms var(--ease-out);
  position: relative;
}
.perf-heat-cell.label {
  background: transparent;
  font-size: 9.5px;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.perf-heat-cell:not(.label):hover {
  transform: scale(1.06);
  box-shadow: 0 4px 12px rgba(15, 17, 21, 0.18);
  z-index: 2;
  color: var(--text);
}
:root[data-theme="dark"] .perf-heat-cell:not(.label):hover {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.45);
  color: #FFFFFF;
}

/* --- 5. Calendar + Risk row --- */
.perf-grid-bottom {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  gap: 10px;
}

/* Calendar (re-uses cal-* tokens from dashboard, with bigger cells) */
.perf-calendar-card {
  padding: 13px 15px 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-height: 0;
}
.perf-cal-weekdays {
  margin-top: 0;
  grid-template-columns: repeat(7, 1fr);
}
.perf-cal-weekdays span { font-size: 10px; padding: 4px 0; }
.perf-cal-grid {
  grid-template-columns: repeat(7, 1fr);
  grid-auto-rows: minmax(46px, 1fr);
  gap: 4px;
  flex: 1;
  min-height: 240px;
}
.perf-cal-grid .cal-cell { padding: 5px 6px; min-height: 0; }
.perf-cal-grid .cal-day { font-size: 11px; }
.perf-cal-grid .cal-pnl { font-size: 10.5px; }
.perf-cal-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  padding-top: 6px;
  border-top: 1px solid var(--border-hair);
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.perf-cal-summary strong { color: var(--text-2); font-weight: 700; }
.perf-cal-summary .pos { color: var(--pos); }
.perf-cal-summary .neg { color: var(--neg); }

/* Risk analytics */
.perf-risk-card {
  padding: 13px 15px 14px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 0;
}
.perf-risk-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 14px;
  flex: 1;
  align-content: start;
}
.perf-risk-cell {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.perf-risk-label {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.perf-risk-value {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.015em;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.perf-risk-value.pos { color: var(--pos); }
.perf-risk-value.neg { color: var(--neg); }
.perf-risk-value small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  margin-left: 1px;
}
.perf-risk-sub {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-risk-hero {
  grid-column: 1 / -1;
  padding-top: 8px;
  border-top: 1px solid var(--border-hair);
  margin-top: 2px;
}
.perf-risk-hero .perf-risk-value { font-size: 22px; }

/* ============================================================
   Account balance tooltip + diagnostic performance/settings
   ============================================================ */

.chart-tooltip {
  position: absolute;
  z-index: 5;
  min-width: 186px;
  padding: 10px 12px 11px;
  border: 1px solid color-mix(in srgb, var(--border-strong) 80%, transparent);
  border-radius: 11px;
  background: color-mix(in srgb, var(--surface) 92%, var(--surface-sunken));
  box-shadow:
    0 18px 42px rgba(0, 0, 0, 0.22),
    inset 0 1px 0 rgba(255, 255, 255, 0.05);
  color: var(--text);
  pointer-events: none;
  opacity: 0;
  transform: translateY(-6px) scale(0.97);
  transition: opacity 120ms var(--ease-out), transform 120ms var(--ease-out), left 80ms var(--ease-out), top 80ms var(--ease-out);
  /* No backdrop-filter: this tooltip is repositioned via inline left/top on
     every mousemove over the chart — blurring the backdrop each frame was the
     single worst per-frame paint cost. Background is already opaque. */
  font-variant-numeric: tabular-nums;
}

.chart-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
}

.balance-tooltip-date,
.chart-tooltip span {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  color: var(--text-3);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.balance-tooltip-date {
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.chart-tooltip strong {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin: 6px 0 7px;
  padding-bottom: 7px;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 65%, transparent);
  font-size: 15px;
  font-weight: 850;
  letter-spacing: -0.012em;
}

.chart-tooltip strong small {
  font-size: 10.5px;
  font-weight: 700;
  opacity: 0.88;
  margin-left: auto;
}

.chart-tooltip b {
  font-weight: 800;
}

.performance-diagnostics {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1 1 auto;
  min-height: 0;
}

/* ============================================================
   PERFORMANCE PAGE v2 — "diagnostics terminal" structure.
   Five sections (Edge / Destroy / Consistency / Psychology /
   Capital). Each section gets a quiet header + a grid of cards.
   No more /100 scores up top — just the tight Edge Status strip.
   ============================================================ */

/* Top status strip — replaces the 5-card score row. */
.perf-status {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
  padding: 0 2px;
}
.perf-status-cell {
  position: relative;
  padding: 14px 16px;
  border-radius: 14px;
  background:
    radial-gradient(circle at 18% -8%, rgba(92, 200, 255, 0.06), transparent 42%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 96%, var(--surface-soft)), var(--surface));
  border: 1px solid var(--border-hair);
  display: flex;
  flex-direction: column;
  gap: 4px;
  box-shadow: 0 16px 30px -28px rgba(8, 12, 22, 0.35);
}
.perf-status-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-status-value {
  font-size: 24px;
  font-weight: 850;
  letter-spacing: -0.015em;
  line-height: 1;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.perf-status-value.pos { color: var(--pos); }
.perf-status-value.neg { color: var(--neg); }
.perf-status-cell small {
  font-size: 11px;
  color: var(--text-3);
  font-weight: 600;
}

/* Behavioral context bar — replaces the 4 KPI strip */
.perf-behavior-bar {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1px;
  background: var(--border-hair);
  border-radius: 16px;
  border: 1px solid var(--border-hair);
  overflow: hidden;
}
.perf-behavior-cell {
  padding: 13px 16px;
  background: var(--surface);
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.perf-behavior-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-behavior-value {
  font-size: 20px;
  font-weight: 850;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.015em;
}
.perf-behavior-sub {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}
/* Clickable performance rows/cards */
.perf-clickable {
  cursor: pointer;
  position: relative;
  transition: background 140ms var(--ease-out), border-color 140ms var(--ease-out);
}
.perf-clickable:hover {
  background: color-mix(in srgb, var(--pos) 4%, transparent) !important;
  border-color: color-mix(in srgb, var(--pos) 20%, transparent) !important;
}
.perf-clickable::after {
  content: '→';
  position: absolute;
  right: 10px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 11px;
  color: var(--text-4);
  opacity: 0;
  transition: opacity 140ms var(--ease-out);
  pointer-events: none;
}
.perf-clickable:hover::after { opacity: 1; }
/* Data source label */
.perf-data-src {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-4);
  display: block;
  margin-top: 2px;
}

/* Block = one analytical section. */
/* Performance hero layout: mistake breakdown (3fr) + capital sidebar (1fr).
   Both columns stretch to the same height (grid default). The right column's
   4 visual boxes — streak-split (W+L), leak chip, edge chip — split the height
   so the last chip's bottom matches "Where Your Money Disappears". */
.perf-hero-grid {
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 8px;
}
.perf-hero-side {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.perf-hero-side > .perf-streak-split { flex-grow: 2; flex-shrink: 0; }
.perf-hero-side > .perf-leak-card,
.perf-hero-side > .perf-edge-card {
  flex-grow: 1;
  flex-shrink: 0;
  justify-content: center;
}
.perf-hero-side > .perf-streak-split .perf-streak-half {
  flex: 1;
  justify-content: center;
}
.perf-hero-streak {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 14px 16px;
}
.perf-hero-streak .perf-card-eyebrow { margin-bottom: 2px; }
.perf-hero-streak strong {
  font-size: 26px;
  font-weight: 850;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-hero-streak small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}

/* Behavioral Edge Map — compact grid of key context expectancy */
.perf-edge-map-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(130px, 1fr));
  gap: 8px;
}
.perf-edge-map-cell {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 11px 13px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface-soft) 50%, transparent);
  border: 1px solid var(--border-hair);
}
.perf-edge-map-group {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-4);
}
.perf-edge-map-label {
  font-size: 12px;
  font-weight: 700;
  color: var(--text-2);
  line-height: 1.2;
}
.perf-edge-map-cell strong {
  font-size: 18px;
  font-weight: 840;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-edge-map-meta {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-4);
}
.perf-edge-map-cell.is-best { border-color: color-mix(in srgb, var(--pos) 22%, var(--border-hair)); background: color-mix(in srgb, var(--pos) 5%, transparent); }
.perf-edge-map-cell.is-worst { border-color: color-mix(in srgb, var(--neg) 22%, var(--border-hair)); background: color-mix(in srgb, var(--neg) 4%, transparent); }

.perf-block {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.perf-block-head {
  padding: 3px 4px 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.perf-block-head h2 {
  font-size: 18px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text);
}
.perf-block-head p {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-3);
}

.perf-block-card {
  padding: 14px 16px 13px;
  border-radius: 16px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  background: linear-gradient(180deg, color-mix(in srgb, var(--surface) 97%, var(--surface-soft)), var(--surface));
  box-shadow: 0 16px 30px -28px rgba(8, 12, 22, 0.24);
}

.perf-card-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 70%, transparent);
}
.perf-card-eyebrow {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.075em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-card-head h3 {
  font-size: 15px;
  font-weight: 820;
  letter-spacing: -0.005em;
  color: var(--text);
  margin-top: 3px;
}
.perf-card-head small {
  font-size: 11px;
  font-weight: 700;
  color: var(--text-3);
  text-align: right;
  white-space: nowrap;
  padding: 4px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-soft) 65%, transparent);
}
.perf-card-head small.pos { color: var(--pos); background: var(--pos-soft); }
.perf-card-head small.neg { color: var(--neg); background: var(--neg-soft); }

/* === Section 1: Actual Edge === */
.perf-matrix-card { padding-bottom: 4px; }
.perf-edge-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

/* Setup performance matrix — sortable feel via sticky header + row hover. */
.perf-matrix {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-variant-numeric: tabular-nums;
}
.perf-matrix th {
  position: sticky;
  top: 0;
  padding: 9px 10px;
  font-size: 9.5px;
  font-weight: 800;
  color: var(--text-3);
  letter-spacing: 0.075em;
  text-transform: uppercase;
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
  border-bottom: 1px solid var(--border-hair);
  text-align: left;
}
.perf-matrix th.num { text-align: right; }
.perf-matrix td {
  padding: 11px 10px;
  font-size: 12.5px;
  font-weight: 650;
  color: var(--text);
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 60%, transparent);
}
.perf-matrix td.num { text-align: right; }
.perf-matrix tbody tr:last-child td { border-bottom: 0; }
.perf-matrix tbody tr {
  transition: background 180ms var(--ease-out);
}
.perf-matrix tbody tr:hover td {
  background: color-mix(in srgb, var(--pos-soft) 30%, var(--surface));
}
.perf-matrix tbody tr.is-best td {
  background: color-mix(in srgb, var(--pos-soft) 22%, transparent);
}
.perf-matrix tbody tr.is-best td:first-child {
  box-shadow: inset 3px 0 0 var(--pos);
}
.perf-matrix tbody tr.is-loser td {
  opacity: 0.62;
}
.perf-matrix tbody tr.is-loser:hover td {
  opacity: 1;
}
.perf-matrix-name {
  font-weight: 750;
  letter-spacing: -0.005em;
}
.perf-matrix-tag {
  display: inline-block;
  margin-left: 8px;
  padding: 2px 7px;
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--pos);
  background: var(--pos-soft);
  border-radius: 999px;
}

.perf-source-note {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.055em;
  text-transform: uppercase;
  color: var(--text-3);
}

.perf-setup-list {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.perf-setup-row {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 13px 14px;
  border: 1px solid var(--border-hair);
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface-soft) 48%, transparent);
}

.perf-setup-row.is-top {
  border-color: color-mix(in srgb, var(--pos) 24%, var(--border-hair));
  background:
    linear-gradient(90deg, color-mix(in srgb, var(--pos-soft) 40%, transparent), transparent 48%),
    color-mix(in srgb, var(--surface-soft) 44%, transparent);
}

.perf-setup-row.is-loser {
  border-color: color-mix(in srgb, var(--neg) 18%, var(--border-hair));
}

.perf-setup-main {
  display: flex;
  gap: 12px;
  min-width: 0;
  align-items: flex-start;
}

.perf-setup-rank {
  width: 28px;
  height: 28px;
  display: inline-grid;
  place-items: center;
  flex: 0 0 28px;
  border-radius: 9px;
  color: var(--text-3);
  background: var(--surface);
  border: 1px solid var(--border-hair);
  font-size: 11px;
  font-weight: 850;
  font-variant-numeric: tabular-nums;
}

.perf-setup-copy {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 0;
}

.perf-setup-copy strong {
  color: var(--text);
  font-size: 14px;
  font-weight: 820;
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.perf-setup-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.perf-setup-meta span {
  padding: 3px 7px;
  border-radius: 999px;
  color: var(--text-3);
  background: color-mix(in srgb, var(--surface) 70%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 70%, transparent);
  font-size: 10.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.perf-setup-stats {
  display: grid;
  grid-template-columns: minmax(70px, 0.7fr) minmax(0, 1fr) minmax(82px, 0.75fr);
  gap: 10px;
  align-items: center;
}

.perf-setup-number {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.perf-setup-number small {
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.perf-setup-number strong {
  font-size: 15px;
  font-weight: 850;
}

.perf-setup-track {
  position: relative;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 72%, transparent);
}

.perf-setup-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
}

.perf-setup-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}

/* Setup payoff hero — mirrors the behavioral loss bars with a blue profit bias. */
.perf-edge-focus-grid {
  display: grid;
  grid-template-columns: 3fr 1fr;
  gap: 8px;
  align-items: start;
}
/* Section 2 container — fully neutral so all green weight collapses onto the
   single #1 setup card. No outer wash competing with the inner premium tint. */
.perf-pay-card {
  border-color: var(--border-hair);
}
.perf-pay-list {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.perf-pay-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr) auto;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
}
.perf-pay-row.is-best .perf-pay-label strong {
  color: var(--pos);
}
.perf-pay-row.is-best .perf-pay-fill {
  box-shadow: 0 0 14px color-mix(in srgb, var(--pos-light) 42%, transparent);
}
.perf-pay-row.is-loss .perf-pay-label strong {
  color: var(--neg);
}
.perf-pay-label {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.perf-pay-label strong {
  color: var(--text);
  font-size: 12.5px;
  font-weight: 760;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-pay-label small {
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 600;
}
.perf-pay-track {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  overflow: hidden;
}
.perf-pay-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-pay-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}
.perf-pay-value {
  text-align: right;
  display: flex;
  flex-direction: column;
  font-variant-numeric: tabular-nums;
}
.perf-pay-value strong {
  font-size: 13px;
  font-weight: 850;
}
.perf-pay-value small {
  color: var(--text-3);
  font-size: 10px;
  font-weight: 650;
}
.perf-sequence-card .perf-trade-no {
  grid-template-columns: 1fr;
  gap: 8px;
}
.perf-sequence-card .perf-trade-no-card {
  padding: 11px 13px;
}
.perf-sequence-card .perf-trade-no-value {
  font-size: 19px;
}

/* Ranked net bars — long/short, session, weekday, confidence, plan. */
.perf-ranked {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
/* Inside the Edge Details / Execution Quality grids, ranked lists stretch
   to match neighbour card heights. Long vs Short (2 rows) gets a
   comparison footer (renderSideSplitFooter) that fills the otherwise-empty
   space with useful directional-bias info; everything else uses
   space-around so rows distribute naturally. */
.perf-edge-grid .perf-ranked,
.perf-review-grid .perf-review-list,
.perf-review-grid .perf-rv-card {
  flex: 1;
  justify-content: space-around;
  padding-block: 4px;
}

/* Long vs Short comparison footer — fills the bottom space of the 2-row
   side card with a stacked split bar + bias label. Reads at-a-glance:
   "which side carries my edge, and by how much". */
.perf-ls-footer {
  margin-top: auto;
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--border-hair);
}
.perf-ls-split {
  display: flex;
  height: 6px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 60%, transparent);
}
.perf-ls-split-seg {
  display: block;
  height: 100%;
  min-width: 4px;
}
.perf-ls-split-seg.pos {
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
}
.perf-ls-split-seg.neg {
  background: linear-gradient(90deg, var(--neg-deep), var(--neg));
}
.perf-ls-split-seg + .perf-ls-split-seg {
  /* 1px white sliver between the two segments so the eye can distinguish
     them when both are the same tone (rare but possible). */
  margin-left: 1px;
}
.perf-ls-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}
.perf-ls-bias {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: -0.005em;
  color: var(--text);
}
.perf-ls-bias[data-tone="pos"]    { color: var(--pos); }
.perf-ls-bias[data-tone="neg"]    { color: var(--neg); }
.perf-ls-bias[data-tone="neutral"]{ color: var(--text-3); }
.perf-ls-dom {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
.perf-ranked-row {
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.4fr) auto;
  align-items: center;
  gap: 10px;
}
.perf-ranked-label {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.perf-ranked-label strong {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.005em;
}
.perf-ranked-label small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-ranked-bar {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  overflow: hidden;
}
.perf-ranked-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: 999px;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-ranked-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}
.perf-ranked-value {
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.perf-ranked-value.pos { color: var(--pos); }
.perf-ranked-value.neg { color: var(--neg); }

@keyframes perf-bar-fill {
  from { transform: scaleX(0); opacity: 0.4; }
  to   { transform: scaleX(1); opacity: 1; }
}
/* Every .perf-*-fill bar reveals via the perf-bar-fill keyframe above. They animate
   transform: scaleX() (GPU-composited, no per-frame layout) instead of width. Each
   bar's WIDTH still encodes its data proportion (var(--target) / var(--w) / inline);
   scaleX only animates the 0→full reveal from the left edge. scaleX(0) base keeps the
   bar collapsed before — and while — the animation is (re)armed by replayPerformanceIntro. */
.perf-pay-fill, .perf-ranked-fill, .perf-bar-fill, .perf-behavior-fill,
.perf-discipline-fill, .perf-rv-bar-fill, .perf-betrayal-fill, .perf-drift-bar-fill,
.perf-mistake-fill, .perf-setup-rank-fill, .perf-drift-card-fill {
  transform: scaleX(0);
  transform-origin: left center;
}

/* === Section 2: Destruction === */
.perf-destroy-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(280px, 1fr);
  gap: 10px;
}

.perf-bars-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.perf-bar-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.4fr) auto;
  align-items: center;
  gap: 10px;
  padding: 4px 0;
}
.perf-bar-row.is-biggest .perf-bar-label strong {
  color: var(--neg);
}
.perf-bar-row.is-biggest .perf-bar-fill {
  box-shadow: 0 0 12px color-mix(in srgb, var(--neg) 35%, transparent);
}
.perf-bar-label {
  display: flex;
  flex-direction: column;
  min-width: 0;
}
.perf-bar-label strong {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
}
.perf-bar-label small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-bar-track {
  position: relative;
  height: 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  overflow: hidden;
}
.perf-bar-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: 999px;
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-bar-value {
  text-align: right;
  display: flex;
  flex-direction: column;
  font-variant-numeric: tabular-nums;
}
.perf-bar-value strong { font-size: 13px; font-weight: 800; }
.perf-bar-value small  { font-size: 10px; font-weight: 600; color: var(--text-3); }

.perf-behavior-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.perf-behavior-row {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.perf-behavior-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  font-size: 12.5px;
  font-weight: 700;
}
.perf-behavior-head .neg { color: var(--neg); font-weight: 800; font-variant-numeric: tabular-nums; }
.perf-behavior-meta {
  display: flex;
  justify-content: space-between;
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-behavior-meta .neg { color: var(--neg); }
.perf-behavior-bar {
  margin-top: 2px;
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  overflow: hidden;
  display: block;
}
.perf-behavior-fill {
  display: block;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
  width: var(--target, 0%);
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}

/* === Section 3: Consistency === */
.perf-consistency-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 10px;
}
.perf-trade-no {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.perf-trade-no-card {
  padding: 14px 16px;
  border-radius: 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  background: color-mix(in srgb, var(--surface-soft) 50%, transparent);
  border: 1px solid var(--border-hair);
  transition: border-color 180ms var(--ease-out), background 180ms var(--ease-out);
}
.perf-trade-no-card.pos { border-color: color-mix(in srgb, var(--pos) 22%, transparent); }
.perf-trade-no-card.neg { border-color: color-mix(in srgb, var(--neg) 22%, transparent); }
.perf-trade-no-card.is-warn {
  background: linear-gradient(180deg, color-mix(in srgb, var(--neg-soft) 50%, transparent), transparent);
}
.perf-trade-no-label {
  font-size: 10.5px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-trade-no-value {
  font-size: 22px;
  font-weight: 850;
  letter-spacing: -0.015em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}
.perf-trade-no-value.pos { color: var(--pos); }
.perf-trade-no-value.neg { color: var(--neg); }
.perf-trade-no-sub {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}

.perf-warn {
  margin-top: 8px;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  border-radius: 12px;
  font-size: 11.5px;
  font-weight: 700;
  color: var(--neg);
  background: var(--neg-soft);
  border: 1px solid color-mix(in srgb, var(--neg) 16%, transparent);
}
.perf-warn svg { flex-shrink: 0; }

.perf-discipline {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.perf-discipline-row {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr) auto;
  align-items: center;
  gap: 10px;
}
.perf-discipline-row > span:first-child {
  display: flex;
  flex-direction: column;
}
.perf-discipline-row strong {
  font-size: 12.5px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}
.perf-discipline-row > span:first-child strong { font-weight: 700; }
.perf-discipline-row > span:first-child small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-discipline-bar {
  position: relative;
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 70%, transparent);
  overflow: hidden;
}
.perf-discipline-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: 999px;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-discipline-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}
.perf-discipline-row > strong:last-child {
  font-size: 13px;
  font-weight: 800;
  text-align: right;
}

/* === Section 4: Psychology === */
.perf-psych-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.perf-review-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 1fr);
  /* Row gap is intentionally slightly larger than column gap so the eye
     reads two semantic rows (plan/entry above, confidence/emotion below)
     instead of one undifferentiated 2x2 mass. The cards are paired by height
     — the two shorter cards share the top row, the two taller share the
     bottom — so the gap reads as one clean band. Tightened 16px → 12px once
     the plan dead-space was distributed, for a denser vertical rhythm. */
  column-gap: 10px;
  row-gap: 12px;
}

.perf-review-list {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.perf-review-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr) auto;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface-soft) 42%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 70%, transparent);
}

.perf-review-label {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.perf-review-label strong {
  color: var(--text);
  font-size: 12.5px;
  font-weight: 780;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.perf-review-label small {
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 650;
}

.perf-review-track {
  height: 7px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 72%, transparent);
}

.perf-review-fill {
  display: block;
  height: 100%;
  width: var(--target, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
}

.perf-review-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}

.perf-review-value {
  display: flex;
  flex-direction: column;
  gap: 2px;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.perf-review-value strong {
  font-size: 13px;
  font-weight: 850;
}

.perf-review-value small {
  color: var(--text-3);
  font-size: 10px;
  font-weight: 650;
}

/* ============================================================
   PERFORMANCE v4 — Execution Quality semantic rows
   Tone-driven rows that break the spreadsheet rhythm. Left accent
   carries the semantic; net value dominates; bar is hairline-subtle.
   ============================================================ */
.perf-rv-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1;
  /* Distribute rows across the available height instead of letting them
     pile at the top with empty bottom space. With only 3 plan-adherence
     rows the card looked hollow; space-around now fills that gap evenly. */
  justify-content: space-around;
}
/* When the card has a summary footer (.perf-rv-summary), distribute the rows
   AND the footer through the stretched height so the band that used to sit
   hollow below 3 rows becomes even breathing room between every element
   instead of one dead gap above the footer. Rows keep their natural size
   (no shrink) so the gaps absorb the slack. */
.perf-rv-card.has-summary {
  justify-content: space-between;
}
.perf-rv-card.has-summary .perf-rv-row {
  flex-shrink: 0;
}

/* Plan adherence summary footer — mirrors the Long-vs-Short comparison strip
   but for the Followed/Partial/Broke card. Fills the otherwise-empty space
   below 3 rows with a useful read: total plan-adherence rate + a 3-segment
   split bar showing the share of each plan outcome. */
.perf-rv-summary {
  padding-top: 14px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  border-top: 1px solid var(--border-hair);
}
.perf-rv-summary-split {
  display: flex;
  height: 6px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 60%, transparent);
}
.perf-rv-summary-seg {
  display: block;
  height: 100%;
  min-width: 4px;
}
.perf-rv-summary-seg + .perf-rv-summary-seg {
  margin-left: 1px;
}
.perf-rv-summary-seg.pos {
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
}
.perf-rv-summary-seg.warn {
  background: linear-gradient(90deg, #f59e0b, #d97706);
}
.perf-rv-summary-seg.neg {
  background: linear-gradient(90deg, var(--neg-deep), var(--neg));
}
.perf-rv-summary-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}
.perf-rv-summary-label {
  font-size: 11px;
  font-weight: 800;
  letter-spacing: -0.005em;
  color: var(--text);
}
.perf-rv-summary-label[data-tone="pos"] { color: var(--pos); }
.perf-rv-summary-label[data-tone="neg"] { color: var(--neg); }
.perf-rv-summary-detail {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  white-space: nowrap;
}
/* Denser summary read: a large tabular adherence headline + small caption,
   then a compact 3-up legend (Followed / Partial / Broke) so the bottom slot
   carries real information instead of a thin label strip. */
.perf-rv-summary-headline {
  display: flex;
  align-items: baseline;
  gap: 8px;
}
.perf-rv-summary-pct {
  font-size: 22px;
  font-weight: 850;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--text);
}
.perf-rv-summary-pct[data-tone="pos"] { color: var(--pos); }
.perf-rv-summary-pct[data-tone="neg"] { color: var(--neg); }
.perf-rv-summary-legend {
  display: flex;
  flex-direction: column;
  gap: 4px;
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
}
.perf-rv-summary-legend span {
  display: flex;
  align-items: center;
  white-space: nowrap;
}
.perf-rv-summary-legend i {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 2px;
  margin-right: 6px;
  flex: 0 0 auto;
}
.perf-rv-summary-legend i.pos  { background: var(--pos); }
.perf-rv-summary-legend i.warn { background: #f59e0b; }
.perf-rv-summary-legend i.neg  { background: var(--neg); }
.perf-rv-row {
  position: relative;
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr);
  align-items: stretch;
  gap: 12px;
  padding: 11px 14px 11px 11px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--surface-soft) 28%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 60%, transparent);
  transition: border-color 140ms var(--ease-out), background 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.perf-rv-accent {
  display: block;
  border-radius: 99px;
  background: var(--rv-accent, color-mix(in srgb, var(--text-3) 60%, transparent));
  transition: background 160ms var(--ease-out);
}
.perf-rv-content {
  display: flex;
  flex-direction: column;
  gap: 6px;
  min-width: 0;
}
.perf-rv-line1 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.perf-rv-name {
  font-size: 13px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-rv-value {
  font-size: 15px;
  font-weight: 870;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  color: var(--rv-value, var(--text));
  white-space: nowrap;
}
.perf-rv-bar {
  height: 3px;
  border-radius: 99px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 55%, transparent);
}
.perf-rv-bar-fill {
  display: block;
  height: 100%;
  width: var(--target, 0%);
  border-radius: inherit;
  background: var(--rv-bar, color-mix(in srgb, var(--text-3) 40%, transparent));
  opacity: var(--rv-intensity, 1);
  animation: perf-bar-fill 700ms var(--ease-emphasized) forwards;
}
.perf-rv-line2 {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  font-size: 10.5px;
  font-weight: 650;
  color: var(--text-3);
  letter-spacing: 0.005em;
}
.perf-rv-stats { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.perf-rv-exp { font-variant-numeric: tabular-nums; }
.perf-rv-row:hover { transform: translateY(-1px); }
.perf-rv-row.perf-clickable:hover { background: inherit !important; border-color: inherit !important; }
/* Rank emphasis — used when opts.rankEmphasis = true. Leader = first row,
   positive expectancy. Laggard = last row, negative expectancy. */
.perf-rv-row.is-leader {
  border-color: color-mix(in srgb, var(--pos) 36%, var(--border-hair));
  box-shadow: 0 12px 28px -22px color-mix(in srgb, var(--pos) 32%, transparent);
}
.perf-rv-row.is-leader .perf-rv-value { font-size: 17px; }
.perf-rv-row.is-laggard {
  border-color: color-mix(in srgb, var(--neg) 48%, var(--border-hair));
  box-shadow: 0 12px 28px -22px color-mix(in srgb, var(--neg) 38%, transparent);
}
.perf-rv-row.is-laggard .perf-rv-value { font-size: 17px; }

/* ===== Tone variants ===== */

/* CALM — controlled positive edge (mint) */
.perf-rv-row[data-tone="calm"] {
  --rv-accent: var(--pos);
  --rv-value:  var(--pos);
  --rv-bar:    linear-gradient(90deg, var(--pos-light), var(--pos));
  border-color: color-mix(in srgb, var(--pos) 20%, var(--border-hair));
  background: color-mix(in srgb, var(--pos-soft) 11%, transparent);
}

/* NEUTRAL — quiet middle ground */
.perf-rv-row[data-tone="neutral"] {
  --rv-accent: color-mix(in srgb, var(--text-3) 50%, transparent);
  --rv-bar:    color-mix(in srgb, var(--text-3) 38%, transparent);
}

/* SPECULATIVE — anticipatory / amber */
.perf-rv-row[data-tone="speculative"] {
  --rv-accent: #f59e0b;
  --rv-value:  color-mix(in srgb, #b3760f 78%, var(--text));
  --rv-bar:    linear-gradient(90deg, color-mix(in srgb, #f59e0b 50%, transparent), #f59e0b);
  border-color: color-mix(in srgb, #f59e0b 22%, var(--border-hair));
  background: color-mix(in srgb, #f59e0b 5%, transparent);
}
:root[data-theme="dark"] .perf-rv-row[data-tone="speculative"] {
  --rv-value: color-mix(in srgb, #fbbf24 88%, var(--text));
}

/* WEAK — slipping, muted red */
.perf-rv-row[data-tone="weak"] {
  --rv-accent: color-mix(in srgb, var(--neg) 48%, var(--text-3));
  --rv-value:  color-mix(in srgb, var(--neg) 72%, var(--text-3));
  --rv-bar:    linear-gradient(90deg, color-mix(in srgb, var(--neg) 40%, transparent), color-mix(in srgb, var(--neg) 60%, transparent));
  border-color: color-mix(in srgb, var(--neg) 14%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 8%, transparent);
}
.perf-rv-row[data-tone="weak"] .perf-rv-name { color: var(--text-2); }

/* DANGER — emotionally destructive, deep red */
.perf-rv-row[data-tone="danger"] {
  --rv-accent: var(--neg);
  --rv-value:  var(--neg);
  --rv-bar:    linear-gradient(90deg, var(--neg-deep), var(--neg));
  border-color: color-mix(in srgb, var(--neg) 34%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 18%, transparent);
}
.perf-rv-row[data-tone="danger"] .perf-rv-name {
  color: var(--neg);
  font-weight: 850;
}

.perf-next-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.95fr) minmax(0, 1fr) minmax(0, 1fr);
  gap: 10px;
}

.perf-next-card {
  position: relative;
  padding: 14px 16px 14px 18px;
  border-radius: 14px;
  border: 1px solid var(--border-hair);
  background: color-mix(in srgb, var(--surface-soft) 46%, transparent);
  display: flex;
  flex-direction: column;
  gap: 7px;
}
/* Left accent strip carries the severity tone. */
.perf-next-card::before {
  content: '';
  position: absolute;
  top: 14px;
  bottom: 14px;
  left: 8px;
  width: 3px;
  border-radius: 99px;
  background: var(--next-accent, color-mix(in srgb, var(--text-3) 40%, transparent));
}

.perf-next-card span {
  color: var(--next-eyebrow, var(--text-3));
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.perf-next-card strong {
  color: var(--text);
  font-size: 15px;
  font-weight: 820;
  letter-spacing: -0.005em;
}

.perf-next-card small {
  color: var(--text-3);
  font-size: 11px;
  font-weight: 650;
}

.perf-next-card[data-tone="danger"] {
  --next-accent:  var(--neg);
  --next-eyebrow: var(--neg);
  border-color: color-mix(in srgb, var(--neg) 28%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 14%, transparent);
}
.perf-next-card[data-tone="speculative"] {
  --next-accent:  #f59e0b;
  --next-eyebrow: color-mix(in srgb, #b3760f 80%, var(--text));
  border-color: color-mix(in srgb, #f59e0b 22%, var(--border-hair));
  background: color-mix(in srgb, #f59e0b 5%, transparent);
}
:root[data-theme="dark"] .perf-next-card[data-tone="speculative"] {
  --next-eyebrow: color-mix(in srgb, #fbbf24 88%, var(--text));
}
.perf-next-card[data-tone="neutral"] {
  --next-accent:  color-mix(in srgb, var(--text-3) 55%, transparent);
}

/* ============================================================
   Key Behavioral Findings — three compact, tone-coded insight
   cards: subject title, one-line read, single impact metric.
   Quiet institutional surfaces — left accent + faint tint, no
   glow stacks, no icons, no chat-style decoration.
   ============================================================ */
.perf-finding-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.perf-finding-card {
  position: relative;
  display: grid;
  grid-template-columns: 3px minmax(0, 1fr);
  gap: 13px;
  padding: 15px 16px 15px 13px;
  border-radius: 14px;
  border: 1px solid var(--border-hair);
  background: color-mix(in srgb, var(--surface-soft) 34%, transparent);
}
.perf-finding-accent {
  border-radius: 99px;
  background: var(--find-accent, color-mix(in srgb, var(--text-3) 45%, transparent));
}
.perf-finding-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.perf-finding-title {
  font-size: 14.5px;
  font-weight: 840;
  letter-spacing: -0.01em;
  color: var(--text);
  line-height: 1.2;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-finding-caption {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  line-height: 1.4;
}
/* Impact metric — the data anchor. Pinned to the card base so all three
   findings align their numbers regardless of caption length. Thin top hairline
   gives the metric an institutional "results line" rhythm without adding noise. */
.perf-finding-metric {
  margin-top: auto;
  padding-top: 10px;
  border-top: 1px solid color-mix(in srgb, var(--border-hair) 55%, transparent);
  font-size: 19px;
  font-weight: 860;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  color: var(--text);
}
.perf-finding-metric.pos { color: var(--pos); }
.perf-finding-metric.neg { color: var(--neg); }

/* Tone surfaces — a single faint tint; the accent stripe carries the semantic. */
.perf-finding-card[data-tone="calm"] {
  --find-accent: var(--pos);
  border-color: color-mix(in srgb, var(--pos) 20%, var(--border-hair));
  background: color-mix(in srgb, var(--pos-soft) 10%, transparent);
}
.perf-finding-card[data-tone="speculative"] {
  --find-accent: #f59e0b;
  border-color: color-mix(in srgb, #f59e0b 22%, var(--border-hair));
  background: color-mix(in srgb, #f59e0b 5%, transparent);
}
.perf-finding-card[data-tone="danger"] {
  --find-accent: var(--neg);
  border-color: color-mix(in srgb, var(--neg) 24%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 12%, transparent);
}
/* Amber tone owns its negative metric — variance, not destruction. */
.perf-finding-card[data-tone="speculative"] .perf-finding-metric.neg {
  color: color-mix(in srgb, #b3760f 80%, var(--text));
}
:root[data-theme="dark"] .perf-finding-card[data-tone="speculative"] .perf-finding-metric.neg {
  color: color-mix(in srgb, #fbbf24 88%, var(--text));
}

@media (max-width: 760px) {
  #performance-diagnostics .perf-finding-grid { grid-template-columns: 1fr; }
}

/* Primary fix card — dominant action. Wider via grid, larger typography,
   tighter accent strip; dominance comes from typography + padding, not from a
   colored ambient halo. The shadow stays subtle so the card feels weighted, not
   illuminated. */
.perf-next-card.is-primary {
  padding: 18px 20px 18px 24px;
  gap: 10px;
  box-shadow: 0 12px 24px -22px color-mix(in srgb, var(--next-accent, var(--text-3)) 28%, transparent);
}
.perf-next-card.is-primary::before {
  top: 18px;
  bottom: 18px;
  left: 10px;
  width: 4px;
}
.perf-next-card.is-primary span {
  font-size: 10.5px;
  letter-spacing: 0.08em;
}
.perf-next-card.is-primary strong {
  font-size: 19px;
  font-weight: 850;
  letter-spacing: -0.012em;
  line-height: 1.18;
}
.perf-next-card.is-primary small {
  font-size: 12px;
  color: var(--text-2);
}

/* Secondary cards stay quiet so the primary can lead — slightly muted surface,
   tighter eyebrow letter-spacing, smaller title. They feel supportive, not
   competitive. */
.perf-next-card:not(.is-primary) {
  background: color-mix(in srgb, var(--surface-soft) 32%, transparent);
}
.perf-next-card:not(.is-primary) strong {
  font-size: 14px;
}
.perf-next-card:not(.is-primary) span {
  opacity: 0.78;
}

/* Risk-control warnings stay amber but feel more urgent than the average
   secondary card. Stronger border + a faint amber depth shadow so a risk
   breach reads as important, not neutrally-amber. Triggered by .is-warning. */
.perf-next-card.is-warning {
  --next-accent:  #f59e0b;
  --next-eyebrow: color-mix(in srgb, #b3760f 82%, var(--text));
  border-color: color-mix(in srgb, #f59e0b 48%, var(--border-hair));
  background: color-mix(in srgb, #f59e0b 11%, transparent);
  box-shadow: 0 10px 22px -22px color-mix(in srgb, #f59e0b 32%, transparent);
}
.perf-next-card.is-warning::before {
  background: #f59e0b;
}
.perf-next-card.is-warning span { opacity: 1; }
:root[data-theme="dark"] .perf-next-card.is-warning {
  --next-eyebrow: color-mix(in srgb, #fbbf24 88%, var(--text));
}

/* === Section 5: Capital Preservation === */
.perf-capital-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}
.perf-capital-stat {
  align-items: flex-start;
  padding: 14px 16px;
  gap: 6px;
}
.perf-capital-stat strong {
  font-size: 22px;
  font-weight: 850;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-capital-stat strong.pos { color: var(--pos); }
.perf-capital-stat strong.neg { color: var(--neg); }
.perf-capital-stat small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}

/* Diagnostics page wrapper — single root that holds all blocks. */
#performance-diagnostics {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 15px;
  padding: 3px 2px 20px;
}

@media (max-width: 1180px) {
  #performance-diagnostics .perf-status,
  #performance-diagnostics .perf-capital-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  #performance-diagnostics .perf-hero-grid,
  #performance-diagnostics .perf-edge-focus-grid {
    grid-template-columns: 1fr;
  }
  #performance-diagnostics .perf-edge-grid,
  #performance-diagnostics .perf-next-grid {
    grid-template-columns: 1fr;
  }
  #performance-diagnostics .perf-destroy-grid,
  #performance-diagnostics .perf-consistency-grid,
  #performance-diagnostics .perf-review-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 760px) {
  #performance-diagnostics .perf-status,
  #performance-diagnostics .perf-capital-grid,
  #performance-diagnostics .perf-trade-no,
  #performance-diagnostics .perf-drift-grid {
    grid-template-columns: 1fr;
  }
  #performance-diagnostics .perf-setup-row,
  #performance-diagnostics .perf-setup-stats,
  #performance-diagnostics .perf-ranked-row,
  #performance-diagnostics .perf-bar-row,
  #performance-diagnostics .perf-pay-row,
  #performance-diagnostics .perf-review-row,
  #performance-diagnostics .perf-discipline-row {
    grid-template-columns: 1fr;
  }
  #performance-diagnostics .perf-setup-number,
  #performance-diagnostics .perf-pay-value,
  #performance-diagnostics .perf-review-value {
    text-align: left;
  }
}

/* =====================================================
   New diagnostic sections — behavior / decay / tilt
   ===================================================== */

/* Side-by-side comparison: after-loss vs after-win */
.perf-vs-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.perf-vs-card {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 16px 18px 14px;
}
.perf-vs-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}
.perf-vs-label.neg { color: var(--neg); }
.perf-vs-label.pos { color: var(--pos); }
.perf-vs-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.perf-vs-stat strong {
  font-size: 22px;
  font-weight: 850;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-vs-stat small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-vs-rows {
  display: flex;
  flex-direction: column;
  gap: 6px;
  margin-top: 2px;
}
.perf-vs-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
  padding: 7px 10px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--surface-soft) 38%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 60%, transparent);
}
.perf-vs-row span {
  font-size: 12px;
  font-weight: 600;
  color: var(--text-2);
}
.perf-vs-row strong {
  font-size: 13px;
  font-weight: 820;
  font-variant-numeric: tabular-nums;
}

/* Edge trend: first half vs second half */
.perf-trend-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.perf-trend-card {
  padding: 16px 18px 14px;
}
.perf-trend-header {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-bottom: 10px;
}
.perf-trend-header span {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-trend-header strong {
  font-size: 22px;
  font-weight: 850;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-trend-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.perf-trend-stat {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.perf-trend-stat span {
  font-size: 10px;
  font-weight: 700;
  color: var(--text-3);
  letter-spacing: 0.02em;
}
.perf-trend-stat strong {
  font-size: 14px;
  font-weight: 820;
  font-variant-numeric: tabular-nums;
}

/* Tilt / rapid-sequence diagnostic */
.perf-tilt-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}
.perf-tilt-stat {
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.perf-tilt-stat strong {
  font-size: 26px;
  font-weight: 850;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-tilt-stat strong .perf-tilt-unit {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0;
  color: var(--text-3);
  margin-left: 4px;
  text-transform: none;
}
.perf-tilt-stat span {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-tilt-stat small {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
}

/* Setup betrayal: plan adherence per setup */
.perf-betrayal-list {
  display: flex;
  flex-direction: column;
  gap: 7px;
}
.perf-betrayal-row {
  display: grid;
  grid-template-columns: minmax(0,1fr) 80px auto;
  align-items: center;
  gap: 10px;
  padding: 9px 10px;
  border-radius: 10px;
  background: color-mix(in srgb, var(--surface-soft) 38%, transparent);
  border: 1px solid color-mix(in srgb, var(--border-hair) 60%, transparent);
}
.perf-betrayal-row.is-flagged {
  border-color: color-mix(in srgb, var(--neg) 28%, transparent);
  background: color-mix(in srgb, var(--neg) 5%, transparent);
}
.perf-betrayal-name {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.perf-betrayal-name strong {
  font-size: 12.5px;
  font-weight: 760;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-betrayal-name small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-betrayal-bar {
  height: 6px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 72%, transparent);
}
.perf-betrayal-fill {
  display: block;
  height: 100%;
  width: var(--target, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-betrayal-fill.ok {
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
}
.perf-betrayal-value {
  font-size: 13px;
  font-weight: 820;
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Highlighted insight callout */
.perf-callout {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px 14px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--neg) 7%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 24%, transparent);
}
.perf-callout.is-ok {
  background: color-mix(in srgb, var(--pos) 6%, transparent);
  border-color: color-mix(in srgb, var(--pos) 20%, transparent);
}
.perf-callout.is-warn {
  background: color-mix(in srgb, var(--pos-light) 5%, transparent);
  border-color: color-mix(in srgb, var(--pos-light) 22%, transparent);
}
.perf-callout svg {
  flex-shrink: 0;
  margin-top: 1px;
  color: var(--neg);
}
.perf-callout.is-ok svg { color: var(--pos); }
.perf-callout.is-warn svg { color: var(--text-3); }
.perf-callout-body {
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.perf-callout-body strong {
  font-size: 13px;
  font-weight: 780;
  color: var(--text);
}
.perf-callout-body small {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--text-3);
}

/* Discipline Drift — 6-bucket behavioral context grid */
.perf-drift-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 8px;
}
.perf-drift-cell {
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 13px 14px 11px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface) 96%, var(--surface-soft));
  border: 1px solid var(--border-hair);
  cursor: pointer;
  position: relative;
  transition: border-color 130ms, background 130ms;
}
.perf-drift-cell:hover { border-color: var(--border); }
.perf-drift-cell.is-warn {
  border-color: color-mix(in srgb, var(--neg) 22%, var(--border-hair));
  background: color-mix(in srgb, var(--neg) 3%, transparent);
}
.perf-drift-label {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-4);
}
.perf-drift-expect {
  font-size: 22px;
  font-weight: 860;
  letter-spacing: -0.025em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
  margin-top: 1px;
}
.perf-drift-sub {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-3);
  line-height: 1.4;
}
.perf-drift-bar {
  height: 3px;
  border-radius: 99px;
  overflow: hidden;
  background: var(--border-hair);
  margin-top: 4px;
}
.perf-drift-bar-fill {
  display: block;
  height: 100%;
  width: var(--w, 0%);
  border-radius: inherit;
  background: var(--pos);
  animation: perf-bar-fill 700ms var(--ease-emphasized) forwards;
}
.perf-drift-bar-fill.neg { background: var(--neg); }
.perf-drift-cell::after {
  content: '→';
  position: absolute;
  right: 11px;
  top: 11px;
  font-size: 10px;
  color: var(--text-4);
  opacity: 0;
  transition: opacity 130ms;
}
.perf-drift-cell:hover::after { opacity: 1; }

/* Split best/worst streak card in hero sidebar */
.perf-streak-split {
  padding: 0;
  overflow: hidden;
  gap: 0;
}
.perf-streak-half {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 15px;
}
.perf-streak-half + .perf-streak-half {
  border-top: 1px solid var(--border-hair);
}
.perf-streak-half .perf-card-eyebrow { margin-bottom: 1px; }
.perf-streak-half strong {
  font-size: 22px;
  font-weight: 860;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1;
}
.perf-streak-half small {
  font-size: 10px;
  font-weight: 600;
  color: var(--text-3);
}

/* ============================================================
   PERFORMANCE v3 — diagnostic intensity pass
   Cards inherit semantic weight: destructive (red), edge (mint/blue),
   neutral (quiet). Worst leaks dominate the page.
   ============================================================ */

/* Money Lost By Behavior — hero mistake card.
   Quiet institutional surface: single flat tint, single ambient depth shadow.
   Red weight is carried by border + the inner #1 row, not stacked glow layers. */
.perf-mistake-card {
  border-color: color-mix(in srgb, var(--neg) 26%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 11%, var(--surface));
  box-shadow: 0 14px 28px -28px rgba(8, 12, 22, 0.22);
}
.perf-mistake-stack {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.perf-mistake-row {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1.55fr) auto;
  align-items: center;
  gap: 14px;
  padding: 11px 14px;
  border-radius: 13px;
  background: color-mix(in srgb, var(--neg-soft) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 12%, transparent);
  transition: border-color 140ms var(--ease-out), background 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.perf-mistake-row:hover {
  background: color-mix(in srgb, var(--neg-soft) 28%, transparent) !important;
  border-color: color-mix(in srgb, var(--neg) 30%, transparent) !important;
}
.perf-mistake-row.is-worst {
  padding: 16px 18px;
  background: color-mix(in srgb, var(--neg-soft) 28%, transparent);
  border-color: color-mix(in srgb, var(--neg) 38%, transparent);
}
.perf-mistake-head {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
.perf-mistake-rank {
  flex-shrink: 0;
  display: inline-grid;
  place-items: center;
  min-width: 30px;
  height: 26px;
  padding: 0 8px;
  font-size: 10.5px;
  font-weight: 850;
  letter-spacing: 0.04em;
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 12%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 26%, transparent);
  border-radius: 999px;
  font-variant-numeric: tabular-nums;
}
.perf-mistake-row.is-worst .perf-mistake-rank {
  background: var(--neg);
  color: #fff;
  border-color: var(--neg);
  box-shadow: 0 4px 12px -4px color-mix(in srgb, var(--neg) 55%, transparent);
}
.perf-mistake-name {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.perf-mistake-name strong {
  font-size: 13px;
  font-weight: 800;
  color: var(--text);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-mistake-row.is-worst .perf-mistake-name strong {
  font-size: 16px;
  font-weight: 850;
  color: var(--neg);
  letter-spacing: -0.01em;
}
.perf-mistake-name small {
  font-size: 10.5px;
  font-weight: 600;
  color: var(--text-3);
}
.perf-mistake-track {
  position: relative;
  height: 8px;
  border-radius: 999px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 60%, transparent);
}
.perf-mistake-row.is-worst .perf-mistake-track {
  height: 12px;
}
.perf-mistake-fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: var(--target, 0%);
  border-radius: inherit;
  background: linear-gradient(90deg, var(--neg-deep), var(--neg));
  animation: perf-bar-fill 800ms var(--ease-emphasized) forwards;
}
.perf-mistake-row.is-worst .perf-mistake-fill {
  background: linear-gradient(90deg, var(--neg-deep), var(--neg));
}
.perf-mistake-cost {
  text-align: right;
  display: flex;
  flex-direction: column;
  font-variant-numeric: tabular-nums;
}
.perf-mistake-cost strong {
  font-size: 14px;
  font-weight: 850;
  color: var(--neg);
  letter-spacing: -0.01em;
}
.perf-mistake-row.is-worst .perf-mistake-cost strong {
  font-size: 22px;
  font-weight: 880;
  letter-spacing: -0.02em;
}
.perf-mistake-cost small {
  font-size: 10.5px;
  font-weight: 700;
  color: color-mix(in srgb, var(--neg) 65%, var(--text-3));
  margin-top: 2px;
  letter-spacing: 0.02em;
}

/* Behavioral-cost footer — pinned to the card's bottom (margin-top:auto) so it
   fills the gap left when the mistake stack is shorter than the right column,
   and reads the clean-vs-flagged $/trade comparison + share of losses. */
.perf-mistake-footer {
  margin-top: auto;
  padding-top: 13px;
  border-top: 1px solid color-mix(in srgb, var(--neg) 16%, var(--border-hair));
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.pmf-compare {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
}
.pmf-cell {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.pmf-compare .pmf-cell:last-of-type {
  text-align: right;
  align-items: flex-end;
}
.pmf-k {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-3);
}
.pmf-v {
  font-size: 18px;
  font-weight: 850;
  line-height: 1.05;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.01em;
}
.pmf-v.pos { color: var(--pos); }
.pmf-v.neg { color: var(--neg); }
.pmf-sub {
  font-size: 10px;
  font-weight: 600;
  color: var(--text-4);
  font-variant-numeric: tabular-nums;
}
.pmf-vs {
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-4);
}
.pmf-note {
  margin: 0;
  font-size: 11px;
  line-height: 1.35;
  color: var(--text-3);
}

/* Override generic perf-clickable hover so the mistake hero keeps its red tone */
.perf-mistake-card .perf-clickable:hover {
  background: inherit !important;
  border-color: inherit !important;
}

/* Right-side support — streak split + leak chip */
.perf-streak-split .perf-streak-half.is-win {
  background: color-mix(in srgb, var(--pos-soft) 22%, transparent);
}
.perf-streak-split .perf-streak-half.is-loss {
  background: color-mix(in srgb, var(--neg-soft) 26%, transparent);
}
.perf-streak-split .perf-streak-half.is-review {
  background: transparent;
}
.perf-streak-half.is-review strong {
  color: var(--text);
}
.perf-streak-split .perf-streak-half.is-edge-trend { background: transparent; }
.perf-streak-split .perf-streak-half.is-edge-trend.is-improving {
  background: color-mix(in srgb, var(--pos-soft) 22%, transparent);
}
.perf-streak-split .perf-streak-half.is-edge-trend.is-declining {
  background: color-mix(in srgb, var(--neg-soft) 26%, transparent);
}
.perf-streak-half.is-edge-trend strong { color: var(--text-3); }
.perf-streak-half.is-edge-trend.is-improving strong { color: var(--pos); }
.perf-streak-half.is-edge-trend.is-declining strong { color: var(--neg); }
.perf-leak-card {
  padding: 11px 14px 12px !important;
  gap: 4px !important;
  background: color-mix(in srgb, var(--neg-soft) 13%, var(--surface)) !important;
  border-color: color-mix(in srgb, var(--neg) 24%, var(--border-hair)) !important;
}
.perf-leak-card .perf-leak-name {
  font-size: 17px;
  font-weight: 850;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--neg);
}
.perf-leak-card small {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 650;
}

/* Mint counter-weight to the red leak chip — shows the #1 setup. */
.perf-edge-card {
  padding: 11px 14px 12px !important;
  gap: 4px !important;
  background: color-mix(in srgb, var(--pos-soft) 13%, var(--surface)) !important;
  border-color: color-mix(in srgb, var(--pos) 26%, var(--border-hair)) !important;
}
.perf-edge-card .perf-edge-name {
  font-size: 17px;
  font-weight: 850;
  letter-spacing: -0.015em;
  line-height: 1.15;
  color: var(--pos);
}
.perf-edge-card small {
  font-size: 10.5px;
  color: var(--text-3);
  font-weight: 650;
}

/* Untagged-trades notice — top-right of the Performance page. Redesigned
   as an angular institutional card (10px radius, not a fully rounded pill)
   so it sits visually compatible with the rest of the page rather than
   looking like a chat-toast. Session-dismissible. */
.perf-untagged-pill {
  position: absolute;
  top: 4px;
  right: 4px;
  z-index: 6;
  display: inline-flex;
  align-items: stretch;
  gap: 0;
  padding: 0;
  border-radius: 10px;
  background:
    linear-gradient(180deg, color-mix(in srgb, #f59e0b 9%, var(--surface)), color-mix(in srgb, #f59e0b 5%, var(--surface)));
  border: 1px solid color-mix(in srgb, #f59e0b 30%, var(--border-hair));
  box-shadow: 0 4px 14px -8px color-mix(in srgb, #f59e0b 36%, transparent);
  pointer-events: auto;
  overflow: hidden;
  font-variant-numeric: tabular-nums;
}
.perf-untagged-pill-dot {
  width: 6px;
  background:
    linear-gradient(180deg, #f59e0b, color-mix(in srgb, #f59e0b 75%, #c97e08));
  flex-shrink: 0;
}
.perf-untagged-pill-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.2;
  padding: 8px 12px 7px 12px;
}
.perf-untagged-pill-body strong {
  font-size: 12px;
  font-weight: 820;
  color: color-mix(in srgb, #b3760f 78%, var(--text));
  letter-spacing: -0.005em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.perf-untagged-pill-body small {
  font-size: 9.5px;
  font-weight: 700;
  color: color-mix(in srgb, #b3760f 55%, var(--text-3));
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.perf-untagged-pill-close {
  width: 26px;
  display: grid;
  place-items: center;
  border: 0;
  border-left: 1px solid color-mix(in srgb, #f59e0b 22%, var(--border-hair));
  background: transparent;
  color: color-mix(in srgb, #b3760f 60%, var(--text-3));
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  cursor: pointer;
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.perf-untagged-pill-close:hover {
  background: color-mix(in srgb, #f59e0b 14%, transparent);
  color: color-mix(in srgb, #b3760f 90%, var(--text));
}
:root[data-theme="dark"] .perf-untagged-pill-body strong {
  color: color-mix(in srgb, #fbbf24 90%, var(--text));
}
:root[data-theme="dark"] .perf-untagged-pill-body small {
  color: color-mix(in srgb, #fbbf24 60%, var(--text-3));
}
:root[data-theme="dark"] .perf-untagged-pill-close {
  color: color-mix(in srgb, #fbbf24 60%, var(--text-3));
}
:root[data-theme="dark"] .perf-untagged-pill-close:hover {
  color: color-mix(in srgb, #fbbf24 92%, var(--text));
}

/* === Section 2: Setup ranking cards === */
.perf-setup-ranking {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 10px;
}
.perf-setup-rank-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 14px 14px 12px;
  border-radius: 14px;
  border: 1px solid var(--border-hair);
  background: color-mix(in srgb, var(--surface-soft) 38%, transparent);
  transition: transform 160ms var(--ease-out), border-color 160ms var(--ease-out);
}
.perf-setup-rank-card:hover { transform: translateY(-2px); }
/* Setups #2–#4: fully neutral. Border-hair only, no tint — the number column
   is the data anchor; visual decoration on supporting cards would steal weight
   from #1. The "EDGE" badge already marks #1 as semantically distinct. */
.perf-setup-rank-card.is-pos {
  border-color: var(--border-hair);
  background: color-mix(in srgb, var(--surface-soft) 32%, transparent);
}
/* Setup #1: the single premium card — strongest border, tinted fill and a
   restrained ambient lift. No radial glow stack: the typography step + badge +
   shadow alone open the hierarchy gap to the secondary cards. */
.perf-setup-rank-card.is-top {
  border-color: color-mix(in srgb, var(--pos) 42%, var(--border-hair));
  background: color-mix(in srgb, var(--pos-soft) 24%, transparent);
  box-shadow: 0 12px 26px -22px color-mix(in srgb, var(--pos) 30%, transparent);
}
.perf-setup-rank-card.is-neg {
  border-color: color-mix(in srgb, var(--neg) 14%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 9%, transparent);
}
.perf-setup-rank-card.perf-clickable:hover { background: inherit !important; border-color: inherit !important; }
.perf-setup-rank-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 6px;
}
.perf-setup-rank-no {
  font-size: 10.5px;
  font-weight: 850;
  letter-spacing: 0.06em;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.perf-setup-rank-badge {
  font-size: 9.5px;
  font-weight: 850;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--pos);
  background: color-mix(in srgb, var(--pos) 16%, transparent);
  border: 1px solid color-mix(in srgb, var(--pos) 32%, transparent);
  padding: 2px 8px;
  border-radius: 999px;
}
.perf-setup-rank-name {
  font-size: 13.5px;
  font-weight: 820;
  color: var(--text);
  letter-spacing: -0.005em;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.perf-setup-rank-headline {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.perf-setup-rank-headline strong {
  font-size: 20px;
  font-weight: 870;
  letter-spacing: -0.015em;
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.perf-setup-rank-headline small {
  font-size: 9.5px;
  font-weight: 750;
  letter-spacing: 0.06em;
  color: var(--text-3);
  text-transform: uppercase;
}
.perf-setup-rank-track {
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 60%, transparent);
  overflow: hidden;
}
.perf-setup-rank-fill {
  display: block;
  width: var(--target, 0%);
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, var(--pos-light), var(--pos));
  animation: perf-bar-fill 700ms var(--ease-emphasized) forwards;
}
.perf-setup-rank-fill.neg {
  background: linear-gradient(90deg, var(--neg), var(--neg-deep));
}
.perf-setup-rank-meta {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 6px;
  font-variant-numeric: tabular-nums;
}
.perf-setup-rank-meta span {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.perf-setup-rank-meta strong {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text);
}
.perf-setup-rank-meta small {
  font-size: 9.5px;
  font-weight: 750;
  color: var(--text-3);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.perf-setup-rank-net {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  padding-top: 7px;
  border-top: 1px solid color-mix(in srgb, var(--border-hair) 60%, transparent);
}
.perf-setup-rank-net span {
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-setup-rank-net strong {
  font-size: 14px;
  font-weight: 850;
  font-variant-numeric: tabular-nums;
}

/* Weakest setup callout */
.perf-weakest-callout {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 10px;
  align-items: center;
  margin-top: 10px;
  padding: 10px 14px;
  border-radius: 12px;
  background: color-mix(in srgb, var(--neg-soft) 22%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 22%, transparent);
}
.perf-weakest-callout:hover {
  background: color-mix(in srgb, var(--neg-soft) 34%, transparent) !important;
  border-color: color-mix(in srgb, var(--neg) 36%, transparent) !important;
}
.perf-weakest-icon {
  width: 26px;
  height: 26px;
  display: grid;
  place-items: center;
  font-size: 13px;
  font-weight: 900;
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--neg) 26%, transparent);
  border-radius: 50%;
}
.perf-weakest-body {
  display: flex;
  flex-direction: column;
  gap: 1px;
}
.perf-weakest-body strong {
  font-size: 12.5px;
  font-weight: 800;
  color: var(--text);
}
.perf-weakest-body small {
  font-size: 10.5px;
  font-weight: 650;
  color: color-mix(in srgb, var(--neg) 60%, var(--text-3));
}

/* === Section 3: Discipline Drift strip — 6 buckets === */
.perf-drift-strip {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 8px;
}
.perf-drift-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 5px;
  padding: 12px 13px 11px;
  border-radius: 13px;
  background: color-mix(in srgb, var(--surface) 95%, var(--surface-soft));
  border: 1px solid var(--border-hair);
  transition: border-color 140ms var(--ease-out), background 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.perf-drift-card.is-empty { opacity: 0.55; }
.perf-drift-card.is-edge {
  border-color: color-mix(in srgb, var(--pos) 26%, var(--border-hair));
  background: color-mix(in srgb, var(--pos-soft) 13%, transparent);
}
/* The single strongest positive bucket reads as the calm edge — stronger
   border and a restrained lift, no inner glow. */
.perf-drift-card.is-edge.is-dominant {
  border-color: color-mix(in srgb, var(--pos) 40%, var(--border-hair));
  box-shadow: 0 12px 28px -22px color-mix(in srgb, var(--pos) 28%, transparent);
}
/* Danger / Rapid re-entry — emotionally destructive. Deeper red, a static
   corner dot so the eye is drawn to it. No pulsing animation: an institutional
   dashboard signals severity through color + weight, not motion. */
.perf-drift-card.is-warn {
  border-color: color-mix(in srgb, var(--neg) 40%, var(--border-hair));
  background: color-mix(in srgb, var(--neg-soft) 22%, transparent);
  box-shadow: 0 12px 28px -22px color-mix(in srgb, var(--neg) 30%, transparent);
}
.perf-drift-card.is-warn::before {
  content: '';
  position: absolute;
  top: 11px;
  right: 11px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--neg);
}
.perf-drift-card:hover { transform: translateY(-1px); }
.perf-drift-card.perf-clickable:hover { background: inherit !important; border-color: inherit !important; }
.perf-drift-card-label {
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.075em;
  text-transform: uppercase;
  color: var(--text-3);
}
.perf-drift-card.is-warn .perf-drift-card-label { color: var(--neg); }
.perf-drift-card.is-edge .perf-drift-card-label { color: var(--pos); }
.perf-drift-card-exp {
  font-size: 24px;
  font-weight: 880;
  letter-spacing: -0.025em;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  margin-top: 2px;
}
.perf-drift-card.is-dominant .perf-drift-card-exp { font-size: 26px; }
.perf-drift-card-sub {
  font-size: 10.5px;
  font-weight: 650;
  color: var(--text-3);
  line-height: 1.4;
}
.perf-drift-card-bar {
  height: 3px;
  border-radius: 99px;
  overflow: hidden;
  background: color-mix(in srgb, var(--surface-sunken) 60%, transparent);
  margin-top: 4px;
}
.perf-drift-card-fill {
  display: block;
  width: var(--target, 0%);
  height: 100%;
  border-radius: inherit;
  background: var(--pos);
  animation: perf-bar-fill 700ms var(--ease-emphasized) forwards;
}
.perf-drift-card-fill.neg { background: var(--neg); }

/* Responsive — narrow screens collapse drift strip + setup grid */
@media (max-width: 1180px) {
  #performance-diagnostics .perf-drift-strip {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}
@media (max-width: 760px) {
  #performance-diagnostics .perf-drift-strip,
  #performance-diagnostics .perf-setup-ranking {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  #performance-diagnostics .perf-mistake-row {
    grid-template-columns: 1fr;
    text-align: left;
  }
  #performance-diagnostics .perf-mistake-cost { text-align: left; }
}

/* Untagged losses — amber data quality warning */
.perf-data-warn {
  display: flex;
  gap: 7px;
  align-items: flex-start;
  padding: 8px 10px;
  border-radius: 12px;
  background: color-mix(in srgb, #f59e0b 7%, transparent);
  border: 1px solid color-mix(in srgb, #f59e0b 26%, transparent);
  font-size: 10.5px;
  font-weight: 600;
  color: color-mix(in srgb, #c2790e 90%, var(--text));
  line-height: 1.35;
}
.perf-data-warn span:first-child {
  flex-shrink: 0;
  margin-top: 0.5px;
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: color-mix(in srgb, #f59e0b 14%, transparent);
  color: #9a5f08;
  font-size: 11px;
  font-weight: 900;
}

/* Screenshot paste UX */
.je-slot.is-paste-target {
  border-color: var(--pos);
  background: var(--pos-soft);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pos) 18%, transparent);
}
@keyframes je-paste-flash {
  0%   { opacity: 0.5; }
  40%  { opacity: 1; }
  100% { opacity: 1; }
}
.je-slot.just-pasted .je-slot-img {
  animation: je-paste-flash 280ms ease-out both;
}
/* Single-click selection: subtle glow, ready for CMD+V */
.je-slot.is-selected {
  border-color: color-mix(in srgb, var(--pos) 50%, var(--border));
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--pos) 12%, transparent);
  outline: none;
}
.je-slot.is-selected .je-slot-empty span {
  color: var(--pos);
  opacity: 0.9;
}

/* Legacy 5-card score row — kept for any leftover renderer, but the new
   page uses .perf-status. Width is preserved so nothing else breaks. */
.perf-score-row {
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 10px;
}

.perf-score-card {
  min-height: 104px;
  padding: 13px 14px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 8px;
  background:
    radial-gradient(circle at 20% 0%, rgba(92, 200, 255, 0.05), transparent 38%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 95%, var(--surface-soft)), var(--surface));
}

.perf-score-card span,
.perf-diag-head span {
  color: var(--text-3);
  font-size: 10px;
  font-weight: 800;
  letter-spacing: 0.07em;
  text-transform: uppercase;
}

.perf-score-card strong {
  color: var(--text);
  font-size: 26px;
  font-weight: 850;
  line-height: 1;
  font-variant-numeric: tabular-nums;
}

.perf-score-card strong small {
  margin-left: 2px;
  color: var(--text-3);
  font-size: 12px;
  font-weight: 700;
}

.perf-score-card small {
  color: var(--text-3);
  font-size: 11px;
  font-weight: 650;
}

.perf-score-card.pos strong { color: var(--pos); }
.perf-score-card.neg strong { color: var(--neg); }

/* "?" info button in the corner of each performance score card — hovering
   it spawns a floating tooltip that explains what the metric is and how
   it was calculated. Kept tiny and faded by default so it never competes
   with the value itself. */
.perf-score-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.perf-info {
  width: 18px;
  height: 18px;
  display: inline-grid;
  place-items: center;
  border-radius: 50%;
  color: var(--text-4);
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
  border: 1px solid var(--border-hair);
  cursor: help;
  transition: color 180ms var(--ease-out), background 180ms var(--ease-out), transform 180ms var(--ease-out),
              box-shadow 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.perf-info:hover,
.perf-info:focus-visible {
  color: var(--text);
  background: var(--surface);
  border-color: var(--border);
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgba(15,17,21,0.10);
}
.perf-info svg { display: block; }

/* Floating tooltip that the JS positions next to the hovered info button. */
.perf-tooltip {
  position: fixed;
  z-index: 200;
  max-width: 280px;
  padding: 11px 13px 12px;
  border-radius: 12px;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow:
    0 22px 50px rgba(8, 12, 22, 0.18),
    0 4px 14px rgba(8, 12, 22, 0.10);
  color: var(--text-2);
  font-size: 12px;
  font-weight: 500;
  line-height: 1.45;
  letter-spacing: 0;
  text-transform: none;
  opacity: 0;
  transform: translateY(-4px);
  pointer-events: none;
  transition: opacity 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.perf-tooltip.is-visible {
  opacity: 1;
  transform: translateY(0);
}
:root[data-theme="dark"] .perf-tooltip {
  background: #1B2230;
  border-color: rgba(255,255,255,0.10);
}

.perf-diag-main {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 10px;
}

.perf-diag-grid-3 {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.perf-diag-card {
  padding: 16px 18px 14px;
  min-height: 0;
  display: flex;
  flex-direction: column;
  gap: 14px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 12% -10%, rgba(92, 200, 255, 0.06), transparent 36%),
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 96%, var(--surface-soft)), var(--surface));
  box-shadow:
    0 1px 0 rgba(255,255,255,0.04) inset,
    0 16px 32px -28px rgba(8, 12, 22, 0.30);
}

.perf-diag-span-7 { grid-column: span 7; }
.perf-diag-span-5 { grid-column: span 5; }

.perf-diag-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 12px;
  padding-bottom: 10px;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 70%, transparent);
}

.perf-diag-head h3 {
  margin-top: 3px;
  color: var(--text);
  font-size: 15.5px;
  font-weight: 820;
  letter-spacing: -0.005em;
}

.perf-diag-head small {
  color: var(--text-3);
  font-size: 11px;
  font-weight: 700;
  text-align: right;
  white-space: nowrap;
  padding: 4px 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-soft) 65%, transparent);
}
.perf-diag-head small.pos { color: var(--pos); background: var(--pos-soft); }
.perf-diag-head small.neg { color: var(--neg); background: var(--neg-soft); }

.perf-diag-table {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  font-variant-numeric: tabular-nums;
}

.perf-diag-table th {
  padding: 8px 10px;
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 800;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.075em;
  background: color-mix(in srgb, var(--surface-soft) 55%, transparent);
  border-bottom: 1px solid var(--border-hair);
  position: sticky;
  top: 0;
}
.perf-diag-table th:first-child { border-top-left-radius: 10px; border-bottom-left-radius: 10px; }
.perf-diag-table th:last-child  { border-top-right-radius: 10px; border-bottom-right-radius: 10px; }

.perf-diag-table td {
  padding: 11px 10px;
  color: var(--text);
  font-size: 12.5px;
  font-weight: 650;
  border-bottom: 1px solid color-mix(in srgb, var(--border-hair) 65%, transparent);
}

.perf-diag-table td small {
  display: block;
  margin-top: 2px;
  color: var(--text-3);
  font-size: 10.5px;
  font-weight: 650;
}

.perf-diag-table th.num,
.perf-diag-table td.num {
  text-align: right;
}

.perf-diag-table tbody tr:last-child td { border-bottom: 0; }

.perf-diag-table tbody tr {
  transition: background 180ms var(--ease-out), box-shadow 180ms var(--ease-out);
}
/* Zebra striping — barely-there tint that gives the eye a grid lock
   without screaming "spreadsheet." */
.perf-diag-table tbody tr:nth-child(even) td {
  background: color-mix(in srgb, var(--surface-soft) 30%, transparent);
}
.perf-diag-table tbody tr:hover td {
  background: color-mix(in srgb, var(--pos-soft) 35%, var(--surface));
}
.perf-diag-table tbody tr:hover {
  box-shadow: 0 4px 14px -10px rgba(8, 12, 22, 0.18);
}
.perf-diag-table tbody tr td:first-child { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }
.perf-diag-table tbody tr td:last-child  { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }
.perf-diag-table tbody tr td strong { font-weight: 750; letter-spacing: -0.005em; }

.perf-diag-bars {
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.perf-diag-bars.compact { gap: 8px; }

.perf-diag-bar-row {
  display: grid;
  grid-template-columns: minmax(112px, 0.82fr) minmax(84px, 1fr) minmax(64px, auto);
  align-items: center;
  gap: 10px;
  font-variant-numeric: tabular-nums;
}

.perf-diag-bar-row > span {
  min-width: 0;
  color: var(--text);
  font-size: 12px;
  font-weight: 760;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.perf-diag-bar-row small {
  display: block;
  margin-top: 1px;
  color: var(--text-3);
  font-size: 10px;
  font-weight: 650;
  overflow: hidden;
  text-overflow: ellipsis;
}

.perf-diag-bar-row i {
  height: 5px;
  overflow: hidden;
  border-radius: 999px;
  background: color-mix(in srgb, var(--surface-sunken) 80%, transparent);
}

.perf-diag-bar-row b {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, color-mix(in srgb, var(--pos-light) 70%, var(--pos)), var(--pos));
  transition: width 520ms var(--ease-out);
}

.perf-diag-bar-row b.neg { background: linear-gradient(90deg, color-mix(in srgb, var(--neg) 70%, var(--neg-deep)), var(--neg)); }

.perf-diag-bar-row strong {
  color: var(--text);
  font-size: 12px;
  font-weight: 820;
  text-align: right;
}

.perf-diag-metrics,
.perf-execution-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
}

.perf-execution-strip {
  grid-template-columns: repeat(3, minmax(0, 1fr));
  margin-top: auto;
}

.perf-diag-metrics span,
.perf-execution-strip span {
  padding: 9px;
  border: 1px solid var(--border-hair);
  border-radius: 10px;
  background: var(--surface-soft);
}

.perf-diag-metrics small,
.perf-execution-strip small {
  display: block;
  color: var(--text-3);
  font-size: 9.5px;
  font-weight: 800;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.perf-diag-metrics strong,
.perf-execution-strip strong {
  display: block;
  margin-top: 4px;
  color: var(--text);
  font-size: 16px;
  font-weight: 850;
  font-variant-numeric: tabular-nums;
}

.perf-dist-bars {
  min-height: 140px;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
  align-items: end;
  gap: 8px;
  padding-top: 8px;
}

.perf-dist-bar {
  height: 100%;
  display: grid;
  grid-template-rows: 18px 1fr 18px;
  align-items: end;
  gap: 5px;
  text-align: center;
}

.perf-dist-bar span,
.perf-dist-bar strong {
  color: var(--text-3);
  font-size: 10px;
  font-weight: 750;
}

.perf-dist-bar i {
  width: 100%;
  min-height: 8px;
  border-radius: 6px 6px 3px 3px;
  background: linear-gradient(180deg, var(--pos-light), var(--pos));
  opacity: 0.78;
}

.settings-shell {
  display: grid;
  grid-template-columns: 190px minmax(0, 1fr);
  gap: 12px;
  flex: 1 1 auto;
  min-height: 0;
  /* Centered, contained module: the nav + content block sits in the middle of
     the viewport, growing symmetrically left/right with calm margins on very
     wide screens (premium, never edge-to-edge). max-width = 190 nav + 12 gap +
     1840 content, so the readable content can reach exactly 2× the old measure. */
  width: 100%;
  max-width: 2042px;
  margin-inline: auto;
}

.settings-nav {
  position: sticky;
  top: 0;
  align-self: start;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  /* Opaque (no backdrop-filter): position:sticky means this re-composites
     against scrolling content every frame the settings page scrolls. */
  background:
    linear-gradient(180deg, var(--surface-elevated), var(--surface));
  box-shadow: var(--shadow-1);
}

.settings-nav a {
  position: relative;
  padding: 9px 12px 9px 14px;
  border-radius: 9px;
  color: var(--text-3);
  font-size: 12.5px;
  font-weight: 700;
  letter-spacing: -0.003em;
  transition:
    color 160ms var(--ease-out),
    background 160ms var(--ease-out),
    transform 160ms var(--ease-out);
}

.settings-nav a:hover {
  color: var(--text);
  background: var(--surface-soft);
  transform: translateX(1px);
}

/* Active section indicator — a 2px vertical accent on the leading edge plus
   a stronger label color. Driven by JS via .is-active class, set on the
   nav anchor whose target section is currently in view. */
.settings-nav a.is-active {
  color: var(--text);
  background: color-mix(in srgb, var(--pos) 8%, var(--surface));
  font-weight: 750;
  transform: none;
}
.settings-nav a.is-active::before {
  content: '';
  position: absolute;
  left: 5px;
  top: 8px;
  bottom: 8px;
  width: 2px;
  border-radius: 99px;
  background: var(--pos);
}
.settings-nav a:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px color-mix(in srgb, var(--pos) 50%, transparent);
}

.settings-sections {
  display: flex;
  flex-direction: column;
  /* gap 16px (was 12) so sections read as distinct modules, not a single sheet */
  gap: 16px;
  min-width: 0;
  /* Readable measure: exactly 2× the previous 920px box. Centered within its
     column (which, with the centered shell above, places the whole module in
     the middle of the screen). */
  max-width: 1840px;
  width: 100%;
  margin-inline: auto;
  overflow-y: auto;
  padding-right: 2px;
  scrollbar-gutter: stable;
}

/* Review-tag editors laid out as a compact grid so the (otherwise very long)
   Journal & Review section reads as a tidy panel instead of six stacked blocks.
   Each editor keeps its full label / description / input / chips. */
.settings-opt-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-top: 4px;
}
.settings-opt-grid .settings-subgroup { margin: 0; }
@media (max-width: 1400px) { .settings-opt-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 900px)  { .settings-opt-grid { grid-template-columns: 1fr; } }

.settings-section {
  flex: 0 0 auto;
  padding: 22px 24px 24px;
  display: flex;
  flex-direction: column;
  gap: 18px;
  /* Calmer than Performance — no radial gradient, single soft gradient. The
     idea is "administrative panel that respects the eye", not "analytics
     surface". The hairline border carries enough definition. */
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--surface) 96%, var(--surface-soft)), var(--surface));
}

/* Hidden settings (non-functional Preview fields) — these classes set their own
   display, so the UA [hidden] rule needs reinforcing to actually remove them. */
.settings-section[hidden],
.settings-subgroup[hidden],
.settings-field[hidden],
.settings-nav a[hidden] { display: none !important; }

/* ----- New section header rhythm ----------------------------
   Replaces .settings-card-head for the rebuilt Settings page. Smaller
   title, a short description directly underneath, and an optional inline
   action (Add account). All section headers use this shape so the page
   reads as a consistent administrative document. */
.settings-section-head {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--border-hair);
}
.settings-section-head--with-action {
  flex-direction: row;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
}
.settings-section-head--with-action > div {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}
.settings-section-eyebrow {
  padding-left: 13px;
  font-size: 10px;
  font-weight: 750;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--text-3);
}
.settings-section-title {
  position: relative;
  margin: 0;
  padding-left: 13px;
  color: var(--text);
  font-size: 19px;
  font-weight: 800;
  letter-spacing: -0.014em;
  line-height: 1.22;
}
.settings-section-title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.16em;
  bottom: 0.16em;
  width: 3px;
  border-radius: 3px;
  background: var(--pos);
}
.settings-section-desc {
  margin: 4px 0 0;
  padding-left: 13px;
  font-size: 12.5px;
  font-weight: 550;
  color: var(--text-3);
  line-height: 1.5;
  max-width: 64ch;
}

/* ----- Subgroup ----------------------------
   Each settings section is composed of named subgroups. The subgroup head
   carries a tight eyebrow label + optional description. Subgroups within
   the same section are separated by a hairline so the eye can scan one
   topic at a time. */
.settings-subgroup {
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding-top: 6px;
}
.settings-subgroup + .settings-subgroup {
  padding-top: 18px;
  border-top: 1px solid var(--border-hair);
}
.settings-subgroup-head {
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.settings-subgroup-label {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.settings-subgroup-desc {
  font-size: 11.5px;
  font-weight: 550;
  color: var(--text-3);
  line-height: 1.5;
  max-width: 72ch;
}

/* ----- Cloud account row -----------------------
   Signed-in identity + sign-out. A quiet "live" dot signals the session is
   active (honest status — only shown while actually authenticated), the email
   reads as the workspace owner, and sign-out is a restrained secondary button
   (not a destructive primary). */
.settings-cloud-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 12px 14px;
  background: var(--surface-soft);
  border: 1px solid var(--border-hair);
  border-radius: var(--r-md);
}
.settings-cloud-id {
  display: flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
.settings-cloud-dot {
  flex: none;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--pos);
  box-shadow: 0 0 0 3px var(--pos-soft);
}
.settings-cloud-id-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  min-width: 0;
}
.settings-cloud-id-text small {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.settings-cloud-id-text strong {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-1);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.settings-cloud-signout {
  flex: none;
  font-family: var(--font);
  font-size: 12.5px;
  font-weight: 600;
  color: var(--text-2);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  padding: 8px 14px;
  cursor: pointer;
  transition: background 150ms var(--ease-out), color 150ms var(--ease-out), border-color 150ms var(--ease-out);
}
.settings-cloud-signout:hover { background: var(--surface-sunken); color: var(--text-1); border-color: var(--border-strong); }
.settings-cloud-signout:active { transform: translateY(0.5px); }
.settings-cloud-signout:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.settings-plan-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-top: 11px;
  padding-top: 11px;
  border-top: 1px solid var(--border-hair);
}
.settings-plan-label {
  font-size: 12px;
  color: var(--text-3);
}
.settings-plan-badge {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  padding: 2px 9px;
  border-radius: 20px;
  text-transform: uppercase;
}
.settings-plan-badge.is-free {
  background: var(--surface-3);
  color: var(--text-3);
}
.settings-plan-badge.is-pro {
  background: color-mix(in srgb, var(--accent) 14%, transparent);
  color: var(--accent);
}

/* ----- Status badge ----------------------------
   Used for "Coming soon" markers on disabled action cards and "Preview"
   markers on settings whose value persists but is not yet consumed by any
   downstream logic. Quiet amber-ish so the user understands the control is
   conceptual but not destructive. */
.settings-status-badge {
  display: inline-flex;
  align-items: center;
  padding: 2px 7px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.075em;
  text-transform: uppercase;
  border-radius: 5px;
  margin: 6px 0 0;
}
.settings-status-badge--soon {
  color: color-mix(in srgb, #b3760f 80%, var(--text));
  background: color-mix(in srgb, #f59e0b 16%, transparent);
}
:root[data-theme="dark"] .settings-status-badge--soon {
  color: color-mix(in srgb, #fbbf24 92%, var(--text));
  background: color-mix(in srgb, #f59e0b 22%, transparent);
}

/* Inline "Preview" tag — fits next to a field label so the user knows the
   value saves but isn't enforced yet. Stays small so the rest of the row
   keeps its hierarchy. */
.settings-preview-tag {
  display: inline-flex;
  align-items: center;
  margin-left: 8px;
  padding: 1px 6px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: color-mix(in srgb, #b3760f 80%, var(--text));
  background: color-mix(in srgb, #f59e0b 14%, transparent);
  border-radius: 4px;
}
:root[data-theme="dark"] .settings-preview-tag {
  color: color-mix(in srgb, #fbbf24 92%, var(--text));
  background: color-mix(in srgb, #f59e0b 18%, transparent);
}

/* The soon action behaves visually like a disabled card (lower opacity, no
   lift on hover) but the click still fires the same handler — which surfaces
   the "Coming soon" status in the existing status line. */
.settings-action--soon {
  opacity: 0.78;
  cursor: not-allowed;
}
.settings-action--soon:hover {
  transform: none !important;
  border-color: var(--border) !important;
  background: color-mix(in srgb, var(--surface) 78%, var(--surface-sunken)) !important;
}

/* ----- Danger zone ----------------------------
   The Reset action lives in its own subgroup with a clearly different
   surface treatment so it can never be mistaken for a normal export. */
.settings-danger-zone {
  margin-top: 6px;
  padding: 16px 14px 14px;
  border: 1px solid color-mix(in srgb, var(--neg) 22%, transparent);
  border-radius: 14px;
  background:
    linear-gradient(180deg, color-mix(in srgb, var(--neg) 5%, transparent), color-mix(in srgb, var(--neg) 3%, transparent));
}
.settings-danger-zone + .settings-subgroup,
.settings-subgroup + .settings-danger-zone { border-top: 0; padding-top: 16px; }
.settings-danger-label {
  color: var(--neg);
  text-transform: uppercase;
}
.settings-danger-label svg {
  color: var(--neg);
}
.settings-danger-zone .settings-subgroup-desc {
  color: color-mix(in srgb, var(--neg) 60%, var(--text-3));
}

.settings-profile-row {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  padding: 14px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
  border: 1px solid var(--border-hair);
}

.settings-avatar {
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  border-radius: 18px;
  color: #fff;
  background: linear-gradient(135deg, var(--pos), var(--violet));
  box-shadow: var(--shadow-2);
  font-size: 19px;
  font-weight: 850;
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

/* Variants kept as distinct classes; both now auto-fit so a single visible
   field (others [hidden]) never leaves an empty stranded column. */
.settings-form-2 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
.settings-form-3 { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }

/* Natural widths for short controls (attribute/element selectors only — no
   markup change). Dropdowns and numeric inputs read as compact fields instead
   of stretching the full cell; free-text inputs stay full-cell as before. */
.settings-form-3 select.settings-input,
.settings-form-2 select.settings-input { max-width: 260px; }
.settings-form-3 .settings-input[type="number"],
.settings-form-2 .settings-input[type="number"] { max-width: 200px; }
/* The Trading "Defaults" group now carries a single visible control (Default risk
   per trade). Cap its width so it reads as a deliberate compact setting rather than
   one field stretched across the full card with an empty right side. */
.settings-field-risk { max-width: 300px; }

/* User-defined setups list — chips with an inline × button, plus an
   input + Add button row. The whole block sits between the form grid
   and the session-grid so it gets full width without breaking the
   surrounding 3-column layout. */
.settings-setups-block {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 14px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
  border: 1px solid var(--border-hair);
}
.settings-setups-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.settings-setups-head small {
  display: block;
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-3);
  margin-top: 4px;
}
.settings-setups-list {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  min-height: 28px;
}
.settings-setups-list:empty::before {
  content: 'No setups yet — add your first one below.';
  font-size: 12px;
  font-weight: 500;
  color: var(--text-4);
  padding: 4px 0;
}
.settings-setup-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 5px 6px 5px 11px;
  font-size: 12px;
  font-weight: 600;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border-hair);
  border-radius: 999px;
  transition: box-shadow 180ms var(--ease-out), transform 180ms var(--ease-out), border-color 180ms var(--ease-out);
}
.settings-setup-chip:hover {
  border-color: var(--border);
  box-shadow: 0 4px 12px rgba(15,17,21,0.06);
}
.settings-setup-chip button {
  width: 18px;
  height: 18px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  color: var(--text-4);
  font-size: 13px;
  line-height: 1;
  transition: color 140ms var(--ease-out), background 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.settings-setup-chip button:hover {
  color: var(--neg);
  background: var(--neg-soft);
  transform: scale(1.08);
}
.settings-setups-input-row {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
}
.settings-setups-input { min-height: 38px; }
.settings-setups-add {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 0 14px;
  font-size: 12px;
  font-weight: 700;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  transition: background 180ms var(--ease-out), color 180ms var(--ease-out), box-shadow 180ms var(--ease-out), transform 180ms var(--ease-out);
}
.settings-setups-add:hover {
  background: linear-gradient(180deg, var(--pos-soft), var(--surface));
  color: var(--pos);
  box-shadow: 0 6px 16px rgba(18, 152, 216, 0.14);
}
.settings-setups-add:active { transform: scale(0.97); }

/* Leave a little breathing room above a block when it's scrolled to via a
   field gear (scrollIntoView aligns to the scroller's top edge otherwise). */
.settings-subgroup { scroll-margin-top: 16px; }

/* Brief highlight when a review-options block is opened via a field gear in the
   trade modal, so the user lands exactly on the list they came to edit. */
@keyframes settings-opt-flash {
  0%   { box-shadow: 0 0 0 2px color-mix(in srgb, var(--pos) 60%, transparent); background: color-mix(in srgb, var(--pos) 10%, transparent); }
  100% { box-shadow: 0 0 0 2px transparent; background: transparent; }
}
.settings-subgroup.is-flash-target {
  border-radius: 12px;
  animation: settings-opt-flash 1.5s var(--ease-out);
}

.settings-session-grid,
.settings-toggle-grid,
.settings-action-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.settings-toggle-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

/* Action cards size to content (240–320px) and pack from the start, so a lone
   action (e.g. Import broker CSV) never stretches to half the row. The --2/--3
   modifiers stay as distinct classes; all share this auto-fit recipe. */
.settings-action-grid,
.settings-action-grid--2,
.settings-action-grid--3 {
  grid-template-columns: repeat(auto-fit, minmax(240px, 320px));
  justify-content: start;
}

/* Modular grouping for the toggle & action grids — same tinted inner-surface as
   .settings-setups-block / .settings-profile-row (surface-soft 70% + radius 14)
   so each behavioural cluster reads as a discrete module within the card. The
   hairline border is intentionally omitted here (and ONLY here): the children
   (.settings-toggle-row / .settings-action) already carry their own 1px border +
   radius, so a bordered wrapper would create nested boxes. Tint + radius + pad
   give the grouping cue without that artifact. Plain field grids are untouched. */
.settings-toggle-grid,
.settings-action-grid {
  padding: 14px;
  border-radius: 14px;
  background: color-mix(in srgb, var(--surface-soft) 70%, transparent);
}

.settings-action {
  min-height: 82px;
  padding: 14px 16px;
  border: 1px solid var(--border-hair);
  border-radius: 12px;
  background: var(--surface);
  color: var(--text);
  text-align: left;
  font-size: 13.5px;
  font-weight: 750;
  letter-spacing: -0.005em;
  transition:
    transform 160ms var(--ease-out),
    border-color 160ms var(--ease-out),
    box-shadow 160ms var(--ease-out),
    background 160ms var(--ease-out);
}

.settings-action span {
  display: block;
  margin-top: 6px;
  color: var(--text-3);
  font-size: 11.5px;
  font-weight: 550;
  letter-spacing: -0.003em;
  line-height: 1.5;
}

.settings-action:hover,
.settings-action.is-hovered {
  transform: translateY(-1px);
  border-color: var(--border);
  box-shadow: 0 8px 22px -14px rgba(15, 17, 21, 0.18);
  background: var(--surface);
}

.settings-action.danger {
  color: var(--neg);
  background: color-mix(in srgb, var(--neg) 4%, var(--surface));
  border-color: color-mix(in srgb, var(--neg) 22%, transparent);
}
.settings-action.danger:hover {
  background: color-mix(in srgb, var(--neg) 8%, var(--surface));
  border-color: color-mix(in srgb, var(--neg) 32%, transparent);
  box-shadow: 0 8px 22px -14px color-mix(in srgb, var(--neg) 28%, transparent);
}
.settings-action.danger span {
  color: color-mix(in srgb, var(--neg) 55%, var(--text-3));
}

.settings-status {
  color: var(--text-3);
  font-size: 12px;
  font-weight: 650;
  transition: opacity 180ms var(--ease-out);
}
/* Section-level status line: sits under the section header as a single quiet
   wayfinding line (e.g. "Ready." / "Export created."). Aligned to the title's
   accent gutter so it reads as part of the header block. */
.settings-section-status {
  margin: 6px 0 0;
  padding-left: 13px;
}

.settings-theme-toggle {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  /* Cap to the same 260px as the Accent/Language selects so all three controls
     in the Appearance row share one width and one left edge. Left unset, the
     toggle stretched the full column and crowded the Accent select (only the
     12px grid gap between them) while Accent→Language had ~120px of air — the
     toggle now leaves the Accent field the same separation the others have. */
  max-width: 260px;
}

/* ============================================================
   Premium interaction layer
   ============================================================ */

:where(
  .card,
  .tp-overview-card,
  .mini-stat,
  .account-option,
  .ic-row,
  .edge-row,
  .cal-cell:not(.outside),
  .settings-section,
  .settings-nav a,
  .settings-field,
  .settings-action,
  .settings-toggle-row,
  .settings-input,
  .perf-score-card,
  .perf-diag-card,
  .perf-metric,
  .perf-diag-bar-row,
  .perf-diag-metrics span,
  .perf-execution-strip span,
  .perf-dist-bar,
  .je-slot,
  .td-stat,
  .dm-stat,
  .dm-trade-row,
  .side-stat-card,
  .wl-block,
  .tp-chip,
  .seg,
  .theme-seg,
  .pill,
  .dm-btn,
  .cal-nav-btn,
  .chart-icon-btn,
  .nav-item
) {
  transition:
    transform 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    border-color 180ms var(--ease-out),
    background 180ms var(--ease-out),
    color 180ms var(--ease-out),
    opacity 180ms var(--ease-out);
}

:where(
  .mini-stat,
  .account-option,
  .ic-row,
  .edge-row,
  .settings-section,
  .settings-toggle-row,
  .settings-action,
  .perf-score-card,
  .perf-diag-card,
  .perf-metric,
  .perf-diag-bar-row,
  .perf-diag-metrics span,
  .perf-execution-strip span,
  .perf-dist-bar,
  .td-stat,
  .dm-stat,
  .dm-trade-row,
  .side-stat-card,
  .wl-block
):hover,
:where(
  .mini-stat,
  .account-option,
  .ic-row,
  .edge-row,
  .settings-section,
  .settings-toggle-row,
  .settings-action,
  .perf-score-card,
  .perf-diag-card,
  .perf-metric,
  .perf-diag-bar-row,
  .perf-diag-metrics span,
  .perf-execution-strip span,
  .perf-dist-bar,
  .td-stat,
  .dm-stat,
  .dm-trade-row,
  .side-stat-card,
  .wl-block
).is-hovered {
  transform: translateY(-1px);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-1);
}

:where(
  .tp-chip,
  .seg,
  .theme-seg,
  .pill,
  .dm-btn,
  .cal-nav-btn,
  .chart-icon-btn,
  .nav-item,
  .settings-nav a
):hover,
:where(
  .tp-chip,
  .seg,
  .theme-seg,
  .pill,
  .dm-btn,
  .cal-nav-btn,
  .chart-icon-btn,
  .nav-item,
  .settings-nav a
).is-hovered {
  transform: translateY(-1px);
}

.settings-section:hover,
.settings-section.is-hovered {
  box-shadow: var(--shadow-2);
}

.edge-row:hover,
.ic-row:hover,
.dm-trade-row:hover,
.perf-diag-bar-row:hover,
.edge-row.is-hovered,
.ic-row.is-hovered,
.dm-trade-row.is-hovered,
.perf-diag-bar-row.is-hovered {
  background: color-mix(in srgb, var(--surface-soft) 72%, transparent);
  border-radius: 10px;
}

.perf-dist-bar:hover i,
.perf-dist-bar.is-hovered i {
  opacity: 1;
  filter: saturate(1.08);
}

.cal-cell:not(.outside):hover,
.cal-cell:not(.outside).is-hovered {
  transform: translateY(-1px) scale(1.015);
  box-shadow: 0 8px 20px rgba(15, 17, 21, 0.10);
  z-index: 2;
}

.je-slot:hover,
.je-slot.is-hovered {
  transform: translateY(-1px);
  border-color: var(--pos);
  box-shadow: var(--shadow-1);
}

.settings-input:hover,
.settings-input.is-hovered {
  border-color: var(--border-strong);
  background: var(--surface);
}

/* ── Compact tables (Settings → Density & motion) ──────────────────────────
   A deliberate, clearly-felt density step. The dominant lever is NOT cell padding
   (that alone moved the row by a near-invisible ~6px) but the two-line cell
   stacks: in the Trades ledger the date/clock and symbol/setup pairs collapse
   their gap and drop a point or two, which is what actually sets the row height.
   Result: the trade row goes from ~56px to ~38px (~32% shorter) — an obvious,
   "more rows on screen" change you can feel the instant you toggle it. Horizontal
   padding is left untouched so every column stays aligned and nothing clips.
   Applies to the Trades table, the Performance ranking tables and the diagnostics
   tables — the dense lists where scanning speed matters. */
:root.compact-mode .tp-table tbody td {
  padding-top: 5px;
  padding-bottom: 5px;
  font-size: 12px;
  line-height: 1.18;
}
:root.compact-mode .tp-table thead th {
  padding-top: 6px;
  padding-bottom: 4px;
  font-size: 9.5px;
}
/* The two-line stacks are what really own the row height — tighten them hard. */
:root.compact-mode .tp-time-cell,
:root.compact-mode .tp-sym-stack {
  gap: 0;
  line-height: 1.1;
}
:root.compact-mode .tp-time-cell .tp-date { font-size: 11.5px; }
:root.compact-mode .tp-time-cell .tp-clock { font-size: 9.5px; }
:root.compact-mode .tp-sym-cell { font-size: 12px; }
:root.compact-mode .tp-sym-setup { font-size: 9.5px; }
/* Shorter rows → pull the leading accent stripe and hover inset in to match. */
:root.compact-mode .tp-table tbody tr td:first-child::before { inset: 6px auto 6px 0; }
:root.compact-mode .tp-table tbody tr:hover td:first-child::before { inset: 5px auto 5px 0; }
/* Keep the off-screen intrinsic estimate aligned with the compact row height so
   content-visibility doesn't overshoot the scroll length. `auto` self-corrects
   after first paint; this just makes the first estimate right. */
:root.compact-mode .tp-table tbody tr { contain-intrinsic-size: auto 38px; }
:root.compact-mode .perf-table th {
  padding-top: 3px;
  padding-bottom: 3px;
}
:root.compact-mode .perf-table td {
  padding-top: 3px;
  padding-bottom: 3px;
  font-size: 11.5px;
  line-height: 1.15;
}
:root.compact-mode .perf-diag-table td {
  padding-top: 5px;
  padding-bottom: 5px;
  font-size: 12px;
  line-height: 1.18;
}
:root.compact-mode .perf-diag-table td small { margin-top: 0; font-size: 10px; }
:root.compact-mode .perf-diag-table th {
  padding-top: 5px;
  padding-bottom: 5px;
}

@media (max-width: 1180px) {
  .perf-score-row { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .perf-diag-main,
  .perf-diag-grid-3 { grid-template-columns: 1fr; }
  .perf-diag-span-7,
  .perf-diag-span-5 { grid-column: auto; }
  .settings-shell { grid-template-columns: 1fr; }
  .settings-nav { position: static; flex-direction: row; flex-wrap: wrap; }
  /* (removed the fixed 2-col override for .settings-action-grid — the base
     auto-fit minmax(240px,320px) packs cleanly here and avoids stretching a
     lone action; the <=900px block below still collapses it to 1fr.) */
}

@media (max-width: 900px) {
  .perf-score-row,
  .settings-form-2,
  .settings-form-3,
  .settings-session-grid,
  .settings-toggle-grid,
  .settings-action-grid,
  .settings-profile-row {
    grid-template-columns: 1fr;
  }
  .perf-diag-metrics,
  .perf-execution-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Subtle scrollbar */
::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(0,0,0,0.12);
  border-radius: 999px;
}
::-webkit-scrollbar-thumb:hover { background: rgba(0,0,0,0.22); }

/* ============================================================
   REVIEW MODE — high-speed behavioral review workspace.
   Post-import surface for adding the qualitative layer (setup,
   psychology, mistakes, plan) to many trades fast. Reuses the
   app's surface/text/semantic tokens, the .td-rv-chip and
   .td-stars components, and the .day-modal motion language so it
   reads as a native extension of the product, not a new style.
   ============================================================ */
.review-mode {
  position: fixed;
  inset: 0;
  z-index: 120;
  display: grid;
  place-items: center;
  visibility: hidden;
  pointer-events: none;
  transition: visibility 0ms linear 230ms;
}
.review-mode.is-open {
  visibility: visible;
  pointer-events: auto;
  transition: visibility 0ms linear 0ms;
}
body.review-locked { overflow: hidden; }

.review-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(20, 24, 32, 0.0);
  transition: background 160ms ease;
}
.review-mode.is-open .review-backdrop {
  background: rgba(20, 24, 32, 0.40);
  backdrop-filter: blur(10px) saturate(140%);
  -webkit-backdrop-filter: blur(10px) saturate(140%);
  transition: background 320ms var(--ease-emphasized);
}
:root[data-theme="dark"] .review-mode.is-open .review-backdrop {
  background: rgba(8, 12, 22, 0.62);
}

.review-shell {
  position: relative;
  width: min(1200px, 95vw);
  height: min(880px, 94vh);
  background: var(--surface);
  border-radius: 22px;
  box-shadow:
    0 40px 90px rgba(15, 17, 21, 0.32),
    0 16px 40px rgba(15, 17, 21, 0.14),
    0 1px 3px rgba(15, 17, 21, 0.06);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateY(20px) scale(0.97);
  opacity: 0;
  transition: transform 170ms cubic-bezier(0.4, 0, 1, 1), opacity 150ms ease;
}
.review-mode.is-open .review-shell {
  transform: translateY(0) scale(1);
  opacity: 1;
  transition:
    transform 340ms var(--ease-emphasized),
    opacity 220ms var(--ease-emphasized);
}

/* Head */
.review-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 17px 22px;
  border-bottom: 1px solid var(--border-hair);
}
.review-eyebrow {
  display: block;
  font-size: 9.5px;
  font-weight: 750;
  color: var(--text-3);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  margin-bottom: 3px;
}
.review-title { font-size: 17px; font-weight: 760; letter-spacing: -0.02em; color: var(--text); margin: 0; }
.review-sub { margin: 3px 0 0; font-size: 12px; font-weight: 560; color: var(--text-3); }
.review-head-side { display: flex; align-items: center; gap: 14px; }
.review-progress { min-width: 150px; }
.review-progress-text {
  font-size: 11.5px; font-weight: 620; color: var(--text-2);
  display: flex; align-items: baseline; gap: 4px; justify-content: flex-end;
}
.review-progress-text strong { font-size: 15px; font-weight: 780; color: var(--text); font-variant-numeric: tabular-nums; }
#review-progress-den { color: var(--text-3); font-variant-numeric: tabular-nums; }
.review-progress-word { color: var(--text-3); }
.review-progress-bar {
  margin-top: 6px; height: 4px; width: 100%;
  border-radius: 999px; background: var(--surface-sunken); overflow: hidden;
}
#review-progress-fill {
  display: block; height: 100%; width: 0%; border-radius: 999px;
  background: linear-gradient(90deg, var(--mint), color-mix(in srgb, var(--mint) 55%, var(--pos)));
  transition: width 320ms var(--ease-out);
}
.review-finish-btn {
  appearance: none; border: 1px solid var(--border-strong); border-radius: 10px;
  padding: 8px 16px; font: inherit; font-size: 12.5px; font-weight: 680;
  color: var(--text); background: var(--surface-sunken); cursor: pointer;
  transition: background 140ms var(--ease-out), border-color 140ms var(--ease-out), transform 140ms var(--ease-out);
}
.review-finish-btn:hover { background: var(--surface); border-color: var(--text-4); transform: translateY(-1px); }
.review-finish-btn:active { transform: translateY(0); }
.review-close {
  appearance: none; width: 32px; height: 32px; display: grid; place-items: center;
  border: 1px solid transparent; border-radius: 9px; background: var(--surface-sunken);
  color: var(--text-2); cursor: pointer;
  transition:
    background 160ms var(--ease-out),
    color 160ms var(--ease-out),
    border-color 160ms var(--ease-out),
    transform 220ms cubic-bezier(.34, 1.56, .64, 1);
}
.review-close:hover { color: var(--text); border-color: var(--border-hair); background: var(--surface-soft); transform: scale(1.1); }
.review-close:active { transform: scale(0.94); }

/* Body grid */
.review-body { flex: 1; display: grid; grid-template-columns: minmax(280px, 340px) 1fr; min-height: 0; }

/* Queue (left) */
.review-queue {
  display: flex; flex-direction: column; min-height: 0;
  border-right: 1px solid var(--border-hair); background: var(--surface-soft);
}
.review-queue-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 11px 16px; border-bottom: 1px solid var(--border-hair);
}
.review-selall {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 11px; font-weight: 620; color: var(--text-2);
  text-transform: uppercase; letter-spacing: 0.05em; cursor: pointer; user-select: none;
}
.review-selall input { accent-color: var(--pos); width: 14px; height: 14px; cursor: pointer; }
.review-queue-count {
  font-size: 11px; font-weight: 700; color: var(--text-3); font-variant-numeric: tabular-nums;
  background: var(--surface-sunken); padding: 2px 8px; border-radius: 999px;
}
.review-queue-list { flex: 1; overflow-y: auto; overflow-x: hidden; outline: none; scrollbar-width: thin; }

.review-q-row {
  display: grid; grid-template-columns: auto 1fr auto; align-items: center; gap: 11px;
  padding: 9px 16px; border-bottom: 1px solid var(--border-hair); cursor: pointer;
  border-left: 2px solid transparent;
  transition: background 130ms var(--ease-out), border-left-color 130ms var(--ease-out);
}
.review-q-row:hover { background: var(--surface); }
.review-q-row.is-focused { background: var(--surface); border-left-color: var(--pos); }
.review-q-row.is-selected { background: color-mix(in srgb, var(--pos) 7%, var(--surface-soft)); }
.review-q-check { display: inline-grid; place-items: center; }
.review-q-check input { accent-color: var(--pos); width: 15px; height: 15px; cursor: pointer; }
.review-q-main { min-width: 0; }
.review-q-sym { display: flex; align-items: center; gap: 7px; font-size: 12.5px; font-weight: 720; color: var(--text); }
.review-q-sym strong { font-weight: 760; letter-spacing: -0.01em; }
.review-q-side {
  font-size: 9.5px; font-weight: 680; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 1px 6px; border-radius: 5px;
}
.review-q-side.is-long { color: var(--pos); background: var(--pos-soft); }
.review-q-side.is-short { color: var(--neg); background: var(--neg-soft); }
.review-q-sub {
  margin-top: 2px; font-size: 10.5px; font-weight: 540; color: var(--text-3);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.review-q-right { display: flex; align-items: center; gap: 9px; }
.review-q-pnl { font-size: 12px; font-weight: 720; font-variant-numeric: tabular-nums; }
.review-q-pnl.pos { color: var(--pos); }
.review-q-pnl.neg { color: var(--neg); }
.review-q-dot {
  width: 8px; height: 8px; border-radius: 50%; box-sizing: border-box;
  border: 1.5px solid var(--text-4);
  transition: background 160ms, border-color 160ms, transform 160ms;
}
.review-q-row.is-reviewed .review-q-dot { background: var(--mint); border-color: var(--mint); transform: scale(1.05); }

/* Grouping suggestion (subtle, opt-in) */
.review-group-suggest { margin: 10px 12px 2px; }
.review-group-chip {
  display: flex; align-items: center; gap: 8px; width: 100%;
  padding: 9px 11px; border-radius: 11px;
  border: 1px solid color-mix(in srgb, var(--violet) 26%, var(--border));
  background: color-mix(in srgb, var(--violet) 6%, var(--surface));
  color: var(--text-2); font: inherit; font-size: 11.5px; font-weight: 600;
  cursor: pointer; text-align: left;
  transition: background 140ms, border-color 140ms, transform 140ms;
}
.review-group-chip:hover { transform: translateY(-1px); border-color: color-mix(in srgb, var(--violet) 42%, var(--border)); }
.review-group-chip-star { color: var(--violet); font-size: 12px; }
.review-group-chip strong { color: var(--text); font-weight: 740; }
.review-group-chip-caret { margin-left: auto; color: var(--text-3); transition: transform 180ms var(--ease-out); }
.review-group-suggest.is-expanded .review-group-chip-caret { transform: rotate(90deg); }
.review-group-actions {
  display: grid; gap: 3px; margin-top: 5px; overflow: hidden;
  max-height: 0; opacity: 0;
  transition: max-height 240ms var(--ease-out), opacity 200ms var(--ease-out);
}
.review-group-suggest.is-expanded .review-group-actions { max-height: 170px; opacity: 1; }
.review-group-act {
  appearance: none; border: 0; background: transparent; text-align: left;
  padding: 7px 10px; border-radius: 8px; font: inherit; font-size: 11.5px; font-weight: 600;
  color: var(--text-2); cursor: pointer; transition: background 130ms, color 130ms;
}
.review-group-act:hover { background: var(--surface-sunken); color: var(--text); }
.review-group-act.is-dismiss { color: var(--text-3); }

/* Panel (right) */
.review-panel { display: flex; flex-direction: column; min-height: 0; overflow-y: auto; padding: 18px 22px 0; }
.review-panel-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding-bottom: 12px; margin-bottom: 14px; border-bottom: 1px solid var(--border-hair);
}
.review-panel-id { font-size: 18px; font-weight: 780; letter-spacing: -0.02em; color: var(--text); display: flex; align-items: center; gap: 9px; }
.review-panel-id .review-q-side { font-size: 10px; }
.review-panel-meta { font-size: 12px; font-weight: 600; color: var(--text-3); font-variant-numeric: tabular-nums; text-align: right; white-space: nowrap; }
.review-panel-meta .pnl-pos { color: var(--pos); font-weight: 720; }
.review-panel-meta .pnl-neg { color: var(--neg); font-weight: 720; }

.review-bulk-banner {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  margin-bottom: 14px; padding: 9px 13px; border-radius: 11px;
  background: color-mix(in srgb, var(--pos) 9%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--pos) 24%, var(--border));
}
.review-bulk-text { font-size: 12px; font-weight: 680; color: var(--text); }
.review-bulk-clear { appearance: none; border: 0; background: transparent; font: inherit; font-size: 11.5px; font-weight: 640; color: var(--pos); cursor: pointer; }
.review-bulk-clear:hover { text-decoration: underline; }

.review-fields { display: flex; flex-direction: column; gap: 14px; padding-bottom: 16px; }
.review-field { display: flex; flex-direction: column; gap: 7px; }
.review-field-row { display: grid; gap: 12px; }
.review-field-row-2 { grid-template-columns: 1fr 1fr; }
.review-field-label {
  font-size: 10.5px; font-weight: 680; color: var(--text-3);
  text-transform: uppercase; letter-spacing: 0.06em; display: flex; align-items: center; gap: 7px;
}
.review-field-hint { text-transform: none; letter-spacing: 0; font-size: 9.5px; font-weight: 560; color: var(--text-4); }
.review-input {
  width: 100%; min-height: 34px; padding: 7px 12px;
  border: 1px solid var(--border-hair); border-radius: 9px;
  color: var(--text); background: var(--surface);
  font: inherit; font-size: 12.5px; font-weight: 620; letter-spacing: -0.005em;
  transition: border-color 160ms var(--ease-out), box-shadow 160ms var(--ease-out);
}
.review-input:hover { border-color: var(--border); }
.review-input:focus {
  outline: none; border-color: color-mix(in srgb, var(--text) 30%, var(--border));
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--text) 8%, transparent);
}

/* Panel footer */
.review-panel-foot {
  position: sticky; bottom: 0; margin-top: auto;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  padding: 12px 0 16px;
  background: linear-gradient(to top, var(--surface) 74%, transparent);
  border-top: 1px solid var(--border-hair);
}
.review-hints { display: flex; gap: 14px; flex-wrap: wrap; font-size: 10.5px; font-weight: 560; color: var(--text-3); }
.review-hints kbd {
  font-family: var(--mono); font-size: 9.5px; font-weight: 600;
  padding: 1px 5px; border-radius: 5px; margin-right: 1px;
  background: var(--surface-sunken); color: var(--text-2); border: 1px solid var(--border-hair);
}
.review-foot-actions { display: flex; align-items: center; gap: 8px; }
.review-skip {
  appearance: none; border: 1px solid var(--border); background: var(--surface);
  border-radius: 9px; padding: 8px 14px; font: inherit; font-size: 12px; font-weight: 620;
  color: var(--text-2); cursor: pointer; transition: background 140ms, border-color 140ms;
}
.review-skip:hover { background: var(--surface-soft); border-color: var(--border-strong); }
.review-save-next, .review-apply-bulk {
  appearance: none; border: 0; border-radius: 9px; padding: 8px 16px;
  font: inherit; font-size: 12px; font-weight: 680; color: #fff; background: var(--pos); cursor: pointer;
  transition: transform 140ms var(--ease-out), box-shadow 140ms var(--ease-out);
}
.review-save-next:hover, .review-apply-bulk:hover { transform: translateY(-1px); box-shadow: var(--shadow-2); }
.review-save-next:active, .review-apply-bulk:active { transform: translateY(0); }

/* Empty state — all reviewed */
.review-empty {
  flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 12px; padding: 40px; text-align: center;
}
.review-empty-icon {
  width: 56px; height: 56px; border-radius: 50%; display: grid; place-items: center;
  font-size: 26px; color: var(--mint);
  background: color-mix(in srgb, var(--mint) 14%, var(--surface));
  border: 1px solid color-mix(in srgb, var(--mint) 30%, var(--border));
}
.review-empty-text { font-size: 13px; font-weight: 620; color: var(--text-2); max-width: 280px; }
/* These three set an explicit `display`, which beats the UA `[hidden]` rule —
   reinforce it so toggling the `hidden` attribute actually removes them. */
.review-bulk-banner[hidden], .review-fields[hidden], .review-empty[hidden] { display: none; }

:root[data-theme="dark"] .review-q-row.is-selected { background: color-mix(in srgb, var(--pos) 15%, transparent); }

@media (max-width: 880px) {
  .review-shell { width: 96vw; height: 95vh; }
  .review-body { grid-template-columns: 1fr; grid-template-rows: minmax(116px, 36%) 1fr; }
  .review-queue { border-right: 0; border-bottom: 1px solid var(--border-hair); }
}

@media (prefers-reduced-motion: reduce) {
  .review-backdrop, .review-shell,
  .review-mode.is-open .review-backdrop, .review-mode.is-open .review-shell,
  #review-progress-fill, .review-group-actions, .review-group-chip-caret,
  .review-q-row, .review-q-dot { transition: none !important; }
  .review-shell { transform: none !important; }
}

/* ============================================================
   Auth gate — sign-in / sign-up shown until a Supabase session
   exists. Built only from existing design tokens (surface,
   border, accent, radii, shadows) so it reads as the same
   product, not a bolted-on login. Two body-state classes drive
   visibility (set in JS after the session check):
     • body.auth-booting → hide BOTH app and gate (no flash
       either way until we know if a session exists)
     • body.auth-locked  → show the gate, hide the app
   ============================================================ */
/* ── Auth gate ───────────────────────────────────────────────────── */
.auth-gate {
  position: fixed;
  inset: 0;
  z-index: 4000;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(ellipse 80% 60% at 50% -10%, color-mix(in srgb, var(--accent) 7%, transparent) 0%, transparent 70%),
    var(--bg);
  -webkit-font-smoothing: antialiased;
}
body.auth-booting .app,
body.auth-locked .app { display: none !important; }
body.auth-booting .auth-gate { display: none; }
body.auth-locked .auth-gate { display: flex; }
/* Trial expired: keep the dashboard VISIBLE behind the paywall — blurred,
   muted and fully non-interactive — so the user feels their data still exists
   without being able to read or touch it. The translucent gate scrim above
   (see .access-gate background) lets the blurred app show through. */
body.access-expired .app {
  filter: blur(6px) saturate(0.92);
  pointer-events: none;
  user-select: none;
  -webkit-user-select: none;
}
body.access-expired .access-gate { display: flex; }
body.access-expired #user-avatar-btn { display: none !important; }

/* ── Access gate (trial expired) ────────────────────────────────────────── */
.access-gate {
  position: fixed;
  inset: 0;
  z-index: 3900;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 24px;
  overflow-y: auto;
  /* Translucent scrim: the blurred, non-interactive dashboard behind it stays
     faintly visible (var(--bg) at ~72%) so the user sees their data persists. */
  background:
    radial-gradient(ellipse 80% 60% at 50% -10%, color-mix(in srgb, var(--accent) 7%, transparent) 0%, transparent 70%),
    color-mix(in srgb, var(--bg) 72%, transparent);
  -webkit-font-smoothing: antialiased;
}
.access-card {
  width: 100%;
  max-width: 440px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  box-shadow: 0 4px 6px -1px rgba(0,0,0,.06), 0 16px 48px -4px rgba(0,0,0,.14);
  padding: 36px 36px 28px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0;
  text-align: center;
  animation: auth-card-in 440ms var(--ease-emphasized) both;
}
.access-brand { justify-content: center; margin-bottom: 20px; }
.access-trial-ended {
  font-size: 11.5px;
  font-weight: 560;
  letter-spacing: 0.02em;
  color: var(--text-4);
  text-transform: uppercase;
  margin: 0 0 10px;
}
.access-title {
  font-size: 24px;
  font-weight: 740;
  letter-spacing: -0.03em;
  color: var(--text);
  margin: 0 0 8px;
  line-height: 1.2;
}
.access-sub {
  font-size: 13px;
  color: var(--text-3);
  font-weight: 450;
  margin: 0 0 18px;
  line-height: 1.45;
}
.access-features {
  list-style: none;
  padding: 16px;
  margin: 2px 0 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
  width: 100%;
  text-align: left;
  background: var(--surface-soft);
  border: 1px solid var(--border-hair);
  border-radius: 13px;
}
.access-feature {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 13.5px;
  color: var(--text-2);
  line-height: 1.4;
}
.access-feat-icon {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.access-feat-icon::after {
  content: '';
  display: block;
  width: 8px;
  height: 5px;
  border-left: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg) translate(1px, -1px);
}
.access-pricing {
  display: flex;
  align-items: baseline;
  gap: 5px;
  justify-content: center;
  width: 100%;
  margin: 22px 0 18px;
}
.access-price-amount {
  font-size: 36px;
  font-weight: 720;
  letter-spacing: -0.04em;
  color: var(--text);
  line-height: 1;
}
.access-price-period {
  font-size: 15px;
  color: var(--text-3);
  font-weight: 500;
}
.access-upgrade-btn {
  position: relative;
  width: 100%;
  font-family: var(--font);
  padding: 13px 16px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-size: 14.5px;
  font-weight: 620;
  letter-spacing: -0.01em;
  border: none;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.12), 0 4px 14px color-mix(in srgb, var(--accent) 28%, transparent);
  transition: opacity 120ms, transform 150ms var(--ease-out), box-shadow 150ms var(--ease-out);
  margin-bottom: 10px;
}
.access-upgrade-btn:hover {
  opacity: 0.92;
  transform: translateY(-1px);
  box-shadow: 0 2px 6px rgba(0,0,0,0.15), 0 8px 24px color-mix(in srgb, var(--accent) 36%, transparent);
}
.access-upgrade-btn:active { transform: translateY(0.5px); box-shadow: 0 1px 2px rgba(0,0,0,0.12); }
.access-upgrade-btn:focus-visible { outline: 2px solid color-mix(in srgb, #fff 70%, var(--accent)); outline-offset: 2px; }
.access-upgrade-btn:disabled { cursor: default; opacity: 0.55; transform: none; box-shadow: none; }
.access-upgrade-label { transition: opacity 130ms var(--ease-out); }
.access-upgrade-btn.is-busy .access-upgrade-label { opacity: 0; }
.access-upgrade-btn .access-spinner {
  position: absolute;
  top: 50%; left: 50%;
  width: 16px; height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  border: 2px solid rgba(255,255,255,0.35);
  border-top-color: #fff;
  opacity: 0;
  transition: opacity 130ms var(--ease-out);
}
.access-upgrade-btn.is-busy .access-spinner { opacity: 1; animation: auth-spin 720ms linear infinite; }
.access-reassurance {
  font-size: 11.5px;
  color: var(--text-4);
  margin: 0 0 16px;
}
.access-signout-btn {
  width: 100%;
  padding: 10px;
  border-radius: 10px;
  background: transparent;
  color: var(--text-3);
  font-size: 13px;
  font-weight: 500;
  font-family: var(--font);
  border: 1px solid var(--border);
  cursor: pointer;
  transition: background 120ms, color 120ms;
  margin-bottom: 20px;
}
.access-signout-btn:hover { background: var(--surface-soft); color: var(--text); }
.settings-plan-badge.is-trial  { background: color-mix(in srgb, var(--accent) 12%, transparent); color: var(--accent); }
.settings-plan-badge.is-expired { background: color-mix(in srgb, var(--neg) 12%, transparent); color: var(--neg); }
.access-checkout-error { font-size: 12.5px; color: var(--neg); margin: 0 0 8px; line-height: 1.4; }

/* ── Activation polling state (post-checkout, pre-webhook-sync) ──────────────
   Shown inside the access card when body.activation-pending is set: the normal
   paywall (price + Restore CTA) is hidden and a spinner + status message take
   its place, so a user who just paid is never asked to pay again. */
.access-activating {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  padding: 10px 0 20px;
}
.access-activating[hidden] { display: none; }
.access-activating-spinner {
  width: 28px; height: 28px;
  border-radius: 50%;
  border: 2.5px solid color-mix(in srgb, var(--accent) 26%, transparent);
  border-top-color: var(--accent);
  animation: auth-spin 720ms linear infinite;
}
.access-activating.is-timeout .access-activating-spinner { display: none; }
.access-activating-msg {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-2);
  max-width: 320px;
}
/* While activating, hide the normal paywall content (the panel replaces it). */
body.activation-pending .access-trial-ended,
body.activation-pending .access-title,
body.activation-pending .access-sub,
body.activation-pending .access-features,
body.activation-pending .access-pricing,
body.activation-pending .access-upgrade-btn,
body.activation-pending .access-checkout-error,
body.activation-pending .access-reassurance { display: none; }
@media (prefers-reduced-motion: reduce) {
  .access-activating-spinner { animation: none; }
}

/* ── Subscription activated moment ──────────────────────────────────────────
   Opaque success screen shown briefly after checkout, then fades to reveal the
   dashboard. Sits above every gate (z 4200). Driven by .is-active/.is-leaving. */
.activation-overlay {
  position: fixed;
  inset: 0;
  z-index: 4200;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 24px;
  background:
    radial-gradient(ellipse 70% 50% at 50% 32%, color-mix(in srgb, var(--accent) 8%, transparent) 0%, transparent 70%),
    var(--bg);
  opacity: 0;
  transition: opacity 300ms var(--ease-out);
  -webkit-font-smoothing: antialiased;
}
/* The base rule sets display:flex, which would otherwise beat the UA [hidden]
   rule and leave this opacity:0 overlay on top intercepting every click. Keep
   it truly removed until JS sets hidden=false. */
.activation-overlay[hidden] { display: none; }
.activation-overlay.is-active { opacity: 1; }
.activation-overlay.is-leaving { opacity: 0; }
.activation-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  text-align: center;
  opacity: 0;
  transform: translateY(8px) scale(0.97);
  transition: opacity 360ms var(--ease-out), transform 420ms var(--ease-emphasized);
}
.activation-overlay.is-active .activation-inner { opacity: 1; transform: none; }
.activation-check {
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  background: var(--accent);
  box-shadow: 0 4px 16px color-mix(in srgb, var(--accent) 38%, transparent);
}
.activation-check svg { width: 28px; height: 28px; }
.activation-title {
  font-size: 18px;
  font-weight: 680;
  letter-spacing: -0.02em;
  color: var(--text);
}
.activation-sub { font-size: 13px; color: var(--text-3); }

/* Split shell: value-prop aside (left) + form card (right) unified in one
   bordered, shadowed container. Collapses to a single column on mobile. */
.auth-shell {
  display: flex;
  width: 100%;
  max-width: 860px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 22px;
  box-shadow: 0 4px 6px -1px rgba(0,0,0,.06), 0 16px 48px -4px rgba(0,0,0,.14);
  overflow: hidden;
  animation: auth-card-in 440ms var(--ease-emphasized) both;
}
.auth-card {
  flex: 1 1 auto;
  min-width: 0;
  padding: 40px 40px 30px;
}
.auth-aside {
  flex: 0 0 42%;
  max-width: 360px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 36px;
  padding: 40px 34px;
  background: var(--surface-soft);
  border-right: 1px solid var(--border-hair);
}
.auth-aside-brand { display: flex; align-items: center; gap: 11px; }
.auth-aside-headline {
  font-size: 25px;
  line-height: 1.2;
  font-weight: 680;
  letter-spacing: -0.03em;
  color: var(--text);
  margin: 0 0 12px;
}
.auth-aside-sub {
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text-3);
  font-weight: 450;
  margin: 0;
  max-width: 32ch;
}
.auth-aside-trust {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 11px;
}
.auth-aside-trust li {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-2);
}
.auth-aside-check {
  flex-shrink: 0;
  width: 17px;
  height: 17px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  display: flex;
  align-items: center;
  justify-content: center;
}
.auth-aside-check::after {
  content: '';
  display: block;
  width: 7px;
  height: 4px;
  border-left: 1.5px solid var(--accent);
  border-bottom: 1.5px solid var(--accent);
  transform: rotate(-45deg) translate(1px, -1px);
}
/* On desktop the aside carries the brand + trust; hide the card's own copies.
   Scoped to .auth-card (0,2,0) so it beats the base .auth-trust-strip rule that
   sits later in the file. */
.auth-card > .auth-brand { display: none; }
.auth-card .auth-trust-strip { display: none; }

@keyframes auth-card-in {
  from { opacity: 0; transform: translateY(12px) scale(0.982); }
  to   { opacity: 1; transform: none; }
}

/* Mobile: drop the aside, restore the card's own brand + trust strip. */
@media (max-width: 760px) {
  .auth-shell { flex-direction: column; max-width: 420px; }
  .auth-aside { display: none; }
  .auth-card { padding: 34px 28px 26px; }
  .auth-card > .auth-brand { display: flex; }
  .auth-card .auth-trust-strip { display: flex; }
}

/* Brand */
.auth-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 28px;
}
.auth-brand-mark {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  background: var(--accent);
  border-radius: 9px;
  font-size: 16px;
  font-weight: 800;
  color: #fff;
  letter-spacing: 0;
  flex-shrink: 0;
  user-select: none;
}
.auth-brand-text { display: flex; flex-direction: column; gap: 1px; }
.auth-brand-sub {
  display: block;
  font-size: 9.5px;
  font-weight: 560;
  color: var(--text-3);
  letter-spacing: 0.055em;
  text-transform: uppercase;
}
.auth-brand-name {
  font-weight: 720;
  font-size: 15px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text);
}

/* Trust strip */
.auth-trust-strip {
  margin-top: 18px;
  padding-top: 16px;
  border-top: 1px solid var(--border-hair);
  font-size: 11.5px;
  color: var(--text-4);
  text-align: center;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  flex-wrap: wrap;
}
.auth-trust-dot { color: var(--text-4); user-select: none; }

/* Heading */
.auth-title {
  font-size: 23px;
  font-weight: 720;
  letter-spacing: -0.025em;
  color: var(--text);
  margin-bottom: 6px;
}
.auth-sub {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-2);
  margin-bottom: 26px;
}

/* Form */
.auth-form { display: flex; flex-direction: column; gap: 14px; }
.auth-field { display: flex; flex-direction: column; gap: 6px; }
.auth-field > span {
  font-size: 12px;
  font-weight: 580;
  color: var(--text-2);
  letter-spacing: 0.005em;
}
.auth-field input {
  width: 100%;
  font-family: var(--font);
  font-size: 14px;
  color: var(--text);
  background: var(--surface-soft);
  border: 1px solid var(--border-strong);
  border-radius: 10px;
  padding: 11px 14px;
  transition: border-color 150ms var(--ease-out), box-shadow 150ms var(--ease-out), background 150ms var(--ease-out);
}
.auth-field input::placeholder { color: var(--text-4); }
.auth-field input:hover:not(:focus) {
  border-color: color-mix(in srgb, var(--border-strong) 50%, var(--text-4));
  background: var(--surface);
}
.auth-field input:focus {
  outline: none;
  background: var(--surface);
  border-color: var(--pos-light);
  box-shadow: 0 0 0 3px color-mix(in srgb, var(--pos-light) 16%, transparent);
}

/* Password field with visibility toggle */
.auth-pw-wrap {
  position: relative;
  display: flex;
  align-items: center;
}
.auth-pw-wrap input { flex: 1; padding-right: 42px; }
.auth-pw-toggle {
  position: absolute;
  right: 12px;
  width: 24px;
  height: 24px;
  display: grid;
  place-items: center;
  color: var(--text-3);
  background: none;
  border: none;
  border-radius: 5px;
  cursor: pointer;
  padding: 0;
  transition: color 140ms var(--ease-out);
  flex-shrink: 0;
}
.auth-pw-toggle:hover { color: var(--text); }
.auth-pw-toggle:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.auth-pw-toggle svg { pointer-events: none; }
.auth-pw-toggle .pw-show { display: block; }
.auth-pw-toggle .pw-hide { display: none; }
.auth-pw-wrap.is-visible .pw-show { display: none; }
.auth-pw-wrap.is-visible .pw-hide { display: block; }

/* Messages */
.auth-error,
.auth-notice {
  font-size: 12.5px;
  line-height: 1.45;
  border-radius: 8px;
  padding: 9px 12px;
  margin-top: 0;
}
.auth-error {
  color: var(--neg);
  background: var(--neg-soft);
  border: 1px solid rgba(185, 28, 28, 0.18);
}
.auth-notice {
  color: var(--pos);
  background: var(--pos-soft);
  border: 1px solid rgba(18, 152, 216, 0.18);
}

/* Submit */
.auth-submit {
  position: relative;
  margin-top: 6px;
  width: 100%;
  font-family: var(--font);
  font-size: 14.5px;
  font-weight: 620;
  letter-spacing: -0.01em;
  color: #fff;
  background: #1c1c1e;
  border: none;
  border-radius: 10px;
  padding: 13px 16px;
  cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.2), 0 4px 12px rgba(0,0,0,0.12);
  transition: transform 150ms var(--ease-out), box-shadow 150ms var(--ease-out), opacity 150ms var(--ease-out);
}
.auth-submit:hover { transform: translateY(-1px); box-shadow: 0 2px 6px rgba(0,0,0,0.22), 0 8px 20px rgba(0,0,0,0.14); }
.auth-submit:active { transform: translateY(0.5px); box-shadow: 0 1px 2px rgba(0,0,0,0.2); }
.auth-submit:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.auth-submit:disabled { cursor: default; opacity: 0.55; transform: none; }
.auth-submit-label { transition: opacity 130ms var(--ease-out); }
.auth-submit.is-busy .auth-submit-label { opacity: 0; }
.auth-spinner {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 16px;
  height: 16px;
  margin: -8px 0 0 -8px;
  border-radius: 50%;
  border: 2px solid rgba(255, 255, 255, 0.35);
  border-top-color: #fff;
  opacity: 0;
  transition: opacity 130ms var(--ease-out);
}
.auth-submit.is-busy .auth-spinner { opacity: 1; animation: auth-spin 720ms linear infinite; }
@keyframes auth-spin { to { transform: rotate(360deg); } }

/* Footer switch */
.auth-switch {
  margin-top: 20px;
  text-align: center;
  font-size: 13px;
  color: var(--text-3);
}
.auth-switch-btn {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  color: var(--text-2);
  background: none;
  border: none;
  padding: 0 2px;
  cursor: pointer;
  border-radius: 4px;
}
.auth-switch-btn:hover { color: var(--text); text-decoration: underline; }
.auth-switch-btn:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }

.auth-forgot {
  margin: -4px 0 0;
  text-align: right;
}
.auth-forgot-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 0.785rem;
  color: var(--text-3);
  cursor: pointer;
  transition: color 130ms var(--ease-out);
  line-height: 1.5;
}
.auth-forgot-btn:hover { color: var(--text); }
.auth-forgot-btn:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; border-radius: 2px; }

.auth-resend-wrap { text-align: center; margin: 0; }
.auth-resend-btn {
  background: none;
  border: none;
  padding: 0;
  font-size: 0.785rem;
  color: var(--text-3);
  cursor: pointer;
  transition: color 130ms var(--ease-out);
  line-height: 1.5;
}
.auth-resend-btn:hover:not(:disabled) { color: var(--text); }
.auth-resend-btn:disabled { cursor: default; opacity: 0.5; }
.auth-resend-btn:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; border-radius: 2px; }

.auth-foot { display: none; }
.auth-legal {
  margin-top: 8px;
  font-size: 11px;
  color: var(--text-4);
  text-align: center;
}
.auth-legal a {
  color: inherit;
  text-decoration: none;
}
.auth-legal a:hover { color: var(--text-3); text-decoration: underline; }
.auth-legal a:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; border-radius: 2px; }
.legal-sep { margin: 0 5px; user-select: none; }
/* Inline legal links are real <button>s (a11y) styled to read like the old text
   links — full button-chrome reset, inherit the surrounding muted tone. */
.legal-link-inline {
  appearance: none;
  background: none;
  border: 0;
  padding: 0;
  margin: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-decoration: none;
}
.legal-link-inline:hover { color: var(--text-3); text-decoration: underline; }
.legal-link-inline:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; border-radius: 2px; }

/* ── Support section ──────────────────────────────────────────────── */
.support-feedback { display: flex; flex-direction: column; gap: 12px; }
.support-field { display: flex; flex-direction: column; gap: 6px; }
.support-field-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--text-3);
}
.support-select { max-width: 260px; }
.support-textarea {
  min-height: 104px;
  resize: vertical;
  line-height: 1.5;
  font: inherit;
}
.support-send-btn {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: var(--text);
  color: var(--bg);
  font-size: 12.5px;
  font-weight: 750;
  letter-spacing: -0.005em;
  cursor: pointer;
  transition: transform 150ms var(--ease-out), opacity 150ms var(--ease-out), box-shadow 150ms var(--ease-out);
}
.support-send-btn:hover { transform: translateY(-1px); box-shadow: 0 8px 22px -14px rgba(15,17,21,0.4); }
.support-send-btn:active { transform: translateY(0); }
.support-send-btn:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.support-send-note {
  margin: 0;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--pos);
}
.support-contact {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  align-self: flex-start;
  padding: 10px 14px;
  border: 1px solid var(--border-hair);
  border-radius: 10px;
  background: var(--surface);
  color: var(--text);
  text-decoration: none;
  font-size: 13px;
  font-weight: 650;
  transition: border-color 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.support-contact:hover { border-color: var(--border); transform: translateY(-1px); }
.support-contact:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.support-contact svg { color: var(--text-3); flex: none; }
.support-legal-grid { display: flex; flex-wrap: wrap; gap: 8px; }
.support-legal-link {
  appearance: none;
  padding: 7px 13px;
  border: 1px solid var(--border-hair);
  border-radius: 999px;
  background: var(--surface);
  color: var(--text-2, var(--text));
  font-size: 12px;
  font-weight: 650;
  cursor: pointer;
  transition: border-color 150ms var(--ease-out), color 150ms var(--ease-out), transform 150ms var(--ease-out);
}
.support-legal-link:hover { border-color: var(--border); color: var(--text); transform: translateY(-1px); }
.support-legal-link:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; }
.support-cancel-btn { min-height: auto; width: 100%; }

/* ── Legal / Rechtliches modal ────────────────────────────────────── */
/* Sits ABOVE the auth gate (4000) and access gate (3900) — legal docs must be
   reachable pre-login. The modal node is re-parented to <body> at runtime so
   .app's display:none (while auth-locked) can't hide it. */
.legal-modal { z-index: 5000; }
.legal-panel { width: min(720px, 94vw); max-height: 90vh; }
.legal-head { padding-bottom: 14px; }
.legal-tabs {
  display: flex;
  gap: 2px;
  padding: 0 14px;
  overflow-x: auto;
  border-bottom: 1px solid var(--border-hair);
  scrollbar-width: none;
}
.legal-tabs::-webkit-scrollbar { display: none; }
.legal-tab {
  appearance: none;
  background: none;
  border: 0;
  border-bottom: 2px solid transparent;
  padding: 11px 12px;
  font-size: 12px;
  font-weight: 650;
  white-space: nowrap;
  color: var(--text-3);
  cursor: pointer;
  transition: color 150ms var(--ease-out), border-color 150ms var(--ease-out);
}
.legal-tab:hover { color: var(--text); }
.legal-tab.is-active { color: var(--text); border-bottom-color: var(--accent); }
.legal-tab:focus-visible { outline: 2px solid var(--pos-light); outline-offset: -2px; border-radius: 4px; }
.legal-body {
  padding: 18px 22px 24px;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
}
.legal-disclaimer {
  margin: 0 0 18px;
  padding: 11px 13px;
  border: 1px solid color-mix(in srgb, var(--warn, #b8860b) 30%, transparent);
  border-radius: 10px;
  background: color-mix(in srgb, var(--warn, #b8860b) 7%, var(--surface));
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-2, var(--text));
}
.legal-doc { font-size: 12.5px; line-height: 1.6; color: var(--text-2, var(--text)); }
.legal-doc[hidden] { display: none; }
.legal-doc h4 {
  margin: 0 0 4px;
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -0.01em;
  color: var(--text);
}
.legal-doc h5 {
  margin: 18px 0 5px;
  font-size: 12.5px;
  font-weight: 750;
  color: var(--text);
}
.legal-doc .legal-sub {
  margin: 0 0 12px;
  font-size: 11px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--text-3);
}
.legal-doc p { margin: 0 0 8px; }
.legal-doc a { color: var(--accent); text-decoration: none; }
.legal-doc a:hover { text-decoration: underline; }
.legal-ph {
  padding: 0 4px;
  border-radius: 4px;
  background: color-mix(in srgb, var(--accent) 12%, transparent);
  color: var(--accent);
  font-weight: 600;
  font-style: italic;
}
.legal-form-sample {
  padding: 12px 14px;
  border: 1px dashed var(--border);
  border-radius: 10px;
  background: var(--surface-soft, var(--surface));
  font-size: 11.5px;
  line-height: 1.7;
}
.settings-legal {
  margin-top: 18px;
  padding-top: 14px;
  border-top: 1px solid var(--border-hair);
  font-size: 11.5px;
  color: var(--text-4);
  text-align: center;
}
.settings-legal a {
  color: inherit;
  text-decoration: none;
}
.settings-legal a:hover { color: var(--text-3); text-decoration: underline; }
.settings-legal a:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 2px; border-radius: 2px; }

/* ── User avatar button (always-visible, top-right, shown when signed in) ── */
#user-avatar-btn {
  position: fixed;
  top: 11px;
  right: 15px;
  z-index: 91;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: none;
  align-items: center;
  justify-content: center;
  font-family: var(--font);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0;
  color: #fff;
  background: #1c1c1e;
  border: 1.5px solid var(--border);
  cursor: pointer;
  transition: transform 150ms var(--ease-out), box-shadow 150ms var(--ease-out), opacity 150ms var(--ease-out);
  box-shadow: 0 1px 4px rgba(0,0,0,0.18), 0 0 0 2px var(--surface);
  user-select: none;
  pointer-events: auto;
}
body.auth-locked #user-avatar-btn { display: none !important; }
#user-avatar-btn.is-visible { display: flex; }
#user-avatar-btn:hover { transform: scale(1.07); box-shadow: 0 2px 8px rgba(0,0,0,0.22), 0 0 0 2px var(--surface); }
#user-avatar-btn:active { transform: scale(0.97); }
#user-avatar-btn:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 3px; }

/* While a screenshot lightbox is open it must be the top visual layer. The
   viewer lives inside .app (a z-index:1 stacking context); the avatar + menu are
   body-level siblings at z-index 91/92, so they'd paint OVER the fullscreen
   viewer and intercept its close button. Hide them for the duration — scoped to
   body.lightbox-open, so nav and menus everywhere else are untouched. The
   (1,1,1) specificity beats the avatar's is-visible toggle without !important. */
body.lightbox-open #user-avatar-btn,
body.lightbox-open #user-menu-panel {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 160ms var(--ease-out), visibility 0ms linear 160ms;
}

/* ── User menu panel ────────────────────────────────────────────── */
#user-menu-panel {
  position: fixed;
  top: 52px;
  right: 12px;
  z-index: 92;
  width: 228px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  box-shadow: 0 4px 6px -1px rgba(0,0,0,.08), 0 12px 36px -4px rgba(0,0,0,.18);
  padding: 6px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-6px) scale(0.97);
  transform-origin: top right;
  transition: opacity 160ms var(--ease-out), visibility 0ms linear 160ms, transform 180ms var(--ease-out);
}
#user-menu-panel.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition: opacity 160ms var(--ease-out), visibility 0ms, transform 200ms cubic-bezier(0.16,1,0.3,1);
}
.user-menu-identity {
  padding: 10px 12px 10px;
  border-radius: 9px;
}
.user-menu-name {
  font-size: 13px;
  font-weight: 620;
  color: var(--text);
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.user-menu-email {
  font-size: 11.5px;
  color: var(--text-3);
  margin-top: 1px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.user-menu-sep {
  height: 1px;
  background: var(--border-hair);
  margin: 5px 0;
}
.user-menu-item {
  display: flex;
  align-items: center;
  gap: 9px;
  width: 100%;
  padding: 8px 12px;
  border-radius: 8px;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 500;
  color: var(--text-2);
  background: none;
  border: none;
  text-align: left;
  cursor: pointer;
  transition: background 120ms var(--ease-out), color 120ms var(--ease-out);
}
.user-menu-item svg { color: var(--text-3); flex-shrink: 0; }
.user-menu-item:hover { background: var(--surface-soft); color: var(--text); }
.user-menu-item:hover svg { color: var(--text-2); }
.user-menu-item:focus-visible { outline: 2px solid var(--pos-light); outline-offset: 1px; }
.user-menu-item.is-destructive { color: var(--neg); }
.user-menu-item.is-destructive svg { color: var(--neg); opacity: 0.7; }
.user-menu-item.is-destructive:hover { background: var(--neg-soft); color: var(--neg); }

@media (prefers-reduced-motion: reduce) {
  .auth-card { animation: none; }
  .auth-shell { animation: none; }
  .auth-spinner { animation-duration: 1100ms; }
  #user-menu-panel { transition: opacity 80ms linear, visibility 0ms linear 80ms; }
  #user-menu-panel.is-open { transition: opacity 80ms linear, visibility 0ms; }
  .activation-inner { transition: opacity 120ms linear; transform: none; }
  .activation-overlay.is-active .activation-inner { transform: none; }
}

/* ── DEBUG OVERLAY ─────────────────────────────────────────── */
#dbg-overlay {
  position: fixed;
  top: 0; left: 0;
  z-index: 2147483647;
  background: rgba(0,0,0,0.88);
  color: #39ff14;
  font: 600 10.5px/1.55 'Menlo','Consolas',monospace;
  padding: 8px 10px 10px;
  max-width: 260px;
  width: max-content;
  border-bottom-right-radius: 10px;
  pointer-events: auto;
  user-select: text;
  -webkit-user-select: text;
  touch-action: none;
}
#dbg-overlay table { border-collapse: collapse; }
#dbg-overlay td { padding: 0 6px 1px 0; white-space: nowrap; }
#dbg-overlay td:first-child { color: #aaa; }
#dbg-overlay .dbg-sep { color: #555; font-size: 9px; padding: 2px 0; letter-spacing: .04em; }
#dbg-overlay .dbg-close {
  position: absolute; top: 4px; right: 6px;
  background: none; border: none; color: #aaa;
  font-size: 15px; line-height: 1; cursor: pointer;
  padding: 0 2px;
}
#dbg-overlay .dbg-mq-on  { color: #39ff14; }
#dbg-overlay .dbg-mq-off { color: #555; }
/* ── END DEBUG OVERLAY ─────────────────────────────────────── */

/* ── VERSION STAMP (Settings page footer) ──────────────────── */
.settings-version-stamp {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 8px;
  padding: 6px 4px 2px;
  opacity: 0.45;
  transition: opacity 0.18s ease;
}
.settings-version-stamp:hover {
  opacity: 0.85;
}
.settings-version-text {
  font-size: 10px;
  line-height: 1.55;
  letter-spacing: 0.03em;
  color: var(--text-2);
  text-align: right;
  font-family: var(--mono), ui-monospace, "SF Mono", monospace;
  user-select: none;
}
.settings-version-build {
  color: var(--text-3);
}
.settings-version-copy {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 6px;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  padding: 0;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.settings-version-copy:hover {
  background: var(--surface-2, rgba(255,255,255,0.06));
  border-color: var(--border);
  color: var(--text-1);
}
.settings-version-copy:active {
  opacity: 0.7;
}
.settings-version-copy.is-copied {
  color: var(--pos);
  border-color: color-mix(in srgb, var(--pos) 35%, transparent);
}
/* ── END VERSION STAMP ─────────────────────────────────────── */

/* ============================================================
   NOSTICKY TEST (temporary diagnostic — opt-in)   ·   html.nosticky
   ------------------------------------------------------------
   Toggled by the nosticky IIFE at the top of js/app.js (?nosticky=1 or
   localStorage.NO_STICKY='1'), which tags <html class="nosticky">. Forces every
   position:sticky element in the app to static, to test whether sticky inside an
   overflow scroller is what drops Safari Stable onto main-thread (non-fast)
   scrolling — Chrome / Edge / Safari TP composite sticky; Stable does not.
   Inert unless opted in. ROLLBACK: delete this block + the nosticky IIFE.
   ============================================================ */
html.nosticky .tp-table thead th,
html.nosticky .rt-head-row,
html.nosticky .perf-matrix th,
html.nosticky .perf-diag-table th,
html.nosticky .settings-nav,
html.nosticky .review-panel-foot {
  position: static !important;
  top: auto !important;
  bottom: auto !important;
}
/* ── END NOSTICKY TEST ─────────────────────────────────────── */

/* ============================================================
   SAFARI PERFORMANCE MODE   ·   html.safari-perf
   ------------------------------------------------------------
   Toggled by the applySafariPerfMode IIFE at the top of js/app.js (genuine
   Safari/WebKit only — never Chrome / Edge / Firefox / Safari TP). Trades a couple
   of SCROLL behaviours for smooth scrolling on Safari Stable, which — unlike Blink
   and Safari TP — runs the following on the MAIN THREAD:

     1. position:sticky inside an overflow scroller → non-fast (main-thread)
        scrolling on every page. Forced static here (same 6 surfaces as the
        nosticky diagnostic above).
     2. custom rAF wheel-momentum + a {passive:false} wheel listener → handled in
        JS (wireSmoothWheelScroll early-returns); native WebKit scroll is used.

   The page-enter cascade (page-slide-in + per-item page-item-in) is NO LONGER
   suppressed on Safari: per-visit entrance replay is wanted, and the forensic
   Safari pass cleared the cascade as a lag source. The keep-warm Trades layout-skip
   (content-visibility:hidden, ~line 1039) is already universal.

   Per-user override / rollback: ?safariperf=0 or localStorage SAFARI_PERF='0'.
   ROLLBACK: delete this block + the applySafariPerfMode IIFE + the
   wireSmoothWheelScroll window.__SAFARI_PERF guard.
   ============================================================ */

/* 1 — sticky headers/footers → static (no main-thread sticky scrolling) */
html.safari-perf .tp-table thead th,
html.safari-perf .rt-head-row,
html.safari-perf .perf-matrix th,
html.safari-perf .perf-diag-table th,
html.safari-perf .settings-nav,
html.safari-perf .review-panel-foot {
  position: static !important;
  top: auto !important;
  bottom: auto !important;
}
/* ── END SAFARI PERFORMANCE MODE ───────────────────────────── */

/* ============================================================
   ROOTSCROLL TEST (temporary diagnostic — opt-in)   ·   html.rootscroll
   ------------------------------------------------------------
   Proof mode for the nested-scroller / fixed-shell hypothesis. Normally the
   app pins body (overflow:hidden) + .page-stage (overflow:clip) to the
   viewport and gives each page its OWN overflow:auto scroller:
     · Trades       → .tp-table-card / .tp-table-wrap
     · Settings     → .settings-sections
     · Performance  → .page-performance  AND inner .performance-grid  (nested!)
   In WebKit Stable a nested overflow scroller can fall onto main-thread
   (non-fast) scrolling. This block neutralises those page-level scrollers so
   the DOCUMENT (root) scrolls natively, to confirm/deny that as the lag
   source. Layout/scroll CSS ONLY — no data/render/auth logic touched.
   Toggled by the applyRootScrollTest IIFE in js/app.js (?rootscroll=1 or
   localStorage.ROOTSCROLL='1'). Inert unless opted in.
   ROLLBACK: delete this block + the applyRootScrollTest IIFE.
   ============================================================ */

/* 1 — hand scrolling to the document (html/body). */
html.rootscroll,
html.rootscroll body {
  height: auto !important;
  min-height: 100% !important;
  overflow: visible !important;
}
html.rootscroll .app { height: auto !important; min-height: 100vh; }

/* 2 — break the viewport height-lock chain so each page sizes to its content
   instead of the viewport. The real clamp is <main class="main"> (a flex column
   with height:100vh + overflow:hidden); .page-stage / .page below it are flex:1
   children. Un-height-lock main + un-clip it, and flip the flex:1 children to
   flex:0 0 auto (height:auto alone can't beat the flex-basis:0 that `flex:1`
   sets). Pages stay flex COLUMNS internally so card gaps survive. */
html.rootscroll .main {
  height: auto !important;
  min-height: 0 !important;
  overflow: visible !important;
}
html.rootscroll .page-stage {
  flex: 0 0 auto !important;
  overflow: visible !important;
  height: auto !important;
  min-height: 0 !important;
}
html.rootscroll .page.is-active {
  flex: 0 0 auto !important;
  min-height: 0 !important;
}

/* 3 — Trades: expand the full ledger into document flow (no inner scroller). */
html.rootscroll .tp-table-card,
html.rootscroll .tp-table-wrap {
  flex: 0 0 auto !important;
  overflow: visible !important;
  height: auto !important;
  max-height: none !important;
  min-height: 0 !important;
}

/* 4 — Settings: drop the inner sections scroller. */
html.rootscroll .settings-sections {
  overflow: visible !important;
  height: auto !important;
  max-height: none !important;
  min-height: 0 !important;
}

/* 5 — Performance: drop BOTH the page scroller and the nested grid scroller. */
html.rootscroll .page-performance {
  overflow: visible !important;
  height: auto !important;
  min-height: 0 !important;
}
html.rootscroll .performance-grid {
  flex: 0 0 auto !important;
  overflow: visible !important;
  height: auto !important;
  max-height: none !important;
  min-height: 0 !important;
}

/* 6 — Dashboard is a height-locked single screen by design; keep that definite
   height (so the recent-trades ResizeObserver still reads a stable clientHeight
   and never enters its shrink loop) but let an onboarding-tall dashboard spill
   into document scroll instead of its own inner scroller. */
html.rootscroll .page-dashboard { overflow: visible !important; }
html.rootscroll .page-dashboard.is-active { min-height: calc(100dvh - 92px); }
/* ── END ROOTSCROLL TEST ───────────────────────────────────── */

/* ============================================================
   First-run walkthrough — dimming spotlight tour.
   The intro reuses .day-modal / .day-modal-panel (open animation,
   blur, dark mode all inherited). Defined here: the intro's inner
   layout, the floating coach card, the spotlight veil + hole that
   dim the page around the target, and the grow-emphasis transform.
   ============================================================ */

/* Intro panel — narrower, centred copy on the shared modal material. */
.wt-modal .wt-intro-panel {
  width: min(440px, 92vw);
  padding: 30px 30px 24px;
  text-align: center;
  align-items: center;
}
.wt-intro-eyebrow {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--accent);
}
.wt-intro-title {
  margin: 10px 0 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
.wt-intro-body {
  margin: 10px auto 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--text-2);
  max-width: 38ch;
}
.wt-intro-foot {
  display: flex;
  justify-content: center;
  gap: 10px;
  margin-top: 22px;
}

/* Coach card — a small fixed panel pinned next to the highlighted UI. It sits
   above the spotlight dim (z 200 > 180) so it stays bright and readable. */
.wt-coach {
  position: fixed;
  z-index: 200;
  left: 0;
  top: 0;
  width: min(330px, calc(100vw - 24px));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-3);
  padding: 14px 16px 16px;
  opacity: 0;
  visibility: hidden;
  transform: translateY(6px) scale(0.98);
  transform-origin: top center;
  transition:
    opacity 200ms var(--ease-emphasized),
    transform 240ms var(--ease-emphasized),
    left 260ms var(--ease-emphasized),
    top 260ms var(--ease-emphasized),
    visibility 0ms linear 240ms;
}
.wt-coach.is-open {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
  transition:
    opacity 240ms var(--ease-emphasized),
    transform 280ms var(--ease-emphasized),
    left 260ms var(--ease-emphasized),
    top 260ms var(--ease-emphasized),
    visibility 0ms linear 0ms;
}
:root[data-theme="dark"] .wt-coach {
  background: var(--surface-soft);
}
.wt-coach-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
}
.wt-coach-count {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--text-3);
  font-variant-numeric: tabular-nums;
}
.wt-coach-x {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  border: none;
  background: transparent;
  color: var(--text-3);
  cursor: pointer;
  transition: background 140ms var(--ease-out), color 140ms var(--ease-out);
}
.wt-coach-x:hover { background: var(--surface-soft); color: var(--text); }
:root[data-theme="dark"] .wt-coach-x:hover { background: rgba(255, 255, 255, 0.08); }
.wt-coach-title {
  margin: 0;
  font-size: 15px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--text);
}
.wt-coach-body {
  margin: 6px 0 0;
  font-size: 13px;
  line-height: 1.5;
  color: var(--text-2);
}
.wt-coach-foot {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
  margin-top: 14px;
}
.wt-coach-foot .pill { padding: 6px 12px; font-size: 12px; }
.wt-coach-back:disabled { opacity: 0.4; pointer-events: none; }

/* Spotlight veil — a transparent, full-screen click-catcher that sits over the
   page during the tour so the dimmed background isn't interactive. The visible
   dim is painted by #wt-spot's shadow, not here; .is-dim is only a fallback for
   a step whose target can't be found (no hole → flat dim instead). */
.wt-veil {
  position: fixed;
  inset: 0;
  z-index: 170;
  background: transparent;
  pointer-events: none;
  opacity: 0;
  transition: opacity 220ms var(--ease-out), background 220ms var(--ease-out);
}
.wt-veil.is-on { pointer-events: auto; opacity: 1; }
.wt-veil.is-dim { background: rgba(15, 23, 42, 0.55); }
:root[data-theme="dark"] .wt-veil.is-dim { background: rgba(2, 5, 12, 0.72); }

/* Spotlight hole — sized to the highlighted element. The 0 0 0 100vmax shadow
   dims the ENTIRE screen except this box (the bright target shows through), and
   the two inner rings draw the accent halo right at the hole edge. position/size
   transitions glide the hole between same-page steps; opacity lifts it during a
   page change. pointer-events:none → clicks fall through to the veil beneath. */
.wt-spot {
  position: fixed;
  z-index: 180;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  border-radius: var(--r-lg);
  background: transparent;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  box-shadow:
    0 0 0 2px var(--accent),
    0 0 0 7px color-mix(in srgb, var(--accent) 22%, transparent),
    0 0 0 100vmax rgba(15, 23, 42, 0.55);
  transition:
    left 300ms var(--ease-emphasized),
    top 300ms var(--ease-emphasized),
    width 300ms var(--ease-emphasized),
    height 300ms var(--ease-emphasized),
    opacity 220ms var(--ease-out),
    visibility 0ms linear 220ms;
}
.wt-spot.is-open {
  opacity: 1;
  visibility: visible;
  transition:
    left 300ms var(--ease-emphasized),
    top 300ms var(--ease-emphasized),
    width 300ms var(--ease-emphasized),
    height 300ms var(--ease-emphasized),
    opacity 240ms var(--ease-out),
    visibility 0ms linear 0ms;
}
:root[data-theme="dark"] .wt-spot {
  box-shadow:
    0 0 0 2px var(--accent),
    0 0 0 7px color-mix(in srgb, var(--accent) 26%, transparent),
    0 0 0 100vmax rgba(2, 5, 12, 0.72);
}

/* Grow-emphasis — the highlighted element scales up so focus lands on it. The
   factor is set inline per target (capped so full-width rows barely grow). No
   layout impact: transform is ignored by offset* so fitDashboard is unaffected.
   position+z-index keep the grown box painted over its neighbours. */
.lucra-tour-spot {
  position: relative;
  z-index: 1;
  transform: scale(var(--wt-scale, 1));
  transform-origin: center center;
  transition: transform 360ms var(--ease-emphasized);
}

@media (prefers-reduced-motion: reduce) {
  .wt-coach {
    transition: opacity 120ms linear, visibility 0ms linear 120ms;
  }
  .wt-coach.is-open {
    transition: opacity 120ms linear, visibility 0ms linear 0ms;
  }
  .wt-spot {
    transition: opacity 120ms linear, visibility 0ms linear 120ms;
  }
  .wt-spot.is-open {
    transition: opacity 120ms linear, visibility 0ms linear 0ms;
  }
  .lucra-tour-spot { transition: none; }
}
