/* SPACING: reach for a token — `--card-pad`, `--card-gap`, `--sp-1`…`--sp-6` —
   not a raw rem, and not the value in the rule above. Cards on the padding
   contract are enforced by `test/layout-tokens.test.js`; the contract and the
   list of what is on it are in `docs/visual-language.md` → Tokens. Raw values
   still in this file are legacy from a 2px grid, not a precedent to follow. */
/* Overview, rebuilt on the prototype's two-column shape. */
/* ══ Overview, rebuilt on the prototype's two-column shape ══════════ */
/* ── The Overview's own components. Everything .ov-*, .anom-* and .cs-* is
   here: no other stylesheet states or restates any of it. ── */
#ov-nudge,#ov-startbal-nudge,#ov-sample-nudge{margin-bottom:1.25rem;}
/* The sentence takes the row; the reset button stays a control at the end, and
   wraps under the sentence when the row is narrow. */
#ov-sample-nudge{flex-wrap:wrap;}
#ov-sample-nudge span{flex:1 1 16rem;}
/* Running hot rows: name, overage, bar. Caption already says vs the average;
   a second "spent vs usual" line was the same fact twice. */
.anom-row,
.ov-catsplit .cs-row{
  display:grid;
  grid-template-columns:minmax(0,1fr) max-content max-content;
  column-gap:var(--sp-4);
  row-gap:var(--sp-2);
  align-items:baseline;
  font-size:var(--fs-label);
}
.anom-row .cat-mark{min-width:0;}
.anom-amt{
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
  font-weight:600;
  color:var(--neg);
}
.anom-delta{
  font-size:var(--fs-meta);
  font-weight:500;
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
  color:var(--muted);
  min-width:1.875rem;
  text-align:end;
}
.anom-bar{
  grid-column:1/-1;
  height:var(--sp-2);
  border-radius:var(--radius-pill);
  overflow:hidden;
  background:var(--chart-neg);
}
.anom-bar i{
  display:block;
  height:100%;
  border-radius:var(--radius-pill);
  background:var(--c);
}
/* Ring above, legend beneath it. One legend row per line rather than two side by
   side — at 340px wide the pair would wrap anyway, and stacked they line their
   figures up in a column you can read down. */
/* Recent transactions reuses expense day cards (.exp-tile). The scroll band is
   one surface like the chart and Running hot cards; each day tile matches too. */
.ov-catsplit{display:flex;flex-direction:column;gap:var(--sp-5);}
.ov-catsplit .cs-nm{font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;}
.ov-catsplit .cs-amt{font-weight:600;font-variant-numeric:tabular-nums;}
.ov-catsplit .cs-pct{
  color:var(--muted);
  font-size:var(--fs-meta);
  font-variant-numeric:tabular-nums;
  min-width:1.875rem;
  text-align:end;
}
.ov-catsplit .meter.cs-bar{grid-column:1/-1;background:var(--surface3);}
.ov-catsplit .cs-row.cs-rest .cs-nm{font-weight:500;color:var(--muted);}
.ov-greet{margin:0 0 0.875rem;}
.ov-greet h2{font-size:var(--fs-display);font-weight:600;letter-spacing:-.022em;}
.ov-greet-sub{color:var(--muted);font-size:var(--fs-body);margin-top:2px;}
.split{
  display:grid;
  grid-template-columns:minmax(0,1fr) minmax(var(--rail-min),var(--rail-max));
  gap:var(--split-gap);
  align-items:start;
}
@media (max-width:1150px){
  .split{
    grid-template-columns:minmax(0,1fr);
    grid-template-areas:"rail" "main";
  }
  .split-rail{grid-area:rail;}
  .split-main{grid-area:main;}
}
.split-main,.split-rail{min-width:0;}
/* The hover pill (js/08-ui.js) is prepended to a rail on first hover; counting past it
   keeps the heading from gaining its top margin and the whole rail from dropping. */
