/* overlay.css — P2 layout for the overlay's 13-block tree.
 * Colors come ONLY from tokens.css custom props (theme-swappable). Geometry
 * mirrors the dense tkinter overlay (compact fonts, 2px bars, 3×2 metric grid).
 * No invented chrome: every node maps to an overlay.py widget (see overlay.html
 * data-block comments). Owner bar: "o mais próximo possível do original".
 */

* { box-sizing: border-box; margin: 0; padding: 0; }

html, body {
  height: 100%;
  background: var(--bg);
  color: var(--text);
  /* Font is config-driven via PUSH (P5a): the host sets --ovl-font-family /
     --ovl-font-size on :root when the config §02 font controls change — NO
     window recreate. The fallbacks here are the original hardcoded values, so
     the DEFAULT (no override pushed) renders byte-identically to P2. */
  font-family: var(--ovl-font-family, Tahoma, "Segoe UI", system-ui, sans-serif);
  font-size: var(--ovl-font-size, 13.3px);
  -webkit-font-smoothing: antialiased;
  overflow: hidden;
}

/* ── Block 1 — outer chrome ─────────────────────────────────────────── */
.ovl-border {                 /* border color = FIXA (owner 16-09-2026): one colour whatever the link/lock state */
  height: 100%;
  background: var(--locked-border);
  padding: 7px;               /* BUG-01 — match the scanner's chrome border width (web/index.html body border:7px #666666 = tk BORDER_PX 7). Owner: "mesma largura e cor da borda do scanner". This is also the 7px resize-strip band (the 8 edge handles below are sized to it). */
  position: relative;         /* anchors the 8 P5b edge-resize handles */
}
/* Border colour NO LONGER follows link/lock state (owner 16-09-2026: "muitos
   usuários deixam sem travar e fica feio com a cor"). The old data-linked /
   data-locked recolour rules on the border are GONE on purpose — guarded by
   test_overlay_css_has_p5b_rules. data-linked / data-locked still drive the
   edge handles, header buttons and the link pill. */
