/*
 * Ported from docs/reference/collab-field-controls.html — the visual source
 * of truth for ui-web (CLAUDE.md). Loaded alongside Bootstrap's CSS (for
 * baseline grid/utilities/forms/modal styling — ADR-0019), not a replacement
 * for it.
 */
:root{
  /* The neutral scale, light. Every surface, rule and tint in this file is
     one of these — 147 hex literals were collapsed onto them so that a dark
     theme is a second set of values rather than a second stylesheet.
     Bootstrap's own components follow `data-bs-theme` on their own. */
  --cf-surface:#ffffff;      /* cards, panels, anything raised off the page */
  --cf-raise:#f7f9fb;        /* header strips, a faint fill ON a surface */
  --cf-page:#f4f6f8;         /* the page behind everything */
  --cf-sunken:#eef1f5;       /* separators and inset fills */
  --cf-rule-soft:#dde3ea;    /* the common border */
  --cf-rule:#ced6df;         /* a border meant to be noticed */
  --cf-ink:#1b2430;
  --cf-ink-soft:#5c6a7a;
  --cf-mine:#0d8a7d;
  --cf-mine-rule:#9ed8cd;
  --cf-mine-bg:#eefaf7;
  --cf-pending:#8a8f98;
  --cf-remote:#2563eb;
  --cf-conflict:#b45309;
  --cf-danger:#b91c1c;
  --cf-mauve:#7c3aed;
  --cf-system:#aab4c0;
  --cf-warn-bg:#fffaf3;
  --cf-warn-bg-strong:#fff3e4;
  --cf-warn-rule:#e3b57a;
  --cf-warn-ink:#8a5b08;
  --cf-info-bg:#eef4ff;
  /* The glass rim. Two stops, because an edge that catches light is bright
     where the light hits it and DARK where it does not — a uniformly white
     rim on a white page is no rim at all. */
  /* Softened to match the dark values chosen on 2026-10-04, as far as white
     on white allows: the bright stop comes down, and the shaded stop stays a
     real shadow. White at .15 — the dark theme's value — is invisible on a
     white page, and with `border-color` transparent under the glass there
     would be nothing left to say where the chip ends. */
  --cf-rim-hi:rgba(255,255,255,.75);
  --cf-rim-lo:rgba(15,23,42,.14);
  --cf-rim-sheen:rgba(255,255,255,.70);
  /* Its own token, not `--cf-conflict`: that one also rails the shortfall
     rows and caps their episodes, and a figure being negative is a different
     statement from a wallet being overdrawn. */
  --cf-amount-negative:#dc5959;
  /* The four knobs, deliberately on :root rather than buried in the
     @supports block that uses them — so they can be changed live on <html>
     in an inspector and every chip and panel follows at once. */
  --cf-rim-width:1px;
  --cf-glass-blur:8px;
  --cf-glass-saturate:1.35;
  /*
   * The chip's fill, as a TINT and an amount.
   *
   * Which colour it tints with is the decision, not how much of it. On a
   * white page a chip has to go slightly darker to be seen at all, so it
   * tints with the page. On a dark page the same move buries it: the page is
   * darker than the card the chip sits on, so every percentage of it made
   * the chip a hole punched in the surface rather than a plate laid on it.
   * Dark lifts with white instead — see the dark block.
   */
  --cf-chip-tint:#f4f6f8;
  --cf-chip-fill:78%;
  --cf-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
  /* The "you are here" blue, shared with the rgba flash tints below. */
  --wl-outline-solid:#0d6efd;
}

/*
 * Dark, chosen rather than inverted.
 *
 * A straight inversion of a blue-grey scale goes muddy and loses the
 * ordering that makes a raised card read as raised. These are picked so the
 * same three steps — page, surface, raise — still step the same way, and so
 * the accents keep enough contrast against a dark surface to be read as
 * colour rather than as grey (the warning ochre in particular is unreadable
 * at its light value).
 *
 * `data-bs-theme` is Bootstrap 5.3's own attribute, so setting it on <html>
 * themes the framework's components and this file in one move — which is how
 * legacy did it, and the reason that approach transfers here at all.
 */
:root[data-bs-theme="dark"]{
  --cf-surface:#1c222b;
  --cf-raise:#232a34;
  --cf-page:#13181e;
  --cf-sunken:#262d37;
  --cf-rule-soft:#2f3741;
  --cf-rule:#3b4450;
  --cf-ink:#e6ebf2;
  --cf-ink-soft:#9aa7b6;
  --cf-mine:#4ecdc0;
  --cf-mine-rule:#2a6a62;
  --cf-mine-bg:#15302d;
  --cf-pending:#7e8794;
  --cf-remote:#6ea0ff;
  --cf-conflict:#e0913f;
  --cf-danger:#f08a8a;
  --cf-mauve:#b18cf5;
  --cf-system:#6b7684;
  --cf-warn-bg:#2e2619;
  --cf-warn-bg-strong:#3a2f1c;
  --cf-warn-rule:#7a5c2e;
  --cf-warn-ink:#e8c07a;
  --cf-info-bg:#1d2a40;
  /* On a dark surface the shaded half of the rim is simply less light, not
     more shadow — a dark stop would disappear into the background. */
  --cf-rim-hi:rgba(255,255,255,.28);
  --cf-rim-lo:rgba(255,255,255,.15);
  --cf-rim-sheen:rgba(255,255,255,.12);
  --cf-amount-negative:#ff7a7a;
  /* Lift, do not tint down. Glass on a dark surface is a little light
     caught and held, which is white at a low alpha — a fill taken from any
     of the page colours can only ever be darker than the card behind it,
     and 52% of the page was still a dark plate for exactly that reason.
     The amount is small because white goes a long way here: 10% over the
     card is a clearly raised chip, and 20% is a button. */
  --cf-chip-tint:#ffffff;
  --cf-chip-fill:10%;
}
/*
 * `hidden` has to mean hidden.
 *
 * The attribute works through the UA stylesheet's `[hidden]{display:none}`,
 * and ANY author rule setting `display` outranks a UA rule — so Bootstrap's
 * display utilities, which are `display:… !important`, quietly win. An
 * element carrying `d-flex` or `d-inline-block` therefore stayed on screen
 * when code set `.hidden = true`, with nothing anywhere to say so.
 *
 * Three of those were live when this rule was written: the "not a money leg"
 * dash in the transaction editor, which never went away and pushed the wallet
 * field out of line with its row; the report's tag any/all switch; and the
 * report's "Delete all transactions…" bar, which is meant to appear for
 * administrators only and was appearing for everybody. The server refuses the
 * action regardless, so that was an offered button rather than a granted
 * power — but offering it is its own kind of wrong.
 *
 * Author level and `!important`, because that is what it takes to outrank a
 * utility class that is also `!important`.
 */
[hidden]{display:none!important}

body{background:var(--cf-page);color:var(--cf-ink);font-size:15px}
.cf-shell{max-width:1240px}
.cf-card{background:var(--cf-surface);border:1px solid var(--cf-rule-soft);border-radius:10px}
/* A card holding a full-width list spends ~15% of a 375px viewport on chrome
   (container gutter + card padding + border) and buys little there: filling
   the screen, it has nothing beside it to be grouped apart from. Below 640px
   the table breaks out to the card's edges and the side border/radius go,
   keeping the surface colour, the vertical rhythm, and the padding that any
   header row or prose inside the card still wants.
   Opt-in, not a blanket `.cf-card` rule: the same class is also the centred
   login panel and the launcher's app tiles, which need their padding and
   their edges. The -1rem matches these cards' own `p-3`. */
@media (max-width:640px){
  .cf-card--bleed{border-left:0;border-right:0;border-radius:0}
  /* `max-width:none` is required, not incidental: the wrapper's own
     `max-width:100%` resolves against the padded card interior and would
     cap it right back to that width, negative margins or not. Bleeding to
     the card's edge is exactly what that cap normally prevents. */
  .cf-card--bleed .cf-table-scroll{margin-left:-1rem;margin-right:-1rem;max-width:none}
}
.cf-h{font-size:.7rem;letter-spacing:.06em;text-transform:uppercase;font-weight:700;color:var(--cf-ink-soft)}

/* ===================================================================
   COMPACT FIELD — notched outline
=================================================================== */
/* Idle default is the same grey as the rest of the border, not transparent —
   a fully transparent left edge is indistinguishable from a missing one; the
   notched-outline design only reads as intentional if the thicker left rule
   is always visible, with colour reserved for signalling a real state change. */
.cf-f{position:relative;margin-bottom:14px;--cf-state:var(--cf-rule)}
.cf-f__box{position:relative;display:block}
.cf-f .form-control{
  height:44px;padding:.55rem .75rem;padding-right:44px;
  border:1px solid var(--cf-rule);border-left-width:3px;border-left-color:var(--cf-state);
  border-radius:8px;background:var(--cf-surface);
  transition:border-color .16s ease,box-shadow .16s ease;
}
.cf-f textarea.form-control{height:auto;min-height:62px;padding-top:.7rem}
.cf-f .form-control:focus{box-shadow:0 0 0 .18rem rgba(90,110,140,.12)}

.cf-f__label{
  position:absolute;left:12px;top:50%;transform:translateY(-50%);transform-origin:left center;
  pointer-events:none;color:var(--cf-pending);font-size:.92rem;padding:0 5px;background:transparent;
  transition:top .14s ease,font-size .14s ease,color .14s ease,background-color .14s;
  white-space:nowrap;max-width:calc(100% - 60px);overflow:hidden;text-overflow:ellipsis;
}
.cf-f textarea + .cf-f__label{top:1.1rem;transform:none}
.cf-f .form-control:focus + .cf-f__label,
.cf-f .form-control:not(:placeholder-shown) + .cf-f__label{
  top:0;transform:translateY(-50%);font-size:.7rem;font-weight:600;letter-spacing:.02em;
  color:var(--cf-ink-soft);background:var(--cf-surface);
}
.cf-f textarea.form-control:focus + .cf-f__label,
.cf-f textarea.form-control:not(:placeholder-shown) + .cf-f__label{top:0;transform:translateY(-50%)}

.cf-f__state{
  position:absolute;right:10px;top:0;transform:translateY(-50%);display:none;
  align-items:center;gap:.25rem;height:16px;padding:0 5px;background:var(--cf-surface);
  border-radius:8px;font-size:.68rem;font-weight:600;white-space:nowrap;z-index:2;
}
.cf-f:not(.is-idle):not(.is-system) .cf-f__state{display:inline-flex}
.cf-f__state .cf-dot{
  width:13px;height:13px;border-radius:50%;display:grid;place-items:center;
  color:var(--cf-surface);font-size:.5rem;font-weight:700;flex:0 0 auto;
}
@media (max-width:520px){ .cf-f__state .cf-txt{display:none} }

.cf-f.is-mine    {--cf-state:var(--cf-mine)}
.cf-f.is-mine    .form-control{border-color:var(--cf-mine)}
.cf-f.is-mine    .cf-f__state{color:var(--cf-mine)}
.cf-f.is-pending {--cf-state:var(--cf-pending)}
.cf-f.is-pending .form-control{border-left-style:dashed}
.cf-f.is-locked  {--cf-state:var(--cf-mauve)}
.cf-f.is-locked  .form-control{background:var(--cf-surface);color:var(--cf-ink-soft);cursor:default}
.cf-f.is-remote  {--cf-state:var(--cf-remote)}
.cf-f.is-remote  .form-control{animation:cf-flash 2.4s ease-out 1}
.cf-f.is-remote  .cf-f__state{color:var(--cf-remote)}
.cf-f.is-conflict{--cf-state:var(--cf-conflict)}
.cf-f.is-conflict .form-control{border-color:var(--cf-conflict)}
.cf-f.is-conflict .cf-f__state{color:var(--cf-conflict)}
.cf-f.is-system  {--cf-state:var(--cf-system)}
.cf-f.is-system  .form-control{background:var(--cf-raise);color:var(--cf-ink-soft);border-style:dashed}
.cf-f.is-system  .cf-f__label{color:var(--cf-system)}

@keyframes cf-flash{0%{background:rgba(37,99,235,.16)}100%{background:var(--cf-surface)}}
@keyframes cf-rowflash{0%{background:rgba(37,99,235,.14)}100%{background:transparent}}
@keyframes cf-pulse{0%,100%{opacity:.3}50%{opacity:1}}
@media (prefers-reduced-motion:reduce){
  .cf-f.is-remote .form-control{animation:none;background:rgba(37,99,235,.09)}
  .cf-f__label,.cf-f .form-control{transition:none}
  tr.is-remote{animation:none !important;background:rgba(37,99,235,.08) !important}
}

.cf-f__tools{position:absolute;right:7px;top:22px;transform:translateY(-50%);display:flex;align-items:center;gap:.15rem;z-index:2}
.cf-f textarea + .cf-f__label ~ .cf-f__tools{top:20px}
.cf-hist-btn{
  border:0;background:transparent;color:var(--cf-system);padding:.2rem .3rem;border-radius:6px;
  display:inline-flex;align-items:center;gap:.15rem;font-size:.68rem;line-height:1;
  transition:color .14s,background-color .14s;
}
.cf-hist-btn:hover,.cf-hist-btn:focus-visible{color:var(--cf-ink);background:var(--cf-sunken)}
.cf-f.is-conflict .cf-hist-btn{color:var(--cf-conflict);font-weight:700}
.cf-hist-btn__n{font-variant-numeric:tabular-nums;letter-spacing:-.02em}

.cf-f--toggle{
  display:flex;align-items:center;gap:.6rem;
  border:1px solid var(--cf-rule);border-left-width:3px;border-left-color:var(--cf-state);
  border-radius:8px;height:44px;padding:0 .6rem 0 .75rem;position:relative;
}
.cf-f--toggle .cf-f__state{right:10px}
.cf-f--toggle .cf-f__tools{position:static;transform:none;margin-left:auto}
.cf-f--toggle label{font-size:.9rem;margin:0}

/* ===================================================================
   HISTORY PANEL
=================================================================== */
.cf-hist{position:absolute;z-index:1080;right:0;top:calc(100% + 4px);
  width:min(380px,calc(100vw - 32px));background:var(--cf-surface);border:1px solid var(--cf-rule-soft);
  border-radius:9px;box-shadow:0 12px 30px rgba(20,30,45,.16);padding:.55rem 0 .3rem;display:none}
.cf-hist.show{display:block}
.cf-hist__title{font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;
  color:var(--cf-ink-soft);font-weight:700;padding:0 .75rem .4rem}
.cf-hist__row{padding:.4rem .75rem;border-top:1px solid var(--cf-page)}
.cf-hist__row:hover{background:var(--cf-surface)}
/* Flex, not grid: a grid/flex item defaults to min-width:auto, which sizes
   it to its content's min-content (the longest unbreakable run) regardless
   of word-break — `min-width:0` here is what actually lets long values wrap
   normally instead of being squeezed into a sliver by the dot/badge tracks. */
.cf-hist__top{display:flex;align-items:center;gap:.5rem}
.cf-hist__top .cf-dot{flex:0 0 auto}
.cf-hist__val{font-family:var(--cf-mono);font-size:.78rem;word-break:break-word;
  flex:1 1 auto;min-width:0}
.cf-hist__meta{font-size:.7rem;color:var(--cf-ink-soft);margin-top:.15rem;padding-left:22px}
.cf-hist__origin{font-size:.62rem;text-transform:uppercase;letter-spacing:.04em;
  border:1px solid var(--cf-rule-soft);border-radius:3px;padding:0 .22rem;color:var(--cf-ink-soft)}
.cf-hist__origin.offline{border-color:var(--cf-warn-rule);color:var(--cf-warn-ink);background:var(--cf-warn-bg)}
.cf-hist__cur{font-size:.62rem;text-transform:uppercase;letter-spacing:.04em;
  color:var(--cf-mine);font-weight:700;flex:0 0 auto}