.split-main > .card-head:nth-child(1 of :not(.hover-pill)),.split-rail > .card-head:nth-child(1 of :not(.hover-pill)){margin-top:0;}
.card.pad{padding:var(--card-pad);}
/* hero spend card */
/* ── Overview: three bands, one screen ──────────────────────────────────────
   Band 1 is the KPI row, bands 2 and 3 each pair a wide block with a narrow one.
   The old layout stacked eight full-width blocks in a main column beside a rail,
   which ran 1467px tall and put the donut below the fold. */
.ov-kpis{display:grid;grid-template-columns:1.35fr 1fr 1fr 1fr;gap:var(--card-gap);}
.kpi{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  padding:var(--card-pad);
  min-width:0;
  box-shadow:var(--elev);
}
.kpi.lead{
  background:var(--surface);
  border-color:var(--border);
}
.kpi-strip > .kpi .k,.kpi .k{
  font-size:var(--fs-meta);
  color:var(--muted);
  font-weight:500;
  min-width:0;
  max-width:100%;
  overflow-wrap:anywhere;
}
.kpi-strip > .kpi .v,.kpi .v{
  font-size:var(--fs-figure);
  font-weight:600;
  letter-spacing:-.02em;
  margin-top:var(--sp-1);
  font-variant-numeric:tabular-nums;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
  min-width:0;
  max-width:100%;
}
.kpi-strip > .kpi.lead .v,.kpi.lead .v{font-size:var(--fs-display);}
.kpi-strip > .kpi .s,.kpi .s{
  font-size:var(--fs-meta);
  color:var(--muted);
  margin-top:var(--sp-1);
  min-width:0;
  max-width:100%;
  overflow-wrap:anywhere;
}
.kpi .pill{margin-top:0.3125rem;}
@media (max-width:1150px){
  .ov-kpis{grid-template-columns:1fr 1fr;}
}
.ov-spend-card{padding:1.25rem;}
/* Charts are drawn left to right in every language: the JS places marks, the
   guide and the tip by physical left, and a time axis reads left to right.
   The tip holds words, so it takes the page's direction back. */
.ov-spend-chart{margin-top:0.875rem;position:relative;direction:ltr;}
.ov-spend-chart svg{width:100%;height:clamp(150px,16vh,240px);display:block;}
/* Transparent layer over the plot that owns the pointer, so the tooltip never
   sits between the cursor and the thing it is describing. */
.ov-spend-hit{position:absolute;inset:0 0 18px 0;cursor:crosshair;}
.ov-spend-guide{
  position:absolute;
  top:0;
  bottom:18px;
  width:1px;
  background:var(--border-hover);
  pointer-events:none;
  opacity:0;
  transition:opacity .2s ease;
}
.ov-spend-knob{
  position:absolute;
  width:0.5625rem;
  height:0.5625rem;
  border-radius:50%;
  background:var(--surface);
  border:2.5px solid var(--chart-neg);
  pointer-events:none;
  opacity:0;
  transform:translate(-50%,-50%);
  transition:opacity .2s ease;
}
.ov-spend-tip{
  position:absolute;
  pointer-events:none;
  opacity:0;
  transition:opacity .2s ease;
  z-index:5;
  background:var(--surface3);
  border:1px solid var(--border-hover);
  border-radius:var(--radius-sm);
  padding:var(--sp-2) 0.6875rem;
  box-shadow:var(--elev-hover);
  white-space:nowrap;
  transform:translate(-50%,-100%);
}
:root[dir="rtl"] .ov-spend-tip{direction:rtl;}
.ov-spend-tip .d{
  font-size:var(--fs-meta);
  color:var(--muted);
  font-weight:500;
}
.ov-spend-tip .t{
  font-size:var(--fs-body);
  font-weight:600;
  font-variant-numeric:tabular-nums;
  margin-top:0.1875rem;
}
.ov-spend-tip .x{font-size:var(--fs-micro);color:var(--muted);font-variant-numeric:tabular-nums;margin-top:2px;}
.ov-spend-chart.on .ov-spend-guide,
.ov-spend-chart.on .ov-spend-knob,
.ov-spend-chart.on .ov-spend-tip{
  opacity:1;
}
.ov-spend-axis{
  display:flex;
  justify-content:space-between;
  color:var(--muted);
  font-size:var(--fs-micro);
  margin-top:var(--sp-1);
}
/* rail figures */
/* generic list rows, shared by This month / Sources / Recent / Upcoming */
.split-rows{display:flex;flex-direction:column;}
#ov-recent .empty-state{padding:1.625rem var(--sp-4);}
/* The plot SVG stretches to the card (preserveAspectRatio="none"), which would turn
   an SVG circle into an oval, so the end-of-line dot is an HTML element placed by
   percentage over it and stays round at any width. */
