/* =============================================================================
   ANONPAY design system
   -----------------------------------------------------------------------------
   The single stylesheet every page of the home app loads. Page stylesheets
   (dashboard.css, authenticate.css) compose these primitives and add layout;
   they define no colours, no type sizes and no spacing of their own.

   Three rules this file exists to enforce, because breaking them is what made
   the old dashboard look unstyled:

     1. NOTHING is spaced by a literal space between inline elements. Every
        horizontal cluster is .row or .meta and takes a gap token. If two things
        sit side by side, a token says how far apart.
     2. Separators are hairlines, never glyphs. No middots, no pipes, no slashes.
     3. Every component owns its padding and its alignment. A component is never
        positioned by whatever happens to be around it.

   Palette is black, greys and white plus the three status colours already in
   the product. Nothing else.
   ========================================================================== */


/* =============================================================================
   1. TOKENS
   ========================================================================== */
:root{
    /* --- surfaces: four steps, darkest to lightest ----------------------- */
    --bg:        #0B0B0C;   /* the page */
    --panel:     #141416;   /* a panel on the page */
    --panel2:    #1B1B1E;   /* nested surface, input, row hover */
    --panel3:    #232327;   /* active chip, pressed control */

    /* --- lines ----------------------------------------------------------- */
    --line:      #232327;   /* hairline between rows inside a panel */
    --line2:     #313137;   /* panel border, input border, inline divider */
    --line3:     #43434C;   /* hover border */

    /* --- text: three steps ----------------------------------------------- */
    --txt:       #FAFAFA;
    --txt2:      #9A9AA2;   /* secondary: converted values, timestamps, help */
    --txt3:      #65656E;   /* tertiary: column labels, captions, disabled */

    /* --- status: the three already defined in the product, unchanged ------
       Used for status only, never decoration, and always with a word beside
       them so meaning survives greyscale and colour blindness. */
    --green:     #00D000;
    --red:       #D00000;
    --blue:      #34BBB9;
    --green-bg:  rgba(0,208,0,.13);
    --red-bg:    rgba(208,0,0,.14);
    --blue-bg:   rgba(52,187,185,.14);
    --flat-bg:   rgba(255,255,255,.07);   /* neutral badge */

    /* --- spacing: 4px grid ------------------------------------------------ */
    --s1: 4px;  --s2: 8px;  --s3: 12px; --s4: 16px;
    --s5: 24px; --s6: 32px; --s7: 48px; --s8: 64px;

    /* --- type ------------------------------------------------------------
       Paired size/line-height. Weights are only ever 300/400/500/700/900,
       because those are the faces that exist; 600 and 800 were being
       synthesised. */
    --f1: 11px; --l1: 1.45;   /* column label, caps, tracked */
    --f2: 12px; --l2: 1.5;    /* micro text, identifiers */
    --f3: 13px; --l3: 1.55;   /* secondary, help, timestamps */
    --f4: 14px; --l4: 1.5;    /* body, table cell, input, nav */
    --f5: 16px; --l5: 1.4;    /* panel title, lead */
    --f6: 20px; --l6: 1.3;    /* section hero */
    --f7: 28px; --l7: 1.15;   /* stat value */
    --f8: 40px; --l8: 1.05;   /* page hero */
    --track: .08em;           /* letter-spacing for caps labels */
    --tight: -.02em;          /* letter-spacing for large numerals */
    --mono: ui-monospace, 'SF Mono', Menlo, Consolas, 'Liberation Mono', monospace;

    /* --- shape ------------------------------------------------------------ */
    --r1: 6px;    /* controls */
    --r2: 10px;   /* panels, cards */
    --r3: 14px;   /* large containers */
    --rf: 999px;  /* pills, avatars, switches */

    /* --- motion ------------------------------------------------------------ */
    --fast: .12s ease;
    --slow: .2s ease;
}

@media (prefers-reduced-motion: reduce){
    :root{ --fast: 0s; --slow: 0s; }
    *, *::before, *::after{ animation-duration: .01ms !important; animation-iteration-count: 1 !important; }
}


/* =============================================================================
   2. RESET AND BASE
   ========================================================================== */
*, *::before, *::after{
    margin: 0;
    padding: 0;
    box-sizing: border-box;
}
html{ -webkit-text-size-adjust: 100%; }
body{
    background: var(--bg);
    color: var(--txt);
    font: 400 var(--f4)/var(--l4) Roboto, Arial, sans-serif;
    -webkit-font-smoothing: antialiased;
    text-rendering: optimizeLegibility;
}
a{ color: inherit; text-decoration: none; }
img, svg{ max-width: 100%; display: block; }
button, input, select, textarea{ font: inherit; color: inherit; }
button{ background: none; border: none; cursor: pointer; }
ul, ol{ list-style: none; }
table{ border-collapse: collapse; width: 100%; }