.cf-hist__restore{font-size:.7rem;--bs-btn-padding-y:.05rem;--bs-btn-padding-x:.4rem}
.cf-review{margin:.15rem .55rem .45rem;border:1px solid var(--cf-warn-rule);background:var(--cf-warn-bg);
  border-radius:7px;padding:.5rem .6rem}
.cf-review__h{font-size:.72rem;font-weight:700;color:var(--cf-warn-ink);margin-bottom:.35rem}
.cf-review__opt{display:flex;align-items:center;justify-content:space-between;gap:.5rem;
  font-family:var(--cf-mono);font-size:.75rem;padding:.2rem 0}

/* ===================================================================
   RECORD TABLE
=================================================================== */
/* Scopes overflow to the table itself, never the page (see CLAUDE.md's
   responsive rule) — a row wide enough to need it gets a local scrollbar
   instead of bleeding past the card into whatever is behind it. */
.cf-table-scroll{overflow-x:auto;max-width:100%}
.cf-table{margin-bottom:0;font-size:.85rem}
.cf-table thead th{font-size:.68rem;text-transform:uppercase;letter-spacing:.05em;font-weight:700;
  color:var(--cf-ink-soft);border-bottom:1px solid var(--cf-rule-soft);padding:.4rem .5rem;
  white-space:nowrap;background:var(--cf-surface)}
.cf-table td{padding:.45rem .5rem;vertical-align:middle;border-bottom:1px solid var(--cf-page)}
.cf-table tbody tr:hover{background:var(--cf-raise)}
.cf-table td.cf-gut{width:6px;padding:0 0 0 3px}
.cf-table td.cf-gut span{display:block;width:4px;height:26px;border-radius:4px;background:transparent}
tr.is-open td.cf-gut span{background:var(--row-color,var(--cf-mauve))}
tr.is-remote{animation:cf-rowflash 2.6s ease-out 1}
tr.is-remote td.cf-gut span{background:var(--cf-remote)}
tr.is-tombstone td{color:var(--cf-system);text-decoration:line-through}
/* Grouping row for a table grouped by application (e.g. role grants) — a
   plain, non-interactive header between groups, not a record of its own. */
tr.cf-role-group td{background:var(--cf-raise);font-size:.68rem;text-transform:uppercase;
  letter-spacing:.05em;font-weight:700;color:var(--cf-ink-soft);
  padding:.4rem .5rem;border-top:1px solid var(--cf-rule-soft)}
tr.cf-role-group:first-child td{border-top:0}
.cf-date{font-family:var(--cf-mono);font-size:.78rem;white-space:nowrap}
.cf-date.sys{color:var(--cf-system)}
.cf-title button{border:0;background:none;padding:0;color:inherit;font:inherit;font-weight:500;
  text-align:left;text-decoration:underline;text-decoration-color:var(--cf-rule);text-underline-offset:3px}
.cf-title button:hover{text-decoration-color:var(--cf-ink)}
.cf-rowpres{display:inline-flex;gap:2px;margin-left:.35rem;vertical-align:middle}
.cf-dot{width:16px;height:16px;border-radius:50%;display:inline-grid;place-items:center;
  color:var(--cf-surface);font-size:.58rem;font-weight:700;flex:0 0 auto}

.cf-sr{position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap}

/* "Locked by other" in a list row (SPEC §6.1) — the holder's avatar sits in
   the row's presence slot, their name and a lock beside it, so the gutter
   colour is never the only thing carrying the state. */
.cf-lockedby{font-size:.7rem;color:var(--cf-ink-soft);white-space:nowrap;margin-left:.15rem}

/* ===================================================================
   TRANSACTION LIST (webledger's register)
=================================================================== */
/* The register's rows carry lease state the way a compact field does: the
   row is an outlined block whose left edge is the holder's colour, and the
   holder rides a chip notched into the top border.
 *
 * It used to be a 4px pill in a gutter column plus a badge inline after the
 * description. That said the same thing in two weaker places at once — the
 * badge competed with the description for the same line and pushed the
 * splits summary around as names of different lengths came and went, and the
 * pill was a colour with no word attached until you reached the badge. The
 * field controls had already solved this: border for state, chip for
 * identity, and the content line left alone.
 *
 * Space is reserved either way (invariant #11): the chip overlays the top
 * border inside the cell's existing padding, so a colleague arriving on a
 * record never reflows the row. */
.wl-tx-list{border-collapse:separate;border-spacing:0 6px}
.wl-tx-list thead th{border-bottom:0;padding-bottom:.15rem}
.wl-tx-list tbody td{
  background:var(--cf-surface);
  border-top:1px solid var(--cf-rule-soft);
  border-bottom:1px solid var(--cf-rule-soft);
  padding:.55rem .5rem;
}
.wl-tx-list tbody tr:hover td{background:var(--cf-raise)}
/* The gutter column becomes the block's left edge rather than a pill inside it. */
.wl-tx-list tbody td.cf-gut{
  width:0;padding:0;
  border-left:3px solid var(--row-color,var(--cf-rule-soft));
  border-top-left-radius:9px;border-bottom-left-radius:9px;
}
.wl-tx-list tbody td.cf-gut span{display:none}
.wl-tx-list tbody td:last-child{
  border-right:1px solid var(--cf-rule-soft);
  border-top-right-radius:9px;border-bottom-right-radius:9px;
}
.wl-tx-list td.cf-title{position:relative}
.wl-tx-list .wl-state-chip{position:absolute;left:.45rem;top:0;transform:translateY(-50%)}
/* Notched into the row's top border, same trick as the field's state chip:
   an opaque background cutting the line it sits on. */
.wl-state-chip{
  display:inline-flex;align-items:center;gap:.28rem;
  height:16px;padding:0 6px;
  background:var(--cf-surface);border-radius:8px;
  font-size:.66rem;font-weight:600;line-height:1;white-space:nowrap;
  color:var(--cf-ink-soft);
  z-index:1;
}
.wl-state-chip .cf-dot{width:13px;height:13px;font-size:.5rem}
/* Yours, interrupted. Amber outranks the holder's colour on the border:
   a decision of yours waiting on this row matters more to you than who
   happens to be holding it, and the chip still names them. */
.wl-tx-list tbody tr.wl-tx-held td.cf-gut{border-left-color:var(--cf-conflict)}
/* Queued, not contended: the muted "provisional" grey, not an alarm colour. */
.wl-tx-list tbody tr.wl-tx-pending td.cf-gut{border-left-color:var(--cf-pending)}
.wl-state-chip--held{color:var(--cf-warn-ink)}
.wl-state-chip--queued{color:var(--cf-conflict)}
@media (max-width:640px){
  /* The chip would collide with a wrapped description on a narrow row. */
  .wl-state-chip .wl-state-chip__txt{max-width:14ch;overflow:hidden;text-overflow:ellipsis}
}
/* The splits summary is the informative column and the currency code the
   least, but on a phone the currency held a whole column while the splits
   sat off-screen entirely — and, still being laid out out there, wrapped
   into enough lines to balloon every row. Below 640px both dedicated
   columns fold into one muted line under the description (code first, then
   the legs), clamped so a many-split transaction can't grow the row.
   Reduce, don't reflow — the same approach as the state chip's text and the
   split header's currency echo. */
.wl-tx-sub{display:none}
@media (max-width:640px){
  .wl-tx-list .wl-tx-cur,
  .wl-tx-list .wl-tx-legs{display:none}
  .wl-tx-list .wl-tx-sub{
    display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
    font-size:.72rem;line-height:1.35;color:var(--cf-ink-soft);margin-top:.15rem;
  }
}

/* A draft of yours that somebody interrupted, shown beside the value that
   replaced it. The control above keeps belonging to whoever holds the record
   — it updates live as they type — and this strip carries the half that is
   yours, so nothing has to be painted over your work to show you theirs.
   Amber and a word, never colour alone (invariant #11). */
.wl-held{
  display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;
  min-width:0;
  border:1px solid var(--cf-conflict);border-left-width:3px;
  border-radius:0 0 7px 7px;
  background:var(--cf-warn-bg);
  padding:.25rem .4rem .25rem .55rem;
  margin-top:-1px;                       /* share the control's bottom edge */
  font-size:.74rem;line-height:1.3;
}
.wl-held + .wl-held{margin-top:4px}
.wl-held b{color:var(--cf-warn-ink);font-size:.66rem;text-transform:uppercase;letter-spacing:.04em;white-space:nowrap}
.wl-held__who{display:inline-flex;align-items:center;gap:.2rem;color:var(--cf-ink-soft);font-size:.68rem;white-space:nowrap}
.wl-held__v{font-family:var(--cf-mono);font-size:.73rem;color:var(--cf-ink);flex:1 1 auto;
  overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wl-held .btn{font-size:.66rem;--bs-btn-padding-y:.02rem;--bs-btn-padding-x:.35rem;flex:0 0 auto}
/* The split-table variant: an extra row under the leg it belongs to, so the
   table keeps its columns instead of growing a parallel one. */
tr.wl-held-row td{background:transparent;border-top:0;padding:.1rem .5rem .3rem}
.wl-held--row{border-radius:7px;margin-top:0}

/* ===================================================================
   HELP POPOVER
=================================================================== */
/* Same shape as the history panel above — a borderless icon button owning a
   positioned panel — rather than Bootstrap's Popover plugin, which would
   pull in a second Bootstrap JS component (only Modal is used anywhere in
   this codebase) and need per-open init/dispose. Hover is gated behind
   `hover: hover` so a tap on a touch screen doesn't leave it stuck open
   through emulated hover; touch gets the click toggle (`.show`) instead. */
.cf-help{position:relative;display:inline-flex}
.cf-help__btn{
  border:0;background:transparent;color:var(--cf-system);padding:.15rem .25rem;border-radius:6px;
  display:inline-flex;align-items:center;line-height:1;transition:color .14s,background-color .14s;
}
.cf-help__btn:hover,.cf-help__btn:focus-visible{color:var(--cf-ink);background:var(--cf-sunken)}
.cf-help__panel{
  position:absolute;z-index:1080;right:0;top:calc(100% + 6px);
  /* Right-anchored to a button that is itself inset from the viewport edge
     (modal side margin + header padding), so the cap has to leave room for
     that inset as well — sized against the viewport alone, the panel hangs
     off the *left* edge on a phone. 4.5rem covers both sides' worth plus a
     little slack; on a roomy viewport the 340px preference wins. */
  width:min(340px,calc(100vw - 4.5rem));background:var(--cf-surface);border:1px solid var(--cf-rule-soft);
  border-radius:9px;box-shadow:0 12px 30px rgba(20,30,45,.16);
  padding:.55rem .7rem;font-size:.78rem;font-weight:400;line-height:1.45;
  color:var(--cf-ink-soft);text-align:left;text-transform:none;letter-spacing:normal;display:none;
}
.cf-help__panel.show{display:block}
/*
 * For a help button at the LEFT of its row rather than the trailing end.
 *
 * The default hangs the panel leftwards from the button, which is right
 * beside a header's trailing controls and runs off the card beside a leading
 * one. Anchoring it rightwards from the button instead just moves the
 * problem: 340px starting part-way across a row overflows the other edge.
 *
 * So it is anchored to the ROW, not to the button — `position:static` here
 * hands the panel's containing block to the nearest positioned ancestor,
 * which the row is. It then starts where the row starts and drops below the
 * whole row, so it also stops covering the controls beside it.
 */
.cf-help--left{position:static}
.cf-help--left .cf-help__panel{right:auto;left:0}
@media (hover:hover){
  .cf-help:hover .cf-help__panel,
  .cf-help__btn:focus-visible + .cf-help__panel{display:block}
}

/* ===================================================================
   SPLIT TABLE (webledger's transaction editor)
=================================================================== */
/* Six columns of real controls do not fit a phone, and the two failure modes
   are both worse than scrolling: left to shrink, the account select collapses
   to a couple of characters ("Te", "OT") and the acct-currency column falls
   off the edge; with no scroll container it spills straight past the modal in
   landscape. So the table keeps a legible floor and its `.cf-table-scroll`
   wrapper scrolls it, per this file's own rule that wide content scrolls
   inside its own box rather than bleeding past the card. */
/* Column order: account, +, −, acct-currency amount, memo, remove. These are
   positional, so they move with the header and `addRow`'s template. */
/* ---- A field with its label notched into its border ----
   See `notchedField.ts` for why the label interrupts the border rather than
   sitting on top of it. The frame is drawn by the fieldset, so the control
   inside carries no border of its own and the two can never disagree. */
/* `min-width:0` because a fieldset's default `min-inline-size:min-content`
   will not let a table cell shrink, and this lives in one. */
.wl-nf{display:block;min-width:0;margin:0;padding:0 .35rem .25rem;
  border:1px solid var(--cf-rule);border-radius:.375rem;background:transparent}
/* Sentence case, not caps. The label is a name, and a name read in capitals
   is read letter by letter before it is read as a word — which is a cost
   paid on every field of every row. Slightly larger and without the tracking
   that caps needed to stay legible: lowercase already has the ascenders and
   descenders that make a word recognisable at a glance. */
.wl-nf>legend{float:none;width:auto;max-width:100%;padding:0 .25rem;margin:0 0 0 .1rem;
  font-size:.68rem;line-height:1;white-space:nowrap;overflow:hidden;color:var(--cf-ink-soft)}
/* An unnamed field — the amount columns before an account is chosen — should
   not leave a notch in the border with nothing in it. */
.wl-nf>legend:empty{display:none}
.wl-nf__ctl{display:block;width:100%;border:0;background:transparent;outline:none;
  padding:.1rem .15rem .15rem;font-size:.82rem;line-height:1.35;color:var(--cf-ink);
  box-shadow:none}
.wl-nf:focus-within{border-color:var(--cf-remote);box-shadow:0 0 0 .15rem rgba(37,99,235,.15)}
/* A locked field is readonly, never disabled (invariant 4) — so it keeps its
   place in the tab order and its text stays selectable. */
.wl-nf__ctl[aria-readonly="true"]{cursor:default;user-select:text}
/* Two controls sharing one notch — an amount and its currency, an amount and
   a fixed suffix. They read as one field because they ARE one: "how much" is
   not answered by either half alone. */
.wl-nf__pair{display:flex;align-items:baseline;gap:.15rem;min-width:0}
.wl-nf__pair>.wl-nf__ctl{min-width:0}
.wl-nf__ctl--auto{width:auto;flex:none;padding-right:.1rem}
/* A chip with nothing to notch, standing in a column beside ones that have.
   
   The log stops naming a leg's wallet once it is showing one wallet, so the
   amount chips lose their notch while the running totals beside them keep
   theirs — and a plain chip padded up to the taller one's height centres its
   figure, leaving the two numbers on a row 4.5px apart. The notch's own
   height on top instead, so the figures sit on the same line. */
.wl-reg__amt > .wl-reg__runline > .cf-cur-chip:not(.cf-cur-chip--notch),
.wl-reg__amt .wl-reg__stack .cf-cur-chip:not(.cf-cur-chip--notch){padding-top:10.9px}

/* A control and its clear button sharing one notch. The button keeps to the
   right whatever the control is; a `<select>` draws its own caret at its
   right edge, so the button follows that rather than covering it. */
.wl-nf__clearable{display:flex;align-items:center;gap:.1rem;min-width:0}
.wl-nf__clearable>:first-child{min-width:0;flex:1 1 auto}
.wl-nf__clear{
  flex:none;border:0;background:transparent;cursor:pointer;border-radius:3px;
  padding:1px 2px;line-height:0;color:var(--cf-ink-soft);
}
.wl-nf__clear:hover{color:var(--cf-danger)}
.wl-nf__clear:focus-visible{outline:2px solid var(--cf-remote);outline-offset:1px}
.wl-nf__suffix{flex:none;font-size:.72rem;color:var(--cf-ink-soft);padding-right:.15rem}

/* The date field's own control: text, plus a button that opens our calendar.
   See dateField.ts for why it is ours and not the browser's. */
.wl-date{display:flex;align-items:center;gap:.15rem;min-width:0}
.wl-date__text{min-width:0;font-variant-numeric:tabular-nums}
.wl-date__btn{flex:none;border:0;background:transparent;color:var(--cf-ink-soft);
  padding:0 .15rem;line-height:0;cursor:pointer;border-radius:3px}
.wl-date__btn:hover{color:var(--cf-ink)}
.wl-date__btn:focus-visible{outline:2px solid var(--cf-remote);outline-offset:1px}

/* The tag filter's popover. A button and a count on the page, the whole list
   in here — a book with forty tags used to spend several lines of the page on
   a filter that is mostly not in use. */
.wl-tagf{position:fixed;z-index:1085;background:var(--cf-surface);border:1px solid var(--cf-rule-soft);
  border-radius:10px;box-shadow:0 .5rem 1.5rem rgba(16,24,40,.22);width:16rem;
  display:flex;flex-direction:column;overflow:hidden;max-height:min(24rem,70vh)}
.wl-tagf__head{padding:.35rem .4rem;border-bottom:1px solid var(--cf-sunken);flex:none}
.wl-tagf__search{width:100%;border:0;background:transparent;color:var(--cf-ink);
  font-size:.85rem;padding:.15rem .2rem;outline:none}
/* `contain`, for the reason the account picker's list has it: without it a
   wheel that reaches the end of this list carries on into the register
   behind, and the page moves under an open popover. */
.wl-tagf__list{overflow:auto;overscroll-behavior:contain;padding:.2rem 0;flex:1 1 auto}
.wl-tagf__row{display:flex;align-items:center;gap:.4rem;padding:.25rem .6rem;
  font-size:.84rem;cursor:pointer}
.wl-tagf__row:hover{background:var(--cf-page)}
.wl-tagf__foot{display:flex;align-items:center;gap:.4rem;padding:.3rem .5rem;
  border-top:1px solid var(--cf-sunken);flex:none}

.wl-cal{position:fixed;z-index:1085;background:var(--cf-surface);border:1px solid var(--cf-rule-soft);
  border-radius:10px;box-shadow:0 .5rem 1.5rem rgba(16,24,40,.22);padding:.4rem;width:15rem}
.wl-cal__head{display:flex;align-items:center;gap:.25rem;padding:.1rem .15rem .35rem}
.wl-cal__head>.wl-cal__title,.wl-cal__head>.wl-cal__title--flat{flex:1;justify-content:center;font-size:.8rem}
.wl-cal__nav{border:0;background:transparent;color:var(--cf-ink-soft);font-size:1rem;
  line-height:1;padding:.1rem .4rem;border-radius:4px;cursor:pointer}
.wl-cal__nav:hover{background:var(--cf-sunken);color:var(--cf-ink)}
/* The title is a button: it zooms out to months, then to years. The caret
   says so — the same affordance the native control uses, which is why nobody
   has to be told. */
.wl-cal__title{border:0;background:transparent;color:var(--cf-ink);font-weight:600;
  border-radius:4px;padding:.1rem .4rem;cursor:pointer;display:inline-flex;align-items:center;gap:.2rem}
.wl-cal__title:hover{background:var(--cf-sunken)}
.wl-cal__title--flat{cursor:default;font-weight:600}
.wl-cal__title--flat:hover{background:transparent}
.wl-cal__caret{font-size:.6rem;color:var(--cf-ink-soft)}
/* Months and years are four across, not seven: twelve of them in seven
   columns leaves a ragged five, and a month name needs more room than a
   two-digit day. */
.wl-cal__cell{border:0;background:transparent;color:var(--cf-ink);font-size:.78rem;
  padding:.4rem 0;border-radius:4px;cursor:pointer;font-variant-numeric:tabular-nums}
.wl-cal__cell:hover{background:var(--cf-sunken)}
.wl-cal__cell.is-today{box-shadow:inset 0 0 0 1px var(--cf-rule)}
.wl-cal__cell.is-selected{background:var(--cf-remote);color:var(--cf-surface);font-weight:600}
.wl-cal__cell:focus-visible{outline:2px solid var(--cf-remote);outline-offset:-2px}
.wl-cal__week,.wl-cal__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:1px}
/* After the seven-column rule, not before: both are single classes, so the
   one that wins is the one that comes last. */
