/* Shared control-panel styles — one file, linked from every page's <head> via
   head-assets.php, so a style change only ever needs to happen here.

   The font is self-hosted (fonts/roboto-condensed-var.woff2, latin subset only —
   this panel is English-only) rather than pulled from Google's CDN: same look,
   but no external network round-trip and no async media=print/all swap trick,
   which was one plausible contributor to the cross-browser freeze. font-display:
   swap gets the same "don't block first paint" behavior natively. */
@font-face {
  font-family: 'Roboto Condensed';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('fonts/roboto-condensed-var.woff2') format('woff2');
}

/* Design tokens live in :root. */
:root {
  --bg: #08090b;
  --surface: #090a0d;
  --surface-hover: #0f1114;
  --border: #191c21;
  --text: #e4e6eb;
  --text-muted: #8b93a1;
  --text-dim: #5c6470;
  --accent: #7c8cf8;
  --accent-strong: #96a4ff;
  --accent-soft: rgba(124, 140, 248, 0.16);
  --accent-border: rgba(124, 140, 248, 0.4);
  /* Nav-only — deliberately a muted slate-blue-gray, not another shade of --accent
     (already used for row-target highlights/link hovers) or --running (status blue),
     so the nav's own highlight doesn't echo a color used anywhere else in the app. */
  --nav-accent: #7c8ba3;
  --radius: 7px;
  --radius-sm: 5px;
  --success: #3ecf8e;
  --warning: #f5a623;
  --error: #f16063;
  --hang: #f0883e;
  --running: #58a6ff;
  --font: 'Roboto Condensed', -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif;
}

/* Belt-and-suspenders on both html and body: nothing in this app should ever
   need the page itself to scroll horizontally — any element wide enough to
   threaten that (the category nav strip below, previously) should contain its
   own overflow instead. Browsers propagate body's overflow to the viewport when
   html doesn't set its own, which should already cover this on its own, but the
   propagation rule is exactly the kind of cross-browser inconsistency worth not
   relying on alone — setting both removes the ambiguity. */
html { overflow-x:hidden; }
* { box-sizing:border-box; }
body {
  background:var(--bg); color:var(--text); font-family:var(--font); font-weight:300; letter-spacing:0.02em;
  line-height:1.5; margin:0 auto; padding:32px 24px; font-size:16px; max-width:1100px;
  overflow-x:hidden;
}
/* Section headers — sized relative to the list rows below them (currently 14px)
   rather than a fixed value, so the relationship holds if that ever changes.
   No more uppercase/wide tracking: that was tuned for all-caps text specifically,
   and fights normal-case labels like "Recent Runs" once it's removed. */
h1 {
  font-size:calc(14px + 0.3rem); font-weight:600; color:var(--nav-accent); margin:0 0 16px;
}
/* Actions/Numbers/Projects' actual page-title h1 (as opposed to a section header
   like Overdue) — a bit more prominent now that it's the only heading on those
   pages at all. */
.page-title { font-size:calc(14px + 0.4rem); }
p.muted { color:var(--text-muted); font-size:14px; }
section { margin-bottom:32px; }

.site-header { display:flex; justify-content:center; margin-bottom:12px; }
.site-logo { display:block; max-width:100%; height:auto; }

/* Anchors are list-row content first, "click here" prose second — no default
   browser blue/purple anywhere except the deliberate nav styling below. */
a { color:inherit; text-decoration:none; }

/* Both nav rows are swipeable single-row strips, not flex-wrap — the primary
   nav is only 4 items today, but more panels are coming, and the category
   filter nav already needed this: with enough items, flex-wrap either grows
   into a multi-row block tall enough to push real content down a lot, or (the
   worse case) doesn't wrap cleanly and drags the whole page into horizontal
   scroll. A contained, scrollable single row never does either, at any width. */
