/* ─────────────────────────────────────────────────────────────────────────
 * css/portfolio.css — TAN-355
 * Portfolio tab styles. Scoped under .portfolio-page to avoid leakage into
 * the rest of the app. Mirrors the locked v14 + Variation D mockup
 * (sunburst with glass). All colors pull from the design tokens defined
 * in css/app.css (--bg, --surface, --surface-2, --border, --text-*,
 * --purple, --blue, --cyan, --emerald) so the tab inherits the app's
 * dashboard theme.
 * ───────────────────────────────────────────────────────────────────────── */

.portfolio-page {
  display: flex;
  flex-direction: column;
  gap: 16px;
  padding: 4px 0 32px;
  color: var(--text-primary);
}
/* TAN-684: bump whole tab ~10% on desktop — Matt: "looks much better at 110% zoom".
   Chromium PWA, so zoom scales type + layout proportionally in one line rather than
   touching ~219 hardcoded px font-sizes. SCOPED to >=768px so the 110% bump does NOT
   cause horizontal overflow / cramping on phones (mobile renders at native scale and
   relies on the existing responsive breakpoints below). */
@media (min-width: 768px) {
  .portfolio-page { zoom: 1.1; }
}

/* Row layout */
.portfolio-page .pt-row {
  display: grid;
  gap: 16px;
}
/* The HTML `hidden` attribute only sets `display:none` at UA-default specificity,
   which the `.pt-row { display: grid }` rule above silently overrides. The
   legacy concentration strip (#pt-legacy-strip) and conviction-thesis row
   (#pt-thesis-row) ship `hidden` (their feature flags are off) but were being
   forced visible by that grid rule, leaving 3 perpetual "Loading…" skeleton
   tiles at the bottom of the page. Honor `hidden` explicitly. */
.portfolio-page [hidden] {
  display: none !important;
}
.portfolio-page .pt-row-top {
  /* Narrative (left) ~58% / Pie (right) ~42%. */
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
}
/* TAN-732 Fix 3: AI Insights (left) + Allocation donut (right), matching
   mockE .grid2 (1.45fr / 1fr). The donut is contained in the right column —
   replacing the prior full-width radial row that read as a second donut. */
.portfolio-page .pt-grid2 {
  grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
  align-items: start;
}
.portfolio-page .pt-row-meso {
  /* TAN-725: Drift card dropped from V1 — meso row now holds R/R + Concentration
     Lead, so 2 columns instead of 3. */
  grid-template-columns: repeat(2, minmax(0, 1fr));
}
/* TAN-730: Narrative card (BUG 3) and standalone R/R card (BUG 4) removed.
   The top row now holds only the pie card and the meso row only Concentration
   Lead — both span full width so the lone card doesn't look orphaned. */
.portfolio-page .pt-row-top-solo,
.portfolio-page .pt-row-meso-solo {
  grid-template-columns: 1fr;
}
@media (max-width: 1080px) {
  .portfolio-page .pt-row-top,
  .portfolio-page .pt-grid2,
  .portfolio-page .pt-row-meso {
    grid-template-columns: 1fr;
  }
}

/* Card shell */
.portfolio-page .pt-card,
.portfolio-page .pt-narrative-card,
.portfolio-page .pt-pie-card,
.portfolio-page .pt-rr-card,
.portfolio-page .pt-risk-card,
.portfolio-page .pt-drift-card,
.portfolio-page .pt-pl-card,
.portfolio-page .pt-thesis-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 18px;
  position: relative;
}

/* Eyebrow */
.portfolio-page .pt-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 10px;
}

/* Head row inside the pie card (eyebrow + toggle) */
.portfolio-page .pt-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 6px;
}
.portfolio-page .pt-head .pt-eyebrow { margin-bottom: 0; }
.portfolio-page .pt-toggle {
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-primary);
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.04em;
  padding: 4px 10px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 120ms ease;
}
.portfolio-page .pt-toggle:hover {
  background: var(--bg-alt, #0D1526);
}

/* Skeleton placeholder */
.portfolio-page .pt-skeleton {
  color: var(--text-secondary);
  opacity: 0.6;
  font-size: 13px;
}

/* ── Narrative card ─────────────────────────────────────────────────── */
/* TAN-723 #4: owner review flagged the purple-tinted gradient + left accent
   rail as too heavy, with empty space below the prose. Flattened to a plain
   darker surface (no gradient, no accent rail per handoff rule 20), tighter
   vertical padding, and height:auto / min-height:0 so the card collapses to
   its content instead of leaving a tall empty block. */
.portfolio-page .pt-narrative-card {
  display: flex;
  flex-direction: column;
  gap: 8px;
  background: var(--surface-2);
  padding-top: 12px;
  padding-bottom: 12px;
  min-height: 0;
  height: auto;
}
.portfolio-page .pt-narrative-card .pt-eyebrow {
  color: var(--purple);
}
.portfolio-page .pt-narrative-body {
  font-size: 15.5px;
  line-height: 1.6;
  font-weight: 500;
  color: var(--text-primary);
  display: flex;
  align-items: flex-start;
  gap: 10px;
  flex-wrap: wrap;
}
.portfolio-page .pt-narrative-text { flex: 1 1 auto; color: var(--text-primary); }
.portfolio-page .pt-regime-tag {
  display: inline-block;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--purple);
  background: rgba(139, 92, 246, 0.10);
  border: 1px solid rgba(139, 92, 246, 0.25);
  padding: 3px 8px;
  border-radius: 6px;
  white-space: nowrap;
  flex: 0 0 auto;
}

/* ── Pie card ───────────────────────────────────────────────────────── */
.portfolio-page .pt-pie-card {
  display: flex;
  flex-direction: column;
}
.portfolio-page .pt-pie-stage {
  position: relative;
  padding: 6px 0 4px;
  min-height: 260px;
}
.portfolio-page .pt-pie-svg-wrap {
  position: relative;
  width: 100%;
  display: flex;
  justify-content: center;
}
.portfolio-page .pt-pie-svg {
  width: 100%;
  /* TAN-684: enlarge the donut — Matt nudged the card left to make room.
     Was 360px; the viewBox is fixed (0 0 440 440) so the SVG scales up
     cleanly without touching slice geometry.
     Round-2 (Fix 7): bumped 420→460 for a larger donut to pair with the
     thinner ring + bigger center hole.
     TAN-684 vertical stack: with the donut now on its own full-width row (no
     longer sharing the card with a side panel) it can grow further; cap raised
     so it fills the panel width on the stacked layout. */
  max-width: 520px;
  height: auto;
  display: block;
  margin: 0 auto;
}
.portfolio-page .pt-pie-empty {
  color: var(--text-secondary);
  font-size: 13px;
  text-align: center;
  padding: 60px 24px;
}
.portfolio-page .pt-slice {
  cursor: pointer;
  /* TAN-732 Fix 2 / MOCKUP-E-v2 CHANGE 5: animate the radial pop-out translate
     (~4px) set on the active slice alongside the opacity transition. ~220ms
     ease-out per spec. */
  transition: fill-opacity 220ms ease-out, transform 220ms cubic-bezier(0.22, 1, 0.36, 1);
}
.portfolio-page .pt-slice:hover { fill-opacity: 1 !important; }
.portfolio-page .pt-slice.pt-slice-active { fill-opacity: 1 !important; }

/* MOCKUP-E-v2 (CHANGE 5): one-shot bright sheen swept along the active arc.
   The overlay path is filled with the #pt-sheen gradient; we animate its
   opacity in/out once on activation. (A true offset-sweep would require
   per-frame path morphing; a single bright pulse along the arc reads as the
   "sheen" while staying cheap and SVG-safe.) */
.portfolio-page .pt-slice-sheen {
  pointer-events: none;
  animation: pt-slice-sheen-anim 220ms ease-out 1;
}
@keyframes pt-slice-sheen-anim {
  0%   { fill-opacity: 0; }
  45%  { fill-opacity: 0.55; }
  100% { fill-opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  .portfolio-page .pt-slice { transition: fill-opacity 120ms ease; }
  .portfolio-page .pt-slice-sheen { animation: none; fill-opacity: 0; }
}

/* Pie center text */
.portfolio-page .pt-pie-center-amount {
  fill: var(--text-primary);
  font-family: 'DM Sans', system-ui, sans-serif;
  /* Round-2 (Fix 7): 22→26px — the bigger center hole (r=104) gives room for a
     more readable headline value. */
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.01em;
}
.portfolio-page .pt-pie-center-meta {
  fill: var(--text-secondary);
  font-family: 'Inter', sans-serif;
  font-size: 10px;
  letter-spacing: 0.04em;
}
.portfolio-page .pt-pie-center-today {
  /* fill set by sign modifier below; default neutral so a missing/zero day
     never renders the old hardcoded green. */
  fill: var(--text-secondary);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.06em;
}
/* TAN-684: donut center day-move color must follow the sign (was hardcoded
   emerald, so down days showed green). */
.portfolio-page .pt-pie-center-today--up   { fill: var(--emerald); }
.portfolio-page .pt-pie-center-today--down { fill: var(--red); }
.portfolio-page .pt-pie-center-amount--up   { fill: var(--emerald); }
.portfolio-page .pt-pie-center-amount--down { fill: var(--red); }

/* Pie foot (cluster summary line + hint) */
.portfolio-page .pt-pie-foot,
.portfolio-page .pt-cluster-foot {
  font-size: 11.5px;
  color: var(--text-secondary);
  margin-top: 4px;
  padding: 6px 0 0;
  border-top: 1px dashed var(--border);
  line-height: 1.5;
}
.portfolio-page .pt-pie-foot strong,
.portfolio-page .pt-cluster-foot strong {
  color: var(--text-primary);
  font-weight: 600;
}
.portfolio-page .pt-cluster-diamond {
  color: var(--purple);
  font-size: 10px;
  vertical-align: middle;
}

/* TAN-620-B: rich cluster strip below the pie. Replaces the plain text
   list rendered by _renderClusterFoot. Chips wrap on narrow widths;
   each chip carries a colored diamond matching its slice hue. */
.portfolio-page .pt-cstrip {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 2px;
}
.portfolio-page .pt-cstrip-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  border-radius: 999px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  font-size: 11px;
  line-height: 1.2;
  color: var(--text-secondary);
  white-space: nowrap;
}
.portfolio-page .pt-cstrip-diamond {
  font-size: 11px;
  line-height: 1;
  /* color set inline per cluster */
}
.portfolio-page .pt-cstrip-name {
  color: var(--text-primary);
  font-weight: 600;
  /* TAN-684: labels come pre-cased from _clusterDisplayLabel ("AI infra",
     "Megacap"); capitalize would corrupt "AI infra" → "Ai Infra". */
  text-transform: none;
  letter-spacing: 0.01em;
}
.portfolio-page .pt-cstrip-weight {
  color: var(--text-primary);
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
/* BUG 2: thin separator between cluster name and weight so "name · %" reads as
   two distinct fields rather than a cramped run. */
.portfolio-page .pt-cstrip-weight::before {
  content: '\00B7';
  margin-right: 6px;
  color: var(--border);
  font-weight: 400;
}

/* Pie tooltip (positioned absolutely inside .pt-pie-stage)
   TAN-620-A: widened from 220px → 252px to fit shares×ACB + UPL + Day P/L
   rows + Next ER chip. Vertical layout unchanged.
   TAN-684: in the side-panel layout (.pt-pie-panel) width is auto and the
   tooltip fills the wider panel; conviction + score rows added below Day P/L. */
.portfolio-page .pt-pie-tooltip {
  position: absolute;
  top: 10px;
  right: 6px;
  width: 252px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
  font-size: 12px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.45);
}
.portfolio-page .pt-pie-tt-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 8px;
}
.portfolio-page .pt-pie-tt-titleblock {
  display: flex; flex-direction: column; gap: 1px;
  min-width: 0;
}
.portfolio-page .pt-pie-tt-tkr {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: 14px;
  color: var(--text-primary);
  line-height: 1.1;
}
.portfolio-page .pt-pie-tt-co {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 10.5px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 165px;
}
.portfolio-page .pt-pie-tt-day {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 600;
  flex-shrink: 0;
}
.portfolio-page .pt-pie-tt-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 4px 12px;
  font-size: 11.5px;
}
.portfolio-page .pt-pie-tt-lbl { color: var(--text-secondary); }
.portfolio-page .pt-pie-tt-val { color: var(--text-primary); text-align: right; font-variant-numeric: tabular-nums; }
/* TAN-684: tone the conviction/score values so the tooltip's lower half reads
   as actionable signal, not flat text. Scoped to the grid so it never leaks
   into other surfaces. Palette: green gain / red loss / gold mid / red weak. */
.portfolio-page .pt-pie-tt-val.pt-tone-pos { color: #34D399; }
.portfolio-page .pt-pie-tt-val.pt-tone-neg { color: #F87171; }
.portfolio-page .pt-pie-tt-val.pt-tone-amber { color: #FBBF24; }
.portfolio-page .pt-pie-tt-val.pt-tone-neutral { color: var(--text-secondary); }

/* TAN-954: drop the purple conviction-tier background box on the donut hover
   tooltip's Score value (conf-tier-* carries a purple bg+border). Keep the
   tier text color as the signal so the row matches the text-only conviction
   tone above it. Scoped to the tooltip value so score chips elsewhere keep
   their tier styling. */
.portfolio-page .pt-pie-tt-val.conf-tier-high,
.portfolio-page .pt-pie-tt-val.conf-tier-mid,
.portfolio-page .pt-pie-tt-val.conf-tier-low {
  background: transparent;
  border: 0;
}

/* Next-earnings row — inline label + chip; sits below the data grid. */
.portfolio-page .pt-pie-tt-er {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.portfolio-page .pt-pie-tt-er-lbl {
  font-size: 11px;
  color: var(--text-secondary);
}
/* TAN-684 PR 5/5 — mockup-canonical earnings value, e.g. "Wed Aug 27 · 56d".
   Right-aligned, tabular nums so the day count lines up across tickers.
   Per-tone color overrides since the generic .pt-tone-* classes are
   scoped to other surfaces and don't carry text-only color. */
.portfolio-page .pt-pie-tt-er-val {
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  text-align: right;
}
.portfolio-page .pt-pie-tt-er-val.pt-tone-neg { color: #ef4444; }
.portfolio-page .pt-pie-tt-er-val.pt-tone-amber { color: #F59E0B; }
.portfolio-page .pt-pie-tt-er-val.pt-tone-neutral { color: var(--text-secondary); }
/* TAN-684 — placeholder when a holding has no upcoming earnings. The row
   still renders (constant panel height, no hover layout shift); the text is
   dimmed so it reads as an intentional empty state, not missing data. */
.portfolio-page .pt-pie-tt-er-val.pt-pie-tt-er-none {
  color: var(--text-secondary);
  opacity: 0.5;
  font-style: italic;
}

.portfolio-page .pt-pie-tt-ai {
  margin-top: 8px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-size: 11px;
  color: var(--text-secondary);
}
.portfolio-page .pt-pie-tt-regime {
  margin-top: 4px;
  color: var(--text-primary);
  font-style: italic;
  line-height: 1.4;
}

/* TAN-684: pie layout is a vertical stack (donut → detail card → legend foot).
   The detail panel is a static sibling below the donut; the card inside it
   sits in normal flow (un-absolute'd) and spans the full row width. */
.portfolio-page .pt-pie-grid {
  /* TAN-684: vertical stack — donut on top (full card width), detail card
     full-width below. Was a 2-col grid (donut left / panel right) that left a
     large empty area; the single-column stack lets the donut grow into the
     panel width and gives the detail card the full row. */
  display: flex;
  flex-direction: column;
  gap: 14px;
  align-items: stretch;
}
.portfolio-page .pt-pie-panel .pt-pie-tooltip {
  /* TAN-684: full-width detail card below the donut (was a fixed 252px tooltip
     anchored top-right of the side panel). */
  width: 100%;
  box-shadow: none;
}
/* TAN-732 Fix 1: ETF look-through block (mockE .hd-look). Purple-tinted panel
   surfacing constituent weights underneath an ETF holding. Rendered only when
   the producer supplies constituent data. */
.portfolio-page .pt-pie-tt-look {
  margin-top: 11px;
  padding: 9px 11px;
  background: rgba(139, 92, 246, 0.10);
  border: 1px solid rgba(139, 92, 246, 0.32);
  border-radius: 8px;
  font-size: 11px;
  line-height: 1.5;
  color: #cbb9f5;
}
.portfolio-page .pt-pie-tt-look-lbl {
  display: block;
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.1em;
  color: #c084fc;
  margin-bottom: 4px;
}
.portfolio-page .pt-pie-tt-look b {
  color: #e9e0ff;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-pie-summary {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 12px;
}
.portfolio-page .pt-pie-sum-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
}
.portfolio-page .pt-pie-sum-label {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 9.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-secondary);
}
.portfolio-page .pt-pie-sum-mv {
  font-family: 'JetBrains Mono', monospace;
  font-size: 16px;
  font-weight: 700;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-pie-sum-sub {
  margin-top: 2px;
  font-size: 11px;
  color: var(--text-secondary);
}
.portfolio-page .pt-pie-sum-top {
  margin-top: 10px;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
}
.portfolio-page .pt-pie-sum-toplbl {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 9px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--text-secondary);
  margin-bottom: 5px;
}
.portfolio-page .pt-pie-sum-row {
  display: grid;
  grid-template-columns: 1fr auto auto;
  gap: 8px;
  align-items: baseline;
  padding: 2px 0;
}
.portfolio-page .pt-pie-sum-tkr {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  color: var(--text-primary);
}
.portfolio-page .pt-pie-sum-wt {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-pie-sum-day {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  font-variant-numeric: tabular-nums;
  text-align: right;
  min-width: 56px;
}
@media (max-width: 768px) {
  .portfolio-page .pt-pie-grid {
    gap: 10px;
  }
}

/* % colour helpers (shared) */
.portfolio-page .pt-pct-pos { color: var(--emerald); }
.portfolio-page .pt-pct-neg { color: #EF4444; }

/* ── R/R card ───────────────────────────────────────────────────────── */
.portfolio-page .pt-rr-body {
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--text-primary);
}

/* ── Cluster risk card (TAN-684 PR 3/5 v14 chrome) ──────────────────
 *
 * v14 mockup spec (canonical /tmp/mockup-strips/pl-attribution.png):
 *   Amber-bordered card. Header row: `⚠ CLUSTER RISK DETECTED ·
 *   AI INFRA CONCENTRATION 42%` (left), `CORRELATION-BASED` eyebrow
 *   (right). Body: callout prose. Footer: `Correlation matrix · 60d
 *   rolling` (left), purple `◆ SUGGEST HEDGE` button + `Dismiss for
 *   week` link (right).
 *
 * Lives in the 1/3-width meso row slot (alongside R/R + Drift). Per
 * user direction "keep as is unless you think it needs more breathing
 * room", the v14 chrome is condensed for that width — the tokens scale
 * cleanly if/when the card is later promoted to full-width below P/L.
 *
 * Tone-driven border: amber when tone=amber (concentration risk on),
 * green when balanced, neutral default. The amber tone DOMINATES the
 * card chrome (border, eyebrow color) rather than living in a tiny pill
 * — the alert IS the card.
 */
.portfolio-page .pt-risk-card {
  /* Tone overrides applied via .pt-risk-tone-amber/green/neutral. */
  transition: border-color 160ms ease, box-shadow 160ms ease;
}
.portfolio-page .pt-risk-tone-amber {
  border-color: rgba(245, 158, 11, 0.55);
  box-shadow: 0 0 0 1px rgba(245, 158, 11, 0.18) inset, 0 0 14px rgba(245, 158, 11, 0.08);
}
.portfolio-page .pt-risk-tone-green {
  border-color: rgba(16, 185, 129, 0.45);
  box-shadow: 0 0 0 1px rgba(16, 185, 129, 0.14) inset;
}
/* .pt-risk-tone-neutral keeps the default --border colour. */
.portfolio-page .pt-risk-body {
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.portfolio-page .pt-risk-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
}
.portfolio-page .pt-risk-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #F59E0B;
  line-height: 1.35;
}
.portfolio-page .pt-risk-tone-green .pt-risk-title { color: var(--emerald); }
.portfolio-page .pt-risk-tone-neutral .pt-risk-title { color: var(--text-secondary); }
.portfolio-page .pt-risk-title-icon {
  margin-right: 6px;
  font-size: 12px;
}
.portfolio-page .pt-risk-eyebrow-right {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  color: var(--text-secondary);
  opacity: 0.85;
}
/* Body prose — the producer's ``callout`` string. Inline `<strong>` ok. */
.portfolio-page .pt-risk-text {
  font-size: 12.5px;
  color: var(--text-primary);
  line-height: 1.55;
  margin: 0;
}
/* TAN-723 #11: correlation matrix detail line — light slate on the card
   surface, denser than the callout so it reads as supporting data. */
.portfolio-page .pt-risk-corr {
  font-size: 11.5px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin: 0;
}
/* Footer row: correlation-meta + hedge CTA + dismiss link. */
.portfolio-page .pt-risk-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
  padding-top: 8px;
  border-top: 1px solid rgba(255, 255, 255, 0.04);
}
.portfolio-page .pt-risk-meta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--text-secondary);
  letter-spacing: 0.04em;
}
.portfolio-page .pt-risk-actions {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}
/* TAN-723 #11: the hedge CTA previously rendered purple text on a purple-
   tinted background, which read as low-contrast purple-on-purple. Switched
   to light slate text on a dark slate fill for legibility, keeping a subtle
   purple border so it still associates with the cluster-risk accent. */
.portfolio-page .pt-risk-hedge-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: 8px;
  border: 1px solid rgba(139, 92, 246, 0.45);
  background: #1e293b;
  color: #e2e8f0;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 140ms ease, border-color 140ms ease, transform 100ms ease;
}
.portfolio-page .pt-risk-hedge-btn:hover {
  background: #273449;
  border-color: rgba(139, 92, 246, 0.65);
}
.portfolio-page .pt-risk-hedge-btn:active {
  transform: translateY(1px);
}
.portfolio-page .pt-risk-hedge-btn[disabled] {
  cursor: not-allowed;
  opacity: 0.55;
}
.portfolio-page .pt-risk-hedge-icon { font-size: 10px; }
.portfolio-page .pt-risk-dismiss {
  font-size: 11px;
  color: var(--text-secondary);
  background: none;
  border: none;
  padding: 4px 2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.18);
  text-underline-offset: 3px;
}
.portfolio-page .pt-risk-dismiss:hover {
  color: var(--text-primary);
  text-decoration-color: rgba(255, 255, 255, 0.4);
}
/* Hidden-by-dismiss state — keeps card height stable via a small note. */
.portfolio-page .pt-risk-dismissed {
  font-size: 11.5px;
  color: var(--text-secondary);
  font-style: italic;
}
/* Legacy .pt-tone-* classes retained for safety (consumed by other surfaces). */
.portfolio-page .pt-tone-amber {
  color: #F59E0B;
  background: rgba(245, 158, 11, 0.10);
  border-color: rgba(245, 158, 11, 0.30);
}
.portfolio-page .pt-tone-green {
  color: var(--emerald);
  background: rgba(16, 185, 129, 0.10);
  border-color: rgba(16, 185, 129, 0.30);
}
.portfolio-page .pt-tone-neutral {
  color: var(--text-secondary);
  background: var(--surface-2);
  border-color: var(--border);
}