/* One focus ring for the whole app. Defined here, before the components that
   set `outline: none`, and re-asserted at the end of this file so source order
   cannot beat it - :focus-visible is a pseudo-class and ties with .btn on
   specificity. */
:focus-visible{
    outline: 2px solid var(--blue);
    outline-offset: 2px;
    border-radius: var(--r1);
}


/* =============================================================================
   3. TYPOGRAPHY
   ========================================================================== */
h1{ font-size: var(--f8); line-height: var(--l8); font-weight: 500; letter-spacing: var(--tight); }
h2{ font-size: var(--f6); line-height: var(--l6); font-weight: 500; }
h3{ font-size: var(--f5); line-height: var(--l5); font-weight: 500; }
h4{ font-size: var(--f4); line-height: var(--l4); font-weight: 500; }

/* The uppercase micro-label above a value or over a column. */
.lbl{
    font-size: var(--f1);
    line-height: var(--l1);
    font-weight: 500;
    letter-spacing: var(--track);
    text-transform: uppercase;
    color: var(--txt3);
}
.sec{ font-size: var(--f3); line-height: var(--l3); color: var(--txt2); }
.cap{ font-size: var(--f2); line-height: var(--l2); color: var(--txt3); }

/* Identifiers are read character by character, so they are monospace, and they
   never widen their container. */
.mono{
    font-family: var(--mono);
    font-size: var(--f2);
    color: var(--txt3);
    /* A 32-character identifier has no break opportunity, so without this it
       pushes its container wider than the viewport instead of wrapping.
       Columns still truncate instead - see .lst .uid. */
    overflow-wrap: anywhere;
}
/* Every figure on a page about money. Without this a column of amounts
   jitters, because the default proportional digits are different widths. */
.num{ font-variant-numeric: tabular-nums; font-feature-settings: "tnum"; }

.trunc{ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
.nowrap{ white-space: nowrap; }
.dim{ color: var(--txt2); }
.dim2{ color: var(--txt3); }
.ok-t{ color: var(--green); }
.no-t{ color: var(--red); }
.go-t{ color: var(--blue); }


/* =============================================================================
   4. LAYOUT PRIMITIVES
   These exist so a gap is never forgotten: if two things sit next to each
   other they are inside one of these, and the gap comes from a token.
   ========================================================================== */

/* Horizontal cluster. `.row` alone centres on the cross axis, which is what is
   wanted nine times in ten (an icon beside text, a badge beside a label). */
/* Gap overrides work on any flex or grid container, not only .row, so a
   component that arranges itself still spaces itself from the same scale. */
.g1{ gap: var(--s1); } .g2{ gap: var(--s2); } .g3{ gap: var(--s3); }
.g4{ gap: var(--s4); } .g5{ gap: var(--s5); } .g6{ gap: var(--s6); }

.row{ display: flex; align-items: center; gap: var(--s3); min-width: 0; }
.row.top{ align-items: flex-start; }
.row.base{ align-items: baseline; }
.row.wrap{ flex-wrap: wrap; }
.row.between{ justify-content: space-between; }
.row.end{ justify-content: flex-end; }
.row.centre{ justify-content: center; }
/* Pushes everything after it to the far end. One class instead of a margin. */
.push{ margin-left: auto; }

/* Vertical cluster. Replaces margin-bottom on children, so the last child
   never leaves a dangling gap. */
.stack{ display: flex; flex-direction: column; gap: var(--s3); min-width: 0; }

/* Responsive card grid. One rule covers every "cards that reflow" surface. */
/* min(..., 100%) matters: a bare minmax(260px, 1fr) cannot shrink below its
   floor, so on a narrower container the track overflows instead of reflowing. */
.grid{ display: grid; gap: var(--s4);
       grid-template-columns: repeat(auto-fill, minmax(min(var(--min, 260px), 100%), 1fr)); }
.grid.fit{ grid-template-columns: repeat(auto-fit, minmax(min(var(--min, 260px), 100%), 1fr)); }
.grid.sm{ --min: 180px; } .grid.md{ --min: 220px; } .grid.lg{ --min: 320px; }

/* Self-alignment, so a child never needs an inline style to opt out of what its
   container aligns it to. */
.self-start{ align-self: flex-start; }
.self-end{ align-self: flex-end; }
.self-stretch{ align-self: stretch; }
.grow{ flex: 1; min-width: 0; }

/* A line of metadata. THE REPLACEMENT FOR MIDDOT SEPARATORS: items are spaced
   by a gap, and where a visual break is genuinely needed `.meta.div` draws a
   hairline. A separator is a rule, not a character. */
.meta{
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--s1) var(--s3);
    font-size: var(--f3);
    line-height: var(--l3);
    color: var(--txt2);
    min-width: 0;
}
.meta.div > * + *{
    padding-left: var(--s3);
    border-left: 1px solid var(--line2);
}