.wl-cal__grid--wide{grid-template-columns:repeat(4,1fr);gap:.15rem;padding-top:.15rem}
.wl-cal__week>span{text-align:center;font-size:.6rem;text-transform:uppercase;
  letter-spacing:.04em;color:var(--cf-ink-soft);padding-bottom:.15rem}
.wl-cal__day{border:0;background:transparent;color:var(--cf-ink);font-size:.78rem;
  padding:.25rem 0;border-radius:4px;cursor:pointer;font-variant-numeric:tabular-nums}
.wl-cal__day:hover{background:var(--cf-sunken)}
/* Today is outlined and the chosen day is filled: two different facts, never
   the same signal, and neither is carried by colour alone (invariant 11) —
   the chosen day also carries aria-current. */
.wl-cal__day.is-today{box-shadow:inset 0 0 0 1px var(--cf-rule)}
.wl-cal__day.is-selected{background:var(--cf-remote);color:var(--cf-surface);font-weight:600}
.wl-cal__day:focus-visible{outline:2px solid var(--cf-remote);outline-offset:-2px}
.wl-cal__foot{display:flex;justify-content:flex-end;padding-top:.3rem}
.wl-cal__today{border:0;background:transparent;color:var(--cf-remote);font-size:.72rem;
  padding:.1rem .3rem;border-radius:4px;cursor:pointer}
.wl-cal__today:hover{background:var(--cf-sunken)}

/* The account field's control is a button, because what it opens is a tree
   rather than a list. It has to read like the inputs beside it, not like an
   action: same type, same weight, same alignment, with only the caret to say
   that something happens when you press it. */
.wl-acct-btn{display:flex;align-items:center;gap:.3rem;text-align:left;font-weight:400;
  overflow:hidden;cursor:pointer}
/* The name is two parts, so the RIGHT one can be the one that survives a
   narrow field. The lead shrinks and ellipsises; the account's own name does
   not shrink at all, because it is the half that differs between accounts —
   the full chain is on the button's `title` either way. */
.wl-acct-btn__name{flex:1;min-width:0;display:flex;align-items:baseline;white-space:nowrap;overflow:hidden}
.wl-acct-lead{flex:0 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;color:var(--cf-ink-soft)}
.wl-acct-leaf{flex:0 0 auto;overflow:hidden;text-overflow:ellipsis}
.wl-acct-btn__name--empty{color:var(--cf-ink-soft)}
.wl-acct-btn__caret{flex:none;color:var(--cf-ink-soft);font-size:.7rem}
.wl-acct-btn:hover{background:var(--cf-raise)}
.wl-acct-btn .wl-ico{margin-right:0}

/* Bank sync: one feed account is a small block, not a table row. The mapping
   is three controls of very different shapes — two account trees and a date —
   and five columns of them become unreadable the moment an account name is
   longer than "Cash". Stacked on a phone, side by side from `sm` up. */
.wl-bank-acct{border-top:1px solid var(--cf-sunken);padding:.75rem 0}
.wl-bank-acct:first-child{border-top:0;padding-top:.25rem}
.wl-bank-acct__head{display:flex;justify-content:space-between;align-items:flex-start;
  gap:.75rem;flex-wrap:wrap}
.wl-bank-acct__map{display:grid;grid-template-columns:1fr;gap:.5rem;margin-top:.5rem;
  align-items:end}
@media (min-width:576px){
  .wl-bank-acct__map{grid-template-columns:1fr 1fr 10rem auto}
}
/* A disabled rule is kept but never matches, so it has to read as present and
   inert — dimmed, with the word "Off" in its own column doing the actual
   telling (invariant 11). */
.wl-bank-rule--off>td{opacity:.55}

/* The register's header is the one place a drag means "move this column".
   The grip is a hit area at the right edge; it is not itself draggable, or
   the browser would start a column drag the moment it was pressed and the
   resize would never begin. */
.wl-reg thead th.wl-col{position:relative;cursor:grab;user-select:none}
/* Wide, and straddling the boundary, because missing it is not a near miss —
   it grabs the column and moves it somewhere else. 16px centred on the edge
   is roughly a fingertip and is what people aim at anyway. */
.wl-col__grip{position:absolute;top:0;right:-8px;width:16px;height:100%;cursor:col-resize;
  touch-action:none;z-index:2}
.wl-col__grip::after{content:"";position:absolute;top:20%;right:7px;width:1px;height:60%;
  background:var(--cf-rule)}
.wl-col__grip:hover::after{background:var(--cf-remote,var(--cf-remote));width:2px}
.wl-col--dragging{opacity:.5}
.wl-col--over{box-shadow:inset 3px 0 0 var(--cf-remote,var(--cf-remote))}

/* `table-layout: fixed` is what makes the register's columns obey the width
   they are given instead of the width their content wants. Without it the
   Balance column can never be dragged narrower than the widest chip in it,
   which is exactly the complaint that produced this rule. The table carries
   its own pixel width — the sum of its columns — and the scroll container
   deals with anything wider than the window. */
.wl-reg{table-layout:fixed}
/* So a long description wraps inside its column rather than pushing through
   the one beside it. */
.wl-reg td,.wl-reg th{overflow-wrap:anywhere}
/* Numeric cells stop being nowrap *between* chips: that is what lets Balance
   get narrow, with its currencies stacking instead of sitting in one
   unbreakable line. A chip itself still never breaks — `.cf-cur-chip` keeps
   its own `white-space:nowrap`. */
.wl-reg .wl-num{white-space:normal}

/* Attachments. A tile is the thumbnail when there is one and the file's type
   when there is not — "there is a file here" and "there is a PDF here" answer
   different questions, and the second is usually the one being asked. */
.wl-att{position:relative;display:inline-block;margin:0 3px 3px 0;vertical-align:middle}
.wl-att__link{display:block;width:34px;height:34px;border:1px solid var(--cf-rule-soft);border-radius:6px;
  overflow:hidden;background:var(--cf-page);text-decoration:none}
.wl-att__link img{width:100%;height:100%;object-fit:cover;display:block}
.wl-att__kind{display:flex;align-items:center;justify-content:center;width:100%;height:100%;
  font-size:.58rem;font-weight:700;letter-spacing:.04em;color:var(--cf-ink-soft)}
.wl-att__link:hover{border-color:var(--cf-remote,var(--cf-remote))}
.wl-att__x{position:absolute;top:-6px;right:-6px;width:16px;height:16px;line-height:14px;
  border-radius:999px;border:1px solid var(--cf-rule-soft);background:var(--cf-surface);color:var(--cf-ink-soft);
  font-size:.7rem;padding:0;cursor:pointer}
.wl-att__x:hover{color:var(--cf-conflict);border-color:var(--cf-conflict)}
/* The editor's row of files: label, tiles, the button, then whatever it has
   to say — laid out so adding a file never moves the form under it. */
.wl-att-bar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;min-height:2.25rem}
/* The file input is inside its own label, so the label *is* the button. */
.wl-att-bar label.disabled{pointer-events:none;opacity:.6}
/* In the register the tiles are smaller: the column is a glance, not a gallery. */
.wl-reg .wl-att__link{width:26px;height:26px}

/* The bank-origin badge and its hover panel — see webledgerBankInfo.ts.
   The badge sits inline in a description, small enough not to compete with
   the text and large enough to be a pointer target; it is focusable, so it
   needs a visible focus ring of its own rather than inheriting a cell's. */
.wl-bankbadge{display:inline-block;margin-left:.3rem;font-size:.78em;line-height:1;
  cursor:default;opacity:.75;vertical-align:baseline}
.wl-bankbadge:hover,.wl-bankbadge:focus{opacity:1}
.wl-bankbadge:focus-visible{outline:2px solid var(--cf-remote,var(--cf-remote));outline-offset:2px;border-radius:3px}
/* Fixed, not absolute: the panel is placed against the viewport so it stays
   whole next to a row near the bottom of a long, scrolled register. */
.wl-bi{position:fixed;z-index:1080;max-width:28rem;max-height:60vh;overflow:auto;
  padding:.6rem .7rem;border:1px solid var(--cf-rule-soft);border-radius:8px;background:var(--cf-surface);
  box-shadow:0 6px 24px rgba(16,24,40,.14);font-size:.8rem;
  /* It follows the pointer's row and must never swallow the hover that opened it. */
  pointer-events:none}
.wl-bi__title{font-weight:600;margin-bottom:.35rem}
.wl-bi__entry{font-weight:600;color:var(--cf-ink-soft);margin:.25rem 0}
.wl-bi__row{display:flex;gap:.75rem;justify-content:space-between;padding:.1rem 0}
.wl-bi__row span:first-child{color:var(--cf-ink-soft);white-space:nowrap}
.wl-bi__row span:last-child{text-align:right;word-break:break-word}
.wl-bi__sep{border-top:1px solid var(--cf-sunken);margin:.35rem 0}
.wl-bi__note{color:var(--cf-ink-soft);margin-top:.35rem}

.wl-splits{min-width:44rem}
.wl-splits th:nth-child(1),.wl-splits td:nth-child(1){min-width:9rem}   /* account */
.wl-splits th:nth-child(2),.wl-splits td:nth-child(2),
.wl-splits th:nth-child(3),.wl-splits td:nth-child(3){min-width:7rem}   /* + / − */
.wl-splits th:nth-child(4),.wl-splits td:nth-child(4){min-width:11rem}  /* acct-currency amount */
.wl-splits th:nth-child(5),.wl-splits td:nth-child(5){min-width:7rem}   /* memo */
.wl-splits th:nth-child(6),.wl-splits td:nth-child(6){width:2.5rem}     /* remove */
/* The per-row +/− labels carry the account's own type wording, which is the
   point of the column; the header's currency echo is the redundant half on a
   narrow screen, so that is what goes (same reduce-don't-reflow approach as
   the state chip's text at 520px). */
@media (max-width:520px){
  .wl-splits .txCurLabel{display:none}
}

/* Money inputs: real `type="number"` (native validation, numeric keypad on
   mobile), spinner arrows suppressed — they're never used for amounts and
   steal width from the field. Legacy scoped this rule to one modal only
   (`#txModal input[type=number]`), which is why other pages there still show
   native spinners; we apply it globally instead of replicating that
   inconsistency (docs/legacy/webledger.ux-audit-shared.md). */
.cf-no-spin::-webkit-outer-spin-button,
.cf-no-spin::-webkit-inner-spin-button{-webkit-appearance:none;margin:0}
.cf-no-spin{-moz-appearance:textfield;appearance:textfield}

/* ===================================================================
   CONNECTION INDICATOR
=================================================================== */
/* ADR-0011: "The UI must say so ('editing offline, not reserved') or users
   assume the same protection they get online." A dropped socket used to be
   invisible until a save failed, so this sits in the page chrome permanently.
   Text always accompanies the dot (invariant #11 — colour is never the only
   signal), and the dot is `aria-hidden` in the markup so screen readers get
   the word alone. `is-open` reuses --cf-mine (the same green that means "this
   is yours" on a field) and `is-closed` --cf-conflict rather than a new
   palette entry. */
.cf-conn{display:inline-flex;align-items:center;gap:.35rem;font-size:.75rem;
  color:var(--cf-ink-soft);white-space:nowrap}