/* ── Drift chips ────────────────────────────────────────────────────── */
.portfolio-page .pt-drift-body {
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.portfolio-page .pt-drift-chip {
  display: flex;
  align-items: baseline;
  gap: 8px;
  padding: 6px 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 12px;
}
/* TAN-716: removed left-edge accent strokes per owner review — the
   over/under direction is already carried by the +/- sign on the delta
   value; the extra colored bar was reading as visual noise. */
.portfolio-page .pt-drift-over,
.portfolio-page .pt-drift-under { border-left: none; }
.portfolio-page .pt-drift-tkr {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 700;
  color: var(--text-primary);
}
.portfolio-page .pt-drift-delta {
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  color: var(--text-primary);
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-drift-note {
  color: var(--text-secondary);
  font-size: 11.5px;
  flex: 1 1 auto;
}

/* ── P/L Attribution waterfall (TAN-684 v14) ───────────────────────── */
/*
 * v14 chrome — horizontal strip of ticker blocks, sized by absolute $
 * contribution. Header row carries the purple ◆ eyebrow + as-of timestamp
 * on the left and a right-aligned DAY P/L total. Body renders a single
 * narrative line + sources + Regenerate button.
 *
 * Render layer is _renderPL() in js/portfolio.js. Producer envelope shape
 * is documented in infra/providers/sonar_portfolio.py:fetch_pl_attribution.
 */
.portfolio-page .pt-pl-body {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Empty / awaiting-cron state — mirrors Living Thesis empty card chrome. */
.portfolio-page .pt-pl-empty {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 6px 0;
}
.portfolio-page .pt-pl-empty-body {
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.5;
  max-width: 64ch;
}

/* Header — eyebrow LEFT, day total RIGHT. */
.portfolio-page .pt-pl-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
}
.portfolio-page .pt-pl-header .pt-eyebrow-purple {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
}
.portfolio-page .pt-pl-asof {
  color: var(--text-secondary);
  font-weight: 500;
  letter-spacing: 0.04em;
}
.portfolio-page .pt-pl-header .pt-eyebrow-dot {
  color: var(--text-faint);
}
.portfolio-page .pt-pl-total {
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
  font-variant-numeric: tabular-nums;
  font-size: 13px;
  letter-spacing: 0.01em;
  white-space: nowrap;
}
.portfolio-page .pt-pl-total-label {
  color: var(--text-faint);
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  margin-right: 6px;
}
.portfolio-page .pt-pl-total-val {
  font-weight: 600;
  font-size: 14px;
}
.portfolio-page .pt-pl-total-pct {
  font-weight: 500;
  opacity: 0.85;
  font-size: 12.5px;
}
.portfolio-page .pt-pl-total-val.pt-pl-pos { color: var(--emerald); }
.portfolio-page .pt-pl-total-val.pt-pl-neg { color: #EF4444; }

/* Waterfall — single horizontal strip, flex children with proportional
 * flex-basis set inline by _renderPL. Gap is 2px so the strip reads as a
 * connected ledger rather than a row of pills. */
.portfolio-page .pt-pl-waterfall {
  display: flex;
  align-items: stretch;
  gap: 2px;
  border-radius: 8px;
  /* visible so the per-block hover popover can escape the bar bounds */
  overflow: visible;
  min-height: 56px;
}

.portfolio-page .pt-pl-block {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  /* width driven by inline flex-grow (proportional to |day $|) */
  flex-basis: 0;
  flex-shrink: 1;
  padding: 8px 10px;
  min-width: 0;
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
  font-variant-numeric: tabular-nums;
  text-align: center;
  cursor: default;
  position: relative;
  transition: filter 140ms ease, transform 140ms ease;
}
.portfolio-page .pt-pl-block:first-child { border-top-left-radius: 8px; border-bottom-left-radius: 8px; }
.portfolio-page .pt-pl-block:last-child { border-top-right-radius: 8px; border-bottom-right-radius: 8px; }
.portfolio-page .pt-pl-block:hover,
.portfolio-page .pt-pl-block:focus-visible {
  filter: brightness(1.10);
  z-index: 3;
  outline: none;
}

/* Per-block hover/focus detail popover (Shares, Day move, Contribution,
 * optional vs 30d avg). Hidden by default, revealed on hover/focus. */
.portfolio-page .pt-pl-tip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  min-width: 200px;
  max-width: 260px;
  background: #0E1620;
  border: 1px solid var(--border, rgba(255,255,255,0.10));
  border-radius: 8px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.45);
  padding: 10px 12px;
  text-align: left;
  color: var(--text-primary);
  font-family: 'JetBrains Mono', ui-monospace, SFMono-Regular, monospace;
  opacity: 0;
  pointer-events: none;
  visibility: hidden;
  transition: opacity 120ms ease, transform 120ms ease;
  z-index: 4;
}
.portfolio-page .pt-pl-block:hover .pt-pl-tip,
.portfolio-page .pt-pl-block:focus-visible .pt-pl-tip {
  opacity: 1;
  visibility: visible;
  transform: translateX(-50%) translateY(0);
}
.portfolio-page .pt-pl-tip-head {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  margin-bottom: 6px;
  padding-bottom: 6px;
  border-bottom: 1px solid var(--border, rgba(255,255,255,0.08));
}
.portfolio-page .pt-pl-tip-row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 14px;
  font-size: 11.5px;
  line-height: 1.7;
}
.portfolio-page .pt-pl-tip-row > span { color: var(--text-secondary); }
.portfolio-page .pt-pl-tip-row > b { font-weight: 600; }
.portfolio-page .pt-pl-tip .pt-pl-pos { color: var(--emerald, #34D399); }
.portfolio-page .pt-pl-tip .pt-pl-neg { color: #F87171; }
.portfolio-page .pt-pl-tip-head .pt-pl-pos { color: var(--emerald, #34D399); }
.portfolio-page .pt-pl-tip-head .pt-pl-neg { color: #F87171; }
.portfolio-page .pt-pl-block-label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}
.portfolio-page .pt-pl-block-val {
  font-size: 11px;
  font-weight: 500;
  margin-top: 2px;
  opacity: 0.92;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* Positives — emerald fill. Three intensities tied to dollar magnitude
 * would be nicer but the v14 mockup uses a single emerald block for all
 * positives so keep it flat. */
.portfolio-page .pt-pl-block.pt-pl-pos {
  background: var(--emerald, #10B981);
  color: #0B141B;
}
.portfolio-page .pt-pl-block.pt-pl-pos .pt-pl-block-val {
  color: rgba(11, 20, 27, 0.85);
}

/* Negatives — red fill, mockup uses a saturated brick red. */
.portfolio-page .pt-pl-block.pt-pl-neg {
  background: #EF4444;
  color: #160A0A;
}
.portfolio-page .pt-pl-block.pt-pl-neg .pt-pl-block-val {
  color: rgba(22, 10, 10, 0.85);
}

/* Narrative lead-in. */
.portfolio-page .pt-pl-narrative {
  margin: 0;
  color: var(--text-primary);
  font-size: 13px;
  line-height: 1.55;
  max-width: 80ch;
}

@media (max-width: 720px) {
  .portfolio-page .pt-pl-waterfall {
    flex-wrap: wrap;
  }
  .portfolio-page .pt-pl-block {
    flex-grow: 1;
    flex-basis: 44%;
    min-height: 48px;
  }
  .portfolio-page .pt-pl-tip {
    left: 0;
    transform: translateY(4px);
  }
  .portfolio-page .pt-pl-block:hover .pt-pl-tip,
  .portfolio-page .pt-pl-block:focus-visible .pt-pl-tip {
    transform: translateY(0);
  }
}

/* ── Living thesis drawer ───────────────────────────────────────────── */
.portfolio-page .pt-thesis-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
}
.portfolio-page .pt-thesis-row {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 10px 12px;
}
.portfolio-page .pt-thesis-row[open] {
  border-color: rgba(139, 92, 246, 0.30);
}
.portfolio-page .pt-thesis-row summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: baseline;
  gap: 10px;
  font-size: 13px;
}
.portfolio-page .pt-thesis-row summary::-webkit-details-marker { display: none; }
.portfolio-page .pt-thesis-row summary::before {
  content: '▸';
  color: var(--text-secondary);
  font-size: 10px;
  transition: transform 120ms ease;
}
.portfolio-page .pt-thesis-row[open] summary::before { transform: rotate(90deg); }
.portfolio-page .pt-thesis-tkr {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 700;
  color: var(--text-primary);
  font-size: 13px;
}
.portfolio-page .pt-thesis-why {
  color: var(--text-secondary);
  font-size: 12px;
  flex: 1 1 auto;
}
.portfolio-page .pt-thesis-grid {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  font-size: 11.5px;
}
@media (max-width: 720px) {
  .portfolio-page .pt-thesis-grid { grid-template-columns: 1fr; }
}
.portfolio-page .pt-thesis-grid .pt-eyebrow {
  margin-bottom: 4px;
  font-size: 9.5px;
  letter-spacing: 0.12em;
}
.portfolio-page .pt-thesis-grid ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 3px;
}
.portfolio-page .pt-thesis-grid li {
  color: var(--text-primary);
  line-height: 1.4;
  padding-left: 10px;
  position: relative;
}
.portfolio-page .pt-thesis-grid li::before {
  content: '◆';
  position: absolute;
  left: 0;
  color: var(--purple);
  font-size: 8px;
  top: 4px;
}

/* ─── TAN-684 Living Thesis v14 parity chrome ──────────────────────────
   Extends the existing .pt-thesis-row scaffold (don't touch — the summary
   chevron + open/closed state machine still works). Adds the v14 header
   right-rail (live price), purple eyebrow strip, Why-You-Hold-It block,
   highlighted trigger box, and the sources/buttons footer.
   ──────────────────────────────────────────────────────────────────── */

/* Override the pre-existing summary style so the v14 two-column layout
   (TICKER+cluster left  /  price right) reads correctly. The chevron is
   preserved — still rendered via .pt-thesis-row::before. */
.portfolio-page .pt-thesis-summary {
  width: 100%;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding-left: 4px;
}
.portfolio-page .pt-thesis-summary-left {
  display: inline-flex;
  align-items: baseline;
  gap: 10px;
  min-width: 0;
}
.portfolio-page .pt-thesis-summary-right {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  flex: 0 0 auto;
}
.portfolio-page .pt-thesis-cluster {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.portfolio-page .pt-thesis-price {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13.5px;
  font-weight: 600;
  color: var(--text-primary);
}

/* TAN-716 — collapsed-row preview text. Sits between [TKR cluster] on
   the left and the price on the right, ellipsizes if too long. Keeps the
   row informative even when the user hasn't expanded it yet. */
.portfolio-page .pt-thesis-preview {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--text-secondary);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  padding: 0 12px;
}

/* Eyebrow variant — purple diamond marker matches v14 "◆ LIVING THESIS"
   inline-eyebrow pattern. Applied additively, the base .pt-eyebrow styles
   (mono / uppercase / letter-spaced) still hold. */
.portfolio-page .pt-eyebrow-purple {
  color: var(--purple);
}

/* Content body shows after the row is opened. */
.portfolio-page .pt-thesis-content {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  gap: 12px;
  font-size: 12.5px;
}
.portfolio-page .pt-thesis-meta {
  margin-bottom: 0;
  font-size: 9.5px;
}
.portfolio-page .pt-thesis-why-block .pt-eyebrow {
  font-size: 9.5px;
  margin-bottom: 4px;
  letter-spacing: 0.12em;
}
.portfolio-page .pt-thesis-why-text {
  color: var(--text-primary);
  font-size: 13px;
  line-height: 1.55;
  font-style: normal;
}

.portfolio-page .pt-thesis-grid {
  margin-top: 0;
  padding-top: 0;
  border-top: none;
}
.portfolio-page .pt-thesis-col {
  min-width: 0;
}
.portfolio-page .pt-thesis-empty-list {
  color: var(--text-secondary);
  font-size: 11.5px;
  font-style: italic;
}

/* Trigger highlight box — the mono table-like rows showing NEXT TRIM
   TRIGGER + NEXT ADD TRIGGER. Background is one step darker than
   .pt-thesis-row so it reads as a sub-card without a new border color. */
.portfolio-page .pt-thesis-trig-box {
  background: var(--bg-alt, #0D1526);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 10px 14px;
  display: flex;
  flex-direction: column;
  gap: 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
}
.portfolio-page .pt-thesis-trig-row {
  display: grid;
  grid-template-columns: 180px 1fr;
  align-items: baseline;
  gap: 12px;
}
.portfolio-page .pt-thesis-trig-label {
  color: var(--text-secondary);
  font-size: 10px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.portfolio-page .pt-thesis-trig-val {
  font-weight: 600;
  font-size: 12px;
}
.portfolio-page .pt-thesis-trig-trim { color: var(--danger, #EF4444); }
.portfolio-page .pt-thesis-trig-add  { color: var(--emerald); }
.portfolio-page .pt-thesis-trig-more {
  color: var(--text-secondary);
  font-weight: 500;
  font-size: 10.5px;
}

/* Footer — sources on the left, buttons on the right. Wraps on narrow
   viewports so the buttons sit below the source list instead of
   clipping. */
.portfolio-page .pt-thesis-foot {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding-top: 8px;
  border-top: 1px dashed var(--border);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  color: var(--text-secondary);
}
.portfolio-page .pt-thesis-sources {
  letter-spacing: 0.02em;
}
.portfolio-page .pt-thesis-foot-actions {
  display: inline-flex;
  gap: 8px;
  flex: 0 0 auto;
}
.portfolio-page .pt-thesis-btn {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 8px;
  cursor: pointer;
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.portfolio-page .pt-thesis-btn-ghost {
  background: transparent;
  border: 1px solid var(--border);
  color: var(--text-secondary);
}
.portfolio-page .pt-thesis-btn-ghost:hover {
  background: var(--surface-2);
  color: var(--text-primary);
  border-color: rgba(139, 92, 246, 0.30);
}
.portfolio-page .pt-thesis-btn-primary {
  background: rgba(139, 92, 246, 0.12);
  border: 1px solid rgba(139, 92, 246, 0.35);
  color: var(--purple);
}
.portfolio-page .pt-thesis-btn-primary:hover {
  background: rgba(139, 92, 246, 0.22);
  border-color: rgba(139, 92, 246, 0.55);
  color: #FFFFFF;
}

/* Empty state when the producer has not run yet. Stays inside the card
   so the layout doesn't collapse. */
.portfolio-page .pt-thesis-empty {
  padding: 18px 4px;
  text-align: left;
}
.portfolio-page .pt-thesis-empty .pt-eyebrow {
  margin-bottom: 8px;
}
.portfolio-page .pt-thesis-empty-body {
  color: var(--text-secondary);
  font-size: 12.5px;
  line-height: 1.55;
}

/* TAN-684 PR 4/5 — card-level Hide-for-today affordance. Subtle ghost
   link sitting under all per-ticker rows, right-aligned so it doesn't
   compete with the per-row Regenerate / View Full Thesis buttons. The
   un-hide button reused inside the collapsed state mirrors the inline
   text-link styling Cluster Risk uses for its Show-again button. */
.portfolio-page .pt-thesis-card-foot {
  display: flex;
  justify-content: flex-end;
  padding-top: 10px;
  margin-top: 4px;
  border-top: 1px dashed var(--border);
}
.portfolio-page .pt-thesis-hide-btn {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  letter-spacing: 0.06em;
  color: var(--text-secondary);
  background: none;
  border: none;
  padding: 4px 2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(255, 255, 255, 0.18);
  text-underline-offset: 3px;
}
.portfolio-page .pt-thesis-hide-btn:hover {
  color: var(--text-primary);
  text-decoration-color: rgba(255, 255, 255, 0.4);
}
.portfolio-page .pt-thesis-unhide {
  font-size: 11.5px;
  color: var(--purple);
  background: none;
  border: none;
  padding: 0 2px;
  cursor: pointer;
  text-decoration: underline;
  text-decoration-color: rgba(139, 92, 246, 0.35);
  text-underline-offset: 2px;
}
.portfolio-page .pt-thesis-unhide:hover {
  color: #FFFFFF;
  text-decoration-color: rgba(139, 92, 246, 0.65);
}

/* ─── TAN-730 (BUG 6): Conviction Thesis all-ticker grid ───────────────
   Replaces the single-active switcher with a 2-col grid of per-ticker .pt-ct
   cards (mockE.html .ct-grid / .ct). Each card: ticker + name + weight, a
   conviction-tier chip (from /rankings), a one-line WHY, and a 2x2 meta block
   (Tailwinds / Risks / Triggers / Action). Card-level header (eyebrow +
   freshness) and footer (NFA + actions) wrap the grid.
   ──────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-ct-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}
.portfolio-page .pt-ct-fresh {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  letter-spacing: 0.02em;
  color: var(--text-secondary);
}
.portfolio-page .pt-ct-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-top: 4px;
}
@media (max-width: 768px) {
  .portfolio-page .pt-ct-grid { grid-template-columns: 1fr; }
}
.portfolio-page .pt-ct {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 13px 14px;
  min-width: 0;
}
.portfolio-page .pt-ct-h {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  margin-bottom: 8px;
}
.portfolio-page .pt-ct-sym {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: 15px;
  color: var(--text-primary);
  letter-spacing: -0.01em;
  min-width: 0;
}
.portfolio-page .pt-ct-sym small {
  font-family: 'Inter', system-ui, sans-serif;
  font-weight: 500;
  font-size: 11px;
  color: var(--text-secondary);
  letter-spacing: 0;
}
.portfolio-page .pt-ct-tier {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 3px 8px;
  border-radius: 5px;
  text-transform: uppercase;
  white-space: nowrap;
  flex: none;
}
/* TAN-732 Fix 6: solid, readable tier chips matching the mock contrast. */
.portfolio-page .pt-ct-tier.tier-vh { background: #102217; color: #34D399; border: 1px solid #1f4536; }
.portfolio-page .pt-ct-tier.tier-h  { background: #1a2436; color: #60A5FA; border: 1px solid #1e3a5f; }
.portfolio-page .pt-ct-tier.tier-m  { background: #2a2118; color: #FBBF24; border: 1px solid #3a2f18; }
.portfolio-page .pt-ct-line {
  font-size: 12px;
  line-height: 1.55;
  color: var(--text-primary);
  font-weight: 500;
}
.portfolio-page .pt-ct-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px 16px;
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
/* TAN-684 (Screen 3): the quadrant labels read as crisp, deliberate section
   headers — bumped size/weight/tracking and prefixed with a saturated dot in
   the quadrant's own hue, so the color-coding registers at a glance instead of
   being carried only by a faint text tint. */
.portfolio-page .pt-ct-k {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 9px;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  font-weight: 800;
  margin-bottom: 4px;
}
.portfolio-page .pt-ct-k::before {
  content: '';
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}
.portfolio-page .pt-ct-vv {
  font-size: 11px;
  line-height: 1.45;
}
/* TAN-684 (Screen 3): high-contrast 2×2 quadrant palette. Labels carry the
   fully-saturated app hue; values are bright (near-primary) so the prose reads
   crisply on the dark card instead of as washed-out pastel.
     Tailwinds → green #34D399 · Risks → red #F87171
     Triggers  → blue  #3B82F6 · Action → gold #FBBF24 */
.portfolio-page .pt-ct-k.k-tail { color: #34D399; }
.portfolio-page .pt-ct-vv.v-tail { color: #e6f7ee; }
.portfolio-page .pt-ct-k.k-risk { color: #F87171; }
.portfolio-page .pt-ct-vv.v-risk { color: #fbe3e3; }
.portfolio-page .pt-ct-k.k-trig { color: #3B82F6; }
.portfolio-page .pt-ct-vv.v-trig { color: #e2edfd; }
.portfolio-page .pt-ct-k.k-act { color: #FBBF24; }
.portfolio-page .pt-ct-vv.v-act { color: #fbf0d6; }
.portfolio-page .pt-ct-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 16px;
  padding-top: 13px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  color: var(--text-secondary);
}
.portfolio-page .pt-ct-acts { display: flex; gap: 10px; flex: none; }

/* TAN-725: AI Portfolio Insights hero. Chip/dot color-coding only — no top
   accent rail (repo rule 20). State block uses an all-sides border. */
.portfolio-page .pt-ai-head { margin-bottom: 12px; }
/* TAN polish — freshness stamp top-right of the Portfolio Insights header.
   Same size/weight as the .pt-eyebrow section label but muted slate and
   mixed-case ("Updated 3h ago"). The .pt-rc-head flex (space-between) right-
   aligns it; nowrap keeps it on one line. */
.portfolio-page .pt-insights-timestamp {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  color: var(--text-muted, #8a99b0);
  white-space: nowrap;
}
.portfolio-page .pt-ai-empty {
  font-size: 12.5px;
  color: var(--text-secondary);
  line-height: 1.5;
}
/* TAN-730 / TODO TAN-726: intentional "coming soon" hero state. */
.portfolio-page .pt-ai-state-soon {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
}
.portfolio-page .pt-ai-soon-tag {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  padding: 2px 7px;
  border-radius: 4px;
  background: rgba(59,130,246,0.18);
  color: #93c5fd;
  flex: none;
}
.portfolio-page .pt-ai-actrow-skel { opacity: 0.5; }
.portfolio-page .pt-ai-skel-bar {
  height: 9px;
  border-radius: 5px;
  background: var(--surface-2);
  border: 1px solid var(--border);
}
.portfolio-page .pt-ai-skel-bar-wide { width: 62%; margin-bottom: 6px; }
.portfolio-page .pt-ai-skel-bar-narrow { width: 38%; }
.portfolio-page .pt-ai-state {
  background: rgba(59,130,246,0.08);
  border: 1px solid rgba(59,130,246,0.28);
  border-radius: 10px;
  padding: 13px 15px;
  font-size: 13.5px;
  line-height: 1.5;
  color: #cfe2f7;
  margin-bottom: 15px;
}
.portfolio-page .pt-ai-actrow {
  display: flex;
  align-items: center;
  gap: 15px;
  padding: 14px 4px;
  border-top: 1px solid var(--border);
}
.portfolio-page .pt-ai-actrow:first-of-type { border-top: none; }
.portfolio-page .pt-ai-rank {
  width: 22px;
  height: 22px;
  border-radius: 6px;
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 11px;
  font-weight: 700;
  color: var(--text-secondary);
  flex: none;
  font-family: 'JetBrains Mono', monospace;
}
.portfolio-page .pt-ai-actbody { flex: 1; min-width: 0; }
.portfolio-page .pt-ai-ttl {
  font-size: 13px;
  font-weight: 700;
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 3px;
  color: var(--text-primary);
}
.portfolio-page .pt-ai-desc {
  font-size: 11.5px;
  color: var(--text-secondary);
  line-height: 1.45;
}
.portfolio-page .pt-ai-tag {
  font-size: 8.5px;
  font-weight: 800;
  letter-spacing: 0.05em;
  padding: 2px 6px;
  border-radius: 4px;
  text-transform: uppercase;
  flex: none;
}
.portfolio-page .pt-ai-tag-trim  { background: #2a1a1a; color: #fca5a5; }
.portfolio-page .pt-ai-tag-hedge { background: #1a2436; color: #93c5fd; }
.portfolio-page .pt-ai-tag-add   { background: #13261c; color: #6ee7a8; }
.portfolio-page .pt-ai-tag-rebal { background: #2a2118; color: #fcd34d; }
.portfolio-page .pt-ai-right { text-align: right; flex: none; min-width: 118px; }
.portfolio-page .pt-ai-imp-l {
  font-size: 9px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: 600;
}
.portfolio-page .pt-ai-imp-v {
  font-size: 13px;
  font-weight: 700;
  margin-top: 2px;
  color: var(--text-primary);
  font-family: 'JetBrains Mono', monospace;
}
.portfolio-page .pt-ai-foot {
  font-size: 10px;
  color: var(--text-secondary);
  margin-top: 12px;
  padding-top: 11px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: 12px;
}
.portfolio-page .pt-ai-seeall { color: var(--blue); white-space: nowrap; }
@media (max-width: 640px) {
  .portfolio-page .pt-ai-actrow { flex-wrap: wrap; }
  .portfolio-page .pt-ai-right { min-width: 0; text-align: left; }
}

/* TAN-684: context-rich desk-note cards (diagnose-the-bet rewrite). Replaces
   the prescriptive action rows / tags / vs-target column. Numbered list:
   rank + bold headline + body, optional indented pressure-test, optional slim
   neutral metric chip. No top accent rail / colored borders (repo rules 16/20)
   — color lives only in the clickable ticker chips and the muted chip text. */
.portfolio-page .pt-ai-cardrow {
  display: flex;
  align-items: flex-start;
  gap: 13px;
  padding: 13px 4px;
  border-top: 1px solid var(--border);
}
.portfolio-page .pt-ai-cardrow:first-of-type { border-top: none; }
.portfolio-page .pt-ai-cardrow-skel { opacity: 0.5; }
.portfolio-page .pt-ai-cardbody { flex: 1; min-width: 0; }
.portfolio-page .pt-ai-headline {
  font-size: 13px;
  font-weight: 700;
  line-height: 1.4;
  color: var(--text-primary);
}
.portfolio-page .pt-ai-cardtext {
  font-size: 11.5px;
  color: var(--text-secondary);
  line-height: 1.5;
  margin-top: 4px;
}
.portfolio-page .pt-ai-ptest {
  font-size: 11px;
  font-style: italic;
  color: var(--text-secondary);
  line-height: 1.45;
  margin-top: 5px;
  opacity: 0.82;
}
.portfolio-page .pt-ai-ptest-arrow {
  font-style: normal;
  margin-right: 5px;
  opacity: 0.7;
}
.portfolio-page .pt-ai-chipwrap { flex: none; padding-top: 1px; }
.portfolio-page .pt-ai-chip {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.01em;
  padding: 3px 8px;
  border-radius: 5px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-secondary);
  white-space: nowrap;
  font-family: 'JetBrains Mono', monospace;
}
/* TAN-684: clickable ticker chips now match the app-wide ticker affordance
   (MI briefing .mi-narrative .tk / Street Intel .clickable-ticker): blue +
   underlined, grey underline that goes blue on hover. Previously gold/cyan/
   white by membership, which was inconsistent with the rest of the app. */
.portfolio-page .pt-ai-tk {
  cursor: pointer;
  color: var(--blue);
  background: rgba(59,130,246,0.08);
  font-weight: 600;
  border-radius: 3px;
  padding: 0 4px;
  white-space: nowrap;
  text-decoration: underline;
  text-decoration-color: rgba(148,163,184,0.45);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.15s ease, text-decoration-color 0.15s ease, background 0.15s ease;
}
.portfolio-page .pt-ai-tk:hover {
  background: rgba(59,130,246,0.14);
  text-decoration-color: rgba(59,130,246,0.85);
}
.portfolio-page .pt-ai-tk:focus-visible {
  outline: 1px solid var(--blue);
  outline-offset: 1px;
}
/* Membership no longer changes color — all clickable tickers read as blue
   links. Classes kept so the JS membership logic stays untouched. */
.portfolio-page .pt-ai-tk-held,
.portfolio-page .pt-ai-tk-watch,
.portfolio-page .pt-ai-tk-neutral { color: var(--blue); }

/* TAN-684 formatting pass: inline markdown emphasis + semantic number color.
   Reuses the SAME +/- palette the holdings P&L uses (--red / --emerald) so
   colored numbers read consistently with the rest of the tab. Tasteful, not a
   rainbow — only bolded text and explicitly-signed numbers carry color. */
.portfolio-page .pt-ai-b { color: var(--text-primary); font-weight: 700; }
.portfolio-page .pt-ai-i { font-style: italic; }
.portfolio-page .pt-ai-neg { color: var(--red, #EF4444); font-weight: 600; }
.portfolio-page .pt-ai-pos { color: var(--emerald, #10b981); font-weight: 600; }
/* Metric chips colored by the sign of their label (or producer-set kind). */
.portfolio-page .pt-ai-chip-neg {
  color: var(--red, #EF4444);
  border-color: rgba(239,68,68,0.35);
  background: rgba(239,68,68,0.08);
}
.portfolio-page .pt-ai-chip-pos {
  color: var(--emerald, #10b981);
  border-color: rgba(16,185,129,0.35);
  background: rgba(16,185,129,0.08);
}
.portfolio-page .pt-ai-chip-warn {
  color: var(--amber, #F59E0B);
  border-color: rgba(245,158,11,0.35);
  background: rgba(245,158,11,0.08);
}

/* TAN-730: Conviction Thesis footer NFA line + actions (mockE .ct-foot). */
.portfolio-page .pt-ct-nfa { min-width: 0; line-height: 1.4; }
.portfolio-page .pt-thesis-hide-btn {
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  font-weight: 600;
  color: var(--blue);
  cursor: pointer;
}
.portfolio-page .pt-thesis-hide-btn:hover { text-decoration: underline; }

/* TAN-682 shared faint-text token reused here for missing price em-dash. */
.portfolio-page .pt-text-faint { color: var(--text-secondary); opacity: 0.5; }

/* ─────────────────────────────────────────────────────────────────────────
   TAN-493 Phase 1 — Holdings Management Card (v14 layout)
   Replaces the TAN-421 v1 panel. Scoped under .portfolio-page.
   Uses only the existing design tokens (--surface, --surface-2, --border,
   --text-*, --blue, --purple, --emerald) — no new color literals.
   Shared utility classes (.pt-presets-select, .pt-btn*, .pt-input,
   .pt-muted) preserved below since other surfaces reuse them.
   ───────────────────────────────────────────────────────────────────────── */

.portfolio-page .pt-presets-select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  background-color: var(--surface);
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'><path fill='%23999' d='M0 0l5 6 5-6z'/></svg>");
  background-repeat: no-repeat;
  background-position: right 10px center;
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 28px 6px 10px;
  font-size: 13px;
  cursor: pointer;
  transition: border-color 0.15s ease;
}
.portfolio-page .pt-presets-select:hover {
  border-color: var(--text-secondary);
}
.portfolio-page .pt-presets-select:focus {
  outline: none;
  border-color: var(--blue);
}
.portfolio-page .pt-presets-select option {
  background-color: var(--surface);
  color: var(--text-primary);
}

.portfolio-page .pt-btn {
  border-radius: 8px;
  padding: 6px 12px;
  font-size: 12.5px;
  font-weight: 500;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--text-primary);
  cursor: pointer;
  transition: opacity 0.15s ease;
}
.portfolio-page .pt-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.portfolio-page .pt-btn-primary {
  background: var(--blue);
  border-color: var(--blue);
  color: #fff;
}
.portfolio-page .pt-btn-primary:hover:not(:disabled) {
  filter: brightness(1.1);
}
.portfolio-page .pt-btn-ghost {
  color: var(--text-secondary);
  font-size: 11.5px;
  padding: 4px 9px;
}
.portfolio-page .pt-btn-ghost:hover {
  color: var(--text-primary);
  border-color: var(--text-secondary);
}

.portfolio-page .pt-input {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  /* BUG 4: box-sizing keeps padding inside the grid cell, and min-width:0 lets
     the input shrink with its track instead of overflowing/clipping its
     neighbor. Without these the padded input pushes past its column. */
  box-sizing: border-box;
  min-width: 0;
  width: 100%;
}
.portfolio-page .pt-input::placeholder {
  color: var(--text-secondary);
  opacity: 0.7;
  /* Truncate gracefully rather than hard-clip mid-word. */
  text-overflow: ellipsis;
}
.portfolio-page .pt-input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
.portfolio-page .pt-input[type="number"]::-webkit-inner-spin-button,
.portfolio-page .pt-input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.portfolio-page .pt-input:focus {
  outline: none;
  border-color: var(--blue);
}

.portfolio-page .pt-muted {
  color: var(--text-secondary);
}


/* ─────────────────────────────────────────────────────────────────────────
   TAN-493 v14 Holdings Card
   Single full-width card replacing the v1 panel. Inline-editable rows,
   hover trash, mode pill (TARGET / ACTUAL), warning chip for missing
   target weights, toast notifications, and global .quote-stale styling.
   ───────────────────────────────────────────────────────────────────────── */

/* Card shell (holdings + the TAN-684 consolidated positions card) */
.portfolio-page .pt-holdings-card,
.portfolio-page .pt-positions-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 16px 18px;
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 12px;
}

/* Head: eyebrow + mode pill on one row */
.portfolio-page .pt-holdings-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}
.portfolio-page .pt-holdings-head .pt-eyebrow { margin-bottom: 0; }

/* Mode pill — TARGET (preset) vs ACTUAL (live MV) */
.portfolio-page .pt-mode-pill {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 3px 10px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.portfolio-page .pt-mode-pill.pt-mode-target {
  color: var(--purple);
  border-color: rgba(167, 139, 250, 0.35);
}
.portfolio-page .pt-mode-pill.pt-mode-actual {
  color: var(--emerald);
  border-color: rgba(52, 211, 153, 0.35);
}

/* Controls row: preset dropdown + apply button + ghost actions */
.portfolio-page .pt-holdings-controls {
  display: flex;
  gap: 8px;
  align-items: center;
  flex-wrap: wrap;
}

/* Body wrapper around the table.
   TAN-684 (mobile PWA h-scroll fix): the table is a fixed-track CSS grid wider
   than a phone viewport. The page viewport (.main) keeps overflow-x:hidden to
   prevent whole-page horizontal scroll, so the table needs its OWN horizontal
   scroll region — otherwise the rightmost columns (Market Value / Day % / …)
   are clipped with no way to reach them. overflow-x:auto + iOS momentum scroll
   make the table swipeable; the rows carry a min-width (below) so they overflow
   into this region instead of being squeezed/clipped. */
.portfolio-page .pt-holdings-body,
.portfolio-page .pt-watchlist-body,
.portfolio-page .pt-closed-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  max-width: 100%;
}

/* PWA / mobile h-scroll unblock: body.pwa-standalone .main and the mobile
   @media (max-width: 768px) breakpoint both set .main { overflow-x: hidden },
   which clips the pt-holdings/watchlist/closed-body scroll regions set up
   above. Override to visible so the inner overflow-x:auto containers can
   actually own the horizontal scroll. visible (not auto) is deliberate —
   setting auto on .main would create a competing scroll context that swallows
   the inner scroll. Scoped tightly to .portfolio-page so no other tab is
   affected. */
body.pwa-standalone .main:has(.portfolio-page) {
  overflow-x: visible;
}
@media (max-width: 768px) {
  .main:has(.portfolio-page) {
    overflow-x: visible;
  }
}

/* Table rows — TAN-624: 12 columns (SECTOR dropped, 30D sparkline added
   as col 2, CONVICTION added between Score and Next ER):
   Ticker | 30D | Price | Shares | AvgCost | Weight | MarketValue | UnrealizedP/L
   | Day% | Score | Conviction | NextER
   TAN-684 (Matt redesign): the per-row Close/Delete actions used to live in a
   dedicated 13th column, which clipped Next ER in portrait + landscape. They no
   longer consume layout width — the action cell is an absolute overlay anchored
   to the row's trailing edge, revealed on hover/focus in edit mode (see
   .pt-htbl-action below). Row is position:relative so the overlay anchors to it. */
.portfolio-page .pt-htbl-row {
  display: grid;
  grid-template-columns:
    minmax(110px, 1.2fr)  /* Ticker (+ cluster mini-pill) */
    78px                  /* 30D sparkline (TAN-624) */
    78px                  /* Price */
    78px                  /* Shares */
    88px                  /* Avg Cost */
    64px                  /* Weight (value only, bar removed post-TAN-624) */
    100px                 /* Market Value */
    100px                 /* Unrealized P/L */
    74px                  /* Day % */
    90px                  /* Near/Far (TAN-684 ITEM 6b-i: replaces Score + Conviction) */
    72px;                 /* Next ER */
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  font-size: 13px;
  color: var(--text-primary);
  position: relative;
  /* TAN-684 (mobile PWA h-scroll): keep the full-width grid intact so it
     overflows into the body's scroll region rather than being squeezed. */
  min-width: 940px;
}

/* Head row — uppercase eyebrow style */
.portfolio-page .pt-htbl-row.pt-htbl-head {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  padding-bottom: 7px;
}

/* Data rows — alternating subtle bottom border */
.portfolio-page .pt-htbl-row.pt-htbl-data {
  border-bottom: 1px solid var(--border);
  transition: background 0.12s ease;
}
.portfolio-page .pt-htbl-row.pt-htbl-data:last-of-type {
  border-bottom: none;
}
.portfolio-page .pt-htbl-row.pt-htbl-data:hover {
  background: rgba(255, 255, 255, 0.02);
}
/* TAN-895 follow-up (2026-07-02, v3): prior attempts used a white brighten
   then a black darken + blue accent bar — both looked off and the accent bar
   was unwanted. Matt: "remove the left accent color (hate that) and make the
   whole row dim into the same colour as the BG". So on edit-mode hover, blend
   the row INTO the page background (--bg) — the targeted holding recedes into
   the canvas behind the floating Close/Delete buttons. Solid bg, no overlay,
   no accent bar. View mode keeps the subtle 2% hover (no actions there). */
.portfolio-page .pt-editmode .pt-htbl-row.pt-htbl-data:not(.pt-htbl-cash):hover {
  background: var(--bg, #0B1120);
  box-shadow: none;
}

/* Cell variants */
.portfolio-page .pt-htbl-tkr {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.portfolio-page .pt-htbl-tkr-text {
  font-family: 'JetBrains Mono', monospace;
}

/* TAN-682: clickable ticker cell mirrors the .clickable-ticker hover
   treatment used on /rankings and /pulse rows so users discover the
   sidebar reuse. Focus ring uses the existing accent token so keyboard
   navigation gets the same hint. */
.portfolio-page .pt-htbl-tkr-clickable {
  cursor: pointer;
  transition: color 120ms ease, background 120ms ease;
}
.portfolio-page .pt-htbl-tkr-clickable:hover .pt-htbl-tkr-text {
  /* Match the canonical .clickable-ticker hover (Pulse/Rankings): app blue,
     not the purple --accent fallback that read as off-brand here. */
  color: var(--blue, #3B82F6);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.portfolio-page .pt-htbl-tkr-clickable:focus-visible {
  outline: 1px solid var(--blue, #3B82F6);
  outline-offset: 2px;
  border-radius: 2px;
}
.portfolio-page .pt-htbl-name {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  color: var(--text-secondary);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.portfolio-page .pt-htbl-cluster {
  text-transform: capitalize;
}
.portfolio-page .pt-htbl-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
/* TAN-684 (Matt redesign): per-row Close/Delete overlay. Previously a dedicated
   36px grid column whose Close… button overflowed and clipped Next ER (portrait
   + landscape). Now an absolute overlay anchored to the row's trailing edge —
   it is OUT of grid flow, so columns keep their natural widths and Next ER never
   clips. Hidden by default; revealed only in edit mode (.pt-editmode) on row
   :hover / :focus-within (keyboard + touch reach it via focus). A small gradient
   fade behind it keeps it legible over trailing cell content. */
.portfolio-page .pt-htbl-action {
  position: absolute;
  top: 0;
  right: 4px;
  bottom: 0;
  /* TAN-819 Option A: always flex (was display:none gated by .pt-editmode).
     Close is a frequent action — hiding it behind edit mode adds friction.
     The confirm modal already prevents accidental closes. Opacity/pointer-
     events still hide it until the row is hovered (view or edit mode). */
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
  padding-left: 28px;
  pointer-events: none;     /* re-enabled on row hover */
  opacity: 0;
  transition: opacity 0.12s ease;
  /* TAN-684 (2026-06-17): float the action ABOVE the row's cells so the Close
     button (and its hover title) never clips against / hides behind the Next ER
     column. The overlay is a sibling of the grid cells; a raised z-index lifts
     it out of their stacking flow onto the row's trailing edge. */
  z-index: 5;
  /* fade the row content out behind the actions so text doesn't show through */
  background: linear-gradient(
    to right,
    transparent 0,
    var(--surface, #111827) 28px
  );
}
/* TAN-895: reveal on row hover ONLY in edit mode (.pt-editmode on the holdings
   panel). In view mode, hovering a row shows ZERO action buttons (Close +
   Delete). TAN-819 had ungated this so Close leaked into view mode; TAN-876
   then added Delete into the same overlay — both are now gated again. */
.portfolio-page .pt-editmode .pt-htbl-row:hover .pt-htbl-action,
.portfolio-page .pt-editmode .pt-htbl-row:focus-within .pt-htbl-action {
  opacity: 1;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .portfolio-page .pt-htbl-action { transition: none; }
}

/* TAN-684 (Matt redesign): in-place edit mode. NOTHING editable shows in view
   mode — the editable-cell affordances and the per-row Remove/Close controls
   are revealed ONLY when the holdings panel carries .pt-editmode (set by
   _syncEditModeUi off _editMode). */

/* Inline-edit affordance — only interactive in edit mode. In view mode the
   cell reads as plain text (no cursor/hover hint, no click handler effect). */
.portfolio-page .pt-htbl-editable {
  border-radius: 4px;
  position: relative;
  cursor: default;
}
.portfolio-page .pt-editmode .pt-htbl-editable {
  cursor: text;
}
.portfolio-page .pt-editmode .pt-htbl-editable:hover {
  background: rgba(96, 165, 250, 0.06);
  outline: 1px dashed rgba(96, 165, 250, 0.3);
  outline-offset: -1px;
}
.portfolio-page .pt-htbl-editing {
  background: rgba(96, 165, 250, 0.08);
  outline: 1px solid var(--blue);
  outline-offset: -1px;
}
.portfolio-page .pt-htbl-edit-input {
  width: 100%;
  background: transparent;
  border: none;
  outline: none;
  color: var(--text-primary);
  text-align: right;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  padding: 0;
  /* Strip native UA number-input spinner arrows (2026-06-08): mirrors the
     .pt-input[type="number"] rules at lines 699-707 so the inline-edit
     shares/ACB inputs match the rest of the app's polished inputs. */
  -moz-appearance: textfield;
  appearance: textfield;
}
.portfolio-page .pt-htbl-edit-input::-webkit-inner-spin-button,
.portfolio-page .pt-htbl-edit-input::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
  display: none;
}

/* Per-row Remove (trash) — TAN-684: hidden in view mode, revealed only in
   edit mode (.pt-editmode). Uses inline SVG icon (no emojis, per repo hard
   rule docs/DATA-SOURCE-INVENTORY.md:157). */
.portfolio-page .pt-htbl-trash {
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #2a2d36);
  color: var(--text-secondary);
  cursor: pointer;
  line-height: 1;
  padding: 4px 6px;
  border-radius: 4px;
  display: inline-flex;     /* visibility handled by the .pt-htbl-action overlay */
  align-items: center;
  justify-content: center;
  transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.portfolio-page .pt-htbl-trash svg { display: block; }
.portfolio-page .pt-htbl-trash:hover {
  color: #EF4444;
  background: rgba(239, 68, 68, 0.08);
}

/* Per-row Close (partial/full) — TAN-684: hidden in view mode, revealed only
   in edit mode. Compact ghost button; wires into the canonical close path. */
.portfolio-page .pt-htbl-close-btn {
  display: inline-flex;     /* visibility handled by the .pt-htbl-action overlay */
  align-items: center;
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #2a2d36);
  color: var(--text-secondary);
  cursor: pointer;
  font-family: inherit;
  font-size: 10.5px;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 4px;
  white-space: nowrap;
  transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.portfolio-page .pt-htbl-close-btn:hover {
  color: var(--gold, #FBBF24);
  border-color: var(--gold, #FBBF24);
  background: rgba(251, 191, 36, 0.08);
}

/* TAN-830: Delete button — destructive red variant, shown for shares<=0
   preset placeholder rows only (has no position to Close). */
.portfolio-page .pt-htbl-delete-btn {
  display: inline-flex;
  align-items: center;
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #2a2d36);
  color: var(--text-secondary);
  cursor: pointer;
  font-family: inherit;
  font-size: 10.5px;
  line-height: 1;
  padding: 4px 8px;
  border-radius: 4px;
  white-space: nowrap;
  transition: color 0.12s ease, background 0.12s ease, border-color 0.12s ease;
}
.portfolio-page .pt-htbl-delete-btn:hover {
  color: #F87171;
  border-color: #F87171;
  background: rgba(248, 113, 113, 0.10);
}

/* TAN-876: Delete button alongside Close on real (non-placeholder) holding rows.
   Text variant of .pt-htbl-trash (the bare class still drives _confirmDelete
   wiring); danger treatment, sits to the right of the Close button. */
.portfolio-page .pt-htbl-trash-text {
  font-family: inherit;
  font-size: 10.5px;
  font-weight: 600;
  white-space: nowrap;
  padding: 4px 8px;
  margin-left: 4px;
  border: 1px solid rgba(239, 68, 68, 0.35);
  background: rgba(239, 68, 68, 0.08);
  color: #EF4444;
}
.portfolio-page .pt-htbl-trash-text:hover {
  background: rgba(239, 68, 68, 0.18);
  border-color: rgba(239, 68, 68, 0.6);
  color: #EF4444;
}

/* ─────────────────────────────────────────────────────────────────────────
   TAN-570 — Cash row + TOTAL row (v14 mockup parity).
   ───────────────────────────────────────────────────────────────────────── */

/* Cash row — subtle emerald tint, USD reserve sub-label */
.portfolio-page .pt-htbl-row.pt-htbl-data.pt-htbl-cash {
  background: rgba(16, 185, 129, 0.04);
}
.portfolio-page .pt-htbl-row.pt-htbl-data.pt-htbl-cash:hover {
  background: rgba(16, 185, 129, 0.08);
}
.portfolio-page .pt-htbl-row.pt-htbl-data.pt-htbl-cash .pt-htbl-tkr-text {
  color: var(--emerald, #10B981);
}
/* TAN-723 #8 — hatched marker in the cash row weight cell so the idle USD
   reserve reads visually distinct from invested positions. Diagonal stripe
   swatch sits left of the % value; no colored top border (handoff rule 20). */
.portfolio-page .pt-htbl-cash-hatch {
  display: inline-block;
  width: 14px;
  height: 10px;
  margin-right: 6px;
  border-radius: 2px;
  border: 1px solid var(--border);
  background-image: repeating-linear-gradient(
    45deg,
    var(--surface-2) 0,
    var(--surface-2) 2px,
    rgba(148, 163, 184, 0.35) 2px,
    rgba(148, 163, 184, 0.35) 4px
  );
  vertical-align: middle;
}

/* TOTAL row — heavy top border, accent color on numeric sums */
.portfolio-page .pt-htbl-row.pt-htbl-total {
  border-top: 1px solid var(--border);
  margin-top: 4px;
  padding-top: 11px;
  background: rgba(255, 255, 255, 0.015);
}
.portfolio-page .pt-htbl-row.pt-htbl-total:hover {
  background: rgba(255, 255, 255, 0.015); /* totals shouldn't react on hover */
}
.portfolio-page .pt-htbl-total-lbl {
  color: var(--text-primary);
  font-weight: 700;
  letter-spacing: 0.04em;
}
.portfolio-page .pt-htbl-row.pt-htbl-total .pt-htbl-num {
  font-weight: 600;
}

/* Faint text helper — used for n/a cells (Day %, Score, ER) on cash row */
.portfolio-page .pt-text-faint {
  color: var(--text-faint, rgba(241, 245, 249, 0.35));
}

/* ─────────────────────────────────────────────────────────────────────────
   Weight column.
   TAN-571 originally added a mini-bar (.pt-htbl-bar / -fill / -fill-cash)
   normalized to the largest holding. TAN-624 follow-up removed it — felt
   like unnecessary clutter alongside the % text; the radial pie above
   already carries the dominant-weight signal. Bar rules deleted (dead
   code). The cell now renders just the % value, aligned right.
   ───────────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-htbl-weight {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  white-space: nowrap;
}
.portfolio-page .pt-htbl-weight-val {
  font-variant-numeric: tabular-nums;
  min-width: 32px;
  text-align: right;
}

/* ─────────────────────────────────────────────────────────────────────────
   TAN-573 — Stacked P/L cell (v14 mockup parity).
   Amount on top (mono, 12.5px), percent below (mono, 10.5px).
   ───────────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-htbl-pl {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 1px;
  line-height: 1.15;
}
.portfolio-page .pt-htbl-pl-amt {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  font-size: 12.5px;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-htbl-pl-pct {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 500;
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  opacity: 0.9;
}

/* Warning chip — appears next to sector for NULL target_weight rows */
.portfolio-page .pt-holdings-warn-chip {
  display: inline-flex;
  align-items: center;
  background: rgba(245, 158, 11, 0.12);
  color: #F59E0B;
  border: 1px solid rgba(245, 158, 11, 0.35);
  border-radius: 999px;
  padding: 1px 7px;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  font-family: 'JetBrains Mono', monospace;
  white-space: nowrap;
}

/* Empty state */
.portfolio-page .pt-holdings-empty {
  padding: 28px 12px;
  text-align: center;
  border: 1px dashed var(--border);
  border-radius: 10px;
}
.portfolio-page .pt-holdings-empty-title {
  font-size: 14px;
  color: var(--text-primary);
  margin-bottom: 4px;
}
.portfolio-page .pt-holdings-empty-sub {
  font-size: 12px;
  color: var(--text-secondary);
}

/* Add-row form */
.portfolio-page .pt-holdings-add {
  margin-top: 8px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
}
.portfolio-page .pt-holdings-add-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  margin-bottom: 8px;
}
.portfolio-page .pt-holdings-add-grid {
  display: grid;
  grid-template-columns: 1fr 110px 160px auto;
  gap: 8px;
  align-items: center;
}

/* TAN-684: slim, right-aligned add boxes. Both "Add a holding" and "Add to
   watchlist" reduce to a small ticker input + Add button tucked to the right
   so they read as minor controls, not full-width bars. The new holding row is
   created at 0 shares / $0 ACB; the user fills it in via the table's inline
   cell edit. Shared by both forms so they are visual siblings. */
.portfolio-page .pt-add-compact {
  display: flex;
  justify-content: flex-end;
}
.portfolio-page .pt-add-compact-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
  width: 100%;
  max-width: 260px;
}
@keyframes pt-row-flash {
  0%   { background-color: rgba(56, 178, 132, 0.22); }
  100% { background-color: transparent; }
}
.portfolio-page .pt-htbl-row.pt-row-flash {
  animation: pt-row-flash 1.6s ease-out;
}

/* TAN-684 (Matt redesign): one-shot shimmer on editable cells. Replaces the
   old cascade-down editor reveal. Fired by _shimmerCells() — on entering
   Modify (all editable cells) and on add (the new row's cells only) — then the
   class is removed so it never loops/replays. A gold sweep + soft outline
   signals "this cell is now writable". animation-iteration-count:1. */
@keyframes pt-cell-shimmer {
  0%   { background-color: rgba(251, 191, 36, 0); box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
  35%  { background-color: rgba(251, 191, 36, 0.16); box-shadow: 0 0 0 1px rgba(251, 191, 36, 0.45); }
  100% { background-color: rgba(251, 191, 36, 0); box-shadow: 0 0 0 0 rgba(251, 191, 36, 0); }
}
.portfolio-page .pt-htbl-editable.pt-cell-shimmer,
.portfolio-page .pt-ctbl-editable.pt-cell-shimmer {
  animation: pt-cell-shimmer 900ms ease-out 1;
  border-radius: 4px;
}
@media (prefers-reduced-motion: reduce) {
  .portfolio-page .pt-htbl-editable.pt-cell-shimmer,
  .portfolio-page .pt-ctbl-editable.pt-cell-shimmer { animation: none; }
}

/* Footnote */
.portfolio-page .pt-holdings-foot {
  font-size: 10.5px;
  color: var(--text-secondary);
  line-height: 1.4;
}

/* Toast notifications — pinned to the viewport bottom-right.
   Previously position:absolute inside the holdings card, which clipped the
   toast against an ancestor's overflow at the bottom-right edge. Fixed
   positioning escapes every clipping container so the toast always renders
   fully on-screen, and a high z-index keeps it above page chrome. */
.portfolio-page .pt-toast {
  position: fixed;
  bottom: 20px;
  right: 20px;
  z-index: 1000;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 8px 14px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--text-primary);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.3s ease, transform 0.3s ease;
  max-width: 340px;
}
.portfolio-page .pt-toast.pt-toast-success {
  border-color: rgba(52, 211, 153, 0.4);
  color: var(--emerald);
}
.portfolio-page .pt-toast.pt-toast-error {
  border-color: rgba(239, 68, 68, 0.4);
  color: #FCA5A5;
}
.portfolio-page .pt-toast.pt-toast-info {
  border-color: rgba(96, 165, 250, 0.4);
  color: var(--blue);
}
.portfolio-page .pt-toast.pt-toast-out {
  opacity: 0;
  transform: translateY(6px);
}
/* On narrow viewports the fixed toast must not run off the right edge —
   inset it on both sides and cap its width to the viewport. */
@media (max-width: 768px) {
  .portfolio-page .pt-toast {
    left: 16px;
    right: 16px;
    bottom: 16px;
    max-width: none;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
   Global stale-quote styling (NOT scoped to .portfolio-page so other
   surfaces — Pulse, Briefing, etc. — can reuse via the shared
   isQuoteStale() util once they're backported in a follow-up ticket).
   ───────────────────────────────────────────────────────────────────────── */
.quote-stale {
  opacity: 0.55;
  color: var(--text-muted, #94A3B8);
}
.stale-clock-icon {
  display: inline-block;
  width: 12px;
  height: 12px;
  vertical-align: -1px;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394A3B8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='9'/><polyline points='12 7 12 12 15 14'/></svg>");
  background-repeat: no-repeat;
  background-size: contain;
}

/* Responsive (≤720px). TAN-684 (mobile PWA h-scroll): previously this block
   HID 6 of the 11 columns (30D / AvgCost / Weight / Day% / Near/Far / NextER) so
   only Ticker/Price/Shares/MV/UPL remained — which is exactly the columns the
   user reported as unreachable. The table now lives in a horizontal scroll
   region (.pt-holdings-body overflow-x:auto), so instead of hiding columns we
   keep the FULL grid and let the user swipe to reveal every column. We only
   tighten the gap a touch for density on small screens. */
@media (max-width: 720px) {
  .portfolio-page .pt-htbl-row {
    gap: 8px;
  }
  .portfolio-page .pt-holdings-add-grid {
    grid-template-columns: 1fr 1fr;
  }
}

/* TAN-684 (desktop PORTRAIT fit — corrects #1852's breakpoint).
   The real trigger is NOT "viewport ≤1100px" (that was #1852's wrong guess).
   It is that the tables carry a `min-width: 940px` floor that exceeds the
   CONTENT COLUMN width whenever the sidebar is EXPANDED (240px, grid
   `var(--sidebar-w) 1fr`). In a portrait-shaped window the content column is
   narrow even when the overall viewport is WIDER than 1100px, so the 940px
   table overflowed and clipped NEXT ER. The user confirmed it still clipped on
   v2.0.169 because their portrait window is >1100px.
   Fix: key the compaction on `orientation: portrait` (no upper px cap) so it
   applies at ALL portrait widths ≥721px, and make every track flexible
   (`minmax(floor, fr)` instead of fixed px) with `min-width: 0`. The grid then
   FITS ITS CONTAINER: it shrinks to the readable floor (~560px) on a narrow
   content column AND grows to fill the space on a wide portrait window, so it
   never looks cramped. The ≤720px lower bound leaves #1836's PWA-mobile swipe
   band (which keeps the 940px grid + overflow-x:auto) untouched; landscape is
   never matched. */
@media (orientation: portrait) and (min-width: 721px) {
  .portfolio-page .pt-htbl-row {
    grid-template-columns:
      minmax(48px, 1.4fr)  /* Ticker */
      minmax(38px, 0.7fr)  /* 30D sparkline */
      minmax(48px, 0.9fr)  /* Price */
      minmax(44px, 0.8fr)  /* Shares */
      minmax(48px, 0.9fr)  /* Avg Cost */
      minmax(40px, 0.7fr)  /* Weight */
      minmax(56px, 1fr)    /* Market Value */
      minmax(56px, 1fr)    /* Unrealized P/L */
      minmax(44px, 0.8fr)  /* Day % */
      minmax(50px, 0.9fr)  /* Near/Far */
      minmax(46px, 0.8fr); /* Next ER */
    gap: 4px;
    padding: 8px 4px;
    font-size: 12px;
    min-width: 0;
  }
  .portfolio-page .pt-htbl-row.pt-htbl-head { font-size: 9.5px; letter-spacing: 0.04em; }
  .portfolio-page .pt-htbl-spark .sparkline-placeholder,
  .portfolio-page .pt-htbl-spark-svg { width: 100%; max-width: 64px; min-width: 38px; }

  /* Watchlist — same container-fit compaction (7 tracks incl. action). */
  .portfolio-page .pt-wtbl-row {
    grid-template-columns:
      minmax(70px, 1.6fr)  /* Ticker */
      minmax(40px, 0.8fr)  /* 30D sparkline */
      minmax(58px, 1fr)    /* Price */
      minmax(50px, 0.9fr)  /* Day % */
      minmax(58px, 1fr)    /* Near/Far */
      minmax(50px, 0.9fr)  /* Next ER */
      30px;                /* action */
    gap: 5px;
    padding: 8px 4px;
    font-size: 12px;
    min-width: 0;
  }
  .portfolio-page .pt-wtbl-row.pt-wtbl-head { font-size: 9.5px; letter-spacing: 0.04em; }

  /* Closed P/L — same container-fit compaction (drop the 940px floor). */
  .portfolio-page .pt-ctbl-row {
    grid-template-columns:
      minmax(60px, 1.2fr)  /* Ticker */
      minmax(62px, 1fr)    /* Shares Closed */
      minmax(58px, 1fr)    /* Avg Cost */
      minmax(58px, 1fr)    /* Exit Price */
      minmax(72px, 1.1fr)  /* Exit Date */
      minmax(60px, 1fr)    /* Realized P/L */
      minmax(72px, 1.1fr)  /* Price Now */
      minmax(72px, 1.1fr)  /* SPY/QQQ */
      minmax(62px, 1fr)    /* Alpha */
      0px;                 /* Action */
    gap: 5px;
    padding: 8px 4px;
    font-size: 12px;
    min-width: 0;
  }
  .portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-row {
    grid-template-columns:
      minmax(60px, 1.2fr) minmax(62px, 1fr) minmax(58px, 1fr) minmax(58px, 1fr) minmax(72px, 1.1fr) minmax(60px, 1fr) minmax(72px, 1.1fr) minmax(72px, 1.1fr) minmax(62px, 1fr) 28px;
  }
  .portfolio-page .pt-ctbl-row.pt-ctbl-head { font-size: 9.5px; letter-spacing: 0.04em; }
}

/* TAN-684 touch/mobile (≤767px): hover doesn't exist on touch devices, so the
   hover-reveal would strand the Close/Delete actions. In edit mode on small
   screens, show them persistently (anchored to the row's trailing edge) so a
   tap reaches them. Slightly larger hit targets for fingers. */
@media (max-width: 767px) {
  .portfolio-page .pt-editmode .pt-htbl-action {
    opacity: 1;
    pointer-events: auto;
  }
  .portfolio-page .pt-editmode .pt-htbl-close-btn,
  .portfolio-page .pt-editmode .pt-htbl-delete-btn,
  .portfolio-page .pt-editmode .pt-htbl-trash {
    padding-top: 6px;
    padding-bottom: 6px;
  }
}

/* Coarse-pointer fallback: any touch/no-hover device (e.g. tablets >767px)
   also can't hover, so reveal the actions persistently in edit mode there too. */
@media (hover: none) {
  .portfolio-page .pt-editmode .pt-htbl-action {
    opacity: 1;
    pointer-events: auto;
  }
}

/* ─────────────────────────────────────────────────────────────────────────
 * Mockup-parity Hero KPI strip — 5 tiles above the holdings card.
 * Tones (pos/neg/neutral) map to text color on the .pt-kpi-val.
 * ───────────────────────────────────────────────────────────────────────── */

.portfolio-page .pt-kpi-strip {
  grid-template-columns: repeat(5, minmax(0, 1fr));
  gap: 12px;
}

.portfolio-page .pt-kpi-tile {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 12px 14px 14px;
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-height: 78px;
  position: relative;
  overflow: hidden;
}

/* TAN-568: No left-edge accent stripes on KPI tiles (repo-wide rule, PR #820/#934).
   Tone is communicated via .pt-kpi-val text color only. */

.portfolio-page .pt-kpi-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-secondary);
}

.portfolio-page .pt-kpi-val {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  color: var(--text-primary);
  line-height: 1.15;
}

.portfolio-page .pt-kpi-tile.pt-tone-pos .pt-kpi-val { color: var(--emerald, #10b981); }
.portfolio-page .pt-kpi-tile.pt-tone-neg .pt-kpi-val { color: var(--red, #ef4444); }

.portfolio-page .pt-kpi-sub {
  font-size: 11.5px;
  font-weight: 500;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
}

.portfolio-page .pt-kpi-tile.pt-tone-pos .pt-kpi-sub { color: var(--emerald, #10b981); opacity: 0.85; }
.portfolio-page .pt-kpi-tile.pt-tone-neg .pt-kpi-sub { color: var(--red, #ef4444); opacity: 0.85; }

@media (max-width: 1080px) {
  .portfolio-page .pt-kpi-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 640px) {
  .portfolio-page .pt-kpi-strip {
    grid-template-columns: 1fr;
  }
}

/* âââââââââââââââââââââââââââââââââââââ
 * R/R Alignment â TAN-684 Concept B (drag killed, TAN-781 for the what-if).
 * Display-only: status badge + score on a row with a TARGET chip, a thin
 * neutral track carrying a SINGLE non-draggable position marker, DEFENSIVE/
 * AGGRESSIVE end labels, one condensed commentary line. No rainbow, no knob.
 * âââââââââââââââââââââââââââââââââââââ */

.portfolio-page .pt-rrbar-card {
  padding: 14px 18px 16px;
}

.portfolio-page .pt-rrbar-body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  /* Concept B renders at the panel's natural ~half width â do NOT force full
     screen width (leftover space is fine; full-width polish = TAN-780). */
  max-width: 520px;
}

/* Top row: status badge + score on the left, TARGET chip on the right. */
.portfolio-page .pt-rrbar-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.portfolio-page .pt-rrbar-statusgrp {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.portfolio-page .pt-rrbar-badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 10px;
  border-radius: 999px;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.01em;
  background: var(--surface-2, #1A2332);
  border: 1px solid var(--border, #1E293B);
  color: var(--text-secondary, #94A3B8);
}
.portfolio-page .pt-rrbar-badge-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--text-faint, #64748B);
}
.portfolio-page .pt-rrbar-badge.pt-tone-pos { color: #10b981; }
.portfolio-page .pt-rrbar-badge.pt-tone-pos .pt-rrbar-badge-dot { background: #10b981; }
.portfolio-page .pt-rrbar-badge.pt-tone-neg { color: #ef4444; }
.portfolio-page .pt-rrbar-badge.pt-tone-neg .pt-rrbar-badge-dot { background: #ef4444; }
.portfolio-page .pt-rrbar-scorelbl {
  font-size: 12px;
  font-weight: 500;
  color: var(--text-secondary, #94A3B8);
  white-space: nowrap;
}
.portfolio-page .pt-rrbar-scorelbl b {
  font-family: 'JetBrains Mono', monospace;
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-rrbar-scorelbl b.pt-tone-pos { color: #10b981; }
.portfolio-page .pt-rrbar-scorelbl b.pt-tone-neg { color: #ef4444; }
.portfolio-page .pt-rrbar-scorelbl b.pt-tone-neutral { color: var(--text-primary, #F1F5F9); }
/* TARGET chip â matches the presets-drawer mini chip styling. */
.portfolio-page .pt-rrbar-targetchip {
  flex: 0 0 auto;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint, #64748B);
  background: var(--surface-2, #1A2332);
  border: 1px solid var(--border, #1E293B);
  border-radius: 6px;
  padding: 5px 10px;
}
.portfolio-page .pt-rrbar-targetchip b {
  color: var(--text-primary, #F1F5F9);
  font-weight: 700;
}

/* Thin neutral track + single display-only position marker (NOT draggable). */
.portfolio-page .pt-rrbar-track {
  position: relative;
  height: 6px;
  border-radius: 4px;
  background: #222b3b;
  margin-top: 2px;
}
.portfolio-page .pt-rrbar-marker {
  position: absolute;
  top: -4px;
  bottom: -4px;
  width: 4px;
  background: var(--text-primary, #fff);
  border-radius: 4px;
  transform: translateX(-50%);
  box-shadow: 0 0 0 2px rgba(0,0,0,0.55), 0 2px 6px rgba(0,0,0,0.4);
  pointer-events: none;
}
.portfolio-page .pt-rrbar-marker.pt-tone-pos { background: #10b981; }
.portfolio-page .pt-rrbar-marker.pt-tone-neg { background: #ef4444; }

/* DEFENSIVE / AGGRESSIVE endpoint labels under the track. */
.portfolio-page .pt-rrbar-ends {
  display: flex;
  justify-content: space-between;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-tertiary, rgba(160,174,192,0.6));
  opacity: 0.7;
  padding: 0 2px;
  margin-top: 6px;
}

/* ONE condensed commentary line (diagnose, not prescribe). */
.portfolio-page .pt-rrbar-commentary {
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px dashed var(--border);
}
.portfolio-page .pt-rrbar-note {
  font-size: 12px;
  line-height: 1.5;
  color: var(--text-secondary);
}
.portfolio-page .pt-rrbar-note-primary {
  color: var(--text-primary);
  font-weight: 500;
}
.portfolio-page .pt-rrbar-note-primary.pt-tone-pos { color: #10b981; }
.portfolio-page .pt-rrbar-note-primary.pt-tone-neg { color: #ef4444; }

/* ─────────────────────────────────────────────────────────────────────────
 * Mockup-parity Score + Next ER chips (holdings table cells)
 * ───────────────────────────────────────────────────────────────────────── */

.portfolio-page .pt-score-chip,
.portfolio-page .pt-er-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 42px;
  padding: 2px 7px;
  border-radius: 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  border: 1px solid transparent;
  line-height: 1.4;
}

.portfolio-page .pt-score-chip.pt-tone-pos {
  color: var(--emerald, #10b981);
  background: rgba(16, 185, 129, 0.12);
  border-color: rgba(16, 185, 129, 0.35);
}
.portfolio-page .pt-score-chip.pt-tone-neutral {
  color: var(--text-primary);
  background: rgba(148, 163, 184, 0.12);
  border-color: rgba(148, 163, 184, 0.35);
}
.portfolio-page .pt-score-chip.pt-tone-neg {
  color: var(--red, #ef4444);
  background: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.35);
}

/* Confluence score tiers — all purple, 3 bands (0-100 normalised scale) */
.conf-tier-high {
  color: #c084fc;                        /* light purple */
  background: rgba(192, 132, 252, 0.12);
  border: 1px solid rgba(192, 132, 252, 0.3);
}
.conf-tier-mid {
  color: #a855f7;                        /* mid purple */
  background: rgba(168, 85, 247, 0.10);
  border: 1px solid rgba(168, 85, 247, 0.25);
}
.conf-tier-low {
  color: #7c3aed;                        /* deep purple */
  background: rgba(124, 58, 237, 0.08);
  border: 1px solid rgba(124, 58, 237, 0.20);
}
/* Scoped chip overrides — the base .pt-score-chip sets a transparent 1px
 * border at higher specificity, so re-assert the tier border-color here. */
.portfolio-page .pt-score-chip.conf-tier-high {
  color: #c084fc; background: rgba(192, 132, 252, 0.12); border-color: rgba(192, 132, 252, 0.3);
}
.portfolio-page .pt-score-chip.conf-tier-mid {
  color: #a855f7; background: rgba(168, 85, 247, 0.10); border-color: rgba(168, 85, 247, 0.25);
}
.portfolio-page .pt-score-chip.conf-tier-low {
  color: #7c3aed; background: rgba(124, 58, 237, 0.08); border-color: rgba(124, 58, 237, 0.20);
}

.portfolio-page .pt-er-chip.pt-tone-neg {
  color: var(--red, #ef4444);
  background: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.35);
}
.portfolio-page .pt-er-chip.pt-tone-amber {
  color: var(--amber, #f59e0b);
  background: rgba(245, 158, 11, 0.12);
  border-color: rgba(245, 158, 11, 0.35);
}
.portfolio-page .pt-er-chip.pt-tone-neutral {
  color: var(--text-primary);
  background: rgba(148, 163, 184, 0.10);
  border-color: rgba(148, 163, 184, 0.30);
}
.portfolio-page .pt-er-chip.pt-tone-muted {
  color: var(--text-secondary);
  background: transparent;
  border-color: var(--border);
  opacity: 0.7;
}

/* TAN-684 ITEM 6b-i: Near/Far cell — two tone-colored rankings scores
   (near-term / far-term) shown as "76.0 / 79.0", matching the /rankings page
   format. Plain colored text (no chip) so both values fit the compact column.
   Tone colors mirror the score-chip palette. */
.portfolio-page .pt-nf-cell {
  display: inline-flex;
  align-items: baseline;
  gap: 3px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-nf-slash { color: var(--text-secondary); opacity: 0.5; font-weight: 400; }
.portfolio-page .pt-nf-near.pt-tone-pos,
.portfolio-page .pt-nf-far.pt-tone-pos { color: var(--emerald, #10b981); }
.portfolio-page .pt-nf-near.pt-tone-neutral,
.portfolio-page .pt-nf-far.pt-tone-neutral { color: var(--text-primary); }
.portfolio-page .pt-nf-near.pt-tone-neg,
.portfolio-page .pt-nf-far.pt-tone-neg { color: var(--red, #ef4444); }

/* ============================================================
   TAN-567 — Presets first-view (v12 Scene 1)
   Welcome hero + 4 preset cards shown when user has no real
   positions yet. Hides every downstream section so the page is
   focused on the pick-a-profile choice. Tokens lifted verbatim
   from v12 mockup; all scoped under .portfolio-page.
   ============================================================ */

/* When first-view is active, hide every other section on the page. */
.portfolio-page.pt-firstview-active .pt-kpi-strip,
.portfolio-page.pt-firstview-active .pt-rrbar-card,
.portfolio-page.pt-firstview-active .pt-row-top,
.portfolio-page.pt-firstview-active .pt-row-meso,
.portfolio-page.pt-firstview-active .pt-pl-card,
.portfolio-page.pt-firstview-active .pt-thesis-card,
/* TAN-812: hide the whole AI zone in the no-holdings first-view. Its hero row
   (.pt-row-hero) is :first-of-type within #pt-ai-zone, so the generic
   ".pt-row:not(:first-of-type)" rule below never caught it — leaving the
   perpetual "Loading…" insights panel and "Loading pie…" radial panel on
   screen for an empty book. Hiding #pt-ai-zone removes both; it re-shows
   untouched once holdings exist (the active class is dropped). */
.portfolio-page.pt-firstview-active .pt-ai-zone,
.portfolio-page.pt-firstview-active .pt-row:not(:first-of-type) {
  display: none !important;
}
/* TAN-684: the consolidated Positions card must survive the first-view collapse
   — a user may track names (Watchlist tab) or have closed everything (Closed
   P/L tab) before owning anything. Re-show it below the welcome hero with a top
   divider so it doesn't butt against it. */
.portfolio-page.pt-firstview-active .pt-row-positions {
  display: block !important;
  margin-top: 14px;
}

.portfolio-page .pt-firstview { display: block; }
.portfolio-page .pt-firstview[hidden] { display: none; }

/* TAN-588: trimmed banner padding (was 22 24 20) and dropped the ◆ icon. */
.portfolio-page .pt-fv-welcome {
  background: linear-gradient(180deg, rgba(59,130,246,0.06), rgba(59,130,246,0.02));
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 14px 22px 14px;
  margin-bottom: 14px;
  position: relative;
  overflow: hidden;
}
.portfolio-page .pt-fv-title {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 18px; font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  letter-spacing: -0.01em;
  margin-bottom: 4px;
}
.portfolio-page .pt-fv-sub {
  font-size: 13px;
  color: var(--text-muted, #8a99b0);
  max-width: 760px;
  line-height: 1.55;
}

.portfolio-page .pt-fv-section-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 12px;
  margin: 18px 0 12px;
}
.portfolio-page .pt-fv-section-title {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 14px; font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  letter-spacing: -0.005em;
}
.portfolio-page .pt-fv-section-sub {
  font-size: 11.5px;
  color: var(--text-muted, #8a99b0);
  margin-top: 2px;
}
.portfolio-page .pt-fv-live {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em;
  background: rgba(16,185,129,0.10);
  color: var(--emerald, #10b981);
  padding: 4px 8px; border-radius: 3px;
  border: 1px solid rgba(16,185,129,0.25);
  text-transform: uppercase;
  white-space: nowrap;
}

.portfolio-page .pt-fv-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}
@media (max-width: 1280px) {
  .portfolio-page .pt-fv-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 640px) {
  .portfolio-page .pt-fv-grid { grid-template-columns: 1fr; }
}

.portfolio-page .pt-fv-card {
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 8px;
  padding: 18px 16px 16px;
  display: flex;
  flex-direction: column;
  transition: border-color 180ms cubic-bezier(0.16, 1, 0.3, 1);
}
.portfolio-page .pt-fv-card:hover { border-color: rgba(255,255,255,0.10); }

/* TAN-812: "Add manually" card — fills the 4th first-view slot vacated by the
   parked Match Regime preset. Same .pt-fv-card chrome/height as the preset
   cards; content is vertically centered with the CTA pinned to the bottom
   (the shared .pt-fv-cta margin-top:auto handles that). */
.portfolio-page .pt-fv-card-add { border-style: dashed; }
.portfolio-page .pt-fv-card-add:hover { border-color: rgba(59,130,246,0.35); }
.portfolio-page .pt-fv-add-inner {
  flex: 1;
  display: flex; flex-direction: column;
  align-items: center; justify-content: center;
  text-align: center;
  gap: 8px;
  padding: 8px 4px 14px;
}
.portfolio-page .pt-fv-add-mark {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 50%;
  background: rgba(59,130,246,0.10);
  border: 1px solid rgba(59,130,246,0.30);
  color: var(--blue, #3b82f6);
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 24px; font-weight: 600; line-height: 1;
}
.portfolio-page .pt-fv-add-title {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 15px; font-weight: 600;
  color: var(--text-primary, #e2e8f0);
}
.portfolio-page .pt-fv-add-sub {
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 11.5px; line-height: 1.45;
  color: var(--text-muted, #94a3b8);
  max-width: 22ch;
}

.portfolio-page .pt-fv-head {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 4px;
}
.portfolio-page .pt-fv-name {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 16px; font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  letter-spacing: -0.01em;
}
.portfolio-page .pt-fv-rr {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; font-weight: 700; letter-spacing: 0.08em;
  padding: 2px 6px; border-radius: 3px;
  text-transform: uppercase;
}
.portfolio-page .pt-fv-rr-low { background: rgba(16,185,129,0.12); color: var(--emerald, #10b981); }
.portfolio-page .pt-fv-rr-mid { background: rgba(59,130,246,0.10);  color: var(--blue, #3b82f6); }
.portfolio-page .pt-fv-rr-hi  { background: rgba(249,115,22,0.12); color: var(--orange, #f97316); }
.portfolio-page .pt-fv-rr-dyn { background: rgba(139,92,246,0.12); color: var(--purple, #8b5cf6); }

.portfolio-page .pt-fv-target {
  font-size: 11.5px;
  color: var(--text-muted, #8a99b0);
  margin-bottom: 10px;
}
.portfolio-page .pt-fv-target b {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--text-primary, #f1f5f9);
}

.portfolio-page .pt-fv-tags {
  display: flex; flex-wrap: wrap; gap: 4px;
  margin-bottom: 12px;
}
.portfolio-page .pt-fv-tag {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9px; font-weight: 600; letter-spacing: 0.06em;
  padding: 2px 6px; border-radius: 3px;
  background: var(--surface-2, #1a2332);
  color: var(--text-faint, #64748b);
  border: 1px solid var(--border, #1e293b);
  text-transform: uppercase;
}

.portfolio-page .pt-fv-positions {
  background: var(--bg-alt, #0d1526);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  padding: 8px 10px;
  margin-bottom: 12px;
}
.portfolio-page .pt-fv-pos {
  display: flex; align-items: center; justify-content: space-between;
  padding: 4px 0;
  font-size: 11.5px;
  border-bottom: 1px solid rgba(30,41,59,0.5);
}
.portfolio-page .pt-fv-pos:last-child { border-bottom: none; }
.portfolio-page .pt-fv-pos-l { display: inline-flex; align-items: baseline; min-width: 0; }
.portfolio-page .pt-fv-tkr {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  font-size: 11.5px;
}
.portfolio-page .pt-fv-nm {
  color: var(--text-faint, #64748b);
  margin-left: 6px;
  font-size: 10.5px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 110px;
}
.portfolio-page .pt-fv-wt {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  color: var(--text-secondary, #94a3b8);
  font-size: 11.5px;
  margin-left: 8px;
}
.portfolio-page .pt-fv-pos-cash {
  background: rgba(16,185,129,0.05);
  margin: 4px -10px -8px;
  padding: 6px 10px;
  border-bottom: none;
  border-top: 1px dashed rgba(16,185,129,0.25);
  border-radius: 0 0 6px 6px;
}
.portfolio-page .pt-fv-pos-cash .pt-fv-tkr { color: var(--emerald, #10b981); }
.portfolio-page .pt-fv-pos-cash .pt-fv-wt { color: var(--emerald, #10b981); }

.portfolio-page .pt-fv-meta {
  display: grid; grid-template-columns: 1fr 1fr; gap: 8px;
  margin-bottom: 12px;
}
.portfolio-page .pt-fv-cell {
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  padding: 8px 10px;
}
.portfolio-page .pt-fv-lbl {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px; font-weight: 600; letter-spacing: 0.08em;
  color: var(--text-faint, #64748b);
  text-transform: uppercase;
}
.portfolio-page .pt-fv-val {
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; font-weight: 600;
  color: var(--text-primary, #f1f5f9);
  margin-top: 2px;
}

.portfolio-page .pt-fv-cash {
  margin-bottom: 12px;
  padding: 10px 12px;
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
}
.portfolio-page .pt-fv-cash-top {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 8px;
}
.portfolio-page .pt-fv-cash-lbl {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px; font-weight: 600; letter-spacing: 0.08em;
  color: var(--text-muted, #8a99b0);
  text-transform: uppercase;
}
.portfolio-page .pt-fv-cash-pct {
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px; font-weight: 700;
  color: var(--emerald, #10b981);
}
.portfolio-page .pt-fv-card-regime .pt-fv-cash-pct { color: var(--purple, #8b5cf6); }
.portfolio-page .pt-fv-cash-bar {
  height: 6px; border-radius: 3px;
  background: var(--bg-alt, #0d1526);
  border: 1px solid var(--border, #1e293b);
  overflow: hidden;
}
.portfolio-page .pt-fv-cash-fill {
  height: 100%;
  background: var(--emerald, #10b981);
  border-radius: 3px;
}
.portfolio-page .pt-fv-card-regime .pt-fv-cash-fill { background: var(--purple, #8b5cf6); }

.portfolio-page .pt-fv-cta {
  display: flex; align-items: center; justify-content: center;
  gap: 6px;
  width: 100%; padding: 10px 12px;
  border-radius: 6px;
  background: rgba(59,130,246,0.10);
  color: var(--blue, #3b82f6);
  border: 1px solid rgba(59,130,246,0.30);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px; font-weight: 600;
  cursor: pointer;
  transition: all 150ms cubic-bezier(0.16, 1, 0.3, 1);
  margin-top: auto;
}
.portfolio-page .pt-fv-cta:hover {
  background: rgba(59,130,246,0.16);
  box-shadow: 0 0 16px rgba(59,130,246,0.25);
}
.portfolio-page .pt-fv-card-cons .pt-fv-cta {
  background: rgba(16,185,129,0.10); color: var(--emerald, #10b981);
  border-color: rgba(16,185,129,0.30);
}
.portfolio-page .pt-fv-card-cons .pt-fv-cta:hover { box-shadow: 0 0 16px rgba(16,185,129,0.30); }
.portfolio-page .pt-fv-card-agg .pt-fv-cta {
  background: rgba(249,115,22,0.10); color: var(--orange, #f97316);
  border-color: rgba(249,115,22,0.30);
}
.portfolio-page .pt-fv-card-agg .pt-fv-cta:hover { box-shadow: 0 0 16px rgba(249,115,22,0.30); }
.portfolio-page .pt-fv-card-regime .pt-fv-cta {
  background: rgba(139,92,246,0.10); color: var(--purple, #8b5cf6);
  border-color: rgba(139,92,246,0.30);
}
.portfolio-page .pt-fv-card-regime .pt-fv-cta:hover { box-shadow: 0 0 16px rgba(139,92,246,0.30); }

.portfolio-page .pt-fv-warn {
  margin-top: 8px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  color: var(--amber, #f59e0b);
  text-align: center;
}

.portfolio-page .pt-fv-escape {
  margin-top: 18px;
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 8px;
  padding: 14px 18px;
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px;
}
.portfolio-page .pt-fv-escape-title {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 13px; font-weight: 600;
  color: var(--text-primary, #f1f5f9);
}
.portfolio-page .pt-fv-escape-sub {
  font-size: 11.5px; color: var(--text-muted, #8a99b0);
  margin-top: 2px;
}
.portfolio-page .pt-fv-escape-btn {
  background: var(--surface-2, #1a2332);
  color: var(--text-primary, #f1f5f9);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  padding: 9px 14px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px; font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: all 150ms cubic-bezier(0.16, 1, 0.3, 1);
}
.portfolio-page .pt-fv-escape-btn:hover {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.10);
}

@media (max-width: 640px) {
  .portfolio-page .pt-fv-escape {
    flex-direction: column;
    align-items: stretch;
  }
  .portfolio-page .pt-fv-escape-btn { width: 100%; }
}

/* ─────────────────────────────────────────────────────────────────────────
 * TAN-589: Populated-state preset accordion (Option B mockup)
 *
 * Sits between the R/R Alignment bar and the holdings card. Native <details>
 * elements give us ARIA-accordion semantics and keyboard nav for free. Color
 * tokens reused from .pt-fv-card-* variants (defined ~L1531+) so per-preset
 * tinting stays consistent between this strip and the first-view hero.
 * ───────────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-preset-accordion {
  margin-bottom: 14px;
}

/* Collapsible toggle header (active-mode only). Per turn-158 Option B spec:
 * single-line "Switch preset · Currently on <Active> ▾" that expands the
 * 4-card strip on click. Reuses surface/border/text tokens so it matches
 * .pt-pa-item and the rest of the dashboard chrome. */
.portfolio-page .pt-pa-toggle {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 14px;
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 10px;
  color: var(--text-primary, #e5e7eb);
  font-size: 13px;
  cursor: pointer;
  text-align: left;
  transition: background 120ms ease, border-color 120ms ease;
}
.portfolio-page .pt-pa-toggle:hover {
  background: rgba(96, 165, 250, 0.04);
  border-color: rgba(96, 165, 250, 0.35);
}
.portfolio-page .pt-pa-toggle:focus-visible {
  outline: 2px solid var(--blue, #60a5fa);
  outline-offset: 2px;
}
.portfolio-page .pt-pa-toggle-chev {
  color: var(--text-secondary, #94a3b8);
  font-size: 14px;
  transition: transform 160ms ease;
  display: inline-block;
  flex-shrink: 0;
}
.portfolio-page [data-pa-collapsed="0"] .pt-pa-toggle-chev {
  transform: rotate(180deg);
}

/* When expanded, hide the mini chips (they're redundant with the hero below)
 * and show a compact "Collapse presets" label instead. When collapsed, do the
 * opposite. This keeps a single preset surface on screen at any time. */
.portfolio-page .pt-pa-toggle-collapse-lbl {
  display: none;
  flex: 1 1 auto;
  font-size: 12px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--text-secondary, #94a3b8);
}
.portfolio-page [data-pa-collapsed="0"] .pt-pa-toggle-mini {
  display: none;
}
.portfolio-page [data-pa-collapsed="0"] .pt-pa-toggle-collapse-lbl {
  display: inline-block;
}
.portfolio-page [data-pa-collapsed="0"] .pt-pa-toggle {
  padding: 6px 14px;
}

/* 4-up mini preview row inside the collapsed shelf. Each chip mirrors the
 * .pt-pa-summary tone (name + R/R tag) but in a single horizontal line so the
 * shelf stays slim. Active chip gets the same purple ring as .pt-pa-item-active. */
.portfolio-page .pt-pa-toggle-mini {
  flex: 1 1 auto;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 8px;
  align-items: stretch;
  min-width: 0;
}
.portfolio-page .pt-pa-mini {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 6px;
  padding: 6px 10px;
  background: rgba(255,255,255,0.02);
  border: 1px solid var(--border, #1e293b);
  border-radius: 8px;
  min-width: 0;
  position: relative;
}
.portfolio-page .pt-pa-mini-name {
  font-size: 13px;
  font-weight: 600;
  color: var(--text-primary, #e5e7eb);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}
.portfolio-page .pt-pa-mini-rr {
  flex-shrink: 0;
  font-size: 10px;
  padding: 2px 6px;
}
.portfolio-page .pt-pa-mini-active {
  border-color: var(--purple, #8b5cf6);
  box-shadow: 0 0 0 1px var(--purple, #8b5cf6) inset, 0 0 14px rgba(139,92,246,0.12);
}
.portfolio-page .pt-pa-mini-dot {
  position: absolute;
  top: 4px;
  right: 4px;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--purple, #8b5cf6);
}
@media (max-width: 700px) {
  .portfolio-page .pt-pa-toggle-mini { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 420px) {
  .portfolio-page .pt-pa-toggle-mini { grid-template-columns: 1fr; }
}
.portfolio-page .pt-pa-strip-wrap {
  margin-top: 10px;
}

.portfolio-page .pt-pa-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}
@media (max-width: 900px) {
  .portfolio-page .pt-pa-strip { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
  .portfolio-page .pt-pa-strip { grid-template-columns: 1fr; }
}

/* Chip card (post-TAN-589 follow-up: always-visible body — the <details>
 * collapse mechanic was removed because users expected all 4 baskets to be
 * glanceable at all times. The element is now a static card, not a details
 * disclosure widget. Class names kept for continuity.) */
.portfolio-page .pt-pa-item {
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 10px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: border-color 150ms cubic-bezier(0.16, 1, 0.3, 1),
              box-shadow 150ms cubic-bezier(0.16, 1, 0.3, 1);
}
.portfolio-page .pt-pa-item:hover {
  border-color: rgba(255,255,255,0.10);
}
/* Active chip ring — color matches the preset variant so Balanced (blue/cyan)
 * doesn't look identical to Match Regime (purple). Per-variant overrides
 * follow; the generic purple is the fallback only. */
.portfolio-page .pt-pa-item.pt-pa-item-active {
  border-color: var(--purple, #8b5cf6);
  box-shadow: 0 0 0 1px var(--purple, #8b5cf6) inset, 0 0 18px rgba(139,92,246,0.15);
}
.portfolio-page .pt-pa-item.pt-fv-card-cons.pt-pa-item-active {
  border-color: var(--emerald, #10b981);
  box-shadow: 0 0 0 1px var(--emerald, #10b981) inset, 0 0 18px rgba(16,185,129,0.18);
}
.portfolio-page .pt-pa-item.pt-fv-card-bal.pt-pa-item-active {
  border-color: var(--blue, #3b82f6);
  box-shadow: 0 0 0 1px var(--blue, #3b82f6) inset, 0 0 18px rgba(59,130,246,0.20);
}
.portfolio-page .pt-pa-item.pt-fv-card-agg.pt-pa-item-active {
  border-color: var(--orange, #f97316);
  box-shadow: 0 0 0 1px var(--orange, #f97316) inset, 0 0 18px rgba(249,115,22,0.18);
}
.portfolio-page .pt-pa-item.pt-fv-card-regime.pt-pa-item-active {
  border-color: var(--purple, #8b5cf6);
  box-shadow: 0 0 0 1px var(--purple, #8b5cf6) inset, 0 0 18px rgba(139,92,246,0.18);
}

/* Mini-chip active ring — same per-variant treatment as the expanded card. */
.portfolio-page .pt-pa-mini.pt-fv-card-cons.pt-pa-mini-active {
  border-color: var(--emerald, #10b981);
  box-shadow: 0 0 0 1px var(--emerald, #10b981) inset, 0 0 14px rgba(16,185,129,0.14);
}
.portfolio-page .pt-pa-mini.pt-fv-card-bal.pt-pa-mini-active {
  border-color: var(--blue, #3b82f6);
  box-shadow: 0 0 0 1px var(--blue, #3b82f6) inset, 0 0 14px rgba(59,130,246,0.16);
}
.portfolio-page .pt-pa-mini.pt-fv-card-agg.pt-pa-mini-active {
  border-color: var(--orange, #f97316);
  box-shadow: 0 0 0 1px var(--orange, #f97316) inset, 0 0 14px rgba(249,115,22,0.14);
}
.portfolio-page .pt-pa-mini.pt-fv-card-regime.pt-pa-mini-active {
  border-color: var(--purple, #8b5cf6);
  box-shadow: 0 0 0 1px var(--purple, #8b5cf6) inset, 0 0 14px rgba(139,92,246,0.14);
}
/* Mini-chip active dot — color per variant. */
.portfolio-page .pt-pa-mini.pt-fv-card-cons   .pt-pa-mini-dot { background: var(--emerald, #10b981); }
.portfolio-page .pt-pa-mini.pt-fv-card-bal    .pt-pa-mini-dot { background: var(--blue, #3b82f6); }
.portfolio-page .pt-pa-mini.pt-fv-card-agg    .pt-pa-mini-dot { background: var(--orange, #f97316); }
.portfolio-page .pt-pa-mini.pt-fv-card-regime .pt-pa-mini-dot { background: var(--purple, #8b5cf6); }
/* Expanded-card active dot, same treatment. */
.portfolio-page .pt-pa-item.pt-fv-card-cons   .pt-pa-active-dot { background: var(--emerald, #10b981); }
.portfolio-page .pt-pa-item.pt-fv-card-bal    .pt-pa-active-dot { background: var(--blue, #3b82f6); }
.portfolio-page .pt-pa-item.pt-fv-card-agg    .pt-pa-active-dot { background: var(--orange, #f97316); }
.portfolio-page .pt-pa-item.pt-fv-card-regime .pt-pa-active-dot { background: var(--purple, #8b5cf6); }

/* Header row (ticker name + R/R tag + active dot) */
.portfolio-page .pt-pa-summary {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 12px;
  user-select: none;
}

.portfolio-page .pt-pa-name {
  font-family: 'DM Sans', system-ui, sans-serif;
  font-size: 13px; font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  letter-spacing: -0.01em;
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.portfolio-page .pt-pa-rr {
  flex: 0 0 auto;
}
.portfolio-page .pt-pa-active-dot {
  flex: 0 0 auto;
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--purple, #8b5cf6);
  box-shadow: 0 0 6px rgba(139,92,246,0.6);
}

/* Body (always rendered — no expand/collapse) */
.portfolio-page .pt-pa-body {
  padding: 0 12px 12px;
  display: flex;
  flex-direction: column;
  flex: 1 1 auto;
}

.portfolio-page .pt-pa-target {
  font-size: 11px;
  color: var(--text-muted, #8a99b0);
  margin: 10px 0 8px;
}
.portfolio-page .pt-pa-target b {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--text-primary, #f1f5f9);
}

.portfolio-page .pt-pa-positions {
  background: var(--bg-alt, #0d1526);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  padding: 6px 10px;
  margin-bottom: 10px;
}
.portfolio-page .pt-pa-pos {
  display: flex; align-items: center; justify-content: space-between;
  padding: 3px 0;
  font-size: 11px;
  border-bottom: 1px solid rgba(30,41,59,0.5);
}
.portfolio-page .pt-pa-pos:last-child { border-bottom: none; }
.portfolio-page .pt-pa-pos-l { display: inline-flex; align-items: baseline; min-width: 0; }
.portfolio-page .pt-pa-tkr {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 700;
  color: var(--text-primary, #f1f5f9);
  font-size: 11px;
}
.portfolio-page .pt-pa-nm {
  color: var(--text-faint, #64748b);
  margin-left: 6px;
  font-size: 10px;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 100px;
}
.portfolio-page .pt-pa-wt {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  color: var(--text-secondary, #94a3b8);
  font-size: 11px;
  margin-left: 8px;
}
.portfolio-page .pt-pa-pos-cash {
  background: rgba(16,185,129,0.05);
  margin: 3px -10px -6px;
  padding: 5px 10px;
  border-top: 1px dashed rgba(16,185,129,0.25);
  border-bottom: none;
  border-radius: 0 0 6px 6px;
}
.portfolio-page .pt-pa-pos-cash .pt-pa-tkr,
.portfolio-page .pt-pa-pos-cash .pt-pa-wt { color: var(--emerald, #10b981); }

/* CTA button — base. State-specific tint provided by .pt-fv-card-<variant>
 * cascading rules below (re-used from first-view CSS for visual consistency).
 * margin-top: auto pins the CTA to the bottom of the card so chips with
 * different basket sizes still bottom-align their CTAs across the strip. */
.portfolio-page .pt-pa-cta {
  margin-top: auto;
  display: flex; align-items: center; justify-content: center;
  width: 100%;
  padding: 8px 10px;
  border-radius: 6px;
  background: rgba(59,130,246,0.10);
  color: var(--blue, #3b82f6);
  border: 1px solid rgba(59,130,246,0.30);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12px; font-weight: 600;
  cursor: pointer;
  transition: all 150ms cubic-bezier(0.16, 1, 0.3, 1);
}
.portfolio-page .pt-pa-cta:hover:not(:disabled) {
  background: rgba(59,130,246,0.16);
  box-shadow: 0 0 16px rgba(59,130,246,0.25);
}
/* State C: ✓ Active — disabled, muted */
.portfolio-page .pt-pa-cta-active,
.portfolio-page .pt-pa-cta:disabled {
  background: rgba(139,92,246,0.08);
  color: var(--purple, #8b5cf6);
  border-color: rgba(139,92,246,0.25);
  cursor: default;
  opacity: 0.85;
  box-shadow: none;
}
.portfolio-page .pt-pa-cta:disabled:hover { box-shadow: none; }

/* Per-variant CTA tint — same palette as first-view cards */
.portfolio-page .pt-fv-card-cons   .pt-pa-cta:not(:disabled) {
  background: rgba(16,185,129,0.10); color: var(--emerald, #10b981);
  border-color: rgba(16,185,129,0.30);
}
.portfolio-page .pt-fv-card-cons   .pt-pa-cta:hover:not(:disabled) { box-shadow: 0 0 16px rgba(16,185,129,0.30); }
.portfolio-page .pt-fv-card-agg    .pt-pa-cta:not(:disabled) {
  background: rgba(249,115,22,0.10); color: var(--orange, #f97316);
  border-color: rgba(249,115,22,0.30);
}
.portfolio-page .pt-fv-card-agg    .pt-pa-cta:hover:not(:disabled) { box-shadow: 0 0 16px rgba(249,115,22,0.30); }
.portfolio-page .pt-fv-card-regime .pt-pa-cta:not(:disabled) {
  background: rgba(139,92,246,0.10); color: var(--purple, #8b5cf6);
  border-color: rgba(139,92,246,0.30);
}
.portfolio-page .pt-fv-card-regime .pt-pa-cta:hover:not(:disabled) { box-shadow: 0 0 16px rgba(139,92,246,0.30); }

/* ─────────────────────────────────────────────────────────────────────────
 * TAN-589 follow-up: Suggest Changes stub modal (will be replaced by TAN-591)
 *
 * Centered modal anchored to document.body — escapes the .portfolio-page
 * scope so we don't fight stacking context. Selectors all prefixed with
 * .pt-pa-modal so they don't collide with any other modal layer.
 * ───────────────────────────────────────────────────────────────────────── */
.pt-pa-modal-overlay {
  position: fixed; inset: 0;
  background: rgba(2, 6, 23, 0.72);
  backdrop-filter: blur(4px);
  display: flex; align-items: center; justify-content: center;
  z-index: 9999;
  animation: pt-pa-modal-fade 140ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes pt-pa-modal-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}
.pt-pa-modal {
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 14px;
  max-width: 520px;
  width: calc(100% - 32px);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(139,92,246,0.15);
  animation: pt-pa-modal-pop 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes pt-pa-modal-pop {
  from { opacity: 0; transform: translateY(8px) scale(0.98); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@media (prefers-reduced-motion: reduce) {
  .pt-pa-modal-overlay,
  .pt-pa-modal { animation: none; }
}
.pt-pa-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px;
  border-bottom: 1px solid var(--border, #1e293b);
}
.pt-pa-modal-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--purple, #8b5cf6);
}
.pt-pa-modal-x {
  background: transparent;
  border: none;
  color: var(--text-faint, #64748b);
  font-size: 22px;
  line-height: 1;
  padding: 0 4px;
  cursor: pointer;
  transition: color 120ms ease;
}
.pt-pa-modal-x:hover { color: var(--text-primary, #f1f5f9); }

.pt-pa-modal-body {
  padding: 18px 20px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--text-secondary, #94a3b8);
}
.pt-pa-modal-lead { margin: 0 0 14px; color: var(--text-primary, #f1f5f9); }
.pt-pa-modal-lead a {
  color: var(--purple, #8b5cf6);
  text-decoration: none;
  font-weight: 600;
}
.pt-pa-modal-lead a:hover { text-decoration: underline; }

.pt-pa-modal-list-h {
  margin: 0 0 6px;
  font-size: 11px;
  font-family: 'JetBrains Mono', monospace;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-faint, #64748b);
}
.pt-pa-modal-list {
  margin: 0;
  padding-left: 18px;
  display: flex; flex-direction: column; gap: 4px;
}
.pt-pa-modal-list li { font-size: 13px; }

.pt-pa-modal-foot {
  display: flex; justify-content: flex-end;
  gap: 8px;
  padding: 12px 18px 16px;
  border-top: 1px solid var(--border, #1e293b);
}
.pt-pa-modal-close {
  padding: 8px 16px;
  border-radius: 6px;
  background: var(--surface-2, #1a2332);
  color: var(--text-primary, #f1f5f9);
  border: 1px solid var(--border, #1e293b);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: all 120ms ease;
}
.pt-pa-modal-close:hover {
  background: rgba(255,255,255,0.04);
  border-color: rgba(255,255,255,0.10);
}

/* ─────────────────────────────────────────────────────────────────────────
 * TAN-623: preset state machine — active-state mini dropdown + diff modal
 *
 * When the user has live holdings (any row with shares>0), the big starter
 * accordion is hidden and replaced by this compact dropdown injected into
 * the YOUR HOLDINGS card head. Clicking Apply opens the diff modal which
 * reuses the .pt-pa-modal-overlay shell from the prior TAN-589 stub.
 * ───────────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-presets-mini {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-left: auto;
}
.portfolio-page .pt-presets-mini-lbl {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint, #64748b);
}
.portfolio-page .pt-presets-mini-select {
  background: var(--surface-2, #1a2332);
  color: var(--text-primary, #f1f5f9);
  border: 1px solid var(--border, #1e293b);
  border-radius: 6px;
  padding: 5px 10px;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px;
  font-weight: 500;
  cursor: pointer;
  transition: border-color 120ms ease, background 120ms ease;
  min-width: 220px;
}
.portfolio-page .pt-presets-mini-select:hover {
  border-color: rgba(139, 92, 246, 0.45);
}
.portfolio-page .pt-presets-mini-select:focus {
  outline: none;
  border-color: var(--purple, #8b5cf6);
  box-shadow: 0 0 0 2px rgba(139, 92, 246, 0.18);
}
.portfolio-page .pt-presets-mini-apply {
  padding: 6px 14px;
  border-radius: 6px;
  background: var(--purple, #8b5cf6);
  color: #fff;
  border: 1px solid rgba(167, 139, 250, 0.55);
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px;
  font-weight: 600;
  cursor: pointer;
  transition: opacity 120ms ease, transform 80ms ease, background 120ms ease;
}
.portfolio-page .pt-presets-mini-apply:hover:not(:disabled) {
  background: #a78bfa;
}
.portfolio-page .pt-presets-mini-apply:active:not(:disabled) {
  transform: translateY(1px);
}
.portfolio-page .pt-presets-mini-apply:disabled {
  background: var(--surface-2, #1a2332);
  color: var(--text-faint, #64748b);
  border-color: var(--border, #1e293b);
  cursor: not-allowed;
  opacity: 0.7;
}

/* Diff modal — wider variant of the existing .pt-pa-modal shell. */
.pt-pa-modal.pt-pa-modal--diff {
  max-width: 720px;
}

.pt-pa-modal-foot-note {
  margin: 14px 0 0;
  padding-top: 12px;
  border-top: 1px dashed var(--border, #1e293b);
  font-size: 11.5px;
  line-height: 1.5;
  color: var(--text-faint, #64748b);
}
.pt-pa-modal-foot-note a {
  color: var(--purple, #8b5cf6);
  text-decoration: none;
  font-weight: 600;
}
.pt-pa-modal-foot-note a:hover { text-decoration: underline; }

/* Diff table — structured per-op rendering inside the modal body. */
.pt-diff-table-wrap {
  margin-top: 4px;
  border: 1px solid var(--border, #1e293b);
  border-radius: 8px;
  overflow: hidden;
  max-height: 360px;
  overflow-y: auto;
}
.pt-diff-table {
  width: 100%;
  border-collapse: collapse;
  font-family: 'Inter', system-ui, sans-serif;
  font-size: 12.5px;
}
.pt-diff-table thead th {
  position: sticky;
  top: 0;
  background: var(--surface-2, #1a2332);
  color: var(--text-faint, #64748b);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  text-align: left;
  padding: 8px 12px;
  border-bottom: 1px solid var(--border, #1e293b);
}
.pt-diff-table .pt-diff-th-num,
.pt-diff-table .pt-diff-th-flag { text-align: right; }
.pt-diff-table .pt-diff-th-op   { width: 78px; }

.pt-diff-row td {
  padding: 8px 12px;
  border-bottom: 1px solid rgba(30, 41, 59, 0.55);
  color: var(--text-primary, #f1f5f9);
  vertical-align: middle;
}
.pt-diff-row:last-child td { border-bottom: none; }
.pt-diff-row:hover td { background: rgba(255,255,255,0.025); }

.pt-diff-ticker {
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.pt-diff-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
}
.pt-diff-flag-cell { text-align: right; }
.pt-diff-pos { color: var(--emerald, #34d399); }
.pt-diff-neg { color: var(--rose,    #f87171); }

/* Verb chip — color-coded per op kind. */
.pt-diff-verb {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.06em;
  border: 1px solid transparent;
}
.pt-diff-verb--add {
  color: var(--emerald, #34d399);
  background: rgba(52, 211, 153, 0.10);
  border-color: rgba(52, 211, 153, 0.30);
}
.pt-diff-verb--resize {
  color: var(--blue, #60a5fa);
  background: rgba(96, 165, 250, 0.10);
  border-color: rgba(96, 165, 250, 0.30);
}
.pt-diff-verb--trim {
  color: var(--amber, #fbbf24);
  background: rgba(251, 191, 36, 0.10);
  border-color: rgba(251, 191, 36, 0.30);
}
.pt-diff-verb--remove {
  color: var(--rose, #f87171);
  background: rgba(248, 113, 113, 0.10);
  border-color: rgba(248, 113, 113, 0.30);
}

/* Earnings auto-defer flag (⚠ ER) — chip + dimmed row treatment. */
.pt-diff-flag {
  display: inline-block;
  padding: 2px 6px;
  border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--amber, #fbbf24);
  background: rgba(251, 191, 36, 0.10);
  border: 1px solid rgba(251, 191, 36, 0.30);
  cursor: help;
}
.pt-diff-row--deferred td { opacity: 0.55; }
.pt-diff-row--deferred .pt-diff-flag { opacity: 1; }

@media (max-width: 720px) {
  .portfolio-page .pt-presets-mini {
    margin-left: 0;
    width: 100%;
  }
  .portfolio-page .pt-presets-mini-select { flex: 1; min-width: 0; }
  .pt-pa-modal.pt-pa-modal--diff { max-width: calc(100% - 32px); }
  .pt-diff-table thead .pt-diff-th-op { width: 60px; }
}

/* ─────────────────────────────────────────────────────────────────────────
 * TAN-624: holdings table column rework
 *
 *   • .pt-htbl-spark           — 30D sparkline cell (col 2). Hosts a
 *     .sparkline-placeholder which the shared app.js loader populates with
 *     an inline <svg>. Mini-bar version of the /rankings sparkline (smaller
 *     height to fit the row).
 *   • .pt-htbl-cluster-mini    — compact cluster pill that lives inside the
 *     Ticker cell now that SECTOR is gone. Keeps cluster context visible
 *     without claiming a full column.
 *   • .pt-conv-chip            — Conviction chip, color-coded to match the
 *     /rankings tab tier palette (getTier('conviction') in app.js).
 * ───────────────────────────────────────────────────────────────────────── */
.portfolio-page .pt-htbl-spark {
  display: flex;
  align-items: center;
  justify-content: flex-start;
  min-height: 22px;
}
.portfolio-page .pt-htbl-spark .sparkline-placeholder,
.portfolio-page .pt-htbl-spark-svg {
  display: inline-block;
  width: 64px;
  height: 22px;
  line-height: 0;
  opacity: 0.92;
}
.portfolio-page .pt-htbl-spark svg {
  width: 100%;
  height: 100%;
  display: block;
}

.portfolio-page .pt-htbl-cluster-mini {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #1e293b);
  color: var(--text-secondary, #94a3b8);
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
  max-width: 90px;
  overflow: hidden;
  text-overflow: ellipsis;
  vertical-align: middle;
}

/* TAN-684: SHORT position badge inside the ticker cell. Same chip geometry as
   .pt-htbl-cluster-mini (Bloomberg-terminal style, matches the DRAM/NAND
   bucket chips) with a distinct desaturated red-slate tone so a short row
   reads at a glance. Color-coded via text + border only — no top accent /
   gradient rail (repo rule 16/20). */
.portfolio-page .pt-htbl-short-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(239, 68, 68, 0.10);
  border: 1px solid rgba(239, 68, 68, 0.38);
  color: #F87171;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  white-space: nowrap;
  vertical-align: middle;
}

/* TAN-723 creative win: read-only tier-1 alert badge inside the ticker
   cell. Amber tone (matches the cluster-risk alert tone) so it reads as a
   signal without a colored top border. */
.portfolio-page .pt-htbl-alert-badge {
  display: inline-block;
  margin-left: 6px;
  padding: 1px 7px;
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.12);
  border: 1px solid rgba(245, 158, 11, 0.40);
  color: #F59E0B;
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  font-weight: 600;
  letter-spacing: 0.03em;
  white-space: nowrap;
  vertical-align: middle;
}

/* Conviction chip — matches the tier palette used in /rankings. */
.portfolio-page .pt-conv-chip {
  display: inline-block;
  min-width: 32px;
  padding: 2px 8px;
  border-radius: 4px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: 0.02em;
  text-align: center;
  border: 1px solid transparent;
}
.portfolio-page .pt-conv-chip.pt-tone-pos {
  color: var(--emerald, #10B981);
  background: rgba(16, 185, 129, 0.10);
  border-color: rgba(16, 185, 129, 0.30);
}
.portfolio-page .pt-conv-chip.pt-tone-neutral {
  color: var(--text-secondary, #94a3b8);
  background: rgba(148, 163, 184, 0.10);
  border-color: rgba(148, 163, 184, 0.28);
}
.portfolio-page .pt-conv-chip.pt-tone-amber {
  color: var(--amber, #F59E0B);
  background: rgba(245, 158, 11, 0.10);
  border-color: rgba(245, 158, 11, 0.30);
}
.portfolio-page .pt-conv-chip.pt-tone-neg {
  color: #EF4444;
  background: rgba(239, 68, 68, 0.10);
  border-color: rgba(239, 68, 68, 0.30);
}

/* ─────────────────────────────────────────────────────────────────────────
   TAN-612 — Portfolio-AI platform: shared highlight tokens + classes.
   Loaded site-wide via css/portfolio.css (existing import path). Consumed
   by js/util/portfolio-highlight.js (TAN-610) — other surfaces (FF,
   Rankings, Algorithm, Heatmaps) reference these classes directly via
   the helper's renderHeldChip() / applyRing(). No surface-specific
   re-definition needed.
   ───────────────────────────────────────────────────────────────────────── */
:root {
  /* TAN-603/604 visual system (gold). Legacy purple kept for any
     surface still using the .pf-highlight-ring fallback path. */
  --pf-highlight-ring:    rgba(251, 191, 36, 0.75);
  --pf-highlight-ring-w:  1.5px;
  --pf-held-chip-bg:      rgba(251, 191, 36, 0.14);
  --pf-held-chip-fg:      #FBBF24;
  --pf-held-chip-border:  rgba(251, 191, 36, 0.55);
  --pf-held-counter-fg:   #FBBF24;

  /* TAN-684 watchlist visual system (cyan). Distinct from holdings gold so a
     watched-but-not-owned ticker reads clearly wherever holdings are
     color-coded. Cyan #22d3ee matches the donut legend "software"/cyan hue
     (CLUSTER_COLORS in js/portfolio.js) per the locked color decision. */
  --pf-watch-chip-bg:      rgba(34, 211, 238, 0.13);
  --pf-watch-chip-fg:      #22D3EE;
  --pf-watch-chip-border:  rgba(34, 211, 238, 0.52);

  /* TAN-800 — basket tier ("held via" indirect exposure). Ticker stays white;
     gold badge label "DRAM" appended via .pf-basket-tag <sup> element.
     AMBER RULE: gold stays held-only — basket ticker text is NOT gold,
     only the small badge label is. --basket hex is no longer used for text. */
  --basket:                #A78BFA; /* kept for any legacy ref, not rendered */
  --pf-basket-chip-bg:     rgba(251, 191, 36, 0.10);
  --pf-basket-chip-fg:     #FBBF24;
  --pf-basket-chip-border: rgba(251, 191, 36, 0.35);
}

/* Legacy ribbon chip (kept for any non-bucket surface that still calls
   PortfolioHighlight.renderHeldChip()). Bucket surfaces use the
   .tz-chip.pf-held class modifier below instead. */
.pf-held-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--pf-held-chip-bg);
  color: var(--pf-held-chip-fg);
  border: 1px solid var(--pf-held-chip-border);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.pf-held-chip::before {
  content: '★';
  font-size: 9px;
}

.pf-highlight-ring {
  box-shadow: 0 0 0 var(--pf-highlight-ring-w) var(--pf-highlight-ring);
  border-radius: inherit;
}

/* TAN-603/604 — HELD treatment for Rankings TARGET-zone ticker pills.
   Applied via PortfolioHighlight.getHeldClass(ticker) which returns
   'pf-held' when the ticker is in the active preset, '' otherwise.
   Gold border + gold ticker symbol, no separate pill. */
.tz-chip.pf-held {
  border-color: var(--pf-held-chip-border);
  background: var(--pf-held-chip-bg);
  box-shadow:
    0 0 0 1px rgba(251, 191, 36, 0.08),
    0 0 10px rgba(251, 191, 36, 0.05);
  color: var(--pf-held-chip-fg);
}

/* TAN-684 — cyan WATCH ribbon chip (parity with .pf-held-chip). Rendered by
   PortfolioHighlight.renderWatchChip() on surfaces that show a standalone
   state pill. The ★ marker is reserved for HELD; WATCH uses an eye-style dot. */
.pf-watch-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 10px;
  padding: 2px 7px;
  border-radius: 4px;
  background: var(--pf-watch-chip-bg);
  color: var(--pf-watch-chip-fg);
  border: 1px solid var(--pf-watch-chip-border);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  white-space: nowrap;
}
.pf-watch-chip::before {
  content: '◇';
  font-size: 9px;
}

/* TAN-684 — cyan WATCH treatment for ticker pills (parity with .tz-chip.pf-held).
   Applied via PortfolioHighlight.getClassFor(ticker) which returns 'pf-watched'
   for watchlist tickers. Cyan border + cyan ticker symbol, no separate pill. */
.tz-chip.pf-watched {
  border-color: var(--pf-watch-chip-border);
  background: var(--pf-watch-chip-bg);
  box-shadow:
    0 0 0 1px rgba(34, 211, 238, 0.08),
    0 0 10px rgba(34, 211, 238, 0.05);
  color: var(--pf-watch-chip-fg);
}

/* TAN-684 — bare class-modifier coloring for surfaces that render their own
   inline ticker span (Top Movers .mv4-ticker, News .nf-ticker-badge, PTA
   .alert-v2-ticker-name, Pulse rows, MI-brief wrapped tickers). These surfaces
   apply 'pf-held'/'pf-watched' via PortfolioHighlight.getClassFor() without the
   .tz-chip pill chrome, so they only need the gold/cyan text color (no border /
   background / accent rail — keeps the calm data-first chrome, rules 16 & 20).
   Reuses the same FG tokens as the chip system; no new hex values. */
.pf-held {
  color: var(--pf-held-chip-fg) !important;
}
.pf-watched {
  color: var(--pf-watch-chip-fg) !important;
}
/* TAN-800 — basket tier: indirect exposure via a held thematic ETF/basket.
   Ticker span itself stays white (no color override) — only the gold badge
   label .pf-basket-tag distinguishes it. AMBER RULE: ticker is NOT gold.
   Priority in PortfolioHighlight.classify(): held > basket > watched > none. */
.pf-basket {
  /* intentionally no color — ticker text stays --text-primary (white) */
}
/* TAN-800 — gold "via DRAM" badge appended after the ticker text on basket
   constituents. <sup class="pf-basket-tag"> injected by app.js next to the
   ticker <span>. Gold color signals indirect exposure without violating
   AMBER RULE (the ticker text itself is not gold). */
.pf-basket-tag {
  display: inline-block;
  vertical-align: super;
  font-size: 8px;
  font-weight: 700;
  letter-spacing: 0.06em;
  line-height: 1;
  color: var(--pf-basket-chip-fg);
  margin-left: 3px;
  opacity: 0.90;
  font-family: var(--font-sans, sans-serif);
  text-transform: uppercase;
  pointer-events: none;
  white-space: nowrap;
}
/* TAN-800 — basket tooltip trigger. The ticker span carries both
   data-pf-ticker (for the repaint walker) and data-tooltip="Held via X"
   (for the CSS-only hover tip). Uses position:relative so the ::after
   can escape overflow:hidden on .table-wrap via z-index. */
[data-pf-ticker][data-tooltip] {
  position: relative;
  cursor: pointer;
}
[data-pf-ticker][data-tooltip]::after {
  content: attr(data-tooltip);
  position: absolute;
  bottom: calc(100% + 6px);
  /* Anchor to the left edge of the ticker span so the tooltip never clips
     off the left side of the viewport (Rankings column is near the left
     rail). Using left:0/transform:none keeps the bubble flush-left with
     the ticker text instead of centre-aligned, which is correct here. */
  left: 0;
  transform: none;
  background: #0F172A;
  color: #F1F5F9;
  font-size: 11px;
  font-weight: 500;
  font-family: var(--font-sans, sans-serif);
  letter-spacing: 0.02em;
  padding: 5px 10px;
  border-radius: 6px;
  border: 1px solid rgba(148,163,184,0.20);
  box-shadow: 0 6px 20px rgba(0,0,0,0.45), 0 2px 6px rgba(0,0,0,0.25);
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  transition: opacity 150ms ease;
  z-index: 200;
}
[data-pf-ticker][data-tooltip]:hover::after { opacity: 1; }
/* Rankings: td.td-ticker has no overflow of its own, but .table-wrap has
   overflow:hidden which clips the ::after. Override the cell to visible so
   the tooltip escapes the row boundary. */
td.td-ticker {
  overflow: visible;
}
/* TAN-684 (2026-06-17): terminal/command-center surface scope extension. The
   bare .pf-held/.pf-watched rules above color inline ticker spans everywhere
   EXCEPT the command-center terminal, where the pulse rows under .intel-feed-
   wrap (carrying .pulse-v3-row--surface-cc) get their .ticker color from the
   higher-specificity surface rule `.pulse-v3-active .feed-* .ticker`
   (css/app.css) — gold/cyan never showed there. Re-assert the SAME tokens (no
   new colors) with a terminal-scoped, higher-specificity selector so held/
   watched tickers read gold/cyan in the terminal exactly as on the app tabs. */
.pulse-v3-active .intel-feed-wrap .ticker.pf-held,
.pulse-v3-active .intel-feed-wrap .pf-held {
  color: var(--pf-held-chip-fg) !important;
}
.pulse-v3-active .intel-feed-wrap .ticker.pf-watched,
.pulse-v3-active .intel-feed-wrap .pf-watched {
  color: var(--pf-watch-chip-fg) !important;
}

/* ── TAN-684 Watchlist table (portfolio page, watch-only rows) ──────────────
   Mirrors the holdings table (.pt-htbl-*) but with 8 columns and NO
   shares/ACB/weight/MV/PL — a watch row never enters portfolio math. Cyan
   eyebrow + inline WATCH tag distinguish it from gold holdings. */
.portfolio-page .pt-watchlist-eyebrow {
  color: var(--pf-watch-chip-fg);
}
.portfolio-page .pt-wtbl-row {
  display: grid;
  grid-template-columns:
    minmax(110px, 1.4fr)  /* Ticker (+ WATCH tag) */
    78px                  /* 30D sparkline */
    84px                  /* Price */
    78px                  /* Day % */
    90px                  /* Near/Far (TAN-684 ITEM 6b-i: replaces Score + Conviction) */
    72px                  /* Next ER */
    36px;                 /* action */
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  font-size: 13px;
  color: var(--text-primary);
  /* TAN-684 (mobile PWA h-scroll): keep the full-width grid intact so it
     overflows into the body's scroll region rather than being squeezed. */
  min-width: 560px;
}
.portfolio-page .pt-wtbl-row.pt-wtbl-head {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  padding-bottom: 7px;
}
.portfolio-page .pt-wtbl-row.pt-wtbl-head .pt-wtbl-tkr { text-align: left; }
.portfolio-page .pt-wtbl-row.pt-wtbl-head .pt-wtbl-spark,
.portfolio-page .pt-wtbl-row.pt-wtbl-head .pt-wtbl-num { text-align: right; }
.portfolio-page .pt-wtbl-row.pt-wtbl-data {
  border-bottom: 1px solid var(--border);
  transition: background 0.12s ease;
}
.portfolio-page .pt-wtbl-row.pt-wtbl-data:last-of-type { border-bottom: none; }
.portfolio-page .pt-wtbl-row.pt-wtbl-data:hover { background: rgba(255, 255, 255, 0.02); }
.portfolio-page .pt-wtbl-tkr {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  letter-spacing: 0.02em;
}
.portfolio-page .pt-wtbl-tkr-text { font-family: 'JetBrains Mono', monospace; }
.portfolio-page .pt-htbl-tkr-clickable.pt-wtbl-tkr:hover .pt-wtbl-tkr-text {
  color: var(--pf-watch-chip-fg);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.portfolio-page .pt-wtbl-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-wtbl-spark { text-align: right; }
.portfolio-page .pt-wtbl-action { display: flex; justify-content: flex-end; align-items: center; }
.portfolio-page .pt-wtbl-row.pt-wtbl-data:hover .pt-watch-trash { opacity: 1; }

/* Watch add form — single ticker input + Add button (no shares/ACB).
   BUG 3 (TAN-684): spans the full card width like the "Add a holding" form so
   the two forms read as siblings. The ticker input flexes; the Add button is
   sized to match the holding form's button. */
.portfolio-page .pt-watchlist-add-grid {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: center;
}
.portfolio-page .pt-wtbl-row.pt-row-flash {
  animation: pt-row-flash 1.6s ease-out;
}

@media (max-width: 768px) {
  .portfolio-page .pt-wtbl-row {
    /* TAN-684 ITEM 6b-i: 7 cols (Score+Conviction → one Near/Far). */
    grid-template-columns:
      minmax(90px, 1.4fr) 60px 70px 64px 78px 60px 30px;
    gap: 6px;
    font-size: 12px;
  }
}

/* TAN-603/604 — "X held" suffix appended to .tz-card-count when
   PortfolioHighlight.countHeld() reports held > 0. Renders as a
   glowing gold dot + count, separated from the base count by a thin
   vertical divider. Hidden when held = 0 (renderTargetZones simply
   skips the markup). */
.tz-card-count .tz-held-suffix {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-left: 8px;
  padding-left: 8px;
  border-left: 1px solid rgba(255, 255, 255, 0.18);
  color: var(--pf-held-counter-fg);
  font-variant-numeric: tabular-nums;
}
.tz-card-count .tz-held-suffix::before {
  content: '';
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--pf-held-counter-fg);
  box-shadow: 0 0 6px var(--pf-held-counter-fg);
}

/* ─── TAN-673: Themed confirm modal ──────────────────────────────────────── */
/* Replaces native window.confirm() popups on the Portfolio tab. Scoped to
   .pt-cm-* so it never collides with global modals. Palette: existing
   --bg-alt / --surface / --text-primary / --border tokens from app.css +
   #06B6D4 cyan literal matching kpi-cyan precedent (css/app.css:765). */
.pt-cm-root {
  position: fixed;
  inset: 0;
  z-index: 10000;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(7, 12, 24, 0.72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  opacity: 1;
  transition: opacity 120ms ease-out;
}
.pt-cm-root.pt-cm-closing { opacity: 0; }

.pt-cm-card {
  width: min(440px, calc(100vw - 32px));
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1E293B);
  border-radius: 10px;
  box-shadow:
    0 24px 60px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(6, 182, 212, 0.10),
    0 0 24px rgba(6, 182, 212, 0.08);
  padding: 22px 22px 18px;
  transform: translateY(0);
  animation: pt-cm-in 140ms ease-out;
}
@keyframes pt-cm-in {
  from { transform: translateY(6px); opacity: 0; }
  to   { transform: translateY(0);   opacity: 1; }
}

.pt-cm-title {
  font-size: 15px;
  font-weight: 600;
  color: var(--text-primary, #F1F5F9);
  letter-spacing: -0.01em;
  margin: 0 0 10px;
  line-height: 1.3;
}
.pt-cm-body {
  font-size: 13px;
  color: var(--text-secondary, #94A3B8);
  line-height: 1.5;
  margin: 0 0 20px;
}

.pt-cm-actions {
  display: flex;
  justify-content: flex-end;
  gap: 8px;
}
.pt-cm-btn {
  height: 32px;
  padding: 0 14px;
  border-radius: 6px;
  font-size: 12px;
  font-weight: 600;
  font-family: inherit;
  letter-spacing: 0.01em;
  cursor: pointer;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-primary, #F1F5F9);
  transition: background 120ms ease, border-color 120ms ease, color 120ms ease;
}
.pt-cm-btn:focus-visible {
  outline: 2px solid #06B6D4;
  outline-offset: 2px;
}

.pt-cm-btn-cancel {
  background: transparent;
  border-color: var(--border, #1E293B);
  color: var(--text-secondary, #94A3B8);
}
.pt-cm-btn-cancel:hover {
  background: rgba(148, 163, 184, 0.06);
  color: var(--text-primary, #F1F5F9);
}

.pt-cm-btn-confirm {
  background: linear-gradient(135deg, #06B6D4 0%, #3B82F6 100%);
  border-color: transparent;
  color: #061018;
}
.pt-cm-btn-confirm:hover {
  filter: brightness(1.08);
  box-shadow: 0 0 0 1px rgba(6, 182, 212, 0.4), 0 4px 14px rgba(6, 182, 212, 0.25);
}

.pt-cm-btn-danger {
  background: rgba(239, 68, 68, 0.12);
  border-color: rgba(239, 68, 68, 0.5);
  color: #FCA5A5;
}
.pt-cm-btn-danger:hover {
  background: rgba(239, 68, 68, 0.20);
  border-color: #EF4444;
  color: #FECACA;
}

/* ════════════════════════════════════════════════════════════════════════
   TAN-732 ROUND 4 — bottom-half parity with mockE.html
   (hero equal-height row, 3-up risk strip, treemap P/L, donut no-reflow)
   ════════════════════════════════════════════════════════════════════════ */

/* BUG 3 — hero row: AI Insights (left) + Allocation·Radial (right) equal height.
   Grid stretches both columns by default; matched card heights come from the
   grid track + the cards filling it (display:flex column on the pie card). */
/* MOCKUP-E-v2 (CHANGE 2): invisible flex layout wrapper for the four AI surfaces.
   Purple border + "AI-POWERED INSIGHTS" label removed (TAN-684); div kept as
   flex column container for the cards. */
.portfolio-page .pt-ai-zone {
  position: relative;
  padding: 0;
  margin: 18px 0;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
/* The zone owns the row gaps; the inner rows no longer need their own margin. */
.portfolio-page .pt-ai-zone > .pt-row { margin: 0; }

.portfolio-page .pt-row-hero {
  grid-template-columns: minmax(0, 1.45fr) minmax(0, 1fr);
  align-items: stretch;
}
.portfolio-page .pt-row-hero > .pt-card,
.portfolio-page .pt-row-hero > .pt-pie-card {
  height: 100%;
}
.portfolio-page .pt-ai-card {
  display: flex;
  flex-direction: column;
}
.portfolio-page .pt-ai-card .pt-ai-body {
  flex: 1 1 auto;
}
@media (max-width: 1080px) {
  .portfolio-page .pt-row-hero {
    grid-template-columns: 1fr;
  }
}

/* TAN-684 — vertical-stack layout: the detail card flows full-width below the
   donut as a normal block row (was an absolute overlay in a fixed-height box
   for the prior side-by-side grid, where hover-induced height changes would
   have grown the shared row). Every detail-panel row now always renders (with
   muted "—" placeholders for Cash / unscored names), so the only remaining
   height variable is the ETF look-through line. The min-height reserve is
   sized to the TALLEST panel (full live position + conviction + score +
   earnings + cluster + a 1-line look-through allowance); content is
   top-aligned so shorter panels (Cash, non-ETF names) pad with empty space at
   the bottom rather than collapsing — the donut/hero row stays pixel-constant
   across every slice. */
.portfolio-page .pt-pie-panel {
  position: relative;
  width: 100%;
  min-width: 0;
  min-height: 296px;
}
.portfolio-page .pt-pie-panel > .pt-pie-tooltip,
.portfolio-page .pt-pie-panel > .pt-pie-summary {
  position: static;
  width: 100%;
}

/* BUG 1 — 3-up risk strip trio. Matches mockE `.grid3` (1fr 1fr 1.1fr). */
.portfolio-page .pt-row-risk3 {
  grid-template-columns: 1fr 1fr 1.1fr;
}
@media (max-width: 1080px) {
  .portfolio-page .pt-row-risk3 {
    grid-template-columns: 1fr;
  }
}
.portfolio-page .pt-risk-c {
  position: relative;
  overflow: hidden;
}
/* MOCKUP-E-v2 (CHANGE 2): per-card accent borders are removed inside the AI
   zone — the zone's purple outline is the only accent. The Stress card now uses
   the normal neutral card border (inherited from .pt-card) like its siblings. */

/* Card head: title + eyebrow tag (mockE `.ch`) */
.portfolio-page .pt-rc-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  margin-bottom: 4px;
}
.portfolio-page .pt-rc-head .pt-eyebrow {
  margin-bottom: 0;
}
.portfolio-page .pt-rc-eye {
  font-size: 9px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: 700;
  white-space: nowrap;
}
/* MOCKUP-E-v2 round-2 (Fix 5): the per-card purple dots (.pt-rc-gem / .pt-ai-dot)
   were removed from the four AI-zone card headers. The zone badge and glowing dot
   were also removed in TAN-684 — the whole app is AI-based. */

/* Ring (mockE `.ring`) — floats top-right of the card */
.portfolio-page .pt-ring {
  float: right;
  width: 54px;
  height: 54px;
  margin-left: 10px;
}

/* Big number (mockE `.big`) */
.portfolio-page .pt-rc-big {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.5px;
  margin-top: 2px;
}
.portfolio-page .pt-rc-big.pt-rc-amber {
  color: var(--amber);
}
.portfolio-page .pt-rc-u {
  font-size: 13px;
  color: var(--text-secondary);
  font-weight: 600;
}
.portfolio-page .pt-rc-sub {
  font-size: 11px;
  color: var(--text-secondary);
  margin-top: 5px;
  line-height: 1.45;
  clear: none;
}

/* TAN polish — Variation A "intentional empty" state for the empty/benign
   Redundant Capital / MCTR / Stress Test cards. Accent-tinted icon tile + bold
   headline + muted helper line, vertically centered. No CTA, no stat grid, no
   accent rail — the icon tint and text tone carry the color-coding (repo rule
   20). Reuses the repo's --purple accent — no new color tokens introduced. */
.portfolio-page .pt-empty-card {
  margin-top: 6px;
  clear: both;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  min-height: 180px;
  gap: 10px;
}
.portfolio-page .pt-empty-icon-wrap {
  width: 44px;
  height: 44px;
  border-radius: 10px;
  background: rgba(139, 92, 246, 0.12);
  color: var(--purple, #8b5cf6);
  display: flex;
  align-items: center;
  justify-content: center;
}
.portfolio-page .pt-empty-icon-wrap svg {
  width: 22px;
  height: 22px;
  stroke: var(--purple, #8b5cf6);
}
.portfolio-page .pt-empty-headline {
  font-size: 14px;
  font-weight: 600;
  color: var(--text-primary, #e7ecf3);
}
.portfolio-page .pt-empty-helper {
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--text-secondary);
  max-width: 280px;
  text-align: center;
}

/* Diversification effbar (mockE `.effbar`) */
.portfolio-page .pt-effbar {
  display: flex;
  gap: 4px;
  margin-top: 14px;
  clear: both;
}
.portfolio-page .pt-effbar span {
  height: 7px;
  flex: 1;
  border-radius: 2px;
  background: #1c2533;
}
.portfolio-page .pt-effbar span.on {
  background: linear-gradient(90deg, var(--blue), #60a5fa);
}

/* Hedge chip (mockE `.hedge-chip`) */
.portfolio-page .pt-hedge-chip {
  margin-top: 12px;
  padding: 8px 11px;
  background: #1a2436;
  border: 1px solid rgba(59, 130, 246, 0.45);
  border-radius: 7px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: #93c5fd;
  clear: both;
}

/* Stress test — segmented severity pip meter (TAN-684; replaces the #1819
   scaled red bar). Each scenario is a stacked block: title row ($ loss on the
   right, no clipping), sub-tag row (% of book on the right), then a full-width
   10-pip meter. Every filled pip is red (severe); unfilled = off-color
   headroom. (Amber "moderate" tier dropped — amber reserved for held tickers.) */
.portfolio-page .pt-st-scenario {
  padding: 16px 0;
  border-bottom: 1px solid #151c29;
}
.portfolio-page .pt-st-scenario:last-of-type {
  border-bottom: none;
}
.portfolio-page .pt-st-title-row,
.portfolio-page .pt-st-subtag-row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 10px;
}
/* TAN-684 font normalization: scale the Stress type down to the Redundant /
   MCTR baseline so the three risk cards read as one type system. Scenario
   title matches the MCTR row scale (12px); the $ figure sits at 13px/700 —
   no longer larger/heavier than the sibling cards' metric text. */
.portfolio-page .pt-st-title {
  font-weight: 600;
  font-size: 12px;
  color: var(--text-primary);
}
.portfolio-page .pt-st-dollar {
  font-weight: 700;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--red, #EF4444);
}
.portfolio-page .pt-st-subtag-row {
  margin-top: 3px;
}
.portfolio-page .pt-st-subtag {
  font-size: 10.5px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--text-secondary);
}
.portfolio-page .pt-st-pct {
  font-weight: 700;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  color: var(--red, #EF4444);
}
/* Pip meter — 10 equal cells filling the panel width. */
.portfolio-page .pt-st-pips {
  display: flex;
  gap: 5px;
  margin-top: 11px;
}
.portfolio-page .pt-st-pip {
  flex: 1 1 auto;
  height: 12px;
  border-radius: 3px;
  background: #222b3b;
}
.portfolio-page .pt-st-pip--red {
  background: var(--red, #EF4444);
}
/* Legend under the scenarios. */
.portfolio-page .pt-st-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: 8px 14px;
  margin-top: 4px;
  padding-top: 12px;
  border-top: 1px solid var(--border);
  font-size: 10.5px;
  color: var(--text-secondary);
}
.portfolio-page .pt-st-legend-keys {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}
.portfolio-page .pt-st-legend-key {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.portfolio-page .pt-st-legend-key .pt-st-pip {
  flex: 0 0 auto;
  width: 18px;
  height: 10px;
}
/* LOW → SEVERE red-intensity gradient swatch (matches the per-pip ramp). */
.portfolio-page .pt-st-legend-ramp {
  flex: 0 0 auto;
  width: 28px;
  height: 10px;
  border-radius: 3px;
}
.portfolio-page .pt-st-sub {
  margin-top: 11px;
}
.portfolio-page .pt-st-note {
  display: block;
  margin-top: 4px;
  font-size: 10px;
  color: var(--text-secondary);
  font-style: italic;
}

/* BUG 2 — P/L Attribution treemap. The hover popover is anchored ~70px below
   the treemap top and is ~95px tall, so it reaches ~100px below the treemap.
   The popover is position:absolute (no layout cost) and only shows on hover, so
   we keep the card at the normal 16px bottom padding and let the transient
   popover overlay the gap beneath the bar instead of reserving a permanent
   empty band (the 135px reserve read as a large dead gap on every render). */
.portfolio-page .pt-pl-card {
  padding-bottom: 16px;
}
.portfolio-page .pt-pl-header {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px;
  flex-wrap: wrap;
  margin-bottom: 4px;
}
.portfolio-page .pt-pl-total {
  font-size: 12px;
  color: var(--text-secondary);
}
.portfolio-page .pt-pl-total-label {
  font-size: 9px;
  letter-spacing: 0.1em;
  font-weight: 700;
  color: var(--text-secondary);
}
.portfolio-page .pt-pl-total-val {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-pl-total-val.pt-pl-pos { color: var(--emerald); }
.portfolio-page .pt-pl-total-val.pt-pl-neg { color: var(--danger); }
.portfolio-page .pt-pl-total-pct { font-weight: 600; }
.portfolio-page .pt-pl-sub {
  font-size: 11px;
  color: var(--text-secondary);
  margin-bottom: 10px;
  line-height: 1.45;
}

/* TAN-684 — netting context line under the header. Shows gainers / losers /
   net so the gross treemap blocks read consistently with the net DAY total. */
.portfolio-page .pt-pl-netting {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
  margin-bottom: 8px;
}
.portfolio-page .pt-pl-net-gain { color: var(--emerald); }
.portfolio-page .pt-pl-net-loss { color: #fca5a5; }
.portfolio-page .pt-pl-net-net { color: var(--text-primary); font-weight: 600; }
.portfolio-page .pt-pl-net-dot { color: var(--text-secondary); opacity: 0.6; }

/* TAN-684 ITEM 6 — compact single-strip P/L attribution. The header right side
   carries the inline gainers/losers cluster + the DAY total on one line; the
   standalone netting row is folded in. Tiles sit in one tighter row below. */
.portfolio-page .pt-pl-header--compact {
  align-items: baseline;
  margin-bottom: 6px;
}
.portfolio-page .pt-pl-headright {
  display: flex;
  align-items: baseline;
  gap: 12px;
  flex-wrap: wrap;
  justify-content: flex-end;
}
.portfolio-page .pt-pl-netting-inline {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  font-size: 11px;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-treemap--compact {
  height: 46px;
  gap: 4px;
  margin-top: 4px;
}
.portfolio-page .pt-treemap--compact .pt-tm-sym { font-size: 12px; }
.portfolio-page .pt-treemap--compact .pt-tm-val { font-size: 10px; }
/* Footnote sits right-aligned under the compact strip. */
.portfolio-page .pt-pl-header--compact ~ .pt-pl-sub { text-align: right; margin-top: 6px; margin-bottom: 0; }

/* Treemap (mockE `.treemap` / `.tm` / `.tm-tip`) */
.portfolio-page .pt-treemap {
  display: flex;
  gap: 5px;
  height: 60px;
  margin-top: 6px;
  position: relative;
}
.portfolio-page .pt-tm {
  border-radius: 7px;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  color: #06140c;
  font-weight: 700;
  position: relative;
  min-width: 0;
  cursor: default;
  outline: none;
}
.portfolio-page .pt-tm-sym { font-size: 13px; }
.portfolio-page .pt-tm-val { font-size: 11px; opacity: 0.85; font-weight: 600; }
.portfolio-page .pt-tm-up {
  background: linear-gradient(180deg, #34d399, #10b981);
}
.portfolio-page .pt-tm-down {
  background: linear-gradient(180deg, #f87171, #ef4444);
  color: #fff;
}

/* Hover/focus popover anchored below the block (mockE `.tm-tip`) */
.portfolio-page .pt-tm-tip {
  position: absolute;
  top: 70px;
  left: 0;
  width: 240px;
  background: #0c1420;
  border: 1px solid rgba(59, 130, 246, 0.45);
  border-radius: 10px;
  padding: 12px 14px;
  box-shadow: 0 12px 30px rgba(0, 0, 0, 0.5);
  z-index: 5;
  color: var(--text-primary);
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 0.12s ease;
}
.portfolio-page .pt-tm:hover .pt-tm-tip,
.portfolio-page .pt-tm:focus .pt-tm-tip,
.portfolio-page .pt-tm:focus-within .pt-tm-tip {
  opacity: 1;
  visibility: visible;
}
.portfolio-page .pt-tm-tip::before {
  content: '';
  position: absolute;
  top: -7px;
  left: 30px;
  width: 12px;
  height: 12px;
  background: #0c1420;
  border-left: 1px solid rgba(59, 130, 246, 0.45);
  border-top: 1px solid rgba(59, 130, 246, 0.45);
  transform: rotate(45deg);
}
/* TAN-732 (BUG 1): edge-aware popover. Right-side blocks (esp. the rightmost,
   e.g. SNDK) would overflow the viewport with the default left:0 anchor, so we
   flip the tip to right-anchor and move the arrow to the right edge. */
.portfolio-page .pt-tm-tip.pt-tm-tip-right {
  left: auto;
  right: 0;
}
.portfolio-page .pt-tm-tip.pt-tm-tip-right::before {
  left: auto;
  right: 30px;
}
.portfolio-page .pt-tm-th {
  font-size: 13px;
  font-weight: 700;
  margin-bottom: 8px;
  display: flex;
  justify-content: space-between;
}
.portfolio-page .pt-tm-tr {
  display: flex;
  justify-content: space-between;
  font-size: 11px;
  padding: 3px 0;
  color: var(--text-secondary);
}
.portfolio-page .pt-tm-tr .v {
  color: var(--text-primary);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* ── TAN-684 mobile P/L attribution (≤767px ONLY) ──────────────────────────
   The desktop horizontal treemap (flex-grow + fixed 60px height) crams blocks
   to near-zero width on phones. On mobile we stack each contribution as a
   full-width horizontal BAR ROW: ticker left, $ + day% right, the per-touch
   hover popover INLINED below as static facts (shares·price, day move,
   share-of-side %) since hover/focus tips aren't reachable on touch. Desktop
   (≥768px, where the .portfolio-page zoom:1.1 scope lives) is untouched. */
@media (max-width: 767px) {
  .portfolio-page .pt-treemap {
    flex-direction: column;
    height: auto;
    gap: 6px;
  }
  .portfolio-page .pt-tm {
    flex: none !important;       /* neutralize the inline flex-grow from JS */
    flex-grow: 0 !important;
    width: 100%;
    min-height: 40px;
    /* grid: sym (left) + val (right) on row 1, inlined tip spans row 2. */
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: baseline;
    column-gap: 8px;
    padding: 9px 12px;
    border-radius: 8px;
  }
  /* Top line of each bar: ticker left, $ value right. */
  .portfolio-page .pt-tm-sym {
    font-size: 13px;
    grid-column: 1;
    text-align: left;
  }
  .portfolio-page .pt-tm-val {
    font-size: 12px;
    opacity: 1;
    grid-column: 2;
    text-align: right;
  }
  /* Inline the tip below the sym/val line — static, no hover, no overflow.
     It spans both grid columns as a full-width second row. */
  .portfolio-page .pt-tm .pt-tm-tip,
  .portfolio-page .pt-tm:hover .pt-tm-tip,
  .portfolio-page .pt-tm:focus .pt-tm-tip,
  .portfolio-page .pt-tm:focus-within .pt-tm-tip {
    position: static;
    grid-column: 1 / -1;         /* span the full bar width on row 2 */
    width: auto;
    left: auto;
    right: auto;
    top: auto;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    background: transparent;
    border: none;
    box-shadow: none;
    padding: 6px 0 0;
    margin-top: 6px;
    border-top: 1px solid rgba(255, 255, 255, 0.14);
    z-index: auto;
    color: inherit;
  }
  .portfolio-page .pt-tm-tip::before { display: none; } /* drop the arrow */
  /* Hide the redundant in-tip header (ticker/$ already on the bar's top line). */
  .portfolio-page .pt-tm-th { display: none; }
  .portfolio-page .pt-tm-tr {
    color: inherit;
    opacity: 0.92;
    padding: 2px 0;
    font-size: 11px;
  }
  .portfolio-page .pt-tm-tr .v { color: inherit; }
  /* Down (loser) bars keep white text; gainers use the dark-on-green default,
     so the inlined facts inherit a readable color on each side. */
  .portfolio-page .pt-tm-down .pt-tm-tip { border-top-color: rgba(255, 255, 255, 0.22); }

  /* Header / netting / sub-line already wrap (flex-wrap); tighten for phones. */
  .portfolio-page .pt-pl-netting { font-size: 10.5px; gap: 5px; }
  .portfolio-page .pt-pl-sub { font-size: 11px; }
}

/* ─────────────────────────────────────────────────────────────────────────
   TAN-684 — Portfolio insight cards: Overlap & Redundant Conviction + MCTR.
   Reuses the existing card chrome (.pt-risk-c / .pt-rc-head / .pt-ring /
   .pt-rc-big / .pt-rc-sub). No top accents, no emojis (rules 16/20). Gold
   held-name tokens match the design-system --gold; correlation tones reuse
   the red/amber/green semantic palette. Mobile-first: the parent .pt-row-risk3
   already collapses to a single column at <=1080px; bars/grids are fluid.
   ───────────────────────────────────────────────────────────────────────── */

/* Gold held-name token (matches mockup .gold). */
.portfolio-page .pt-overlap-gold {
  color: var(--gold, #FBBF24);
  font-weight: 700;
}

/* ── Redundant Capital (TAN-684) ────────────────────────────────────────────
   Opportunity-cost reframe of the old Overlap panel: amber redundant-$ hero,
   a diversification-captured meter, a plain-bordered narrative callout, and an
   all-pairs redundancy scan. Reuses the dark token palette + the #222b3b
   off-pip literal from the Stress meter. No white boxes, no colored left rails. */
.portfolio-page .pt-rcap-headline {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin-top: 4px;
}
.portfolio-page .pt-rcap-big {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -0.5px;
  color: var(--ink, #e7ecf3);
  font-variant-numeric: tabular-nums;
  line-height: 1.05;
}
.portfolio-page .pt-rcap-cap {
  font-size: 11px;
  color: var(--text-secondary);
  line-height: 1.45;
}

/* Diversification-captured meter: neutral muted-slate fill on an off-pip track.
   Neutral (not amber/red) because "more captured" is good — color would imply
   a severity it doesn't have. */
.portfolio-page .pt-rcap-meter-wrap {
  margin-top: 14px;
}
.portfolio-page .pt-rcap-meter-lbl {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 10.5px;
  color: var(--text-secondary);
  margin-bottom: 5px;
}
.portfolio-page .pt-rcap-meter-val {
  color: var(--text-primary);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-rcap-track {
  height: 10px;
  border-radius: 5px;
  background: #222b3b;
  overflow: hidden;
}
/* Diversification-captured meter — the one "good = more captured" meter, so
   it gets a positive EMERALD fill (not grey, not red, not amber). Track #222b3b. */
.portfolio-page .pt-rcap-fill {
  display: block;
  height: 100%;
  border-radius: 5px;
  background: var(--emerald, #10b981);
}
.portfolio-page .pt-rcap-ticks {
  display: flex;
  justify-content: space-between;
  font-size: 9px;
  color: var(--text-faint, #64748B);
  margin-top: 4px;
}

/* Opportunity-cost narrative callout. PLAIN even 1px border — NO left-edge
   accent (repo design-system rule, strictly enforced). */
.portfolio-page .pt-rcap-callout {
  margin-top: 14px;
  padding: 12px 14px;
  background: var(--surface-2, #1A2332);
  border: 1px solid var(--border);
  border-radius: 8px;
  font-size: 11.5px;
  line-height: 1.55;
  color: var(--text-secondary);
}
.portfolio-page .pt-rcap-ink { color: var(--text-primary); font-weight: 700; }
/* Narrative emphasis on the redundant-$ phrase — neutral ink, NOT amber (it is
   not a ticker; amber is reserved for held-ticker emphasis only). */
.portfolio-page .pt-rcap-amber { color: var(--ink, #e7ecf3); font-weight: 700; }

/* TAN-684 ITEM 4: row ticker labels on the Redundant Capital + MRCT cards read
   WHITE/ink (amber dropped here — it competed with the colored bars). Amber
   stays reserved for the Holdings table / conviction chips. */
.portfolio-page .pt-rcap-tk { color: var(--ink, #e7ecf3); font-weight: 700; }

/* TAN-684 ITEM 5: blurb box pinned to the TOP of a risk card (directly under
   the eyebrow row). Same panel treatment as the narrative callout but with no
   top margin since it leads the card; small bottom gap before the body. */
.portfolio-page .pt-rcap-callout--top { margin-top: 10px; margin-bottom: 12px; }

/* All-pairs redundancy scan. */
.portfolio-page .pt-rcap-scan {
  display: flex;
  flex-direction: column;
  gap: 7px;
  margin-top: 4px;
}
.portfolio-page .pt-rcap-pairrow {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 11px;
}
.portfolio-page .pt-rcap-pairnames {
  flex: 0 0 auto;
  min-width: 96px;
  font-weight: 700;
  color: var(--text-primary);
}
.portfolio-page .pt-rcap-pairmeter {
  flex: 1 1 auto;
  display: flex;
  gap: 4px;
}
.portfolio-page .pt-rcap-pip {
  flex: 1 1 auto;
  height: 9px;
  border-radius: 3px;
  background: #222b3b;
}
/* Filled segment base — actual fill color is set inline on a RED INTENSITY
   ramp scaled by ρ (brighter = higher correlation). */
.portfolio-page .pt-rcap-pip--red { background: var(--red, #EF4444); }
/* TAN-684 (revert off #1827 red ramp): blue/purple/teal severity tier by ρ —
   NO red, NO amber on these bars. Higher ρ reads purple (most redundant), mid
   reads blue, low/floor reads teal. */
.portfolio-page .pt-rcap-pip--purple { background: var(--purple, #8B5CF6); }
.portfolio-page .pt-rcap-pip--blue   { background: var(--blue, #3B82F6); }
.portfolio-page .pt-rcap-pip--teal   { background: var(--cyan, #22d3ee); }
.portfolio-page .pt-rcap-pairstat {
  flex: 0 0 auto;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* Shared italic source note (mockup .note). */
.portfolio-page .pt-rc-note {
  font-size: 10px;
  font-style: italic;
  color: var(--text-secondary);
  margin-top: 12px;
  line-height: 1.4;
  clear: both;
}
.portfolio-page .pt-rc-sectionlbl {
  font-size: 9.5px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-secondary);
  font-weight: 700;
  margin: 14px 0 4px;
  clear: both;
}

/* MCTR rows: ticker · dual-bar (solid MCTR + thin weight overlay) · values. */
.portfolio-page .pt-mctr-lead { color: var(--red, #F87171); font-weight: 700; }
.portfolio-page .pt-mctr-rows {
  display: flex;
  flex-direction: column;
  gap: 9px;
}
.portfolio-page .pt-mctr-row {
  display: flex;
  align-items: center;
  gap: 10px;
}
.portfolio-page .pt-mctr-tk {
  width: 48px;
  font-weight: 800;
  font-size: 12px;
  flex-shrink: 0;
}
.portfolio-page .pt-mctr-bar {
  flex: 1;
  height: 8px;
  border-radius: 4px;
  background: #1a2233;
  position: relative;
  overflow: hidden;
}
.portfolio-page .pt-mctr-bar > i {
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  border-radius: 4px;
  display: block;
}
/* TAN-684 — weight overlay reads as an intentional measure, not a translucent
   "white smear" glitch. A dim neutral hairline (#3a4456) with a slightly
   brighter end-cap dot (#6b7688) at its tip (.pt-mctr-wt-cap) so the eye
   registers it as a deliberate marker against the red-intensity MCTR fill.
   Semantics unchanged: bar width = % weight; solid fill = % variance.
   To swap to dual-track later: drop the cap, move this hairline to its own
   track below the fill (top/height) — markup already isolates it. */
.portfolio-page .pt-mctr-bar > i.pt-mctr-wt {
  height: 2px;
  top: 3px;
  bottom: auto;
  border-radius: 1px;
  background: #3a4456;
}
.portfolio-page .pt-mctr-bar > i.pt-mctr-wt-cap {
  width: 3px;
  height: 8px;
  top: 0;
  bottom: 0;
  border-radius: 1px;
  background: #6b7688;
  transform: translateX(-50%);
}
.portfolio-page .pt-mctr-val {
  width: 92px;
  text-align: right;
  font-size: 11px;
  color: var(--text-secondary);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.portfolio-page .pt-mctr-val .pt-mctr-pct {
  color: var(--text-primary);
  font-weight: 700;
}
.portfolio-page .pt-mctr-val .pt-mctr-zero {
  color: var(--emerald, #34D399);
  font-weight: 700;
}

@media (max-width: 768px) {
  .portfolio-page .pt-rcap-pairnames { min-width: 84px; font-size: 10.5px; }
  .portfolio-page .pt-rcap-pairstat { font-size: 10px; }
  .portfolio-page .pt-mctr-val { width: 78px; font-size: 10px; }
  .portfolio-page .pt-mctr-tk { width: 42px; }
}

/* ─────────────────────────────────────────────────────────────────────────
   TAN-684 — Closed / Realized P/L + Modify Positions editor.
   Closed P/L card mirrors the watchlist card treatment (subordinate to the
   live holdings table); the Modify editor is an IN-PLACE edit mode rendered
   inside the Holdings panel (no overlay) reusing the shared .pt-btn /
   .pt-input primitives. Bloomberg-clean, no accent bars.
   ───────────────────────────────────────────────────────────────────────── */

/* Modify Positions button on the holdings header (right side, ghost). */
.portfolio-page .pt-modify-btn {
  font-size: 11.5px;
  padding: 5px 11px;
  white-space: nowrap;
}

/* ── TAN-684 Positions tab switcher ────────────────────────────────────────
   Single host card (#pt-positions) consolidating Holdings / Watchlist /
   Closed P/L into one card with a terminal-style tab bar. Holdings = gold
   accent, Watchlist = cyan, Closed P/L = neutral. Only the active panel is
   visible (others get [hidden]); the tab bar sits in the card header next to
   the Modify Positions button. */
.portfolio-page .pt-tabs-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 12px;
  border-bottom: 1px solid var(--border);
}
.portfolio-page .pt-tabs {
  display: flex;
  align-items: flex-end;
  gap: 2px;
  flex: 1 1 auto;
  min-width: 0;
  overflow-x: auto;          /* mobile: horizontal scroll instead of wrap */
  scrollbar-width: none;
}
.portfolio-page .pt-tabs::-webkit-scrollbar { display: none; }

.portfolio-page .pt-tab {
  appearance: none;
  background: transparent;
  border: 0;
  border-bottom: 2px solid transparent;
  margin-bottom: -1px;       /* overlap the head's bottom border */
  padding: 8px 14px;
  font-family: 'JetBrains Mono', monospace;
  font-size: 11px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
  color: var(--text-secondary);
  cursor: pointer;
  transition: color 0.15s ease, border-color 0.15s ease, background 0.15s ease;
}
.portfolio-page .pt-tab:hover {
  color: var(--text-primary);
  background: var(--surface-2);
}
.portfolio-page .pt-tab[hidden] { display: none; }

/* Active state — accent underline per tab identity. */
.portfolio-page .pt-tab[aria-selected="true"] {
  color: var(--text-primary);
}
.portfolio-page .pt-tab-holdings[aria-selected="true"] {
  color: var(--gold, #FBBF24);
  border-bottom-color: var(--gold, #FBBF24);
}
.portfolio-page .pt-tab-watchlist[aria-selected="true"] {
  color: var(--pf-watch-chip-fg, #22D3EE);
  border-bottom-color: var(--pf-watch-chip-fg, #22D3EE);
}
.portfolio-page .pt-tab-closed[aria-selected="true"] {
  color: var(--text-primary);
  border-bottom-color: var(--text-secondary);
}

/* Keyboard focus ring (Bloomberg-clean, no rainbow). */
.portfolio-page .pt-tab:focus-visible {
  outline: 2px solid var(--border);
  outline-offset: -2px;
  border-radius: 3px;
}

/* Panels — only the active one shows. */
.portfolio-page .pt-tab-panel[hidden] { display: none; }
.portfolio-page .pt-tab-panel--active { display: block; }

/* ── Closed P/L card ── */
/* Hide the card entirely when it has no rows (empty body shows the empty-state
   markup, but a brand-new user with zero closes shouldn't see an empty card).
   The card un-hides as soon as _renderClosedPl populates real rows. */
.portfolio-page .pt-ctbl-row {
  display: grid;
  grid-template-columns:
    minmax(84px, 1.1fr)  /* Ticker */
    96px                 /* Shares Closed */
    88px                 /* Avg Cost */
    88px                 /* Exit Price */
    104px                /* Exit Date */
    minmax(88px, 0.9fr)  /* Realized P/L */
    104px                /* Price Now + vs Exit (ITEM 6c) */
    104px                /* SPY / QQQ since exit (ITEM 6c) */
    96px                 /* Alpha vs SPY (ITEM 6c) */
    0px;                 /* Action (Delete) — 0 in view mode, expands in edit */
  align-items: center;
  gap: 10px;
  padding: 9px 6px;
  font-size: 13px;
  color: var(--text-primary);
  /* TAN-684 (mobile PWA h-scroll): keep the full-width grid intact so it
     overflows into the body's scroll region rather than being squeezed. */
  min-width: 940px;
}
/* TAN-684 follow-up: in Modify mode the Closed P/L rows reveal a Delete action
   column. Widen the last track + show the cell only under .pt-editmode. */
.portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-row {
  grid-template-columns:
    minmax(84px, 1.1fr) 96px 88px 88px 104px minmax(88px, 0.9fr) 104px 104px 96px 32px;
}
.portfolio-page .pt-ctbl-action {
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.portfolio-page .pt-ctbl-row.pt-ctbl-head {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-secondary);
  border-bottom: 1px solid var(--border);
  padding-bottom: 7px;
}
.portfolio-page .pt-ctbl-row.pt-ctbl-head .pt-ctbl-tkr { text-align: left; }
.portfolio-page .pt-ctbl-row.pt-ctbl-head .pt-ctbl-num { text-align: right; }
.portfolio-page .pt-ctbl-row.pt-ctbl-data {
  border-bottom: 1px solid var(--border);
  transition: background 0.12s ease;
}
.portfolio-page .pt-ctbl-row.pt-ctbl-data:last-of-type { border-bottom: none; }
.portfolio-page .pt-ctbl-row.pt-ctbl-data:hover { background: rgba(255, 255, 255, 0.02); }
.portfolio-page .pt-ctbl-tkr {
  font-weight: 600;
  letter-spacing: 0.02em;
}
.portfolio-page .pt-ctbl-tkr-text { font-family: 'JetBrains Mono', monospace; }
.portfolio-page .pt-ctbl-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-ctbl-num .pt-htbl-pl { align-items: flex-end; }

/* ── Closed P/L row enrichment cells (TAN-684 ITEM 6c) ──
   Price Now + vs Exit / SPY-QQQ since exit / Alpha vs SPY. Stacked, right-
   aligned, tabular nums. Tone (.pt-pct-pos / .pt-pct-neg) is applied on the
   cell itself by _paintCloseEnrich and inherited by the figures. */
.portfolio-page .pt-ctbl-enrich {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  justify-content: center;
  line-height: 1.25;
  font-variant-numeric: tabular-nums;
}
.portfolio-page .pt-ctbl-enrich .pt-ce-now,
.portfolio-page .pt-ctbl-enrich .pt-ce-alpha { font-weight: 600; }
.portfolio-page .pt-ctbl-enrich .pt-ce-line { display: block; }
.portfolio-page .pt-ctbl-enrich .pt-ce-sub {
  font-size: 10.5px;
  color: var(--text-secondary);
}
/* When a tone is set on the cell, the sub/line figures follow it too. */
.portfolio-page .pt-ctbl-enrich.pt-pct-pos,
.portfolio-page .pt-ctbl-enrich.pt-pct-pos .pt-ce-sub { color: var(--emerald); }
.portfolio-page .pt-ctbl-enrich.pt-pct-neg,
.portfolio-page .pt-ctbl-enrich.pt-pct-neg .pt-ce-sub { color: #EF4444; }
/* Benchmark cell stays neutral regardless of direction. */
.portfolio-page .pt-ctbl-bench,
.portfolio-page .pt-ctbl-bench .pt-ce-sub { color: var(--text-secondary); }
/* TAN polish — SPY/QQQ font equalization. SPY and QQQ in the benchmark cell are
   peer values (% since exit), but QQQ carried .pt-ce-sub (font-size 10.5px)
   while SPY inherited the row's 13px, so SPY rendered larger. Restore QQQ to the
   peer size; scoped to .pt-ctbl-bench so the Price-Now "since exit" subline
   keeps its intentional smaller size. */
.portfolio-page .pt-ctbl-bench .pt-ce-line.pt-ce-sub { font-size: inherit; }
.portfolio-page .pt-ctbl-enrich .pt-ce-dash { color: var(--text-tertiary, rgba(160,174,192,0.5)); }

/* ── Closed P/L edit mode (TAN-684 follow-up) ──
   Inline-editable Shares-Closed / Exit-Price cells + per-row Delete, revealed
   ONLY under .pt-editmode (mirrors the Holdings in-place edit affordances). */
.portfolio-page .pt-ctbl-editable { cursor: default; }
.portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-editable {
  cursor: text;
  border-radius: 4px;
}
.portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-editable:hover {
  outline: 1px dashed var(--accent-blue, #3b82f6);
  outline-offset: 1px;
}
.portfolio-page .pt-ctbl-editable.pt-htbl-editing { outline: none; }
.portfolio-page .pt-ctbl-editable .pt-htbl-edit-input {
  width: 100%;
  text-align: right;
}
/* Per-row Delete — hidden in view mode, revealed under .pt-editmode. */
.portfolio-page .pt-ctbl-trash { display: none; }
.portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-trash { display: inline-flex; }

/* Empty-state placeholder shown when there are 0 closed lots. */
.portfolio-page .pt-closed-empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 44px 20px;
  text-align: center;
}
.portfolio-page .pt-closed-empty-icon { color: var(--text-faint, #5b606b); opacity: 0.7; }
.portfolio-page .pt-closed-empty-text {
  color: var(--text-secondary, #9aa0ad);
  font-size: 13px;
  max-width: 320px;
  line-height: 1.5;
}

/* TAN-684: Closed P/L is now a tab inside the consolidated .pt-row-positions
   card (which survives the first-view collapse above), so the standalone
   .pt-row-closed first-view rule is no longer needed — the tab button stays
   hidden until _renderClosedPl sees a realized row regardless of first-view. */

/* ── Nested closed-lots toggle + sub-rows under a holding ── */
.portfolio-page .pt-htbl-closes-toggle {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  margin-left: 6px;
  padding: 1px 6px;
  border: 1px solid var(--border);
  border-radius: 10px;
  background: transparent;
  color: var(--text-secondary);
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  cursor: pointer;
  transition: background 0.12s ease, color 0.12s ease;
}
.portfolio-page .pt-htbl-closes-toggle:hover {
  background: rgba(255, 255, 255, 0.04);
  color: var(--text-primary);
}
.portfolio-page .pt-htbl-closes-caret {
  display: inline-block;
  transition: transform 0.12s ease;
}
.portfolio-page .pt-htbl-closes-caret.pt-open { transform: rotate(90deg); }
.portfolio-page .pt-htbl-closes-count { font-weight: 600; }

.portfolio-page .pt-htbl-closelots {
  padding: 0 6px 8px 18px;
  border-bottom: 1px solid var(--border);
}
.portfolio-page .pt-htbl-closelots-inner {
  border-left: 2px solid var(--border);
  padding: 6px 0 2px 12px;
}
.portfolio-page .pt-htbl-closelots-title {
  font-family: 'JetBrains Mono', monospace;
  font-size: 9.5px;
  letter-spacing: 0.07em;
  text-transform: uppercase;
  margin-bottom: 4px;
}
.portfolio-page .pt-htbl-closelot-line {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 12px;
  padding: 3px 0;
  font-variant-numeric: tabular-nums;
  color: var(--text-secondary);
}
.portfolio-page .pt-htbl-closelot-date { min-width: 96px; }
/* TAN-684 ITEM 6a: the realized-P/L figure was pushed to the far right edge
   (margin-left:auto), where it visually landed under the NEXT ER column and
   read as disconnected from the close it belongs to. Keep it inline directly
   after the exit price so "250 sh @ $115.50 · +6,625" reads as one unit. */
.portfolio-page .pt-htbl-closelot-pl { font-weight: 600; }
.portfolio-page .pt-htbl-closelot-sep { color: var(--text-tertiary, rgba(160,174,192,0.5)); opacity: 0.6; }

/* ── Modify Positions — IN-PLACE edit mode (TAN-684 Matt redesign) ──
   The separate editor panel is gone. "Modify Positions" toggles edit mode in
   place: the existing Shares/Avg Cost/Cash cells become writable (CSS gating
   on .pt-editmode + the existing inline cell-edit handler) and the per-row
   Remove/Close controls + the retained footer Add (#1777) appear. The active
   button gets a gold tint to signal edit mode is on. Editable-cell shimmer +
   the affordance gating live alongside the table styles above. */
.portfolio-page .pt-modify-btn--active {
  background: rgba(251, 191, 36, 0.14);
  border-color: var(--gold, #FBBF24);
  color: var(--gold, #FBBF24);
}

/* ── Close prompt (layered modal for partial/full close) ──
   TAN-684 (Matt): restyled to match the app's modal design language — the same
   glassy dark surface / hairline border / soft glow / blurred scrim / fade+pop
   used by the .pt-pa-modal shell (TAN-589). Reuses the shared --surface /
   --border / --accent / --gold tokens and the .pt-btn / .pt-btn-primary buttons.
   Presentation only — all close functionality + the descriptive Realized P/L
   readout are unchanged. */
.pt-closeprompt-overlay {
  position: fixed;
  inset: 0;
  z-index: 1010;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(2, 6, 23, 0.72);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  animation: pt-pa-modal-fade 140ms cubic-bezier(0.16, 1, 0.3, 1);
}
.pt-closeprompt-panel {
  width: min(400px, 100%);
  background: var(--surface, #111827);
  border: 1px solid var(--border, #1e293b);
  border-radius: 14px;
  padding: 18px 20px 20px;
  /* Match the canonical .pt-pa-modal surface (the app's standard modal): same
     soft outer shadow + a faint accent ring glow instead of the neutral white
     inset, so the close prompt reads as a first-class app modal rather than a
     one-off. Mirrors the .pt-pa-modal box-shadow token at ~line 3541. */
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45), 0 0 0 1px rgba(139, 92, 246, 0.15);
  color: var(--text-primary, #e6e6ec);
  display: flex;
  flex-direction: column;
  gap: 12px;
  animation: pt-pa-modal-pop 160ms cubic-bezier(0.16, 1, 0.3, 1);
}
@media (prefers-reduced-motion: reduce) {
  .pt-closeprompt-overlay,
  .pt-closeprompt-panel { animation: none; }
}
/* Header row — ticker pill chip + uppercase monospace eyebrow caption. */
.pt-closeprompt-head {
  display: flex;
  align-items: center;
  gap: 10px;
}
.pt-closeprompt-pill {
  display: inline-flex;
  align-items: center;
  font-family: 'JetBrains Mono', monospace;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.04em;
  color: var(--text-primary, #f1f5f9);
  background: var(--surface-2, #1a2332);
  border: 1px solid var(--border, #1e293b);
  border-radius: 999px;
  padding: 3px 10px;
}
.pt-closeprompt-head .pt-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--text-faint, #64748b);
}
/* TAN-819: modal meta (shares held + avg cost) made more prominent.
   Was 12px/muted — easy to miss. Now 13px/white with a light rule below
   so it reads as reference data at a glance before filling the fields. */
.pt-closeprompt-meta {
  font-size: 13px;
  color: var(--text-primary, #F1F5F9);
  font-weight: 500;
  padding: 6px 0 10px;
  border-bottom: 1px solid rgba(148,163,184,0.12);
  margin-bottom: 4px;
  letter-spacing: 0.01em;
}
.pt-closeprompt-panel .pt-modify-field {
  display: flex;
  flex-direction: column;
  gap: 5px;
  font-size: 12px;
}
/* Uppercase letter-spaced monospace micro-label captions (design-language match). */
.pt-closeprompt-panel .pt-modify-lbl {
  font-family: 'JetBrains Mono', monospace;
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-faint, #64748b);
}
/* TAN-684 (2026-06-17): the close-position modal is appended to document.body,
   OUTSIDE .portfolio-page, so the canonical `.portfolio-page .pt-input` theme
   (lines 1824-1857) never reached its inputs — they rendered as raw white
   native number/text/date controls. Re-bind the EXACT same dark-input theme
   here scoped to the modal, plus dark-mode the native number spinner and the
   date-picker calendar indicator (the inline editors are number/text only, so
   the canonical block didn't cover type=date). Values mirror .pt-input. */
.pt-closeprompt-panel .pt-input {
  background: transparent;
  color: var(--text-primary);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 6px 10px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  box-sizing: border-box;
  min-width: 0;
  width: 100%;
  /* hint UA form controls (date picker, spinners) to render in dark mode */
  color-scheme: dark;
}
.pt-closeprompt-panel .pt-input::placeholder {
  color: var(--text-secondary);
  opacity: 0.7;
  text-overflow: ellipsis;
}
.pt-closeprompt-panel .pt-input[type="number"] {
  -moz-appearance: textfield;
  appearance: textfield;
}
.pt-closeprompt-panel .pt-input[type="number"]::-webkit-inner-spin-button,
.pt-closeprompt-panel .pt-input[type="number"]::-webkit-outer-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
/* Date picker: invert the (black) native calendar glyph so it reads on the dark
   fill, and brighten on hover for affordance. */
.pt-closeprompt-panel .pt-input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(0.8);
  cursor: pointer;
  opacity: 0.7;
}
.pt-closeprompt-panel .pt-input[type="date"]::-webkit-calendar-picker-indicator:hover {
  opacity: 1;
}
.pt-closeprompt-panel .pt-input:focus {
  outline: none;
  border-color: var(--blue);
}
.pt-closeprompt-proj {
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  padding: 8px 0 2px;
  border-top: 1px solid var(--border, #1e293b);
  margin-top: 2px;
}
.pt-closeprompt-actions { display: flex; justify-content: flex-end; gap: 8px; margin-top: 4px; }

/* TAN-895: Close-position modal footer buttons — explicit button styling,
   scoped to the modal so the shared .pt-btn* utilities used elsewhere are
   untouched. Cancel = ghost/muted, Record close = solid blue primary. */
.pt-closeprompt-actions #pt-cp-cancel,
.pt-closeprompt-actions #pt-cp-confirm {
  cursor: pointer;
  border-radius: 6px;
  font-size: 13px;
  padding: 6px 14px;
  transition: background 0.15s;
}
.pt-closeprompt-actions #pt-cp-cancel {
  border: 1px solid rgba(255, 255, 255, 0.15);
  background: transparent;
  color: #94a3b8;
}
.pt-closeprompt-actions #pt-cp-cancel:hover {
  border-color: rgba(255, 255, 255, 0.3);
  color: #94a3b8;
}
.pt-closeprompt-actions #pt-cp-confirm {
  background: #3b82f6;
  border: 1px solid #3b82f6;
  color: #fff;
}
.pt-closeprompt-actions #pt-cp-confirm:hover {
  background: #2563eb;
  border-color: #2563eb;
  filter: none;
}

/* TAN-895: Realized P/L line — green when positive, red when negative.
   updateProj() toggles .pt-pct-pos / .pt-pct-neg on this element. */
.pt-closeprompt-proj.pt-pct-pos { color: #22c55e; }
.pt-closeprompt-proj.pt-pct-neg { color: #ef4444; }

@media (max-width: 767px) {
  .pt-closeprompt-overlay { padding: 12px; align-items: center; }
  .pt-closeprompt-panel { width: 100%; }
}

@media (max-width: 768px) {
  .portfolio-page .pt-ctbl-row {
    grid-template-columns: minmax(64px, 1fr) 72px 68px 68px 88px minmax(74px, 0.9fr) 84px 84px 78px 0px;
    font-size: 11.5px;
    gap: 6px;
  }
  .portfolio-page #pt-panel-closed.pt-editmode .pt-ctbl-row {
    grid-template-columns: minmax(64px, 1fr) 72px 68px 68px 88px minmax(74px, 0.9fr) 84px 84px 78px 30px;
  }
}