/* Horizontal rule inside a panel. */
.hr{ height: 1px; background: var(--line); border: none; }


/* =============================================================================
   5. PANEL — the only surface. Everything on a page sits in one.
   ========================================================================== */
.p{
    background: var(--panel);
    border: 1px solid var(--line2);
    border-radius: var(--r2);
    min-width: 0;
}
.p > header{
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s4) var(--s5);
    border-bottom: 1px solid var(--line);
    min-height: 60px;
}
/* The title takes the slack, so meta and the action land at the right edge
   without anyone writing a margin. */
.p > header > h3{ margin-right: auto; }
.p > .body{ padding: var(--s5); }
.p > footer{
    display: flex;
    align-items: center;
    gap: var(--s3);
    padding: var(--s3) var(--s5);
    border-top: 1px solid var(--line);
}
/* A panel that is only a header, for a bare action bar. */
.p.flush > header{ border-bottom: none; }


/* =============================================================================
   6. BUTTONS
   ========================================================================== */
.btn{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--s2);
    height: 38px;
    padding: 0 var(--s4);
    border: 1px solid var(--line2);
    border-radius: var(--r1);
    background: var(--panel2);
    color: var(--txt);
    font-size: var(--f4);
    font-weight: 500;
    white-space: nowrap;
    cursor: pointer;
    transition: background var(--fast), border-color var(--fast), color var(--fast);
}
.btn:hover{ background: var(--panel3); border-color: var(--line3); }
.btn:active{ background: var(--panel3); }
.btn img{ width: 16px; opacity: .8; }