.cf-conn__dot{width:.5rem;height:.5rem;border-radius:50%;background:var(--cf-pending);
  flex:0 0 auto}
.cf-conn.is-open .cf-conn__dot{background:var(--cf-mine)}
.cf-conn.is-connecting .cf-conn__dot{background:var(--cf-conflict);
  animation:cf-conn-pulse 1.2s ease-in-out infinite}
.cf-conn.is-closed{color:var(--cf-conflict);font-weight:600}
.cf-conn.is-closed .cf-conn__dot{background:var(--cf-conflict)}
@keyframes cf-conn-pulse{0%,100%{opacity:1}50%{opacity:.3}}
@media (prefers-reduced-motion:reduce){
  .cf-conn.is-connecting .cf-conn__dot{animation:none}
}

/* A transaction created offline and still in the outbox. Muted rather than
   alarming — nothing is wrong, it just has not left the device yet — but
   never colour alone: the row carries a "waiting to sync" label and its own
   glyph (invariant #11). */
/* On the cells, not the row: the register's rows paint their own background
   to make the outlined-block look work, which would hide a stripe set on the
   `tr` behind them. */
.wl-tx-pending td{background:repeating-linear-gradient(135deg,transparent,transparent 6px,rgba(138,143,152,.07) 6px,rgba(138,143,152,.07) 12px)}
.wl-tx-pending .cf-lockedby{color:var(--cf-conflict)}

/* "A new version is ready" — a quiet bar, never a modal. A cache-first shell
   (ADR-0022) means a deploy reaches the user on their next reload, and this
   is how they find out; reloading unasked would discard a half-typed split
   table for a cosmetic update. Text plus a real button, in a polite live
   region (invariant #11). */
/* `width:max-content` matters: a shrink-to-fit fixed box lets its flex
   children collapse to min-content, which wrapped this to one word per line.
   Size to the natural content, and only give way when the viewport is
   genuinely narrower. */
.cf-updatebar{position:fixed;left:50%;transform:translateX(-50%);bottom:1rem;z-index:1080;
  display:flex;align-items:center;gap:.6rem;padding:.5rem .75rem;font-size:.8rem;
  background:var(--cf-surface);border:1px solid var(--cf-rule);border-radius:8px;
  box-shadow:0 4px 16px rgba(27,36,48,.14);
  width:max-content;max-width:calc(100vw - 2rem);flex-wrap:wrap}
.cf-updatebar .btn{flex:0 0 auto;white-space:nowrap}
.cf-updatebar .btn-link{padding:0;font-size:.8rem}

/* ===================================================================
   CHANGE HISTORY (webledger's transaction timeline)
=================================================================== */
/* A slide-over rather than a section inside the transaction modal: the modal
   already carries a six-column split table, and the point of the panel is to
   be readable *beside* what you are editing. Sits above the modal's own
   backdrop, and on a phone becomes a full sheet — there is no room for two
   panes at 375px. */
.cf-timeline{position:fixed;top:0;right:0;bottom:0;width:min(30rem, 100vw);z-index:1070;
  background:var(--cf-surface);border-left:1px solid var(--cf-rule);
  box-shadow:-8px 0 24px rgba(27,36,48,.12);display:flex;flex-direction:column}
.cf-timeline__head{display:flex;align-items:center;gap:.5rem;padding:.6rem .9rem;
  border-bottom:1px solid var(--cf-rule)}
.cf-timeline__body{overflow-y:auto;padding:.5rem .9rem 1.5rem}
@media (max-width:640px){ .cf-timeline{width:100vw;border-left:0} }

/* One commit. The rail and dot make the sequence readable at a glance without
   colour carrying meaning on its own (invariant #11) — every entry also
   states who, when and what in words. */
.cf-tl{position:relative;padding:.55rem 0 .55rem 1.4rem;border-left:2px solid var(--cf-rule);
  margin-left:.35rem}
.cf-tl:last-child{border-left-color:transparent}
.cf-tl__dot{position:absolute;left:-.42rem;top:.85rem;width:.7rem;height:.7rem;border-radius:50%;
  background:var(--cf-rule);border:2px solid var(--cf-surface)}
.cf-tl.is-current .cf-tl__dot{background:var(--cf-mine)}
.cf-tl.is-import .cf-tl__dot{background:var(--cf-system)}
/* The version the form is currently showing. Marked with a tinted rail and a
   "shown in the form" chip, never colour alone (invariant #11) — the form
   looks identical whichever version it holds, so this is the only thing
   saying which one you are looking at. */
.cf-tl.is-viewing{border-left-color:var(--cf-remote);background:rgba(37,99,235,.045)}
.cf-tl.is-viewing .cf-tl__dot{background:var(--cf-remote)}
.cf-tl__who{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;font-size:.8rem}
.cf-tl__when{color:var(--cf-ink-soft);font-size:.72rem}
.cf-tl__summary{font-size:.78rem;color:var(--cf-ink-soft);margin:.1rem 0 .2rem}
.cf-tl__changes{margin:.35rem 0 0;border:1px solid var(--cf-rule);border-radius:6px;overflow:hidden}
.cf-tl__change{display:grid;grid-template-columns:1fr auto auto auto;gap:.4rem;align-items:baseline;
  padding:.3rem .5rem;font-size:.75rem;border-top:1px solid var(--cf-rule)}
.cf-tl__change:first-child{border-top:0}
.cf-tl__field{color:var(--cf-ink-soft)}
.cf-tl__from{font-family:var(--cf-mono);font-size:.72rem;color:var(--cf-ink-soft);
  text-decoration:line-through;word-break:break-word}
.cf-tl__arrow{color:var(--cf-ink-soft)}
.cf-tl__to{font-family:var(--cf-mono);font-size:.72rem;word-break:break-word}
.cf-tl__warn{display:inline-flex;align-items:center;gap:.25rem;margin-top:.3rem;font-size:.7rem;
  color:var(--cf-conflict);font-weight:600}
.cf-tl__actions{margin-top:.35rem;display:flex;gap:.4rem}

/* A panel's grab area. `touch-action:none` is required, not cosmetic: without
   it a touch drag scrolls the page instead of moving the panel, because the
   browser claims the gesture before `pointermove` ever fires. */
.cf-drag-handle{cursor:grab;touch-action:none;user-select:none}
.cf-drag-handle.is-dragging{cursor:grabbing}
.cf-drag-handle:focus-visible{outline:2px solid var(--cf-remote);outline-offset:-2px}
.cf-drag-grip{color:var(--cf-ink-soft);line-height:1;letter-spacing:.1em;font-size:.8rem}
/* Dragging is a pointer/keyboard affordance with nowhere to go on a phone,
   where the panel is a full-width sheet already. */
@media (max-width:640px){ .cf-drag-handle{cursor:default} .cf-drag-grip{display:none} }

/* ===================================================================
   REPORTS (webledger's three cross-account reports)
=================================================================== */
/* The filter bar stays put while a long report scrolls under it — these
   reports have no row cap by design (legacy's "never show partial truth"),
   so "scroll back up to change the date range" is a real cost. */
.wl-filters{position:sticky;top:0;z-index:3;background:var(--cf-surface)}
.wl-filters .form-label{font-size:.7rem;text-transform:uppercase;letter-spacing:.04em;
  font-weight:700;color:var(--cf-ink-soft)}

/* The totals bar sits under the filters, not at the foot of the page: with no
   row cap the foot can be thousands of rows away, and the total is the thing
   most people came for. */
.wl-totals{position:sticky;top:64px;z-index:2;
  display:flex;flex-wrap:wrap;align-items:center;gap:.5rem;
  background:var(--cf-surface);border:1px solid var(--cf-rule-soft);border-radius:9px;
  padding:.45rem .6rem;margin-bottom:1rem}


/* The same bar on a page with nothing sticky above it. The reports' 64px
   offset clears their filter bar; the wallets page has no such thing, so
   pinning it there would park the totals in the middle of the viewport. */
.wl-totals--flow{position:static}

/* Date rule between days in the all-transactions report. */
.wl-daterule{font-size:.78rem;font-weight:700;letter-spacing:.03em;
  color:var(--cf-remote);border-bottom:1px solid var(--cf-rule-soft);
  padding-bottom:.25rem;margin:1rem 0 .5rem}

.wl-tx-card{border:1px solid var(--cf-rule-soft);border-radius:9px}
.wl-legs{font-size:.82rem}
.wl-legs thead th{font-weight:400;font-size:.7rem;color:var(--cf-ink-soft);
  border-bottom:1px solid var(--cf-page);padding:.2rem .4rem}
.wl-legs td{padding:.28rem .4rem;vertical-align:middle}
.wl-num{text-align:right;white-space:nowrap}
/* The register vocabulary ("Increase"/"Expense"/…) beside the figure it
   describes — the sign alone does not say what a negative means for an
   income account (invariant #11 again: never the one signal). */
.wl-dir{font-size:.66rem;color:var(--cf-ink-soft);margin-right:.4rem;text-transform:uppercase;letter-spacing:.03em}
/* An account name that is also the way into that account's register, at the
   transaction you are looking at — legacy's `transfer-link`, and the thing
   that makes a report readable *from* rather than only readable.

   Quiet on purpose. A report card names two or three accounts and a register
   split line names one per row; a column of blue beside the figures would
   drown them. The underline is always there, so the link is never signalled
   by colour alone (invariant #11), and it firms up on hover and focus. */
/* An account's icon in running text — before a name in a split line, a
   Transfer cell, a trial-balance row. Smaller than the chart of accounts'
   because these sit inside a dense table, and never underlined with the link
   it sits in: an underline running under a picture reads as a mistake. */
/* The path in front of an account name is context, not the name: dimmed so
   the account's own name reads first. Opacity rather than a colour, so it
   works inside a link, on a marked row's tint and on an out-of-scope leg's
   already-muted ink — all of which a hardcoded grey would fight. */
.wl-acct-path{opacity:.6;font-weight:400}
.wl-ico{margin-right:.3rem;text-decoration:none;display:inline-block}
.wl-ico .wl-acct-icon{width:16px;height:16px;vertical-align:-3px}
.wl-acct{color:inherit;text-decoration:underline;text-decoration-color:var(--cf-rule);text-underline-offset:3px}
a.wl-acct:hover,a.wl-acct:focus-visible{color:var(--cf-ink);text-decoration-color:currentColor}

/* A leg outside the active purpose or folder scope. Muted and struck from the
   running column, because it is shown for context only and counts towards
   nothing — the whole point of scoping a folder view. */
.wl-outscope td{color:var(--cf-ink-soft);opacity:.75}

@media (max-width:640px){
  .wl-totals{top:0;position:static}
  .wl-filters{position:static}
}

/* Totals-bar mode select and the "this figure is incomplete" marker. */
.wl-totalmode{width:auto;font-size:.75rem}
.wl-fx-warn{color:var(--cf-conflict);font-size:.72rem;font-weight:600;cursor:help}

/* ===================================================================
   WEBLEDGER PAGE HEADER
=================================================================== */
/* Title, tabs and page-level controls on one line, as legacy's navbar has
   them. The tabs carry the bottom rule for the whole row, so the header still
   reads as one band rather than a strip of loose controls — `align-items:
   flex-end` is what lines that rule up with the baseline of everything else. */
.wl-head{
  display:flex;align-items:flex-end;gap:.75rem;flex-wrap:wrap;
  border-bottom:1px solid var(--cf-rule-soft);
}
/* Measured, not guessed: the padding is what puts the word's centre on the
   tab labels' centre, and at 1.1rem against their .88rem the two do not
   share a baseline for free. */
.wl-head__brand{font-size:1.1rem;font-weight:600;line-height:1;padding-bottom:.425rem;white-space:nowrap}
/* `min-width:0` and `overflow:hidden` are what let the bar be MEASURED: a
   flex item defaults to its content's width, so without them `scrollWidth`
   and `clientWidth` are always equal and nothing ever overflows. */
.wl-head__tabs{border-bottom:0;margin-bottom:-1px;flex:1 1 auto;min-width:0;overflow:hidden;flex-wrap:nowrap}
.wl-head__tabs .nav-link{padding:.4rem .75rem;font-size:.88rem;white-space:nowrap}
/* The status word sits on the tab labels' line by its own height; a shade of
   clearance from the rule is all it needs. */
.wl-head > .cf-conn{margin-bottom:.4rem}
/* The buttons bottom-align with the TAB BOXES rather than floating a fixed
   distance above the rule.
 
   They used to share the status word's .4rem, and because a small button is
   5px shorter than a tab, that lifted their LABELS almost six pixels above
   the tab labels — enough to read as two rows pretending to be one. A tab
   box ends at the rule, so a control that ends there too has its text where
   a tab's text is, whatever either of them is padded by. The 1px is a
   hairline of clearance, so the outline reads as a button sitting in the
   band rather than as a thickening of the rule itself. */
.wl-head > .btn,
.wl-head__more{margin-bottom:1px}
/* The way out sits first, where the eye goes back to. */
.wl-head__back{order:-1}

.wl-head__more{position:relative;flex:0 0 auto}
/* `fixed`, not `absolute`, and placed by script.
   The header sits inside `.wl-head-fold__in`, whose `overflow:hidden` is what
   lets the log's header fold — and an absolutely positioned menu is clipped
   by exactly that, so the disclosure opened a sliver one line tall on every
   page in the app. A fixed element is clipped only by an ancestor that
   establishes a containing block (a transform, filter or will-change), and
   the header chain has none, so this escapes the fold wrapper without the
   fold having to give up clipping. The cost is that it does not travel with
   the page, which is why `wireNavOverflow` closes it on scroll. */
.wl-head__menu{
  position:fixed;z-index:30;margin:0;padding:.25rem;
  list-style:none;min-width:190px;
  border:1px solid var(--cf-rule);border-radius:8px;background:var(--cf-surface);
  box-shadow:0 8px 24px rgba(15,23,42,.14);
}
/* Out of the way: it carries the filter definition and nothing visible. */
.cf-lens{position:absolute;width:0;height:0;overflow:hidden}
.wl-head__menu .nav-link{display:block;padding:.35rem .6rem;border-radius:5px;font-size:.88rem}
.wl-head__menu .nav-link:hover{background:var(--cf-page)}
.wl-head__menu .nav-link.active{font-weight:600}

@media (max-width:640px){
  /* The brand is the first thing to go: the tabs say where you are. */
  .wl-head__brand{display:none}
}

/* ===================================================================
   BOOTSTRAP'S FIXED LIGHT UTILITIES, UNDER A DARK THEME
=================================================================== */
/*
 * `text-bg-light`, `bg-light`, `bg-white` and `table-light` are FIXED
 * variants: Bootstrap deliberately does not move them with `data-bs-theme`,
 * because "light" there names a colour rather than a role. So every account
 * type badge stayed a bright white plate on a dark page.
 *
 * Re-pointed at the theme's own surfaces, which is what legacy did for the
 * same reason — these four selectors are carried over from its dark block
 * almost unchanged.
 */
:root[data-bs-theme="dark"] .table-light{
  --bs-table-bg:var(--cf-raise);
  --bs-table-color:var(--cf-ink);
  --bs-table-border-color:var(--cf-rule-soft);
}
:root[data-bs-theme="dark"] .bg-light,
:root[data-bs-theme="dark"] .bg-white{background-color:var(--cf-raise) !important}
:root[data-bs-theme="dark"] .badge.text-bg-light,
:root[data-bs-theme="dark"] .badge.bg-light{
  background-color:var(--cf-sunken) !important;color:var(--cf-ink) !important;
}
:root[data-bs-theme="dark"] .badge.bg-light.text-dark{color:var(--cf-ink) !important}
/* An icon drawn on a pale tint needs an edge, or it bleeds into the page. */
:root[data-bs-theme="dark"] .acct-icon{border-radius:4px}