.ovl-inner {
  height: 100%;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

/* ── Block 2 — header (HDR_H≈28) ────────────────────────────────────── */
.ovl-header {
  display: flex;
  align-items: center;
  height: 28px;
  padding: 0 6px 0 8px;
  background: var(--header-bg);
  flex: none;
}
.hdr-ticker { font-size: 1.3em; font-weight: 700; color: var(--text); margin-right: 10px; }   /* owner: more breathing room between header infos */
.hdr-mcap { font-size: 1em; font-weight: 700; margin: 0 6px; }
.hdr-flag { font-size: 1em; line-height: 1; margin: 0 7px; }
.hdr-flag svg { display: inline-block; width: 20px; height: 14px; vertical-align: middle; border: 1px solid rgba(0,0,0,.35); border-radius: 1px; }
/* Real bundled flag image (flags/<iso>.svg via PANDA_FLAGS) — same 20x14 box as
   the legacy inline svg so the header layout is unchanged; object-fit keeps the
   4:3 art crisp inside the slot. */
.hdr-flag img.pflag { display: inline-block; width: 20px; height: 14px; object-fit: cover; vertical-align: middle; border: 1px solid rgba(0,0,0,.35); border-radius: 1px; }
.hdr-warn-country { color: var(--warn-color); font-size: 1em; font-weight: 700; }
/* Incorporation tag ("Inc:KY") — HQ+Inc 2026-08-23; cor inline via JS
   (toxic offshore / dim estado US / caution estrangeiro comum). */
.hdr-inc { font-size: .85em; font-weight: 700; margin: 0 4px; white-space: nowrap; }
.hdr-adr { font-size: 1em; font-weight: 700; margin: 0 6px; }
.hdr-spacer { flex: 1; }
.hdr-btn {
  background: transparent; border: none; cursor: pointer;
  color: var(--text-dim); font-size: 1em; line-height: 1;       /* HB1 — C_DIM (overlay.py L1377) */
  padding: 1px 5px; border-radius: 0;       /* HB5 — padx=5 pady=1, no radius (overlay.py L1378-1381) */
  font-variant-emoji: text;                 /* force monochrome emoji → inherit the CSS color (🔗/🔓 like tk Segoe UI Symbol) */
}
#btnRefresh { color: var(--accent); }   /* HB2 — C_ACCENT (overlay.py L1390) */
#btnCollapse { color: var(--text); }    /* HB3 — C_TEXT (overlay.py L1397) */
/* HB4 — no hover: the header buttons are tk.Labels (no hover state). */

/* The HTML `hidden` attribute must always win — even over a class that sets
   `display` (the flex bar below). Without this, show(id,false) on the
   update-bar leaves an EMPTY coloured bar visible (a class
   selector's `display:flex` beats the UA `[hidden]{display:none}`). */
[hidden] { display: none !important; }

/* ── Block 3 — full-width bar ──────────────────────────────────── */
.ovl-update-bar { background: var(--update-bar-bg); color: var(--update-bar-fg); }
.ovl-update-bar {
  flex: none; padding: 0; font-size: 1em; font-weight: 700;
  text-align: center;
  display: flex; align-items: center; justify-content: center;
}
.ovl-update-bar { height: 22px; }

/* ── Block 4 — score + sector subheader ─────────────────────────────── */
.ovl-score-sector {
  display: flex; align-items: center;
  padding: 3px 6px; background: var(--bg); flex: none;   /* SS1 — padx=6, pady 0→3 top+bottom: tk score_sector Labels are _afont(-1)=Tahoma10 with ~17px line leading the web row collapsed to ~13.3px; +6px restores the strip height (overlay.py L1419-1430) */
}
.score-label { font-size: 1em; font-weight: 700; }
.sector-label { margin-left: auto; font-size: 1em; text-align: right; }
.ai-insight-btn {
  background: transparent; color: var(--accent-glow); border: none;          /* AI1 — tk.Label, fg=accent_glow, no bg/border/radius/padding (overlay.py L545-549) */
  font-size: 1em; font-weight: 700; cursor: pointer;
  padding: 0; border-radius: 0; display: inline-flex; align-items: center; gap: 4px;
  margin: 0 4px;          /* AI-INSIGHT frame padx=(4,4) — 4px each side (overlay.py L539) */
}
.ai-insight-btn.ai-inert { cursor: default; opacity: .8; }
/* AI2 — status is a TEXT glyph ●/⏳/⚠ on the same baseline (overlay.py L554-559),
   NOT a CSS circle. JS sets dot.textContent per FSM state (idle ""/busy ⏳/ready ●/
   error ⚠); the color comes from the dot-state classes below.
   BUG-03 — render the glyphs as MONOCHROME TEXT, not colour emoji: give the dot the
   symbol-font fallback tkinter itself uses (Segoe UI Symbol) + force text presentation
   so ⏳ (U+23F3) / ● (U+25CF) / ⚠ (U+26A0) resolve to glyphs that pick up the
   .ai-dot-* colour below. Without this, the trader font (Tahoma) has no ⏳ and the
   busy/ready states rendered blank — the FSM glyph map in overlay.js was already
   correct (matches overlay.py L744-749: ⏳ loading / ● ready / ⚠ error). */
.ai-status-dot {
  display: inline;
  font-family: "Segoe UI Symbol", "Segoe UI Emoji",
    var(--ovl-font-family, Tahoma, "Segoe UI", system-ui, sans-serif);
  font-variant-emoji: text;
}
/* Insight FSM dot color (overlay.py _on_insight_state_change): ready green, error
   red — the EXACT hexes (#44dd44 / #dd4444), not the score tokens (AI4). Busy is
   the static ⏳ glyph (no pulse — AI3). */
.ai-status-dot.ai-dot-idle { color: var(--text-dim); }
.ai-status-dot.ai-dot-busy { color: var(--score-caution); }
.ai-status-dot.ai-dot-ready { color: #44dd44; }
.ai-status-dot.ai-dot-error { color: #dd4444; }

/* ── Block 5 / 6 — slide stage + native scroll ──────────────────────── */
.ovl-stage { position: relative; flex: 1; overflow: hidden; }
.stage-view { position: absolute; inset: 0; transition: transform .234s cubic-bezier(0.215, 0.61, 0.355, 1); }  /* SL1 — ImageGrab slide steps=26 delay=9 ≈ 234ms ease-out-cubic (overlay.py L941-954) */
/* Default (ticker) state: ticker-view fills the stage, insight-view parked off
   the right edge. The .234s ease-out-cubic transition on .stage-view animates
   the swap (overlay.py _animate_stage_slide direction=+1: outgoing slides left
   off the stage, incoming reveals from the right). */
.ticker-view { transform: translateX(0); }
.insight-view { transform: translateX(100%); }
/* SLIDE state — html[data-view="insight"] (overlay.py _show_insight direction=+1).
   The ticker-view slides OUT to the left (-100%); the insight-view slides IN to
   x=0. Reverting to data-view="ticker" (the default rules above) runs the same
   transition in reverse (overlay.py _show_ticker_data direction=-1). The own
   .ovl-scroll inside ticker-view keeps its native scroll position across the
   slide (the transform doesn't reset it), matching the tk view-cache. */
html[data-view="insight"] .ticker-view { transform: translateX(-100%); }
html[data-view="insight"] .insight-view { transform: translateX(0); }
.ovl-scroll { height: 100%; overflow-y: auto; overflow-x: hidden; padding: 0 6px 4px; }
.ovl-scroll::-webkit-scrollbar { width: 7px; }
.ovl-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }

/* ── Block 8 — metrics grid (3×2, responsive) ───────────────────────── */
/* C-FIX (inter-row spacing) — the ORIGINAL spaces rows more than the web:
   (1) tk rowconfigure(minsize=ROW_MIN=58) is a FLOOR, not a fixed track — the
       card grows to content+pady. So grid-auto-rows is minmax(58px,auto), not a
       hard 58px cap (overlay.py L1250/1465).
   (2) each _card is grid()'d with pady=CARD_PADY=2 → 2+2 = 4px inter-row gap →
       row-gap:4px (already matched). column-gap = CARD_PADX 2+2 = 4px, NOT 6
       (overlay.py L1251/1289).
   (3) the whole grid has a 4px top gap (DF_PADY_T=(4,0); overlay.py L1280/1458)
       → margin-top:4px. */
.metrics-grid { display: grid; grid-template-columns: repeat(3, 1fr); column-gap: 4px; row-gap: 4px; grid-auto-rows: minmax(62px, auto); margin-top: 6px; margin-bottom: 2px; }  /* floor 58→62px: tk rowconfigure minsize=ROW_MIN=58 is a FLOOR; with the +8px label→value gap + tk leading the real tk cell is ~60-62px. margin-top 4→6: tk strip-bottom leading + DF_PADY_T=(4,0) above first card row (overlay.py L1280/1458). margin-bottom 0→2: tk bottom card row keeps CARD_PADY=2 below it (overlay.py L1289) */
@media (max-width: 300px) { .metrics-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 200px) { .metrics-grid { grid-template-columns: 1fr; } }
.metric-card {
  background: var(--card-bg);
  display: flex; flex-direction: column;   /* lets .metric-bar drop to the card bottom via margin-top:auto */
  padding: 5px 8px 6px;   /* INNER_PADX=8 / INNER_PADY_T=5 / BAR_PADY_B=6 (overlay.py); borderless square tk.Frame */
}
.metric-top { display: flex; align-items: baseline; gap: 4px; }
.metric-label { font-size: 1em; font-weight: 700; color: var(--label); line-height: 1.3; white-space: nowrap; }  /* tk Tahoma10 ~17px line box (F_LBL=-2 clamps to 10pt); line-height:1.3 ≈17.3px restores tk leading on the label row */
.metric-sub { font-size: 1em; color: var(--text); margin-left: auto; }
/* C-FIX — value row vertical pad = pady=(2, VAL_PADY_B=3) in the original
   (overlay.py L1255/1478): 2px above + 3px below the value. The web had only
   the 2px above; the missing 3px below adds card height (rows now grow via the
   minmax floor above), pushing the stacked rows apart like the original. */
.metric-valrow { display: flex; align-items: center; gap: 3px; margin-top: 8px; margin-bottom: 3px; }  /* margin-top 2→8px: tk label-row→value-row visual pitch ≈16px (label trailing leading on Tahoma10 17px line box + val pack pady top=2px); web measured ~10px → +6px restores the gap */
.metric-val { font-size: 1em; font-weight: 700; line-height: 1.3; }  /* tk Tahoma10 ~17px value-row line box (F_VAL=0→10pt); line-height:1.3 ≈17.3px matches tk's value-row leading */
/* M3 — Float/Split value is right-aligned (anchor=e / side=right; overlay.py L1502,1546). */
.metric-card[data-metric="Float"] .metric-val,
.metric-card[data-metric="Split"] .metric-val { margin-left: auto; }
.warn-float, .warn-split { color: var(--warn-color); font-size: 1em; font-weight: 700; }
.split-date { font-size: 1em; color: var(--text-dim); margin-left: auto; }
.metric-bar { height: var(--bar-h); background: var(--surface-high); margin-top: auto; border-radius: 0; overflow: hidden; }  /* M4 — track surface_high, rect; margin-top:auto drops the bar to the card bottom (pady=(0,BAR_PADY_B), ROW_MIN=58) */
.metric-bar > i { display: block; height: 100%; width: 0; }

/* ── Block 9 — Dilution & Risk Ratings ──────────────────────────────── */
/* B-FIX — the whole Dilution & Risk block sits on a C_SURFACE #161616 BAND in
   the original (_dil_outer bg=C_SURFACE; every child frame is #161616) against
   the #000000 page (overlay.py L1578-1631). The web children stay transparent,
   so the surface band shows through behind the Overall row + ratings grid. */
.dt-risk-group { margin-top: 8px; background: var(--surface); }
.overall-row { display: flex; align-items: center; justify-content: center; gap: 8px; padding: 8px 0 6px; }  /* R2 — CENTERED, pady=(8,6), label→pill gap 8 (overlay.py L1589-1601) */
.overall-label { font-size: 1em; font-weight: 700; color: var(--text-muted); text-transform: none; }  /* R3 — fg=text_muted, mixed-case "Overall Dilution Risk" (overlay.py L1593) */
.hdivider { height: 1px; background: var(--separator); margin: 0 10px; }
.ratings-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 8px 0; margin: 2px 0 8px; }  /* bottom 6→8: tk grid pady=(2,GRID_PADY_B=6) + cell bottom leading before _dt_only_group (overlay.py L1608) */
.rating-cell { display: flex; align-items: center; justify-content: space-between; padding: 6px 10px; }  /* R6 — inner padx=10, pady 4→6: tk CELL_PADY=4 + the 22px PillBadge leading taller than the web cell's flat 4px (overlay.py L1616) */
/* R6 — vertical divider on col-0 cells: relheight=0.75 y=5 vdiv between the two
   columns (overlay.py L1626-1627). Odd children (1st, 3rd, …) are the left col. */
.ratings-grid .rating-cell:nth-child(odd) { position: relative; }
.ratings-grid .rating-cell:nth-child(odd)::after {
  content: ""; position: absolute; right: 0; top: 5px; height: 75%; width: 1px;
  background: var(--separator);
}
.rating-name { font-size: 1em; color: var(--text-muted); white-space: nowrap; }
/* CSS-P1..P5 — pill = FILLED badge (_PillBadge canvas: fill=pill_bg + text=pill_fg,
   min 120×22, stadium radius; overlay.py _set_dt L2453-2462 sets bg/fg by risk class). */
/* B-FIX (pill geometry) — the original _PillBadge is a 120×22 tk.Canvas whose
   PAINTED stadium is INSET: pad=6 transparent side gutter + the polygon rect is
   y1=2..y2=h-2 (widgets.py L42-87). So the visible fill is 108×18 centered in a
   120×22 footprint, and the 6px/2px gutter shows the canvas outer_bg = C_SURFACE
   #161616 (now the .dt-risk-group band). Modelled here as margin:2px 6px so the
   layout/alignment footprint stays 120×22 (margin-box) while the painted box is
   108×18 min and the gutter is transparent → the #161616 band shows through. */
.pill {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 108px; height: 18px; line-height: 18px; margin: 2px 6px; padding: 0 6px;
  border-radius: 9px; font-weight: 700; font-size: 1em;
}
.pill.risk-low { background: var(--badge-low); color: var(--badge-low-fg); }      /* P2 — badge_low / _fg */
.pill.risk-med { background: var(--badge-med); color: var(--badge-med-fg); }      /* P3 — badge_med / _fg */
.pill.risk-high { background: var(--badge-high); color: var(--badge-high-fg); }   /* P4 — badge_high / _fg */
.pill.risk-none { background: var(--card-bg); color: var(--text); }               /* P5 — no match → card_bg / text */
/* All 5 pills (Overall + 4 sub) share BADGE_W_RAT = BADGE_W_OVR = 120px lower
   bound (overlay.py / widgets.py PillBadge never shrinks below it) — sub-pills
   inherit the base 120px min, no narrower override. */

/* ── Block 10 — DT-only: financials + instruments ───────────────────── */
.dt-only-group { margin-top: 10px; }  /* 8→10: tk SEC_SPACER_H=8 spacer frame THEN first fin _card row pady=(INNER_PADY_T=5,…) on a Tahoma10 line taller than the web's flat 5px (overlay.py L1639-1650) */
/* Fin cells use the SAME _card helper → grid padx=CARD_PADX=3 (3+3=6px between
   the two columns) + pady=CARD_PADY=2 (2+2=4px between rows) (overlay.py
   L1251-1252/1647). column-gap 6px / row-gap 4px to match. */
.fin-grid { display: grid; grid-template-columns: 1fr 1fr; column-gap: 6px; row-gap: 4px; }
.fin-cell { display: flex; align-items: center; justify-content: space-between; background: var(--surface); padding: 6px 8px 7px; }  /* 5/6→6/7: tk fin row pady=(INNER_PADY_T=5,FIN_PADY_B=6) + Tahoma10 leading runs a couple px taller than the web's flat pad (overlay.py L1649-1650) */
.fin-name { font-size: 1em; color: var(--text-muted); white-space: nowrap; }   /* tk labels have no wraplength → single-line (e.g. "GC e NASDAQ") */
.fin-val { font-size: 1em; font-weight: 700; white-space: nowrap; }            /* tk values never wrap (e.g. "True / True") */

.ovl-section { margin-top: 10px; border: 1px solid var(--news-lts-border); overflow: hidden; }  /* S1 — 1px outer frame (#555555 via --news-lts-border, tokens.css L72 = the DAS BLACK .get fallback; overlay.py L1311-1319), body surface. margin-top 8→10: tk _section pady=(SEC_PADY_T=8,0) + header strip Tahoma leading before body (overlay.py L1316) */
.section-hdr { display: flex; align-items: center; gap: 6px; background: var(--news-lts-hdr-bg); padding: 3px 6px; border-bottom: none; }  /* S2 — filled header strip padx=6 pady=3 (overlay.py L1322-1326) */
.section-title { font-size: 1em; font-weight: 700; color: var(--news-lts-fg); text-transform: uppercase; }  /* S3 — fg=news_lts_fg, .upper() in Python (overlay.py L1324) */
.section-body { padding: 0 6px 4px; }
/* §6 — the Why title is per-theme-cased by the JS (whyMoving): UPPERCASE for
   das-black, mixed-case for das-white/das-blue. Scope text-transform:none here so
   the JS-provided casing wins; the shared .section-title uppercase still governs
   the always-upper DILUTION INSTRUMENTS header. */
#whyTitle { text-transform: none; }
/* Instruments host + _w2_container are bg=C_SURFACE #161616 (overlay.py
   L1678/1680) — a graphite band behind the black instrument rows. Web body was
   transparent (showed pure #000000); paint it #161616 so the rows read as a
   black inset ON a graphite panel (the original look). Scoped to the instruments
   body so the Why-section (own .why-frame inset) is unaffected.
   _w2_container packs padx=INNER_PADX-2=6 + host padx=3 → ~9px L/R inset; top
   inset = container pady 6 → 6px above the first "Warrants:" row; bottom inset =
   container pady 6 + body pady-bottom SEC_BODY_PAD 4 → 10px below the last row
   (overlay.py L1329/1679/1682-1683). */
#instrumentsBody { background: var(--surface); padding: 6px 9px 10px; }
.instr-row { display: flex; align-items: center; min-height: 22px; gap: 0; font-size: 1em; background: var(--bg); }  /* INS3 — row bg=t["bg"] #000000 (overlay.py L2357); row.pack() has NO pady (L2358); min-height:22px = measured tk row.winfo_height (Tahoma10 linespace16 + Label internal pad); align-items:center = tk Label vertical centering in the 22px cell */
.instr-type { color: var(--label); min-width: 10ch; font-size: 1em; }  /* INS1 — width=10 chars (overlay.py LBL_W=10, _font(-1) normal); ch-based to track the config font */
.instr-detail { color: var(--text); }  /* INS2 — t["text"] (overlay.py L2364) */

/* ── Block 11 — Why Stock Moving ────────────────────────────────────── */
.why-catalyst { font-size: 1em; font-weight: 700; margin-left: auto; }
.why-frame { padding: 7px 8px; }  /* tk why_frame pack pady=7 (overlay.py L1693). NO max-width: at the 440px compare width the tk live render wraps the headline to 2 lines (full frame width) — the web must wrap the SAME, not a forced narrow 3-line wrap. */
.why-headline { font-size: 1em; font-weight: 700; color: var(--text); line-height: 1.2; }  /* tk _afont(-1,bold)=Tahoma10 linespace=16px (PIL getmetrics 13+3) = ratio 1.20 at 13.3px base; wraps at full frame width like tk (2 lines @440px) */
.why-summary { font-size: 1em; color: var(--text-muted); line-height: 1.2; margin-top: 3px; }  /* tk _afont(-2)=Tahoma10 same 16px box (ratio 1.20); margin-top:3px = summary pady=(3,0); wraps at full frame width like tk */
/* Expanded Finviz-style bullet list (overlay.js _applyWhyText): one .why-li per
   "- " line of the AI summary; key figures come wrapped in <b>. Collapsed
   preview stays a plain truncated line, so these only apply expanded. */
.why-summary .why-li { display: flex; gap: 6px; margin-top: 4px; line-height: 1.3; }
.why-summary .why-li:first-child { margin-top: 0; }
.why-summary .why-li-dot { flex: none; }
.why-summary .why-li-text { flex: 1 1 auto; min-width: 0; }
.why-summary b { font-weight: 700; color: var(--text); }

/* ── Block 12 — news zones ──────────────────────────────────────────── */
/* C-FIX — each zone border.pack(pady=(top,3)) has a 3px gap BELOW it too
   (overlay.py L1184/1192); the web only had the margin-top. Add margin-bottom:3px
   so the effective inter-zone gap = 3 (below upper) + margin-top (above lower). */
.news-zone { border: 1px solid; border-radius: 0; overflow: hidden; margin-bottom: 3px; }   /* N2 — tk zones are rectangular */
.news-breaking { border-color: var(--news-brk-border); background: var(--news-brk-bg); margin-top: 10px; }
.news-recent { border-color: var(--news-rec-border); background: var(--news-rec-bg); margin-top: 4px; }
.news-latest { border-color: var(--news-lts-border); background: var(--news-lts-bg); margin-top: 4px; }
/* Notícias unificadas (dono 03-09): as duas zonas legadas ficam vazias e o
   show() as marca [hidden], então o bloco perderia o respiro de entrada que
   vinha do .news-breaking e colaria na seção de cima. */
.news-breaking[hidden] + .news-recent[hidden] + .news-latest { margin-top: 10px; }
.news-hdr { display: flex; align-items: center; gap: 5px; padding: 0 4px; min-height: 22px; }   /* tk zone header band = _font(-1,bold) Tahoma10 Label height ≈22px (overlay.py L1012-1018) */
.news-breaking .news-hdr { background: var(--news-brk-hdr-bg); }
.news-recent .news-hdr { background: var(--news-rec-hdr-bg); }
.news-latest .news-hdr { background: var(--news-lts-hdr-bg); }
.news-hdr-title { font-size: 1em; font-weight: 700; }
.news-breaking .news-hdr-title { color: var(--news-brk-fg); }
.news-recent .news-hdr-title { color: var(--news-rec-fg); }
.news-latest .news-hdr-title { color: var(--news-lts-fg); }
.news-count { font-size: 1em; font-weight: 700; color: var(--text-muted); }
/* CSS-N1 — news-count fg = zone fg + bold (overlay.py L1016-1059) */
.news-breaking .news-count { color: var(--news-brk-fg); }
.news-recent .news-count { color: var(--news-rec-fg); }
.news-latest .news-count { color: var(--news-lts-fg); }
/* C-FIX — each news row.pack(pady=1) → 1px top + 1px bottom = 2px effective gap
   between rows (overlay.py L223). CSS gap is the single inter-item space → 2px. */
.news-body { padding: 0 2px 2px; display: flex; flex-direction: column; gap: 2px; }
/* No uniform row gap — each pill carries the EXACT tk padx as an external margin
   (transparent), with the colored pill's internal padding emulating the literal
   " {tag} " / " {src} " space glyphs (overlay.py L233/242). Separating the two
   matches the original 1:1 (padx = margin between pills; spaces = pill padding). */
.news-row { display: flex; align-items: center; gap: 0; font-size: 1em; line-height: 1.25; min-height: 22px; }  /* tk news row Frame = Tahoma10 Label height ≈22px (same as the verified 22px instrument row, overlay.py L222-268); align-items:center vertically centers pills+headline+time like tk */
.news-src { font-size: 1em; font-weight: 700; padding: 0 4px; margin: 0 4px 0 2px; border-radius: 0; background: var(--news-src-other-bg); color: var(--news-src-fg); flex: none; }   /* N7 — rect Label, text " {src} " (padding), padx=(2,4) (margin) */
.news-src.is-sec { background: var(--news-src-sec-bg); }
.news-bias + .news-src { margin-left: 0; }   /* JS-11 — src padx left = 0 when a bias badge precedes (overlay.py L245 padx=(0 if tag else 2, 4)) */
.news-bias { font-size: 1em; font-weight: 700; padding: 0 4px; margin: 0 3px 0 2px; border-radius: 0; flex: none; }   /* N8 — rect Label, text " {tag} " (padding), padx=(2,3) (margin) */
.bias-short { background: var(--bias-short-bg); color: var(--bias-short-fg); }
.bias-long { background: var(--bias-long-bg); color: var(--bias-long-fg); }
.bias-neutral { background: var(--bias-neutral-bg); color: var(--bias-neutral-fg); }
/* Row visual order: [bias] [src] headline(grows) time(right). The headline is
   appended after the time element in the DOM (overlay.py packs time side=right
   first), so flex `order` restores the visual order: badges 0, headline 1,
   time 2 (pushed right by the headline's flex-grow). */
.news-time { font-size: 1em; color: var(--text-muted); flex: none; order: 2; margin: 0 2px 0 4px; }   /* AGE padx=(4,2) (margin) */
.news-head { color: var(--text); flex: 1; min-width: 0; order: 1; line-height: 1.25; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }  /* tk _font(-2)=Tahoma10 single-line row height = font linespace ≈16.6px (overlay.py L264-265); prior tight default made rows shorter than tk */
.news-head.expanded { white-space: normal; overflow: visible; }

/* ── Block 13 — loading (overlay.py show_loading L1842) ───────────────────
   The original centers a "Loading..." tk.Label over the content_frame via
   place(relx=.5, rely=.5, anchor="center") with bg=C_BG (panel bg) while the
   ticker loads (BUG-02). As a direct child of the position:relative .ovl-stage,
   inset:0 + flex-center reproduce the centered label; the opaque --bg hides the
   previous ticker's data behind it (tk show_loading also clears every field).
   font-size 1.1em ≈ tk _afont(1) (base+1); text-muted ≈ C_MUTED. The [hidden]
   rule above (display:none !important) keeps it hidden when not loading. */
.ovl-loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--bg);
  color: var(--text-muted);
  font-size: 1.1em;
  z-index: 5;
}

