/* EquityTruth — site-wide overrides on Bootstrap 5 dark theme */

:root {
  /* Canonical cobalt DS tokens — SSOT: frontend/src/styles/tokens.css.
     Keep names in sync with that file; do not reintroduce divergent shims. */
  --et-bg:            #0a1628;
  --et-bg-deep:       #070f1c;
  --et-surface:       #16213e;
  --et-surface-2:     #1a2744;
  --et-surface-3:     #0f1d33;
  --et-border:        #0f3460;
  --et-border-faint:  #1a2744;
  --et-text:          #c8c8d0;
  --et-text-bright:   #e0e0e0;
  --et-text-dim:      #8899aa;
  --et-text-muted:    #5588aa;
  --et-text-faint:    #556677;
  --et-accent:        #64b5f6;
  --et-accent-hover:  #90caf9;
  --et-positive:      #26a69a;
  --et-negative:      #ef5350;
  --et-warning:       #fbbf24;
  --et-orange:        #ffa726;
  /* status tokens */
  --et-ok-bg: #1a4a1a; --et-ok-border: #2a7a2a; --et-ok-text: #7cfc7c;
  --et-err-bg: #3a1010; --et-err-border: #6a2020; --et-err-text: #ff6b6b;
  /* ratio gradient — source: frontend/src/lib/ratio-colors.ts (not yet tokens) */
  --et-ratio-red: #ef5350; --et-ratio-orange: #FFB74D; --et-ratio-green: #81C784; --et-ratio-blue: #42A5F5;
  --et-radius: 6px; --et-radius-sm: 4px;

  /* Legacy shim names kept as aliases (older pages still reference them);
     pointed at the canonical tokens so the site stays consistent. */
  --et-bg-card: var(--et-surface);
  --et-danger:  var(--et-negative);
  --et-muted:   var(--et-text-dim);
}