/* ===================================================================
   CURRENCY CHIP (legacy's `cur-chip`)
=================================================================== */
/* One amount with its currency, used wherever a signed figure appears. The
   marker is a column — flag over a small code — so the whole thing stays
   narrow enough for a table cell while still naming the currency in words. */
.cf-cur-chips{display:inline-flex;flex-wrap:wrap;gap:4px 6px;align-items:center}
.cf-cur-chip{
  display:inline-flex;align-items:center;gap:6px;
  background:var(--cf-page);border:.5px solid var(--cf-rule-soft);border-radius:7px;
  padding:2px 9px 2px 6px;
  font-variant-numeric:tabular-nums;font-size:.82rem;line-height:1.2;
  white-space:nowrap;
}
/* A chip wearing its own label in its top border — the wallet a leg belongs
   to, or the mark that says a figure is a total. See
   `CurrencyChipOptions.notch`.
   
   The rim is NOT a border here. A chip's rim is a gradient, which a
   `border-color` cannot be, so it is a ring masked out of `::after` — and a
   pseudo-element covering the whole box knows nothing about a legend, which
   is why the fieldset this started as drew a second unbroken border inside
   the notched one. The gap is cut out of that mask instead: one more mask
   layer, a strip the width of the label, subtracted from the full-size
   rectangle before the ring is taken out of it. Nothing is painted over the
   rim, so nothing needs to know the colour behind it — which was the whole
   case for the fieldset.
   
   `--cf-notch-w` is the width of the label text, measured by the component,
   because it is the one thing in that strip CSS cannot work out for itself.
   The default is a guess for a chip that arrives without one; an undefined
   length here would invalidate the mask and paint the ring solid.
   
   The chip is lowered by half a line so the rim lands on the label's middle,
   as a legend does. That half-line is a margin and not padding, so the label
   can hang above the rim while staying inside what the row lays out.
   
   Directly after `.cf-cur-chip`, and not up with the notched fields where it
   used to live: the two selectors are one class each, so the padding below
   quietly won until this moved. */
.cf-cur-chip--notch{
  position:relative;min-width:0;
  margin:.31rem 0 0;padding:calc(1px + .31rem) 9px 2px 6px;
  border-color:transparent;
  --cf-notch-w:3.5rem;
  --cf-chip-rim:var(--cf-rule-soft);
  --cf-chip-rim-width:.5px;
}
.cf-cur-chip--notch::after{
  content:'';position:absolute;inset:0;border-radius:inherit;
  padding:var(--cf-chip-rim-width);pointer-events:none;
  background:var(--cf-chip-rim);
  /* Where the gap starts, and how wide. The 8px is the label's breathing
     room, 4px a side, as `.wl-nf`'s legend has. Capped at the label's own
     `max-width`, or a truncated name would ask for a gap wider than the
     ellipsis it is drawn with.
     
     Lengths only, no percentages: a `min()` carrying one inside a mask
     gradient drops the whole layer in Chrome, and a dropped layer is not a
     missing gap but a solid rectangle over the chip. */
  --cf-notch-x:4.5px;
  --cf-notch-gap:calc(min(var(--cf-notch-w),7.5rem) + 8px);
  --cf-notch-hole:linear-gradient(90deg,
      transparent var(--cf-notch-x),
      #000 var(--cf-notch-x) calc(var(--cf-notch-x) + var(--cf-notch-gap)),
      transparent calc(var(--cf-notch-x) + var(--cf-notch-gap)))
    no-repeat left top / 100% var(--cf-chip-rim-width);
  /* Bottom up: the full rectangle less the gap, then the content box taken
     out of that — a ring with a bite in its top edge. */
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0),var(--cf-notch-hole);
  -webkit-mask-composite:xor,source-out,source-over;
  mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0),var(--cf-notch-hole);
  mask-composite:exclude,subtract,add;
}
.cf-cur-chip__notch{
  /* Lifted half its own line above the rim, which is where a legend sits. It
     is out of flow, so a long name can neither widen the chip nor push the
     figure down. */
  position:absolute;top:calc(-.31rem + .5px);left:8.5px;
  /* Capped, so a long wallet cannot stagger the column beside it. The whole
     name is in the chip's accessible label. `--cf-notch-w` is capped to
     match, so the gap ends where the ellipsis does. */
  max-width:7.5rem;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;
  font-size:.62rem;line-height:1;font-weight:400;color:var(--cf-ink-soft);
}
.cf-cur-mark{display:inline-flex;flex-direction:column;align-items:center;line-height:1;width:22px;flex:none}
.cf-cur-code{color:var(--cf-ink-soft);font-size:8.5px;margin-top:1px;letter-spacing:.02em}
.cf-cur-flag{flex:none;border-radius:2px;border:.5px solid rgba(0,0,0,.12);display:block}
.cf-cur-amt{font-weight:500}
/* Negative is the one thing colour alone would carry, so the minus sign stays
   in the formatted number too (invariant #11) — this only reinforces it. */
.cf-cur-amt.is-negative{color:var(--cf-amount-negative)}
/* A chip on a row that is out of scope counts towards nothing, and should not
   draw the eye like one that does. */
.cf-cur-chip.is-muted{opacity:.55;background:transparent}
/* Chip tally: a picked chip has to be obvious at a glance in a table of
   several hundred, and obvious without colour alone (invariant 11) — hence the
   ring plus the leading sign, which is also the only thing distinguishing an
   added pick from a subtracted one. */
.cf-cur-chip--picked{outline:2px solid var(--cf-mine,var(--cf-mine));outline-offset:1px;border-radius:4px}
.cf-cur-chip--picked::before{content:"+";font-weight:700;color:var(--cf-mine,var(--cf-mine));margin-right:.15rem}
.cf-cur-chip--minus{outline-color:var(--cf-danger)}
.cf-cur-chip--minus::before{content:"\2212";color:var(--cf-danger)}

/* The panel belongs to no page's layout: fixed, so it never moves anything
   when it appears and stays with the reader wherever they have scrolled. */
.wl-tally{position:fixed;right:12px;bottom:12px;z-index:1050;min-width:11rem;max-width:16rem;
  max-height:60vh;overflow:auto;background:var(--cf-surface);border:1px solid var(--cf-rule-soft);
  border-radius:10px;box-shadow:0 6px 20px rgba(15,23,42,.14);padding:.5rem .6rem}
.wl-tally__head{display:flex;align-items:center;justify-content:space-between;gap:.5rem}
.wl-tally__x{border:0;background:transparent;line-height:1;color:var(--cf-ink-soft);cursor:pointer;
  padding:0 .15rem}
.wl-tally__x:hover,.wl-tally__x:focus-visible{color:var(--cf-ink)}
.wl-tally__rows{margin-top:.25rem}
.wl-tally__line{display:flex;align-items:center;gap:.35rem;width:100%;border:0;background:transparent;
  padding:.15rem 0;cursor:pointer;text-align:left}
.wl-tally__line:hover{background:var(--cf-raise)}
.wl-tally__n{font-size:.7rem;color:var(--cf-ink-soft);font-variant-numeric:tabular-nums}
.wl-tally__parts{padding:.1rem 0 .25rem .5rem;border-left:2px solid var(--cf-sunken);margin-left:.15rem}
.wl-tally__part{display:flex;gap:.3rem;font-size:.72rem;font-variant-numeric:tabular-nums}
.wl-tally__sub{font-size:.62rem;text-transform:uppercase;letter-spacing:.04em;color:var(--cf-ink-soft);
  margin-top:.15rem}
.wl-tally__hint{font-size:.66rem;color:var(--cf-ink-soft);margin:.35rem 0 0}
/* On a phone the panel would cover the row being read; it sits across the
   bottom instead, where it covers a margin. */
@media (max-width:520px){
  .wl-tally{left:12px;right:12px;max-width:none;max-height:40vh}
  .wl-tally__hint{display:none}
}


.cf-cur-chip.is-muted .cf-cur-amt{font-weight:400;color:var(--cf-ink-soft)}

/* One leg in the register's splits summary: account, then its chip. */
.wl-leg{display:inline-flex;align-items:center;gap:.3rem;margin-right:.6rem;white-space:nowrap}

/* A report card carries the same state vocabulary a register row does: the
   holder's colour on the left edge, and a chip notched into the top border.
   Same shapes as `.wl-tx-list`, because they say the same things. */
.wl-tx-card{position:relative;border-left-width:3px;border-left-color:var(--row-color,var(--cf-rule-soft))}
.wl-tx-card.wl-tx-held{border-left-color:var(--cf-conflict)}
.wl-tx-card.wl-tx-pending{border-left-color:var(--cf-pending)}
.wl-tx-card > [data-state-slot]{position:absolute;left:.6rem;top:0;transform:translateY(-50%);z-index:1}
.wl-tx-card > [data-state-slot] .wl-state-chip{position:static;transform:none}

/* ===================================================================
   CHART OF ACCOUNTS (webledger's tree)
=================================================================== */
.wl-acct-bar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}
.wl-acct-bar__sel{width:auto;font-size:.78rem}
.wl-acct-name{display:flex;align-items:center;gap:.35rem;min-width:0}
/* Reserved whether or not this row has children, so names line up down the
   column instead of stepping in and out with the tree's shape. */
.wl-caret{
  border:0;background:none;padding:0;width:16px;flex:none;
  color:var(--cf-ink-soft);font-size:.7rem;line-height:1;
  border-radius:4px;
}
.wl-caret:hover{color:var(--cf-ink);background:var(--cf-sunken)}
.wl-caret--empty{display:inline-block;width:16px;flex:none}
.wl-acct-icon{width:18px;height:18px;flex:none;border-radius:3px;object-fit:contain}
/* Edit stays out of the way until the row is touched — every row having a
   visible button turns a 59-row tree into a wall of buttons. It remains in
   the tab order regardless (invariant #4's reasoning: never unreachable). */
.wl-acct-edit{
  border:0;background:none;padding:0 .25rem;border-radius:4px;
  font-size:.68rem;color:var(--cf-ink-soft);opacity:0;transition:opacity .12s;
}
tr:hover .wl-acct-edit,.wl-acct-edit:focus-visible{opacity:1}
.wl-acct-edit:hover{color:var(--cf-ink);background:var(--cf-sunken)}
/* The "own" line: what this account holds directly, shown only when it also
   has children (otherwise it is the subtree total said twice). */
.wl-acct-own{display:flex;align-items:center;gap:.4rem;margin-top:2px;padding-left:2.4rem}
.wl-acct-own__lbl{font-size:10px;color:var(--cf-ink-soft);text-transform:uppercase;letter-spacing:.03em}
.wl-purpose-row td{background:var(--cf-raise);border-top:1px solid var(--cf-rule-soft)}

/* ===================================================================
   ACCOUNT REGISTER
=================================================================== */
.wl-reg-head{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}
.wl-reg-title{font-size:.95rem}
.wl-reg tbody tr[data-tx-row]{cursor:grab}
.wl-reg tbody tr[data-tx-row]:active{cursor:grabbing}
/* Where a dragged row would land. Only ever drawn on a row of the same date —
   dragging across days is refused, because the date decides the position and
   `seq` only orders within it. */
.wl-drop-target td{box-shadow:inset 0 2px 0 0 var(--cf-remote)}
/* The wallet log's rows are grid items, not table rows: same mark, no `td` to hang it on. */
.wl-reg__row.wl-drop-target{box-shadow:inset 0 2px 0 0 var(--cf-remote)}
/* Legs of a transaction, under its row, when "Show splits" is on. */
.wl-reg-split td{background:var(--cf-raise);font-size:.78rem;padding-top:.15rem;padding-bottom:.15rem;border-top:0}
.wl-reg-opening td{background:var(--cf-page);font-style:italic}

/* Drag-to-reorder feedback, shared by the account tree and the register. */
.wl-dragging{opacity:.5}
/* A visible grip, where the chart of accounts makes the whole row draggable.
   A short flat list gives no other hint that its order is the reader's to
   change, and a glyph says so without relying on discovery or on colour
   (invariant #11). */
.wl-grip{width:1.5rem;color:var(--cf-ink-soft);cursor:grab;user-select:none;text-align:center}

/* Transaction tags. A pill with a readable name in it — no colour coding,
   because a tag told apart only by hue is a tag some readers cannot tell
   apart at all (invariant #11). */
.wl-tag{display:inline-flex;align-items:center;gap:.25rem;margin:0 .25rem .25rem 0;
  padding:.1rem .45rem;border:1px solid var(--cf-rule-soft);border-radius:999px;background:var(--cf-page);
  font-size:.78rem;line-height:1.35;white-space:nowrap}
.wl-tag__x{border:0;background:none;padding:0 0 0 .1rem;line-height:1;color:var(--cf-ink-soft);
  font-size:.9rem;cursor:pointer}
.wl-tag__x:hover{color:var(--cf-conflict)}
/* The editor's tag row, laid out so adding one never moves the form under it. */
.wl-tag-bar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;min-height:2.25rem}
/* The "Between wallets" row in the full editor — same shape as the tag bar
   beneath it, because it answers the same kind of question about the whole
   transaction rather than about one leg. */
/* "Between wallets" is a LIST now — one entry can carry two loans that have
   nothing to do with each other — so the bar stacks its rows rather than
   laying one row out across itself. */
.wl-xfer{display:flex;flex-direction:column;align-items:flex-start;gap:.4rem}
.wl-xfer > .cf-h{margin-bottom:-.1rem}
#txMoveRows:empty{display:none}
/* Each row reads as a sentence that wraps: kind, from, to, of which amount.
   The words between the controls are what make it one, so they stay on the
   line with the control they introduce. */
.wl-xfer__row{display:flex;align-items:center;gap:.35rem;flex-wrap:wrap;width:100%}
.wl-xfer__row > select{min-width:0}
.wl-xfer__row > [data-move-remove]{margin-left:auto;line-height:1;padding:.1rem .4rem}
/* Selected in the report filter: the same pill, pressed. */
.wl-tag.is-on{background:var(--cf-remote,var(--cf-remote));border-color:var(--cf-remote,var(--cf-remote));color:var(--cf-surface)}
.wl-tag--pick{cursor:pointer}
.wl-grip:active{cursor:grabbing}

.wl-merge-sources{max-height:16rem;overflow-y:auto;border:1px solid var(--cf-rule-soft);border-radius:7px;padding:.5rem}

/* ---- Tree account picker ----
   A `<select>` of 59 accounts is a flat list with no hierarchy and no search,
   in a book where three different accounts are called "Cash". The panel is
   `position:fixed` and placed against the window, so it can be taller than
   the modal it is opened from. */
.wl-apk{position:fixed;z-index:1080;display:flex;flex-direction:column;overflow:hidden;
  background:var(--cf-surface);border:1px solid var(--cf-rule-soft);border-radius:10px;
  box-shadow:0 .5rem 1.5rem rgba(16,24,40,.22);max-height:80vh}
.wl-apk__head{display:flex;align-items:center;gap:.25rem;padding:.35rem .5rem;
  border-bottom:1px solid var(--cf-sunken);flex:none}
.wl-apk__input{flex:1;min-width:0;border:0;background:transparent;color:var(--cf-ink);
  font-size:.85rem;padding:.15rem 0;outline:none}
.wl-apk__btn{border:0;background:transparent;color:var(--cf-ink-soft);line-height:1;
  padding:.15rem .35rem;border-radius:4px;font-size:.8rem}
.wl-apk__btn:hover{background:var(--cf-sunken);color:var(--cf-ink)}
.wl-apk__close{margin-left:.15rem;border-left:1px solid var(--cf-sunken);padding-left:.45rem}
/* `contain`, not the default `auto`: without it a wheel that reaches the end
   of this list carries on into the page behind, so looking for an account
   near the bottom of the tree scrolls the register instead and the tree
   appears not to respond at all. */