/* ══ P5b — edge-resize handles (overlay.py _setup_edge_resize) ════════════
   8 invisible strips/corners on .ovl-border driving api.overlay_resize. Side
   strips are sized to the 7px border band (BUG-01 — was 5px); corners are ~2×
   so they read as resize grips and protrude past the side strips (overlay.py
   _setup_edge_resize place_kw + the index-4 tkraise).
   The cursors mirror tkinter's size_we / size_ns / size_nw_se / size_ne_sw. */
.ovl-edge { position: absolute; z-index: 10; background: transparent; }
.ovl-edge-e { top: 7px; bottom: 7px; right: 0; width: 7px; cursor: ew-resize; }
.ovl-edge-w { top: 7px; bottom: 7px; left: 0; width: 7px; cursor: ew-resize; }
.ovl-edge-s { left: 7px; right: 7px; bottom: 0; height: 7px; cursor: ns-resize; }
.ovl-edge-n { left: 7px; right: 7px; top: 0; height: 7px; cursor: ns-resize; }
.ovl-edge-se { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; z-index: 11; }
.ovl-edge-nw { left: 0; top: 0; width: 14px; height: 14px; cursor: nwse-resize; z-index: 11; }
.ovl-edge-ne { right: 0; top: 0; width: 14px; height: 14px; cursor: nesw-resize; z-index: 11; }
.ovl-edge-sw { left: 0; bottom: 0; width: 14px; height: 14px; cursor: nesw-resize; z-index: 11; }
/* No resize while locked — the strips stop responding (overlay.py _rs_start
   `if self._locked: return`), and the corner grips shrink flush to the border
   (overlay.py _apply_corner_grips: EDGE*2 → EDGE when locked). */