body {
  background: var(--et-bg);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

/* Navbar */
.navbar {
  background: var(--et-bg-card);
}
.navbar-brand {
  color: var(--et-accent) !important;
  font-size: 1.15rem;
}

/* Footer */
footer {
  background: var(--et-bg-card);
}

/* Spinner (processing page) */
.et-spinner {
  width: 40px;
  height: 40px;
  border: 3px solid #1e3a5f;
  border-top: 3px solid var(--et-accent);
  border-radius: 50%;
  animation: et-spin 1s linear infinite;
  margin: 0 auto 20px;
}
@keyframes et-spin {
  to { transform: rotate(360deg); }
}

/* ─────────────────────────────────────────────────────────────────────
   Dashboard (Trading Desk) — scoped under .dashboard so these rules never
   bleed into other Jinja pages. Cobalt DS metric tables + status chips.
   All colors via canonical --et-* tokens (above).
   ───────────────────────────────────────────────────────────────────── */
.dashboard {
  font-size: 13px;
  line-height: 1.55;
  font-variant-numeric: tabular-nums;
  color: var(--et-text);
}
.dashboard .num,
.dashboard .metric-cell { font-variant-numeric: tabular-nums; }

/* Page header */
.dashboard .dash-title { color: var(--et-text-bright); font-weight: 600; letter-spacing: -0.01em; }
.dashboard .btn-new {
  background: var(--et-active, #1a6fbf); border: 1px solid var(--et-border);
  color: #fff; border-radius: var(--et-radius-sm);
}
.dashboard .btn-new:hover { background: var(--et-active-hover, #2585e0); color: #fff; }

/* Tabs — reskinned Bootstrap nav-tabs */
.dashboard .nav-tabs { border-bottom: 1px solid var(--et-border); }
.dashboard .nav-tabs .nav-link {
  color: var(--et-text-muted); border: none; border-bottom: 2px solid transparent;
  background: none; padding: .5rem .9rem;
}
.dashboard .nav-tabs .nav-link:hover { color: var(--et-text-bright); border-bottom-color: var(--et-border-hover, #2a4a7a); }
.dashboard .nav-tabs .nav-link.active {
  color: var(--et-text-bright); background: none;
  border-bottom: 2px solid var(--et-accent);
}

/* Section card — surface container wrapping a section's header + table */
.dashboard .section-card {
  background: var(--et-surface); border: 1px solid var(--et-border);
  border-radius: var(--et-radius); margin-bottom: 1rem; overflow: hidden;
}
.dashboard .section-head {
  display: flex; align-items: center; gap: 10px;
  padding: .65rem .85rem; border-bottom: 1px solid var(--et-border);
  background: var(--et-surface-3);
}
.dashboard .section-label { text-transform: uppercase; letter-spacing: .08em; font-size: 11px; font-weight: 700; color: var(--et-text-dim); }
.dashboard .section-count { color: var(--et-text-dim); font-size: 11px; }
.dashboard .section-aggregate { margin-left: auto; display: flex; gap: 18px; font-size: 11px; color: var(--et-text-dim); white-space: nowrap; }
.dashboard .section-aggregate b { font-weight: 600; }

/* Metric table */
.dashboard .dash-table { color: var(--et-text); margin-bottom: 0; }
.dashboard .dash-table > :not(caption) > * > * { border-bottom-color: var(--et-border-faint); background: transparent; box-shadow: none; }
.dashboard .dash-head th {
  color: var(--et-text-dim); font-size: 11px; font-weight: 600; letter-spacing: .04em;
  border-bottom: 1px solid var(--et-border); white-space: nowrap; padding: .5rem .6rem;
}
.dashboard .dash-table tbody td { padding: .5rem .6rem; }
.dashboard .dash-table tbody tr:hover > td { background: var(--et-surface-2); }
.dashboard .metric-cell { white-space: nowrap; }
.dashboard .report-link { color: var(--et-text-bright); text-decoration: none; }
.dashboard .report-link:hover { color: var(--et-accent); }
.dashboard .th-star, .dashboard .td-star { width: 34px; }

/* ── Sticky frame: freeze the first (star+Title) and last (actions) columns so they
   stay visible while the metric columns scroll horizontally on narrow screens. The
   .table-responsive wrapper already provides overflow-x:auto. Sticky cells need an
   OPAQUE background (else scrolling cells show through) that matches every row state
   — base, :hover, footer — and an edge shadow as the "more content" affordance.
   Bootstrap .table is border-collapse:collapse by default; per-cell sticky+bg works,
   but we set separate so the sticky borders paint cleanly. */
.dashboard .dash-table { border-collapse: separate; border-spacing: 0; }
.dashboard .dash-table th.th-star,
.dashboard .dash-table td.td-star,
.dashboard .dash-table th.th-title,
.dashboard .dash-table td.td-title,
.dashboard .dash-table th.th-actions,
.dashboard .dash-table td.td-actions {
  position: sticky; z-index: 2; background: var(--et-surface);
}
/* left freeze: star at 0, Title after the 34px star column */
.dashboard .dash-table th.th-star,
.dashboard .dash-table td.td-star  { left: 0; }
.dashboard .dash-table th.th-title,
.dashboard .dash-table td.td-title { left: 34px; }
/* right freeze: actions column */
.dashboard .dash-table th.th-actions,
.dashboard .dash-table td.td-actions { right: 0; }
/* Header/footer sticky cells sit on the SAME body plane (--et-surface) as their
   non-sticky neighbours, so the frozen Title/Status columns don't read as a
   different shade than the scrolling metric columns. The header is set apart by its
   bottom border + dim label text, the footer by its top border — not by a fill.
   (thead keeps the higher z-index so it stacks above body sticky cells.) */
.dashboard .dash-table thead th.th-star,
.dashboard .dash-table thead th.th-title,
.dashboard .dash-table thead th.th-actions { z-index: 3; background: var(--et-surface); }
.dashboard .dash-table tfoot td.td-star,
.dashboard .dash-table tfoot td.td-title,
.dashboard .dash-table tfoot td.td-actions { background: var(--et-surface); }
/* keep the sticky cells in sync with row hover so no "hole" appears */
.dashboard .dash-table tbody tr:hover > td.td-star,
.dashboard .dash-table tbody tr:hover > td.td-title,
.dashboard .dash-table tbody tr:hover > td.td-actions { background: var(--et-surface-2); }
/* Title is the always-visible anchor; cap its width so it can't swallow a narrow
   viewport (long names wrap inside the cell rather than pushing metrics off-screen). */
.dashboard .dash-table th.th-title,
.dashboard .dash-table td.td-title { max-width: 340px; }
/* Edge shadows on the frozen columns — gated on ACTUAL horizontal scroll so they only
   appear when content is hidden on that side (JS toggles .has-x-left / .has-x-right on
   the .table-responsive). A permanent shadow would falsely imply offscreen content. */
.dashboard .table-responsive.has-x-left .dash-table th.th-title,
.dashboard .table-responsive.has-x-left .dash-table td.td-title { box-shadow: 6px 0 6px -6px rgba(0,0,0,.45); }
.dashboard .table-responsive.has-x-right .dash-table th.th-actions,
.dashboard .table-responsive.has-x-right .dash-table td.td-actions { box-shadow: -6px 0 6px -6px rgba(0,0,0,.45); }

/* Actions: a single ⋮ kebab at every width so the sticky actions column stays slim
   and the scrollable metric area gets the width — table real estate matters. */
.dashboard .row-actions-kebab { display: inline-block; }
/* Collection-toggle menu items: a check (member) or plus (not yet) glyph; the .active
   accent comes from the shared .dropdown-item.active rule. Dim briefly while the
   add/remove request is in flight. */
/* NOTE: these target the row kebab's menu, which is PORTALED to <body> on open (the
   sticky/overflow escape fix) — so they must NOT be scoped under .dashboard, or they'd
   stop matching once the menu leaves the .dashboard subtree. Class names are unique
   enough to be safe unscoped. */
.coll-toggle .coll-check { width: 1em; }
.coll-toggle.busy { opacity: .5; pointer-events: none; }
/* Collapsible submenu sections (Move to folder / Add to collection) in the kebab. */
.submenu-toggle { display: flex; align-items: center; width: 100%; text-align: left; }
/* Caret: the Bootstrap-Icons glyph won't take a CSS transform reliably, so SWAP the
   glyph instead of rotating — ▸ when closed, ▾ when open (handled in JS). */
.submenu-caret { margin-left: auto; font-size: 10px; }
.move-menu .submenu-item { padding-left: 2.25rem !important; }  /* indent under the header */

/* ── Column-bound per-folder filter row (COLUMN_FILTERS_PLAN) ── */
/* Funnel toggle in the folder head — three states:
   - default (row closed): faint;
   - .open (row expanded, no filters yet): accent — signals "click to close";
   - .active (has filters): accent + the count badge (set by applyFilter). */
.dashboard .filter-toggle {
  position: relative; color: var(--et-text-dim); line-height: 1;
  background: none; border: 0; margin-left: 4px;
}
/* Colour the icon glyph itself — the .bi <i> doesn't reliably inherit the button's
   color across states, so target it directly (and its ::before glyph). */
.dashboard .filter-toggle {
  display: inline-flex; align-items: center; justify-content: center;
  width: 24px; height: 24px;  /* WCAG 2.5.8 target size */
}
.dashboard .filter-toggle,
.dashboard .filter-toggle > i { color: var(--et-text-dim); }
.dashboard .filter-toggle:hover,
.dashboard .filter-toggle:hover > i { color: var(--et-text-bright); }
.dashboard .filter-toggle.open,
.dashboard .filter-toggle.open > i,
.dashboard .filter-toggle.active,
.dashboard .filter-toggle.active > i { color: var(--et-accent); }
.dashboard .filter-badge {
  position: absolute; top: -6px; right: -8px; min-width: 14px; height: 14px;
  padding: 0 3px; border-radius: 7px; background: var(--et-accent); color: #fff;
  font-size: 9px; line-height: 14px; text-align: center; font-weight: 700;
}
/* The filter row sits under the head; its cells align by the same column loop. */
.dashboard .filter-row > th { padding: .3rem .4rem; border-bottom: 1px solid var(--et-border); background: var(--et-surface-3); vertical-align: middle; }
.dashboard .filter-input {
  width: 100%; min-width: 52px; max-width: 88px; margin-left: auto; display: block;
  background: var(--et-bg); border: 1px solid var(--et-border); border-radius: 4px;
  color: var(--et-text); font-size: 12px; padding: 3px 5px; text-align: right;
}
.dashboard .filter-input:focus { outline: none; border-color: var(--et-accent); }
/* Placeholder carries the operator/unit (≥ %, ≥ days) — bump from the browser-faint
   default to --et-text-dim so it clears WCAG AA against --et-bg. */
.dashboard .filter-input::placeholder { color: var(--et-text-dim); opacity: 1; }
/* Title filter is text + left-aligned + fills its (wider) sticky cell. */
.dashboard .filter-title { max-width: none; text-align: left; }
.dashboard .filter-title::-webkit-search-cancel-button { -webkit-appearance: none; }

/* Metric filter cell = quick "≥" min input + a small sliders button that opens the
   Min/Max range popover. The wrapper keeps them on one line, right-aligned. */
.dashboard .filter-cell-wrap { display: inline-flex; align-items: center; gap: 3px; width: 100%; justify-content: flex-end; }
.dashboard .filter-cell-wrap .filter-min { margin-left: 0; min-width: 44px; max-width: 68px; }
.dashboard .filter-adv {
  flex: 0 0 auto; display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; background: none; border: 0; padding: 0; line-height: 1;
  color: var(--et-text-dim); font-size: 12px; cursor: pointer;
}
.dashboard .filter-adv:hover { color: var(--et-text-bright); }
.dashboard .filter-adv.active { color: var(--et-accent); }
/* Range popover (portaled to <body>; position set in JS). */
.range-pop {
  position: fixed; z-index: 9999; width: 150px;
  background: var(--et-bg); border: 1px solid var(--et-border); border-radius: var(--et-radius);
  padding: .55rem .6rem; box-shadow: 0 8px 28px rgba(0,0,0,.5);
}
.range-pop-title { font-size: 11px; font-weight: 600; color: var(--et-accent); margin-bottom: 6px; }
.range-pop .range-row { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 11px; color: var(--et-text-dim); margin-bottom: 5px; }
.range-pop .range-row:last-child { margin-bottom: 0; }
.range-pop .range-field { display: inline-flex; align-items: baseline; gap: 4px; }
.range-pop .range-unit { color: var(--et-text-dim); font-size: 11px; min-width: 1.6em; }
.range-pop input {
  width: 70px; background: var(--et-surface-3); border: 1px solid var(--et-border);
  border-radius: 4px; color: var(--et-text); font-size: 11px; padding: 2px 5px; text-align: right;
}
.range-pop input:focus { outline: none; border-color: var(--et-accent); }
.range-pop input::-webkit-inner-spin-button, .range-pop input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* Clear-all in the filter row's sticky actions cell — orange by default, red on
   hover. The CELL is the flex centring context (the reliable way to vertically
   centre a control in a table cell, vs. fiddly vertical-align on inline-replaced
   content); the button just carries colour + sizing. */
.dashboard tr.filter-row > th.td-actions { padding: .3rem .4rem; }
.dashboard .filter-clear {
  display: flex; align-items: center; justify-content: center; width: 100%;
  color: var(--et-orange); background: none; border: 0; padding: 0;
  line-height: 1; font-size: 15px;
}
.dashboard .filter-clear:hover { color: var(--et-danger, #ef4444); }
.dashboard .filter-input::-webkit-inner-spin-button,
.dashboard .filter-input::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
/* Sticky filter cells inherit the frozen-column treatment so inputs under the
   star/Title/actions columns don't scroll away (same offsets as the body cells). */
.dashboard .dash-table tr.filter-row > th.td-star,
.dashboard .dash-table tr.filter-row > th.td-title,
.dashboard .dash-table tr.filter-row > th.td-actions {
  position: sticky; z-index: 3; background: var(--et-surface-3);
}
.dashboard .dash-table tr.filter-row > th.td-star  { left: 0; }
.dashboard .dash-table tr.filter-row > th.td-title { left: 34px; }
.dashboard .dash-table tr.filter-row > th.td-actions { right: 0; }
.dashboard .folder-group.filtering { opacity: .6; transition: opacity .1s; }

/* Sortable headers (client-side) */
.dashboard th.sortable { cursor: pointer; user-select: none; }
.dashboard th.sortable:hover { color: var(--et-text-bright); }
.dashboard th.t-left { text-align: left; }
.dashboard th.t-center { text-align: center !important; }
/* Sort arrow: glyphless (empty <i>) when unsorted → no width, denser header.
   margin-left only applies once a bi-* glyph is present (active state). */
.dashboard th .sort-ico[class*="bi-"] { font-size: 9px; margin-left: 3px; }
.dashboard th.sorted-asc .sort-ico,
.dashboard th.sorted-desc .sort-ico { color: var(--et-accent); }

/* "updated N ago" beside the status chip */
.dashboard .updated-ago { display: block; color: var(--et-text-dim); font-size: 11px; margin-top: 2px; }
.dashboard .last-traded { display: block; color: var(--et-text-dim); font-size: 11px; margin-top: 1px; font-variant-numeric: tabular-nums; }
.dashboard .th-spark { width: 104px; }
.dashboard .td-spark { width: 104px; }
.dashboard .spark { display: block; }
.dashboard .spark-na { color: var(--et-text-faint); }

/* Metric coloring (DS 1.5 + ratio-colors.ts) */
.dashboard .mc-pos     { color: var(--et-positive); }
.dashboard .mc-neg     { color: var(--et-negative); }
.dashboard .mc-neutral { color: var(--et-text); }
.dashboard .mc-na      { color: var(--et-text-faint); }
.dashboard .mc-r-red    { color: var(--et-ratio-red); }
.dashboard .mc-r-orange { color: var(--et-ratio-orange); }
.dashboard .mc-r-green  { color: var(--et-ratio-green); }
.dashboard .mc-r-blue   { color: var(--et-ratio-blue); }

/* Aggregate footer — sits on the body plane (transparent over the card's
   --et-surface), set apart only by a hairline top border, so the card reads as one
   continuous surface instead of a dark recessed band. */
.dashboard .dash-foot td {
  border-top: 1px solid var(--et-border); color: var(--et-text-dim); font-size: 12px;
  padding: .5rem .6rem; background: transparent;
}

/* Owner @handle on followed rows */
.dashboard .owner-handle { color: var(--et-text-dim); font-size: 11px; margin-left: .4rem; }
/* When the @handle is a link to the owner's public page: quiet at rest (same dim
   look), brighten + underline on hover/focus so it reads as actionable. */
.dashboard a.owner-handle-link { text-decoration: none; cursor: pointer; }
.dashboard a.owner-handle-link:hover,
.dashboard a.owner-handle-link:focus-visible { color: var(--et-accent); text-decoration: underline; }
.dashboard a.owner-handle-link:focus-visible { outline: 2px solid var(--et-accent); outline-offset: 2px; border-radius: 2px; }

/* Chips & visibility */
.dashboard .chip {
  display: inline-block; font-size: 10px; padding: 1px 6px; border-radius: var(--et-radius-sm);
  vertical-align: middle;
}
.dashboard .chip-custom { background: rgba(38,166,154,.18); color: var(--et-positive); }
.dashboard .chip-temp { background: rgba(251,191,36,.14); color: var(--et-warning); }
/* Source-type chip (MQL5 Signal / Backtest MT5 / Statement MT4 / …) — a calm,
   neutral meta tag; must not compete with Custom (green) or Temporary (yellow). */
.dashboard .chip-source { background: var(--et-surface-2); color: var(--et-text-dim); border: 1px solid var(--et-border); }
.dashboard .vis-chip { color: var(--et-text-muted); font-size: 11px; margin-left: .4rem; }
/* Owner's visibility chip is a button (click to change) — reset button chrome, keep it
   inline like the static span; brighten on hover to signal it's interactive. */
.dashboard .vis-dd { display: inline; }
.dashboard button.vis-chip {
  background: none; border: 1px solid transparent; border-radius: var(--et-radius-sm);
  padding: 1px 3px; cursor: pointer; line-height: 1;
}
/* hover/open: subtle bg + border so the chip reads as an interactive control. */
.dashboard button.vis-chip:hover,
.dashboard button.vis-chip.show { color: var(--et-text-bright); background: var(--et-surface-2); border-color: var(--et-border); }
/* tiny caret signals the chip is a dropdown (status switcher). */
.dashboard .vis-caret { font-size: 7px; margin-left: 2px; vertical-align: middle; color: var(--et-text-faint); }
.dashboard .vis-hint { color: var(--et-text-dim); font-size: 11px; margin-left: .25rem; }

/* Status badges (DS status tokens) */
.dashboard .status {
  display: inline-block; font-size: 11px; padding: 1px 8px; border-radius: var(--et-radius-sm);
  border: 1px solid transparent; white-space: nowrap;
}
.dashboard .status-ok      { background: var(--et-ok-bg); border-color: var(--et-ok-border); color: var(--et-ok-text); }
.dashboard .status-err     { background: var(--et-err-bg); border-color: var(--et-err-border); color: var(--et-err-text); }
.dashboard .status-run,
.dashboard .status-pending { background: rgba(251,191,36,.10); border-color: rgba(251,191,36,.40); color: var(--et-warning); }

/* Action buttons */
.dashboard .td-actions .btn-outline-light {
  --bs-btn-color: var(--et-text-dim); --bs-btn-border-color: var(--et-border);
  --bs-btn-hover-bg: var(--et-surface-2); --bs-btn-hover-border-color: var(--et-border-hover, #2a4a7a);
  --bs-btn-hover-color: var(--et-text-bright);
}
.dashboard .td-actions .btn-outline-danger {
  --bs-btn-color: var(--et-negative); --bs-btn-border-color: var(--et-border);
}

/* Star button */
.dashboard .btn-star .bi-star-fill { color: var(--et-warning); }
.dashboard .btn-star .bi-star      { color: var(--et-text-faint); }
.dashboard .btn-star:hover .bi-star { color: var(--et-warning); }

/* Sub-tabs (Mine / Following) — pill toggle inside a section */
.dashboard .subtabs { display: inline-flex; gap: 2px; padding: 3px; background: var(--et-surface-3); border: 1px solid var(--et-border); border-radius: var(--et-radius); }
.dashboard .subtab {
  border: none; background: none; color: var(--et-text-muted);
  font-size: 12px; font-weight: 600; padding: .3rem .8rem; border-radius: var(--et-radius-sm);
  cursor: pointer; white-space: nowrap;
}
.dashboard .subtab:hover { color: var(--et-text-bright); }
.dashboard .subtab.active { background: var(--et-surface); color: var(--et-text-bright); }
.dashboard .subtab .bi-star-fill { color: var(--et-warning); }
.dashboard .subtab-count { color: var(--et-text-dim); font-weight: 500; margin-left: .2rem; }
.dashboard .subtab.active .subtab-count { color: var(--et-text-dim); }

/* Tab count badge (Collections) */
.dashboard .count-badge {
  display: inline-block; margin-left: .35rem; font-size: 10px; font-weight: 600;
  padding: 0 6px; border-radius: 9px; background: var(--et-surface-3); color: var(--et-text-dim);
}

/* Misc text */
.dashboard .section-subhead { color: var(--et-text-muted); font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.dashboard .text-muted-cell { color: var(--et-text-dim); font-size: 12px; }

/* Collection cards (Collections section) — header strip + collapsible members */
/* Shared collapsible-card head layout — on the BASE class so it applies to both
   folder (.folder-head) and collection (.collection-head) regardless of the
   kind-specific modifier. (Regression fix: the R2 wrapper emits "{{kind}}-head",
   i.e. "collection-head" ≠ the old ".coll-head" the flex rule was written for, so
   collection heads lost flex and stacked vertically.) */
.dashboard .dash-card-head {
  display: flex; align-items: center; gap: .5rem;
  padding: .6rem .8rem; cursor: pointer; user-select: none;
}
.dashboard .dash-card-head:hover { background: var(--et-surface-2); }
.dashboard .dash-card-chevron { color: var(--et-text-muted); font-size: 12px; transition: transform .15s; }
/* folders: chevron points right when collapsed; collections: flips 180° when open. */
.dashboard .folder-head[aria-expanded="false"] .dash-card-chevron { transform: rotate(-90deg); }
.dashboard .collection-head[aria-expanded="true"] .dash-card-chevron { transform: rotate(180deg); }

.dashboard .coll-card {
  background: var(--et-surface); border: 1px solid var(--et-border);
  /* Left accent edge brands the card as the "analysis" concept (collections compare),
     distinguishing it from folders (storage, no accent edge) down the whole left side. */
  border-left: 3px solid var(--et-accent);
  border-radius: var(--et-radius); margin-bottom: .75rem; overflow: hidden;
}
/* Recessed collection head over the body plane — same model as folders, so the head
   reads as a labelled title bar, not another report row. The body keeps --et-surface.
   NB: the R2 wrapper emits "collection-head" (not the legacy "coll-head"), so the
   background MUST be on .collection-head or it won't apply. Layout comes from the
   shared .dash-card-head rule above. */
.dashboard .collection-head {
  background: var(--et-surface-3); border-bottom: 1px solid var(--et-border);
}
.dashboard .collection-head:hover { background: var(--et-surface-2); }
.dashboard .coll-name { color: var(--et-text-bright); text-decoration: none; font-weight: 600; }
.dashboard .coll-name:hover { color: var(--et-accent); }
.dashboard .coll-count { color: var(--et-text-dim); font-size: 12px; }
/* Capacity "n/20": faint pill; amber when within 2 of the cap. */
.dashboard .coll-cap {
  margin-left: .5rem; font-size: 10px; font-variant-numeric: tabular-nums;
  color: var(--et-text-faint); border: 1px solid var(--et-border); border-radius: 999px; padding: 0 6px;
}
.dashboard .coll-cap.near { color: var(--et-orange); border-color: var(--et-orange); }
/* brief highlight pulse when a count updates live (add/remove from kebab) */
.dashboard .count-pulse { animation: countPulse .7s ease-out; }
@keyframes countPulse { 0% { background: var(--et-orange); color: #fff; border-radius: 3px; } 100% { background: transparent; } }
.dashboard .coll-agg { color: var(--et-text-dim); font-size: 12px; white-space: nowrap; }
.dashboard .btn-star-coll .bi-star-fill { color: var(--et-warning); }
.dashboard .btn-star-coll .bi-star { color: var(--et-text-faint); }
.dashboard .btn-star-coll:hover .bi-star { color: var(--et-warning); }
.dashboard .chip-owner { background: var(--et-accent-bg, #1a3050); color: var(--et-accent); border: 1px solid var(--et-border); }
.dashboard .coll-card .collapse .dash-table { border-top: 1px solid var(--et-border); }
/* (Member rows inherit the shared hover --et-surface-2; the old --et-surface-3 here
   collided with the head colour, so the override was removed.) */
.dashboard .coll-empty { padding: 1rem .8rem; color: var(--et-text-dim); font-size: 12px; text-align: center; border-top: 1px solid var(--et-border); }

/* Folder groups (Mine subtab) — collapsible card per folder + "No folder" */
.dashboard .folder-group { margin-bottom: .75rem; }
.dashboard .folder-head {
  display: flex; align-items: center; gap: .5rem;
  padding: .55rem .8rem; cursor: pointer; user-select: none;
  background: var(--et-surface-3); border-bottom: 1px solid var(--et-border);
}
.dashboard .folder-head:hover { background: var(--et-surface-2); }
.dashboard .folder-chevron { color: var(--et-text-muted); font-size: 12px; transition: transform .15s; }
.dashboard .folder-head[aria-expanded="false"] .folder-chevron { transform: rotate(-90deg); }
.dashboard .folder-icon { color: var(--et-text-muted); font-size: 13px; }
.dashboard .folder-name { color: var(--et-text-bright); font-weight: 600; }
.dashboard .folder-empty { padding: 1rem .8rem; color: var(--et-text-dim); font-size: 12px; text-align: center; }

/* Collapsible-card reorder grip (folders + collections). The card-head grip is the
   handle that reorders a whole card, distinct from the header-click collapse. */
.dashboard .dash-card-grip {
  display: inline-flex; align-items: center; color: var(--et-text-faint);
  cursor: grab; font-size: 13px; margin-right: -.15rem;
}
.dashboard .dash-card-grip:hover { color: var(--et-text-dim); }
.dashboard .dash-card.card-reordering { opacity: .5; }
.dashboard .dash-card.reorder-over { outline: 2px dashed var(--et-accent); outline-offset: -2px; }

/* Folder toolbar (New folder) */
.dashboard .folder-toolbar { display: flex; align-items: center; gap: .75rem; margin-bottom: .6rem; }

/* Subtabs row: Mine/Following on the left, view toggle on the right. */
.dashboard .subtabs-row { display: flex; align-items: center; justify-content: space-between; gap: 1rem; }

/* View toggle: folder grouping ⇄ flat list (segmented control) */
.dashboard .view-toggle {
  display: inline-flex; border: 1px solid var(--et-border);
  border-radius: var(--et-radius-sm); overflow: hidden;
}
.dashboard .view-opt {
  display: inline-flex; align-items: center; padding: .25rem .7rem; font-size: 12px;
  color: var(--et-text-dim); text-decoration: none; background: transparent;
}
.dashboard .view-opt + .view-opt { border-left: 1px solid var(--et-border); }
.dashboard .view-opt:hover { color: var(--et-text-bright); background: var(--et-surface-2); }
.dashboard .view-opt.active { background: var(--et-active, #1a6fbf); color: #fff; }
.dashboard .btn-ghost-sm {
  background: transparent; border: 1px solid var(--et-border); color: var(--et-text-dim);
  font-size: 12px; padding: .25rem .7rem; border-radius: var(--et-radius-sm);
}
.dashboard .btn-ghost-sm:hover { background: var(--et-surface-2); color: var(--et-text-bright); border-color: var(--et-border-hover, #2a4a7a); }

/* Folder header kebab */
/* Pin the kebab to the right edge ALWAYS. Non-empty folders get there via the
   aggregate's margin-left:auto, but an empty folder omits the aggregate — without
   this the kebab would sit mid-row next to the count and visibly jump between
   empty/non-empty folders. */
.dashboard .folder-menu { margin-left: auto; }
.dashboard .folder-head .section-aggregate ~ .folder-menu { margin-left: .5rem; }
.dashboard .folder-kebab { background: none; border: none; color: var(--et-text-muted); }
.dashboard .folder-kebab:hover { color: var(--et-text-bright); }
/* The folder card clips its body (overflow:hidden, for the rounded table corners),
   which would also clip the kebab dropdown — most visibly on a short empty folder.
   Bootstrap's data-bs-strategy="fixed" floats the open menu with position:fixed so
   it escapes the clip; keep it above sibling cards. */
.dashboard .folder-menu .dropdown-menu.show { z-index: 1080; }

.dashboard .empty-state { color: var(--et-text-dim); }
.dashboard .empty-state .bi { color: var(--et-text-faint); }

/* "Load more" bar under a folder / flat list */
.dashboard .load-more-bar {
  display: flex; align-items: center; justify-content: center; gap: .75rem;
  padding: .5rem .8rem; border-top: 1px solid var(--et-border);
}
.dashboard .load-more-note { color: var(--et-text-dim); font-size: 11px; }
.dashboard .load-more-btn:disabled { opacity: .6; cursor: default; }

/* Cobalt styling for the dashboard's reusable modals (Bootstrap, not React DS) */
#inputModal .modal-content, #confirmModal .modal-content, #deleteModal .modal-content {
  background: var(--et-surface); border: 1px solid var(--et-border); color: var(--et-text);
}
#inputModal .modal-header, #confirmModal .modal-header, #deleteModal .modal-header { border-bottom-color: var(--et-border); }
#inputModal .modal-footer, #confirmModal .modal-footer, #deleteModal .modal-footer { border-top-color: var(--et-border); }
#inputModal .modal-title, #confirmModal .modal-title, #deleteModal .modal-title { color: var(--et-text-bright); }
#inputModal .form-control {
  background: var(--et-surface-3); border: 1px solid var(--et-border); color: var(--et-text-bright);
}
#inputModal .form-control:focus { border-color: var(--et-accent); box-shadow: 0 0 0 2px rgba(100,181,246,.25); background: var(--et-surface-3); color: var(--et-text-bright); }
#inputModal .form-label { color: var(--et-text-dim); }
#inputModal .btn-close, #confirmModal .btn-close, #deleteModal .btn-close { filter: invert(1) grayscale(1) brightness(1.5); }

/* Dropdown menus (kebab / Move-to / Add-to-collection / visibility) on exact cobalt
   surfaces, not Bootstrap dark. IMPORTANT: row menus are PORTALED to <body> on open
   (the sticky/overflow escape fix), so they leave the .dashboard subtree — these rules
   must ALSO match the portaled location, else the active item etc. fall back to
   Bootstrap's default blue. We match the dashboard's own menu classes (move-menu /
   vis-menu) which travel with the menu, plus body > .dropdown-menu for any portaled
   one. Keep the in-page .dashboard scope for menus that aren't portaled. */
.dashboard .dropdown-menu,
.move-menu, .vis-menu, body > .dropdown-menu {
  background: var(--et-surface-3); border: 1px solid var(--et-border); border-radius: var(--et-radius);
}
.dashboard .dropdown-item,
.move-menu .dropdown-item, .vis-menu .dropdown-item, body > .dropdown-menu .dropdown-item { color: var(--et-text); }
.dashboard .dropdown-item:hover, .dashboard .dropdown-item:focus,
.move-menu .dropdown-item:hover, .move-menu .dropdown-item:focus,
.vis-menu .dropdown-item:hover, .vis-menu .dropdown-item:focus,
body > .dropdown-menu .dropdown-item:hover, body > .dropdown-menu .dropdown-item:focus { background: var(--et-surface-2); color: var(--et-text-bright); }
.dashboard .dropdown-item.active, .dashboard .dropdown-item:active,
.move-menu .dropdown-item.active, .move-menu .dropdown-item:active,
.vis-menu .dropdown-item.active, .vis-menu .dropdown-item:active,
body > .dropdown-menu .dropdown-item.active, body > .dropdown-menu .dropdown-item:active { background: var(--et-accent-bg, #1a3050); color: var(--et-accent); }
.dashboard .dropdown-header,
.move-menu .dropdown-header, .vis-menu .dropdown-header, body > .dropdown-menu .dropdown-header { color: var(--et-text-muted); }
.dashboard .dropdown-divider,
.move-menu .dropdown-divider, .vis-menu .dropdown-divider, body > .dropdown-menu .dropdown-divider { border-top-color: var(--et-border); }
/* Danger items (Delete) must keep the danger color after portaling too. */
.move-menu .dropdown-item.text-danger, .vis-menu .dropdown-item.text-danger,
body > .dropdown-menu .dropdown-item.text-danger { color: var(--et-danger, #ef4444); }
.dashboard .dropdown-item.text-danger { color: var(--et-negative) !important; }
.dashboard .dropdown-item.text-danger:hover { background: var(--et-err-bg); color: var(--et-err-text) !important; }

/* Modal Cancel buttons → cobalt ghost (not Bootstrap stock grey) */
#inputModal .btn-secondary, #confirmModal .btn-secondary, #deleteModal .btn-secondary {
  background: var(--et-surface-2); border: 1px solid var(--et-border); color: var(--et-text);
}
#inputModal .btn-secondary:hover, #confirmModal .btn-secondary:hover, #deleteModal .btn-secondary:hover {
  background: var(--et-surface); border-color: var(--et-border-hover, #2a4a7a); color: var(--et-text-bright);
}

/* Toast stack (transient dashboard messages) */
.dash-toast-stack { position: fixed; bottom: 18px; right: 18px; z-index: 1090; display: flex; flex-direction: column; gap: 8px; width: 320px; max-width: calc(100vw - 36px); }
/* Actionable undo snackbar lives TOP-CENTER. On a tall data table the post-click
   gaze sits UP near the row, so a far bottom corner is easy to miss; the navbar is
   plain-flow (not fixed), so top:16px clears it at scroll-top with no real
   collision. Auto-width (one short line + link), capped. Same z-index as the
   passive stack so neither hides the other. */
.dash-toast-stack--center {
  position: fixed; top: 16px; left: 50%; transform: translateX(-50%);
  right: auto; bottom: auto; width: auto; max-width: min(440px, calc(100vw - 36px)); align-items: center;
}
.dash-toast {
  border: 1px solid var(--et-border); border-radius: var(--et-radius); padding: .6rem .8rem;
  font-size: 13px; opacity: 0; transform: translateY(8px); transition: opacity .2s, transform .2s; cursor: pointer;
}
.dash-toast.show { opacity: 1; transform: translateY(0); }
/* The undo snackbar is top-anchored, so it slides DOWN into view (negative→0) and
   gets one soft accent-border pulse on entry, so a peripheral-recovery cue actually
   catches the eye (calm, no flash). */
.dash-toast--action { transform: translateY(-12px); }
.dash-toast--action.show { transform: translateY(0); animation: toastActionPulse .9s ease-out 1; }
@keyframes toastActionPulse {
  0% { border-color: var(--et-accent); box-shadow: 0 0 0 2px rgba(100,181,246,.25); }
  100% { border-color: var(--et-border); box-shadow: none; }
}
.dash-toast.is-error { background: var(--et-err-bg); border-color: var(--et-err-border); color: var(--et-err-text); }
.dash-toast.is-ok { background: var(--et-ok-bg); border-color: var(--et-ok-border); color: var(--et-ok-text); }
/* Inline action (e.g. Undo) inside a snackbar toast — looks like a quiet link button. */
.dash-toast-action {
  margin-left: .25rem; padding: 0 .15rem; background: none; border: none; cursor: pointer;
  color: var(--et-accent); font-weight: 600; text-decoration: underline; font-size: inherit;
}
.dash-toast-action:hover { color: var(--et-accent-hover, #90caf9); }
.dash-toast-action:focus-visible { outline: 2px solid var(--et-accent); outline-offset: 2px; border-radius: 2px; }

/* Column filter bar (the standalone top search box was removed — title search
   now lives in the Title column's filter input). */
.dashboard .filter-field { display: flex; align-items: center; gap: .35rem; }
.dashboard .filter-field label { color: var(--et-text-dim); font-size: 12px; white-space: nowrap; }
.dashboard .filter-field input {
  width: 64px; background: var(--et-surface-3); border: 1px solid var(--et-border);
  color: var(--et-text-bright); border-radius: var(--et-radius-sm); padding: .25rem .4rem; font-size: 12px;
}
.dashboard .filter-field input:focus { outline: none; border-color: var(--et-accent); }
.dashboard .filter-check { display: flex; align-items: center; gap: .3rem; color: var(--et-text-dim); font-size: 12px; white-space: nowrap; cursor: pointer; }


/* Query-mode banner (flat ranked list active) */
.dashboard .query-banner {
  background: var(--et-surface-3); border: 1px solid var(--et-border); border-radius: var(--et-radius);
  padding: .5rem .8rem; margin-bottom: .75rem; font-size: 12.5px; color: var(--et-text-dim);
}
/* Highlighted values in the banner — brighter, NOT bold (kept understated). */
.dashboard .query-banner .qb-val { color: var(--et-text-bright); }
/* Reset action inside the banner — a small bordered pill so it reads as "the way
   out of query mode", not just inline link text. */
.dashboard .query-banner .query-clear {
  display: inline-flex; align-items: center; margin-left: .6rem;
  border: 1px solid var(--et-negative); color: var(--et-negative);
  border-radius: var(--et-radius-sm); padding: .1rem .55rem; font-size: 12px;
  text-decoration: none; white-space: nowrap;
}
.dashboard .query-banner .query-clear:hover { background: var(--et-err-bg); color: var(--et-err-text); }

/* "showing N of M" cap note */
.dashboard .cap-note { color: var(--et-text-dim); font-size: 11.5px; margin: .5rem 0 0; text-align: center; }

/* Owner-only banner on one's own public page (full-width, under the navbar — NOT
   inside the .dashboard scope). Reuses the query-banner idiom (recessed surface +
   border) in a neutral, non-error tone with a bordered "back to dashboard" pill. */
.owner-banner {
  display: flex; align-items: center; justify-content: center; gap: 1rem; flex-wrap: wrap;
  background: var(--et-surface-3); border-bottom: 1px solid var(--et-border);
  padding: .5rem .8rem; font-size: 12.5px; color: var(--et-text-dim);
}
.owner-banner-link {
  display: inline-flex; align-items: center;
  border: 1px solid var(--et-accent); color: var(--et-accent);
  border-radius: var(--et-radius-sm); padding: .1rem .6rem; font-size: 12px;
  text-decoration: none; white-space: nowrap;
}
.owner-banner-link:hover { background: var(--et-accent); color: #fff; }
.owner-banner-link:focus-visible { outline: 2px solid var(--et-accent); outline-offset: 2px; }

/* Server-sort header links */
.dashboard th.sortable.srv a { color: inherit; text-decoration: none; display: inline-block; }
.dashboard th.sortable.srv:hover a { color: var(--et-text-bright); }

/* Intro line under the page title (defines "report") */

/* Header (i) info button → opens a click-popover (full name + description), matching
   the React Comparison header. Header click stays pure-sort; the (i) is its own
   button. */
.dashboard th .hdr-info {
  display: inline-flex; align-items: center; justify-content: center;
  /* glyph stays small but the HIT AREA is ~22px (toward the 24px WCAG 2.5.8 target);
     flex-centres the glyph so growing the box doesn't offset it. */
  width: 22px; height: 22px; margin-left: 2px; padding: 0;
  vertical-align: middle; position: relative; top: -1px;
  border: none; border-radius: 50%; background: transparent; cursor: pointer;
  /* --et-text-muted clears the 3:1 minimum for UI glyphs (was --et-text-faint ≈2.9:1). */
  color: var(--et-text-muted); font-size: 10px; line-height: 1;
}
.dashboard th .hdr-info:hover { color: var(--et-accent); background: var(--et-accent-bg, #1a3050); }
/* The popover panel (appended to <body>, position set in JS). */
.dashboard-pop, .hdr-pop {
  position: fixed; z-index: 9999; width: 280px;
  background: var(--et-bg); border: 1px solid var(--et-border); border-radius: var(--et-radius);
  padding: .5rem .85rem; box-shadow: 0 8px 28px rgba(0,0,0,.5);
  text-align: left; white-space: normal;
}
.hdr-pop-title { font-size: 11px; font-weight: 600; color: var(--et-accent); margin-bottom: 2px; }
.hdr-pop-body { font-size: 11px; line-height: 1.5; color: var(--et-text-dim); }
/* .sorting = brief busy state during the AJAX per-folder re-sort. */
.dashboard th.fld-sort.sorting { opacity: .55; }

/* One-line section explainer (folders organize · collections compare) */
.dashboard .section-explainer {
  color: var(--et-text-dim); font-size: 12px; margin: -0.5rem 0 1rem;
}
.dashboard .section-explainer b { color: var(--et-text-bright); font-weight: 600; }
.dashboard .section-explainer .bi { color: var(--et-text-muted); }

/* Keyboard focus ring (WCAG 2.4.7) — visible on the cobalt surface */
.dashboard a:focus-visible,
.dashboard button:focus-visible,
.dashboard [role="button"]:focus-visible,
.dashboard th.sortable:focus-visible {
  outline: 2px solid var(--et-accent);
  outline-offset: 2px;
  border-radius: var(--et-radius-sm);
}