nav {
  display:flex; align-items:center; gap:2px; margin-bottom:20px; border-bottom:1px solid var(--border);
  max-width:100%; flex-wrap:nowrap; overflow-x:auto; -webkit-overflow-scrolling:touch; scrollbar-width:none;
}
nav::-webkit-scrollbar { display:none; }
nav a {
  display:flex; align-items:center; gap:8px; padding:9px 14px; font-size:14px; font-weight:300;
  color:var(--text-muted); border-bottom:2px solid transparent; margin-bottom:-1px; flex-shrink:0;
  transition:color 0.5s ease;
}
nav a i { font-size:14px; }
nav a:hover { color:var(--nav-accent); }
nav a.active { color:var(--text); border-bottom-color:var(--nav-accent); }
/* the secondary category-filter nav on actions.php: same links, lighter treatment */
nav + nav { border-bottom:none; margin-top:-8px; margin-bottom:20px; gap:4px; }
nav + nav a { padding:4px 10px; border:1px solid var(--border); border-radius:999px; font-size:13px; margin-bottom:0; }
nav + nav a:hover { border-color:var(--text-dim); color:inherit; }
nav + nav a.active {
  color:var(--text);
  background:color-mix(in srgb, var(--nav-accent) 16%, transparent);
  border-color:color-mix(in srgb, var(--nav-accent) 40%, transparent);
}

@media (max-width: 700px) {
  nav a .nav-label { display:none; }
  nav a i { font-size:30px; margin-top:-4px; }
  nav a { padding:6px 10px; }
}

/* font-size must stay >=16px — same iOS Safari auto-zoom-on-focus issue as the
   toolbar fields above, applies to every text field (e.g. rolldown edits on mobile). */
input[type=text], input[type=number], input[type=color], select, textarea {
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  padding:7px 10px; font-family:inherit; font-size:16px; border-radius:var(--radius-sm);
  transition:border-color .15s, box-shadow .15s;
}
input[type=text]:focus, input[type=number]:focus, select:focus, textarea:focus {
  outline:none; border-color:var(--border); box-shadow:none;
}
input[type=number] { width:80px; }
input[type=color] { width:36px; height:30px; padding:2px; cursor:pointer; }
input.wide { width:100%; max-width:320px; }

/* Custom checkbox, styled to match the run-now button (same dark --surface fill,
   --border outline) instead of the browser-default checkbox appearance. */
input[type=checkbox] {
  appearance:none; -webkit-appearance:none; width:20px; height:20px;
  background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-sm);
  cursor:pointer; flex-shrink:0; position:relative; transition:background .15s, border-color .15s;
}
input[type=checkbox]:hover { background:var(--surface-hover); }
input[type=checkbox]:checked {
  background:#000; border-color:var(--text-dim);
}
input[type=checkbox]:checked::after {
  content:""; position:absolute; left:6px; top:2px; width:5px; height:10px;
  border:solid var(--text); border-width:0 2px 2px 0; transform:rotate(45deg);
}

button {
  font-family:inherit; font-size:14px; font-weight:500; border-radius:var(--radius-sm);
  border:1px solid transparent; padding:7px 14px; cursor:pointer; transition:background .15s, border-color .15s, color .15s;
  background:var(--surface); color:var(--text); border-color:var(--border);
}
button:hover { background:var(--surface-hover); }
button:disabled { opacity:0.5; cursor:default; }
button:disabled:hover { background:var(--surface); }
/* Save (and Add, on projects.php) — an icon instead of a filled pill, matching
   the same plain-icon-button treatment as .delete-btn below (same shape, just
   colored for "confirm" instead of "destroy"). */
button[type=submit] {
  background:none; border:none; color:var(--nav-accent); opacity:0.85;
  font-size:16px; line-height:1; padding:4px 8px; border-radius:var(--radius-sm);
}
button[type=submit]:hover {
  opacity:1; background:color-mix(in srgb, var(--nav-accent) 12%, transparent);
}

/* Soft, outlined tag style for user-colored category/project chips — a colored
   --chip-color custom property tints background/border/text, instead of the old
   solid-fill pills (which read as a lot of loud, disconnected colors at once). */
.chip {
  --chip-color: var(--text-dim);
  display:inline-flex; align-items:center; padding:0 5px; border-radius:3px;
  font-size:12px; font-weight:500; white-space:nowrap;
  background:color-mix(in srgb, var(--chip-color) 16%, transparent);
  color:color-mix(in srgb, var(--chip-color) 65%, white);
  border:1px solid color-mix(in srgb, var(--chip-color) 38%, transparent);
}