.wl-apk__list{overflow:auto;overscroll-behavior:contain;padding:.25rem 0;flex:1 1 auto}
.wl-apk__sec{font-size:.62rem;text-transform:uppercase;letter-spacing:.05em;
  color:var(--cf-ink-soft);padding:.3rem .6rem .1rem}
.wl-apk__sec--top{border-top:1px solid var(--cf-sunken);margin-top:.2rem}
.wl-apk__row{display:flex;align-items:center;gap:.3rem;padding:.2rem .5rem;font-size:.84rem;
  line-height:1.35;cursor:pointer;white-space:nowrap}
.wl-apk__row:hover,.wl-apk__row--active{background:var(--cf-page)}
/* The chosen account carries the same marker as a chosen row anywhere else,
   and the flash settles into it — see "You are here" below. */
.wl-apk__row.wl-current{background:var(--wl-current)}
.wl-apk__row.wl-flash{animation:wl-flash-apk 1.5s ease-out 1}
@keyframes wl-flash-apk{0%{background:var(--wl-flash)}100%{background:var(--wl-current)}}
.wl-apk__row--folder .wl-apk__name{font-weight:600}
.wl-apk__caret{width:12px;flex:none;text-align:center;color:var(--cf-ink-soft);font-size:.7rem}
/* The row is a flex line with its own gap; the icon's inline margin would
   double it. */
.wl-apk__row .wl-ico{margin-right:0}
.wl-apk__name{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis}
.wl-apk__cur,.wl-apk__count{font-size:.68rem;color:var(--cf-ink-soft);flex:none}
.wl-apk__count{background:var(--cf-sunken);border-radius:8px;padding:0 .35rem}
.wl-apk__hit{background:var(--cf-warn-rule);color:inherit;padding:0;border-radius:2px}
.wl-apk__empty{padding:.6rem;font-size:.82rem;color:var(--cf-ink-soft)}
.wl-apk__foot{display:flex;gap:.75rem;padding:.25rem .6rem;border-top:1px solid var(--cf-sunken);
  font-size:.62rem;color:var(--cf-ink-soft);flex:none}

/* ---- "You are here" marker ----
   Two parts, and the second one is the part that was missing. A bright flash
   draws the eye to the row you came back to, then decays into a lasting tint
   that stays until another row is picked — so you can look away, answer the
   phone, and still find your place. The first port kept only the flash and
   faded it to transparent from 16% alpha: by the time you looked back there
   was nothing there, which is indistinguishable from nothing having
   happened.

   Painted as a full-bleed inset shadow rather than a background, because
   Bootstrap's own striping and hover states are `inset 0 0 0 9999px` too and
   would paint straight over a background. The shadow still sits behind the
   text, and neither part of this reflows the row.

   Blue, and never blue alone: a marked row also carries
   `aria-current="true"`, which is what actually says "this one" to a screen
   reader (invariant 11).

   This was amber, on the reasoning that SPEC 6.1's blue is about a *field* —
   "just changed remotely", a claim about the data rather than about where
   you are — and that reusing it here would blur the two. The reasoning
   stands and the result still lost: amber over a dark page reads as a
   warning, and a row you merely walked to should not look like a problem.
   The two blues do not in fact collide, because they speak on different
   channels: SPEC 6.1's is a field's own border, this is a full-row tint, and
   no element carries both.

   Themed rather than one colour for both. Amber was a single value for light
   and dark, which is most of why it looked wrong in one of them: the same
   alpha that reads as a gentle wash on white is a slab on #13181e. Each
   theme gets the blue it already uses elsewhere — Bootstrap's primary on
   light, the lifted `--cf-remote` tone on dark — at an alpha chosen against
   its own background. */
:root{--wl-flash:rgba(13,110,253,.42);--wl-current:rgba(13,110,253,.13);
  --wl-outline:rgba(13,110,253,.60)}