/* One primary per panel. */
.btn.pri{ background: var(--txt); border-color: var(--txt); color: #000; }
.btn.pri:hover{ background: #DCDCDC; border-color: #DCDCDC; }
.btn.pri img{ opacity: 1; filter: invert(1); }

.btn.qui{ background: transparent; border-color: transparent; color: var(--txt2); }
.btn.qui:hover{ background: var(--panel2); color: var(--txt); }

/* Outlined, never filled: a filled red beside a filled white button is a coin
   flip for someone moving fast. */
.btn.dgr{ background: transparent; border-color: rgba(208,0,0,.4); color: var(--red); }
.btn.dgr:hover{ background: var(--red-bg); border-color: var(--red); }

.btn.sm{ height: 30px; padding: 0 var(--s3); font-size: var(--f3); }
.btn.lg{ height: 44px; padding: 0 var(--s5); font-size: var(--f5); }
.btn.full{ width: 100%; }
.btn.start{ justify-content: flex-start; }
.btn:disabled, .btn[aria-disabled="true"]{
    opacity: .45;
    cursor: default;
    pointer-events: none;
}


/* =============================================================================
   7. FORMS
   ========================================================================== */

/* Label above, control, help below. One element, three consistent gaps. */
.f{ display: flex; flex-direction: column; gap: var(--s2); min-width: 0; }
.f > .lbl, .f > span:first-child{
    font-size: var(--f3);
    line-height: var(--l3);
    color: var(--txt2);
}
.f > em, .f > .help{
    font-style: normal;
    font-size: var(--f2);
    line-height: var(--l2);
    color: var(--txt3);
}
.f > .err{ font-size: var(--f2); color: var(--red); }

.in{
    width: 100%;
    height: 38px;
    padding: 0 var(--s3);
    border: 1px solid var(--line2);
    border-radius: var(--r1);
    background: var(--panel2);
    color: var(--txt);
    font-size: var(--f4);
    transition: border-color var(--fast);
}
.in::placeholder{ color: var(--txt3); }
.in:hover{ border-color: var(--line3); }
.in:focus{ outline: none; border-color: var(--line3); }
.in:focus-visible{ outline: 2px solid var(--blue); outline-offset: 1px; }
.in[readonly]{ background: #111113; color: var(--txt2); cursor: default; }
.in:disabled{ opacity: .5; cursor: default; }
select.in{ padding-right: var(--s2); cursor: pointer; }
select.in option{ background: var(--panel2); color: var(--txt); }
textarea.in{ height: auto; min-height: 92px; padding: var(--s3); resize: vertical; line-height: var(--l4); }
input[type="file"].in{ height: auto; padding: var(--s2) var(--s3); cursor: pointer; }
.in.w-sm{ max-width: 140px; } .in.w-md{ max-width: 240px; } .in.w-lg{ max-width: 400px; }

/* Fieldset: a group of related controls. Replaces a <label> wrapped round nine
   inputs, which made clicking any text in the group focus the first one. */
fieldset{ border: none; min-width: 0; }
legend{
    font-size: var(--f3);
    line-height: var(--l3);
    color: var(--txt2);
    padding-bottom: var(--s2);
}

/* Checkbox and radio, drawn. The native control stays in the accessibility
   tree and keeps its keyboard behaviour; only the box is ours. */
.ck{ display: inline-flex; align-items: center; gap: var(--s2); cursor: pointer; font-size: var(--f4); }
.ck > input{ position: absolute; opacity: 0; width: 0; height: 0; }
.ck > i{
    width: 17px; height: 17px; flex: none;
    border: 1px solid var(--line3);
    border-radius: 4px;
    background: var(--panel2);
    /* The mark is centred by the grid, not by hand-tuned offsets. Absolute
       left/top values put it visibly high and left of the box centre, because
       rotating a 4x9 rectangle moves where its ink sits. */
    display: grid;
    place-items: center;
    transition: background var(--fast), border-color var(--fast);
}
.ck.rd > i{ border-radius: var(--rf); }
.ck > input:checked + i{ background: var(--txt); border-color: var(--txt); }
.ck > input:checked + i::after{
    content: "";
    width: 4px; height: 8px;
    border: solid #000; border-width: 0 2px 2px 0;
    /* The ink of an L-shape sits in its bottom-right, so after rotating about
       the centre it reads a shade low. One pixel of lift corrects it. */
    transform: translateY(-1px) rotate(45deg);
}
.ck.rd > input:checked + i::after{
    width: 7px; height: 7px;
    border: none; border-radius: var(--rf); background: #000; transform: none;
}
.ck > input:focus-visible + i{ outline: 2px solid var(--blue); outline-offset: 2px; }
.ck > input:disabled + i{ opacity: .4; }

/* Switch. The VISUAL is .chk + .tr and the LAYOUT is whatever wraps them, so a
   row that arranges itself differently - a payment-method row, say - reuses the
   control instead of describing it again. Used wherever a setting takes effect
   as a state rather than as a choice in a form: 61 inverted pills were not
   legible as on/off. */
.chk{ position: absolute; opacity: 0; width: 0; height: 0; }
.tr{
    width: 38px; height: 22px; flex: none;
    border: 1px solid var(--line2);
    border-radius: var(--rf);
    background: var(--panel3);
    position: relative;
    transition: background var(--fast), border-color var(--fast);
}
.tr::after{
    content: "";
    position: absolute; top: 2px; left: 2px;
    width: 16px; height: 16px;
    border-radius: var(--rf);
    background: var(--txt3);
    transition: transform var(--fast), background var(--fast);
}
.chk:checked + .tr{ background: var(--green-bg); border-color: rgba(0,208,0,.5); }
.chk:checked + .tr::after{ transform: translateX(16px); background: var(--green); }
.chk:focus-visible + .tr{ outline: 2px solid var(--blue); outline-offset: 2px; }
.chk:disabled + .tr{ opacity: .45; }

/* The default layout for one: the track, then its label. */
.sw{ display: inline-flex; align-items: center; gap: var(--s3); cursor: pointer; }


/* =============================================================================
   7b. VALUES — a figure and its unit, and the stat card built from them
   A number and its unit are two elements with a gap, not a literal space in the
   markup, and they sit on a shared baseline so the unit does not float.
   ========================================================================== */
.val{
    display: flex;
    align-items: baseline;
    gap: var(--s2);
    font-variant-numeric: tabular-nums;
    font-feature-settings: "tnum";
    font-weight: 500;
    letter-spacing: var(--tight);
    min-width: 0;
}
.val > .unit{
    font-size: var(--f5);
    font-weight: 400;
    letter-spacing: normal;
    color: var(--txt2);
}
.val.s7{ font-size: var(--f7); line-height: var(--l7); }
.val.s8{ font-size: var(--f8); line-height: var(--l8); }
.val.s6{ font-size: var(--f6); line-height: var(--l6); }
.val.s6 > .unit, .val.s7 > .unit{ font-size: var(--f4); }
/* A currency code is a separate word and takes a space; a percent sign is part
   of the number and must not. */
.val.tight{ gap: 0; }

/* The change against the previous window. Written as "+12%" / "-2%": an arrow
   glyph adds nothing the sign does not already say, and it does not align. */
.delta{
    display: inline-flex;
    align-items: center;
    justify-self: start;
    width: fit-content;
    padding: 2px var(--s3);
    border-radius: var(--rf);
    font-size: var(--f2);
    font-weight: 500;
    font-variant-numeric: tabular-nums;
    background: var(--flat-bg);
    color: var(--txt2);
}
.delta.up{ background: var(--green-bg); color: var(--green); }
.delta.dn{ background: var(--red-bg);   color: var(--red); }

/* label / value / delta, in that order, with one gap between each. */
.stat{ display: flex; flex-direction: column; align-items: flex-start; gap: var(--s3); }


/* =============================================================================
   8. BADGE AND CHIP
   ========================================================================== */

/* A dot and a word. The word carries the meaning, so the badge still works in
   greyscale or for a colour-blind reader. */
.b{
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* A grid item is justify-self:stretch by default, and inline-flex blockifies
       to flex - so without this the pill filled its whole table column and the
       dot and word sat at the left edge of it. */
    justify-self: start;
    width: fit-content;
    gap: var(--s2);
    padding: 3px var(--s3) 3px var(--s2);
    border-radius: var(--rf);
    background: var(--flat-bg);
    color: var(--txt2);
    font-size: var(--f2);
    font-weight: 500;
    white-space: nowrap;
}
.b::before{
    content: "";
    width: 6px; height: 6px; flex: none;
    border-radius: var(--rf);
    background: currentColor;
}
.b.ok{ background: var(--green-bg); color: var(--green); }
.b.no{ background: var(--red-bg);   color: var(--red); }
.b.go{ background: var(--blue-bg);  color: var(--blue); }
/* Just the dot, for a list where the word is in the row beside it. */
.b.dot{ padding: 3px; gap: 0; }

/* A bullet in a list of claims. The offset is derived from the line-height of the
   text beside it rather than nudged with a magic number, so it stays centred on
   the first line at any type size. */
.bullets{ display: flex; flex-direction: column; gap: var(--s3); }
.bullets > li{
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--s3);
    align-items: start;
    font-size: var(--f3);
    line-height: var(--l3);
    color: var(--txt2);
}
.bullets > li::before{
    content: "";
    width: 6px; height: 6px;
    border-radius: var(--rf);
    background: var(--green);
    margin-top: calc((1em * var(--l3) - 6px) / 2);
}

.chip{
    display: inline-flex;
    align-items: center;
    gap: var(--s2);
    height: 34px;
    padding: 0 var(--s3) 0 var(--s1);
    border: 1px solid var(--line2);
    border-radius: var(--rf);
    background: var(--panel2);
    color: var(--txt2);
    font-size: var(--f3);
    cursor: pointer;
    transition: background var(--fast), color var(--fast), border-color var(--fast);
}
.chip img{ width: 26px; height: 26px; border-radius: var(--rf); }
.chip:hover{ border-color: var(--line3); color: var(--txt); }

.av{
    width: 28px; height: 28px; flex: none;
    border-radius: var(--rf);
    background: var(--panel3);
    display: grid; place-items: center;
    font-size: var(--f2); font-weight: 700; color: var(--txt2);
}


/* =============================================================================
   9. THE LIST — one markup, two layouts
   Rows are written once, one cell per column, with no labels in the markup.
   Table mode makes each row a subgrid of the panel's column template, so the
   header can never drift from its own cells. Card mode re-places the same
   cells, each one positioned by its class.
   ========================================================================== */
.rad{ position: absolute; opacity: 0; width: 0; height: 0; }

.lst{ display: grid; }
.lst .hd{
    display: none;
    align-items: center;
    gap: var(--s4);
    padding: var(--s3) var(--s5);
    border-bottom: 1px solid var(--line);
}
.lst .hd > *{
    font-size: var(--f1);
    line-height: var(--l1);
    font-weight: 500;
    letter-spacing: var(--track);
    text-transform: uppercase;
    color: var(--txt3);
}
.lst .r{
    display: grid;
    align-items: center;
    gap: var(--s2) var(--s4);
    padding: var(--s3) var(--s5);
    border-bottom: 1px solid var(--line);
    transition: background var(--fast), border-color var(--fast);
    min-width: 0;
}
.lst .r:last-child{ border-bottom: none; }
.lst a.r:hover{ background: var(--panel2); }

/* --- cell roles: appearance only, identical in both layouts -------------- */
.lst .ic{ width: 28px; height: 28px; border-radius: var(--rf); flex: none; }
.lst .amt{ font-size: var(--f4); font-weight: 500; font-variant-numeric: tabular-nums; }
.lst .meth{ font-size: var(--f3); color: var(--txt2); }
.lst .tm{ font-size: var(--f3); color: var(--txt2); white-space: nowrap; }
.lst .sec2{ font-size: var(--f3); color: var(--txt2); font-variant-numeric: tabular-nums; }
.lst .uid{
    font-family: var(--mono); font-size: var(--f2); color: var(--txt3);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0;
}
/* A numeric column reads right-aligned, and its header has to follow it there
   or the label stops describing the column under it. */
/* Right alignment is a TABLE-mode column property: the header has to follow its
   column there or the label stops describing the cells beneath it. Card mode
   places every cell explicitly instead, so .rt must not leak into it. */
.p:has(.t:checked) .lst .rt{ text-align: right; justify-self: end; }

/* --- TABLE mode ----------------------------------------------------------- */
.p:has(.t:checked) .lst{
    grid-template-columns: var(--cols);
    column-gap: var(--s4);
    overflow-x: auto;
    scrollbar-width: thin;
}
.p:has(.t:checked) .lst .hd,
.p:has(.t:checked) .lst .r{ display: grid; grid-template-columns: subgrid; grid-column: 1 / -1; }

/* --- CARD mode ------------------------------------------------------------ */
/* Cards reflow into columns rather than each stretching the full panel width.
   A single 1100px-wide card puts its amount at one end and its badge at the
   other with a quarter of the screen of nothing between them. 380px is wide
   enough for an amount, a badge and an identifier; min(...,100%) lets it drop
   to one column when there is not room for two. */
.p:has(.s:checked) .lst{
    padding: var(--s4);
    gap: var(--s3);
    grid-template-columns: repeat(auto-fill, minmax(min(380px, 100%), 1fr));
}
.p:has(.s:checked) .lst .hd{ display: none; }
.p:has(.s:checked) .lst .r{
    grid-template-columns: auto 1fr auto;
    gap: var(--s1) var(--s4);
    padding: var(--s4);
    border: 1px solid var(--line);
    border-radius: var(--r2);
    background: var(--panel2);
}
.p:has(.s:checked) .lst a.r:hover{ border-color: var(--line3); background: var(--panel3); }
.p:has(.s:checked) .lst .ic   { grid-column: 1; grid-row: 1 / 3; align-self: start;
                                 width: 32px; height: 32px; }
.p:has(.s:checked) .lst .amt  { grid-column: 2; grid-row: 1; font-size: var(--f5);
                                justify-self: start; text-align: left; }
.p:has(.s:checked) .lst .b    { grid-column: 3; grid-row: 1; justify-self: end; }
.p:has(.s:checked) .lst .meth,
.p:has(.s:checked) .lst .sec2 { grid-column: 2; grid-row: 2;
                                justify-self: start; text-align: left; }
.p:has(.s:checked) .lst .tm   { grid-column: 3; grid-row: 2; justify-self: end;
                                text-align: right; }
.p:has(.s:checked) .lst .uid  { grid-column: 2 / -1; grid-row: 3; }
/* A row with nothing in the second slot - the ledger has no Method - left the
   time hanging at the right edge against an empty half-line. When there is no
   middle cell the time takes that slot instead, directly under the amount. */
.p:has(.s:checked) .lst .r:not(:has(.meth)):not(:has(.sec2)) .tm{
    grid-column: 2;
    justify-self: start;
    text-align: left;
}
/* Cards in a reflowing grid rather than one column. */
.p:has(.s:checked) .lst.tiles{
    grid-template-columns: repeat(auto-fill, minmax(min(280px, 100%), 1fr)); }

/* Every cell must be allowed to shrink, or its min-content width props the
   1fr track open and the row grows past the card. */
.p:has(.s:checked) .lst .r > *{ min-width: 0; }

/* A card is a summary and a table is the full record, so a column with no card
   slot is marked table-only rather than being auto-placed into whatever cell
   happens to be free - which is what would scramble the layout. */
.p:has(.s:checked) .lst .only-t{ display: none; }
.p:has(.t:checked) .lst .only-s{ display: none; }

/* Under ~480px the icon, the amount and the badge no longer fit on one line:
   the amount is squeezed to a few characters and the badge pushes out of the
   card. The badge takes a line of its own instead. */
@media (max-width: 480px){
    .p:has(.s:checked) .lst .r   { grid-template-columns: auto 1fr; }
    .p:has(.s:checked) .lst .ic  { grid-row: 1; }
    .p:has(.s:checked) .lst .b   { grid-column: 2; grid-row: 2; justify-self: start; }
    .p:has(.s:checked) .lst .meth,
    .p:has(.s:checked) .lst .sec2{ grid-column: 2; grid-row: 3; }
    .p:has(.s:checked) .lst .tm  { grid-column: 2; grid-row: 3; justify-self: end; }
    .p:has(.s:checked) .lst .r:not(:has(.meth)):not(:has(.sec2)) .tm{
        grid-row: 3; justify-self: start;
    }
    .p:has(.s:checked) .lst .uid { grid-column: 2; grid-row: 4; }
}


/* =============================================================================
   10. SEGMENTED CONTROL, TABS, NAV
   ========================================================================== */
.seg{
    display: inline-flex;
    gap: 2px;
    padding: 2px;
    border: 1px solid var(--line2);
    border-radius: var(--r1);
    background: var(--panel2);
}
.seg label{
    display: grid; place-items: center;
    width: 32px; height: 26px;
    border-radius: 4px;
    cursor: pointer;
    opacity: .45;
    transition: opacity var(--fast), background var(--fast);
}
.seg label:hover{ opacity: .85; }
.seg label.on{ opacity: 1; background: var(--panel3); }
.seg img{ width: 15px; }
.p:has(.t:checked) .seg [for$="-t"],
.p:has(.s:checked) .seg [for$="-s"]{ opacity: 1; background: var(--panel3); }

.tabs{ display: flex; align-items: center; gap: var(--s1); flex-wrap: wrap; }
.tabs a{
    display: inline-flex; align-items: center; gap: var(--s2);
    height: 32px; padding: 0 var(--s3);
    border-radius: var(--r1);
    color: var(--txt2);
    font-size: var(--f4);
    transition: background var(--fast), color var(--fast);
}
.tabs a:hover{ background: var(--panel2); color: var(--txt); }
.tabs a.on{ background: var(--panel3); color: var(--txt); font-weight: 500; }
.tabs img{ width: 16px; opacity: .7; }
.tabs a.on img{ opacity: 1; }

.nav{ display: flex; flex-direction: column; gap: 2px; }
.nav a{
    display: flex; align-items: center; gap: var(--s3);
    height: 38px; padding: 0 var(--s2);
    border-radius: var(--r1);
    color: var(--txt2);
    font-size: var(--f4);
    transition: background var(--fast), color var(--fast);
}
.nav a img{ width: 18px; opacity: .6; transition: opacity var(--fast); }
.nav a:hover{ background: var(--panel2); color: var(--txt); }
.nav a:hover img{ opacity: .85; }
.nav a.on{ background: var(--panel3); color: var(--txt); font-weight: 500; }
.nav a.on img{ opacity: 1; }
.nav .grp{ padding: var(--s4) var(--s2) var(--s2); }
/* Sub-items under an expanded parent. The indent line shows the relationship
   without a second nav column. */
.nav .sub{ display: flex; flex-direction: column; gap: 2px; margin: 2px 0 var(--s2) var(--s4); padding-left: var(--s3); border-left: 1px solid var(--line); }
.nav .sub a{ height: 32px; font-size: var(--f3); }


/* =============================================================================
   11. PAGINATION, EMPTY STATE, FLASH, METER
   ========================================================================== */
.pg{
    display: flex; align-items: center; gap: var(--s3);
    padding: var(--s3) var(--s5);
    border-top: 1px solid var(--line);
}
.pg .at{ margin-left: auto; font-size: var(--f3); color: var(--txt3); }

.empty{
    display: flex; flex-direction: column; align-items: center;
    gap: var(--s2);
    padding: var(--s7) var(--s5);
    text-align: center;
}
.empty b{ font-size: var(--f5); font-weight: 500; }
.empty p{ font-size: var(--f3); color: var(--txt3); max-width: 46ch; }
.empty .btn{ margin-top: var(--s2); }

/* Flash messages. .flash is the fixed container; .msg is the message itself,
   which is an ordinary block and can sit anywhere. They fade out, and
   pointer-events:none at the end of the animation is what stops an invisible
   block covering the top-right corner of every page for the rest of the
   session. The dismiss link exists because with no JavaScript there is nothing
   else to close them. */
.flash{
    position: fixed;
    top: var(--s4); right: var(--s4);
    z-index: 100;
    display: flex; flex-direction: column; gap: var(--s2);
    width: min(360px, calc(100% - var(--s6)));
}
.flash > .msg{ animation: flash-out 6s forwards; }
.msg{
    display: flex; align-items: flex-start; gap: var(--s3);
    padding: var(--s3) var(--s4);
    background: var(--panel);
    border: 1px solid var(--line2);
    border-left: 2px solid var(--txt3);
    border-radius: var(--r1);
}
.msg.success{ border-left-color: var(--green); }
.msg.error{ border-left-color: var(--red); }
.msg b{ font-size: var(--f4); font-weight: 500; }
/* The leading dot is centred on the first line of text beside it, derived from
   that line height rather than nudged with a magic number. */
.msg > .b.dot{ margin-top: calc((1em * var(--l4) - 12px) / 2); }
.msg > .x{
    margin-left: auto;
    align-self: flex-start;
    color: var(--txt3);
    font-size: var(--f3);
    padding: 0 var(--s1);
    white-space: nowrap;
}
.msg > .x:hover{ color: var(--txt); }
@keyframes flash-out{
    0%, 85%{ opacity: 1; transform: none; }
    100%{ opacity: 0; transform: translateX(16px); pointer-events: none; }
}

/* Only ever a real ratio: balance share, completion rate. Never decoration. */
.bar{ height: 4px; border-radius: var(--rf); background: var(--panel3);
      overflow: hidden; width: 100%; }
.bar.wide{ align-self: stretch; }
.bar > i{ display: block; height: 100%; border-radius: var(--rf);
          background: var(--txt2); width: 0; }
.bar > i.g{ background: var(--green); }
.bar > i.r{ background: var(--red); }
/* A width that comes from data cannot come from a class, and an inline style
   would put unsafe-inline back into the CSP that removing inline styles just
   bought. So the template rounds the percentage to the nearest 5, which on a
   4px bar is well below what anyone can read off it. */
.bar > i.w0{width:0} .bar > i.w5{width:5%} .bar > i.w10{width:10%} .bar > i.w15{width:15%}
.bar > i.w20{width:20%} .bar > i.w25{width:25%} .bar > i.w30{width:30%} .bar > i.w35{width:35%}
.bar > i.w40{width:40%} .bar > i.w45{width:45%} .bar > i.w50{width:50%} .bar > i.w55{width:55%}
.bar > i.w60{width:60%} .bar > i.w65{width:65%} .bar > i.w70{width:70%} .bar > i.w75{width:75%}
.bar > i.w80{width:80%} .bar > i.w85{width:85%} .bar > i.w90{width:90%} .bar > i.w95{width:95%}
.bar > i.w100{width:100%}


/* =============================================================================
   11b. A CENTRED PAGE - 404, 500, suspended, contact
   ========================================================================== */
.mid{
    min-height: 100dvh;
    display: grid;
    place-items: center;
    padding: var(--s5);
    text-align: center;
}
.mid > .col{
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--s4);
    max-width: 54ch;
}
.mid h1{ font-size: var(--f8); line-height: var(--l8); }
.mid p{ color: var(--txt2); }
.mid .row{ flex-wrap: wrap; justify-content: center; }
@media (max-width: 600px){
    .mid h1{ font-size: var(--f7); line-height: var(--l7); }
}


/* =============================================================================
   12. THE FOCUS RING, RE-ASSERTED
   :focus-visible is a pseudo-class, so it ties on specificity with .btn and
   .in above. Whichever comes last wins, so it comes last.
   ========================================================================== */
:focus-visible{ outline: 2px solid var(--blue); outline-offset: 2px; }
.btn:focus-visible, .in:focus-visible, .seg label:focus-within{ outline: 2px solid var(--blue); }


/* =============================================================================
   13. FONTS
   WOFF2 first; the TTF is a fallback no current browser reaches. font-display
   swap because the default blocks first paint on ~370 KB of font, which over
   Tor is the whole page.
   ========================================================================== */
@font-face{font-family:Roboto;src:url('./fonts/Roboto-Light.woff2') format('woff2'),url('./fonts/Roboto-Light.ttf') format('truetype');font-weight:300;font-style:normal;font-display:swap}
@font-face{font-family:Roboto;src:url('./fonts/Roboto-Regular.woff2') format('woff2'),url('./fonts/Roboto-Regular.ttf') format('truetype');font-weight:400;font-style:normal;font-display:swap}
@font-face{font-family:Roboto;src:url('./fonts/Roboto-Medium.woff2') format('woff2'),url('./fonts/Roboto-Medium.ttf') format('truetype');font-weight:500;font-style:normal;font-display:swap}
@font-face{font-family:Roboto;src:url('./fonts/Roboto-Bold.woff2') format('woff2'),url('./fonts/Roboto-Bold.ttf') format('truetype');font-weight:700;font-style:normal;font-display:swap}
@font-face{font-family:Roboto;src:url('./fonts/Roboto-Black.woff2') format('woff2'),url('./fonts/Roboto-Black.ttf') format('truetype');font-weight:900;font-style:normal;font-display:swap}
