/* =========================================================================
   DWH bookkeeping — single stylesheet, design-token driven.

   A "theme" is the block of custom properties under :root. To restyle the
   whole app (colours, fonts, spacing, radii) edit the tokens here; the rest
   of the file and the templates only ever reference var(--…), never raw
   values. No build step — Django/WhiteNoise serves this file directly, and
   the font url()s below are rewritten by ManifestStaticFilesStorage in prod.
   ========================================================================= */

/* --- Fonts (already shipped in static/fonts/) ---------------------------- */
@font-face {
  font-family: "Mulish";          /* variable: weight axis 200–1000 */
  font-weight: 200 1000;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/Mulish.17e081942f31.ttf") format("truetype");
}
@font-face {
  font-family: "Poppins";         /* static light, used for headings */
  font-weight: 300;
  font-style: normal;
  font-display: swap;
  src: url("../fonts/Poppins-Light.7c448dffabde.ttf") format("truetype");
}

/* --- Theme: DWH brand ---------------------------------------------------- */
:root {
  /* Brand palette (straight from the logo) */
  --brand-blue:   #2aaae2;
  --brand-green:  #3bb34a;
  --brand-purple: #66328f;
  --brand-orange: #f04e28;
  --brand-yellow: #f6ec27;

  /* Semantic colours (darkened where they carry text on white, for contrast) */
  --accent:        #1488c4;   /* primary action / links */
  --accent-strong: #0f6e9e;   /* hover/active */
  --money-in:      #2f9442;   /* credits */
  --money-out:     #c93d1c;   /* debits */
  --warn:          #b45309;   /* uncategorised / attention */

  /* Surfaces & text */
  --bg:        #f8fafc;
  --surface:   #ffffff;
  --ink:       #1a1a1a;
  --muted:     #6b7280;
  --border:    #e5e7eb;
  --border-soft: #f1f5f9;
  --row-tint: rgba(148, 163, 184, .16);   /* shaded table rows; see .cat-group */
  --row-tint-solid: #eef0f4;              /* --row-tint flattened onto white */

  /* Header */
  --header-bg:   #eef2f6;
  --header-ink:  #1a1a1a;
  --header-link: #475569;

  /* Type */
  --font-head: "Poppins", system-ui, sans-serif;
  --font-body: "Mulish", system-ui, sans-serif;

  /* Shape & rhythm */
  --radius:    .5rem;
  --radius-sm: .25rem;
  --gap:       1rem;
  --pad:       1.5rem;
  --shadow:    0 1px 2px rgba(15, 23, 42, .06);

  /* Touch metrics (phone layout) */
  --tap-min: 2.75rem;             /* ≥44px touch target (WCAG 2.5.8 / Apple HIG) */
  --bottomnav-clear: calc(3.9rem + env(safe-area-inset-bottom));
                                  /* height of the fixed .bottomnav incl. the
                                     iPhone home indicator; keep content and
                                     sticky elements clear of it */

  font-family: var(--font-body);
  line-height: 1.5;
  color: var(--ink);
}

/* --- Base elements ------------------------------------------------------- */
* { box-sizing: border-box; }

body { margin: 0; color: var(--ink); background: var(--bg); }

h1, h2, h3, h4 { font-family: var(--font-head); font-weight: 300; line-height: 1.25; }
h1 { font-size: 1.6rem; }
h2 { font-size: 1.25rem; }

a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-strong); text-decoration: underline; }

main { max-width: 60rem; margin: 1.5rem auto; padding: 0 1.25rem; }
/* Data-dense pages (e.g. the transactions table) opt into a wider container
   via {% block main_class %}main--wide{% endblock %}. */
main.main--wide { max-width: 110rem; }