.ov-spend-plot{position:relative;}
.ov-spend-dot{
  position:absolute;
  width:0.5625rem;
  height:0.5625rem;
  border-radius:50%;
  background:var(--surface);
  border:2.5px solid var(--chart-neg);
  transform:translate(-50%,-50%);
  pointer-events:none;
}
/* ══ Overview bento dashboard ══════════════════════════════════════════════
   12-column grid; see the comment in index.html for the row plan. Row 1 is the
   KPI tiles across the width; row 2 the spend chart; row 3 Where the money went
   beside Running hot. Recent transactions is the right-hand column and spans from
   row 2 to the bottom of the window, so the height nothing else wants becomes
   more transactions rather than empty card. */
.ov-dash{display:grid;grid-template-columns:repeat(12,minmax(0,1fr));gap:var(--dash-gap);align-items:stretch;}
.ov-dash > *{min-width:0;display:flex;flex-direction:column;}
.ov-dash > * > .card{flex:1;}
.ov-dash > .ov-kpis{grid-column:1/-1;display:grid;}
/* The heading keeps its line and the note beside it gives up the width: at five
   columns "RUNNING HOT" wrapped while its note was clipped mid-word, which put the
   two row-3 cards on different baselines. */
.ov-dash .card-head{margin:0 0 var(--sp-2);white-space:nowrap;min-width:0;}
.ov-dash .card-head .cap{min-width:0;overflow:hidden;text-overflow:ellipsis;}
/* Nine columns for the chart and the two lists under it, three for Recent. The
   categories take 4 of the 9 so the longest names ("Transportation") stay whole at
   1280px, and Running hot takes the other 5 because its row is a sentence. */
.ov-tile-chart{grid-column:1/9;grid-row:2;}
.ov-tile-cats{grid-column:1/5;grid-row:3;}
.ov-tile-hot{grid-column:5/9;grid-row:3;}
.ov-tile-recent{grid-column:9/-1;grid-row:2/-1;}
/* These two size to their rows. Recent still eats leftover height on the right;
   stretching this pair with the grid left a blank well in each card. */