/* The dashboard's big current-value badge is a real KPI readout, not a tag —
   keeps a bold solid fill on purpose so it still reads at a glance. */
.value-badge { display:inline-block; padding:0 8px; border-radius:var(--radius-sm); font-size:17px; font-weight:600; color:#0b0d10; }

.muted { color:var(--text-muted); }
.from-file { color:var(--text-dim); font-style:italic; }

.dot { display:inline-block; width:8px; height:8px; border-radius:50%; margin-right:6px; flex-shrink:0; }
.status-dot { display:inline-block; width:9px; height:9px; border-radius:50%; flex-shrink:0; }

/* Tiles used to be content-width only, wrapping raggedly and leaving the right
   quarter of the row empty once there weren't quite enough of them to reach the
   edge — flex-grow now has each one claim its share of whatever's left instead
   of sizing to content alone. Each calc() below accounts for its share of the
   row gap so N tiles + the gaps between them land on exactly 100%: 2-up on
   phones (the default), 4-up on tablets, 6-up back at desktop width. */
.numbers { display:flex; flex-wrap:wrap; gap:12px; margin-bottom:24px; }
.number-tile {
  background:var(--surface); border:1px solid var(--border); border-left:3px solid #444;
  border-radius:var(--radius); padding:12px 16px; flex:1 1 calc(50% - 6px); min-width:140px;
}
.number-tile .value { font-size:28px; font-weight:600; color:#ededed; }
.number-tile .label { font-size:14px; color:var(--text-muted); text-transform:uppercase; letter-spacing:0.05em; margin-bottom:2px; }
.number-tile .subtitle { font-size:15px; color:var(--text-dim); margin-top:2px; }

@media (min-width: 701px) and (max-width: 1000px) {
  .number-tile { flex-basis: calc(25% - 9px); }
}
@media (min-width: 1001px) {
  .number-tile { flex-basis: calc(16.6666% - 10px); }
}

/* Charts (charts.php): each card is its own bordered box (not a shared-border
   .list like actions/numbers) — min-width alone handles mobile (wraps to one
   column). The chart itself stays always visible; Project/ChartType/SortOrder
   editing rides the usual expandable .item-detail, tucked below it. */
.chart-grid { display:flex; flex-wrap:wrap; gap:16px; margin-top:14px; }
.chart-card { flex:1 1 calc(50% - 8px); min-width:280px; border:1px solid var(--border); border-radius:var(--radius); overflow:hidden; padding-top:5px; }
.chart-card:last-child { border-bottom:1px solid var(--border); } /* override .item:last-child — every card keeps its own full border, not just the list's last row */
.chart-title { font-size:14px; font-weight:600; color:var(--text); transition:color 0.5s ease; }
.chart-title:hover { color:var(--nav-accent); }
.chart-canvas-wrap { position:relative; height:220px; padding:4px 12px 14px; }
.chart-card p.muted { padding:4px 12px 14px; margin:0; }

.toolbar { display:flex; align-items:center; gap:8px; margin-bottom:14px; flex-wrap:wrap; }
.toolbar button { background:var(--surface); color:var(--text-muted); border:1px solid var(--border); padding:5px 12px; font-size:15px; border-radius:var(--radius-sm); font-weight:500; }
.toolbar button.active { background:var(--surface-hover); border-color:var(--text-dim); color:var(--text); }
.toolbar button.active[data-status-filter="fail"] { background:color-mix(in srgb, var(--error) 20%, var(--surface)); border-color:var(--error); color:var(--text); }
.toolbar button.active[data-status-filter="hang"] { background:color-mix(in srgb, var(--hang) 20%, var(--surface)); border-color:var(--hang); color:var(--text); }
.toolbar button.active[data-status-filter="running"] { background:color-mix(in srgb, var(--running) 20%, var(--surface)); border-color:var(--running); color:var(--text); }
.toolbar button .count-badge { opacity:0.7; font-variant-numeric:tabular-nums; }
/* font-size must stay >=16px — iOS Safari auto-zooms the viewport on focus of
   any input/select below that, which was firing on these toolbar fields. */
.toolbar select, .toolbar input[type=text] { font-size:16px; padding:6px 10px; }
.toolbar input[type=text] { width:240px; }

/* The shown/total count (actions.php/numbers.php) now lives in the page-title
   h1 itself — "Actions (184/184)" — rather than trailing the search box, where
   it used to fold down onto its own line on narrow screens. Light weight so it
   reads as a subordinate detail next to the (600-weight) heading text. */
.count-paren { font-weight:200; }

/* .delete-btn is a <button type="submit"> (it submits its own tiny delete form),
   so it also matches button[type=submit] above — which has higher specificity
   than a bare class and was winning regardless of source order, forcing the
   Save/Add styling onto it. `button.delete-btn` matches that specificity
   exactly, so this rule (declared later) wins the tie instead. Same plain-icon
   shape as Save, red instead of slate blue — "destroy" rather than "confirm". */
button.delete-btn {
  background:none; border:none; color:var(--error); opacity:0.75; font-weight:400;
  cursor:pointer; font-size:15px; line-height:1; padding:4px 8px; border-radius:var(--radius-sm);
}
button.delete-btn:hover { opacity:1; background:color-mix(in srgb, var(--error) 12%, transparent); }
/* Recent Runs' delete-X is always visible (not tucked in a rolldown like the
   others), so it gets an extra-subtle resting state — full opacity still only
   on hover, same as everywhere else. */
#recentRuns button.delete-btn { opacity:0.5; }

.add-form { margin-top:20px; display:flex; gap:8px; align-items:center; }

/* ---- list + expandable-detail rows (actions.php, numbers.php), and plain
   summary-only rows (Recent Runs on index.php) share this same component. ---- */

.list { display:flex; flex-direction:column; border:1px solid var(--border); border-radius:var(--radius); overflow:hidden; }
.item { border-bottom:1px solid var(--border); background:var(--surface); }
.item:last-child { border-bottom:none; }
/* One consistent highlight for "this is the row you care about right now" —
   arrived via a #a-<slug> link from elsewhere (:target/.jump-highlight),
   hovering it, or having it expanded all used to be three different treatments
   (a blue tint, a dark gray, and no highlight at all respectively); now they're
   all the same --surface-hover gray. */
.item:target, .item.jump-highlight { background:var(--surface-hover); }
#actionList .item[data-enabled="0"], #newsList .item[data-enabled="0"] { opacity:0.4; }

/* Mobile-safe default: everything just wraps in DOM order. Above 700px, each list
   upgrades to a fixed-column grid below so fields actually line up row to row —
   flex-wrap alone let a missing chip (no project, no fails, etc.) shift everything
   after it left, which is why nothing lined up between rows. */
.item-summary {
  display:flex; align-items:center; gap:14px; padding:3px 12px;
  flex-wrap:wrap;
}
.item.expandable .item-summary { cursor:pointer; }
.item.expandable .item-summary:hover, .item.expanded .item-summary { background:var(--surface-hover); }

/* Every text field in a row shares one font-size — the name isn't a "heading",
   it's just another column, same as the slug/meta/output next to it. */
.item-slug, .item-name, .item-meta, .item-output { font-size:14px; }

/* white-space:nowrap specifically because a literal "-" in text is already a
   valid line-break point per the browser's own line-breaking rules — slugs are
   mostly hyphens, so without this they'd wrap mid-word even though there's
   nothing else here forcing a wrap (no CSS `hyphens` property involved). */
.item-slug { color:var(--text-dim); flex-shrink:0; font-variant-numeric:tabular-nums; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
.item-name { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; transition:color 0.5s ease; }
a.item-name:hover { color:var(--nav-accent); }
.item-meta { color:var(--text-muted); flex-shrink:0; white-space:nowrap; text-align:left; font-variant-numeric:tabular-nums; }
.item-output { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; color:var(--text-dim); }
.item-chip-slot { min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis; }

/* finance.php: Account opens the accounts editor — styled like a link (small,
   accent-colored) since it's a secondary utility click, not the point of the
   row. Transaction drills into that description's all-time history — kept
   plain-colored like .item-name (its un-clickable predecessor) since it's
   still the row's main content, just interactive now; only the hover
   underline hints it's clickable at all. */
.finance-account {
  background:none; border:none; padding:0; color:var(--nav-accent); font-size:14px;
  font-weight:500; text-align:left; cursor:pointer; white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.finance-account:hover { text-decoration:underline; }
.finance-transaction {
  background:none; border:none; padding:0; color:var(--text); font-size:14px;
  text-align:left; cursor:pointer; min-width:0; overflow:hidden; white-space:nowrap; text-overflow:ellipsis;
}
.finance-transaction:hover { text-decoration:underline; }
/* Blank/whitespace-only Transaction — shown as "Unknown" rather than an empty
   cell (which read as a rendering bug, not a data gap) and dimmed to read
   as a placeholder, not a real transaction description. */
.finance-transaction-unknown { color:var(--text-dim); font-style:italic; }
.amount-positive { color:var(--success); }
.amount-negative { color:var(--error); }
/* One-line account editor: fields left, Save flush right (margin-left:auto)
   on the same row instead of dropping to its own row below — the ask was
   specifically to keep this compact vertically. flex-end so Save aligns with
   the bottom of the input/select controls, not their labels above. */
.account-editor-row { display:flex; flex-wrap:wrap; align-items:flex-end; gap:16px 24px; }
.account-editor-row .save-account-btn { margin-left:auto; }

.chevron { flex-shrink:0; color:var(--text-dim); font-size:12px; transition:transform 0.15s; margin-left:auto; }
.item.expanded .chevron { transform:rotate(90deg); }

/* Lets the delete form's own button sit directly in the parent flex/grid layout,
   in both the mobile (flex) and desktop (grid) cases, instead of the form itself
   taking up a box. */
.item-summary form.delete-run-form { display:contents; }

/* Recent Runs and Overdue group their summary content into a line-head (dot/name/
   chip) and a line-meta (times/output) so the ~700px breakpoint below can stack
   them into a real two-line card. Above that, both are display:contents — inert
   wrappers that unwrap straight into the grid, so the desktop column math further
   down only ever has to think about the actual leaf elements, unchanged from
   before these wrappers existed. */
.line-head, .line-meta { display:contents; }

@media (min-width: 701px) {
  #recentRuns .item-summary {
    display:grid; grid-template-columns: 12px minmax(160px,1fr) 92px 68px 64px minmax(140px,2fr) 24px;
  }
  /* Slug widened again (88px -> 140px) and given nowrap+ellipsis (see .item-slug
     above) so the many hyphenated slugs here stop wrapping mid-word — taken from
     the truncated Output column's own share (2.2fr -> 1.6fr) rather than Name,
     since Output already truncates by design and can afford to give up room
     more than the primary name column can. */
  #actionList .item-summary {
    display:grid; grid-template-columns: 12px 140px minmax(140px,1fr) 92px 64px 34px minmax(120px,1.6fr) 16px;
  }
  /* Slug widened another 10% (120px -> 132px) on top of the earlier bump — same
     nowrap+ellipsis reasoning as actionList above. Name and Subtitle split the
     row's remaining flexible space (1.2fr/1fr) — Subtitle used to be crammed
     into the same cell as Name, which is what was actually blowing the row
     out; each gets its own column and its own truncation now. */
  #numberList .item-summary {
    display:grid; grid-template-columns: 12px 132px minmax(140px,1.2fr) minmax(100px,1fr) 110px 56px 16px;
  }
  #overdueList .item-summary {
    display:grid; grid-template-columns: 12px minmax(160px,1fr) auto auto; column-gap:14px; align-items:center;
  }
  /* No leading status dot or slug column here (unlike actionList/numberList) —
     feeds have neither a per-run status nor a slug of their own. */
  #newsList .item-summary {
    display:grid; grid-template-columns: minmax(160px,1fr) 92px 64px minmax(140px,1.8fr) 16px;
  }
  /* Project (dot) | ID | Transaction | Amount | Account | full date | relative
     date. Amount/Project/full-date drop out entirely on mobile (see below)
     rather than shrinking — there isn't room to keep 7 columns legible under
     700px. */
  #financeList .item-summary {
    display:grid; grid-template-columns: 20px 60px minmax(200px,1fr) 90px 70px 140px 70px;
  }
  #recentRuns .item-summary > *, #actionList .item-summary > *, #numberList .item-summary > *,
  #newsList .item-summary > *, #financeList .item-summary > * {
    flex:none;
  }
}