/* --- Header / nav -------------------------------------------------------- */
.brandbar {                 /* thin five-colour stripe echoing the logo */
  height: 4px;
  background: linear-gradient(90deg,
    var(--brand-blue)   0 20%,
    var(--brand-green)  20% 40%,
    var(--brand-yellow) 40% 60%,
    var(--brand-orange) 60% 80%,
    var(--brand-purple) 80% 100%);
}
header.site {
  display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
  padding: .5rem 1.25rem;
  background: var(--header-bg); color: var(--header-ink);
  border-bottom: 1px solid var(--border);
}
header.site .brand { display: flex; align-items: center; gap: .6rem; color: var(--header-ink); }
header.site .brand img { height: 28px; width: auto; display: block; }
header.site .brand strong {            /* DWH wordmark in the five brand colours */
  background: linear-gradient(90deg,
    var(--brand-orange), var(--brand-yellow), var(--brand-green),
    var(--brand-blue), var(--brand-purple));
  -webkit-background-clip: text; background-clip: text;
  -webkit-text-fill-color: transparent; color: transparent;
}
header.site nav { display: flex; gap: .25rem; align-items: center; flex-wrap: wrap; }
header.site .usernav { margin-left: auto; gap: .5rem; }
header.site nav a {
  color: var(--header-link); padding: .4rem .7rem; border-radius: .4rem;
  transition: background-color .15s ease, color .15s ease;
}
/* utility (user) nav: subtle neutral hover box */
header.site nav a:hover { background: rgba(0, 0, 0, .06); color: var(--header-ink); text-decoration: none; }
/* main nav: each item lights up in a brand colour, cycling through all five */
header.site .mainnav a:nth-child(5n+1) { --hl: var(--brand-blue);   --hl-ink: #1a1a1a; }
header.site .mainnav a:nth-child(5n+2) { --hl: var(--brand-green);  --hl-ink: #1a1a1a; }
header.site .mainnav a:nth-child(5n+3) { --hl: var(--brand-yellow); --hl-ink: #1a1a1a; }
header.site .mainnav a:nth-child(5n+4) { --hl: var(--brand-orange); --hl-ink: #1a1a1a; }
header.site .mainnav a:nth-child(5n+5) { --hl: var(--brand-purple); --hl-ink: #ffffff; }
header.site .mainnav a:hover { background: var(--hl); color: var(--hl-ink); }
header.site .logout { background: none; border: 0; color: var(--header-link);
  padding: .4rem .3rem; cursor: pointer; font: inherit; }
header.site .logout:hover { color: var(--header-ink); }

/* --- Cards & layout helpers --------------------------------------------- */
.card {
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); padding: var(--pad); box-shadow: var(--shadow);
}
.card + .card { margin-top: var(--gap); }
/* …but cards side by side in a .row must keep their tops aligned (the rule
   above is for vertically stacked cards). */
.row > .card { margin-top: 0; }

/* Auth pages (login / OTP): a single card centred in the viewport. */
.auth { min-height: calc(100vh - 3rem); display: grid; place-items: center; }
.auth-card { width: 100%; max-width: 24rem; }
.auth-card h1 { margin-top: 0; }
.auth-card form p:last-child { margin-bottom: 0; }
.auth-card .btn { margin-top: .5rem; }

.row    { display: flex; gap: var(--gap); flex-wrap: wrap; }
.spread { display: flex; justify-content: space-between; align-items: center; gap: var(--gap); }
.toolbar { display: flex; gap: .5rem; align-items: center; flex-wrap: wrap; }
.grow   { flex: 1; min-width: 14rem; }
.muted  { color: var(--muted); }
.stat   { font-size: 1.6rem; margin: .2rem 0; }

/* --- Forms --------------------------------------------------------------- */
form p { margin: .5rem 0; }
label { display: block; font-weight: 600; }
input, select, textarea {
  padding: .4rem; border: 1px solid #cbd5e1; border-radius: var(--radius-sm);
  width: 100%; max-width: 22rem; box-sizing: border-box; font: inherit;
  background: var(--surface); color: var(--ink);
}
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent);
}
/* Checkboxes and radios should never stretch to the field width. */
input[type=checkbox], input[type=radio] { width: auto; }

/* Language switcher (public header): a single flag for the OTHER language,
   click to switch. Sits top-right of the stripped public header. */
.langswitch { display: flex; align-items: center; }
.langswitch .flagbtn {
  display: inline-flex; padding: .2rem; border: 0; border-radius: .35rem;
  background: none; cursor: pointer; line-height: 0;
}
.langswitch .flagbtn:hover { background: rgba(0, 0, 0, .06); }
.langswitch .flagbtn img {
  height: 22px; width: auto; display: block; border-radius: 3px;
  border: 1px solid var(--border); box-shadow: 0 1px 2px rgba(0, 0, 0, .12);
}

/* Plain list: no bullets, no default indent (committee home). */
.list-plain { list-style: none; padding: 0; margin: 0; }
.list-plain li { padding: .35rem 0; }
/* Committee list (home.html): indent by tree depth via a custom property
   instead of an inline style, per repo convention. */
.committee-list__item { padding-left: calc(var(--d, 0) * 1rem); }

/* Receipts file list (receipt_files.js): chosen files with a remove button. */
.filelist { list-style: none; padding: 0; margin: .5rem 0 0;
            display: flex; flex-direction: column; gap: .35rem; }
.filelist li { display: flex; align-items: center; justify-content: space-between;
               gap: .5rem; max-width: 22rem; padding: .3rem .5rem;
               background: var(--border-soft); border: 1px solid var(--border);
               border-radius: var(--radius-sm); }
.filelist-remove { padding: .1rem .5rem; font-size: .8rem; }

/* --- Field rows (shared two-column label / field layout) ----------------- */
.field-row { display: grid; grid-template-columns: 16rem 1fr; gap: var(--gap);
             align-items: center; margin: .65rem 0; max-width: 42rem; }
.field-row > label { margin: 0; }
.field-row input[type=checkbox] { width: auto; }
.field-row .help { color: var(--muted); font-size: .85rem; font-weight: 400;
                   margin-top: .25rem; }
.field-row .errorlist { list-style: none; padding: 0; margin: .25rem 0 0;
                        color: var(--money-out); font-size: .9rem; }
/* On phones the fixed 16rem label column leaves no room for the input, so
   stack the label above its field. */
@media (max-width: 40rem) {
  .field-row { grid-template-columns: 1fr; gap: .25rem; align-items: start; }
}

/* Journal-entry line editor: the raw DELETE checkbox is driven by the
   per-row Remove button (static/js/memoriaal_lines.js), so keep it hidden. */
.del-box { display: none; }
.line-row.removed { display: none; }
.balance { font-weight: 600; margin: .5rem 0; }

/* --- Buttons ------------------------------------------------------------- */
button, .btn {
  display: inline-block; padding: .5rem 1rem; border: 0;
  border-radius: var(--radius-sm); background: var(--accent); color: #fff;
  cursor: pointer; font: inherit; text-decoration: none; line-height: 1.2;
}
button:hover, .btn:hover { background: var(--accent-strong); color: #fff; text-decoration: none; }
.btn-muted { background: var(--muted); }
.btn-muted:hover { background: #4b5563; }
.btn-sm { padding: .25rem .6rem; font-size: .85rem; }
a > button, a > .btn { vertical-align: middle; }

/* Inline row controls (e.g. Edit link next to a Delete button) sit on one line. */
.row-actions { display: inline-flex; align-items: center; gap: .6rem; }

/* Drag-to-reorder rows (rules list). The handle hints the row is draggable; the
   row itself is the drag source so grabbing anywhere works. */
.table tr[draggable="true"] { cursor: grab; }
.table tr.dragging { opacity: .5; background: var(--border-soft); }
.drag-handle { color: var(--muted); cursor: grab; user-select: none; font-size: 1.1rem; }

/* --- Tables -------------------------------------------------------------- */
.table { width: 100%; border-collapse: collapse; }
.table th, .table td { padding: .5rem .35rem; }
.table thead th { text-align: left; border-bottom: 1px solid var(--border); }
.table tbody tr { border-bottom: 1px solid var(--border-soft); }
.table tr.total td { border-top: 2px solid var(--border); font-weight: 600; }
.table tr.total--strong td { border-top: 2px solid var(--ink); }
/* Group header row in the budget overview: its figures roll up its members. */
/* Translucent so the .table-scroll edge fades read through shaded rows;
   --row-tint-solid is the same colour flattened onto white, for sticky cells
   that must be opaque to cover the content scrolling beneath them. */
.table tr.cat-group { background: var(--row-tint); }
.table tr.cat-group td { font-weight: 600; }
/* Sortable column headers: the whole cell is one click target; a neutral
   ↕ marks sortable-but-unsorted columns, ▲/▼ the active sort direction. */
th.sortable { padding: 0; }
.th-sort {
  display: flex; align-items: center; gap: .3rem; width: 100%;
  padding: .5rem .35rem; color: inherit; text-decoration: none;
  white-space: nowrap; cursor: pointer;
}
.th-sort--right { justify-content: flex-end; }
.th-sort:hover { color: var(--accent); text-decoration: none; }
.th-sort:hover .sort-ind--idle { color: var(--accent); }
.sort-ind { font-size: .8em; line-height: 1; color: var(--accent); }
.sort-ind--idle { color: #cbd5e1; }   /* visible but quiet until hovered */

/* --- Transactions filter bar (inline, above the table) ------------------- */
.filterbar {
  display: flex; flex-wrap: wrap; align-items: end; gap: var(--gap);
  margin-bottom: var(--gap); padding: var(--gap);
  background: var(--border-soft); border: 1px solid var(--border);
  border-radius: var(--radius);
}
.filterbar__fields {
  flex: 1; display: grid; gap: .6rem var(--gap);
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.filterbar__actions { display: flex; gap: .5rem; align-items: end; }
.filter-field { display: flex; flex-direction: column; gap: .25rem; }
.filter-field > label {
  font-size: .72rem; font-weight: 600; color: var(--muted);
  text-transform: uppercase; letter-spacing: .02em;
}
.filter-field select, .filter-field > input { width: 100%; max-width: none; }
/* Range fields hold two inputs side by side, so give them twice the width of a
   single field. On phone widths the grid has only one real column, so a span-2
   field would spill past the viewport edge — fall back to a single column and
   let the inputs shrink (min-width:0 overrides their intrinsic minimum). */
.filter-field--range { grid-column: span 2; }
@media (max-width: 40rem) {
  .filter-field--range { grid-column: auto; }
}
.filter-range { display: flex; align-items: center; gap: .4rem; }
.filter-range input { width: 100%; max-width: none; min-width: 0; }
.filter-range__sep { color: var(--muted); }

/* --- Active-filter chips ------------------------------------------------- */
.chips {
  display: flex; flex-wrap: wrap; align-items: center; gap: .4rem;
  margin-bottom: var(--gap);
}
.chips__label { color: var(--muted); font-size: .85rem; }
.chip {
  display: inline-flex; align-items: center; gap: .4rem;
  padding: .2rem .35rem .2rem .65rem; border-radius: 1em;
  background: #e8f4fb; border: 1px solid #bfe2f4; color: var(--accent-strong);
  font-size: .82rem; line-height: 1.6; text-decoration: none;
}
.chip:hover { background: #d7ecf8; color: var(--accent-strong); text-decoration: none; }
.chip__x {
  display: inline-flex; align-items: center; justify-content: center;
  width: 1.15em; height: 1.15em; border-radius: 50%;
  background: rgba(15, 110, 158, .15); font-size: .72em;
}
.chip:hover .chip__x { background: rgba(15, 110, 158, .32); }

/* --- Screen-reader-only helper ------------------------------------------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* --- Table view tools (above the table) ---------------------------------- */
.table-tools {
  display: flex; justify-content: flex-end; align-items: center;
  gap: 1rem; margin-bottom: .5rem;
}
/* Let a wide table scroll within its card instead of overflowing the page.
   position:relative makes the wrapper the containing block for the absolutely
   positioned .sr-only labels inside its table — without it they escape the
   scroll clip and stretch the page itself sideways on narrow screens.
   The layered backgrounds are scroll shadows (Lea Verou's technique): a fade
   appears at an edge only while more of the table is hidden on that side, so
   phones get a visible cue that the table pans. The two --surface layers
   scroll with the content (background-attachment:local) and cover the fixed
   fades once the corresponding edge is reached. */
.table-scroll {
  overflow-x: auto;
  position: relative;
  background-image:
    linear-gradient(to right, var(--surface), var(--surface)),
    linear-gradient(to right, var(--surface), var(--surface)),
    linear-gradient(to right, rgba(15, 23, 42, .14), rgba(255, 255, 255, 0)),
    linear-gradient(to left,  rgba(15, 23, 42, .14), rgba(255, 255, 255, 0));
  background-position: left center, right center, left center, right center;
  background-repeat: no-repeat;
  background-size: 2rem 100%, 2rem 100%, .875rem 100%, .875rem 100%;
  background-attachment: local, local, scroll, scroll;
}

/* Generic dropdown: a <details> button (styled as .btn) that reveals a menu. */
.dropdown { position: relative; display: inline-block; }
.dropdown > summary { list-style: none; }
.dropdown > summary::-webkit-details-marker { display: none; }
.dropdown > summary::marker { content: ""; }
.dropdown[open] > summary.btn-muted { background: #4b5563; }
.dropdown__menu {
  position: absolute; top: calc(100% + .35rem); right: 0; z-index: 30;
  min-width: 9rem; padding: .35rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 6px 20px rgba(15, 23, 42, .14);
  display: flex; flex-direction: column;
}
.dropdown__menu a, .dropdown__menu button {
  display: block; width: 100%; padding: .4rem .6rem; border-radius: var(--radius-sm);
  background: none; border: 0; color: var(--ink); font: inherit;
  text-align: left; text-decoration: none; cursor: pointer;
}
.dropdown__menu a:hover, .dropdown__menu button:hover {
  background: var(--border-soft); color: var(--ink); text-decoration: none;
}

/* Columns dropdown: a button that reveals per-column show/hide checkboxes. */
.colmenu { position: relative; display: inline-block; }
.colmenu__toggle { list-style: none; padding: .4rem .8rem; font-size: .85rem; }
.colmenu__toggle::-webkit-details-marker { display: none; }
.colmenu__toggle::marker { content: ""; }
.colmenu[open] .colmenu__toggle { background: #4b5563; }
.colmenu__panel {
  position: absolute; top: calc(100% + .35rem); right: 0; z-index: 30;
  min-width: 13rem; padding: .5rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 6px 20px rgba(15, 23, 42, .14);
  display: flex; flex-direction: column; gap: .1rem; text-align: left;
}
.colmenu__hint {
  margin: 0 0 .25rem; font-size: .72rem; font-weight: 600;
  text-transform: uppercase; letter-spacing: .02em; color: var(--muted);
}
.colmenu__item {
  display: flex; align-items: center; gap: .5rem; padding: .25rem .3rem;
  border-radius: var(--radius-sm); font-size: .9rem; cursor: pointer;
}
.colmenu__item:hover { background: var(--border-soft); }
.colmenu__item input { margin: 0; width: auto; }
.toggle {
  display: inline-flex; align-items: center; gap: .4rem;
  font-size: .85rem; color: var(--muted); cursor: pointer; user-select: none;
}
.toggle input { margin: 0; }

/* --- Searchable select (searchable_select.js) ---------------------------- */
/* A `<select data-searchable>` enhanced into a type-to-filter combobox. The
   native <select> is hidden but still holds and submits the value. */
.ss { position: relative; max-width: 22rem; }
.ss__native { display: none; }
.ss__input { width: 100%; max-width: none; }
.ss__panel {
  position: absolute; top: calc(100% + .25rem); left: 0; right: 0; z-index: 30;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 6px 20px rgba(15, 23, 42, .14);
  overflow: hidden;
}
.ss__list {
  list-style: none; margin: 0; padding: .25rem;
  max-height: 15rem; overflow-y: auto;
}
.ss__option {
  padding: .35rem .55rem; border-radius: var(--radius-sm);
  cursor: pointer; font-size: .95rem;
}
.ss__option--active { background: var(--border-soft); }
.ss__option--selected { font-weight: 600; }
.ss__empty { padding: .4rem .55rem; color: var(--muted); font-size: .9rem; }
.ss__header {
  padding: .4rem .55rem .1rem; color: var(--muted); font-size: .78rem;
  text-transform: uppercase; letter-spacing: .04em; white-space: pre;
}
.ss__option--grouped { padding-left: 1.3rem; }

/* Description column: single line, truncated with an ellipsis by default.
   The "Wrap descriptions" toggle adds .tx-wrap to the table to show the
   full text across multiple lines (width stays capped so the table is stable). */
.desc {
  max-width: 24rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  cursor: pointer;
}
/* Expanded: either globally (the toggle) or one row at a time (click). */
.tx-wrap .desc, .desc--open { overflow: visible; white-space: normal; }
.tx-wrap .desc { cursor: auto; }

/* Clickable rows: the row opens the transaction; cell links filter instead. */
tr.txrow { cursor: pointer; }
tr.txrow:hover { background: var(--row-tint); }
.cellfilter { color: inherit; text-decoration: none; }
.cellfilter:hover { text-decoration: underline; }

/* --- Money & status tags ------------------------------------------------- */
.amount      { text-align: right; }
.text-in,  .amount--in  { color: var(--money-in); }
.text-out, .amount--out { color: var(--money-out); }

.tag { display: inline-block; }
.tag--muted { color: var(--muted); }
.tag--warn  { color: var(--warn); }

/* Count badge (e.g. unprocessed declaraties in the nav) */
.badge {
  display: inline-block; min-width: 1.3em; padding: 0 .4em;
  border-radius: 1em; background: var(--brand-orange); color: #fff;
  font-size: .75rem; font-weight: 700; line-height: 1.5; text-align: center;
}

/* --- Coloured / status buttons ------------------------------------------- */
.btn-ok     { background: var(--money-in); }
.btn-ok:hover     { background: #257a37; }
.btn-danger { background: var(--money-out); }
.btn-danger:hover { background: #a8330f; }

/* --- Utilities ----------------------------------------------------------- */
.num, .right { text-align: right; }
.left   { text-align: left; }
.w-full { width: 100%; max-width: none; }
.inline { display: inline; }
.mt  { margin-top: var(--gap); }
.mb  { margin-bottom: var(--gap); }
.ml  { margin-left: .5rem; }
.mt0 { margin-top: 0; }
.m0  { margin: 0; }

/* --- Messages ------------------------------------------------------------ */
.messages { list-style: none; padding: 0; }
.messages li {
  padding: .5rem .75rem; border-radius: var(--radius-sm); margin: .25rem 0;
  background: #ecfdf5; border: 1px solid #a7f3d0;
}
.messages li.error   { background: #fef2f2; border-color: #fecaca; }
.messages li.warning { background: #fffbeb; border-color: #fde68a; }

/* --- Category tree (budgets: groups + drag-drop) -------------------------- */
.cat-tree, .cat-tree ul { list-style: none; margin: 0; padding: 0; }
.cat-tree__children { padding-left: 1.4rem; }
.cat-tree__item--folded > .cat-tree__children { display: none; }
.cat-tree__row {
  display: flex; align-items: center; gap: .5rem;
  padding: .3rem .5rem; border-radius: var(--radius-sm);
}
.cat-tree__row:hover { background: var(--border-soft); }
.cat-tree__row--selected { background: var(--border-soft); outline: 1px solid var(--accent); }
.cat-tree__row--group .cat-tree__name { font-weight: 600; }
.cat-tree__code { color: var(--muted); font-variant-numeric: tabular-nums; min-width: 3.2rem; }
.cat-tree__kind { font-size: .85rem; }
.cat-tree__edit { margin-left: auto; font-size: .9rem; }
.cat-tree__chevron {
  background: none; border: 0; padding: 0 .15rem; margin: 0;
  color: var(--muted); cursor: pointer; font-size: .9rem; line-height: 1;
  transform: rotate(90deg); transition: transform .15s;
}
.cat-tree__item--folded > .cat-tree__row .cat-tree__chevron { transform: rotate(0deg); }
.cat-tree__row.dragging { opacity: .5; }
.cat-tree__row--drop { outline: 2px dashed var(--accent); outline-offset: -2px; background: var(--border-soft); }
.cat-tree__root-drop {
  margin-top: .75rem; padding: .6rem; text-align: center;
  border: 2px dashed var(--border); border-radius: var(--radius-sm);
}
.cat-tree__root-drop.cat-tree__row--drop { border-color: var(--accent); }

/* --- Budget overview (report + dashboard): tree, bars, flags -------------- */
/* Pace caption above the table (explains the .ubar__tick position). */
.bt-pace { margin: .25rem 0 .5rem; text-align: right; font-size: .85rem; }

/* Tree cell: one guide line per ancestor level; code + name indent together.
   The guide is per-row (td padding gaps it between rows) — intentional. */
.bt-tree { display: flex; align-items: center; }
.bt-tree .gd { flex: none; align-self: stretch; width: 1.15rem;
               margin-left: .55rem; border-left: 1px solid var(--border); }
.bt-tree .chev { flex: none; width: 1.1rem; padding: .3rem 0; margin: -.3rem 0;
                 border: 0; background: none; color: var(--muted); font: inherit;
                 font-size: .72rem; line-height: 1; }
.bt-tree button.chev { cursor: pointer; }
.bt-tree button.chev:hover { color: var(--ink); }
.bt-tree .chev:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.bt-tree .code { min-width: 2.9rem; margin-right: .35rem; color: var(--muted);
                 font-size: .82rem; font-variant-numeric: tabular-nums; }
/* Category name links to the transaction list filtered on it — same quiet look
   as the list's .cellfilter links. inline-flex keeps .code a flex item so its
   min-width still aligns the codes into a column. */
.bt-tree .cat-link { display: inline-flex; align-items: center; color: inherit; }
.bt-tree .cat-link:hover { text-decoration: underline; }

/* Leaves with no postings yet fade back but keep the column rhythm. */
tr.bt-zero td { color: #9ca3af; }
tr.bt-zero .code { color: inherit; }  /* the code must not render darker than the name */

/* Usage bar: track = the budget, fill = actual (capped at 100%), tick = the
   share of the bookyear elapsed. Fill colour carries the status; the label
   repeats it in text so colour is never the only signal. */
.ubar { display: flex; align-items: center; gap: .5rem; min-width: 8.1rem; }
.ubar__track { position: relative; flex: 1; min-width: 5rem; height: .5rem;
               border: 1px solid var(--border); border-radius: 1em;
               background: var(--surface); }
.ubar__fill { position: absolute; inset: 0 auto 0 0; border-radius: 1em;
              background: #94a3b8; }
.ubar__tick { position: absolute; top: -.28rem; bottom: -.28rem; width: 2px;
              border-radius: 1px; background: var(--ink); opacity: .55; }
.ubar__label { min-width: 2.6rem; text-align: right; font-size: .82rem;
               color: var(--muted); font-variant-numeric: tabular-nums; }
.ubar--near .ubar__fill, .ubar--behind .ubar__fill { background: var(--warn); }
.ubar--over .ubar__fill { background: var(--money-out); }
.ubar--near .ubar__label, .ubar--behind .ubar__label {
  color: var(--warn); font-weight: 800;
}
.ubar--over .ubar__label { color: var(--money-out); font-weight: 800; }

/* Status flag on exception rows (".chip" is taken by the filter chips). */
.flag { display: inline-block; padding: .05rem .55rem; border-radius: 1em;
        font-size: .74rem; font-weight: 800; white-space: nowrap; }
.flag--over { background: #fdf1ec; color: var(--money-out); }
.flag--warn { background: #fef3e2; color: var(--warn); }

/* --- Budget summary layer: KPI cards, attention panel, group bullets ------ */
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(13.5rem, 1fr));
        gap: var(--gap); margin-bottom: var(--gap); }
.kpi { background: var(--surface); border: 1px solid var(--border);
       border-radius: var(--radius); padding: 1rem 1.1rem; box-shadow: var(--shadow); }
.kpi h3 { margin: 0 0 .3rem; font-family: var(--font-body); font-size: .74rem;
          font-weight: 800; letter-spacing: .05em; text-transform: uppercase;
          color: var(--muted); }
.kpi__big { margin: .1rem 0 .3rem; font-family: var(--font-head); font-weight: 300;
            font-size: 1.45rem; font-variant-numeric: tabular-nums; }
.kpi__sub { margin: 0; font-size: .82rem; color: var(--muted);
            font-variant-numeric: tabular-nums; }
.kpi .ubar { margin: .5rem 0 .4rem; }
.kpi__flags { display: flex; flex-wrap: wrap; gap: .35rem; margin: .35rem 0; }
.kpi--attn { border-left: 4px solid var(--warn); }

/* Needs-attention panel: one row per exception, biggest euro gap first. */
.attn { border-left: 4px solid var(--warn); }
.attn ul { list-style: none; margin: .3rem 0 0; padding: 0; }
.attn li { display: flex; align-items: center; gap: .7rem; flex-wrap: wrap;
           padding: .5rem 0; border-bottom: 1px solid var(--border-soft); }
.attn li:last-child { border-bottom: 0; }
.attn__who { min-width: 13rem; }
.attn__who .code { margin-right: .4rem; color: var(--muted); font-size: .82rem;
                   font-variant-numeric: tabular-nums; }
.attn__fig { margin-left: auto; color: var(--muted); font-size: .9rem;
             text-align: right; font-variant-numeric: tabular-nums; }
.attn .ubar { flex: 1 1 9rem; max-width: 12rem; }

/* Spending-by-group bullets (expense magnitudes; tick = elapsed year). */
.bullets { display: grid; gap: .65rem; margin-top: .5rem; }
.bullet { display: grid; grid-template-columns: minmax(4rem, 11rem) minmax(8.1rem, 1fr) 8.5rem;
          gap: .8rem; align-items: center; font-size: .88rem; }
.bullet__name { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bullet__fig { text-align: right; color: var(--muted); font-size: .82rem;
               white-space: nowrap; font-variant-numeric: tabular-nums; }
@media (max-width: 60rem) {
  .bullet { grid-template-columns: minmax(4rem, 7.5rem) minmax(0, 1fr); }
  .bullet__fig { display: none; }
}

/* Two summary cards side by side above the table; stacks on phones. */
.summary-cols { display: grid;
                grid-template-columns: repeat(auto-fit, minmax(min(19rem, 100%), 1fr));
                gap: var(--gap); margin-top: var(--gap); margin-bottom: var(--gap); }
.summary-cols > .card { margin-top: 0; }

/* Cumulative spend chart (inline SVG, geometry precomputed server-side).
   Strokes/fills live here so the SVG reuses the theme tokens — presentation
   attributes can't take var(), CSS can. */
.spendchart svg { display: block; width: 100%; height: auto; }
.spendchart .axis { stroke: var(--border); stroke-width: .5; }
.spendchart .diag { stroke: #94a3b8; stroke-width: .7; stroke-dasharray: 2 1.5; }
.spendchart .spend { fill: none; stroke: var(--accent); stroke-width: 1.2; }
.spendchart .today { stroke: var(--ink); opacity: .35; stroke-width: .5; stroke-dasharray: 1 1.5; }
.spendchart .mark { font-size: 4.5px; fill: var(--muted); }
.figcap-line { margin: .5rem 0 0; font-size: .82rem; color: var(--muted); }

/* --- Touch targets ------------------------------------------------------- */
/* On coarse pointers (phones/tablets) grow interactive elements toward the
   44px Apple/Material size — WCAG 2.5.8 asks for 24px minimum and the dense
   desktop table links sit well under that. The in-cell links get their extra
   hit area from symmetric padding + negative margin, so row heights and the
   visual layout stay unchanged. */
@media (pointer: coarse) {
  button, .btn { min-height: var(--tap-min); }
  .mainnav a, .usernav a { padding: .6rem .25rem; }
  /* Only the anchor: the .tag--* spans inside category cells are always
     wrapped in one, and padding both would double the hit area. */
  .table td a {
    display: inline-block; padding-block: .55rem; margin-block: -.55rem;
  }
}

/* =========================================================================
   Phone layout (≤40rem) — bottom navigation and mobile data surfaces.
   Desktop keeps the header nav and the data tables; these rules swap in
   thumb-reachable navigation and record-style lists on phone widths.
   ========================================================================= */

/* Viewport-scoped visibility utilities. List pages render both a desktop
   table and a mobile list from the same context; exactly one is shown.
   Range syntax: the boundaries share the single 40rem edge, so no fractional
   viewport width (zoom, odd devicePixelRatio) can show both at once (#161). */
@media (width <= 40rem) { .only-desktop { display: none; } }
@media (width > 40rem)  { .only-mobile  { display: none; } }

/* --- Bottom navigation bar ----------------------------------------------- */
.bottomnav { display: none; }
@media (max-width: 40rem) {
  header.site .mainnav { display: none; }
  /* keep content clear of the fixed bar (and the iPhone home indicator) —
     only on pages that actually render it (base.html sets the class) */
  body.has-bottomnav { padding-bottom: var(--bottomnav-clear); }
  .bottomnav {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    display: grid; grid-template-columns: repeat(5, 1fr); gap: .15rem;
    padding: .3rem .3rem calc(.3rem + env(safe-area-inset-bottom));
    background: var(--surface); border-top: 1px solid var(--border);
  }
  /* committee nav: one tab and no More sheet, so the single item spans the
     whole bar instead of sitting in the leftmost of five columns */
  .bottomnav--single { grid-template-columns: 1fr; }
}
.bottomnav__item {
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: .15rem; min-height: var(--tap-min); padding: .25rem 0; border-radius: var(--radius);
  font-size: .62rem; font-weight: 700; letter-spacing: .02em; text-align: center;
  color: var(--header-link); text-decoration: none; cursor: pointer; position: relative;
}
.bottomnav__item:hover { text-decoration: none; color: var(--header-ink); }
.bottomnav__item svg {
  width: 1.25rem; height: 1.25rem; fill: none;
  stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; stroke-linejoin: round;
}
.bottomnav__item--on { color: var(--accent); background: #e8f4fb; }
/* unread-style dot on the More item while claims await review */
.badge--dot { position: absolute; top: .2rem; right: 22%;
  min-width: 0; width: .5rem; height: .5rem; padding: 0; }

/* The "More" sheet: a plain <details>; the open summary grows a full-screen
   ::before so tapping anywhere outside the sheet closes it. */
.bottomnav__more > summary { list-style: none; }
.bottomnav__more > summary::-webkit-details-marker { display: none; }
.bottomnav__more[open] > .bottomnav__item { color: var(--accent); }
.bottomnav__more[open] > summary::before {
  content: ""; position: fixed; inset: 0; z-index: -1;
  background: rgba(15, 23, 42, .35);
}
.bottomnav__sheet {
  position: absolute; bottom: calc(100% + .6rem); left: .5rem; right: .5rem;
  display: grid; grid-template-columns: 1fr 1fr; gap: .4rem; padding: .75rem;
  background: var(--surface); border: 1px solid var(--border);
  border-radius: var(--radius); box-shadow: 0 -8px 30px rgba(15, 23, 42, .2);
}
.bottomnav__sheet a {
  display: flex; align-items: center; gap: .4rem; min-height: var(--tap-min);
  padding: .4rem .6rem; border: 1px solid var(--border-soft);
  border-radius: var(--radius-sm); color: var(--ink); font-size: .85rem;
  font-weight: 600; text-decoration: none;
}
.bottomnav__sheet a:hover { background: var(--border-soft); text-decoration: none; }

/* --- Collapsible filter panel (phone) ------------------------------------ */
/* Desktop keeps the always-open .filterbar; on phones it collapses behind a
   "Filters" button (checkbox toggle, in-flow — a fixed sheet would fight the
   virtual keyboard on the text/date inputs inside). */
.filters-btn { display: none; }
@media (max-width: 40rem) {
  .filters-btn { display: inline-flex; align-items: center; gap: .45rem;
                 margin-bottom: var(--gap); }
  .filterbar { display: none; }
  .filters-toggle:checked ~ .filterbar { display: flex; }
}

/* --- Transactions as an amount-forward card list (phone) ----------------- */
.txcards { list-style: none; margin: 0; padding: 0; }
.txcards__month {
  font-size: .7rem; font-weight: 800; letter-spacing: .1em; text-transform: uppercase;
  color: var(--muted); padding: 1rem .25rem .35rem;
  border-bottom: 1px solid var(--border); margin-bottom: .1rem;
}
.txcard a, .txcard__body {
  display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: .1rem .8rem;
  align-items: center; padding: .55rem .25rem; min-height: 3.25rem;
  color: var(--ink); text-decoration: none;
  border-bottom: 1px solid var(--border-soft);
}
.txcard a:hover { background: var(--border-soft); text-decoration: none; color: var(--ink); }
.txcard__who {
  font-weight: 700; font-size: .92rem;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.txcard__amt { grid-row: span 2; align-self: center; font-weight: 700;
  font-variant-numeric: tabular-nums; white-space: nowrap; }
.txcard__sub {
  font-size: .76rem; color: var(--muted); min-width: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.txcards__empty { color: var(--muted); padding: 1rem .25rem; }
/* Committee items list (phone): a plain (non-link) card for a subtotal/total
   row, bolded and set off with a top rule — the mobile equivalent of the
   desktop table's tr.total. */
.txcard--total .txcard__body { font-weight: 700; border-top: 2px solid var(--border); }

/* --- Budget overview as progress rows (phone) ---------------------------- */
.bo-cards { list-style: none; margin: 0; padding: 0; }
.bo-cards .code { color: var(--muted); font-size: .78em; margin-right: .25rem; }
.bo-group {
  font-weight: 700; font-size: .82rem; background: var(--border-soft);
  padding: .5rem .6rem; padding-left: calc(.6rem + var(--d, 0) * .8rem);
  border-radius: var(--radius-sm); margin-top: .6rem;
  display: flex; justify-content: space-between; gap: .8rem;
}
.bo-group__name { min-width: 0; }
.bo-group__mixed { font-weight: 400; font-size: .74rem; color: var(--muted); }
.bo-group__rem { font-variant-numeric: tabular-nums; font-weight: 600; }
/* Status in words on flagged cards — colour is never the only signal (#166). */
.bo-group .flag { font-size: .68rem; vertical-align: .05em; }
.bo-row__flag { display: block; margin-top: .3rem; }
.bo-row details { border-bottom: 1px solid var(--border-soft); }
.bo-row summary {
  list-style: none; cursor: pointer; padding: .55rem .25rem .6rem;
  padding-left: calc(.25rem + var(--d, 0) * .8rem); min-height: var(--tap-min);
}
.bo-row summary::-webkit-details-marker { display: none; }
.bo-row__l1 { display: flex; justify-content: space-between; gap: .8rem; font-size: .9rem; }
.bo-row__name { min-width: 0; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.bo-row__rem { font-variant-numeric: tabular-nums; white-space: nowrap; }
.bo-row .ubar { margin-top: .35rem; min-width: 0; }
.bo-row__detail {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: .4rem;
  padding: 0 .25rem .7rem; padding-left: calc(.25rem + var(--d, 0) * .8rem);
  font-size: .8rem;
}
.bo-row__detail > span { background: var(--border-soft); border-radius: var(--radius-sm);
  padding: .35rem .5rem; font-variant-numeric: tabular-nums; }
.bo-row__detail b { display: block; font-size: .64rem; font-weight: 800;
  letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
/* Jump-to-transactions link under the three figures, full width for the thumb. */
.bo-row__detail .bo-row__link { grid-column: 1 / -1; text-align: center;
  padding: .5rem; background: var(--border-soft); border-radius: var(--radius-sm);
  font-weight: 600; }

/* --- Budget matrix: sticky identity columns (phone) ---------------------- */
/* The +/− kind cue on category cells only matters where the Kind column is
   hidden (phones); everywhere else it stays out of the way. */
.matrix .kind-cue { display: none; }

@media (max-width: 40rem) {
  .matrix { --code-w: 4rem; }   /* one source of truth: column width = sticky offset */
  .matrix .col-kind { display: none; }
  .matrix .col-code, .matrix .col-cat { position: sticky; z-index: 1; background: var(--surface); }
  .matrix .col-code { left: 0; width: var(--code-w); min-width: var(--code-w); max-width: var(--code-w);
                      overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  /* Cap the category column too (#160): one long unbroken name would otherwise
     make the sticky pair wider than the viewport, leaving the amount inputs
     0px visible. Only --code-w feeds a sticky `left`, so this cap cannot
     desync the offsets. */
  .matrix .col-cat  { left: var(--code-w); max-width: 40vw;
                      overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
                      box-shadow: inset -1px 0 0 var(--border); }
  .matrix tr.cat-group .col-code, .matrix tr.cat-group .col-cat { background: var(--row-tint-solid); }
  /* With Kind hidden and amounts stored as unsigned magnitudes (#162), the
     +/− glyph is the only income/expense signal on this screen. */
  .matrix .kind-cue { display: inline; font-weight: 700; }
  .matrix .kind-cue--income  { color: var(--money-in); }
  .matrix .kind-cue--expense { color: var(--money-out); }
}

/* On phones the page toolbars (Accounts / Rules / Export / … buttons) become
   one swipeable row instead of a tall right-aligned stack. */
@media (max-width: 40rem) {
  .spread { flex-wrap: wrap; }
  .spread > .toolbar { flex-basis: 100%; justify-content: flex-start; }
  .toolbar { flex-wrap: nowrap; overflow-x: auto; max-width: 100%; }
  .toolbar .btn, .toolbar button { white-space: nowrap; flex: none; }
  /* `overflow-x: auto` makes the toolbar clip on BOTH axes (per spec it forces
     overflow-y to auto too), which would trap an open dropdown menu — or an
     open searchable-select panel (the declaratie approve form is a toolbar) —
     inside the thin strip (#159). While one is open, wrap into rows instead
     of scrolling: the toolbar stops being a scroll container, the popup
     escapes, and nothing overflows the page sideways. */
  .toolbar:has(.dropdown[open], .ss__panel:not([hidden])) {
    flex-wrap: wrap; overflow-x: visible;
  }
}

/* --- Phone polish (audit P2) --------------------------------------------- */
@media (max-width: 40rem) {
  /* GOV.UK pattern: dense data tables step down slightly on small screens
     so a few more of their (mostly numeric) columns fit before scrolling. */
  .table { font-size: .85rem; }

  /* Keep "Save budgets" in reach while editing a long matrix: the button
     sticks just above the bottom nav until its form scrolls past. */
  .matrix-save {
    position: sticky; bottom: var(--bottomnav-clear);
    z-index: 2; margin-bottom: 0; padding: .5rem 0;
    background: linear-gradient(to top, var(--surface) 75%, transparent);
  }
  .matrix-save button { width: 100%; }
}
