/* ═══════════════════════════════════════════════════════════════════
   Mocca — Dashboard (Payments / Balance) styles
   Lives next to shell.css. Pulls tokens from colors_and_type.css.
   ═══════════════════════════════════════════════════════════════════ */

/* ── PAGE / TAB ROUTING ─────────────────────────────────────────────
   Each "page" inside body-in toggles visibility via data-page; each
   tab inside payments toggles via data-tab. Active panes are flex
   columns AND set `min-height:0` so they can shrink inside the body's
   flex container — without that, the inner .page can't compute a
   bounded height and its overflow-y:auto never triggers. */
.page-view{display:none;flex:1;min-width:0;min-height:0}
.body[data-page="payments"] .page-view[data-view="payments"],
.body[data-page="metrics"]  .page-view[data-view="metrics"]{
  display:flex;flex-direction:column;flex:1;min-height:0;
}

.tab-view{display:none}
.body[data-tab="balance"]  .tab-view[data-tab="balance"],
.body[data-tab="expenses"] .tab-view[data-tab="expenses"],
.body[data-tab="income"]   .tab-view[data-tab="income"]{
  display:flex;flex-direction:column;gap:18px;
}

/* The .tabs strip should be hidden on the metrics page (it has no tabs). */
.body[data-page="metrics"] .tabs{display:none}

/* ── PAGE LAYOUT ────────────────────────────────────────────────── */
.body[data-page="payments"] .page,
.body[data-page="metrics"]  .page{
  gap:18px;
}

/* ── GENERIC CARD ──────────────────────────────────────────────── */
.card{
  background:var(--bg-1);border:1px solid var(--border);border-radius:var(--mk-radius-lg);
  padding:18px;display:flex;flex-direction:column;gap:14px;min-width:0;min-height:0;
}
.card-h{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}
.card-h h3{margin:0;font:700 15px var(--mk-font-ui);letter-spacing:-.01em;color:var(--fg-1)}
.card-h p{margin:2px 0 0;font:500 12px var(--mk-font-ui);color:var(--fg-3)}

/* Card legends — small color swatches + labels.
   B51-17: the hand-written header legend is retired; `.chart-legend` is the host
   `dashboard.js` renders series into. `.card-legend` stays for any card that still
   declares one by hand. */
.card-legend{display:flex;gap:14px;flex-wrap:wrap;align-items:center;font:500 11px var(--mk-font-ui);color:var(--fg-2)}
.card-legend > span{display:inline-flex;gap:6px;align-items:center}
.card-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;flex-shrink:0}
/* ═══ B51-17 · the shape-aware legend ══════════════════════════════
   Under the plot by default — a WRAPPING row, so nine series wrap instead of
   squeezing; beside it (a column) when the card is wide, via `.legend-side` set by
   `renderLegend()`. Either way the count changes nothing about the layout. */
.chart-legend{display:flex;flex-wrap:wrap;align-items:center;gap:5px 14px;flex:0 0 auto;
  padding-top:8px;font:500 11px var(--mk-font-ui);color:var(--fg-2);min-width:0}
.chart-legend:empty{display:none}
.chart-legend .cl-i{display:inline-flex;gap:6px;align-items:center;min-width:0}
.chart-legend .cl-i > span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.chart-legend i{display:inline-block;width:10px;height:10px;border-radius:3px;flex-shrink:0}
/* B58 (Pablo, on the combo card's "Money Debt Net" row: "These legends could be
   somewhere else, they're just wasting space here") — a legend is a KEY, not
   content: it belongs on the header line beside the title, where the card already
   has slack, instead of taking a row (or a 34% column) away from the plot.
   `renderLegend()` moves the host into `.card-h`, so the old `.legend-side`
   grid — plot + legend column — is retired with the row it replaced. */
.card-h > .chart-legend{padding-top:0;align-self:center;gap:4px 12px;
  font:600 10.5px var(--mk-font-ui);color:var(--fg-3);max-width:60%;justify-content:flex-end}
.card-h > .chart-legend i{width:8px;height:8px;border-radius:2px}

/* Ghost button used in card heads ("View more") */
.btn-ghost{
  display:inline-flex;align-items:center;gap:6px;
  background:transparent;border:0;cursor:pointer;
  color:var(--accent);font:600 12px var(--mk-font-ui);padding:6px 8px;border-radius:8px;
}
.btn-ghost .mi{font-size:16px}
.btn-ghost:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}

/* ── BALANCE BANNER ─────────────────────────────────────────────── */
.bal-banner{
  display:grid;
  grid-template-columns:1.4fr 1fr;
  /* Center the hero column and the stat tiles against each other so the
     banner reads balanced rather than top-pinned with empty space below.
     Combined with the `auto` row-1 height (see .dash-grid) the banner now
     hugs its content instead of stretching to a full square cell. */
  align-items:center;
  gap:24px;
  background:
    radial-gradient(90% 110% at 0% 0%, color-mix(in srgb, var(--accent) 8%, transparent), transparent 72%),
    linear-gradient(135deg, var(--mk-navy-700), var(--mk-navy-900));
  color:#fff;
  border-radius:var(--mk-radius-lg);
  padding:24px;
  box-shadow:var(--shadow-md);
  position:relative;overflow:hidden;
  /* Container query — when the user resizes the widget narrower than
     ~520px, the inner content reflows to a single-column stack so the
     Net Balance + Active/Passive split don't get crushed. The widget
     grows taller instead. Pablo 2026-05-30. */
  container-type:inline-size;
  container-name:balbanner;
}
@container balbanner (max-width: 520px){
  .bal-banner{
    grid-template-columns:1fr;
    gap:16px;
  }
  .bal-banner .bb-split{
    grid-template-columns:1fr 1fr;
  }
}
@container balbanner (max-width: 360px){
  /* On very narrow widths the KPI split itself also stacks so the
     Active and Passive tiles get full reading width. */
  .bal-banner .bb-split{
    grid-template-columns:1fr;
  }
}
/* Second corner glow removed — the single soft top-left wash is enough;
   stacked glows read as "extra" (matches the calmed landing hero). */