.ov-tile-cats,.ov-tile-hot{align-self:start;}
/* Nothing running hot: that card is display:none and the categories take the row. */
.ov-dash:has(#ov-anomaly-card[style*="display:none"]) .ov-tile-cats{grid-column:1/9;}
/* The KPI row was sized for a screen where it shared the fold with one big chart. */
.ov-dash .ov-kpis{grid-template-columns:subgrid;gap:var(--dash-gap);row-gap:var(--sp-3);}
/* Balance, Income and Spent share one strip card — one figure size for all three panes. */
.ov-dash .kpi-strip > .kpi .v{font-size:var(--fs-display);}
/* The list fills the column under the heading. It is an absolute layer so a
   grid item's min-height does not grow with every card; overflow scrolls. */
.ov-tile-recent .ov-recent-frame{
  position:relative;
  flex:1;
  min-height:0;
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--elev);
}
.ov-tile-recent #ov-recent{
  position:absolute;
  inset:0;
  overflow:auto;
  scrollbar-width:none;
  -ms-overflow-style:none;
  container-type:inline-size;
  /* Tight to the panel edge; room lives inside each day tile instead. */
  padding:var(--sp-2);
  gap:var(--sp-3);
}
.ov-tile-recent #ov-recent::-webkit-scrollbar{display:none;}
.ov-tile-recent #ov-recent > .exp-tile{
  flex-shrink:0;
  background:var(--surface);
  border-radius:var(--radius-sm);
  box-shadow:none;
  padding-block:var(--sp-3);
  padding-inline:var(--sp-3) 0;
  gap:var(--sp-4);
}
.ov-tile-recent #ov-recent > .exp-tile .exp-entry{gap:var(--sp-4);}
.ov-tile-recent #ov-recent > .exp-tile .exp-entry + .exp-entry{
  margin-top:var(--sp-3);
  padding-top:var(--sp-3);
}
.ov-tile-recent #ov-recent > .exp-tile .exp-day{background:var(--surface2);}
/* Balance tile meter */
.ov-meter:empty{display:none;}
.ov-meter{margin-top:0.625rem;}
/* Two captions share the bar. They stay on one line while the pane is wide
   enough, and wrap inside it when it is not — a nowrap pair used to paint
   across the hairline into the next pane (and, at half a wide window, into
   Financial trend). A single caption that is still wider than the pane ellipsizes
   rather than leaving the card. */
.ov-meter-legend{
  display:flex;
  flex-wrap:wrap;
  justify-content:space-between;
  gap:var(--sp-1) var(--sp-2);
  margin-top:0.375rem;
  font-size:var(--fs-micro);
  color:var(--muted);
  min-width:0;
  max-width:100%;
}
.ov-meter-legend > span{
  min-width:0;
  max-width:100%;
  overflow:hidden;
  text-overflow:ellipsis;
  white-space:nowrap;
}
.ov-meter-legend b{font-weight:600;}
.ov-meter-legend b.red{color:var(--neg);}
.ov-meter-legend b.green{color:var(--pos);}
/* Running hot: as tall as its rows. More over-pace categories make it taller. */
#ov-anomaly{
  display:flex;
  flex-direction:column;
  gap:var(--sp-5);
}
/* Where the money went: one category per row, largest first. The card is as
   tall as the rows; more spend categories make it taller. */
.ov-tile-cats > .card,.ov-tile-hot > .card{overflow:visible;flex:none;}
.ov-tile-cats .ov-catsplit{
  display:grid;
  grid-template-columns:minmax(0,1fr);
  gap:var(--sp-5);
}
.ov-tile-cats .catbar-row{margin-bottom:0;}
.ov-dash #ov-anomaly-card{max-width:none;}
/* The tiles share four row tracks (label, number, sub-line, meter) through
   subgrid, so every headline sits on one line and every number on the next, level
   with the Balance figure. Only Balance fills the meter track.
   The inner column is minmax(0, 1fr), not auto: a nowrap meter caption's
   min-content used to widen the pane past its track and paint onto the card
   beside it. */
.ov-dash .kpi{display:grid;grid-row:span 4;grid-template-rows:subgrid;grid-template-columns:minmax(0,1fr);row-gap:0;align-content:start;padding:var(--card-pad);}
.ov-dash .kpi > .k{grid-row:1;align-self:end;}
.ov-dash .kpi > .v{grid-row:2;align-self:last baseline;}
.ov-dash .kpi > .s,.ov-dash .kpi > .pill{grid-row:3;align-self:start;}
.ov-dash .kpi > .ov-meter{grid-row:4;}
.ov-dash .kpi > .k,
.ov-dash .kpi > .v,
.ov-dash .kpi > .s,
.ov-dash .kpi > .pill,
.ov-dash .kpi > .ov-meter{min-width:0;max-width:100%;}
/* One line, clipped with an ellipsis: the chip wrapped below ~1300px and, because
   the tiles share row tracks, that second line set the height of the whole KPI
   row. The whole sentence is the tile's tooltip (js/15-overview.js). */