:root[data-bs-theme="dark"]{--wl-flash:rgba(110,160,255,.38);
  --wl-current:rgba(110,160,255,.17);--wl-outline:rgba(110,160,255,.55);
  --wl-outline-solid:#6ea0ff}
@keyframes wl-flash{0%{box-shadow:inset 0 0 0 9999px var(--wl-flash)}
  100%{box-shadow:inset 0 0 0 9999px var(--wl-current)}}
tr.wl-current>td,tr.wl-current>th{box-shadow:inset 0 0 0 9999px var(--wl-current)}
tr.wl-flash>td,tr.wl-flash>th{animation:wl-flash 1.5s ease-out 1}

/* A transaction card in the reports is the same marker on a shape that
   fights back in two ways, both of which legacy hit first:

   - its left border is already spoken for. That 3px edge is the lease
     colour — who holds this record — and a marker that reused it would be
     claiming something about other people rather than about the reader. So
     the card is outlined instead, which is a channel nothing else uses.
   - the split table inside paints opaque cell backgrounds, which cover the
     card's own background completely. Tint the cells with it, not just the
     card. */
.card.wl-current{outline:2px solid var(--wl-outline);outline-offset:-1px}
.card.wl-current,
.card.wl-current .table>:not(caption)>*>*{background-color:var(--wl-current)}
@keyframes wl-flash-card{0%{outline-color:var(--wl-outline-solid);outline-width:4px}
  100%{outline-color:var(--wl-outline);outline-width:2px}}
.card.wl-flash{animation:wl-flash-card 1.5s ease-out 1}

/* No animation, but the lasting tint and outline are already applied by
   `wl-current`, so the marker is still there — it just arrives without the
   sweep. */
@media (prefers-reduced-motion:reduce){
  tr.wl-flash>td,tr.wl-flash>th,.card.wl-flash{animation:none}}

/* ===================================================================
   WALLETS (ADR-0023)
   A shortfall episode is drawn as a rail down the rows it spans, with a
   word at each end — the rail is the shape of the gap, the words are what
   a reader who cannot see the rail gets instead (invariant #11).
=================================================================== */
.wl-inv{
  border:1px solid var(--cf-mine-rule);background:var(--cf-mine-bg);border-radius:9px;padding:10px 14px;
}
.wl-attn{
  border:1px solid var(--cf-warn-rule);background:var(--cf-warn-bg);border-radius:9px;padding:10px 12px;margin-bottom:8px;
}
.wl-num{font-family:var(--cf-mono);font-variant-numeric:tabular-nums}
.wl-num--neg{color:var(--cf-conflict);font-weight:600}

/* The section switcher: pills on the left, the one action that belongs to
   every section on the right. Wraps rather than scrolls on a phone. */
.wl-sec{display:flex;flex-wrap:wrap;justify-content:space-between;align-items:center;gap:8px}

/* The log's controls stay put while the log scrolls under them.
   A register is long by nature and the thing you most often want halfway down
   it is the wallet picker or the tag filter — which were at the top, a page
   and a half away. The background is the card's own, so rows disappear under
   it rather than showing through. */
.wl-log__bar{
  position:sticky;top:0;z-index:20;
  background:var(--cf-surface);
  padding-top:.5rem;
  margin-bottom:.5rem;
}
/* The list scrolls here rather than with the page, so the header above can
   fold away and come back without taking the reader's place with it. */
.wl-reg-scroll{overflow-y:auto;overscroll-behavior:contain}

/*
 * Folded: the totals and the nav give their height to the list.
 *
 * `grid-template-rows` from 1fr to 0 rather than `display:none`, because
 * this is meant to be seen moving — the row collapses and the content is
 * clipped by the wrapper, which animates where `height:auto` cannot.
 */
.wl-head-fold{display:grid;grid-template-rows:1fr}
/* An inner box with nothing of its own — no margin, no padding, no border.
   `overflow:hidden` on the CONTENT only clips the content, so a child's own
   margin, padding and border survive a fold to `0fr`: the first version left
   forty-nine pixels of them behind. This box has none to leave, and its
   `overflow` also stops the child's margin escaping through it. */
.wl-head-fold__in{overflow:hidden;min-height:0}
/* Animated only when a click asked for it. While it is tracking the list it
   must not lag behind, and a transition on every scroll frame is exactly
   that lag. */
.wl-head-fold--anim{transition:grid-template-rows .24s ease}
@media (prefers-reduced-motion:reduce){ .wl-head-fold--anim{transition:none} }

/* A wallet row is the way into that wallet's log, so it is a button. Reset
   what the UA gives a button and keep the card it already looked like; the
   indent lives on a wrapper, so this can be full width at any depth. */
.wl-wal{
  border:1px solid var(--cf-rule-soft);border-left:4px solid transparent;border-radius:9px;
  background:var(--cf-surface);padding:9px 12px;margin-bottom:8px;
}
/* The card and its edit button are siblings: a button inside a button is not
   valid HTML, and the card as a whole is the way into that wallet's log. */
.wl-wal-row{display:flex;align-items:center;gap:6px}
.wl-wal-row > .wl-wal{flex:1 1 auto;min-width:0}
.wl-wal__edit{
  flex:none;align-self:stretch;margin-bottom:8px;
  border:1px solid var(--cf-rule-soft);border-radius:9px;background:var(--cf-surface);
  padding:0 .6rem;color:var(--cf-ink-soft);cursor:pointer;line-height:1;
}
.wl-wal__edit:hover{border-color:var(--cf-system);background:var(--cf-raise);color:var(--cf-ink)}
/* Holds the space, shows nothing — see the comment at its only call site. */
.wl-wal__edit--placeholder{visibility:hidden;pointer-events:none}
button.wl-wal{display:block;width:100%;text-align:left;font:inherit;color:inherit;cursor:pointer}
button.wl-wal>span{width:100%}
button.wl-wal:hover{border-color:var(--cf-system);background:var(--cf-raise)}
.wl-wal--over{border-left-color:var(--cf-conflict);background:var(--cf-warn-bg)}
/* Listed after the hover rule and more specific, or hovering a wallet that is
   over would wash the one colour that says so straight off it. */
button.wl-wal--over:hover{background:var(--cf-warn-bg-strong)}
button.wl-wal--unassigned:hover{background:var(--cf-sunken)}
.wl-wal--unassigned{background:var(--cf-raise)}
.wl-wal__name{font-weight:600}
/* Takes the room the name does not. The charts want width and the name
   rarely does, and `min-width:0` is what lets this shrink rather than force
   the row wider than the card. */
.wl-wal__bal{flex:1 1 auto;min-width:0;max-width:640px}
/*
 * Two columns: the figure, then the chart.
 *
 * A grid rather than a flex row, and that is the whole fix for two separate
 * complaints. Flex put the chip wherever the chart's width left it, so a
 * wallet with a long name — which wraps, which changes what
 * `justify-content` has to work with — ended up with its chips aligned
 * differently from its neighbours. And the charts have to start at the SAME
 * x on every row or the shared time axis is a lie: one track of fixed width
 * does both, with the figures pushed up against its left edge.
 */
.wl-wal__ccy{
  display:grid;grid-template-columns:1fr var(--wl-spark-w);
  align-items:center;gap:10px;font-size:.88rem;padding:1px 0;
}
.wl-wal__ccy > .cf-cur-chip{justify-self:end}
.wl-wal__code{color:var(--cf-ink-soft);font-size:.78rem}

/* A wallet's balance over time, one chart per currency, beside its chip.
   The scrollbar is hidden on every one of them — fourteen down the side of a
   wallet list is noise, and they would disagree the moment one was dragged.
   The position is held in script and applied to all of them together. */
.wl-spark{
  width:100%;height:30px;overflow-x:auto;overflow-y:hidden;
  scrollbar-width:none;-ms-overflow-style:none;
  border-radius:4px;background:var(--wl-spark-bg);
}
.wl-spark::-webkit-scrollbar{display:none}
/* Says it can be dragged before anyone tries. `user-select:none` because a
   drag across a chart should scrub it, not select the page around it. */
.wl-spark{cursor:grab;user-select:none;-webkit-user-select:none}
.wl-spark.is-dragging{cursor:grabbing}
/* The only thing saying there is more history that way. Inset, so it is
   painted on the box rather than on the content, and it stays put while the
   chart moves under it. */
.wl-spark.is-more-left{box-shadow:inset 16px 0 12px -12px var(--wl-spark-edge)}
.wl-spark.is-more-right{box-shadow:inset -16px 0 12px -12px var(--wl-spark-edge)}
.wl-spark.is-more-left.is-more-right{
  box-shadow:inset 16px 0 12px -12px var(--wl-spark-edge),
             inset -16px 0 12px -12px var(--wl-spark-edge);
}
.wl-spark__svg{display:block}
/* The line is ink rather than a series colour: one series per chart, and the
   chip beside it already says which currency this is. */
:root{
  --wl-spark-up:#2e9e6b;
  --wl-spark-down:#dc5959;
  --wl-spark-zero:var(--cf-system);
  --wl-spark-under:rgba(220,89,89,.20);
  --wl-spark-bg:rgba(15,23,42,.035);
  --wl-spark-edge:rgba(15,23,42,.45);
  --wl-spark-w:360px;
}
:root[data-bs-theme="dark"]{
  --wl-spark-up:#57c98f;
  --wl-spark-down:#ff7a7a;
  --wl-spark-zero:var(--cf-pending);
  --wl-spark-under:rgba(255,122,122,.22);
  --wl-spark-bg:rgba(255,255,255,.04);
  --wl-spark-edge:rgba(255,255,255,.55);
}
.wl-spark__tip{
  position:fixed;z-index:1090;pointer-events:none;
  display:flex;align-items:center;gap:8px;
  padding:5px 9px;border-radius:8px;
  border:1px solid var(--cf-rule-soft);background:var(--cf-surface);
  box-shadow:0 8px 22px rgba(2,6,23,.22);font-size:.82rem;
}
.wl-spark__tipdate{color:var(--cf-ink-soft);font-variant-numeric:tabular-nums}

/* Below the width where a chart and a figure can share a line, the chart
   moves UNDER its chip rather than away. Both still belong to the currency
   the chip names, so they stay in the same box and stack; the chart takes
   the chip's width so the pair reads as one unit. */
@media (max-width:640px){
  /* One column, the chart under its chip: there is no room for a track wide
     enough to read beside a figure that cannot be abbreviated. */
  /* One column, and the chart takes all of it: stacked under the figure
     there is nothing beside it to leave room for, and a wider track is more
     history on screen. */
  .wl-wal__ccy{grid-template-columns:minmax(0,1fr);gap:2px}
  .wl-wal__ccy > .cf-cur-chip{justify-self:end}
  .wl-spark{width:100%;justify-self:stretch}
}

/* `clip` rather than `hidden`: both keep the tinted rows inside the rounded
   corners, but `hidden` makes this a scrollport, and a scrollport is what
   `position:sticky` measures against — the column header would have stuck to
   a box that never scrolls, which is to say not at all. */
.wl-reg{border:1px solid var(--cf-rule-soft);border-radius:8px;overflow:clip}
.wl-reg__head,.wl-reg__row{
  /* 172px, not 158: the ∑ mark inside a running chip wants about fourteen of
     them, and a track that is a hair too narrow does not wrap here, it
     overflows. */
  display:grid;grid-template-columns:88px minmax(0,1fr) 130px 172px;gap:8px;
  padding:5px 10px 5px 7px;align-items:baseline;
  /* Both edges reserved, so a row that gains a marker does not shift its
     contents by three pixels relative to the rows around it. */
  border-left:3px solid transparent;border-right:3px solid transparent;
}
/* `--all` no longer adds a column: a leg's wallet is notched into the leg's
   own chip rather than listed beside it (see `CurrencyChipOptions.notch`).
   The class stays because the register still uses it to decide what to put
   in that notch. */
/* A second running total appears only while a tag filter is on — with none,
   it would reproduce the column beside it exactly. The description keeps the
   `1fr`, so the extra column comes out of it rather than pushing the row wide
   enough to scroll. */
.wl-reg--tag .wl-reg__head,.wl-reg--tag .wl-reg__row{grid-template-columns:88px minmax(0,1fr) 130px 172px 172px}

/* The row's two sides are wrappers with no box of their own here: the six
   cells are direct members of this grid, in the order the columns want them.
   They become real containers only at phone width, where each side flows on
   its own — see the media query at the end of this block. */
.wl-reg__side{display:contents}
/* Pinned inside the list's own scroller: the list is the thing that scrolls
   now, so the labels have to stay with it rather than with the page. */
.wl-reg__head{position:sticky;top:0;z-index:5;
  background:var(--cf-raise);border-bottom:1px solid var(--cf-rule-soft);
  font-size:.7rem;letter-spacing:.06em;text-transform:uppercase;font-weight:700;color:var(--cf-ink-soft)}
.wl-reg__row{border-bottom:1px solid var(--cf-sunken);font-size:.87rem}
.wl-reg__row:last-child{border-bottom:0}
/* A shortfall is marked down the RIGHT edge, not by tinting the row.
   The tint was amber and so is the "you are here" marker, so a row you had
   just opened and a row the wallet was under on looked like the same kind of
   thing. They are not, and the marker is the one that must win — it answers
   "which one did I press", which is a question about the last half second.
   The edge is on the right, beside the running total that is the reason the
   row is marked at all. Not colour alone: that total already says "over"
   (invariant #11). */
.wl-reg__row--gap{border-right:3px solid var(--cf-danger)}
.wl-reg__row--cover{background:var(--cf-info-bg)}
.wl-reg__row--hl{outline:2px solid var(--cf-remote);outline-offset:-2px}
/* The word that says a running total is below zero — the rail and the red
   are the same fact twice over, and this is the one a reader who sees
   neither gets (invariant #11). */
/*
 * "over", as a mark to the RIGHT of the figure.
 *
 * It was a word on a line of its own, which on a narrow column spent a whole
 * row of the register on five letters. What it has to do is mark the figure,
 * and a mark sits beside it.
 *
 * The slot is reserved whether or not it is filled, so a column of running
 * totals stays a column: without that, the one row that is over pulls its
 * chip left of every other.
 *
 * Not colour alone — the glyph is a shape, the chip beside it carries a
 * minus sign, and the sentence is in `title` and the accessible name.
 */
.wl-reg__over{
  display:inline-block;width:1.05em;flex:none;
  margin-left:.3rem;font-size:.7rem;line-height:1;
  text-align:center;vertical-align:middle;cursor:help;
  /* A letter now, not "❗": `W` for the wallet or the book, `A` for the
     asset account. Bold and in the danger colour so it reads as a mark
     rather than as a stray initial, and small enough that two of them on one
     row — a wallet short AND an account empty — do not shout twice as loud
     as one problem deserves. */
  font-weight:800;color:var(--cf-danger);letter-spacing:0;
}
.wl-reg__over--none{cursor:auto}
/* The figure and its mark are one line. Without this they wrap — the column
   is barely wider than a long forint figure — and the mark lands back on a
   row of its own, which is the thing it was moved beside the figure to
   stop. The column was widened to make room for the slot it now reserves. */
.wl-reg__runline{display:inline-flex;align-items:center;white-space:nowrap}
/* A multi-split transaction's legs used to be separate rows inside a box.
   They are cells of one row now, stacked in the column they belong to, so
   the date and the description are said once and there is one thing to
   click. The box is gone with them. */
/* `minmax(0,1fr)` above, and this, are one fix.
   
   A bare `1fr` floors at the content's min-content width, and a bank's
   description is full of unbreakable tokens — "2026.05.09 8944850848
   SIMPLEP*PostaCsekk/O". Rows carrying one could not shrink that column, so
   the row grew wider than the list and every column to its right went with
   it: the running totals' right edge wandered by thirty pixels down the
   page, worst on the rows with the longest descriptions. `minmax(0,1fr)`
   lets the track shrink; this lets the word inside it break rather than
   setting the floor straight back where it was. */
.wl-reg__what{overflow-wrap:anywhere;min-width:0}

.wl-reg__stack{display:flex;flex-direction:column;align-items:flex-end;gap:2px}

/* Every leg's figure the same height, so a row's three numeric stacks stay
   level with each other.
   
   An amount chip and a running chip differ by whatever is notched into them
   — a wallet name on one, nothing on the other when the log is scoped to a
   single wallet — and without a floor the stacks drifted apart a few pixels
   per leg. At least the tallest chip's own height, or the chip wins and the
   drift comes back: 2.4rem against a natural 36.4px for a notched one.
   Wide layout only; at phone width each side is its own stack with nothing
   to line up against. */
@media (min-width:860px){
  .wl-reg__row{--wl-leg-h:2.4rem}
  .wl-reg__amt .cf-cur-chip,
  .wl-reg__run .cf-cur-chip,
  .wl-reg__tag .cf-cur-chip{min-height:var(--wl-leg-h)}
  /* A notched chip carries half a line of margin above it, so its box is
     that much shorter for the pair to come out level. */
  .wl-reg__amt .cf-cur-chip--notch,
  .wl-reg__run .cf-cur-chip--notch,
  .wl-reg__tag .cf-cur-chip--notch{min-height:calc(var(--wl-leg-h) - .31rem)}
}

/* The numeric cells align their contents to their own right edge, rather
   than leaving it to `text-align` on an inline box.
   
   `.wl-reg__runline` is `inline-flex` with `white-space:nowrap`, so it cannot
   be narrower than its content — and a grid track here is a fixed 158px. A
   running total too wide for the track therefore overflowed, and an inline
   box in a `text-align:right` cell overflows to the RIGHT: those rows pushed
   their chips 13px past every other row's, and the column's right edge went
   ragged exactly on the rows with the biggest numbers.
   
   It had been fitting by a hair until the ∑ mark was added inside the chip,
   which is what made it visible. As a flex container with `align-items`, the
   cell pins the right edge whatever the content does: a line that will not
   fit now runs off to the left, where the gap between columns absorbs it,
   and the edge the eye reads down stays straight.
   
   Multi-leg rows already got this from `.wl-reg__stack`, which is why they
   were the ones that looked right. */
.wl-reg__amt,.wl-reg__run,.wl-reg__tag{
  display:flex;flex-direction:column;align-items:flex-end;min-width:0;
}

.wl-reg__cap{
  font-size:.72rem;font-weight:700;color:var(--cf-conflict);
  text-transform:uppercase;letter-spacing:.04em;
}

/* A movement that stayed inside the wallets on screen: one row, an unsigned
   figure, and a running total that does not move because nothing did.
   The word beside the amount is the third channel — the muted chip and the
   unchanged total are the other two, and a reader may take neither
   (invariant #11). */
.wl-reg__moved{margin-left:.35rem;color:var(--cf-ink-soft)}
.cf-cur-chip--moved{opacity:.75}
/* The disclosure sits inside a row that is itself a button, so it needs to
   read as its own control: its own focus ring, its own hit area. */
.wl-reg__exp{
  border:0;background:none;padding:0 .3rem 0 0;margin:0;line-height:1;
  font-size:.8rem;color:var(--cf-ink-soft);cursor:pointer;
}
.wl-reg__exp:hover{color:var(--cf-ink)}
.wl-reg__exp:focus-visible{outline:2px solid var(--cf-remote);outline-offset:2px;border-radius:3px}
/* The legs of a collapsed row. A sibling of the row, not a child: the row is
   a grid of fixed columns and a panel inside one would take that column's
   width. Indented to the description column so it reads as belonging to the
   row above rather than as two more entries. */
.wl-reg__legs{
  padding:.2rem 10px .4rem 99px;border-bottom:1px solid var(--cf-sunken);
  background:var(--cf-raise);font-size:.82rem;
}
.wl-reg__leg{display:flex;gap:.6rem;align-items:baseline;padding:.1rem 0}
.wl-reg__leg > span:first-child{min-width:140px;color:var(--cf-ink-soft)}

/* What a debt on the Between-wallets page is made of, folded under its row.
   
   The page showed a net and nothing else, so there was no way to check it. A
   panel in a cell of its own spanning the table, for the same reason the
   register's legs are a sibling of their row: a full-width panel inside one
   column would be squeezed into that column's width. */
.wl-debt__holder{white-space:nowrap}
.wl-debt__holder > .wl-reg__exp{margin-right:.2rem}
.wl-debt__panelrow > td{background:transparent}
.wl-debt__panel{
  padding:.35rem .6rem .5rem 2.1rem;background:var(--cf-raise);
  border-bottom:1px solid var(--cf-sunken);font-size:.82rem;
}
.wl-debt__legend{margin:0 0 .3rem;color:var(--cf-ink-soft);font-size:.74rem}
.wl-debt__lines{list-style:none;margin:0;padding:0}
/* Date, what it was, then the two figures hard right — the arithmetic reads
   down the last column and lands on the figure in the row above. */
.wl-debt__line{
  display:grid;grid-template-columns:5.6rem minmax(0,1fr) 7rem 7rem;
  gap:.4rem;align-items:baseline;padding:.15rem 0;
}
.wl-debt__date{color:var(--cf-ink-soft);font-variant-numeric:tabular-nums}
/* A button, because it opens the entry — styled as the text it sits in, so
   the row does not read as a toolbar. */
.wl-debt__what{
  border:0;background:transparent;padding:0;text-align:left;cursor:pointer;
  color:inherit;min-width:0;display:block;
}
.wl-debt__what:hover .wl-debt__descr{text-decoration:underline}
.wl-debt__what:focus-visible{outline:2px solid var(--cf-remote);outline-offset:2px;border-radius:3px}
.wl-debt__descr{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.wl-debt__kind{display:block;color:var(--cf-ink-soft);font-size:.74rem}
.wl-debt__eff,.wl-debt__run{text-align:right;font-variant-numeric:tabular-nums}
.wl-debt__eff{color:var(--cf-ink-soft)}
/* Below the width where four columns fit, the two figures keep their own line
   rather than squeezing the description to nothing. */
@media (max-width:639px){
  .wl-debt__line{grid-template-columns:5.6rem minmax(0,1fr);row-gap:0}
  .wl-debt__eff{grid-column:1;text-align:left}
  .wl-debt__run{grid-column:2}
  .wl-debt__panel{padding-left:1rem}
}

/* The marker on a register row — the same "you are here" as the chart of
   accounts and the reports (`markCurrentRow`), on a third shape.
   Background rather than the inset shadow a table row uses, because here that
   channel already belongs to the lease rail below: a row can be the one you
   last opened AND be open in somebody else's editor, and neither fact may
   erase the other. `aria-current` comes with the marker and is what says
   "this one" without colour (invariant #11). */
.wl-reg__row.wl-current{background:var(--wl-current)}
@keyframes wl-flash-reg{0%{background:var(--wl-flash)}100%{background:var(--wl-current)}}
.wl-reg__row.wl-flash{animation:wl-flash-reg 1.5s ease-out 1}
@media (prefers-reduced-motion:reduce){.wl-reg__row.wl-flash{animation:none}}

/* The register on a narrow screen. Five fixed columns cannot be squeezed into
   375px — they overflow sideways, and a ledger you have to scroll horizontally
   to read the amount of is not readable at all. So the same five cells lay
   themselves out in three lines, the header goes (it would be labelling
   columns that no longer exist), and the running total carries its own label
   instead — that is the number whose meaning is not self-evident. */
/* Stacked below 860, not below 640.
   
   At 641 the six-column grid gave the description SIX pixels. With the
   wallet column already dropped above, the worst case left is a tagged log:
   88 + 130 + 172 + 172 of fixed track plus gaps and chrome is 620, so the
   description is `container - 620` and needs 820 of container — about 860 of
   viewport — before it is worth calling a column. Below that the row stacks,
   which has no such floor. */
@media (max-width:859px){
  .wl-reg__head{display:none}
  /* With the head gone the first row is against the container's top edge, and
     the state chip sits half above its row — `.wl-reg` clips to its rounded
     corners, so without this the first row's chip would be cut in half. */
  .wl-reg{padding-top:9px}
  /* Two columns that flow INDEPENDENTLY, which is the whole point of the
     wrappers becoming real here.

     One grid with shared rows cannot do this. A cell holding two stacked
     currency chips makes its row as tall as itself, and whatever sits beside
     it is pushed down by the difference — so a conversion showed its date,
     then a blank gap, then its description, and read as two entries rather
     than one. Each side keeps its own rhythm instead: date, description and
     wallet follow each other immediately, and the chips live their own life
     beside them.

     The date leads, as it does at every other width and in the header this
     layout replaces. */
  /* Every wide-screen variant is named, not just the plain row. A media
     query adds no specificity, so `.wl-reg--all.wl-reg--tag .wl-reg__row`
     above — three classes — would otherwise keep its six columns here and
     lay two children out across them. It did, and the result was chips
     printed over the date. */
  .wl-reg__row,
  .wl-reg--all .wl-reg__row,
  .wl-reg--tag .wl-reg__row,
  .wl-reg--all.wl-reg--tag .wl-reg__row{
    grid-template-columns:minmax(0,1fr) auto;
    align-items:start;
    row-gap:0;column-gap:10px;padding:7px 10px 7px 7px;
  }
  .wl-reg__side{display:flex;flex-direction:column;min-width:0;gap:1px}
  /* An amount cannot be wrapped or abbreviated — flag, code and every digit
     of "-3,122,401.10" are one unbreakable run — so the numbers take the
     width they need and the description takes what is left. */
  .wl-reg__side--nums{align-items:flex-end;flex:0 0 auto}
  /* The legs indent to the description column on a wide screen; at phone
     width there is no such column, so they take the row's own padding. */
  .wl-reg__legs{padding-left:14px}
  /* A gap above the tag total, so the "over" word that follows the wallet's
     number reads as belonging to it rather than to the number underneath.
     Stacked and right-aligned, the two are otherwise one column of text with
     a label loose in the middle of it. */
  .wl-reg__tag{margin-top:.3rem}
  /* Above the number, not beside it. A currency chip cannot wrap — flag,
     code and every digit of "-3,122,401.10" are one unbreakable run — so an
     inline label is 56px permanently taken out of the date's column. */
  /* Beside the number it is another unbreakable 28px in the widest column. */
  /* Beside the figure at every width now — it is a mark, not a line. */
  .wl-reg__over{margin-left:.3rem}
  /* No word above the tag total any more: its chip says "∑ tag" in its own
     notch, which is the same thing one line shorter and in the place the
     figure already is. */
  /* The empty shortfall slot reserves width so that a row which gains the
     mark does not pull its chip out of the column — right, where the rows
     share a column. Here each row is its own stack, so the reserved width
     pushed the running chip ~18px left of the amount chip directly above it,
     and the two numbers in one entry no longer lined up. Reported as exactly
     that: "currency chips are not right aligned anymore". */
  .wl-reg__over--none{display:none}
  /* The wallet column goes; each leg's wallet rides beside its own figure
     instead — see `legWallet`. At this width the column was a list in one
     part of the row and the figures a list in another. */

  /* And the real one moves to the other side of the figure.
     
     Stacked like this, the amount and the running total are one column to
     the eye, so every chip has to end on the same pixel — and a mark after
     the chip pushes exactly the rows that have one 18px off that line. To
     the left of the figure there is nothing but space. `row-reverse` with
     the default packing keeps the chip against the right edge and puts the
     mark before it; the DOM order is unchanged, so what a screen reader
     reads is unchanged too. */
  .wl-reg__runline{flex-direction:row-reverse}
  .wl-reg__over{margin-left:0;margin-right:.3rem}
}

/* The mark that leads a running total: ∑ for one wallet, ∑∑ for the whole
   book. See `runningMark`. Muted and a shade smaller than the figure — it
   says which total this is, it is not part of the number, and the sentence
   it stands for is the cell's accessible name and the caption above the
   list (invariant #11: never the glyph alone). */
/* Outside a chip, for prose that refers to the mark — the line under the
   wallet selector that says what the running column counts. */
.wl-reg__sum{color:var(--cf-ink-soft);font-size:.9em;letter-spacing:.02em;margin-right:.3rem;flex:0 0 auto}

/* `background` stated rather than inherited from the UA's dialog styling: the
   quick-entry one is a plain <div> inside a transparent shell so that it can
   be dragged, and a <div> gets no such default — it rendered see-through. */
/* The short form. 560px is what its fields want — Bootstrap's own modal-lg
   is 800 and made it 240 wider than it had ever been. */
.wl-modal--quick{max-width:560px}
.wl-dlg{
  border:1px solid var(--cf-rule-soft);border-radius:10px;padding:18px;max-width:440px;width:92vw;
  background:var(--cf-surface);color:var(--cf-ink);
}
.wl-dlg::backdrop{background:rgba(27,36,48,.35)}
/* A question, not a form: narrower than the wallet dialogs because it holds
   two lines and two buttons, and a 440px panel around them reads as though
   something is missing. Every one of these is asked from inside a modal, so
   its backdrop goes darker than `.wl-dlg`'s — a second scrim over a page
   that already has one has to be visible as a second one. */
.wl-confirm{max-width:380px}
.wl-confirm::backdrop{background:rgba(15,23,42,.45)}
/* While a modal dialog is open the page behind must not scroll. `showModal()`
   makes the rest of the document inert to CLICKS, but a wheel still scrolls
   it — so reaching for something in the dialog moved the page underneath
   instead. The dialog keeps its own scrolling below, or a form taller than
   the window would become unreachable the moment the page stopped moving. */
body:has(dialog[open]){overflow:hidden}


/* Who is in a wallet-register row right now.
   The left BORDER already belongs to the shortfall rail, so this uses an
   inset shadow: a row can be both part of a gap and open in somebody's
   editor, and neither fact should erase the other. The chip beside the
   description carries the name and glyph — this is the peripheral cue,
   never the only one (invariant #11). */
.wl-reg__row{position:relative}
.wl-reg__row.is-open{box-shadow:inset 4px 0 0 var(--row-color,var(--cf-remote))}
.wl-reg__row.wl-tx-held{box-shadow:inset 4px 0 0 var(--cf-conflict)}
.wl-reg__row.wl-tx-pending{box-shadow:inset 4px 0 0 var(--cf-pending)}
/* Notched into the row's top border, exactly as on a register row and a
   report card (`.wl-tx-list`, `.wl-tx-card`): an opaque chip cutting the line
   it sits on. It was inline in the description before, which made it read as
   part of the text rather than as something about the record, and pushed the
   description sideways whenever somebody opened a row. Out of flow, it does
   neither. */
.wl-reg__row > * > [data-state-slot],
.wl-reg__row > [data-state-slot]{position:absolute;left:.45rem;top:0;transform:translateY(-50%);z-index:1}
.wl-reg__row [data-state-slot] .wl-state-chip{position:static;transform:none}

/* Quick entry: the short form on the wallets page. The preview shows BOTH
   legs on purpose — the category leg carries no wallet, and that is easier
   to believe when you can see it. */
.wl-q-preview{border:1px solid var(--cf-rule-soft);border-radius:8px;padding:8px 10px;background:var(--cf-raise)}
.wl-q-leg{display:grid;grid-template-columns:1fr 130px 150px;gap:8px;align-items:baseline;
  padding:2px 0;border-bottom:1px dotted var(--cf-sunken);font-size:.88rem}
.wl-q-leg:last-of-type{border-bottom:0}

/*
 * Budgets (ADR-0024).
 *
 * The bar is decoration for a fact that is already written out beside it in
 * words: "1,200,000 HUF of 5,000,000 HUF" and "3,800,000 HUF left — 24% used"
 * are both on the card whatever the fill looks like, and the track carries
 * role="img" with the same sentence as its label. Invariant #11 is not
 * satisfied by picking an accessible pair of colours; it is satisfied by the
 * colour being redundant.
 *
 * Over runs the same amber as a wallet shortfall (`--cf-conflict`) rather
 * than a new red, because it is the same news — this envelope is beyond what
 * was meant for it — and a second alarm colour for one more shade of the same
 * meaning is how a palette stops meaning anything.
 */
.wl-bud{
  border:1px solid var(--cf-rule-soft);border-left:4px solid transparent;border-radius:9px;
  background:var(--cf-surface);padding:10px 12px;margin-bottom:8px;
}
.wl-bud__head{display:flex;flex-wrap:wrap;align-items:start;justify-content:space-between;gap:8px}
.wl-bud__who{min-width:0}
.wl-bud__name{font-weight:600}
.wl-bud__where,.wl-bud__when{color:var(--cf-ink-soft);font-size:.82rem;margin-left:.45rem}
.wl-bud__acts{display:flex;align-items:center;gap:6px;flex:none}
/* Same pencil as a wallet row, so "change this" looks like itself everywhere. */
.wl-bud__acts .wl-wal__edit{align-self:auto;margin-bottom:0;padding:.25rem .6rem}
.wl-bud__bar{margin:.55rem 0 .35rem}
.wl-bud__track{
  display:block;height:9px;border-radius:5px;background:var(--cf-sunken);overflow:hidden;
}
.wl-bud__fill{display:block;height:100%;background:var(--cf-mine);border-radius:5px}
.wl-bud__figures{display:flex;flex-wrap:wrap;justify-content:space-between;gap:8px;font-size:.87rem}
.wl-bud__spent{font-variant-numeric:tabular-nums}
.wl-bud__left{color:var(--cf-ink-soft)}
.wl-bud__note{margin:.4rem 0 0;font-size:.85rem;color:var(--cf-ink-soft);font-style:italic}
/* The admissions under a budget: what it could not count, and what it shares
   with another. Small, but never hidden behind anything — a figure whose
   caveats are a click away is a figure that gets quoted without them. */
.wl-bud__caveats{margin:.45rem 0 0;padding-left:1.1rem;font-size:.82rem;color:var(--cf-ink-soft)}
.wl-bud__caveats li{margin-top:.15rem}

.wl-bud--near{border-left-color:var(--cf-pending)}
.wl-bud--near .wl-bud__fill{background:var(--cf-pending)}
.wl-bud--over{border-left-color:var(--cf-conflict);background:var(--cf-warn-bg)}
.wl-bud--over .wl-bud__fill{background:var(--cf-conflict)}
.wl-bud--over .wl-bud__left{color:var(--cf-conflict);font-weight:600}

/* An attachment whose file is not reachable from this device (ADR-0025): the
   thumbnail is here, the bytes are not. Muted rather than hidden, and never
   `disabled` — the name, size and picture stay readable and selectable, and
   the tile's own title says what is missing. */
.wl-att__link--offline{cursor:default;opacity:.72}
.wl-att__link--offline:hover{opacity:.85}

/*
 * On a touch screen a currency chip is a gesture target: tap adds it to the
 * tally, long-press subtracts (see webledgerChipTally). Two things have to be
 * suppressed for that to feel like a control rather than a fight with the OS —
 * the text-selection callout that a long press otherwise raises, and the
 * highlight flash on tap.
 *
 * Scoped to `(hover: none)` so a mouse keeps everything: there, a chip is
 * ordinary selectable text and the tally is on Cmd-click.
 */
@media (hover: none) {
  .cf-cur-chip[data-cur]{
    -webkit-touch-callout:none;
    -webkit-user-select:none;
    user-select:none;
    -webkit-tap-highlight-color:transparent;
  }
}

/*
 * A whole row is the target, not just the words in it.
 *
 * `cursor: pointer` is declared on the row ITSELF rather than left to
 * inherit, because iOS Safari decides whether to synthesise a click from a
 * tap by asking whether the thing under the finger looks clickable — and an
 * inherited cursor does not count. Without it a tap that misses the
 * description does nothing but leave the row highlighted, which is exactly
 * how this was reported.
 */
.wl-tx-list tbody tr[data-open-row]{cursor:pointer}
.wl-reg__row{cursor:pointer}
/* The description keeps looking like the control it is; the row around it
   just stops being dead space. */
.wl-tx-list tbody tr[data-open-row]:hover{background:var(--cf-raise)}

/*
 * The app shell uses every pixel it is given, up to a reading maximum.
 *
 * Bootstrap's `.container` steps between fixed widths — 540, 720, 960, 1140,
 * 1320 — which suits a page of prose and not a ledger. At 812px, which is a
 * phone turned on its side, it pins to 720 and leaves 92px of the screen
 * empty: the reported "landscape does not use the full width". The steps do
 * the same thing at every size between two breakpoints.
 *
 * So: fluid, with a cap where the widest step was. Nothing changes at 1320
 * and above; everything below it gains the width it was throwing away.
 * `!important` because Bootstrap sets its own `max-width` per breakpoint at a
 * higher specificity than a single class can reach.
 */
.cf-shell{width:100%;max-width:1320px!important;margin-inline:auto}

/* ===================================================================
   GLASS lives LAST, and that is load-bearing
===================================================================
   Every rule below restates a `background` that an earlier section already
   set, at the same specificity — `.cf-cur-chip`, `.wl-dlg` and the rest are
   all one class. Order is therefore the only thing deciding the winner, and
   while this block sat above the currency-chip section the chip's own opaque
   fill won every time: the rim and the blur applied, the translucency never
   did, and the fill percentage was a knob connected to nothing.
=================================================================== */
/* ===================================================================
   GLASS — only on things that FLOAT over content
=================================================================== */
/*
 * Translucency reads as depth, and depth is a claim: "this is in front of
 * that". It is true of a dialog, a popover and a dropdown, and it is false
 * of a table row. So the blur is scoped to the floating surfaces by name
 * rather than offered as a utility class somebody will put on the register.
 *
 * It is kept OFF the ledger deliberately. Text over a blurred background
 * costs legibility, and this is an app where misreading a digit is the
 * failure mode; `backdrop-filter` is also expensive per painted pixel, and
 * a wallet log is a tall scrolling surface that would pay it on every frame.
 *
 * `@supports`, because without the blur a translucent panel is just a panel
 * you can read the page through. Browsers that cannot do it keep the solid
 * background they already had.
 */
@supports ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  @media (prefers-reduced-transparency:no-preference){
    .wl-head__menu,
    .wl-bi,
    .cf-popover,
    .wl-dlg,
    .wl-modal--quick .modal-content{
      /* `color-mix` keeps one declaration for both themes: the surface token
         already differs, so the glass is a tint of whatever is underneath
         rather than a second palette to maintain. */
      background:color-mix(in srgb, var(--cf-surface) 82%, transparent);
      -webkit-backdrop-filter:blur(14px) saturate(1.4);
      backdrop-filter:blur(14px) saturate(1.4);
    }

    /*
     * The fields inside a form, and the currency chips.
     *
     * Asked for after the first pass deliberately left them out, and taken
     * further than I would have alone — so the numbers get the cautious
     * version. A chip is barely translucent (92%) and its blur is small:
     * enough to pick up the surface under it, not enough to let anything
     * through that competes with a digit. The ledger's own ROWS are still
     * untouched; this is the chip, which is a small plate that sits ON a row.
     */
    .wl-nf__ctl,
    .form-control,
    .form-select{
      background-color:color-mix(in srgb, var(--cf-surface) 70%, transparent);
      -webkit-backdrop-filter:blur(8px);
      backdrop-filter:blur(8px);
    }
    /*
     * The chip as a lens, which is what "liquid glass" actually is: the fill
     * barely tints, and the EDGE does the work — a bright rim where light
     * would catch the lip and a dim one where it would not, so the pill
     * reads as something with thickness sitting on the page rather than a
     * painted rectangle.
     *
     * The rim is a gradient, and a gradient cannot be a `border-color`. The
     * ring is a padding-box cut out of a full-size gradient with
     * `mask-composite`, on `::after` — `::before` already carries the + and
     * the − of the chip tally.
     */
    .cf-cur-chip{
      position:relative;
      border-color:transparent;
      background-color:color-mix(in srgb, var(--cf-chip-tint) var(--cf-chip-fill), transparent);
      -webkit-backdrop-filter:blur(var(--cf-glass-blur)) saturate(var(--cf-glass-saturate));
      backdrop-filter:blur(var(--cf-glass-blur)) saturate(var(--cf-glass-saturate));
      box-shadow:inset 0 1px 0 var(--cf-rim-sheen);
    }
    .cf-cur-chip:not(.cf-cur-chip--notch)::after{
      content:'';position:absolute;inset:0;border-radius:inherit;
      padding:var(--cf-rim-width);pointer-events:none;
      background:linear-gradient(135deg,
        var(--cf-rim-hi) 0%, var(--cf-rim-lo) 36%,
        var(--cf-rim-lo) 64%, var(--cf-rim-hi) 100%);
      -webkit-mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      -webkit-mask-composite:xor;
      mask:linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
      mask-composite:exclude;
    }
    /*
     * A notched chip cuts its own ring, because the gap has to be cut out of
     * the same mask — so it takes the paint and the width from here and
     * nothing else. Excluded from the rule above rather than restating after
     * it: the two selectors have the same specificity, and a `:not()` says
     * which chips are meant instead of leaving it to source order.
     */
    .cf-cur-chip--notch{
      --cf-chip-rim:linear-gradient(135deg,
        var(--cf-rim-hi) 0%, var(--cf-rim-lo) 36%,
        var(--cf-rim-lo) 64%, var(--cf-rim-hi) 100%);
      --cf-chip-rim-width:var(--cf-rim-width);
    }
    /* Out of scope counts towards nothing, so it should not catch light either. */
    .cf-cur-chip.is-muted::after{opacity:.35}

    /* The same lip on the surfaces that float, so the two read as one idea. */
    .wl-head__menu,.wl-bi,.cf-popover,.wl-dlg,.wl-modal--quick .modal-content{
      border:1px solid transparent;
      box-shadow:inset 0 1px 0 var(--cf-rim-sheen),0 10px 30px rgba(2,6,23,.22);
    }

    /*
     * And these four actually REFRACT what is behind them.
     *
     * A displacement map bends the backdrop instead of only softening it,
     * which is the difference between glass and frosting. It is here and
     * not on the chips for two measured reasons: a chip sits on a flat
     * card, where displacing a flat colour returns the same flat colour —
     * applied to all of them the page came back indistinguishable — and one
     * wallet log holds 610 chips against the three or four of these that
     * are ever on screen at once.
     *
     * Its own `@supports`, nested inside the one above, so a browser that
     * takes `backdrop-filter` but not a filter reference keeps the plain
     * blur rather than dropping the declaration and the panel's background
     * with it.
     */
    @supports (backdrop-filter:url("#cfGlassLens")) or (-webkit-backdrop-filter:url("#cfGlassLens")){
      .wl-head__menu,.wl-bi,.cf-popover,.wl-dlg,.wl-modal--quick .modal-content{
        -webkit-backdrop-filter:blur(14px) saturate(1.4) url(#cfGlassLens);
        backdrop-filter:blur(14px) saturate(1.4) url(#cfGlassLens);
        /* Denser than the plain-blur version, to put back the opacity the
           displacement takes out at the edges. A panel you type into has to
           stay a panel. */
        background:color-mix(in srgb, var(--cf-surface) 92%, transparent);
      }
    }
  }
}

/* "in EUR" beside the register's Running heading — a qualifier on the column,
   not a second heading, so it carries the currency without competing with the
   word it modifies. */
.wl-reg__inccy{font-weight:400;opacity:.7;white-space:nowrap}