.bal-banner::after{ content:none; }
.bb-net{display:flex;flex-direction:column;gap:6px;min-width:0;position:relative;z-index:1}
.bb-l{font:600 11px var(--mk-font-ui);letter-spacing:.08em;text-transform:none;color:rgba(255,255,255,.7)}
.bb-v{font:800 36px var(--mk-font-ui);letter-spacing:-.025em;line-height:1.1;color:#fff;font-variant-numeric:tabular-nums;white-space:nowrap}
.bb-d{display:flex;gap:8px;align-items:center;font:500 12px var(--mk-font-ui);color:rgba(255,255,255,.7);margin-top:4px}
.bb-up{display:inline-flex;align-items:center;gap:2px;color:var(--mk-teal-300);font-weight:600}
.bb-up .mi{font-size:14px}
.bb-down{display:inline-flex;align-items:center;gap:2px;color:var(--mk-debt);font-weight:600}
.bb-down .mi{font-size:14px}
/* Tiles size to their content (no `align-self:stretch`) so they don't
   balloon to fill a tall cell — the banner height is content-driven now. */
.bb-split{display:grid;grid-template-columns:1fr 1fr;gap:12px;align-self:center;position:relative;z-index:1}
.bb-side{
  background:rgba(255,255,255,.07);
  border:1px solid rgba(255,255,255,.10);
  border-radius:12px;padding:14px 16px;display:flex;flex-direction:column;gap:4px;
  justify-content:center;
  backdrop-filter:blur(4px);
  -webkit-backdrop-filter:blur(4px);
}
.bb-side .bb-l{color:rgba(255,255,255,.6)}
.bb-side .bb-v{font-size:20px}
.bb-active::before{
  content:"";display:inline-block;width:8px;height:8px;border-radius:999px;
  background:var(--accent);margin-bottom:4px;
}
.bb-passive::before{
  content:"";display:inline-block;width:8px;height:8px;border-radius:999px;
  background:var(--mk-debt);margin-bottom:4px;
}

/* ── DASHBOARD BENTO GRID ──────────────────────────────────────────
   One unified SQUARE-CELL grid for every widget (balance banner + all
   charts). `--dash-cols` is set per breakpoint by dashboard-editor.js
   (P=4 / T=3 / V=2 / H=2) and `--dash-cell` is the computed square cell
   side (= column width) so a widget spanning w×h cells keeps a clean
   w:h aspect ratio. `grid-auto-flow: row dense` repacks widgets in
   reading order when the column count shrinks. Each widget's span is set
   inline by applyLayoutToCards (clamped to the column count + its
   min-span); resize snaps to whole cells. Pablo 2026-06-01 #1. */
.dash-grid{
  display:grid;
  grid-template-columns:repeat(var(--dash-cols, 4), minmax(0, 1fr));
  /* Row 1 is content-height (`auto`) so the full-width Balance banner sits
     at its own balanced height instead of being stretched to a square cell;
     every implicit row after it (the charts) uses the square `--dash-cell`
     so a w×h span keeps a clean aspect ratio. The balance widget is always
     alone on row 1 (full-width at every breakpoint), so this never starves a
     chart of height. (Pablo 2026-06-02 W1 #2 — "balance widget too tall".) */
  grid-template-rows:auto;
  /* Row tracks use the square cell as a MINIMUM but may grow (`auto`) so a
     card whose content floor (chart-card min-height:230px) is taller than
     the computed cell can never overflow its track and overlap the widget
     in the row below. The square cell stays the visual baseline; only rows
     holding an over-tall widget expand. (Pablo 2026-06-19 — "widgets have
     different heights and overlap".) */
  grid-auto-rows:minmax(var(--dash-cell, 220px), auto);
  grid-auto-flow:row dense;
  gap:16px;
  align-items:stretch;
}
.dash-grid > .card,
.dash-grid > .bal-banner{ min-width:0; min-height:0 }
/* Widgets fill the cell block they span so the grid reads as even bands. */
.dash-grid > .card{ display:flex; flex-direction:column; height:auto }
/* Charts must always stay legible no matter how short the span/cell gets
   (Pablo 2026-06-19 — "widgets too short, I want the charts always visible,
   configure a min_height"). The card floors at a height that leaves room
   for the header + a visible chart; the SVG itself carries a min so it can
   never collapse to a sliver. */
.dash-grid > .chart-card{ min-height:230px; }
.dash-grid > .card > .card-h{ flex:0 0 auto }
/* Chart SVG fills the card's remaining height within its cell rather than
   a fixed pixel height, so a taller span = a taller chart. Direct child
   only — nested svgs (the spark small-multiples) size to THEIR cell, and
   the 150px floor would otherwise blow them out of their box (B46 C39). */
.dash-grid .chart-card > svg{
  flex:1 1 0; min-height:150px; width:100%; height:100%;
  display:block; overflow:visible;
}
.dash-grid .txn-card .txn-list{ flex:1 1 0; min-height:0; overflow:auto }
/* Resize handle target sits in the card's bottom-inline corner. */
.dash-grid > .card.is-resizing,
.dash-grid > .bal-banner.is-resizing{ z-index:5; opacity:.96 }

/* ── CHART CARDS ───────────────────────────────────────────────────
   No `preserveAspectRatio="none"` anywhere — text would distort. SVGs
   keep their aspect ratio (default xMidYMid meet) and the card sizes
   the SVG via height. Width:100% lets the card determine the visual
   width while the viewBox keeps ticks proportional. */
.chart-card svg{width:100%;display:block;overflow:visible}

.combo-card svg  { aspect-ratio: 600 / 240; height: auto; max-height: 320px; }
/* The 2×2 grid below — each row should read as one unified band, so all
   four SVGs target the same display height. Without a uniform height the
   wide-aspect charts (candle, bar) shrink to ~160 px while the square
   radar fills to 280, leaving uneven whitespace between cards in a row. */
.radar-card svg,
.candle-card svg,
.pie-card svg,
.area-card svg,
.rings-card svg,
.flow-card svg,
.bar-card svg {
  width:100%;height:220px;max-height:220px;
}
/* B40 C56 — new chart cards. B46 C39: the spark cells are a fluid grid and each
   cell is a bounded card so a sparkline can never bleed past its own box. The
   svg fills the cell's remaining height and dashboard.js draws it at that real
   pixel size.
   B46 P6-22/P6-23 — two failure modes to hold at once: rows must SHARE the
   card's height (`1fr`) so there is no dead space under the strips, AND a strip
   must never become a portrait chart when the widget is tall (`max-height`
   bound). Columns cap at 2 (`minmax(min(272px,100%),1fr)`) so 4 accounts always
   form 2 rows × 2 — with 4 columns on one row the single row could not absorb
   the card height and left ~250px blank. */
/* ── B51-16 · the account selector on the balance chart ───────────────────
   The 2×2 `.spark-grid` of small multiples is retired (Pablo: "I'm not sure 4 charts
   into a chart makes sense"). What is left is a `.seg` row in the card header — the
   same control the app uses everywhere else for "pick one of a handful" — which
   scrolls rather than wrapping so the header keeps one line. */
.spark-seg{ flex:0 1 auto;min-width:0;max-width:62%;overflow-x:auto;scrollbar-width:none; }
.spark-seg::-webkit-scrollbar{ display:none; }
.spark-seg .seg-b{ white-space:nowrap; }
.spk-dot{ opacity:.9; }
/* B51-17 — a 1:1-ish chart no longer has to be tall. `chart-flex` lowers the card's
   height floor and its SVG's, so a wide-and-short cell renders a squat donut with a
   side legend instead of a stretched card. */
.dash-grid > .chart-card.chart-flex{ min-height:168px; }
.dash-grid .chart-card.chart-flex > svg{ min-height:112px; }
.ring-leg{ cursor:default; }
.ring-leg-t,.pie-leg-t{ font-size:11.5px; }
/* Debt timeline strip — rows on a shared track: a dot at the day position
   plus a label that flips to the dot's other side past the midpoint, so a
   long name can never run off the card (B46 C39 rebuild). */
/* ── B59 — the debts strip is a COLUMN CHART ───────────────────────────────
   Pablo: "The upcoming and overdue debts look nice but the visualization is not
   quite what I want, I was thinking bars on each timeline date that would show on a
   tooltip how much was for each description."

   The B46 C39 row-per-debt strip (`.debt-tl*`, ~20 rules) is gone with the markup it
   styled. What replaces it: one absolutely-positioned bar per DATE on a shared
   baseline, its height a percentage of the busiest day, its tooltip the day's
   descriptions. Three things this shape has to get right —
     • bars sit on a baseline and grow UP, so the row is read as a chart, not a list;
     • a bar is a real button (keyboard-reachable, and it carries the aria-label the
       tooltip shows), because the tooltip is the content;
     • the day label rides UNDER the baseline, which is why the track reserves room
       for it instead of letting the bar occupy the whole card. */
.debt-tl{ position:relative;display:flex;flex-direction:column;gap:8px;padding:6px 2px 0;flex:1 1 0;min-height:0; }
/* B61 - the axis is the ZERO line in the middle now, not the bottom edge, so the
   bottom rule is gone; a second horizontal line there read as a second axis. */
.debt-bars{ position:relative;flex:1 1 0;min-height:124px;padding-bottom:18px; }
/* today's line runs the full height of the plot, behind the bars */
.debt-bars-now{ position:absolute;inset-block:0 18px;width:2px;border-radius:2px;
  background:color-mix(in srgb,var(--accent) 55%,transparent);transform:translateX(-50%);z-index:0; }
[dir="rtl"] .debt-bars-now{ transform:translateX(50%); }
.debt-bars-now-l{ position:absolute;top:-2px;inset-inline-start:50%;transform:translateX(-50%);
  padding:0 5px;border-radius:6px;background:var(--bg-1,#fff);white-space:nowrap;
  font:700 9.5px var(--mk-font-ui);color:var(--accent-text,var(--accent)); }
[dir="rtl"] .debt-bars-now-l{ transform:translateX(50%); }
/* B61 - a DIVERGING column plot: the zero axis is the middle of the track, out
   goes down from it, in goes up from it, and a segment is anchored ON the axis
   (bottom:50% / top:50%) so nothing can hover above the line. */
.debt-bar{ position:absolute;top:0;bottom:18px;transform:translateX(-50%);z-index:1;
  width:26px;padding:0;border:0;background:none;cursor:pointer; }
[dir="rtl"] .debt-bar{ transform:translateX(50%); }
.debt-zero{ position:absolute;inset-inline:0;top:calc(50% - 9px);height:1px;z-index:0;
  background:var(--border,#e3e8ee); }
.debt-seg{ position:absolute;inset-inline-start:50%;width:14px;margin-inline-start:-7px;
  transition:height .32s cubic-bezier(.4,0,.2,1),filter .15s ease; }
.debt-seg-in{ bottom:calc(50% + 9px);height:var(--in-h);border-radius:5px 5px 0 0;
  background:var(--mk-success,#22C55E); }
.debt-seg-out{ top:calc(50% - 9px);height:var(--out-h);border-radius:0 0 5px 5px;
  background:var(--accent); }
.debt-bar:hover .debt-seg{ filter:brightness(1.08) saturate(1.1); }
.debt-bar:focus-visible{ outline:2px solid var(--accent);outline-offset:2px;border-radius:6px; }
/* a day carrying more than one debt says so on the bar — the tooltip has the detail */
.debt-bar-n{ position:absolute;top:0;inset-inline-start:50%;transform:translateX(-50%);
  min-width:14px;height:14px;padding:0 3px;display:grid;place-items:center;border-radius:999px;
  background:var(--bg-1,#fff);box-shadow:inset 0 0 0 1px var(--border,#e3e8ee);
  font:700 9px var(--mk-font-mono,var(--mk-font-ui));color:var(--fg-2); }
.debt-bar-d{ position:absolute;bottom:-17px;white-space:nowrap;
  font:600 9.5px var(--mk-font-ui);color:var(--fg-3);font-variant-numeric:tabular-nums; }
/* only the OUT side carries the overdue tone - money coming in is never overdue */
.debt-bar-over .debt-seg-out{ background:var(--mk-debt,#DC2626); }
.debt-bar-over .debt-bar-d{ color:var(--mk-debt-text,#DC2626);font-weight:700; }
.debt-bars-key{ display:flex;flex-wrap:wrap;gap:10px;justify-content:center;flex:0 0 auto; }
.debt-key{ display:inline-flex;align-items:center;gap:5px;font:600 10px var(--mk-font-ui);color:var(--fg-3); }
.debt-key i{ width:8px;height:8px;border-radius:2px;flex:0 0 auto; }
.debt-key-due i{ background:var(--accent); }
.debt-key-in i{ background:var(--mk-success,#22C55E); }
.debt-key-over i{ background:var(--mk-debt,#DC2626); }
/* Keep the radar centred when its 1:1 width is narrower than the card. */
.radar-card svg { margin-inline:auto;display:block; }

/* Inside the bento grid the SVG fills the spanned cell block — drop the
   fixed pixel heights, max-height caps, and intrinsic aspect-ratio so a
   taller span yields a taller chart. The default preserveAspectRatio
   (meet) keeps each chart's own proportions, centered, within the cell. */
.dash-grid .chart-card > svg{ aspect-ratio:auto; max-height:none; height:100% }
.dash-grid .radar-card svg{ max-width:none }

/* ── SVG PRIMITIVES ────────────────────────────────────────────── */
.cx-grid line{stroke:var(--border);stroke-width:1;stroke-dasharray:2 4}
.cx-axis text{fill:var(--fg-2);font:500 10px var(--mk-font-ui)}
.cx-axis-num{fill:var(--fg-3);font:500 10px var(--mk-font-mono);font-variant-numeric:tabular-nums}
/* B58 (Pablo, on the donut's slice labels: "On dark theme, these labels have an
   unreadable font") — `.axis-t` had NO rule anywhere in the project, so every
   pie/ring legend label fell back to the SVG defaults: black fill in a serif
   face. Invisible on a dark surface, and the wrong font on a light one. */
.axis-t{fill:var(--fg-2);font:600 11px var(--mk-font-ui)}
.cx-area-money{fill:color-mix(in srgb, var(--accent) 22%, transparent)}
.cx-area-debt {fill:color-mix(in srgb, var(--mk-debt) 18%, transparent)}
.cx-line-money{fill:none;stroke:var(--accent);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.cx-line-debt {fill:none;stroke:var(--mk-debt);stroke-width:1.5;stroke-linecap:round;stroke-linejoin:round}
.cx-line-net  {fill:none;stroke:var(--accent-2);stroke-width:2.5;stroke-linecap:round;stroke-linejoin:round}
.cx-dot-net   {fill:var(--accent-2);stroke:var(--bg-1);stroke-width:2}

.radar-grid polygon{fill:none;stroke:var(--border);stroke-width:1}
.radar-axis line{stroke:var(--border);stroke-width:1;stroke-dasharray:2 4}
.radar-axis text{fill:var(--fg-2);font:600 11px var(--mk-font-ui)}
.radar-shape{fill:color-mix(in srgb, var(--accent) 28%, transparent);stroke:var(--accent);stroke-width:2;stroke-linejoin:round}
.radar-dot{fill:var(--accent);stroke:var(--bg-1);stroke-width:1.5;cursor:pointer}

.candle-up   .c-body{fill:var(--accent)}
.candle-up   .c-wick{stroke:var(--accent);stroke-width:1.5}
.candle-down .c-body{fill:var(--mk-debt)}
.candle-down .c-wick{stroke:var(--mk-debt);stroke-width:1.5}
.candle-axis text{fill:var(--fg-2);font:500 10px var(--mk-font-ui)}
.candle-grid text{fill:var(--fg-3);font:500 10px var(--mk-font-mono);font-variant-numeric:tabular-nums}

.pie-slice{stroke:var(--bg-1);stroke-width:2;cursor:pointer;transition:transform 200ms var(--mk-ease);transform-origin:center}
.pie-slice:hover{transform:scale(1.04)}
.pie-slice-1{fill:var(--accent)}
.pie-slice-2{fill:var(--accent-2)}
.pie-slice-3{fill:var(--mk-navy-700)}
.pie-slice-4{fill:var(--mk-debt)}
.pie-slice-5{fill:var(--mk-blue-300)}
.pie-label{fill:var(--fg-1);font:600 11px var(--mk-font-ui)}
.pie-label-sm{fill:var(--fg-3);font:500 10px var(--mk-font-mono);font-variant-numeric:tabular-nums}

.bar-income{fill:var(--accent);transition:fill 150ms var(--mk-ease)}
.bar-expense{fill:var(--mk-debt);transition:fill 150ms var(--mk-ease)}
.bar-axis text{fill:var(--fg-2);font:500 10px var(--mk-font-ui)}
.bar-grid text{fill:var(--fg-3);font:500 10px var(--mk-font-mono);font-variant-numeric:tabular-nums}

/* ── HOVER HIT ZONES (invisible rects) ──────────────────────────── */
.hit{fill:transparent;cursor:crosshair}
.hit:hover ~ .crosshair{opacity:1}

/* ── TOOLTIP ────────────────────────────────────────────────────── */
.chart-tooltip{
  position:absolute;pointer-events:none;
  background:var(--bg-1);
  border:1px solid var(--border);
  border-radius:8px;
  box-shadow:var(--shadow-md);
  padding:8px 10px;
  font:500 11px var(--mk-font-ui);
  color:var(--fg-1);
  min-width:120px;
  --tt-dx:0px;
  opacity:0;
  transform:translate(calc(-50% + var(--tt-dx)), calc(-100% - 8px));
  transition:opacity 120ms var(--mk-ease);
  z-index:5;
}
.chart-tooltip.on{opacity:1}
/* Edge-aware flip: when the anchor is too close to the top of the
   chart host the JS adds .tt-below, which places the tip under the
   point instead. Horizontal clamp (--tt-dx) is set by the same code
   and applied via the transform above; .tt-clamp-l / .tt-clamp-r are
   provided as hooks for any future left/right-edge specific styling. */
.chart-tooltip.tt-below{
  transform:translate(calc(-50% + var(--tt-dx)), 8px);
}
.chart-tooltip .tt-title{font:700 11px var(--mk-font-ui);color:var(--fg-1);margin-bottom:4px;letter-spacing:.02em}
.chart-tooltip .tt-row{display:flex;justify-content:space-between;gap:14px;align-items:center;line-height:1.4}
.chart-tooltip .tt-row > span:first-child{color:var(--fg-2);display:inline-flex;align-items:center;gap:6px}
.chart-tooltip .tt-row > span:last-child{font:600 11px var(--mk-font-mono);color:var(--fg-1);font-variant-numeric:tabular-nums}
.chart-tooltip .tt-sw{display:inline-block;width:8px;height:8px;border-radius:2px}

.chart-host{position:relative;min-width:0}

/* ── WIDGET MOCK / RELOAD SKELETON (Pablo 2026-06-02 W1 #1) ──────────
   `.widget-ghost` is an absolute overlay built by dashboard-editor.js
   buildWidgetGhost(). On reload it sits over each card carrying a typed
   mock chart + pulsing label bars (the held skeleton state), then
   cross-fades out as real content fades in. The SAME markup, with
   `.is-pulsing` dropped, is the static no-access placeholder (Wave 3).
   Each sub-element pulses on its own (not one block per widget). */
.dash-grid > .card{position:relative}
.widget-ghost{
  position:absolute;inset:0;z-index:3;
  display:flex;flex-direction:column;gap:14px;
  padding:18px;
  background:var(--bg-1);
  border-radius:var(--mk-radius-lg);
  pointer-events:none;
  transition:opacity 420ms var(--mk-ease);
}
.widget-ghost.is-leaving{opacity:0}
/* Balance ghost sits on the navy banner — match the flattened hydrate
   surface (bg-2) and the banner's own layout (hero column + two tiles). */
.bal-banner > .widget-ghost{background:var(--bg-2);padding:24px;flex-direction:row;align-items:center;gap:24px}
.ghost-balance .gh-net{flex:1.4;display:flex;flex-direction:column;gap:10px;min-width:0}
.ghost-balance .gh-tiles{flex:1;display:grid;grid-template-columns:1fr 1fr;gap:12px}
.ghost-balance .gh-tile{
  background:var(--bg-1);border-radius:12px;padding:16px;
  display:flex;flex-direction:column;gap:10px;justify-content:center;
}
.gh-head{display:flex;flex-direction:column;gap:8px;flex:0 0 auto}
/* Pulsing bars — bg pulse per element, with a small per-bar stagger so
   the skeleton breathes rather than flashing as one flat block. */
.gh-bar{display:block;height:12px;border-radius:7px;background:var(--bg-2)}
.widget-ghost.is-pulsing .gh-bar{animation:skel-pulse 1.6s ease-in-out infinite}
.widget-ghost.is-pulsing .gh-bar:nth-child(2){animation-delay:.2s}
.widget-ghost.is-pulsing .gh-bar:nth-child(3){animation-delay:.4s}
.gh-title{width:46%;height:15px}
.gh-bar-sm{width:32%;height:11px}
.gh-bar-xs{width:24%;height:10px}
.gh-bar-md{width:60%;height:18px}
.gh-hero{width:62%;height:34px;border-radius:10px}
/* Typed mock chart — desaturated so it reads as a placeholder, not real
   data. !important beats the body.hydrating `.body-in svg{opacity:0}`
   content-hide rule (which would otherwise blank the ghost chart too). */
.gh-chart{flex:1 1 0;min-height:0;position:relative}
.gh-chart svg{width:100%;height:100%;display:block;filter:grayscale(1);opacity:.5 !important}
.widget-ghost.is-pulsing .gh-chart{animation:gh-soft-pulse 1.6s ease-in-out infinite .3s}
@keyframes gh-soft-pulse{0%,100%{opacity:.85}50%{opacity:.5}}
/* txn ghost rows */
.ghost-txn .gh-rows{flex:1 1 0;display:flex;flex-direction:column;justify-content:space-around;gap:6px;min-height:0}
.gh-row{display:flex;align-items:center;gap:12px}
.gh-dot{width:34px;height:34px;border-radius:10px;background:var(--bg-2);flex:0 0 auto}
.widget-ghost.is-pulsing .gh-dot{animation:skel-pulse 1.6s ease-in-out infinite}
.gh-row-l{flex:1;height:12px}
.gh-row-amt{width:64px;height:12px;flex:0 0 auto}
/* Preview no-access mock (W3): a STATIC widget ghost (no pulse) + a purple
   "No access" lock chip, so a viewing-as user's restricted widget reads as
   "you can't see this", not "still loading". */
.widget-ghost.is-preview-noaccess{ /* static — no pulse classes applied */ }
.widget-noaccess-tag{
  position:absolute;top:14px;inset-inline-end:14px;
  display:inline-flex;align-items:center;gap:5px;
  padding:4px 9px;border-radius:999px;
  background:color-mix(in srgb, var(--mk-preview) 14%, var(--bg-1));
  border:1px solid color-mix(in srgb, var(--mk-preview) 35%, var(--border));
  color:var(--mk-preview);
  font:600 10px var(--mk-font-ui);letter-spacing:.02em;
}
.widget-noaccess-tag .mi{font-size:13px}

/* ── DASHBOARD EDITOR (Wave C) ──────────────────────
   Triggered by `.shell.dashboard-edit-mode` on the shell root. Each
   chart-card gains a draggable handle (the .card-h bar), a resize
   handle (bottom-right corner), and a corner action cluster (edit +
   remove). Save/Cancel float in `#dashEditBar` at the bottom of the
   viewport. */
.dashboard-edit-toggle{display:none}
body[data-role="admin"] .dashboard-edit-toggle{
  display:inline-flex;
  /* Distinct from neighbour Filter/Sort/Alerts pills — accent-tinted
     border so the user reads it as an editor entry, not just another
     filter chip. */
  border:1px solid color-mix(in srgb, var(--accent) 55%, var(--border)) !important;
  background:color-mix(in srgb, var(--accent) 6%, transparent);
  color:var(--accent);
}
body[data-role="admin"] .dashboard-edit-toggle:hover{
  background:color-mix(in srgb, var(--accent) 14%, transparent);
}
body[data-role="admin"] .dashboard-edit-toggle.on{
  background:var(--accent);
  color:var(--accent-fg);
  border-color:var(--accent) !important;
}
body[data-role="admin"] .dashboard-edit-toggle .mi{color:inherit}
/* Hover-only edit chrome (Pablo 2026-05-31): a staging dashboard reads as
   a regular dashboard at rest — no outlines, no tint, no corner handle, no
   edit/delete buttons. Hovering (or sustained-touch / keyboard focus) a
   single widget reveals THAT widget's chrome. The active drag / drop /
   resize states below still force their own outline so a drag in progress
   stays legible even when the pointer leaves the source card. */
.shell.dashboard-edit-mode .chart-card,
.shell.dashboard-edit-mode .txn-card{
  outline:1.5px dashed transparent;
  outline-offset:-2px;
  transition:transform 120ms ease, outline-color 150ms ease;
}
.shell.dashboard-edit-mode .is-editable:hover,
.shell.dashboard-edit-mode .is-editable:focus-within,
.shell.dashboard-edit-mode .is-editable.mocca-touch-revealed{
  outline-color:color-mix(in srgb, var(--accent) 55%, transparent);
}
.shell.dashboard-edit-mode .chart-card .card-h,
.shell.dashboard-edit-mode .txn-card .card-h{cursor:grab}
.shell.dashboard-edit-mode .chart-card.is-dragging,
.shell.dashboard-edit-mode .txn-card.is-dragging{opacity:.45;transform:scale(.985)}
.shell.dashboard-edit-mode .chart-card.is-drop-target,
.shell.dashboard-edit-mode .txn-card.is-drop-target,
.shell.dashboard-edit-mode .dash-add-tile.is-drop-target{
  outline-color:var(--accent);
  background:color-mix(in srgb, var(--accent) 6%, transparent);
}
.shell.dashboard-edit-mode .chart-card.is-resizing,
.shell.dashboard-edit-mode .txn-card.is-resizing{outline-color:var(--accent)}

/* Edit/delete affordances on every editable widget (Pablo 2026-05-30,
   tightened 2026-05-30b after they were still showing at rest):
   - Top-RIGHT corner of the widget (mirrored to top-left in RTL via
     `inset-inline-end`).
   - Hover (mouse) OR sustained-touch (`mocca-touch-revealed` class set
     by moccaSustainedTouch helper in shell.js) reveals them.
   - `!important` on the default opacity:0 because earlier feedback was
     "still showing on non-hover" — we want to win the cascade against
     any future widget-card rule that might bleed opacity in.
   - Staging-only color (the staging green token bleeds through here so
     the affordance reads as a staging-environment control). */
.is-editable{position:relative}
.is-editable > .card-edit-actions{
  position:absolute;
  top:10px;
  inset-inline-end:10px;
  display:inline-flex;gap:4px;
  z-index:8;
  opacity:0 !important;
  pointer-events:none;
  visibility:hidden;
  transition:opacity 160ms var(--mk-ease), visibility 0s linear 160ms;
}
.is-editable:hover > .card-edit-actions,
.is-editable:focus-within > .card-edit-actions,
.is-editable.mocca-touch-revealed > .card-edit-actions,
.is-editable > .card-edit-actions:hover,
.is-editable > .card-edit-actions:focus-within{
  opacity:1 !important;
  pointer-events:auto;
  visibility:visible;
  transition:opacity 160ms var(--mk-ease), visibility 0s linear 0s;
}
/* B67 R67-026 — the corner stays where Pablo put it; while the affordances show, a header that carries its own action
   ("View more") makes room for them — hovering the card to reach "View more" put the pencil on top of it. */
.is-editable > .card-h{transition:padding-inline-end 160ms var(--mk-ease)}
.is-editable:is(:hover, :focus-within, .mocca-touch-revealed) > .card-h:has(> .btn-ghost, > a, > button){padding-inline-end:66px}
.card-edit-btn{
  width:28px;height:28px;border-radius:7px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-2);cursor:pointer;
  display:inline-flex;align-items:center;justify-content:center;
}
.card-edit-btn:hover{color:var(--accent);border-color:var(--accent)}
.card-edit-btn .mi{font-size:15px}
.card-edit-rm:hover{color:var(--mk-danger);border-color:var(--mk-danger)}

/* Staging-only widget chrome — dashed staging outline + a low-opacity
   staging tint. Both are HOVER-ONLY (Pablo 2026-05-31): at rest the
   widget shows nothing, so a staging dashboard is indistinguishable from
   production until you hover a card. Sits BELOW the header (.page-h has
   z-index:15) so the chrome never peeks above sticky chrome. */
body[data-env="staging"][data-role="admin"] .is-editable{
  outline:1px dashed transparent;
  outline-offset:2px;
  border-radius:var(--mk-radius-lg);
  transition:outline-color 150ms ease;
}
body[data-env="staging"][data-role="admin"] .is-editable:hover,
body[data-env="staging"][data-role="admin"] .is-editable:focus-within,
body[data-env="staging"][data-role="admin"] .is-editable.mocca-touch-revealed{
  outline-color:color-mix(in srgb, var(--mk-staging) 55%, transparent);
}
body[data-env="staging"][data-role="admin"] .is-editable::after{
  /* Translucent staging tint — sits behind interactive content but on
     top of the widget surface. Pointer-events off so it doesn't block
     drag / resize / button clicks. Hidden at rest, fades in on hover. */
  content:'';
  position:absolute;
  inset:0;
  border-radius:inherit;
  background:color-mix(in srgb, var(--mk-staging) 6%, transparent);
  pointer-events:none;
  z-index:1;
  opacity:0;
  transition:opacity 160ms var(--mk-ease);
}
body[data-env="staging"][data-role="admin"] .is-editable:hover::after,
body[data-env="staging"][data-role="admin"] .is-editable:focus-within::after,
body[data-env="staging"][data-role="admin"] .is-editable.mocca-touch-revealed::after{
  opacity:1;
}
/* Staging-green --accent override for .card-edit-actions lives in
   env-theater.css (app-level, outside the DS closure). */
body[data-env="staging"][data-role="admin"] .card-edit-btn{
  background:color-mix(in srgb, var(--mk-staging) 14%, var(--bg-1));
  border-color:color-mix(in srgb, var(--mk-staging) 40%, var(--border));
}
body[data-env="staging"][data-role="admin"] .card-edit-btn:hover{
  color:var(--mk-staging);
  border-color:var(--mk-staging);
}
body[data-env="staging"][data-role="admin"] .card-edit-rm:hover{
  color:var(--mk-danger);
  border-color:var(--mk-danger);
}
body[data-env="staging"][data-role="admin"] .card-resize-handle{
  color:var(--mk-staging);
}
/* Resize handle — three little parallel diagonal strokes in the bottom-
   right corner (Material-style drag handle), opacity-tuned so it reads
   as an affordance, not chrome. The strokes are SVG-mask gradients,
   tinted via currentColor. (Pablo 2026-05-30 redesign — the old
   half-triangle gradient looked weird.) */
.card-resize-handle{
  position:absolute;inset-inline-end:6px;bottom:6px;
  width:16px;height:16px;
  cursor:nwse-resize;z-index:6;
  color:var(--accent);
  /* touch-action:none so a finger-drag on the handle resizes the widget
     instead of scrolling the page (Pablo 2026-06-01 — touch resize). */
  touch-action:none;
  /* Hidden at rest — the corner indicator is part of the per-widget edit
     chrome and reveals on hover with the outline / buttons (Pablo
     2026-05-31). */
  opacity:0;
  transition:opacity 140ms var(--mk-ease);
  background:
    linear-gradient(135deg, transparent 5px, currentColor 5px, currentColor 6px, transparent 6px),
    linear-gradient(135deg, transparent 9px, currentColor 9px, currentColor 10px, transparent 10px),
    linear-gradient(135deg, transparent 13px, currentColor 13px, currentColor 14px, transparent 14px);
  background-repeat:no-repeat;
  background-size:100% 100%;
}
/* Bigger invisible hit area on touch so the 16px handle is grabbable with
   a fingertip without enlarging the visible glyph. B46 P6-ML02 made route
   edit mode reachable at mobile for the first time, so this target now
   carries real weight — -14px puts it at exactly the 44px floor. */
@media (pointer: coarse){
  .card-resize-handle::before{
    content:'';position:absolute;inset:-14px;
  }
}
/* !important beats the hydrate-cascade @keyframes (mocca-chart-chrome-in,
   fill-mode:both) that otherwise holds its animated end value over a
   normal :hover rule — same pattern as .card-edit-actions above. */
.is-editable:hover > .card-resize-handle,
.is-editable:focus-within > .card-resize-handle,
.is-editable.mocca-touch-revealed > .card-resize-handle,
.card-resize-handle:hover{opacity:1 !important}
html[dir="rtl"] .card-resize-handle{
  /* Mirror the strokes in RTL so the diagonal slope points the right way. */
  transform:scaleX(-1);
  cursor:nesw-resize;
}

.card-trunc-ctl{
  /* RESERVE the slot at rest (visibility, not display) so revealing the
     control on hover doesn't reflow the header and shove the card legend
     sideways (Pablo 2026-06-01: "the legends move on hover, this should
     not happen"). The control is only mounted in edit mode, so this
     reserved slot never affects a production/non-edit header. */
  display:inline-flex;visibility:hidden;
  align-items:center;gap:6px;
  margin-inline-start:auto;
}
/* Truncation control is part of the per-widget edit chrome — reveal it
   (in place, no layout shift) with the rest on hover (Pablo 2026-05-31). */
.shell.dashboard-edit-mode .is-editable:hover .card-trunc-ctl,
.shell.dashboard-edit-mode .is-editable:focus-within .card-trunc-ctl,
.shell.dashboard-edit-mode .is-editable.mocca-touch-revealed .card-trunc-ctl{visibility:visible}
.card-trunc-l{
  font:600 10px var(--mk-font-ui);letter-spacing:.06em;
  text-transform:none;color:var(--fg-3);
}
.card-trunc-ctl .cs{position:relative}
.card-trunc-ctl .cs .cs-btn{
  height:26px;padding:0 8px;border-radius:6px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-1);font:500 11px var(--mk-font-ui);
  display:inline-flex;align-items:center;gap:4px;cursor:pointer;
}
.card-trunc-ctl .cs .cs-arrow{font-size:14px;color:var(--fg-3)}
.card-trunc-ctl .cs.open .cs-btn{border-color:var(--accent)}
.card-trunc-ctl .cs .cs-menu{
  position:absolute;top:calc(100% + 4px);inset-inline-end:0;z-index:10;
  min-width:120px;background:var(--bg-1);border:1px solid var(--border);
  border-radius:8px;box-shadow:var(--shadow-pop);
  padding:4px;display:none;
}
.card-trunc-ctl .cs.open .cs-menu{display:block}
.card-trunc-ctl .cs .cs-item{
  padding:6px 8px;border-radius:6px;cursor:pointer;
  font:500 12px var(--mk-font-ui);color:var(--fg-1);
}
.card-trunc-ctl .cs .cs-item.on,
.card-trunc-ctl .cs .cs-item:hover{
  background:color-mix(in srgb, var(--accent) 10%, transparent);
}

/* Floating Save/Cancel bar at bottom-center of viewport. */
.dash-edit-bar{
  position:fixed;bottom:18px;left:50%;transform:translateX(-50%);
  z-index:400;display:flex;align-items:center;gap:14px;
  padding:10px 14px;border-radius:14px;
  background:var(--bg-1);border:1px solid var(--border);
  box-shadow:0 16px 40px rgba(0,0,0,.22);
}
.dash-edit-bar[hidden]{display:none !important}
.dash-edit-msg{
  font:500 12px var(--mk-font-ui);color:var(--fg-3);
  max-width:380px;
}
.dash-edit-actions{display:flex;gap:8px}

/* Per-card accent override (color picker in chart edit form). */
.chart-card[style*="--card-accent"] .card-legend i{
  background:var(--card-accent) !important;
}

/* ── CHART EDIT PANEL (C.2) ────────────────────────── */
#chartEditPanel .panel-body{
  display:flex;flex-direction:column;gap:14px;
  padding:14px 16px;
  overflow-y:auto;
}
.ce-section{display:flex;flex-direction:column;gap:6px}
.ce-label{
  font:600 11px var(--mk-font-ui);color:var(--fg-2);
  letter-spacing:.04em;text-transform:none;
}
.ce-input{
  width:100%;padding:8px 10px;border-radius:8px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);
}
.ce-input:focus{outline:none;border-color:var(--accent);box-shadow:0 0 0 3px var(--ring)}
.ce-axis-row{display:flex;gap:8px;align-items:center}
.ce-cs{position:relative;flex:1;min-width:0}
.ce-cs-narrow{flex:0 0 140px}
.ce-cs .cs-btn{
  display:flex;align-items:center;gap:6px;
  height:36px;padding:0 10px;border-radius:8px;
  background:var(--bg-1);border:1px solid var(--border);
  color:var(--fg-1);font:500 13px var(--mk-font-ui);cursor:pointer;
  width:100%;justify-content:space-between;user-select:none;
}
.ce-cs:hover .cs-btn{border-color:var(--accent)}
.ce-cs.open .cs-btn{border-color:var(--accent);box-shadow:0 0 0 3px var(--ring)}
.ce-cs .cs-val{
  flex:1;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;text-align:start;
}
.ce-cs .cs-arrow{font-size:16px;color:var(--fg-3);transition:transform 150ms ease}
.ce-cs.open .cs-arrow{transform:rotate(180deg)}
.ce-cs .cs-menu{
  position:absolute;top:calc(100% + 4px);inset-inline-start:0;inset-inline-end:0;
  z-index:10;max-height:220px;overflow-y:auto;
  background:var(--bg-1);border:1px solid var(--border);border-radius:10px;
  box-shadow:var(--shadow-pop);
  padding:4px;display:none;
}
.ce-cs.open .cs-menu{display:block}
.ce-cs .cs-item{
  padding:8px 10px;border-radius:6px;cursor:pointer;
  font:500 12px var(--mk-font-ui);color:var(--fg-1);
}
.ce-cs .cs-item.on,
.ce-cs .cs-item:hover{background:color-mix(in srgb, var(--accent) 10%, transparent)}
.ce-toggle-row{
  display:flex;align-items:center;gap:8px;
  font:600 12px var(--mk-font-ui);color:var(--fg-1);cursor:pointer;
}
.ce-toggle-row input{width:16px;height:16px;accent-color:var(--accent)}
.is-disabled{opacity:.4;pointer-events:none}
.ce-color-row{display:flex;align-items:center;gap:8px}
.ce-color{
  width:42px;height:36px;padding:0;border:1px solid var(--border);border-radius:8px;
  background:transparent;cursor:pointer;
}
.ce-color-clear{
  padding:6px 10px;border-radius:8px;
  background:transparent;border:1px solid var(--border);color:var(--fg-2);
  cursor:pointer;font:500 12px var(--mk-font-ui);
}
.ce-color-clear:hover{border-color:var(--accent);color:var(--accent)}
.crosshair{
  stroke:var(--accent);stroke-width:1;stroke-dasharray:2 3;
  opacity:0;transition:opacity 120ms;pointer-events:none;
}

/* ── TRANSACTIONS ───────────────────────────────────────────────── */
.txn-card{min-height:0}
.txn-card .txn-list{display:flex;flex-direction:column;gap:0;margin:0 -6px}
.txn-row{
  display:grid;
  grid-template-columns:36px 1fr auto;
  gap:12px;align-items:center;
  padding:10px 6px;border-bottom:1px solid var(--divider);
}
.txn-row:last-child{border-bottom:none}
.txn-icon{
  width:36px;height:36px;border-radius:10px;
  background:var(--bg-2);display:inline-flex;align-items:center;justify-content:center;
  color:var(--fg-2);
}
.txn-icon .mi{font-size:18px}
.txn-row.txn-in  .txn-icon{background:color-mix(in srgb, var(--accent)   12%, transparent);color:var(--accent)}
.txn-row.txn-out .txn-icon{background:color-mix(in srgb, var(--mk-debt) 14%, transparent);color:var(--mk-debt)}
.txn-meta{min-width:0;display:flex;flex-direction:column;gap:1px}
.txn-name{font:600 13px var(--mk-font-ui);color:var(--fg-1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.txn-sub{font:500 11px var(--mk-font-ui);color:var(--fg-3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.txn-amt{font:700 13px var(--mk-font-mono);font-variant-numeric:tabular-nums;text-align:end}
.txn-row.txn-in  .txn-amt{color:var(--accent-text)}
.txn-row.txn-out .txn-amt{color:var(--mk-debt-text)}

/* ── EMPTY STATE (placeholder tabs/pages) ──────────────────────── */
.empty-state{
  flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:12px;color:var(--fg-3);padding:48px 24px;text-align:center;
  border:1px dashed var(--border);border-radius:var(--mk-radius-lg);
  background:var(--bg-1);
}
.empty-state .mi{font-size:36px;color:var(--fg-3)}
.empty-state h4{margin:0;font:600 15px var(--mk-font-ui);color:var(--fg-2)}
.empty-state p{margin:0;font:500 12px var(--mk-font-ui);color:var(--fg-3);max-width:320px}

/* ── RESPONSIVE — banner stacks on tablet, charts stack on mobile ── */
@media (max-width: 720px){
  .bal-banner{grid-template-columns:1fr;gap:18px;padding:20px}
  .bb-v{font-size:30px;white-space:normal}
  .bb-side .bb-v{font-size:18px}
}

/* Mobile-H: compact dashboard. */
@media (max-height: 599px) and (orientation: landscape){
  .bal-banner{padding:14px;gap:12px}
  .bb-v{font-size:22px;white-space:normal}
  .bb-side .bb-v{font-size:16px}
  .card{padding:14px}
  .combo-card svg, .candle-card svg, .pie-card svg, .bar-card svg, .area-card svg, .rings-card svg, .flow-card svg{max-height:180px}
  .radar-card svg{max-height:180px;max-width:200px}
}

/* ── B35 N3 — dashboard style variants ── */
.page-actions-check{ margin-inline-start:auto;font-size:16px;color:var(--accent); }
/* SOFT — airy: bigger radius, feathered shadows, no hard borders */
[data-dash-style="soft"] .dash-grid > *{ border-radius:22px !important;border-color:transparent !important;box-shadow:0 10px 34px rgba(23,32,48,.09) !important; }
[data-dash-style="soft"] .bal-banner{ border-radius:26px !important; }
[data-dash-style="soft"] .dash-grid{ gap:18px !important; }
[data-dash-style="soft"] .kpi,[data-dash-style="soft"] .tbl-card{ border-radius:20px !important;border-color:transparent !important;box-shadow:0 8px 26px rgba(23,32,48,.08) !important; }
/* INK — flat editorial: square-ish, 1.5px outlines, zero shadows */
[data-dash-style="ink"] .dash-grid > *{ border-radius:6px !important;border:1.5px solid var(--fg-1,#22303e) !important;box-shadow:none !important; }
[data-dash-style="ink"] .bal-banner{ border-radius:6px !important; }
[data-dash-style="ink"] .dash-grid{ gap:10px !important; }
[data-dash-style="ink"] .kpi,[data-dash-style="ink"] .tbl-card{ border-radius:6px !important;border:1.5px solid var(--fg-1,#22303e) !important;box-shadow:none !important; }


/* ── B44 C38 — route edit mode: add-widget tile, dyn cards, header truncation ── */
.dash-add-tile{border:1.5px dashed var(--border);border-radius:14px;background:transparent;display:flex;align-items:center;justify-content:center;gap:8px;color:var(--fg-3);cursor:pointer;min-height:140px;font:inherit;font-size:14px;font-weight:600}
.dash-add-tile:hover{color:var(--accent);border-color:var(--accent)}
.dash-add-tile .mi{font-size:22px}
/* B62 UI-80 — the Add tile's picker of unplaced widgets. Mounted on <body>
   (the tile is a <button>), so it takes fixed positioning and its own floor
   above the panel layer's scrim-less dropdowns; the rest is the shell's own
   `.cs-menu`, inherited untouched. */
.dash-add-cs{position:fixed;z-index:640;display:block}
.dash-add-cs > .cs-menu{inset-inline:0;min-width:220px;overflow-y:auto;scrollbar-width:thin}
.cs-empty-note{padding:8px 12px;font:500 12px var(--mk-font-ui);color:var(--fg-3);max-width:260px;text-wrap:pretty}
.dyn-card{display:flex;flex-direction:column}
.dyn-card svg{width:100%;flex:1;min-height:0}
.ce-hint{font-size:11.5px;color:var(--fg-3);margin-top:6px}
.ce-hint b{color:var(--fg-2);font-weight:600}
.dash-trunc{position:relative}
.dash-trunc .cs-menu .cs-item{display:flex;align-items:center;justify-content:space-between;gap:18px;white-space:nowrap}
.dash-trunc-tf{font-size:11px;color:var(--fg-3)}
/* B50-26 (Pablo: "I don't really want a dropdown, I would prefer the row with the
   options in the Roadmap screen") — the timeframe selector is now the same `.seg`
   segmented row as the Roadmap period control. Six segments fit the desktop
   header; at compact widths (where shell.css surfaces this control inline) the
   row scrolls horizontally instead of pushing the header wider. */
.dash-trunc-seg{max-width:100%;flex:0 1 auto}
.dash-trunc-seg button{white-space:nowrap}
@media (max-width:900px){
  /* B50-32 — the seg's own `overflow-x:auto` can only engage if every ancestor
     in the flex chain is allowed to shrink. TWO things block that on `.acts`:
     its default `min-width:auto` floors it at the 6 segments' min-content, AND
     it is `flex:0 0 auto`, so flex-shrink is 0 and `min-width:0` alone changes
     nothing (that caught me once — both must be set). Scoped with `:has()` so no
     other header's actions area is affected. */
  .acts:has(.dash-trunc-seg){ min-width:0;flex-shrink:1; }
  .dash-trunc-seg{overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch;min-width:0}
  .dash-trunc-seg::-webkit-scrollbar{display:none}
  .dash-trunc-seg button{flex:0 0 auto}
}
@media (pointer:coarse){ .dash-trunc-seg button{min-height:38px} }

/* ══ B61 — every chart-editor picker option carries a glyph ═══════════════
   Pablo: "In the chart edit form there's tons of dropdowns, we could have them
   have some icons on the options so that the front end looks a bit more
   complete." The glyph rides the button AND the menu row, so the closed state
   states the pick visually too. */
.ce-cs .cs-btn{display:flex;align-items:center;gap:7px}
.ce-cs-mi{font-size:16px;color:var(--fg-3);flex:0 0 auto}
.ce-cs .cs-btn .cs-val{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ce-cs .cs-item{display:flex;align-items:center;gap:8px}
.ce-cs .cs-item .mi{font-size:16px;color:var(--fg-3);flex:0 0 auto}
.ce-cs .cs-item.on .mi,.ce-cs .cs-item:hover .mi{color:var(--accent-text,var(--accent))}
.ce-cs .cs-item > span:not(.mi){min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