.ov-dash .kpi > .pill.sm{
  justify-self:start;
  display:inline-block;
  max-width:100%;
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
/* The chart's own top margin made the card 10px taller above than below. */
.ov-dash .ov-spend-chart{margin-top:0;}
/* A fixed band rather than a share of the viewport: a month of cumulative spend is
   one gently rising line, and past ~200px the extra height adds no detail. Letting
   it stretch made it the only thing on the screen the eye read. Drawn at 90% of
   that band so the lists under it keep a row. */
.ov-dash .ov-spend-card{padding:var(--sp-4) 1.125rem;}
.ov-dash .ov-spend-chart svg{height:calc(0.9 * clamp(200px, 24vh, 280px));}
.ov-meter-legend b.gold{color:var(--accent);}
.ov-meter-legend b.violet{color:var(--violet);}
.ov-meter-legend b.muted{color:var(--muted);}
.ov-meter-legend b.committed{color:var(--accent);}
/* Financial trend sits in the KPI strip like the other tiles: surface, muted label,
   the verdict word at the lead size (coloured from js/15-overview.js), the reason
   on one line, and the six-month net as a sparkline in the meter track. */
.kpi.trend{
  position:relative;
  background:var(--surface);
  border-color:var(--border);
}
.kpi.trend > .k{color:var(--muted);font-weight:500;}
.kpi.trend > .v{font-size:var(--fs-display);}
.kpi.trend > .s{
  white-space:nowrap;
  overflow:hidden;
  text-overflow:ellipsis;
}
/* The shared sparkline (03-base-layout.css), shrunk to sit in one meter track. */
.kpi.trend .spark-svg{height:1.5rem;}
/* The spend chart's key, drawn in the chart's own marks. */
.ov-spend-key{display:inline-flex;gap:0.875rem;align-items:center;}
.ov-spend-key > span{display:inline-flex;align-items:center;gap:0.375rem;white-space:nowrap;}
.ov-spend-key i{display:inline-block;width:1rem;flex:0 0 auto;}
.ov-spend-key .kl{height:2px;background:var(--chart-neg);border-radius:2px;}
.ov-spend-key .kd{height:0;border-top:2px dotted var(--chart-neg);}
.ov-spend-key .kb{
  height:0.5rem;
  border-radius:2px;
  background:color-mix(in srgb,var(--accent) 45%,transparent);
  border-top:1.5px solid var(--accent);
}
/* The tooltip's fourth line: how much of the running total was recurring or an
   instalment, read as a footnote to the figure above it. */
.ov-spend-tip .f{font-size:var(--fs-micro);color:var(--accent);font-variant-numeric:tabular-nums;margin-top:2px;}
/* Balance, Income and Spent are one card with three panes; Financial trend stays a
   card of its own on the right. The KPI row is a subgrid of the dashboard's 12 columns.
   The three panes take columns 1–9 and Financial trend takes 10–12, pinned to the
   end. The group is a subgrid on
   the row axis — the four tracks every tile shares — so each pane's heading,
   number, sub-line and bar still line up with the trend tile's. Hairlines between the
   panes sit in the middle of the column gap. */
.ov-dash .ov-kpis > .kpi-strip{
  grid-column:1/10;
  grid-row:span 4;
  display:grid;
  grid-template-columns:1.28fr 1fr 1fr;
  column-gap:1.25rem;
  grid-template-rows:subgrid;
  row-gap:0;
}
.ov-dash .ov-kpis > .kpi.trend{grid-column:10/-1;justify-self:end;width:100%;}
/* The look of a group: one card, its panes separated by hairlines. Used by the
   Overview's Balance / Income / Spent card and by the tile rows on Trends. */
.kpi-strip{
  background:var(--surface);
  border:1px solid var(--border);
  border-radius:var(--radius);
  box-shadow:var(--elev);
  padding:var(--card-pad);
}
.kpi-strip > .kpi{background:transparent;border:0;border-radius:0;box-shadow:none;position:relative;padding:0;}
/* Signed figures colour the number only — no pane wash. */
.kpi-strip > .kpi:has(.v.green),
.kpi-strip > .kpi:has(.v.red){background:transparent;}
/* The three headline figures wear the three meanings: what you hold, money in,
   money out. #ov-current is set from js/15-overview.js because it turns red below
   zero; these two never change sign. */
#ov-inc{color:var(--pos);}
#ov-spent{color:var(--neg);}
.kpi-strip > .kpi .v.green,.kpi .v.green{color:var(--pos);}
.kpi-strip > .kpi .v.red,.kpi .v.red{color:var(--neg);}
.kpi-strip > .kpi .s.green{color:var(--pos);font-weight:600;}
.kpi-strip > .kpi .s.red{color:var(--neg);font-weight:600;}
.kpi-strip > .kpi + .kpi::before{
  content:'';
  position:absolute;
  inset-inline-start:calc(-1.125rem / 2);
  top:0.75rem;
  bottom:0.75rem;
  width:1px;
  background:var(--border);
}
/* Stacked, the hairline lies between two panes rather than standing between two
   columns, so it turns on its side and is centred in the `--sp-4` row gap.
   Every strip goes to one column here except Yearly's, which is held at two
   (07-section-bars.css) and states its own exception. This spent a while in
   03-base-layout.css, where it never applied at all: the rule it overrides is in
   this file, which loads later and won, so a stacked strip wore a 1px vertical
   line beside its panes instead of a rule between them. */
@media (max-width:760px){
  .kpi-strip > .kpi + .kpi::before{
    inset-inline-start:var(--sp-3);
    inset-inline-end:var(--sp-3);
    top:calc(var(--sp-4) / -2);
    bottom:auto;
    width:auto;
    height:1px;
  }
}
/* Fill the window on wide screens. The shell is min-height:100vh with no cap, so
   row 3 used to grow the page instead of shrinking; pinning the shell to the
   viewport while the Overview is the open panel keeps everything above the fold
   and lets the two lists scroll inside their own cards. */
@media (min-width:1151px) and (min-height:700px){
  main:has(> #panel-overview.active){display:flex;flex-direction:column;min-height:0;}
  #panel-overview.active{flex:1;min-height:0;}
  :root:has(#panel-overview.active) .app{height:100vh;min-height:0;}
  :root:has(#panel-overview.active) .content{min-height:0;}
  #panel-overview .ov-dash{
    flex:1;
    grid-template-rows:auto auto minmax(0,1fr);
    grid-auto-rows:auto;
    align-content:stretch;
    min-height:0;
  }
  #panel-overview .ov-spend-card{display:block;}
  #panel-overview .ov-spend-chart{display:block;}
  #panel-overview .ov-spend-chart svg{position:static;height:calc(0.9 * clamp(200px, 24vh, 280px));}
  #panel-overview .ov-tile-cats > .card,#panel-overview .ov-tile-hot > .card{overflow:auto;}
  #panel-overview .ov-tile-hot{min-height:0;}
}
/* On an 800px-tall screen the KPI row and the chart take most of the panel; both
   give up a little height there so the two lists below keep a usable number of
   rows. */
@media (min-width:1151px) and (min-height:700px) and (max-height:850px){
  .ov-dash .kpi{padding:var(--sp-2) var(--sp-4);}
  .ov-dash .kpi-strip > .kpi .v{font-size:var(--fs-figure);}
  #panel-overview .ov-spend-card{padding:var(--sp-3) var(--sp-4);}
  #panel-overview .ov-spend-chart svg{height:calc(0.9 * clamp(160px, 20vh, 220px));}
  #panel-overview .ov-dash{gap:var(--sp-3) var(--dash-gap);}
  .kpi.trend > .v{font-size:var(--fs-display);}
}
/* Compact: KPIs first, category lists on the fold, then chart, then Recent preview. */
@media (max-width:1150px){
  .ov-dash .ov-kpis{grid-column:1/-1;grid-row:1;grid-template-columns:1fr 1fr;}
  .ov-dash .ov-kpis > .kpi-strip{
    grid-column:1/-1;
    grid-template-columns:repeat(3,minmax(0,1fr));
    column-gap:var(--dash-gap);
  }
  .ov-dash .ov-kpis > .kpi.trend{grid-column:1/-1;}
  .ov-tile-cats{grid-column:1/7;grid-row:2;}
  .ov-tile-hot{grid-column:7/-1;grid-row:2;}
  .ov-dash:has(#ov-anomaly-card[style*="display:none"]) .ov-tile-cats{grid-column:1/-1;}
  .ov-tile-chart{grid-column:1/-1;grid-row:3;}
  .ov-tile-recent{grid-column:1/-1;grid-row:4;}
  .ov-recent-frame{flex:none;}
  .ov-tile-recent #ov-recent{position:static;overflow:visible;}
  .ov-dash .ov-spend-chart svg{height:calc(0.9 * clamp(140px, 18vh, 200px));}
  .ov-tile-cats .ov-catsplit{grid-template-columns:minmax(0,1fr);gap:var(--sp-4);}
  .ov-tile-cats > .card,.ov-tile-hot > .card{overflow:visible;}
  #ov-anomaly{gap:var(--sp-4);}
}
/* Narrow: the three panes stack. They held three columns all the way down, and
   under about 760px each pane is too narrow to read a meter caption beside its
   neighbour. Captions wrap and ellipsize inside the pane at every width
   (see .ov-meter-legend); this tier is so three figures are not crushed
   into one row.
   Stacking means giving up the four shared row tracks: a pane still spanning
   four rows in a single column would claim the same four as the pane above it,
   which is the overlap again in the other axis. The subgrid unwinds to a flex
   stack, and the panes' `align-self` goes with it — in a column flex box that
   property moves them sideways, not up and down. The hairline between them is
   already horizontal at this tier (03-base-layout.css). */
@media (max-width:760px){
  .ov-dash .ov-kpis > .kpi-strip{
    grid-template-columns:minmax(0,1fr);
    grid-template-rows:none;
    row-gap:var(--sp-4);
  }
  .ov-dash .kpi{grid-row:auto;display:flex;flex-direction:column;}
  .ov-dash .kpi > .k,.ov-dash .kpi > .v,.ov-dash .kpi > .s,.ov-dash .kpi > .pill,
  .ov-dash .kpi > .ov-meter{grid-row:auto;align-self:stretch;}
}
/* Short windows on split+ pinned Overview only — compact keeps its own density. */
@media (min-width:1151px) and (max-height:1250px){
  .ov-greet{margin:0 0 10px;}
  .ov-greet h2{font-size:var(--fs-figure);}
  .ov-greet-sub{font-size:var(--fs-body);}
  .kpi{padding:var(--sp-2) var(--sp-3);}
  .kpi .v{font-size:var(--fs-figure);}
  .kpi.lead .v{font-size:var(--fs-display);}
  .ov-spend-chart{margin-top:10px;}
  .ov-spend-chart svg{height:180px;}
  .ov-spend-card{padding:var(--sp-4);}
  .ov-catsplit,#ov-anomaly{gap:var(--sp-3);}
  .content{padding-bottom:22px;}
  main{padding-top:18px;}
  #ov-nudge,#ov-startbal-nudge,#ov-sample-nudge{margin-bottom:var(--sp-3);}
}
@media (min-width:1151px) and (max-height:940px){
  .ov-spend-chart svg{height:150px;}
  .kpi{padding:var(--sp-2) var(--sp-3);}
  .kpi .v{font-size:var(--fs-figure);}
  .kpi.lead .v{font-size:var(--fs-display);}
  .ov-greet{margin:0 0 var(--sp-2);}
}