/* projectList's summary row: chip flush left, the action count flush right
   against the chevron (not just "somewhere after the chip" at its own fixed
   gap) — the count gets the margin-left:auto instead of the chevron, so all of
   the row's leftover space collapses into one gap right after the chip, and
   count+chevron sit tight together at the trailing edge. */
#projectList .item-summary { padding:6px 12px; }
#projectList .item-meta { margin-left:auto; }
#projectList .chevron { margin-left:0; }

.item-detail { display:none; padding:6px 12px 20px; border-top:1px solid var(--border); }
.item.expanded .item-detail { display:block; }
.detail-grid { display:flex; flex-wrap:wrap; gap:16px 24px; padding-top:14px; }
/* align-items defaults to stretch, which was quietly stretching every field's value
   to match the field's own (content-driven) width — invisible for text/selects since
   they mostly already filled that space, but a checkbox has a fixed native size that
   can't stretch, so browsers rendered its glyph centered inside the oversized stretched
   box instead — reading as "detached" from the label sitting flush left above it. */
.field { display:flex; flex-direction:column; gap:4px; align-items:flex-start; }
.field label { font-size:11px; color:var(--text-muted); text-transform:uppercase; letter-spacing:0.05em; font-weight:600; }
/* This was the actual bug: .field's value elements (.from-file / .muted spans,
   the unclassed zb_truncated() span) had no font-size of their own, so they fell
   through to body's 16px/15px — visibly larger than the 14px inputs/selects right
   next to them in the same grid, and larger than the 14px list row above it. */