html[data-locked="1"] .ovl-edge { pointer-events: none; cursor: default; }

/* ══ P5b — collapse state (overlay.py _toggle_collapse) ═══════════════════
   The geometry (header-only height) is the host's authoritative window.resize;
   the JS hides .ovl-stage so only the header shows. This rule is a belt-and-
   suspenders clamp so the body can't paint past the collapsed frame. */
html[data-collapsed="1"] .ovl-inner { overflow: hidden; }
html[data-collapsed="1"] .ovl-stage { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   AI INSIGHT PANEL (v6.3) — port of ui/insight_renderer.py
   ══════════════════════════════════════════════════════════════════════
   build_panel: a fixed header bar (age badge + 🔄 Reload) packed BEFORE the
   scrollable accordion (insight_renderer L1069-1163). The .insight-view keeps
   its slide transform (above); flex-column makes the header fixed at the top
   while the scroll area fills the rest, mirroring the tk header-then-canvas
   layout. DAS BLACK tokens, SQUARE borders, every label 1em (the tk _font
   helper clamps negative deltas to 0 → bold + colour are the ONLY hierarchy). */
.insight-view { display: flex; flex-direction: column; background: var(--bg); }

/* Header bar — bar.pack(pady=(2,4) padx=4) (insight_renderer L1005). Age badge
   left, 🔄 Reload right. */
.insight-header { display: flex; align-items: center; flex: none; padding: 2px 4px 4px; }
/* age label pack side=left padx=(2,0); muted_text fresh, score_caution stale
   (insight_renderer L1017-1028). "• Nm ago" fresh / "⚠ …" stale (>4h). */
.insight-age { font-size: 1em; color: var(--text-muted); padding-left: 2px; }
.insight-age.stale { color: var(--score-caution); }
/* 🔄 Reload pack side=right padx=(0,4); accent_glow, bold, hand cursor
   (insight_renderer L1031-1040). tk.Label → no bg/border/radius. */
.insight-reload { margin-left: auto; padding-right: 4px; font-size: 1em; font-weight: 700;
  color: var(--accent-glow); cursor: pointer; }

/* Scroll container — the tk Canvas + inner Frame (wheel-only, no scrollbar).
   The web uses native overflow; the accordion lives inside. */
.insight-scroll { flex: 1; min-height: 0; overflow-y: auto; overflow-x: hidden; }
.insight-scroll::-webkit-scrollbar { width: 7px; }
.insight-scroll::-webkit-scrollbar-thumb { background: var(--border-strong); border-radius: 4px; }
/* acc.pack(fill=x padx=4 pady=4) (insight_renderer L1163). */
.insight-accordion { padding: 4px; }

/* ── Accordion section (insight_renderer.Accordion + widgets.make_section) ──
   outer 1px border frame (card_border #262626) → header strip
   (panel_header_bg #0a0a0a) → body surface (card_bg #161616). SQUARE borders.
   outer_pady=(4,0) → margin-top 4px; first section's margin collapses fine. */
.ins-section { margin-top: 4px; border: 1px solid var(--card-border); background: var(--card-bg); overflow: hidden; }
.ins-section:first-child { margin-top: 0; }
/* header strip — whole strip is click-to-toggle (cursor=hand2). hdr padding
   mirrors title_lbl pack padx=6 pady=3 (widgets.make_section L156). */
.ins-sec-hdr { display: flex; align-items: center; gap: 4px; background: var(--panel-header-bg);
  padding: 3px 6px; cursor: pointer; user-select: none; }
/* chevron ▸ collapsed / ▾ open — accent (section_title), bold, pack padx=(2,4)
   (insight_renderer L201-204). */
.ins-sec-chevron { font-size: 1em; font-weight: 700; color: var(--section-title); flex: none; width: 1em; text-align: center; }
/* section title — section_title fg, bold, .upper() (widgets.make_section L154). */
.ins-sec-title { font-size: 1em; font-weight: 700; color: var(--section-title); text-transform: uppercase; white-space: nowrap; }
/* right-aligned pill/peek group (insight_renderer packs side=right). header
   pills pack padx=(1,3) (insight_renderer L220) → ~4px margin + each canvas's
   pad=2 gutter ≈ 8px between visible pill fills; gap 3→6 (the +2 fill padding
   each side already lives in .ins-pill). */
.ins-sec-right { margin-left: auto; display: flex; align-items: center; gap: 6px; flex: none; }
/* plain-text peek (header_text, e.g. "0.95 - 0.12 - …"); text fg, bold, no pill
   (insight_renderer L226-229). */
.ins-sec-peek { font-size: 1em; font-weight: 700; color: var(--text); white-space: nowrap; }
/* section body — card_bg surface; _expand packs body pady=(6,6) (insight_renderer
   L274) + section body L/R inset. Collapsed bodies are hidden (lazy-built). */
.ins-sec-body { background: var(--card-bg); padding: 6px; }
.ins-sec-body[hidden] { display: none; }

/* ── header pills (PillBadge — same theme tokens as the ticker overlay's
   HIGH/LOW/MEDIUM risk badges; insight_labels sentiment_pill_colors L272).
   SQUARE-ish small pill, bold, every label 1em. ─────────────────────── */
/* PillBadge geometry (widgets.py L52-87): the filled pill width auto-sizes to
   `font.measure(text) + 12` → 6px of fill padding on EACH side of the text, and
   the pill never shrinks below its per-call `width` floor (120/200/70/90/60px →
   short labels sit CENTERED in a wide box). The web port can't carry every
   per-type floor, so it reproduces the BREATHING with the internal padding + a
   sensible min-width: vertical pad = the canvas `height` (18-20px) minus the
   text line, horizontal pad widened to 10px/side (matches the centered look of
   the original's wide fixed-width pills). Inter-pill gap = the pack padx (2+2)
   plus each canvas's pad=2 transparent gutter = ~8px between the visible fills
   (see the per-pill margins below). */
.ins-pill { display: inline-flex; align-items: center; justify-content: center;
  font-size: 1em; font-weight: 700; padding: 2px 10px; border-radius: 0; white-space: nowrap;
  cursor: pointer; min-width: 56px; }
.ins-pill-bear    { background: var(--badge-high); color: var(--badge-high-fg); }   /* bear → badge_high (red)   */
.ins-pill-bull    { background: var(--badge-low);  color: var(--badge-low-fg); }    /* bull → badge_low (green)  */
.ins-pill-neutral { background: var(--badge-med);  color: var(--badge-med-fg); }    /* neutral → badge_med (amber) */
.ins-pill-stage   { background: #4a4a4a; color: #ffffff; }                          /* STAGE — neutral gray (insight_renderer L1183) */
.ins-pill-bt      { background: #3a3f4a; color: #dfe6f0; }                          /* business_type — neutral slate (insight_renderer L1207) */
.ins-pill-hot     { background: var(--badge-med); color: var(--badge-med-fg); }     /* hot_sector → badge_med amber (insight_renderer L1259) */

/* ── section-body primitives (insight_renderer body helpers) ───────────────
   The tk body uses padx=10 throughout; pady values map straight to margins.
   Every label is 1em (the _font helper clamps negative deltas to 0 → bold +
   colour are the ONLY hierarchy). SQUARE borders, no radius. ─────────────── */
/* _divider() (insight_renderer L343): 1px line, fill=x padx=10 pady=(10,8). */
.ins-divider { height: 1px; background: var(--separator); margin: 10px 10px 8px; }
/* _ksection_label (L302): uppercase bold sub-heading, pack padx=10 pady=(8,2).
   SPACING (issue A): the uppercase micro-label → prose gap is pady-bottom (2) +
   the label's bottom half-leading + the prose's top half-leading ≈ 4px; bottom
   2→4 restores that breathing. The 8px top sits below a divider (own 8px bottom)
   so it stays at 8. */
.ins-ksection { font-size: 1em; font-weight: 700; color: var(--text);
  text-transform: uppercase; margin: 8px 10px 4px; }
/* WHAT'S HAPPENING heading + REAL/NOT-REAL pill on ONE line (the pill moved here
   from the Play section header). The row carries the .ins-ksection margins; the
   inner label drops its own so the pill right-aligns within the 10px body inset. */
.ins-ksection-row { display: flex; align-items: center; gap: 6px; margin: 8px 10px 4px; }
.ins-ksection-row .ins-ksection { margin: 0; }
.ins-ksection-row .ins-pill { margin-left: auto; cursor: default; }
/* _prose (L311): wrap-responsive prose, pack padx=10. The tk colour map points
   text/muted/dim all at t["text"], so both kinds share the same fg. */
.ins-prose { font-size: 1em; color: var(--text); margin: 0 10px; line-height: 1.35; }
.ins-prose-muted { color: var(--text); }
/* label + inline-pill row (Secondary Play L356-368 padx=10 pady=(4,4);
   Theme L383-392 padx=10 pady=(0,4)). Label sits left, pills wrap after it. */
.ins-row { display: flex; align-items: center; flex-wrap: wrap; gap: 6px;
  margin: 6px 10px; }
.ins-row-label { font-size: 1em; color: var(--text); }
/* play-tags row (§1: secondary plays + the relocated business_type pill) — a
   left label + a pill GRID that packs at most 2 pills per LINE (the ≤2-cards-
   per-line layout rule, owner 2026-06-30). The label aligns to the first row. */
.ins-row-grid { align-items: flex-start; }
.ins-pillgrid { display: flex; flex-direction: column; gap: 6px; }
.ins-pillrow { display: flex; flex-wrap: wrap; gap: 6px; }
/* WHAT'S HAPPENING bullets (L401-406 padx=10 pady=(1,0)) + bold punchline
   (L408-413 padx=10 pady=(4,0)). justify=left, wrap. SPACING (issue A): tk
   bullet→bullet gap = pady-top (1) + each Tahoma10 line's top/bottom half-leading
   ≈ 6px visual; margin-top 1→6 restores the per-bullet breathing (the same
   .ins-bullet is reused by DILUTION INSIGHTS). Punchline pady=(4,0)+leading ≈
   8px. */
.ins-bullet { font-size: 1em; color: var(--text); margin: 6px 10px 0;
  line-height: 1.35; }
.ins-punchline { font-weight: 700; margin-top: 8px; }
/* AI ANALYSIS CONFIDENCE rows (L441-453): cap (bold, width=8) + (sub) muted +
   right-aligned pill. cell pack padx=18 pady=1; sub padx=(2,6). */
.ins-conf-row { display: flex; align-items: center; margin: 3px 18px 1px; }
.ins-conf-cap { font-size: 1em; font-weight: 700; color: var(--text);
  min-width: 8ch; }
.ins-conf-sub { font-size: 1em; color: var(--text); margin: 0 6px 0 2px; }
.ins-conf-row .ins-pill { margin-left: auto; }

/* ── Hidden Levels body (insight_renderer _build_levels_body L626-749) ──────
   Minimalist row pattern copied from the ticker overlay's Dilution Instruments
   section: a 3-col grid [KIND:] [$PRICE bold] [label wraps], plus an optional
   indented muted trader-note row. No cards/badges/boxes. SQUARE, every label
   1em (bold + colour are the only hierarchy). ────────────────────────────── */
/* "No hidden levels…" empty label — text fg, padx=10 pady=8 (L643-645). */
.ins-levels-empty { font-size: 1em; color: var(--text); margin: 8px 10px; }
/* Level row — tk Frame pack padx=10 pady=(2,0); grid col2 (label) weight=1 takes
   remaining width. align-items:flex-start = tk anchor="nw" top alignment.
   SPACING (issue A): tk level→level gap = note-row pady-bottom (4) + next
   level-row pady-top (2) + each Tahoma10 line's top/bottom half-leading (~3-4px)
   ≈ 9-10px visual. CSS sibling margins COLLAPSE, so the whole block separation
   lives on the level-row's own margin-top (8px); the note hugs its level (no
   bottom margin). First level's top margin separates it from the body top. */
.ins-level-row { display: flex; align-items: flex-start; margin: 8px 10px 0; font-size: 1em; }
/* col0 kind label — t["label"] fg, width=LBL_W=10ch (L681-685). */
.ins-level-kind { color: var(--label); min-width: 10ch; flex: none; white-space: nowrap; }
/* col1 "$price - " — t["text"] fg, BOLD (L686-689). The tk text carries a literal
   trailing space ("{ptxt} - ") that flex would trim at the item edge → a
   non-collapsing right gap reinstates the "$5.20 - Legacy" space (issue B; the JS
   also emits a non-breaking space). */
.ins-level-price { color: var(--text); font-weight: 700; flex: none; white-space: nowrap; }
/* col2 label text — t["text"] fg, wraps, fills remaining width (L690-694). */
.ins-level-label { color: var(--text); flex: 1 1 auto; min-width: 0; line-height: 1.35; }
/* trader-note row — tk Frame pack padx=10 pady=(0,4); note aligned under col2
   via a kind+price-width spacer (L716-732). The note hugs its level; the NEXT
   level-row's 8px top margin provides the block separation (issue A). */
.ins-level-note-row { display: flex; align-items: flex-start; margin: 2px 10px 0; font-size: 1em; }
/* spacer = kind(10ch) + price col width — keeps the note under the label column. */
.ins-level-note-spacer { flex: none; min-width: 10ch; }
/* note text — t["text"] fg, wraps (L725-731). */
.ins-level-note { color: var(--text); flex: 1 1 auto; min-width: 0; line-height: 1.35; }
/* spacers — tk.Frame height=10 before DILUTION INSIGHTS (L740) + height=6 trailing
   (L749). */
.ins-levels-gap { height: 10px; }
.ins-levels-foot { height: 6px; }

/* ── Narrative body (insight_renderer _build_narrative_body L458-617) ───────
   Colon-aligned [label:][value] rows (the tk _grid_row helper): a fixed label
   column of width LBL_W=10ch + a value cell that fills the rest (grid col1
   weight=1). Each row pack padx=10 pady=(2,0). SQUARE, every label 1em (bold +
   colour are the only hierarchy). align-items:flex-start = tk anchor="nw". ── */
/* SPACING (issue A): tk row→row gap = pady-top (2) + each value's top/bottom
   half-leading ≈ 6px visual; margin-top 2→6 restores the per-row breathing the
   colon-aligned Event/Source/PR/Piggyback/Fade/Comparables/Peers rows show in
   the original. Bottom stays 0 (CSS collapses adjacent siblings → the 6px top
   is the single inter-row gap, additive-equivalent to tk here). */
.ins-narr-row { display: flex; align-items: flex-start; margin: 6px 10px 0; font-size: 1em; }
/* col0 label — t["label"] fg, width=LBL_W=10ch (L477-480). */
.ins-narr-label { color: var(--label); min-width: 10ch; flex: none; white-space: nowrap; }
/* col1 value cell — grid weight=1, fills the rest (L481-482). */
.ins-narr-cell { flex: 1 1 auto; min-width: 0; display: flex; flex-wrap: wrap; align-items: center; }
/* prose value — t["text"] fg, wraps responsively (Event / PR subst., L510-542). */
.ins-narr-prose { color: var(--text); line-height: 1.35; }
/* plain text value — t["text"] fg (Source / "• " comparable / chip count,
   L520-523/588-592). */
.ins-narr-text { color: var(--text); line-height: 1.35; }
/* bold value — t["text"] fg, bold (PR lag "Nh" L528-531; "(N found)" / "(N peers)"
   counts L581-603). */
.ins-narr-strong { color: var(--text); font-weight: 700; }
/* peer chip flow — chips that wrap horizontally, each _badge_pill padx=(0,2)
   pady=2 (L605-614). */
.ins-narr-chips { display: flex; flex-wrap: wrap; align-items: center; }
/* peer chip — _badge_pill(pill_bg=surface_high, fg=accent) (L610-613). Reuses
   .ins-pill geometry; overrides only the colour to the surface_high/accent
   tokens + the per-chip margin (padx=(0,2) pady=2). */
.ins-narr-chip { background: var(--surface-high); color: var(--accent); margin: 2px 6px 2px 0; }
/* trailing 6px spacer (tk.Frame height=6, L617). */
.ins-narr-foot { height: 6px; }

/* ── Timeline & Catalysts body (insight_renderer _build_timeline_body L752-962) ─
   FOUR sub-blocks, each with a block-header (divider + coloured uppercase label).
   NOW/WATCH ride amber (badge_med_fg); COMING/HISTORY ride bright (text). Colon-
   aligned date column (LBL_W=10ch); HISTORY is a CSS dot+line rail replacing the
   tk Canvas. SQUARE, every label 1em (bold + colour are the only hierarchy). ── */
/* _divider() (L786-789): 1px line, fill=x padx=10 pady=(12,6). */
.ins-tl-divider { height: 1px; background: var(--separator); margin: 12px 10px 6px; }
/* _block_header label (L797-800): uppercase bold, padx=10 pady=(0,4). amber =
   badge_med_fg (● NOW / ⚐ WATCH); bright = text (COMING / HISTORY). */
/* SPACING (issue A): block-header → first row gap = pady-bottom (4) + the
   header's bottom half-leading + the first row's top half-leading ≈ 6px; bottom
   4→6 restores the breathing under ● NOW / ⚐ WATCH / COMING / HISTORY. */
.ins-tl-block-hdr { font-size: 1em; font-weight: 700; text-transform: uppercase;
  margin: 0 10px 6px; }
.ins-tl-hdr-amber { color: var(--badge-med-fg); }   /* NOW / WATCH — amber */
.ins-tl-hdr-bright { color: var(--text); }          /* COMING / HISTORY — bright */

/* NOW / WATCH / COMING row — tk Frame pack padx=10 pady≈(1-2,0); grid col1 (cell)
   takes the rest. align-items:flex-start = tk anchor="nw". SPACING (issue A): tk
   row→row gap = pady-top (1-2) + each row's top/bottom half-leading ≈ 5-6px
   visual; margin-top 2→5 restores the WATCH-bullet / COMING-row breathing. */
.ins-tl-row { display: flex; align-items: flex-start; margin: 5px 10px 0; font-size: 1em; }
/* _empty_col0 (L842-845): width=LBL_W*7 = 70px spacer aligning NOW/WATCH text
   under the COMING event column. */
.ins-tl-col0 { flex: none; min-width: 70px; }
/* COMING date col — accent, bold, width=LBL_W=10ch (L892-895). */
.ins-tl-date { color: var(--accent); font-weight: 700; flex: none; min-width: 10ch; white-space: nowrap; }
/* value cell — grid weight=1, fills the rest. */
.ins-tl-cell { flex: 1 1 auto; min-width: 0; }
/* COMING cell holds [event grows] [type pill right] in one flex row (L896-909). */
.ins-tl-cell-event { display: flex; align-items: flex-start; }
/* active_now prose — text fg, BOLD, wraps (L856-861). */
.ins-tl-now { color: var(--text); font-weight: 700; line-height: 1.35; }
/* "• {m}" watch row — text fg, wraps (L875-878). */
.ins-tl-watch { color: var(--text); line-height: 1.35; }
/* scheduled event title — text fg, wraps, fills before the pill (L898-902). */
.ins-tl-event { color: var(--text); flex: 1 1 auto; min-width: 0; line-height: 1.35; }
/* type pill — _badge_pill(pill_bg=surface_high, fg=text) (L905-909). Reuses the
   .ins-pill geometry; only colours + the left margin (padx=(4,0)). */
.ins-tl-type-pill { background: var(--surface-high); color: var(--text);
  margin-left: 4px; flex: none; }

/* ── HISTORY rail (insight_renderer L912-960) — date | dot+line track | event ──
   pady=0 → continuous track (L919). 3 cols: [date+age] [20px rail] [event]. */
.ins-tl-hist-row { display: flex; align-items: stretch; margin: 0 10px; font-size: 1em; }
/* col0 — date (bold, width LBL_W) + relative age below; pady=(2,0) (L924-935).
   SPACING (issue A): the HISTORY rows pack pady=0 (continuous track), so the
   per-pivot breathing lives in the date/event cell padding. tk date-cell
   pady=(2,0) + the line half-leading ≈ 4px top; padding-top 2→4 to match the
   event cell (below) so the rail rows don't crowd. */
.ins-tl-hist-date-cell { flex: none; min-width: 10ch; display: flex; flex-direction: column;
  padding-top: 4px; }
.ins-tl-hist-date { color: var(--text); font-weight: 700; white-space: nowrap; }
.ins-tl-hist-age { color: var(--text); }   /* _font(-2) → 1em, text fg (L932-935) */
/* col1 — the track column (tk Canvas width=20 → 20px). The line runs the full row
   height through the centre (x=10); the dot sits near the top (center ~y=9). */
.ins-tl-track { position: relative; flex: none; width: 20px; align-self: stretch; }
/* connecting line — 2px, centred (x=10), text_dim, edge-to-edge by default. */
.ins-tl-track-line { position: absolute; left: 9px; top: 0; bottom: 0; width: 2px;
  background: var(--text-dim); }
/* first row trims the line above the dot (top→dot only); last row trims below it
   (dot→bottom only) — so the track doesn't bleed past the section (L826-831). */
.ins-tl-track-first .ins-tl-track-line { top: 9px; }
.ins-tl-track-last .ins-tl-track-line { bottom: calc(100% - 9px); }
/* filled dot — 8px, accent, centred on the line at y≈9 (dot center, L823/833). */
.ins-tl-track-dot { position: absolute; left: 6px; top: 5px; width: 8px; height: 8px;
  border-radius: 50%; background: var(--accent); }
/* col2 — event (bold) + "→ impact"; grid weight=1, pady=(2,4) (L943-959).
   SPACING (issue A): tk event-cell pady=(2,4) + the bold line + impact line
   half-leading ≈ 4px top / 6px bottom visual per pivot on the continuous track;
   padding 2/4 → 4/6 restores the per-pivot breathing (rail stays continuous,
   the row just grows). */
.ins-tl-hist-event-cell { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column;
  padding: 4px 0 6px; }
.ins-tl-hist-event { color: var(--text); font-weight: 700; line-height: 1.35; }
/* impact — "→ {impact}" text fg, indented padx=(6,0) (L952-959). The event→impact
   line sits directly below the bold event in the same cell; a 2px top margin
   restores the line half-leading between them (issue A). */
.ins-tl-hist-impact { color: var(--text); line-height: 1.35; padding-left: 6px; margin-top: 2px; }

/* trailing 6px spacer (tk.Frame height=6, L962). */
.ins-tl-foot { height: 6px; }


/* ══════════════════════════════════════════════════════════════════════
   P6 — POLISH (variação B "Equilibrado", aprovada)  ·  SÓ APARÊNCIA
   Aplicado no fim do arquivo → sobrepõe as regras-base de mesma classe.
   NENHUM id / class / data-attrs / aninhamento muda. A borda externa .ovl-border
   (7px, faixa de redimensionamento da janela) NÃO é tocada. Contrato OK.
   ══════════════════════════════════════════════════════════════════════ */

/* — sub-rótulos viram secundários e não quebram (FLOAT / SPLIT) — */
.metric-sub  { font-size: .85em; white-space: nowrap; }
.split-date  { font-size: .8em;  white-space: nowrap; }
.metric-top  { gap: 6px; }

/* — valor da métrica com mais presença + barras 3px arredondadas — */
.metric-val  { font-size: 1.08em; }
.metric-bar, .metric-bar > i { border-radius: 2px; }

/* — ritmo de espaçamento mais consistente entre os blocos — */
.metrics-grid  { row-gap: 6px; column-gap: 6px; }
.metric-card   { padding: 6px 9px 7px; }
.dt-risk-group { margin-top: 12px; }
.dt-only-group { margin-top: 14px; }
.ovl-section   { margin-top: 12px; }
.news-breaking { margin-top: 12px; }
/* mesmo ritmo quando as duas zonas legadas estão ocultas (notícias unificadas) */
.news-breaking[hidden] + .news-recent[hidden] + .news-latest { margin-top: 12px; }

/* — financials: folga entre nome e valor ("GC e NASDAQ" não cola) — */
.fin-cell { gap: 10px; padding: 7px 10px 8px; }

/* — ratings: pills de MESMA largura, responsivos, nunca escapam da moldura
   (o min-width fixo de 108px estourava a coluna em janela estreita).
   Como as 2 colunas são 1fr iguais, o % rende a MESMA largura nos 4 pills. */
.ratings-grid .rating-cell { gap: 10px; }
.ratings-grid .pill {
  flex: 0 0 auto;
  width: clamp(68px, 44%, 104px);
  min-width: 0;
  margin: 2px 0;
  padding: 0 6px;
  justify-content: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* — instrumentos: respiro lateral (texto não cola na faixa preta) — */
#instrumentsBody .instr-row { padding: 0 8px; }

/* — WHY STOCK MOVING: cabeçalho não quebra feio. O título longo ocupa a
   largura disponível e o selo "✓ CATALYST" fica numa peça só, alinhado à
   direita e centralizado (antes ambos embrulhavam e colidiam). */
.why-section .section-hdr { align-items: center; gap: 8px; }
.why-section #whyTitle    { flex: 1 1 auto; min-width: 0; font-size: .9em; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.why-catalyst             { flex: none; white-space: nowrap; }

/* ══ Compartilhar v2 — MODO CAPTURA (html[data-sharecap="1"], JS sharePrep) ══
   A imagem compartilhada é PADRONIZADA: nenhum chrome de janela pode vazar
   para a captura — a borda colorida de link/lock (a .ovl-border é o wrapper
   da janela; linkada ela pinta --ovl-link-color, e foi ESSA cor que vazou no
   smoke do dono 08-12) funde com o fundo do conteúdo, edges/toast somem, as
   transições morrem (o colapso/slide do sharePrep tem de ser instantâneo) e
   a barra de rolagem não entra no PNG. shareRestore remove o atributo. */
html[data-sharecap="1"] .ovl-border { background: var(--bg) !important; }
html[data-sharecap="1"] .ovl-edge { display: none !important; }
html[data-sharecap="1"] #ovlShareToast { display: none !important; }
html[data-sharecap="1"] #railHandle { display: none !important; }   /* alça do trilho fora da captura */
html[data-sharecap="1"] * { transition: none !important; animation: none !important; }
html[data-sharecap="1"] ::-webkit-scrollbar { display: none !important; }

/* DEMO TOUR — amber pulse pushed by the Studio's guided tour
 * (PandaOverlay.tourFlash: "edges" = resize frame, "link"/"lock"/"collapse"/
 * "share" = header buttons). Pure chrome highlight, self-removing. */
.tour-flash {
  animation: tourFlashPulse .55s ease-in-out 4;
  outline: 3px solid #ffaa00 !important;
  outline-offset: -3px;
}
@keyframes tourFlashPulse {
  0%, 100% { outline-color: rgba(255, 170, 0, 1); }
  50%      { outline-color: rgba(255, 170, 0, .15); }
}

/* ══ TICKER INTEL (SPEC_THEME_VIEWER_AI §3.8 · TICKER_INTEL_PLAN §1.4/§1.8) ══
   Additive + DORMANT: every selector below targets nodes that only exist or
   only unhide when overlay.js receives the intel extras (why_ai / filings /
   items[i].ai / intel state). Without that push the live app paints nothing
   new. Tokens ONLY (tokens.css); register = the same as the rows above:
   1em relative sizes (track the pushed --ovl-font-size), 22px rows, SQUARE
   corners (every chip in the ticker body is border-radius:0 — .news-src /
   .news-bias / .ins-pill). Placed at the END of the file on purpose: the
   `.news-row { flex-wrap }` override must come after L305 and the P6 block. */

/* — source badge: FINVIZ (raw) · PANDA AI (ready) · ⚡ analyzing (busy) — in the
   WHY header (#whySrcBadge) and the FILINGS header (#filingsSrcBadge). Starts
   `hidden` in the HTML; [hidden]{display:none!important} (L85) wins until the
   JS removes the attribute. Pill corners (--radius-pill, SPEC §3.8) — the one
   rounded chip in the body, so the SOURCE badge reads apart from the square
   tag/bias chips. */
.src-badge { font-size: .8em; font-weight: 700; padding: 0 5px; margin-left: 6px; border-radius: var(--radius-pill); letter-spacing: .04em; flex: none; white-space: nowrap; }
.src-badge.src-finviz { background: var(--news-lts-hdr-bg); color: var(--text-muted); border: 1px solid var(--border-strong); }
.src-badge.src-ai     { background: var(--badge-high); color: var(--badge-high-fg); }
.src-badge.src-busy   { background: var(--badge-med); color: var(--badge-med-fg); }
/* glifo estático: a lei "nada apagado" (dono 03-09) proíbe opacidade < 1 em texto,
   e o pulso era um fade do "●" — o estado "analisando" já é dito pelo rótulo + cor */
.src-badge.src-busy::before { content: "●"; margin-right: 4px; }

/* — Block 11 · PANDA EDGE line under the why summary (why_ai.edge). Always
   visible (collapsed or expanded) when panda why is on; `hidden` otherwise, so
   the 5px margin never paints on the Finviz path. Lives inside .why-frame →
   inherits the whole-frame expand/collapse click (wireWhyExpand). — */
.why-edge { margin-top: 5px; font-size: 1em; line-height: 1.25; color: var(--score-caution); }
.why-edge b { font-weight: 700; color: var(--score-caution); }

/* — Block 11b · FILINGS section. Shares .ovl-section/.section-hdr/.section-title/
   .section-body/.news-count with DILUTION INSTRUMENTS (margin-top 12px from the
   P6 block, uppercase title, --text-muted count). gap:6px re-states the base
   header gap (the why header alone runs 8px). — */
.filings-section .section-hdr { gap: 6px; }
/* row = same 22px register as .instr-row / .news-row; wraps so the expanded
   .filing-ai body drops under the title line (flex-basis:100%) */
.filing-row { display: flex; flex-wrap: wrap; align-items: center; min-height: 22px; font-size: 1em; line-height: 1.25; }
.filing-form { font-weight: 700; padding: 0 4px; margin: 0 4px 0 2px; background: var(--news-src-sec-bg); color: var(--news-src-fg); flex: none; }  /* = .news-src.is-sec (red SEC chip) */
.filing-title { flex: 1; min-width: 0; color: var(--text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; cursor: pointer; }
.filing-row.open .filing-title { white-space: normal; overflow: visible; }
.filing-time { color: var(--text-muted); flex: none; margin: 0 2px 0 4px; }
.filing-chev { color: var(--accent); font-weight: 700; flex: none; margin-left: 4px; cursor: pointer; white-space: nowrap; }  /* "▼ AI" / "▲ AI" / "🔒 PRO" */
/* expanded AI body (levels + risk), graphite inset like #instrumentsBody */
.filing-ai { flex-basis: 100%; padding: 4px 6px 6px 8px; background: var(--surface); border-top: 1px solid var(--border); }
.filing-chips { display: flex; gap: 4px; flex-wrap: wrap; margin-bottom: 4px; }  /* reuses span.news-bias.bias-<x> for the tag chip */
.filing-sev { font-weight: 700; padding: 0 4px; background: var(--news-lts-hdr-bg); color: var(--text-muted); }
.filing-sev.sev-HIGH, .filing-sev.sev-CRIT { background: var(--badge-high); color: var(--badge-high-fg); }
.filing-sev.sev-MED { background: var(--badge-med); color: var(--badge-med-fg); }
.filing-dil { font-weight: 700; padding: 0 4px; background: var(--bias-short-bg); color: var(--bias-short-fg); }  /* "DILUTIVE" = bias-short colours */
.filing-sub { font-size: .85em; font-weight: 700; color: var(--label); text-transform: uppercase; margin: 4px 0 2px; }  /* "LEVELS" heading */
.filing-level { display: flex; gap: 6px; align-items: baseline; margin-top: 2px; }
.filing-level-label { color: var(--text-muted); flex: 1 1 auto; min-width: 0; }
.filing-level-val { color: var(--text); font-weight: 700; flex: none; white-space: nowrap; }
.filing-risk { margin-top: 5px; line-height: 1.3; color: var(--text-muted); }  /* colour by severity (sev-LOW stays muted) */
.filing-risk.sev-HIGH, .filing-risk.sev-CRIT { color: var(--score-toxic); }
.filing-risk.sev-MED { color: var(--score-caution); }

/* — Block 12 · news AI takeaway + noise. `.news-row` gains flex-wrap so the
   takeaway (order:3, flex-basis:100%) drops under the headline line; with no
   .news-take child nothing wraps (bias/src/time are flex:none, head is flex:1
   min-width:0) → dormant for the live rows. .83em ≈ 11px at the 13.3px base
   (spec said 11px; em keeps it tracking the config font like every other
   size in this file). `.expanded` on the ROW (JS toggles it alongside the
   .news-head one) un-ellipsizes the takeaway with the headline. — */
.news-row { flex-wrap: wrap; }
.news-take { flex-basis: 100%; order: 3; font-size: .83em; line-height: 1.25; color: var(--text-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; padding: 0 2px 1px 4px; }
.news-row.expanded .news-take { white-space: normal; overflow: visible; }
/* Expanded row in the intel era (html[data-intel] = an intel state was pushed;
   never set by the live app without the feature): the headline takes a FULL
   line under the chips instead of wrapping in the narrow slot between the
   chips and the time (owner 02-09: "super feio e confuso"); the time slides to
   the right end of the chip line. */
html[data-intel] .news-row.expanded .news-head { flex-basis: 100%; order: 3; }
html[data-intel] .news-row.expanded .news-time { margin-left: auto; }
html[data-intel] .news-row.expanded .news-take { order: 4; }