.field > span { font-size:14px; }
/* .field.field-wide (not just .field-wide) so this beats the mobile .field
   override below on specificity rather than losing to it on source order —
   .field-wide elements (Description/Notes/Last output) were quietly never
   actually full-width on mobile despite the class name saying so. */
.field.field-wide { flex:1 1 100%; }
.url-row { display:flex; gap:8px; align-items:center; width:100%; }
.url-row input[type=text] { flex:1 1 auto; min-width:0; max-width:none; }

/* Save (this row's own <form>) and delete (a separate sibling <form> — can't
   nest forms) share one action bar below the grid, delete on the left and save
   on the right, matching every other save/delete pairing in the app. The save
   button lives outside its <form> and points back at it via the form="..."
   attribute (id is the row's real DB ID, so it's unique even with multiple rows
   expanded at once) — the only way to get two different forms' controls into one
   visual row without nesting them. */
.detail-actions { display:flex; justify-content:space-between; align-items:center; padding-top:14px; }
.project-action-list { font-size:13px; color:var(--text-dim); padding-top:14px; line-height:1.6; }
.project-action-list a:hover { color:var(--nav-accent); }

@media (max-width: 700px) {
  body { padding:16px; font-size:15px; }
  .item-summary { gap:8px; }
  .detail-grid { gap:12px 16px; }
  .toolbar input[type=text] { width:100%; }
  .item.expandable .item-summary { min-height:40px; }

  /* Detail-grid fields (actions.php/numbers.php rolldowns): a sane minimum instead
     of shrinking to whatever the input's default/unset width happens to be, which
     is what made this "just the desktop form, tiny" below ~400px. */
  .field { flex:1 1 160px; min-width:160px; }
  .field select, .field input[type=text]:not(.wide) { width:100%; }

  /* ---- Recent Runs (index.php) + Overdue (index.php): two-line card ----
     line-head/line-meta stop being display:contents here and become the two
     actual rows. Recent Runs also needs its delete button sharing line-head's
     row (flush right), which is a 2D placement problem — hence grid-template-
     areas rather than fighting flex order for something that isn't a simple
     top-to-bottom reorder. Overdue has no delete button, so it's a plain stack. */
  #recentRuns .item-summary {
    display:grid; grid-template-columns:1fr auto; column-gap:8px; row-gap:4px;
    grid-template-areas:"head del" "meta meta"; padding:8px 12px;
  }
  #recentRuns .line-head { grid-area:head; }
  #recentRuns .line-meta { grid-area:meta; }
  #recentRuns .item-summary form.delete-run-form { grid-area:del; display:flex; align-self:start; }

  #overdueList .item-summary {
    display:flex; flex-direction:column; gap:4px; padding:8px 12px;
  }

  #recentRuns .line-head, #overdueList .line-head,
  #recentRuns .line-meta, #overdueList .line-meta {
    display:flex; align-items:center; gap:6px; min-width:0;
  }
  #recentRuns .line-head .item-name, #overdueList .line-head .item-name {
    flex:1; min-width:0; white-space:nowrap;
  }
  .line-meta .item-meta + .item-meta::before { content:"· "; color:var(--text-dim); }
  .line-meta .item-output:not(:empty)::before { content:"· "; color:var(--text-dim); }

  /* ---- Actions: dot/slug/name only — everything else (project, category via
     the row's chip, last-run, consecutive failures, last-output preview) is
     already duplicated in the rolldown detail panel, so nothing is lost by
     hiding it from the compact row. Tap the row to see the rest. ---- */
  #actionList .item-summary .item-chip-slot,
  #actionList .item-summary .item-meta,
  #actionList .item-summary .item-output {
    display:none;
  }
  #actionList .item-summary .item-name { flex:1; min-width:0; }

  /* ---- Numbers: dot/slug and the current value only — Name/Subtitle/Sort are
     already editable in the rolldown, same reasoning as actions.php above. ---- */
  #numberList .item-summary .item-name,
  #numberList .item-summary .item-meta {
    display:none;
  }
  #numberList .item-summary .item-slug { flex:1; min-width:0; }

  /* News: flex-basis:100% forces the headline preview onto its own line every
     time, not just when it's too long to fit alongside name/chip/time (a short
     headline was otherwise staying put on line 1, wrapping inconsistently row
     to row) — max-width leaves just enough room on that line for the chevron
     to sit alongside it instead of wrapping to a third line of its own. */
  #newsList .item-summary .item-output { flex-basis:100%; max-width:92%; }

  /* Finance: Project dot, ID, Transaction, Amount, Account, full date — same
     leading-dot convention as Actions/Numbers above. Full date replaces the
     relative time here (flush right) rather than the other way around, since
     the exact date/time matters more than "2h ago" when you're scanning
     transactions specifically. */
  #financeList .col-relative {
    display:none;
  }
  #financeList .col-fulldate {
    margin-left:auto;
  }

  /* All/Success/Fail/Hang/Running: one full-width row, all 5 sharing it equally
     (min-width:0 lets them shrink below their own text's natural width rather
     than wrapping to a second row — worth the tighter fit to keep this to one
     line's worth of vertical space). */
  .quick-filters { display:flex; flex-wrap:nowrap; width:100%; gap:4px; }
  .quick-filters button { flex:1; min-width:0; padding:8px 2px; }

  /* The view picker (Recent Runs/All/project/category) gets the same full-width
     treatment the search box already has here. */
  .toolbar select { width:100%; }
}

/* login.php — a bare, centered card, no nav (there's nothing to navigate to
   yet). Reuses the same tokens/inputs/button styles as the rest of the app
   rather than introducing a separate look for one page. */
.login-body {
  display:flex; align-items:center; justify-content:center; min-height:100vh; padding:24px;
}
.login-card {
  display:flex; flex-direction:column; align-items:center; gap:18px;
  width:100%; max-width:320px;
}
.login-logo { display:block; max-width:100%; height:auto; }
.login-card form {
  display:flex; flex-direction:column; gap:10px; width:100%;
}
.login-card input[type=password] { width:100%; text-align:center; }
.login-card button[type=submit] {
  background:var(--surface); color:var(--text); border:1px solid var(--border);
  padding:8px 14px; font-weight:500;
}
.login-card button[type=submit]:hover { background:var(--surface-hover); }
.login-error { color:var(--error); font-size:14px; margin:0; }
