/* Figtree, the design's face, with Inter behind it — and Inter is not a spare
   tyre here, it is the Cyrillic.

   Figtree draws no Cyrillic at all, which earlier looked like a reason to skip it
   entirely: the spreadsheet archive's «Итог за месяц» merchant and Alex's own
   category names (Пенсия, Транспорт, Техника) are real data on real rows. But
   font fallback is per GLYPH, not per element — the browser takes Figtree for
   Latin and digits and reaches past it to Inter for anything Figtree lacks. So
   the page gets the design's face and the Cyrillic still gets a face drawn for
   it, rather than whatever the OS would have substituted.

   Both loaded as VARIABLE fonts, not weight lists: this stylesheet leans on
   in-between weights (650, 720, 750, 780) that static instances snap to 700/800. */
@import url('https://fonts.googleapis.com/css2?family=Figtree:ital,wght@0,300..900;1,300..900&family=Inter:opsz,wght@14..32,100..900&family=Source+Serif+4:opsz,wght@8..60,400;8..60,500;8..60,600&display=swap');

/* --lime is the accent, not a colour: it was lime on the dark theme this file
   started as, and the name survives the repaint because it is threaded through
   several hundred rules. --positive stays separate from it — an accent doubling
   as "growth" is what once painted an upward move in a warning colour. */
:root {
    --bg: #f5f5f3;
    --bg-soft: #fbfbfa;
    --panel: #ffffff;
    --panel-2: #fbfbfa;
    --line: #e8e7e2;
    --text: #1b1b19;
    --muted: #6d6d66;
    --modal-bg: #ffffff;

    --lime: #0f7a55;
    --lime-dark: #eef5f1;
    --positive: #0f7a55;
    --aqua: #3f8fa8;
    --danger: #c0562a;
    --warning: #a34a1f;

    --chart-line: #3f8fa8;
    --chart-fill: rgba(63, 143, 168, .22);
    --radius: 14px;
    --shadow: 0 1px 2px rgba(40, 38, 32, .04);
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
    margin: 0;
    min-width: 320px;
    min-height: 100vh;
    background: var(--bg);
    color: var(--text);
    font-family: Figtree, Inter, ui-sans-serif, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
}
button, input, select { font: inherit; }
button, a { -webkit-tap-highlight-color: transparent; }
a { color: inherit; text-decoration: none; }
button { color: inherit; }
button:focus-visible, a:focus-visible, input:focus-visible, select:focus-visible, summary:focus-visible {
    outline: 2px solid var(--lime);
    outline-offset: 3px;
}

.app-shell { min-height: 100vh; }
.sidebar {
    position: fixed;
    inset: 0 auto 0 0;
    z-index: 20;
    display: flex;
    width: 236px;
    flex-direction: column;
    padding: 27px 22px 22px;
    border-right: 1px solid var(--line);
    background: rgba(7, 17, 21, .92);
    backdrop-filter: blur(18px);
}
.brand {
    display: inline-flex;
    align-items: center;
    gap: 11px;
    font-size: 20px;
    font-weight: 780;
    letter-spacing: -.8px;
}
.brand-mark {
    display: grid;
    width: 31px;
    height: 31px;
    place-items: center;
    border-radius: 9px;
    background: var(--lime);
    color: #0b1208;
    font-size: 16px;
    font-weight: 900;
    box-shadow: 0 0 30px rgba(200, 241, 105, .15);
}
.brand--large { font-size: 24px; }
.brand--large .brand-mark { width: 38px; height: 38px; font-size: 19px; }
.main-nav { display: grid; gap: 6px; margin-top: 60px; }
.nav-link {
    display: flex;
    min-height: 43px;
    align-items: center;
    gap: 13px;
    padding: 0 13px;
    border: 0;
    border-radius: 11px;
    color: var(--muted);
    background: transparent;
    font-weight: 600;
    text-align: left;
    transition: .2s ease;
}
.nav-link > span { width: 19px; color: #b9cbc6; font-size: 18px; text-align: center; }
.nav-link:hover { color: var(--text); background: rgba(255,255,255,.035); }
.nav-link.active {
    background: rgba(200, 241, 105, .1);
    color: var(--lime);
}
.nav-link.active > span { color: var(--lime); }
.nav-link small {
    margin-left: auto;
    padding: 3px 6px;
    border-radius: 5px;
    background: rgba(255,255,255,.05);
    color: #687b76;
    font-size: 8px;
    letter-spacing: .7px;
    text-transform: uppercase;
}
.nav-link--future { cursor: default; opacity: .68; }
/* Net-worth sources are grouped, so the sidebar stays readable as bank accounts and
   manual assets join crypto. */
.nav-group { display: grid; gap: 4px; margin-top: 16px; padding-top: 14px; border-top: 1px solid var(--line); }
.nav-group__title {
    margin: 0 0 2px;
    padding: 0 13px;
    color: #5f736e;
    font-size: 8px;
    font-weight: 800;
    letter-spacing: 1px;
    text-transform: uppercase;
}
.sidebar-foot { display: grid; gap: 18px; margin-top: auto; }
.button-reset { width: 100%; cursor: pointer; }
.profile {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-top: 18px;
    border-top: 1px solid var(--line);
}
.avatar {
    display: grid;
    width: 36px;
    height: 36px;
    flex: 0 0 auto;
    place-items: center;
    border: 1px solid rgba(200, 241, 105, .22);
    border-radius: 50%;
    background: #1c2d27;
    color: var(--lime);
    font-weight: 800;
}
.profile-copy { display: grid; min-width: 0; gap: 2px; }
.profile-copy strong { overflow: hidden; font-size: 12px; text-overflow: ellipsis; white-space: nowrap; }
.profile-copy small { color: var(--muted); font-size: 9px; }
.icon-button {
    width: 30px;
    height: 30px;
    margin-left: auto;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: var(--muted);
    cursor: pointer;
}
.icon-button:hover { background: rgba(255,255,255,.05); color: var(--text); }

.workspace { min-height: 100vh; margin-left: 236px; padding: 34px clamp(24px, 3.6vw, 58px) 38px; }
.topbar {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 26px;
}
.eyebrow, .mini-label {
    color: var(--lime);
    font-size: 9px;
    font-weight: 800;
    letter-spacing: 1.7px;
}
/* Tracking eased for Cyrillic: it runs boxier than Latin, and the Manrope-era
   −1.8px crushed "Your net worth" at heading sizes. */
.topbar h1 { margin: 7px 0 0; font-size: clamp(28px, 3vw, 39px); letter-spacing: -1px; line-height: 1; }
.topbar-actions { display: flex; align-items: center; gap: 16px; }
.freshness { display: flex; align-items: center; gap: 8px; color: var(--muted); font-size: 11px; }
.status-dot {
    display: inline-block;
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: var(--lime);
    box-shadow: 0 0 0 4px rgba(200,241,105,.08), 0 0 14px rgba(200,241,105,.35);
}
.status-dot--warn { background: var(--danger); box-shadow: 0 0 0 4px rgba(255,122,144,.08); }
.button {
    display: inline-flex;
    min-height: 41px;
    align-items: center;
    justify-content: center;
    gap: 12px;
    padding: 0 17px;
    border: 1px solid transparent;
    border-radius: 10px;
    font-weight: 750;
    cursor: pointer;
    transition: transform .18s ease, border-color .18s ease, background .18s ease;
}
.button:hover { transform: translateY(-1px); }
.button--ghost { border-color: var(--line); background: rgba(255,255,255,.025); }
.button--ghost:hover { border-color: rgba(200,241,105,.35); }
.button--primary { background: var(--lime); color: #10170b; box-shadow: 0 8px 30px rgba(200,241,105,.08); }
.button--light { background: #f1f5ee; color: #132016; }
.button--wide { width: 100%; min-height: 50px; }

.alert {
    margin: 0 0 18px;
    padding: 12px 15px;
    border: 1px solid;
    border-radius: 11px;
    animation: slide-in .25s ease-out;
}
.alert--success { border-color: rgba(200,241,105,.25); background: rgba(200,241,105,.08); color: #dcf7a0; }
.alert--error { border-color: rgba(255,122,144,.25); background: rgba(255,122,144,.08); color: #ffadba; }
@keyframes slide-in { from { opacity: 0; transform: translateY(-5px); } }

.setup-banner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 18px;
    padding: 14px 16px;
    border: 1px solid rgba(200,241,105,.2);
    border-radius: 14px;
    background: linear-gradient(100deg, rgba(200,241,105,.12), rgba(115,210,222,.06));
}
.setup-banner > div { display: flex; align-items: center; gap: 13px; }
.setup-number { display: grid; width: 36px; height: 36px; place-items: center; border-radius: 50%; background: var(--lime); color: #15200e; font-size: 10px; font-weight: 900; }
.setup-banner strong { display: block; margin-bottom: 3px; }
.setup-banner p { margin: 0; color: var(--muted); font-size: 11px; }

/* The overview stacks its cards in one grid, so the space between any two
   dashboard widgets is this gap — not a per-section margin that drifts. */
.dash-stack { display: grid; gap: 18px; }
.dash-stack > * { min-width: 0; }

.hero-grid { display: grid; grid-template-columns: minmax(0, 1.55fr) minmax(330px, .85fr); gap: 18px; }
.net-worth-card, .allocation-card, .panel {
    border: 1px solid var(--line);
    border-radius: var(--radius);
    background: linear-gradient(145deg, rgba(19, 34, 39, .96), rgba(12, 25, 29, .96));
    box-shadow: var(--shadow);
}
.net-worth-card {
    position: relative;
    min-height: 348px;
    overflow: hidden;
    padding: 24px 28px 0;
}
.net-worth-card::after {
    position: absolute;
    width: 280px;
    height: 280px;
    right: -80px;
    top: -130px;
    border-radius: 50%;
    background: rgba(200,241,105,.035);
    content: "";
}
.card-heading { display: flex; align-items: center; justify-content: space-between; color: #a9bbb6; font-size: 9px; font-weight: 800; letter-spacing: 1.5px; }
.privacy-pill { padding: 5px 8px; border: 1px solid rgba(200,241,105,.15); border-radius: 20px; color: var(--lime); font-size: 7px; }
.net-worth-value { margin-top: 17px; font-size: clamp(38px, 5vw, 58px); font-weight: 760; letter-spacing: -3.5px; line-height: 1; }
.net-worth-value small { margin-right: 4px; color: var(--muted); font-size: .42em; font-weight: 500; vertical-align: top; }
.change-row { display: flex; align-items: center; gap: 8px; margin-top: 13px; color: var(--positive); font-size: 11px; font-weight: 700; }
.change-row span { padding: 4px 7px; border-radius: 5px; background: rgba(200,241,105,.08); }
.change-row small { color: var(--muted); font-weight: 500; }
.negative { color: var(--danger) !important; }
.chart-wrap { position: absolute; inset: 176px 0 34px; }
/* Both the id and the attribute: the accounts page reuses this renderer with
   [data-chart] and, styled by id alone, its canvas fell back to the element's
   intrinsic 300x150 and drew a small chart pinned to the left of the card. */
#portfolio-chart, [data-chart] { width: 100%; height: 100%; }
.chart-empty { position: absolute; inset: 45% 0 auto; color: #536965; font-size: 10px; text-align: center; }
.chart-range { position: absolute; right: 22px; bottom: 13px; z-index: 2; display: flex; gap: 3px; }
.chart-range button { padding: 3px 6px; border: 0; border-radius: 5px; background: transparent; color: #687c77; font-size: 8px; font-weight: 750; cursor: pointer; }
.chart-range button.active { background: rgba(200,241,105,.12); color: var(--lime); }

.allocation-card { padding: 23px 24px 20px; }
.section-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px 14px; }
.section-head h2 { margin: 5px 0 0; font-size: 17px; letter-spacing: -.3px; }
/* Card-title pattern without an eyebrow above it: the h2 sits directly in the row. */
.section-head > h2 { margin: 0; }
.section-head__figure { font-variant-numeric: tabular-nums; }
.asset-count { color: var(--muted); font-size: 10px; }
.allocation-body { display: flex; align-items: center; gap: 24px; min-height: 210px; }
.donut {
    display: grid;
    width: 132px;
    height: 132px;
    flex: 0 0 auto;
    place-items: center;
    border-radius: 50%;
    background: var(--donut);
    box-shadow: inset 0 0 0 1px rgba(255,255,255,.03);
}
.donut::before {
    position: absolute;
    width: 82px;
    height: 82px;
    border-radius: 50%;
    background: #112126;
    content: "";
}
.donut > div { position: relative; z-index: 1; display: grid; gap: 1px; text-align: center; }
.donut strong { font-size: 22px; }
.donut span { color: var(--muted); font-size: 7px; letter-spacing: 1px; }
.legend { display: grid; width: 100%; gap: 11px; }
.legend-row { display: grid; grid-template-columns: 7px 1fr auto; align-items: center; gap: 9px; }
.legend-row > i { width: 6px; height: 6px; border-radius: 50%; background: var(--legend-color); box-shadow: 0 0 10px var(--legend-color); }
.legend-row > span { display: flex; justify-content: space-between; gap: 10px; }
.legend-row strong, .legend-row b { font-size: 10px; }
.legend-row small { color: var(--muted); font-size: 9px; }
.legend-row b { font-weight: 650; }
.metric-strip { display: grid; grid-template-columns: repeat(3, 1fr); padding-top: 16px; border-top: 1px solid var(--line); }
.metric-strip > div, .metric-button { display: grid; gap: 3px; padding-left: 14px; border: 0; border-left: 1px solid var(--line); background: transparent; color: inherit; text-align: left; }
.metric-strip > div:first-child { padding-left: 0; border: 0; }
.metric-strip span { color: var(--muted); font-size: 8px; text-transform: uppercase; }
.metric-strip strong { font-size: 15px; }
.metric-button { cursor: pointer; }
.metric-button:hover span { color: var(--lime); }

.content-grid { display: grid; grid-template-columns: minmax(0, 1.65fr) minmax(300px, .65fr); gap: 18px; margin-top: 18px; }
.panel { padding: 23px 24px; box-shadow: none; }
.table-filter { display: flex; gap: 3px; padding: 3px; border: 1px solid var(--line); border-radius: 8px; }
.table-filter button, .table-filter a { padding: 5px 9px; border: 0; border-radius: 5px; background: transparent; color: var(--muted); font-size: 9px; cursor: pointer; }
.table-filter button.active, .table-filter a.active { background: #223238; color: var(--text); }
.asset-table { margin-top: 20px; }
.asset-row {
    display: grid;
    grid-template-columns: minmax(190px, 1.4fr) minmax(90px, .8fr) minmax(70px, .6fr) 60px minmax(90px, .75fr) 28px;
    align-items: center;
    min-height: 64px;
    gap: 12px;
    border-bottom: 1px solid var(--line);
}
.asset-row:last-child { border-bottom: 0; }
.asset-row--head { min-height: 31px; color: #60736e; font-size: 8px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; }
.asset-name { display: flex; min-width: 0; align-items: center; gap: 10px; }
.asset-name img, .token-fallback { width: 32px; height: 32px; flex: 0 0 auto; border-radius: 50%; }
.asset-name img { object-fit: cover; }
.token-fallback { display: grid; place-items: center; background: color-mix(in srgb, var(--token-color) 28%, #15252a); color: var(--token-color); font-weight: 900; }
.asset-name > span { display: grid; min-width: 0; gap: 3px; }
.asset-name strong { font-size: 11px; }
.asset-name small { overflow: hidden; color: var(--muted); font-size: 8px; text-overflow: ellipsis; white-space: nowrap; }
.verified { display: grid; width: 13px; height: 13px; place-items: center; border-radius: 50%; background: var(--aqua); color: #0b191d; font-size: 8px; font-style: normal; font-weight: 900; }
.numeric { display: grid; gap: 2px; font-size: 10px; text-align: right; }
.numeric small { color: var(--muted); font-size: 7px; }
.numeric.value { font-size: 11px; font-weight: 750; }
.change { color: var(--lime); font-size: 9px; text-align: right; }
.asset-menu { position: relative; }
.asset-menu summary { padding: 6px; color: var(--muted); font-size: 10px; list-style: none; cursor: pointer; }
.asset-menu summary::-webkit-details-marker { display: none; }
.asset-menu > div { position: absolute; z-index: 5; top: 26px; right: 0; width: 145px; padding: 6px; border: 1px solid var(--line); border-radius: 9px; background: #16272c; box-shadow: var(--shadow); }
.asset-menu button { width: 100%; padding: 8px; border: 0; border-radius: 6px; background: transparent; color: #b7c8c3; font-size: 9px; text-align: left; cursor: pointer; }
.asset-menu button:hover { background: rgba(255,255,255,.04); color: var(--text); }

.section-link { color: var(--muted); font-size: 9px; font-weight: 700; letter-spacing: .3px; white-space: nowrap; }
.section-link:hover { color: var(--lime); }

.page-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 10px; margin-top: 18px; }
/* --panel-2 rather than a literal colour, so these cards follow the palette
   instead of pinning a surface that the tokens no longer agree with. */
.page-stats > div, .page-stat-button {
    display: grid;
    gap: 5px;
    padding: 14px 16px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel-2);
    text-align: left;
}
.page-stat-button { cursor: pointer; font: inherit; }
.page-stat-button:hover { border-color: rgba(200,241,105,.3); }
.page-stats span { color: var(--muted); font-size: 8px; font-weight: 700; letter-spacing: .7px; text-transform: uppercase; }
.page-stats strong { font-size: 17px; font-weight: 760; letter-spacing: -.6px; }
.page-note { margin: 14px 0 0; padding: 12px 14px; border: 1px solid var(--line); border-left: 2px solid var(--warning); border-radius: 10px; color: var(--muted); font-size: 10px; line-height: 1.5; }

/* Collections are cards, not table rows: artwork is the point, and a card grid
   reflows cleanly from one column on a phone to four on a wide screen. */
.nft-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(272px, 1fr)); gap: 12px; margin-top: 20px; }
.nft-card-panel { display: grid; align-content: start; gap: 12px; padding: 15px; border: 1px solid var(--line); border-radius: 16px; }
.nft-card-panel:hover { border-color: rgba(200,241,105,.22); }
.nft-card-head { display: grid; grid-template-columns: 44px minmax(0, 1fr) 22px; align-items: center; gap: 11px; }
.nft-avatar, .nft-avatar img, .nft-avatar .token-fallback {
    display: block;
    width: 44px;
    height: 44px;
    flex: 0 0 auto;
    border-radius: 12px;
    object-fit: cover;
}
.nft-card-title { display: grid; min-width: 0; gap: 3px; }
.nft-card-title strong { display: flex; align-items: center; overflow: hidden; gap: 5px; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.nft-card-title small { overflow: hidden; color: var(--muted); font-size: 8px; text-overflow: ellipsis; white-space: nowrap; }
.nft-card-stats { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); margin: 0; gap: 8px; }
.nft-card-stats div { display: grid; min-width: 0; gap: 3px; }
.nft-card-stats dt { color: var(--muted); font-size: 7px; font-weight: 700; letter-spacing: .6px; text-transform: uppercase; }
.nft-card-stats dd { overflow: hidden; margin: 0; font-size: 10px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.nft-card-stats dd.value { font-weight: 780; }
.nft-thumbs { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
.nft-thumb { position: relative; margin: 0; overflow: hidden; aspect-ratio: 1; border: 1px solid var(--line); border-radius: 10px; background: var(--panel-2); }
.nft-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.nft-thumb-placeholder { display: grid; width: 100%; height: 100%; place-items: center; color: var(--muted); font-size: 15px; }
.nft-thumb--more { display: grid; place-items: center; color: var(--muted); font-size: 10px; font-weight: 700; }
.nft-card-contract { justify-self: start; }

.nft-strip { display: grid; grid-auto-flow: column; grid-auto-columns: minmax(132px, 1fr); gap: 10px; margin-top: 18px; overflow-x: auto; padding-bottom: 4px; }
.nft-strip-card { display: grid; justify-items: center; gap: 7px; padding: 13px 10px; border: 1px solid var(--line); border-radius: 14px; text-align: center; }
.nft-strip-card:hover { border-color: rgba(200,241,105,.25); }
.nft-strip-card strong { overflow: hidden; max-width: 100%; font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.nft-strip-card small { color: var(--muted); font-size: 8px; }

.worth-split { display: flex; flex-wrap: wrap; gap: 6px 16px; margin-top: 12px; color: var(--muted); font-size: 9px; }
.worth-split span { display: inline-flex; align-items: center; gap: 6px; }
.worth-split i { width: 6px; height: 6px; flex: 0 0 auto; border-radius: 50%; background: var(--lime); }
.worth-split i.worth-split--nft { background: var(--aqua); }
.worth-split b { color: var(--text); font-size: 10px; font-weight: 750; }
.worth-split small { font-size: 8px; opacity: .75; }

.wallet-list { display: grid; gap: 9px; margin-top: 19px; }
.wallet-card {
    position: relative;
    display: grid;
    grid-template-columns: 38px minmax(0, 1fr) auto;
    align-items: center;
    gap: 10px;
    padding: 12px;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: rgba(255,255,255,.018);
}
.wallet-icon { display: grid; width: 36px; height: 36px; place-items: center; border-radius: 10px; background: rgba(115,210,222,.11); color: var(--aqua); font-size: 12px; font-weight: 900; }
.wallet-icon--bitcoin { background: rgba(247,178,103,.12); color: var(--warning); }
.wallet-icon--solana { background: rgba(169,139,255,.12); color: #a98bff; }
.wallet-icon--polkadot { background: rgba(255,122,144,.12); color: var(--danger); }
.wallet-main { display: grid; min-width: 0; gap: 3px; }
.wallet-main > strong { font-size: 10px; }
.copy-address { overflow: hidden; padding: 0; border: 0; background: transparent; color: var(--muted); font-family: ui-monospace, SFMono-Regular, Consolas, monospace; font-size: 8px; text-align: left; text-overflow: ellipsis; white-space: nowrap; cursor: pointer; }
.copy-address:hover { color: var(--lime); }
.wallet-meta { display: flex; gap: 6px; }
.wallet-meta span { color: #60736e; font-size: 7px; text-transform: uppercase; }
.wallet-value { display: flex; align-items: center; gap: 6px; }
.wallet-value strong { font-size: 10px; }
.sync-button { width: 25px; height: 25px; border: 0; border-radius: 7px; background: rgba(255,255,255,.04); color: var(--muted); cursor: pointer; }
.sync-button:hover { color: var(--lime); }
.spinning { animation: spin 1.2s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }
.wallet-error { grid-column: 2 / -1; margin: 2px 0 0; color: var(--danger); font-size: 8px; line-height: 1.4; }
.add-wallet-inline {
    display: flex;
    width: 100%;
    align-items: center;
    gap: 11px;
    margin-top: 11px;
    padding: 12px;
    border: 1px dashed rgba(200,241,105,.2);
    border-radius: 12px;
    background: transparent;
    color: var(--muted);
    text-align: left;
    cursor: pointer;
}
.add-wallet-inline:hover { border-color: rgba(200,241,105,.4); background: rgba(200,241,105,.025); }
.add-wallet-inline > span, .circle-button { display: grid; width: 29px; height: 29px; flex: 0 0 auto; place-items: center; border: 1px solid rgba(200,241,105,.25); border-radius: 9px; color: var(--lime); }
.add-wallet-inline div { display: grid; gap: 2px; }
.add-wallet-inline strong { color: var(--text); font-size: 9px; }
.add-wallet-inline small { font-size: 7px; }
.wallet-list-more { display: block; margin-top: 11px; color: var(--muted); font-size: 9px; font-weight: 700; }
.wallet-list-more:hover { color: var(--lime); }
.wallet-card--muted { opacity: .72; }
.wallet-card--muted:hover { opacity: 1; }

/* Wallets page: one card per source, wide enough to carry the per-wallet stats and
   the management controls the compact overview card has no room for. */
.wallet-board { display: grid; grid-template-columns: repeat(auto-fill, minmax(310px, 1fr)); gap: 12px; margin-top: 20px; }
.wallet-panel { padding: 15px; border: 1px solid var(--line); border-radius: 13px; background: rgba(255,255,255,.018); }
.wallet-panel__head { display: grid; grid-template-columns: 38px minmax(0, 1fr) auto; align-items: center; gap: 11px; }
.wallet-panel__title { display: grid; min-width: 0; gap: 3px; }
.wallet-panel__title strong { overflow: hidden; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.wallet-panel__value { display: grid; gap: 2px; text-align: right; }
.wallet-panel__value strong { font-size: 12px; font-weight: 760; }
.wallet-panel__value small { color: #60736e; font-size: 7px; letter-spacing: .6px; text-transform: uppercase; }
.wallet-panel__stats { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px 12px; margin: 14px 0 0; padding: 12px 0 0; border-top: 1px solid var(--line); }
.wallet-panel__stats div { display: grid; min-width: 0; gap: 3px; }
.wallet-panel__stats dt { color: var(--muted); font-size: 7px; font-weight: 700; letter-spacing: .7px; text-transform: uppercase; }
.wallet-panel__stats dd { margin: 0; overflow: hidden; font-size: 10px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.wallet-panel__sync--queued, .wallet-panel__sync--syncing { color: var(--aqua); }
.wallet-panel__sync--failed { color: var(--danger); }
.wallet-panel__note { margin: 12px 0 0; color: var(--warning); font-size: 8px; line-height: 1.5; }
.wallet-panel .wallet-error { grid-column: auto; margin-top: 11px; }
.wallet-panel__actions { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 14px; }
.wallet-panel__actions .button--mini span { display: inline-block; }
.wallet-manage summary { padding: 6px 0; color: var(--muted); font-size: 8px; font-weight: 700; letter-spacing: .6px; list-style: none; text-transform: uppercase; cursor: pointer; }
.wallet-manage summary::-webkit-details-marker { display: none; }
.wallet-manage summary:hover { color: var(--lime); }
.wallet-manage__body { display: grid; gap: 12px; margin-top: 10px; padding-top: 12px; border-top: 1px solid var(--line); }
.wallet-manage__rename .field { margin-bottom: 9px; }
.wallet-manage__row { display: grid; gap: 7px; }
.wallet-manage__row p { margin: 0; color: var(--muted); font-size: 8px; line-height: 1.5; }
.wallet-manage__row button {
    justify-self: start;
    min-height: 28px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: 8px;
    background: transparent;
    color: var(--muted);
    font-size: 8px;
    font-weight: 700;
    cursor: pointer;
}
.wallet-manage__row button:hover { border-color: rgba(200,241,105,.35); color: var(--lime); }
.wallet-manage__row--danger button:hover { border-color: rgba(255,122,144,.4); color: var(--danger); }

.source-outlook { margin-top: 18px; }
.source-outlook__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 12px; margin-top: 18px; }
.source-outlook__grid article { display: grid; align-content: start; gap: 7px; padding: 14px; border: 1px solid var(--line); border-radius: 12px; }
.source-outlook__grid article.is-future { border-style: dashed; opacity: .7; }
.source-outlook__grid strong { display: flex; align-items: center; gap: 7px; font-size: 10px; }
.source-outlook__grid strong small { padding: 3px 6px; border-radius: 5px; background: rgba(255,255,255,.05); color: #687b76; font-size: 7px; letter-spacing: .7px; text-transform: uppercase; }
.source-outlook__grid p { margin: 0; color: var(--muted); font-size: 9px; line-height: 1.55; }
.source-outlook__grid .button--mini { justify-self: start; margin-top: 3px; }
.circle-button { border-radius: 50%; background: transparent; cursor: pointer; }
.empty-copy { color: var(--muted); font-size: 10px; line-height: 1.6; }
.empty-state { display: grid; min-height: 250px; place-items: center; align-content: center; gap: 8px; color: var(--muted); text-align: center; }
.empty-state .empty-icon { font-size: 32px; color: #344b46; }
.empty-state strong { color: var(--text); font-size: 15px; }
.empty-state p { margin: 0 0 10px; font-size: 10px; }
.workspace-footer { display: flex; justify-content: space-between; padding: 22px 4px 0; color: #536762; font-size: 8px; letter-spacing: .5px; text-transform: uppercase; }
.workspace-footer span { display: flex; align-items: center; gap: 8px; }
.mobile-nav { display: none; }
/* Both are phone-only chrome: the sidebar covers these routes on a desktop, where a
   second copy of the same links under every heading would be noise. */
.section-nav { display: none; }

.modal {
    width: min(94vw, 470px);
    max-height: 92vh;
    padding: 0;
    border: 1px solid rgba(203,230,224,.15);
    border-radius: 20px;
    background: var(--modal-bg);
    color: var(--text);
    box-shadow: 0 40px 120px rgba(0,0,0,.65);
}
.modal::backdrop { background: rgba(1,8,10,.74); backdrop-filter: blur(7px); }
.modal[open] { animation: modal-in .2s ease-out; }
@keyframes modal-in { from { opacity: 0; transform: translateY(10px) scale(.985); } }
.modal-card { padding: 27px; }
.modal-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 14px; }
.modal-head h2 { margin: 6px 0 0; font-size: 23px; letter-spacing: -1px; }
.modal-close { width: 32px; height: 32px; border: 1px solid var(--line); border-radius: 9px; background: transparent; color: var(--muted); font-size: 20px; cursor: pointer; }
.modal-intro { margin: 17px 0 21px; color: var(--muted); font-size: 11px; line-height: 1.6; }
.field { display: grid; gap: 7px; margin-bottom: 15px; }
/* Was #aebeba, which measured 1.93:1 once the ground went light — every field
   label in every modal and on the login form, unreadable. */
.field > span { color: var(--muted); font-size: 10px; font-weight: 700; letter-spacing: .3px; }
.field input, .field select {
    width: 100%;
    height: 45px;
    padding: 0 13px;
    border: 1px solid var(--line);
    border-radius: 10px;
    /* No `outline: 0` here: it is (0,1,1) and later in the file than the global
       :focus-visible ring, so it silently killed the focus indicator on every
       input and select in every modal and on the login form. */
    background: #0b181c;
    color: var(--text);
    transition: border-color .18s;
}
.field input::placeholder { color: var(--muted); }
.field input:focus, .field select:focus { border-color: rgba(200,241,105,.45); }

.asset-note { margin: 0 0 11px; color: #7d918c; font-size: 10px; }
.safe-callout {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 2px 0 17px;
    padding: 11px;
    border-radius: 10px;
    background: rgba(115,210,222,.06);
    color: var(--aqua);
}
.safe-callout p { display: grid; gap: 2px; margin: 0; color: var(--muted); font-size: 8px; }
.safe-callout strong { color: #b7e7eb; font-size: 9px; }
/* ---------------------------------------------------------------------------
   Settings dialog.
   Grouping used to be carried by margin alone: .integration-card's 22px margin
   made the gap to its OWN field identical to the gap to the NEXT provider, so
   proximity communicated nothing and a provider's card, fields and disconnect
   link could drift apart in the source. One bordered block per provider now
   makes that structurally impossible.
   --------------------------------------------------------------------------- */

/* Sticky head + scrolling body. Scoped by modifier so #wallet-dialog and
   #hidden-dialog keep the plain single-scroll card. .modal already sets
   max-height, so the card must not set it again.

   `display` MUST stay gated on [open]. A bare `display: flex` on a <dialog>
   beats the UA's `dialog:not([open]) { display: none }` — author styles win over
   UA styles — so the settings dialog rendered permanently in the page flow
   instead of only as a modal. */
.modal--sections { overflow: hidden; }
.modal--sections[open] { display: flex; flex-direction: column; }
.modal--sections .modal-card { display: flex; min-height: 0; flex-direction: column; padding: 0; }
.modal--sections .modal-head {
    flex: 0 0 auto;
    padding: 24px 27px 15px;
    border-bottom: 1px solid var(--line);
    background: var(--modal-bg);
}
.modal--sections .modal-body { overflow-y: auto; padding: 20px 27px 26px; overscroll-behavior: contain; }

.settings-group + .settings-group { margin-top: 24px; padding-top: 20px; border-top: 1px solid var(--line); }
.settings-group__title { margin: 0; }
.settings-group__hint { margin: 7px 0 0; color: var(--muted); font-size: 10px; line-height: 1.5; }
.settings-group__title + .provider,
.settings-group__hint + .provider,
.settings-group__title + .pref-form { margin-top: 14px; }

.provider {
    overflow: hidden;
    margin-bottom: 10px;
    border: 1px solid var(--line);
    border-radius: 13px;
    background: color-mix(in srgb, var(--text) 4%, var(--modal-bg));
}
.provider:last-child { margin-bottom: 0; }
.provider__summary {
    display: grid;
    grid-template-areas:
        "logo name  badge chev"
        "logo desc  badge chev";
    grid-template-columns: 38px minmax(0, 1fr) auto 12px;
    align-items: center;
    gap: 2px 12px;
    padding: 12px 13px;
    list-style: none;
    cursor: pointer;
}
.provider__summary::-webkit-details-marker { display: none; }
/* The block clips overflow, so the global 3px-offset ring would be cut off. */
.provider > summary:focus-visible { outline-offset: -2px; }
.provider[open] > summary { border-bottom: 1px solid var(--line); }
.provider__summary::after {
    grid-area: chev;
    align-self: center;
    color: var(--muted);
    font-size: 10px;
    transition: transform .18s ease;
    content: "▾";
}
.provider[open] > .provider__summary::after { transform: rotate(180deg); }
.provider__logo {
    grid-area: logo;
    display: grid;
    width: 38px;
    height: 38px;
    place-items: center;
    border: 1px solid color-mix(in srgb, var(--aqua) 38%, transparent);
    border-radius: 11px;
    background: color-mix(in srgb, var(--aqua) 18%, var(--modal-bg));
    color: var(--text);
    font-size: 12px;
    font-weight: 900;
    letter-spacing: -.3px;
}
.provider__name { grid-area: name; align-self: end; font-size: 12px; }
.provider__desc { grid-area: desc; align-self: start; color: var(--muted); font-size: 10px; line-height: 1.4; }
.provider__summary .connection-badge { grid-area: badge; align-self: center; justify-self: end; }
.provider__body { padding: 14px 13px; }
.provider__hint { margin: 0 0 13px; color: var(--muted); font-size: 10px; line-height: 1.5; }
/* Not .button--wide: three stacked full-bleed bars read as an onboarding wizard,
   and its 50px min-height is silently defeated by the monarch .button override. */
.provider__submit { justify-self: end; }
.provider__body form { display: grid; justify-items: stretch; }

/* Key + secret read as one credential unit; they stack below ~370px on their own. */
.credential-pair { display: grid; grid-template-columns: repeat(auto-fit, minmax(168px, 1fr)); gap: 0 11px; }

/* --lime is an ACCENT token, not a semantic success colour. Painting
   "connected" with it rendered accent-on-accent at ~3:1. Explicit pair here,
   palette override below, same as the .alert--* idiom. */
.connection-badge {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 9px;
    border-radius: 20px;
    background: rgba(255,154,169,.14);
    color: #ff9aa9;
    font-size: 9px;
    font-weight: 750;
    white-space: nowrap;
}
.connection-badge::before { width: 5px; height: 5px; flex: 0 0 auto; border-radius: 50%; background: currentColor; content: ""; }
.connection-badge.connected { background: rgba(168,224,95,.15); color: #a8e05f; }

/* A destructive action gets its own zone and shape — not a smaller, quieter
   copy of the primary CTA sitting in the next tab stop. */
.disconnect-form {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    margin: 0;
    padding: 10px 13px;
    border-top: 1px solid var(--line);
    background: color-mix(in srgb, var(--danger) 7%, transparent);
    text-align: left;
}
.disconnect-form p { margin: 0; color: var(--muted); font-size: 10px; line-height: 1.45; }
.disconnect-form button {
    display: inline-flex;
    min-height: 32px;
    flex: 0 0 auto;
    align-items: center;
    padding: 0 12px;
    border: 1px solid color-mix(in srgb, var(--danger) 45%, transparent);
    border-radius: 9px;
    background: transparent;
    color: var(--danger);
    font-size: 10px;
    font-weight: 700;
    cursor: pointer;
}
.disconnect-form button:hover { border-color: var(--danger); background: color-mix(in srgb, var(--danger) 12%, transparent); }

/* Preferences get a row shape deliberately unlike the credential shape, so the
   dialog stops reading as one undifferentiated form. */
.pref-form { margin: 0; }
.pref-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 16px; padding: 13px 0; }
.pref-form + .pref-form .pref-row { border-top: 1px solid var(--line); }
.pref-row__copy { display: grid; min-width: 0; gap: 3px; }
.pref-row__copy label { cursor: pointer; }
.pref-row__copy strong { color: var(--text); font-size: 12px; font-weight: 650; }
.pref-row__copy small { color: var(--muted); font-size: 10px; font-weight: 500; line-height: 1.45; }
.pref-row input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--lime); cursor: pointer; }

/* One block per sync source. Each is its own form so a save posts only that
   scope, and the "run now" POST stays a sibling rather than a nested form. */
.sync-scope { margin-top: 14px; padding: 13px 14px; border: 1px solid var(--line); border-radius: 12px; background: var(--panel-2); }
.sync-scope__head { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center; gap: 14px; }
.sync-scope__head input[type="checkbox"] { width: 18px; height: 18px; margin: 0; accent-color: var(--lime); cursor: pointer; }
.sync-scope__controls { display: flex; align-items: flex-end; gap: 9px; margin-top: 12px; }
.sync-scope__controls .field { flex: 1 1 auto; margin: 0; }
.sync-scope__status { margin: 10px 0 0; color: var(--muted); font-size: 9px; line-height: 1.5; }
.sync-scope__run { margin-top: 8px; }

.chain-matrix { margin-top: 14px; }
.chain-matrix__head, .chain-matrix__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 58px 58px;
    align-items: center;
    gap: 10px;
}
.chain-matrix__head { padding-bottom: 8px; border-bottom: 1px solid var(--line); color: var(--muted); font-size: 8px; font-weight: 700; letter-spacing: .7px; text-transform: uppercase; }
.chain-matrix__head > :nth-child(n+2), .chain-matrix__row > :nth-child(n+2) { justify-self: center; }
.chain-matrix__row { padding: 9px 0; border-bottom: 1px solid var(--line); }
.chain-matrix__name { display: flex; align-items: center; overflow: hidden; gap: 8px; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
.chain-matrix__name i { width: 8px; height: 8px; flex: 0 0 auto; border-radius: 50%; background: var(--token-color); }
.chain-matrix input[type="checkbox"] { width: 17px; height: 17px; margin: 0; accent-color: var(--lime); cursor: pointer; }
.chain-matrix__na { color: #5c6f6a; font-size: 11px; }
.chain-matrix button { margin-top: 14px; }

.quota-alert {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 12px;
    margin-top: 12px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-left: 2px solid var(--warning);
    border-radius: 11px;
    background: var(--panel-2);
}
.quota-alert > div { display: grid; min-width: 0; gap: 3px; }
.quota-alert strong { font-size: 11px; }
.quota-alert small { color: var(--muted); font-size: 9px; line-height: 1.45; }
.usage-line b { color: var(--text); font-weight: 750; }
.manual-badge { justify-self: end; padding: 2px 7px; border-radius: 20px; background: rgba(247,178,103,.14); color: var(--warning); font-size: 7px; font-weight: 750; letter-spacing: .4px; text-transform: uppercase; }

/* Two options, so a segmented control instead of a dropdown: no JS, no
   arrow-key submit trap, and it reads less like a generic admin form. */
.segmented { display: inline-flex; padding: 3px; border: 1px solid var(--line); border-radius: 10px; background: var(--bg-soft); }
.segmented__option {
    min-height: 28px;
    padding: 0 11px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    font-size: 11px;
    font-weight: 700;
    cursor: pointer;
}
.segmented__option.is-active { background: color-mix(in srgb, var(--lime) 16%, transparent); color: var(--lime); }
.hidden-list { display: grid; gap: 8px; }
.hidden-asset { display: grid; grid-template-columns: 34px 1fr auto; align-items: center; gap: 10px; padding: 10px; border: 1px solid var(--line); border-radius: 11px; }
.hidden-asset .token-fallback { width: 32px; height: 32px; }
.hidden-asset > div { display: grid; gap: 2px; }
.hidden-asset strong { font-size: 10px; }
.hidden-asset small { color: var(--muted); font-size: 8px; }
.button--mini { min-height: 30px; padding: 0 10px; background: rgba(200,241,105,.1); color: var(--lime); font-size: 8px; }

.auth-shell { display: grid; min-height: 100vh; grid-template-columns: 1.1fr .9fr; }
.auth-intro {
    position: relative;
    display: flex;
    overflow: hidden;
    flex-direction: column;
    justify-content: space-between;
    padding: clamp(30px, 5vw, 72px);
    background:
        linear-gradient(140deg, rgba(200,241,105,.08), transparent 34%),
        linear-gradient(30deg, #0b191d, #071115);
}
.auth-intro::after {
    position: absolute;
    right: -160px;
    bottom: -180px;
    width: 540px;
    height: 540px;
    border: 1px solid rgba(200,241,105,.12);
    border-radius: 50%;
    box-shadow: 0 0 0 70px rgba(200,241,105,.018), 0 0 0 140px rgba(115,210,222,.012);
    content: "";
}
.auth-copy { position: relative; z-index: 1; max-width: 630px; }
.auth-copy h1 { margin: 18px 0 25px; font-size: clamp(45px, 6vw, 82px); letter-spacing: -5px; line-height: .92; }
.auth-copy h1 em { color: var(--lime); font-family: Georgia, serif; font-weight: 400; }
.auth-copy p { max-width: 510px; color: #8fa49f; font-size: clamp(14px, 1.5vw, 18px); line-height: 1.7; }
.auth-proof { position: relative; z-index: 1; display: flex; gap: 25px; color: #718681; font-size: 10px; text-transform: uppercase; letter-spacing: .8px; }
.auth-proof span { display: flex; align-items: center; gap: 8px; }
.auth-panel { display: grid; place-items: center; padding: 30px; background: #0b171b; }
.login-card { width: min(100%, 395px); }
.login-card__head { margin-bottom: 30px; }
.login-card__head h2 { margin: 8px 0 7px; font-size: 33px; letter-spacing: -1.5px; }
.login-card__head p { margin: 0; color: var(--muted); }
.check-row { display: flex; align-items: center; gap: 8px; margin: 3px 0 21px; color: var(--muted); font-size: 10px; }
.check-row input { accent-color: var(--lime); }
.security-note { display: flex; align-items: center; justify-content: center; gap: 7px; margin: 19px 0 0; color: #526762; font-size: 8px; }

@media (max-width: 1100px) {
    .hero-grid, .content-grid { grid-template-columns: 1fr; }
    .allocation-body { justify-content: center; }
    .wallets-panel { order: -1; }
}

@media (max-width: 760px) {
    body { padding-bottom: 70px; }
    .sidebar { display: none; }
    .workspace { margin: 0; padding: 24px 15px 30px; }
    .topbar { align-items: center; }
    .freshness { display: none; }
    /* Left over from the "add wallet" button this bar used to carry: it blanked the
       label and drew a "+" instead. That button moved to the wallets page, so the
       only thing still matching was "Sync now" — which the phone therefore showed
       as a plus sign that did something else entirely. */
    .topbar-actions .button { padding: 0 14px; font-size: 12px; }
    /* The heading and the actions cannot share one line at 375px; without wrapping,
       the actions push the whole page into a sideways scroll. */
    .topbar { flex-wrap: wrap; gap: 12px; }
    .topbar-actions { flex: 1 1 100%; justify-content: space-between; gap: 10px; }
    .setup-banner { align-items: flex-start; }
    .setup-banner p { display: none; }
    .setup-banner .button { padding: 0 12px; font-size: 10px; }
    .hero-grid, .content-grid, .dash-stack { gap: 13px; }
    .net-worth-card { min-height: 330px; padding-inline: 20px; }
    .allocation-card, .panel { padding: 20px 17px; }
    .allocation-body { gap: 17px; }
    .donut { width: 115px; height: 115px; }
    .donut::before { width: 71px; height: 71px; }
    .asset-row { grid-template-columns: minmax(150px, 1fr) 80px 26px; min-height: 66px; }
    .asset-row > :nth-child(2), .asset-row > :nth-child(3), .asset-row > :nth-child(4) { display: none; }
    .asset-row--head > :nth-child(5) { display: block; }
    .table-filter { display: none; }
    /* Same treatment as .asset-row: keep the identity and the value, drop the
       intermediate columns rather than letting the row wrap. */
    .nft-grid { grid-template-columns: 1fr; }
    .page-stats { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .page-stats strong { font-size: 15px; }
    .mobile-nav {
        position: fixed;
        z-index: 30;
        right: 0;
        bottom: 0;
        left: 0;
        display: grid;
        /* Auto-flow columns rather than a fixed repeat(6): the add button only
           renders on the wallets page, so the item count varies. minmax(0, 1fr),
           not 1fr: the default min-content floor lets the longest label
           ("Transactions") widen every column and push the page into a horizontal
           scroll. */
        grid-auto-flow: column;
        grid-auto-columns: minmax(0, 1fr);
        padding: 9px 8px max(9px, env(safe-area-inset-bottom));
        border-top: 1px solid var(--line);
        background: rgba(7,17,21,.96);
        backdrop-filter: blur(16px);
    }
    /* Underline tabs rather than a filled pill: every colour here is a palette token,
       so this needs no entry in the "Responsive × palette" block at the end of the
       file — unlike a rule that hardcodes a wash, which has to be restated wherever
       the palette section overrides it.
       overflow-x for the three-item groups at 320px; the row never wraps. */
    .section-nav {
        display: flex;
        margin-bottom: 18px;
        overflow-x: auto;
        border-bottom: 1px solid var(--line);
        scrollbar-width: none;
    }
    .section-nav::-webkit-scrollbar { display: none; }
    .section-nav a {
        min-width: 0;
        flex: 1 1 0;
        /* -1px so the active underline sits on the container's own border rather than
           under it, which would read as a two-line rule. */
        margin-bottom: -1px;
        padding: 10px 8px;
        border-bottom: 2px solid transparent;
        color: var(--muted);
        font-size: 10px;
        font-weight: 650;
        text-align: center;
        white-space: nowrap;
    }
    .section-nav a.active { border-bottom-color: var(--lime); color: var(--text); }
    .mobile-nav a, .mobile-nav button { display: grid; min-width: 0; gap: 3px; place-items: center; border: 0; background: transparent; color: #637772; font-size: 17px; }
    .mobile-nav span { max-width: 100%; overflow: hidden; font-size: 7px; text-overflow: ellipsis; white-space: nowrap; }
    .mobile-nav .active { color: var(--lime); }
    .auth-shell { grid-template-columns: 1fr; }
    .auth-intro { min-height: 38vh; padding: 28px; }
    .auth-copy h1 { margin: 30px 0 14px; font-size: 48px; letter-spacing: -3px; }
    .auth-copy p { display: none; }
    .auth-proof { display: none; }
    .auth-panel { min-height: 62vh; padding: 35px 25px; }
}

@media (max-width: 430px) {
    .allocation-body { align-items: flex-start; }
    .donut { width: 95px; height: 95px; }
    .donut::before { width: 59px; height: 59px; }
    .donut strong { font-size: 17px; }
    .metric-strip > div { padding-left: 9px; }
    .wallet-card { grid-template-columns: 34px minmax(0, 1fr) auto; padding: 10px; }
    .wallet-icon { width: 32px; height: 32px; }
    .wallet-board { grid-template-columns: minmax(0, 1fr); }
    .wallet-panel { padding: 13px; }
    .wallet-panel__head { grid-template-columns: 34px minmax(0, 1fr) auto; }
    .modal-card { padding: 22px 19px; }

    /* .modal--sections .modal-card (0,2,0) keeps its edge-to-edge padding: 0
       over the (0,1,0) rule above regardless of source order. */
    .modal--sections .modal-head { padding: 20px 19px 13px; }
    .modal--sections .modal-body { padding: 17px 19px 22px; }
    /* The badge cannot share a row with the name at this width, so it drops
       under the description and the summary becomes three rows. */
    .provider__summary {
        grid-template-areas:
            "logo name  chev"
            "logo desc  chev"
            "logo badge chev";
        grid-template-columns: 34px minmax(0, 1fr) 12px;
    }
    .provider__logo { width: 34px; height: 34px; }
    .provider__summary .connection-badge { justify-self: start; margin-top: 5px; }
    .disconnect-form { flex-wrap: wrap; }
    .pref-row { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    .pref-row > :last-child { justify-self: start; }
}

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { scroll-behavior: auto !important; animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

html .asset-note { color: #8a8183; }
/* The white wash behind the "soon" badge disappears on a cream surface. */
html .source-outlook__grid strong small { background: #efe9e5; color: #857c7e; }

/* The readable pair for the badge, since the accent cannot carry "connected"
   on its own wash — that measured 2.95:1. Mirrors the .alert--* idiom. */
html .connection-badge { background: #fdeaee; color: #8d2233; }
html .connection-badge.connected { background: #e7f6ef; color: #14603e; }

/* Muted copy sits on tinted surfaces here (a 4% text wash, and a 7% danger wash
   in the disconnect strip), which drags --muted under 4.5:1.
   Darkened just for this block rather than globally. */
html .provider__desc,
html .provider__hint,
html .disconnect-form p { color: #5f574f; }

/* The danger wash over an already-tinted provider block is what pushed the
   contrast down; keep the zone legible by leaning on the border instead. */
html .disconnect-form { background: color-mix(in srgb, var(--danger) 4%, transparent); }

/* The base alert colours were drawn for a dark backdrop, where pale lime/pink
   text reads; against a near-white panel it washes out. */
html .alert--success {
    border-color: rgba(47, 157, 114, .32);
    background: #e7f6ef;
    color: #14603e;
}
html .alert--error {
    border-color: rgba(199, 62, 84, .32);
    background: #fdeaee;
    color: #8d2233;
}

/* ---------------------------------------------------------------------------
   The palette, from the claude.ai/design "budget.alexzuev.com" project.
   A warm-neutral paper ground (#f5f5f3) with white cards, a single hairline
   border instead of a shadow, and a forest-green accent; spending is terracotta
   and the net-worth line is a muted teal, so growth and outflow never share a
   colour. Compact by construction: 14px body, 13-15px card titles, and figures
   that sit ON the baseline of their label rather than under it as a hero number.

   Two greys are DELIBERATELY darker than the design file. It specifies #8a8a82 for
   secondary copy and #a3a39b for captions, which measure 3.48:1 and 2.54:1 on white —
   both under WCAG AA, and the second is the same class of mistake as the #aebeba field
   labels noted further up this file. They are #6d6d66 (5.21:1) and #77776f (4.51:1)
   here; the first is the design's own body-secondary, so the palette is unchanged, only
   the assignment. `.workspace-footer` takes #6d6d66 rather than #77776f because it sits
   on the page ground, where #77776f falls back to 4.13:1.

   Type stays Inter. The design specifies Figtree, which draws no Cyrillic — and
   the source copy in every Blade view is Russian, so Figtree would fall back
   mid-sentence to whatever the OS offers. Same reasoning as the font note at
   the top of this file.
   --------------------------------------------------------------------------- */

html .sidebar {
    width: 232px;
    padding: 16px 12px 14px;
    border-right: 1px solid var(--line);
    background: #fbfbfa;
    backdrop-filter: none;
}
html .brand { gap: 10px; padding: 6px 8px 2px; font-size: 15.5px; font-weight: 700; letter-spacing: -.015em; }
html .brand-mark { width: 28px; height: 28px; border-radius: 9px; color: #fff; font-size: 14px; font-weight: 700; box-shadow: none; }
html .main-nav { gap: 1px; margin-top: 20px; }
html .nav-link {
    min-height: 0;
    gap: 11px;
    padding: 8px 11px;
    border-radius: 9px;
    color: #55554e;
    font-size: 14px;
    font-weight: 400;
}
/* The design marks a destination with a dot, not a glyph — so the emoji in the
   markup becomes the dot rather than being deleted from every view. font-size:0
   is what hides it; the background paints the dot. */
html .nav-link > span {
    width: 6px;
    height: 6px;
    flex: 0 0 6px;
    border-radius: 999px;
    background: #c9c8c1;
    font-size: 0;
}
html .nav-link:hover { background: #efeeea; color: var(--text); }
html .nav-link.active { background: #efeeea; color: var(--text); font-weight: 600; }
html .nav-link.active > span { background: var(--lime); }
html .nav-link small { background: transparent; color: #77776f; font-size: 8px; }
/* Groups are separated by space, not a rule — four hairlines down a 232px
   column read as a table of contents rather than a nav. */
html .main-nav > .nav-group { gap: 1px; margin-top: 16px; padding-top: 0; border-top: 0; }
html .nav-group__title { padding: 4px 11px 6px; color: #77776f; font-size: 10.5px; font-weight: 600; letter-spacing: .1em; }
html .sidebar-foot { gap: 2px; }
html .profile { gap: 10px; padding-top: 10px; border-top: 1px solid var(--line); }
html .avatar { width: 26px; height: 26px; border: 0; background: var(--lime); color: #fff; font-size: 12px; font-weight: 700; }
html .profile-copy strong { font-size: 13px; font-weight: 600; }
html .profile-copy small { color: #77776f; font-size: 11px; }
/* The glyph became an SVG, so the button has to centre a box rather than a line
   of text — the inherited line-height left it sitting a couple of pixels high. */
html .icon-button {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0;
    border-radius: 8px;
    color: #a3a39b;
}
html .icon-button svg { display: block; }
html .icon-button:hover { background: #efeeea; color: var(--danger); }

/* The header is a full-bleed sticky bar in the design, so it breaks out of the
   workspace's own inline padding rather than floating inside it. */
html .workspace { margin-left: 232px; padding: 0 24px 28px; }
html .topbar {
    position: sticky;
    z-index: 5;
    top: 0;
    align-items: center;
    gap: 24px;
    margin: 0 -24px 20px;
    padding: 16px 24px;
    border-bottom: 1px solid var(--line);
    background: #fbfbfa;
}
html .eyebrow { display: none; }
html .topbar h1 { margin: 0; font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
html .topbar-actions { gap: 10px; }
html .freshness { color: #77776f; font-size: 12.5px; }
html .status-dot { width: 7px; height: 7px; box-shadow: none; }

html .button { min-height: 34px; gap: 8px; padding: 0 16px; border-radius: 8px; font-size: 13px; font-weight: 600; }
html .button:hover { transform: none; }
html .button--ghost { border-color: #e0dfd9; background: #fff; color: #55554e; }
html .button--ghost:hover { border-color: #cfcec6; background: #f5f5f3; }
html .button--primary { color: #fff; box-shadow: none; }
html .button--primary:hover { background: #0c6446; }
html .button--mini { font-size: 11px; }

/* One border, one radius, no shadow — repeated across every surface in the
   design, which is what makes the page read as a single sheet of cards. */
html .net-worth-card,
html .allocation-card,
html .panel {
    border-color: var(--line);
    border-radius: 14px;
    background: #fff;
    box-shadow: none;
}
html .dash-stack,
html .hero-grid { gap: 16px; }
/* The stack's gap is the only spacing between its children — margins that predate it
   would add to it and break the rhythm the design keeps at a flat 16px. */
html .dash-stack > .page-note { margin-top: 0; }
html .dash-stack > .section-head--standalone { margin-bottom: 0; }
html .content-grid { gap: 16px; margin-top: 16px; }
html .hero-grid { grid-template-columns: minmax(0, 1.55fr) minmax(320px, 1fr); }

/* padding-bottom is not 0 any more: `.net-worth-card--flow` clears it for the
   pages where the chart runs to the card edge, but here the last thing in the card
   is a paragraph, and it was resting on the border. */
html .net-worth-card { min-height: 330px; padding: 18px 20px 0; }
html .hero-grid > .net-worth-card { padding-bottom: 18px; }
html .net-worth-card::after { display: none; }
/* Card titles are sentence-case labels here, not letterspaced eyebrows. */
html .card-heading { color: #55554e; font-size: 15px; font-weight: 600; letter-spacing: 0; }
/* The design's own values. Warm sand rather than the accent green: the pill says
   "these figures were imported, not fetched live", which is a caveat — and a green
   badge reads as confirmation of exactly the opposite. */
html .privacy-pill {
    padding: 6px 11px;
    border: 0;
    border-radius: 7px;
    background: #f6ece5;
    color: #a34a1f;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .08em;
}
html .net-worth-value { margin-top: 10px; font-size: clamp(26px, 2.6vw, 32px); font-weight: 700; letter-spacing: -.025em; }
html .net-worth-value small { font-size: .5em; }
html .change-row { margin-top: 8px; font-size: 13.5px; font-weight: 600; }
html .change-row span { border-radius: 6px; background: var(--lime-dark); }
html .change-row small { color: #77776f; font-size: 12.5px; }
html .chart-wrap { inset: 118px 0 30px; }
html .chart-empty { color: #77776f; font-size: 11.5px; }

/* Segmented pill: a sunken track with the active tab lifted out in white. The
   design uses this for the chart range, the table filters and the settings
   segmented control, so all three are restated together. */
html .chart-range { right: 20px; bottom: 10px; gap: 2px; padding: 3px; border-radius: 9px; background: #f2f1ed; }
html .chart-range button { padding: 5px 10px; border-radius: 7px; color: #6d6d66; font-size: 11px; font-weight: 600; }
html .chart-range button.active { background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(40, 38, 32, .09); }
html .table-filter,
html .segmented { gap: 2px; padding: 3px; border: 0; border-radius: 9px; background: #f2f1ed; }
html .table-filter button,
html .table-filter a,
html .segmented__option { padding: 6px 13px; border-radius: 7px; color: #6d6d66; font-size: 12.5px; font-weight: 600; }
html .table-filter button.active,
html .table-filter a.active,
html .segmented__option.is-active { background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(40, 38, 32, .09); }

html .allocation-card { padding: 18px 20px 16px; }
html .section-head h2 { font-size: 15px; font-weight: 600; color: #55554e; letter-spacing: 0; }
html .section-head__figure { color: var(--text); font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
html .section-head__sub { margin-left: 6px; }
html .section-head__sub,
html .asset-count { color: #77776f; font-size: 12.5px; }
html .section-link { color: var(--lime); font-size: 12.5px; font-weight: 600; }
html .allocation-body { min-height: 180px; gap: 20px; }
html .donut { width: 112px; height: 112px; box-shadow: none; }
html .donut::before { width: 72px; height: 72px; background: #fff; }
html .donut strong { font-size: 19px; }
html .donut span { color: #77776f; }
html .legend-row > i { box-shadow: none; }
html .legend-row strong,
html .legend-row b { font-size: 12.5px; }
html .legend-row small { color: #77776f; font-size: 11.5px; }

/* Stat strips: uppercase micro-label over a tabular figure, divided by hairline
   rules. Same shape on the overview, the accounts hero and the payments tiles. */
html .metric-strip,
html .flow-stats { gap: 0; padding-top: 13px; }
/* Ruled between cells rather than spaced apart: six figures in a row with nothing
   between them read as one sentence. `:first-child` keeps the run from opening on a
   stray edge. */
html .flow-stats > div { padding: 0 18px; border-left: 1px solid var(--line); }
html .flow-stats > div:first-child { padding-left: 0; border-left: 0; }
html .metric-strip span,
html .flow-stats span,
html .page-stats span,
html .pay-summary__tile span { color: #77776f; font-size: 11px; font-weight: 600; letter-spacing: .07em; }
html .metric-strip strong,
html .flow-stats strong { font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
html .metric-button:hover span { color: var(--lime); }

html .panel { padding: 18px 20px; }
html .dash-stack > .panel:has(.asset-table) { padding: 16px 20px 8px; }
html .page-stats > div,
html .page-stat-button { border-radius: 12px; background: #fff; }
html .page-stats strong { font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
html .page-stat-button:hover { border-color: #cfcec6; }
/* The design's advisory strip: warm sand, not a coloured left rule. */
html .page-note { border-color: #f0e5d4; border-left-width: 1px; border-radius: 12px; background: #fbf5ec; color: #7a6a52; font-size: 12.5px; }
html .page-note--warn strong { color: var(--warning); }
html .chart-note { color: #77776f; font-size: 11.5px; }
/* The sentence that carries the comparison, so it reads at body size in the body
   colour rather than as a footnote under the heading. */
html .chart-note--lead { color: #55554e; font-size: 12.5px; }
html .chart-note--lead b { font-weight: 700; }

/* Rows: hover is a wash, never a border. */
html .asset-row,
html .ledger-row,
html .account-row,
html .pay-row { border-color: #f4f3ef; }
html .asset-row--head,
html .ledger-row--head { color: #77776f; font-size: 10.5px; letter-spacing: .08em; }
/* The hover tint is painted TWICE by the base rule — a background and an 8px spread
   box-shadow that bleeds it past the row's edges. Overriding only the background left
   the shadow drawing the old accent, so the row lit up green on a page with no green
   in it. Both are restated.

   And the meta stays put: the base rule darkens it to --text under the cursor, which
   makes "1 txn · 70.5%" jump from grey to black as the pointer crosses — movement in
   a figure nobody is pointing at. */
html .cat-row:hover,
html .ledger-row:hover,
html .account-row:hover,
html .pay-row:hover { background: #f7f7f5; box-shadow: 0 0 0 8px #f7f7f5; }
html .cat-row:hover .cat-row__meta { color: #77776f; }
html .cat-row__track { background: #efeeea; }
html .cat-row__label { font-size: 13.5px; font-weight: 600; }
html .cat-row__value { font-size: 13.5px; font-weight: 700; }
html .cat-row__meta { font-size: 11.5px; }
/* The two cards head their lists differently in the design: Categories with an
   uppercase micro-label over its total, Income with an ordinary card heading. */
/* Only where a heading row precedes it: in the Income card this block IS the heading,
   and a top margin there would just indent the card. */
html .section-head + .breakdown-col__head { margin-top: 16px; }
html .breakdown-col__head h3 { font-size: 15px; font-weight: 600; color: #55554e; letter-spacing: 0; }
html .breakdown-col__head--label h3 { color: #77776f; font-size: 11px; font-weight: 600; letter-spacing: .08em; text-transform: uppercase; }
html .cat-row__meta { color: #77776f; }

html .flow-col__bars { height: 178px; }
html .flow-col:hover { background: #f2f1ed; }
html .flow-col.is-selected { background: #efeeea; }
html .flow-bar--income { background: var(--lime); }
html .flow-bar--expense { background: var(--danger); }
html .chart-legend span { color: #55554e; font-size: 12px; }

html .leg-chip { gap: 7px; padding: 6px 11px; border-color: #e0dfd9; border-radius: 8px; background: #fff; font-size: 12.5px; }
html .leg-chip:hover { border-color: #cfcec6; }
html .leg-chip.is-on {
    border-color: color-mix(in srgb, var(--leg-colour, var(--lime)) 38%, #e0dfd9);
    background: color-mix(in srgb, var(--leg-colour, var(--lime)) 6%, #fff);
}
/* The design marks a leg with a small square dot, not a tick. Still a real checkbox —
   only its box is redrawn — so the label, keyboard focus and the GET form all behave
   as before; the chip's own border and fill already say whether it is on. */
html .leg-chip input {
    width: 8px;
    height: 8px;
    appearance: none;
    border: 0;
    border-radius: 3px;
    background: #c9c8c1;
}
/* The swatch identifies a source, so it wears that source's own colour rather than
   the accent — eight chips in one green name eight things identically. Off keeps the
   neutral dot: the colour says "this is Pension", the fill says "it is counted". */
html .leg-chip.is-on input { background: var(--leg-colour, var(--lime)); }

/* The annual matrix, to the design's own measurements. Everything inside it ran a
   size or two small against the rest of the page — 11px cells under 13.5px rows
   elsewhere — which read as a different component rather than the same one.
   Two classes on most selectors because the base rules are `.matrix thead th` and
   `.matrix tbody td`, which outrank a lone class. */
html .matrix thead th { color: #77776f; font-size: 10.5px; font-weight: 600; letter-spacing: .06em; }
html .matrix th,
html .matrix td { padding: 7px 8px; }
html .matrix tbody td { font-size: 12.5px; font-weight: 600; }
html .matrix th.matrix-label {
    /* The design's fixed 198px, rather than a 132–168px range: a column that
       resizes with the longest category name moves the whole grid year to year. */
    min-width: 198px;
    max-width: 198px;
    padding-left: 10px;
    font-size: 13px;
    font-weight: 600;
}
html .matrix thead th.matrix-label { font-size: 10.5px; font-weight: 600; }
/* No rule down the Year column — the design separates it by weight and padding
   alone, and a vertical line there cuts the row in two. */
html .matrix th.matrix-year,
html .matrix td.matrix-year { border-left: 0; padding-right: 10px; font-weight: 700; }
html .matrix .matrix-section th { padding: 14px 10px 6px; font-size: 10.5px; font-weight: 700; letter-spacing: .09em; }
html .matrix tbody tr.matrix-section:first-child th,
html .matrix .matrix-section th { color: var(--danger); }
html .matrix .matrix-section--income th { color: var(--positive); }
html .matrix .matrix-section--bottom th { color: #77776f; }
/* A band, not just bold: a summary row sitting in the same white as the twelve
   category rows above it reads as a thirteenth category. */
html .matrix .matrix-sum td,
html .matrix .matrix-sum th { background: #faf9f6; }
html .matrix .matrix-worth td,
html .matrix .matrix-worth th { color: var(--text); background: #f1f4f5; }
html .matrix .matrix-sum td,
html .matrix .matrix-sum th { font-weight: 700; }
html .matrix .matrix-empty { font-size: 12.5px; }
html .matrix tbody tr:hover td,
html .matrix tbody tr:hover th.matrix-label { background: #f7f7f5; }
html .matrix-caption { color: #77776f; font-size: 11.5px; line-height: 1.5; }
@media (max-width: 720px) {
    html .matrix th.matrix-label { min-width: 132px; max-width: 148px; }
}

/* The net-worth header is one baseline: label, figure, change, then the READ ONLY
   pill pushed to the end. The figure is a `span` inside that row now, so it has to
   drop the block-level margins it carried as a standalone hero number. */
html .card-heading { flex-wrap: wrap; align-items: baseline; gap: 4px 12px; justify-content: flex-start; }
html .card-heading > .privacy-pill { margin-left: auto; align-self: center; }
/* Two `auto` margins in one flex row SHARE the free space rather than one winning it,
   which pushed these 167px apart. The tabs take the space; the pill sits beside them. */
html .chart-range--header ~ .privacy-pill { margin-left: 10px; }
html .net-worth-value {
    /* The accounts hero still stacks its figure under the heading, so the margin is
       cleared only where the figure has joined the heading row. */
    margin: 8px 0 0;
    font-size: clamp(24px, 2vw, 28px);
    font-weight: 700;
    letter-spacing: -.025em;
    line-height: 1.1;
}
html .card-heading .net-worth-value { margin: 0; }
/* On the baseline and in the figure's own colour. Raised and greyed, the $ read as
   a footnote marker on the total rather than as part of it. */
html .net-worth-value small { margin-right: 2px; color: inherit; font-size: .62em; font-weight: inherit; vertical-align: baseline; }
html .change-row { margin: 0; gap: 6px; font-size: 13.5px; font-weight: 600; }
html .change-row span { padding: 0; background: none; }
html .card-subtitle { margin: 5px 0 0; color: #77776f; font-size: 12.5px; }

/* The two hero cards share a stretch row, so one of them is always taller and the
   other has to absorb the difference. Whichever card that is depends on the viewport
   — how many legend chips fit on a line, how many lines the footnote wraps to — so
   giving only ONE of them a flexible chart just moves the dead space to the other
   card at a different width, which is exactly what happened: fixing the foot of the
   spending panel put the same gap under the net-worth footnote on a wide screen.

   Both cards are flex columns and in both the CHART takes the slack, so the shorter
   card's chart grows and neither can show dead space at any width. Scoped to the hero
   grid: the accounts page uses these same classes outside a stretch row, where a
   fixed height is right. */
html .hero-grid > .net-worth-card,
html .hero-grid > .panel { display: flex; flex-direction: column; }
/* `flex: 1 1 0`, not `1 1 auto`: the basis has to be zero so the flex algorithm
   decides the height outright, and the canvas has to leave the flow entirely.
   Against an auto-height parent a canvas's `height: 100%` resolves to auto, which
   makes it fall back to its `height` ATTRIBUTE — and the renderer sets that to
   `rect.height * devicePixelRatio`. The parent then grew to the bitmap's height,
   the next redraw doubled it again, and the cards walked from 430px to 650px and
   climbing. Positioned out of flow it cannot feed back. */
html .hero-grid > .net-worth-card > .chart-wrap--inline,
html .hero-grid > .panel > .chart-wrap--panel {
    position: relative;
    /* `inset: auto` is load-bearing. `.chart-wrap` carries an inset for the days it
       was absolutely positioned, and on a RELATIVE box an inset is not a rectangle —
       it is an offset. Left in place it pushed the chart 118px down the card, over
       the legend chips and out through the bottom edge. */
    inset: auto;
    flex: 1 1 0;
    height: auto;
}
html .hero-grid > .net-worth-card > .chart-wrap--inline { min-height: 170px; }
html .hero-grid > .panel > .chart-wrap--panel {
    min-height: 190px;
    /* No max-height. Capping it looks like restraint and is really just the dead
       space again below the cap. */
}
html .hero-grid > .net-worth-card > .chart-wrap--inline > canvas,
html .hero-grid > .panel > .chart-wrap--panel > canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

html .pay-summary__tile strong { font-size: 26px; font-weight: 700; letter-spacing: -.025em; }
/* The third line of a tile: what the figure above it is made of. */
html .pay-summary__tile small { color: #a3a39b; font-size: 11.5px; }
html .payment-date { border-radius: 11px; }

/* Cash against what it has to cover. The bar is the answer; the two figures
   beside it are the working. */
html .pay-coverage {
    display: grid;
    gap: 9px;
    margin-top: 14px;
    padding: 13px 15px;
    border-radius: 11px;
    background: #f7f7f5;
}
html .pay-coverage__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
html .pay-coverage__head b { font-size: 13px; font-weight: 700; }
html .pay-coverage__head span { color: #6d6d66; font-size: 12.5px; font-variant-numeric: tabular-nums; }
html .pay-coverage small { color: #6d6d66; font-size: 11.5px; }
html .pay-coverage__track,
html .plan-row__track {
    display: block;
    overflow: hidden;
    height: 6px;
    border-radius: 999px;
    background: #e6e5e0;
}
html .pay-coverage__track i { display: block; height: 100%; border-radius: 999px; background: #0f7a55; }
/* Over 100% the bar is already full, so the colour is the only thing left to
   carry "this does not cover it". */
html .pay-coverage__track i.over { background: #c0562a; }

/* The next deposit, given the prominence of an answer rather than a list row —
   it is the date the whole period above is measured to. */
html .pay-next {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    margin: 12px 0 4px;
    padding: 13px 15px;
    border-radius: 11px;
    background: #eef5f1;
}
html .pay-next span { display: flex; flex-direction: column; line-height: 1.3; }
html .pay-next b { font-size: 13px; font-weight: 700; color: #2f6b55; }
html .pay-next small { color: #5c8574; font-size: 11.5px; }
html .pay-next > b { font-size: 18px; font-variant-numeric: tabular-nums; color: #0f7a55; }
html .pay-list__label {
    display: block;
    padding: 8px 0 2px;
    color: #a3a39b;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
}

/* An instalment plan reads as progress through a term, so the term is the row. */
html .plan-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 180px 140px 28px;
    align-items: center;
    gap: 0 20px;
    margin: 0 -10px;
    padding: 13px 10px;
    border-radius: 10px;
}
html .plan-row:hover { background: #f7f7f5; }
html .plan-row__name { display: flex; min-width: 0; flex-direction: column; gap: 4px; line-height: 1.35; }
html .plan-row__name strong { overflow: hidden; font-size: 13.5px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
html .plan-row__name small { overflow: hidden; color: #a3a39b; font-size: 11.5px; text-overflow: ellipsis; white-space: nowrap; }
html .plan-row__progress { display: grid; gap: 6px; }
html .plan-row__legend { display: flex; justify-content: space-between; color: #6d6d66; font-size: 11.5px; font-variant-numeric: tabular-nums; }
html .plan-row__track { height: 5px; background: #efeeea; }
html .plan-row__track i { display: block; height: 100%; border-radius: 999px; background: #37648c; }

/* A cash or deposit row is separated by a rule, as the design has it. The tight
   11px stack read as a paragraph rather than a list, and the first row sat close
   enough to the heading to look like part of it. */
html .pay-list { gap: 0; }
html .pay-list li {
    align-items: center;
    padding: 10px 0;
    border-bottom: 1px solid #f4f3ef;
    font-size: 13.5px;
}
html .pay-list li:last-child { border-bottom: 0; }
html .pay-list b { font-size: 13.5px; }
html .pay-list__more { font-size: 12px; }
/* The two-up row stretches, so the note goes to the bottom of whichever card is
   shorter instead of leaving a gap under it. */
html .pay-grid { align-items: stretch; }
html .pay-grid > .panel { display: flex; flex-direction: column; }
html .pay-grid > .panel > .asset-note { margin: auto 0 0; padding-top: 12px; }
html .pay-grid > .panel > .pay-list + .asset-note { border-top: 1px solid #f4f3ef; }

/* One card with three cells, not three cards mortared together. The 1px gap over
   a `--line` background drew a full-width band above the caption, which read as a
   separate strip sitting on the page rather than the card's own footnote. The
   stack owns the spacing above it, so the margin goes. */
html .pay-summary {
    gap: 0;
    margin-top: 0;
    padding: 4px 20px 16px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
}
/* The period switch, above the tiles and right-aligned. `position: static` is
   load-bearing: the base `.chart-range` is absolute, pinned to the bottom-right of
   the net-worth card it was written for, and left alone here it floated out of the
   summary and landed on top of the charge list below. */
html .pay-range {
    position: static;
    right: auto;
    bottom: auto;
    grid-column: 1 / -1;
    justify-self: end;
    margin: 10px 18px 2px;
}
html .pay-range a {
    padding: 5px 10px;
    border-radius: 7px;
    color: #6d6d66;
    font-size: 12px;
    font-weight: 600;
}
html .pay-range a.active { background: #eef1ee; color: var(--lime); }

html .pay-summary__tile { padding: 16px 18px 14px; border-right: 1px solid #eeede8; }
html .pay-summary__tile:nth-child(3) { border-right: 0; }
html .pay-summary__caption {
    margin: 8px 18px 0;
    padding: 12px 0 0;
    border-top: 1px solid #eeede8;
    color: #6d6d66;
    font-size: 12.5px;
}
html .pay-summary__caption b { color: #a34a1f; font-weight: 600; }

/* Every panel on this page opens with a ruled header, as the design has them.
   Scoped by what the panel contains rather than applied to `.section-head`
   globally, so the accounts and overview pages keep the headers already signed
   off there. */
html .panel:has(.pay-list, .pay-row, .plan-row) > .section-head {
    padding-bottom: 11px;
    border-bottom: 1px solid #eeede8;
}
html .pay-cadence {
    padding: 4px 10px;
    border-radius: 6px;
    background: #f2f1ed;
    color: #6d6d66;
    font-size: 12.5px;
    font-weight: 600;
}
/* Written as `html .` and placed after the responsive block on purpose: a plain
   `.plan-row` inside a breakpoint would lose to the rule above it, which is the
   bug that left every panel 119px wide on a phone. */
@media (max-width: 900px) {
    html .plan-row { grid-template-columns: minmax(0, 1fr) auto 28px; gap: 0 14px; }
    html .plan-row__progress { display: none; }
}
/* Pale tint, saturated letter — the dark theme's disc (42% 22%) survived the
   repaint because nothing here was keyed to a token. Applies to /accounts too. */
html .account-avatar { background: hsl(var(--seed, 210) 56% 88%); color: hsl(var(--seed, 210) 45% 31%); }
html .account-avatar,
html .wallet-icon { box-shadow: none; }
html .wallet-card,
html .wallet-panel,
html .source-outlook__grid article,
html .nft-card-panel,
html .nft-strip-card { border-color: var(--line); border-radius: 12px; background: #fff; }
html .nft-thumb { background: #f5f5f3; }
html .add-wallet-inline { border-color: #d9d8d0; border-radius: 12px; }
html .add-wallet-inline:hover { border-color: var(--lime); background: var(--lime-dark); }
html .wallet-panel__note { color: var(--warning); }
html .workspace-footer { color: #6d6d66; }
html .empty-state .empty-icon { color: #d3d2ca; }

html .modal { border-color: var(--line); border-radius: 14px; box-shadow: 0 24px 60px rgba(40, 38, 32, .16); }
html .modal::backdrop { background: rgba(43, 40, 34, .28); }
html .modal-head h2 { font-size: 19px; font-weight: 700; letter-spacing: -.02em; }
html .modal-intro { color: #6d6d66; font-size: 12.5px; }
html .field > span { color: #55554e; font-size: 12px; font-weight: 600; letter-spacing: 0; }
html .field input,
html .field select { height: 40px; border-color: #e0dfd9; border-radius: 8px; background: #fff; }
html .field input::placeholder { color: #77776f; }
html .field input:focus,
html .field select:focus { border-color: var(--lime); }
html .provider { border-radius: 12px; }
html .safe-callout { background: var(--lime-dark); color: #2f6b55; }
html .safe-callout strong { color: #14603e; }
html .modal-tabs button[aria-selected="true"] { color: var(--lime); }

html .mobile-nav { background: rgba(251, 251, 250, .96); }
html .auth-intro { background: linear-gradient(145deg, #e6efe9, #f7f7f4); }
html .auth-panel { background: #fff; }

/* ---- Banking: ledger + accounts -------------------------------------------
   The ledger reuses .asset-table's spacing but needs its own column template:
   a transaction is date/name/category/account/amount, not asset/balance/price. */
.ledger-filters {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    align-items: end;
    gap: 10px;
    margin-top: 16px;
}
.ledger-filters .field { margin-bottom: 0; }
.ledger-filters .button { height: 45px; }
/* Sized to the inputs beside it so the row of filters keeps one baseline. Written as
   `.field > .filter-chip`, because `.field > span` is (0,1,1) and later in the file —
   a lone `.filter-chip` would lose its colour and size to the field-label rule. */
.field > .filter-chip {
    display: flex;
    height: 45px;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 0 10px 0 12px;
    border: 1px solid var(--line);
    border-radius: 10px;
    background: var(--panel-2);
    color: var(--text);
    font-size: 12px;
    font-weight: 400;
    letter-spacing: 0;
}
.filter-chip b { overflow: hidden; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.filter-chip a { color: var(--muted); font-size: 15px; line-height: 1; }
.filter-chip a:hover { color: var(--text); }

.ledger-row {
    display: grid;
    /* Sixth column is the row action, sized to the button so rows without one line
       up with rows that have it. */
    grid-template-columns: minmax(96px, .7fr) minmax(200px, 1.7fr) minmax(120px, .9fr) minmax(120px, .9fr) minmax(96px, .7fr) 28px;
    align-items: center;
    min-height: 56px;
    padding: 9px 0;
    border-bottom: 1px solid var(--line);
    gap: 12px;
    font-size: 12px;
}
.ledger-row:last-child { border-bottom: 0; }
.ledger-row--head { min-height: 31px; padding: 0; color: #60736e; font-size: 8px; font-weight: 700; letter-spacing: .8px; text-transform: uppercase; }
/* Excluded-from-reports rows stay visible but read as set aside: they are in the
   list, and they are deliberately not in the totals above it. */
.ledger-row--muted { opacity: .55; }
.ledger-date { display: grid; gap: 3px; color: var(--muted); font-size: 11px; }
.ledger-name { display: grid; min-width: 0; gap: 3px; }
.ledger-name strong { overflow: hidden; font-size: 12px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.ledger-name small, .ledger-category, .ledger-account { overflow: hidden; color: var(--muted); font-size: 10px; text-overflow: ellipsis; white-space: nowrap; }
.ledger-amount { font-size: 13px; font-weight: 720; letter-spacing: -.3px; text-align: right; font-variant-numeric: tabular-nums; }
.ledger-flag {
    justify-self: start;
    padding: 2px 6px;
    border: 1px solid var(--line);
    border-radius: 20px;
    color: var(--muted);
    font-size: 8px;
    letter-spacing: .4px;
    text-transform: uppercase;
}

.pager { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 20px; }
.pager__page { color: var(--muted); font-size: 10px; letter-spacing: .5px; text-transform: uppercase; }
.pager [aria-disabled="true"] { opacity: .4; pointer-events: none; }

.account-row {
    display: grid;
    grid-template-columns: minmax(200px, 2fr) minmax(110px, .8fr) minmax(110px, .8fr) auto;
    align-items: center;
    min-height: 62px;
    padding: 9px 0;
    border-bottom: 1px solid var(--line);
    gap: 12px;
}
.account-row:last-child { border-bottom: 0; }
.account-row--hidden { opacity: .55; }
.account-name { display: grid; min-width: 0; gap: 3px; }
.account-name strong { overflow: hidden; font-size: 13px; font-weight: 650; text-overflow: ellipsis; white-space: nowrap; }
.account-name small, .account-count { color: var(--muted); font-size: 10px; }
.account-balance { font-size: 14px; font-weight: 740; letter-spacing: -.4px; text-align: right; font-variant-numeric: tabular-nums; }

.provider__hint--error { color: var(--danger); }

/* Below the tablet break the five- and four-column grids stop being readable;
   collapse them to a stacked card with the amount pinned to the first row. */
@media (max-width: 860px) {
    .ledger-row, .account-row { grid-template-columns: 1fr auto; row-gap: 4px; }
    .ledger-row--head { display: none; }
    .ledger-name, .account-name { grid-column: 1; grid-row: 1; }
    .ledger-amount, .account-balance { grid-column: 2; grid-row: 1; }
    .ledger-date, .ledger-category, .ledger-account, .account-count { grid-column: 1 / -1; font-size: 10px; }
    .account-row .button--mini { grid-column: 1 / -1; justify-self: start; }
}

/* The "as of" date sits under the figure: a CSV balance can be days old, and a
   number with no date on it reads as live when it is not. */
.account-asof { display: block; margin-top: 2px; color: var(--muted); font-size: 9px; font-weight: 500; }

/* ---- Settings tabs --------------------------------------------------------
   Revealed by app.js only once it can drive them; without JS the tablist stays
   [hidden] and all panels render stacked, as they did before. */
.modal-tabs {
    display: flex;
    gap: 3px;
    margin: 18px 0 0;
    padding: 3px;
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: 10px;
    scrollbar-width: none;
}
.modal-tabs::-webkit-scrollbar { display: none; }
.modal-tabs[hidden] { display: none; }
.modal-tabs button {
    flex: 1 0 auto;
    padding: 8px 12px;
    border: 0;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    font-size: 10px;
    font-weight: 700;
    letter-spacing: .3px;
    white-space: nowrap;
    cursor: pointer;
}
.modal-tabs button:hover { color: var(--text); }
.modal-tabs button[aria-selected="true"] { background: rgba(200,241,105,.12); color: var(--lime); }
.modal-tabs button:focus-visible { outline: 2px solid var(--lime); outline-offset: -2px; }

.settings-group[hidden] { display: none; }
/* With tabs live only one panel shows, so the divider that separated stacked
   sections would render as a stray rule above whichever panel is open. */
.modal-tabs:not([hidden]) ~ .modal-body .settings-group + .settings-group {
    margin-top: 0;
    padding-top: 0;
    border-top: 0;
}
.settings-group[role="tabpanel"]:focus-visible { outline: 2px solid var(--lime); outline-offset: 4px; }

/* Separates the sign-in half of a provider block from its file-import half. */
.provider__divider { height: 1px; margin: 16px 0; background: var(--line); }

/* Grouping switch above the account panels; `.table-filter` styles buttons, these
   are links so each grouping stays bookmarkable under the CSP's no-inline-JS rule. */
.section-head--standalone { margin-bottom: 14px; }
.table-filter a { text-decoration: none; font-weight: 700; letter-spacing: .4px; }
.group-total { font-size: 15px; font-weight: 740; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }

/* ---- Accounts overview ---------------------------------------------------- */
.hero-grid--accounts { margin-top: 18px; }
.positive { color: var(--positive); }

.account-avatar {
    display: grid;
    width: 34px;
    height: 34px;
    flex: 0 0 auto;
    place-items: center;
    border-radius: 50%;
    /* Colour keyed to the account name, so a row keeps the same swatch between
       visits — the CSV carries no institution logo to show instead. */
    background: hsl(var(--seed) 42% 22%);
    color: hsl(var(--seed) 70% 72%);
    font-size: 13px;
    font-weight: 800;
}

/* ---- Payment schedule ----------------------------------------------------- */
/* Three figures and a caption, instead of the accounts page's two-card hero.
   That layout is built around a chart and there is nothing here to plot, so it
   rendered as a tall empty box beside a wall of numbers. The 1px gap over a
   `--line` background draws the dividers, so the tiles need no borders. */
.pay-summary {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 1px;
    margin-top: 18px;
    overflow: hidden;
    border-radius: var(--radius);
    background: var(--line);
}

.pay-summary__tile { display: grid; gap: 6px; padding: 20px 22px; background: var(--panel); }
.pay-summary__tile span { color: var(--muted); font-size: 10px; letter-spacing: .5px; text-transform: uppercase; }
.pay-summary__tile strong { font-size: 26px; font-weight: 740; letter-spacing: -1px; font-variant-numeric: tabular-nums; }
.pay-summary__caption { grid-column: 1 / -1; margin: 0; padding: 13px 22px; background: var(--panel); color: var(--muted); font-size: 11px; }

.pay-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px; }

/* Its own row rather than `.account-row`, whose five-column template would drop
   the amount into the 84px sparkline slot. */
.pay-row {
    display: grid;
    grid-template-columns: 44px minmax(0, 1fr) auto;
    gap: 14px;
    align-items: center;
    padding: 13px 0;
    border-top: 1px solid var(--line);
}

.pay-row:first-of-type { border-top: 0; }
.pay-row__name { display: grid; gap: 3px; min-width: 0; }
.pay-row__name strong { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pay-row__name small { color: var(--muted); font-size: 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pay-row__amount { font-size: 14px; font-weight: 740; text-align: right; font-variant-numeric: tabular-nums; }
.pay-row__amount small { display: block; margin-top: 2px; color: var(--muted); font-size: 9px; font-weight: 500; }

.payment-date { display: grid; justify-items: center; line-height: 1.1; }
.payment-date strong { font-size: 17px; font-weight: 740; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }
.payment-date small { color: var(--muted); font-size: 9px; font-weight: 600; text-transform: uppercase; letter-spacing: .4px; }

/* Two plain columns. `.summary-list` is not reusable here: it opens with a 9px
   swatch column, which squeezed every account name down to one letter. */
.pay-list { display: grid; gap: 11px; margin: 0; padding: 0; list-style: none; }
.pay-list li { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 14px; align-items: baseline; font-size: 12px; }
.pay-list li > span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pay-list b { font-weight: 700; font-variant-numeric: tabular-nums; }
.pay-list__more { color: var(--muted); font-size: 11px; }

/* A fourth column appears only on rows that carry a delete control, so the plan
   rows stay aligned with the payment rows above them. */
.pay-row:has(.pay-row__action) { grid-template-columns: 44px minmax(0, 1fr) auto 28px; }
.pay-row__action { display: grid; place-items: center; }

/* The instalment badge on a ledger row, in the accent rather than the muted grey
   the description would use: it is a state, not a subtitle. */
.ledger-plan { color: var(--lime) !important; font-weight: 600; }

/* Slider with its readout above it. The value sits in the label rather than beside
   the track, so it stays put while the thumb moves. */
.slider-field { display: grid; gap: 8px; margin-bottom: 16px; }
.slider-field__head { display: flex; align-items: baseline; justify-content: space-between; color: var(--muted); font-size: 11px; }
.slider-field__head b { color: var(--text); font-size: 12px; font-weight: 700; font-variant-numeric: tabular-nums; }

.slider-field input[type="range"] {
    width: 100%;
    height: 4px;
    margin: 6px 0;
    padding: 0;
    border-radius: 2px;
    background: var(--line);
    -webkit-appearance: none;
    appearance: none;
    cursor: pointer;
}

/* The two thumb pseudo-elements cannot be combined into one rule: a selector list
   containing a vendor pseudo-element the browser does not know invalidates the
   whole rule, so each engine needs its own copy. */
.slider-field input[type="range"]::-webkit-slider-thumb {
    width: 16px;
    height: 16px;
    border: 0;
    border-radius: 50%;
    background: var(--lime);
    -webkit-appearance: none;
    appearance: none;
}

.slider-field input[type="range"]::-moz-range-thumb {
    width: 16px;
    height: 16px;
    border: 0;
    border-radius: 50%;
    background: var(--lime);
}

.slider-field input[type="range"]:focus-visible { outline: 2px solid var(--lime); outline-offset: 4px; }

@media (max-width: 720px) {
    .pay-summary { grid-template-columns: minmax(0, 1fr); }
}
.group-total--soft { font-size: 11px; font-weight: 600; color: var(--muted); letter-spacing: 0; }

.sparkline { width: 84px; height: 30px; overflow: visible; }
.sparkline polyline { stroke: var(--lime); stroke-width: 1.6px; stroke-linejoin: round; stroke-linecap: round; }
.sparkline--down polyline { stroke: var(--danger); }
.sparkline--empty { display: block; width: 84px; height: 1px; background: var(--line); }

.summary-block + .summary-block { margin-top: 20px; }
.summary-block__head { display: flex; align-items: baseline; justify-content: space-between; font-size: 12px; }
.summary-block__head strong { font-size: 11px; letter-spacing: .4px; text-transform: uppercase; color: var(--muted); }
.summary-block__head span { font-size: 15px; font-weight: 740; font-variant-numeric: tabular-nums; }
.share-bar { display: flex; height: 7px; margin: 9px 0 12px; overflow: hidden; gap: 2px; border-radius: 20px; }
.share-bar__seg { display: block; height: 100%; border-radius: 20px; }
.summary-list { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.summary-list li { display: grid; align-items: center; gap: 9px; grid-template-columns: 9px 1fr auto; font-size: 11px; }
.summary-list i { width: 9px; height: 9px; border-radius: 3px; }
.summary-list span { color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.summary-list b { font-weight: 700; font-variant-numeric: tabular-nums; }

.share-bar__seg--asset-0, i.share-bar__seg--asset-0 { background: #7fd4e8; }
.share-bar__seg--asset-1, i.share-bar__seg--asset-1 { background: #c8f169; }
.share-bar__seg--asset-2, i.share-bar__seg--asset-2 { background: #52b7a0; }
.share-bar__seg--asset-3, i.share-bar__seg--asset-3 { background: #a5c4ff; }
.share-bar__seg--debt-0, i.share-bar__seg--debt-0 { background: #f0b95e; }
.share-bar__seg--debt-1, i.share-bar__seg--debt-1 { background: #ff7a90; }
.share-bar__seg--debt-2, i.share-bar__seg--debt-2 { background: #d98cff; }
.share-bar__seg--debt-3, i.share-bar__seg--debt-3 { background: #ffa07a; }

.account-row { grid-template-columns: 34px minmax(180px, 2fr) 84px minmax(110px, .8fr) auto; }

/* ---- Cash flow ------------------------------------------------------------ */
.chart-legend { display: flex; gap: 14px; color: var(--muted); font-size: 9px; text-transform: uppercase; letter-spacing: .6px; }
.chart-legend span { display: flex; align-items: center; gap: 6px; }
.legend-dot { width: 8px; height: 8px; border-radius: 3px; }
.legend-dot--income { background: var(--positive); }
.legend-dot--expense { background: var(--danger); }

.flow-chart { display: flex; align-items: flex-end; gap: 6px; margin-top: 20px; overflow-x: auto; padding-bottom: 4px; }
.flow-col {
    display: grid;
    flex: 1 0 40px;
    gap: 8px;
    padding: 8px 4px;
    border-radius: 8px;
    color: var(--muted);
    text-align: center;
    text-decoration: none;
}
/* Accent through the palette vars, not a literal: a hardcoded wash survives a
   repaint of --lime in silence and drifts out of step with everything else. */
.flow-col:hover { background: color-mix(in srgb, var(--text) 4%, transparent); }
.flow-col.is-selected { background: color-mix(in srgb, var(--lime) 12%, transparent); color: var(--text); }
.flow-col__bars { display: flex; height: 138px; align-items: flex-end; justify-content: center; gap: 3px; }
.flow-bar { display: block; width: 10px; min-height: 2px; border-radius: 4px 4px 0 0; }
.flow-bar--income { background: var(--positive); }
.flow-bar--expense { background: var(--danger); }
.flow-col small { font-size: 9px; letter-spacing: .3px; text-transform: uppercase; white-space: nowrap; }

/* Selected-month figures inside the bar-chart card: the bars are the period
   picker, so the numbers they select share their card instead of floating as a
   strip of loose tiles on the page background. */
.flow-stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px, 1fr)); gap: 12px 18px; margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }
.flow-stats > div { display: grid; gap: 4px; align-content: start; }
.flow-stats span { color: var(--muted); font-size: 8px; font-weight: 700; letter-spacing: .7px; text-transform: uppercase; }
.flow-stats strong { font-size: 16px; font-weight: 760; letter-spacing: -.5px; font-variant-numeric: tabular-nums; }

/* Income and expense categories side by side in one card: two stacked
   full-width lists were most of the page's height. */
.breakdown-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); align-items: start; gap: 8px 42px; margin-top: 16px; }
.breakdown-col { min-width: 0; }
.breakdown-col__head { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding-bottom: 10px; border-bottom: 1px solid var(--line); }
.breakdown-col__head h3 { margin: 0; font-size: 12px; font-weight: 750; letter-spacing: .2px; }
/* An anchor, because the row opens the transactions it is a sum of. It keeps reading as
   a row all the same: the global `a` rule already drops the underline and the link
   colour, and the hover tint is painted with a spread box-shadow rather than negative
   margins so the divider below it does not jump wider under the cursor. */
.cat-row { display: grid; grid-template-columns: minmax(0, 1fr) auto auto; align-items: center; column-gap: 16px; row-gap: 5px; padding: 9px 0; border-bottom: 1px solid var(--line); }
.cat-row:last-child { border-bottom: 0; }
.cat-row:hover { background: color-mix(in srgb, var(--lime) 11%, transparent); box-shadow: 0 0 0 8px color-mix(in srgb, var(--lime) 11%, transparent); border-radius: 2px; }
.cat-row:hover .cat-row__meta { color: var(--text); }
.cat-row__label { overflow: hidden; font-size: 12px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.cat-row__value { font-size: 12px; font-weight: 720; text-align: right; font-variant-numeric: tabular-nums; }
/* The share reads from a quiet 4px meter, not a coloured slab behind the row. */
.cat-row__track { grid-column: 1 / -1; align-self: center; height: 4px; overflow: hidden; border-radius: 4px; background: var(--line); }
.cat-row__fill { display: block; height: 100%; border-radius: 4px; }
.cat-row__fill--income { background: var(--positive); }
.cat-row__fill--expense { background: var(--danger); }
.cat-row__meta { color: var(--muted); font-size: 9px; text-align: right; white-space: nowrap; }

@media (max-width: 860px) {
    .account-row { grid-template-columns: 34px 1fr auto; }
    .account-row .sparkline, .account-row .sparkline--empty { display: none; }
    .breakdown-grid { grid-template-columns: minmax(0, 1fr); }
}

/* The annual matrix: categories down, twelve months across.
   Fourteen columns do not fit a phone, so the table scrolls inside its own box and
   the label column freezes — a horizontally scrolled grid whose row labels have left
   the screen is a wall of anonymous numbers. The frozen column takes `--panel`, the
   card surface itself, so it reads as part of the card rather than as a strip
   pasted over it. */
.matrix-scroll { margin-top: 16px; overflow-x: auto; }
/* A month still ahead, hidden on a phone by app.js. The desktop grid keeps it —
   a future month is flagged and blank there, never reported as a month in which
   nothing was spent — but at 390px those columns are the only width there is. */
.matrix-ahead { display: none; }
.matrix { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.matrix-caption { margin-bottom: 12px; color: var(--muted); font-size: 9px; line-height: 1.6; text-align: left; }
.matrix th, .matrix td { padding: 7px 9px; text-align: right; white-space: nowrap; }
.matrix thead th {
    border-bottom: 1px solid var(--line);
    color: var(--muted);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: .5px;
    text-transform: uppercase;
}
.matrix tbody td { font-size: 11px; font-weight: 600; }
.matrix tbody tr { border-bottom: 1px solid color-mix(in srgb, var(--line) 55%, transparent); }

/* Every rule below deliberately carries two classes: the base rules above are
   `.matrix thead th` and `.matrix tbody td`, which outrank a lone class and would
   otherwise win every one of these. */
.matrix th.matrix-label {
    position: sticky;
    left: 0;
    z-index: 2;
    min-width: 132px;
    max-width: 168px;
    overflow: hidden;
    background: var(--panel);
    font-size: 11px;
    font-weight: 620;
    text-align: left;
    text-overflow: ellipsis;
}
.matrix thead th.matrix-label { color: var(--muted); font-size: 9px; font-weight: 700; text-transform: uppercase; }
.matrix th.matrix-year, .matrix td.matrix-year { border-left: 1px solid var(--line); font-weight: 750; }
.matrix tbody tr:hover td, .matrix tbody tr:hover th.matrix-label { background-color: color-mix(in srgb, var(--text) 4%, transparent); }

/* The current month is marked in the header and carried down the column, which is the
   spreadsheet's NOW flag: without it the reader counts across from January every time. */
.matrix thead th.is-now { color: var(--text); }
.matrix th.is-now, .matrix td.is-now {
    box-shadow:
        inset 1px 0 0 color-mix(in srgb, var(--lime) 34%, transparent),
        inset -1px 0 0 color-mix(in srgb, var(--lime) 34%, transparent);
}
.matrix thead th.is-future { opacity: .45; }
.matrix td .matrix-nil { color: var(--muted); font-style: normal; opacity: .5; }

/* Shading is per row, measured above that category's own mean — see the service, which
   also explains why a flat row gets none. Kept under a fifth of full strength: it is a
   hint about where a category spiked, not a second way of reading the number already
   printed in the cell. */
.matrix td[data-kind="expense"] { background-color: color-mix(in srgb, var(--danger) calc(var(--heat) * 20%), transparent); }
.matrix td[data-kind="income"] { background-color: color-mix(in srgb, var(--positive) calc(var(--heat) * 18%), transparent); }

.matrix .matrix-section th {
    padding: 17px 9px 6px;
    background: var(--panel);
    color: var(--muted);
    font-size: 9px;
    font-weight: 750;
    letter-spacing: .9px;
    text-align: left;
    text-transform: uppercase;
}
.matrix .matrix-sum td, .matrix .matrix-sum th { border-top: 1px solid var(--line); font-weight: 780; }
.matrix .matrix-worth td, .matrix .matrix-worth th { color: var(--lime); font-weight: 750; }
.matrix td.negative { color: var(--danger); }
.matrix .matrix-empty { color: var(--muted); font-size: 11px; text-align: left; }

@media (max-width: 720px) {
    .matrix th, .matrix td { padding: 6px 7px; }
    .matrix th.matrix-label { min-width: 104px; max-width: 118px; }
}

/* The overview's .chart-wrap is absolutely positioned at `inset: 176px 0 34px`,
   measured against that card's taller header (it carries a token/NFT split row).
   The accounts card has less above the chart, so it lets the chart sit in normal
   flow instead of guessing a second magic offset. */
.net-worth-card--flow { min-height: 0; padding-bottom: 0; }
.chart-wrap--inline {
    position: static;
    inset: auto;
    height: 168px;
    /* Bleeds to the card edges, matching the overview chart. */
    margin: 20px -28px 0;
}
@media (max-width: 720px) { .chart-wrap--inline { height: 130px; } }

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.account-row { grid-template-columns: 34px minmax(180px, 2fr) 120px minmax(110px, .8fr) 30px; }
html .account-row { grid-template-columns: 32px minmax(180px, 2fr) 120px minmax(110px, .8fr) 30px; }
html .account-row .account-avatar { width: 32px; height: 32px; }
html .sparkline,
html .sparkline--empty { width: 120px; }

/* Row action menu: a "…" affordance that keeps the row about the numbers. */
.row-menu {
    width: 26px;
    height: 26px;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 7px;
    background: transparent;
    color: var(--muted);
    font-size: 15px;
    line-height: 1;
    cursor: pointer;
}
.row-menu:hover { border-color: var(--line); background: rgba(255,255,255,.05); color: var(--text); }
.row-menu:focus-visible { outline: 2px solid var(--lime); outline-offset: 1px; }
.account-dialog__link { margin-top: 10px; text-align: center; text-decoration: none; }

@media (max-width: 900px) {
    .account-row { grid-template-columns: 34px 1fr auto 30px; }
    .account-row .sparkline, .account-row .sparkline--empty { display: none; }
}

/* Account categories in settings. */
.category-add { display: grid; align-items: end; gap: 10px; grid-template-columns: 1fr auto; margin-bottom: 14px; }
.category-add .field { margin-bottom: 0; }
.category-row {
    display: grid;
    align-items: center;
    gap: 10px;
    grid-template-columns: 1fr auto auto;
    padding: 9px 0;
    border-bottom: 1px solid var(--line);
}
.category-row:last-of-type { border-bottom: 0; }
.category-row__rename { display: flex; gap: 7px; }
.category-row__rename input {
    min-width: 0;
    flex: 1;
    height: 32px;
    padding: 0 10px;
    border: 1px solid var(--line);
    border-radius: 7px;
    outline: 0;
    background: rgba(255,255,255,.025);
    color: var(--text);
    font-size: 11px;
}
.category-row__rename input:focus { border-color: rgba(200,241,105,.45); }
.category-row__count { color: var(--muted); font-size: 9px; white-space: nowrap; }
.button--danger { border-color: rgba(255,122,144,.3); color: var(--danger); }
.button--danger:hover { border-color: var(--danger); }

/* Net-worth leg picker under the dashboard chart. */
.leg-picker { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 14px; }
.leg-chip {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    padding: 6px 10px;
    border: 1px solid var(--line);
    border-radius: 20px;
    color: var(--muted);
    font-size: 10px;
    cursor: pointer;
}
.leg-chip:hover { border-color: rgba(200,241,105,.35); }
.leg-chip.is-on { border-color: rgba(200,241,105,.45); color: var(--text); }
.leg-chip input { width: 12px; height: 12px; margin: 0; accent-color: var(--lime); cursor: pointer; }
.leg-chip b { font-weight: 700; font-variant-numeric: tabular-nums; }

.chart-note { margin: 10px 0 0; color: var(--muted); font-size: 10px; line-height: 1.5; }
.chart-wrap--panel { position: static; inset: auto; height: 190px; margin-top: 16px; }
.section-head__sub { color: var(--muted); font-size: 11px; font-weight: 500; }
.legend-dot--muted { background: var(--muted); }

/* Duplicate-source warning and the delete controls it carries.

   Deliberately louder than a `page-note`: this panel says every figure on the page is
   currently counted twice, which is the one thing here that makes the numbers wrong
   rather than merely incomplete. */
.panel--warn { border-color: rgba(255,122,144,.28); }
.panel--warn .mini-label { color: var(--danger); }

/* The one thing left on the accounts page from the source panel that moved into
   settings: a single line, and only while the totals are actually being double-counted.
   A dialog is the right home for maintenance, but not for "these numbers are wrong". */
.page-note--warn {
    padding: 9px 12px;
    border: 1px solid rgba(255,122,144,.28);
    border-radius: 9px;
    color: var(--text);
}
.page-note--warn strong { color: var(--danger); }

/* The constructive counterpart, sitting above the warning panel: merging keeps both
   ledgers where deleting discards one, so it reads as the primary path. */
.panel--accent { border-color: rgba(198,255,110,.28); }
.panel--accent .mini-label { color: var(--lime); }

.pair-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 6px;
    margin: 14px 0;
    /* Fifty-three rows is a page of scrolling on its own; capped so the confirm button
       stays reachable without hunting for it. */
    max-height: 320px;
    overflow-y: auto;
}
.pair-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 11px;
    border: 1px solid var(--line);
    border-radius: 9px;
    cursor: pointer;
}
.pair-row input { width: 13px; height: 13px; margin: 0; accent-color: var(--lime); flex: none; }
.pair-row__copy { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pair-row__copy strong { font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.pair-row__copy small { color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }

.source-list { display: flex; flex-direction: column; gap: 8px; margin: 14px 0 4px; }
.source-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 11px 13px;
    border: 1px solid var(--line);
    border-radius: 10px;
}
/* min-width:0 so a long institution name ellipsises instead of shoving the button
   off the row — the same trap `.summary-list` fell into on the payments page. */
.source-row__copy { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.source-row__copy strong { font-size: 12px; }
.source-row__copy small { color: var(--muted); font-size: 10px; font-variant-numeric: tabular-nums; }

.account-dialog__danger { margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--line); }
.account-dialog__danger-copy { margin: 0 0 10px; color: var(--muted); font-size: 10px; line-height: 1.55; }

/* A submit button that reads as a link, for an action that belongs inside a sentence. */
.inline-form { display: inline; }
.link-button {
    padding: 0;
    border: 0;
    background: none;
    color: var(--lime);
    font: inherit;
    cursor: pointer;
    text-decoration: underline;
}

/* ---- Dashboard: breakdown column, recent transactions, matrix toggle -------
   The design puts Categories beside a narrow column carrying Income and the
   latest rows, rather than splitting one panel into equal halves. Income is five
   rows on any ledger and expenses are thirty, so equal halves left one side half
   empty and the other the only one worth scrolling. */
.content-grid--breakdown { grid-template-columns: minmax(0, 1.55fr) minmax(320px, 1fr); }
.stack-column { display: grid; align-content: start; gap: 18px; min-width: 0; }
html .content-grid--breakdown { gap: 16px; }
html .stack-column { gap: 16px; }

/* A refund is money arriving without being earnings, which is the distinction the
   whole cash-flow classification turns on — so it is stated and named rather than
   folded into the income total above it. */
.refund-note {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    margin: 12px 0 0;
    padding: 12px 14px;
    border-radius: 10px;
    background: var(--lime-dark);
    font-size: 12.5px;
}
html .refund-note { color: #2f6b55; }
.refund-note b { font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }

.txn-row {
    display: grid;
    grid-template-columns: 28px minmax(0, 1fr) auto;
    align-items: center;
    gap: 0 11px;
    padding: 9px 10px;
    margin: 0 -10px;
    border-radius: 9px;
    color: inherit;
}
html .txn-row:hover { background: #f7f7f5; }
.txn-row__copy { display: grid; min-width: 0; gap: 1px; line-height: 1.3; }
.txn-row__copy b { overflow: hidden; font-size: 13.5px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.txn-row__copy small { overflow: hidden; color: var(--muted); font-size: 11.5px; text-overflow: ellipsis; white-space: nowrap; }
.txn-row__amount { font-size: 13.5px; font-weight: 700; font-variant-numeric: tabular-nums; text-align: right; }
html .txn-row .account-avatar { width: 28px; height: 28px; font-size: 12px; }

/* A key for lines is drawn as lines. Sits under the chart, after it in the flex
   column, so it never takes the space the chart is stretching into. */
.chart-legend--foot { flex: 0 0 auto; margin-top: 12px; }
html .chart-legend--foot,
html .chart-legend--plain { color: #55554e; font-size: 12px; letter-spacing: 0; text-transform: none; }
.legend-rule { display: inline-block; width: 14px; height: 2px; flex: 0 0 auto; border-radius: 2px; }
.legend-rule--muted { background: var(--muted); }
.legend-rule--expense { background: var(--danger); }

/* The note and its way back sit on one line, the link pushed to the far edge. */
.page-note--split { display: flex; align-items: baseline; justify-content: space-between; gap: 20px; }
html .page-note--split > a { flex: 0 0 auto; color: var(--lime); font-weight: 600; white-space: nowrap; }
/* A subtitle beside the page title, not under it. */
.topbar-sub { margin-left: 10px; color: var(--muted); font-size: 13px; font-weight: 500; }

/* The charge's kind, as a badge rather than the first clause of its caption. */
.pay-kind {
    display: inline-block;
    padding: 2px 7px;
    border-radius: 5px;
    background: #efeeea;
    color: #6d6d66;
    font-size: 10px;
    font-style: normal;
    font-weight: 700;
    letter-spacing: .06em;
    text-transform: uppercase;
}
.pay-kind--card { background: #f6ece5; color: #a34a1f; }
.pay-kind--fixed { background: #eef1f6; color: #2f5d8a; }

.matrix-toggle { display: flex; justify-content: center; margin-top: 14px; }
html .matrix-toggle .button { min-height: 34px; padding: 0 18px; font-size: 12.5px; }

/* The range tabs sit in the card's header row in the design, not floating over the
   chart — so this variant undoes the absolute placement `.chart-range` carries for
   the corner it used to live in. */
html .chart-range--header {
    position: static;
    inset: auto;
    /* `auto`, not a fixed gap: the tabs belong at the card's right edge, and until
       READ ONLY was removed it was the pill carrying this — so dropping the pill
       left them tucked against the change figure instead. */
    margin-left: auto;
}
html .chart-range--header a {
    padding: 5px 10px;
    border-radius: 7px;
    color: #6d6d66;
    font-size: 11px;
    font-weight: 600;
}
html .chart-range--header a.active { background: #fff; color: var(--text); box-shadow: 0 1px 2px rgba(40, 38, 32, .09); }

@media (max-width: 1100px) {
    .content-grid--breakdown { grid-template-columns: minmax(0, 1fr); }
}

/* ---- Responsive × palette -------------------------------------------------
   The palette section's rules are `html .foo`, which outweighs the plain `.foo`
   in the breakpoints ABOVE. So a palette rule that touches a LAYOUT property has
   to be restated per breakpoint here, after that section. Without the first rule
   below, the hero grid keeps two columns on a phone and crushes the net-worth
   card to a 40px sliver.

   That `html` is also load-bearing rather than decorative: it is what keeps the
   palette one notch above the plain-class rules. Strip it and the specificities
   level out, source order decides — and since the palette section sits after the
   breakpoints, it is the breakpoints that would stop applying. */
@media (max-width: 1100px) {
    html .hero-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 760px) {
    html .workspace { margin-left: 0; padding: 0 15px 30px; }
    /* The bar keeps its full-bleed break-out, but against the phone's 15px gutter
       rather than the desktop 24px — the -24px would poke past the viewport and
       put the whole page into a sideways scroll. */
    html .topbar { margin: 0 -15px 16px; padding: 14px 15px; }
    html .dash-stack,
html .hero-grid,
html .content-grid { gap: 13px; }
    html .net-worth-card { padding-inline: 17px; }
    html .panel,
html .allocation-card { padding: 17px 16px; }
}

/* The charts read a value out on hover, so the pointer should say so. */
.topbar-mark { display: none; }

[data-chart] { cursor: crosshair; }
/* Axis labels need vertical room the old label-less charts did not. */
.chart-wrap--panel { height: 220px; }
.chart-wrap--inline { height: 190px; }

/* ---------------------------------------------------------------------------
   Design completion patch, from `app-design-patch.css` in the design project.

   The palette section above repaints what was keyed to a token. This block is
   the residue of the dark theme the file was repainted FROM: rules whose
   colours are literals. Three families —

     1. rgba(255,255,255,.0x) washes — a lift on a dark ground and invisible on
        white, so the control they shape has no chip at all.
     2. rgba(200,241,105,…) — the ORIGINAL lime. `--lime` was repainted forest
        green; these literals were not, so they still paint yellow-green.
     3. rgba(255,122,144,…) / (115,210,222,…) / (247,178,103,…) — the dark
        theme's pink, aqua and amber, stranded beside their repainted tokens.

   `html .foo` to match the palette section's rank, appended after it so source
   order decides. Colour, surface and border only — no layout.

   One departure from the patch as written: it also repaints `.account-avatar`
   to a paler tint (30%/42%). That swatch was settled during the accounts-page
   review and is left alone here; only its type is taken.
   --------------------------------------------------------------------------- */

/* ---- Accent washes: old lime → the design's green tint --------------------- */
html .button--mini { background: var(--lime-dark); color: var(--lime); }
html .button--mini:hover { background: #e2eee8; }
html .modal-tabs button[aria-selected="true"] { background: var(--lime-dark); }
html .add-wallet-inline > span,
html .circle-button { border-color: #cfe0d7; color: var(--lime); }
html .nft-card-panel:hover,
html .nft-strip-card:hover { border-color: #cfcec6; }
html .wallet-manage__row button:hover { border-color: var(--lime); color: var(--lime); }
html .setup-banner {
    border-color: #d9e6de;
    border-radius: 12px;
    background: var(--lime-dark);
}
html .setup-number { color: #fff; }
html .setup-banner p { color: #55554e; font-size: 12.5px; }
html .status-dot--warn { box-shadow: none; }
html .link-button { color: var(--lime); }

/* ---- White-on-dark washes: give the control a real surface ---------------- */
html .sync-button { background: #f2f1ed; color: #6d6d66; }
html .sync-button:hover { background: #e8e7e2; color: var(--text); }
html .row-menu:hover { border-color: #e0dfd9; background: #f2f1ed; }
html .category-row__rename input {
    border-color: #e0dfd9;
    border-radius: 8px;
    background: #fff;
    font-size: 12.5px;
}
html .category-row__rename input:focus { border-color: var(--lime); }
html .asset-menu > div { border-color: var(--line); border-radius: 10px; background: #fff; box-shadow: 0 12px 28px rgba(40, 38, 32, .12); }
html .asset-menu button { color: #55554e; font-size: 12px; }
html .asset-menu button:hover { background: #f2f1ed; color: var(--text); }

/* ---- Identity swatches ----------------------------------------------------
   All were tinted fills over a dark card: a 11-12% wash of a saturated hue plus
   that hue at full strength for the glyph. On white the wash disappears and the
   glyph is the only thing left, so each becomes a light tint with a dark glyph. */
html .wallet-icon { background: #e9f0f3; color: #2d6b7f; }
html .wallet-icon--bitcoin { background: #f7ede4; color: var(--warning); }
html .wallet-icon--solana { background: #efeaf7; color: #5b4b8a; }
html .wallet-icon--polkadot { background: #f7ebe5; color: var(--danger); }
html .verified { background: var(--aqua); color: #fff; }
html .manual-badge { background: #f7ede4; color: var(--warning); font-size: 10px; letter-spacing: .06em; }
html .account-avatar { font-size: 12.5px; font-weight: 700; }

/* The token monogram mixed its colour into #15252a — a dark card. Mixed into
   white it keeps the same idea on this ground. */
html .token-fallback {
    background: color-mix(in srgb, var(--token-color) 16%, #fff);
    color: color-mix(in srgb, var(--token-color) 78%, #1b1b19);
    font-weight: 700;
}

/* ---- Categorical series ---------------------------------------------------
   The share bars and their legend still ran the dark theme's neon set (#c8f169,
   #ff7a90, #7fd4e8) — the one place left where the old palette was fully intact.
   Redrawn as two families the design already uses: teals and green for what is
   owned, terracottas for what is owed, so a glance at a bar says which side it
   is on before any label is read. */
html .share-bar__seg--asset-0, html i.share-bar__seg--asset-0 { background: #3f8fa8; }
html .share-bar__seg--asset-1, html i.share-bar__seg--asset-1 { background: var(--lime); }
html .share-bar__seg--asset-2, html i.share-bar__seg--asset-2 { background: #74ac9b; }
html .share-bar__seg--asset-3, html i.share-bar__seg--asset-3 { background: #9cc0ce; }
html .share-bar__seg--debt-0, html i.share-bar__seg--debt-0 { background: var(--danger); }
html .share-bar__seg--debt-1, html i.share-bar__seg--debt-1 { background: var(--warning); }
html .share-bar__seg--debt-2, html i.share-bar__seg--debt-2 { background: #d99a72; }
html .share-bar__seg--debt-3, html i.share-bar__seg--debt-3 { background: #a8836a; }
html .share-bar { height: 6px; }
html .summary-block__head strong { color: #77776f; font-size: 11px; letter-spacing: .07em; }
html .summary-block__head span { font-size: 15px; font-weight: 700; letter-spacing: -.02em; }
html .summary-list li { font-size: 12.5px; }
html .summary-list span { color: #6d6d66; }

/* ---- Panels that carry a state -------------------------------------------
   Border-only signalling, since these sit on white and a saturated hairline is
   the whole signal. Pink → the palette's terracotta, old lime → green. */
html .panel--warn,
html .page-note--warn { border-color: #e6c4b4; }
html .page-note--warn { background: #fbf1ec; }
html .panel--accent { border-color: #c5dccf; }
html .button--danger { border-color: #e6c4b4; color: var(--danger); }
html .button--danger:hover { border-color: var(--danger); background: #fbf1ec; }

/* ---- Slate-green greys ----------------------------------------------------
   A family of desaturated blue-greens (#60736e, #5c6f6a, #687b76) drawn to sit
   on the old ground. Beside the design's warm greys they read as a second,
   cooler neutral, and the page's greys have to come from one family or the
   cards look mismatched. All fold into the caption grey used above. */
html .wallet-meta span,
html .wallet-panel__value small,
html .chain-matrix__na,
html .pager__page,
html .ledger-flag,
html .empty-state p { color: #77776f; }
html .wallet-meta span,
html .wallet-panel__value small { font-size: 10.5px; letter-spacing: .06em; }
html .ledger-flag { border-color: #e0dfd9; font-size: 10px; }
html .chain-matrix__na { font-size: 12.5px; }

/* ---- Sign-in --------------------------------------------------------------
   The panel and its wash were already repainted; its copy was not, so light
   sage-greys drawn for a near-black backdrop sat on a white one. */
html .auth-intro::after {
    border-color: #d9e6de;
    box-shadow: 0 0 0 70px rgba(15, 122, 85, .022), 0 0 0 140px rgba(63, 143, 168, .014);
}
html .auth-copy h1 { letter-spacing: -.03em; font-weight: 700; }
html .auth-copy h1 em { color: var(--lime); }
html .auth-copy p { color: #55554e; }
html .auth-proof { color: #77776f; letter-spacing: .07em; }
html .login-card__head h2 { font-size: 24px; font-weight: 700; letter-spacing: -.02em; }
html .login-card__head p { color: #6d6d66; font-size: 13px; }
html .check-row { color: #55554e; font-size: 12.5px; }
html .security-note { color: #77776f; font-size: 11.5px; }

/* ---- Row rhythm -----------------------------------------------------------
   The design divides rows with a hairline one step lighter than the card border
   and marks hover with a wash. The palette section applies both to the tables it
   names; these are the row types it did not reach. */
html .wallet-list .wallet-card:hover,
html .source-row:hover,
html .pair-row:hover,
html .category-row:hover { background: #f7f7f5; }
html .category-row { border-color: #f4f3ef; }
html .category-row__count { color: #77776f; font-size: 11.5px; }
html .source-row__copy small,
html .pair-row__copy small { color: #77776f; font-size: 11.5px; }
html .hidden-asset { border-color: var(--line); border-radius: 12px; }
html .hidden-asset small { color: #77776f; font-size: 11.5px; }

/* ---- Ledger ---------------------------------------------------------------
   From the design's `isLedger` section. Two cards: the filters own one, the
   ledger owns the other, and neither carries a heading — the topbar already
   names the page. */
html .panel--filters { display: grid; gap: 14px; padding: 16px 20px 18px; }
html .panel--ledger { padding: 6px 20px 14px; }
/* `.asset-table` carries a 20px top margin for the pages where it follows a
   heading. Here it opens the card, so the margin stacks on the card padding and
   left a band of empty white above the column headers. */
html .panel--ledger > .asset-table { margin-top: 0; }

/* Three equal selects, a wider search, then the button. `auto-fit` gave the
   search the same width as a month picker, and it is the field most likely to
   hold a long word. */
html .ledger-filters {
    grid-template-columns: repeat(3, minmax(0, 1fr)) 1.4fr auto;
    gap: 12px;
    margin-top: 0;
}
html .ledger-filters .field > span {
    color: #a3a39b;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
}
html .ledger-filters select,
html .ledger-filters input {
    padding: 9px 12px;
    border: 1px solid #e0dfd9;
    border-radius: 9px;
    background: #fff;
    font-size: 13.5px;
}
/* The native arrow is drawn by the platform and cannot be styled, so it is
   switched off and redrawn as a background chevron. A data URI rather than an
   inline <svg> in each label: three selects would otherwise carry the same
   markup three times. */
html .ledger-filters select {
    padding-right: 32px;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%236d6d66' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 11px center;
    cursor: pointer;
}
html .ledger-filters .button {
    height: auto;
    padding: 9px 16px;
    border: 1px solid #e0dfd9;
    border-radius: 9px;
    background: #fff;
    color: #55554e;
    font-size: 13px;
    font-weight: 600;
}
html .ledger-filters .button:hover { background: #f5f5f3; }

/* What the filters did, and one chip per filter to undo it. */
html .ledger-active {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px;
    padding-top: 12px;
    border-top: 1px solid #eeede8;
}
html .ledger-active__count { color: #6d6d66; font-size: 12.5px; }
html .ledger-active .filter-chip {
    display: inline-flex;
    height: auto;
    align-items: center;
    gap: 8px;
    padding: 5px 8px 5px 11px;
    border: 0;
    border-radius: 8px;
    background: #f2f1ed;
    color: #55554e;
    font-size: 12.5px;
}
html .ledger-active .filter-chip b { font-weight: 600; }
html .ledger-active .filter-chip a { color: #8a8a82; font-size: 14px; }
html .ledger-active .filter-chip a:hover { color: var(--text); }

/* Fixed columns, so a long merchant name cannot push the amount around between
   one page of the ledger and the next. */
html .ledger-row {
    grid-template-columns: 104px minmax(0, 1fr) 168px 190px 130px 34px;
    min-height: 0;
    gap: 0 16px;
    margin: 0 -10px;
    padding: 11px 10px;
    border-bottom: 1px solid #f4f3ef;
    border-radius: 10px;
}
html .ledger-row--head {
    padding: 14px 10px 10px;
    border-bottom: 1px solid #eeede8;
    color: #a3a39b;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .08em;
}
html .ledger-date { gap: 2px; color: #55554e; font-size: 12.5px; font-variant-numeric: tabular-nums; }
/* A caption on the date, not a bordered chip: it qualifies the date, and an
   outlined pill here competes with the category pill one column over. */
html .ledger-pending {
    color: #a34a1f;
    font-size: 10.5px;
    font-weight: 700;
    letter-spacing: .05em;
    text-transform: uppercase;
}
html .ledger-name strong { font-size: 13.5px; font-weight: 600; }
html .ledger-name small { color: #a3a39b; font-size: 11.5px; }
html .ledger-account { color: #6d6d66; font-size: 12.5px; }
html .ledger-amount { font-size: 14px; font-weight: 700; letter-spacing: 0; }
/* A category is a label, so it gets a pill. Capped at the column width, since
   `Financial & Legal Services` is longer than the space it is given. */
/* Present only so the phone has something to make a flex row out of; here the
   category and account must stay direct children of the row grid. */
html .ledger-meta { display: contents; }
html .ledger-category { overflow: visible; min-width: 0; font-size: 12px; }
html .ledger-category > span {
    display: inline-block;
    overflow: hidden;
    max-width: 100%;
    padding: 4px 10px;
    border-radius: 7px;
    background: #f2f1ed;
    color: #55554e;
    text-overflow: ellipsis;
    vertical-align: middle;
    white-space: nowrap;
}
html .ledger-category > small { color: #a3a39b; }

html .pager { justify-content: space-between; margin-top: 0; padding: 16px 10px 4px; }
html .pager .button {
    padding: 8px 16px;
    border: 1px solid #e0dfd9;
    border-radius: 9px;
    background: #fff;
    color: #55554e;
    font-size: 13px;
    font-weight: 600;
}
html .pager__page { color: #a3a39b; font-size: 12.5px; letter-spacing: 0; text-transform: none; }

/* The fixed template has to come off on a phone, where 104+168+190+130 alone
   overflows the viewport. Written `html .` and placed after the breakpoints, or
   the rule above would outrank it — the hazard noted with the palette. */
@media (max-width: 900px) {
    html .ledger-row { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 12px; margin: 0; padding: 11px 0; }
    html .ledger-filters { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }
}


/* ---- Settings page ---------------------------------------------------------
   From the design's `Settings (desktop)` file. Two columns: a section list that
   stays put while the panels scroll past it. The list was a horizontal tab strip
   when this was a dialog, where a vertical one had nowhere to go. */
html .settings-layout {
    display: grid;
    grid-template-columns: 212px minmax(0, 1fr);
    align-items: start;
    gap: 20px;
}
html .settings-nav {
    display: flex;
    position: sticky;
    /* Clears the sticky topbar rather than sliding under it. */
    top: 78px;
    flex-direction: column;
    gap: 2px;
    padding: 8px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
}
html .settings-nav[hidden] { display: none; }
html .settings-nav button {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border: 0;
    border-radius: 9px;
    background: transparent;
    color: #55554e;
    cursor: pointer;
    font-family: inherit;
    font-size: 13.5px;
    font-weight: 500;
    text-align: left;
}
/* The same dot the sidebar marks a destination with, so a section reads as one
   more place rather than as a different kind of control. */
html .settings-nav button::before {
    content: "";
    width: 6px;
    height: 6px;
    flex: 0 0 6px;
    border-radius: 999px;
    background: #c9c8c1;
}
html .settings-nav button:hover { background: #f2f1ed; }
html .settings-nav button[aria-selected="true"] {
    background: #e9efec;
    color: var(--lime);
    font-weight: 700;
}
html .settings-nav button[aria-selected="true"]::before { background: var(--lime); }

html .settings-panels { display: flex; min-width: 0; flex-direction: column; gap: 16px; }
/* Each panel is a card of its own now. As a dialog they were stacked sections
   inside one scroller, separated by a rule and a top margin — which on a page
   would read as one long card with hairlines through it. */
html .settings-panels > .settings-group {
    margin: 0;
    padding: 16px 20px 18px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
}
html .settings-panels > .settings-group[hidden] { display: none; }
html .settings-group__title {
    color: var(--text);
    font-size: 14.5px;
    font-weight: 700;
    letter-spacing: -.01em;
    text-transform: none;
}
html .settings-group__hint { margin-top: 6px; color: #6d6d66; font-size: 12.5px; }


/* The Integrations panel is a stack of provider cards, not one card holding
   them — the design gives each provider its own surface at the top level, with
   the section's own heading and hint sitting on the page ground above them.
   Nested, every provider read as a sub-item of a bigger thing. */
html .settings-panels > #panel-sources {
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
}
html #panel-sources > .settings-group__title,
html #panel-sources > .settings-group__hint { padding-inline: 2px; }
html #panel-sources > .provider {
    margin-top: 14px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
}
html #panel-sources > .provider + .provider { margin-top: 16px; }
html .provider__summary { padding: 16px 20px; }
html .provider__logo { width: 38px; height: 38px; border-radius: 11px; font-size: 13px; }
html .provider__name { font-size: 14.5px; font-weight: 700; }
html .provider__desc { font-size: 12px; }
html .provider__body { padding: 0 20px 18px; }
html .provider__hint { font-size: 12px; }

/* "Not connected" is a state, not a fault. It was drawn in the warning red the
   palette uses for a failed sync, which made four providers nobody has set up
   look like four things that had broken. */
html .connection-badge {
    padding: 5px 11px;
    border-radius: 999px;
    background: #f2f1ed;
    color: #8a8a82;
    font-size: 11.5px;
    font-weight: 600;
}
html .connection-badge.connected { background: #e4efe9; color: var(--lime); }
@media (max-width: 900px) {
    /* The list goes back to a strip above the panels: 212px of nav beside a card
       leaves the card too narrow to hold a two-column field grid. */
    html .settings-layout { grid-template-columns: minmax(0, 1fr); }
    html .settings-nav {
        position: static;
        top: auto;
        flex-direction: row;
        overflow-x: auto;
        scrollbar-width: none;
    }
    html .settings-nav::-webkit-scrollbar { display: none; }
    html .settings-nav button { white-space: nowrap; }
    html .settings-nav button::before { display: none; }
}


/* One row per source: what it is, how often, whether it runs. The design's
   `1fr 190px 52px`, with a fourth column for the run button it has no
   equivalent for — running one source now is worth a slot. */
html .sync-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: 0 14px;
    padding: 15px 0;
    border-bottom: 1px solid #f4f3ef;
}
html .sync-row:last-of-type { border-bottom: 0; }
html .sync-row__form {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 190px 52px;
    align-items: center;
    gap: 0 18px;
}
html .sync-row__copy { display: grid; min-width: 0; gap: 3px; line-height: 1.4; }
html .sync-row__copy strong { font-size: 13.5px; font-weight: 600; }
html .sync-row__copy small { color: #a3a39b; font-size: 11.5px; }
html .sync-row__status { color: #8a8a82; }
html .sync-row__frequency select {
    width: 100%;
    padding: 10px 30px 10px 13px;
    border: 1px solid #e0dfd9;
    border-radius: 9px;
    background: #fdfdfc;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath d='M2.5 4.5L6 8l3.5-3.5' fill='none' stroke='%236d6d66' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    appearance: none;
    cursor: pointer;
    font-size: 13px;
    font-weight: 600;
}

/* A 44×26 track with a 20px knob, drawn from the checkbox itself rather than
   from an extra span: the input has to stay a real checkbox for the form to
   post "off", and for a keyboard to reach it. */
html .sync-row__switch {
    position: relative;
    width: 44px;
    height: 26px;
    justify-self: end;
    border-radius: 999px;
    background: #dcdbd5;
    appearance: none;
    cursor: pointer;
    transition: background .15s ease;
}
html .sync-row__switch::after {
    content: "";
    position: absolute;
    top: 3px;
    left: 3px;
    width: 20px;
    height: 20px;
    border-radius: 999px;
    background: #fff;
    box-shadow: 0 1px 2px rgba(27, 27, 25, .2);
    transition: transform .15s ease;
}
html .sync-row__switch:checked { background: var(--lime); }
html .sync-row__switch:checked::after { transform: translateX(18px); }
html .sync-row__run .button { padding: 0 13px; }

@media (max-width: 760px) {
    /* 190px of select plus a switch cannot share a line with the copy here. */
    html .sync-row { grid-template-columns: minmax(0, 1fr); gap: 10px; }
    html .sync-row__form { grid-template-columns: minmax(0, 1fr) 52px; gap: 10px 14px; }
    html .sync-row__copy { grid-column: 1 / -1; }
    html .sync-row__run { justify-self: start; }
}

/* ---- Sign-in ---------------------------------------------------------------
   From `Login Page.dc.html`. One centred 412px column between a thin header and
   a footer, replacing the split hero: the old left panel carried a headline and
   a wash and nothing anyone could act on, and at a phone width it meant
   scrolling past half a screen of decoration to reach the two fields.

   The `.auth-shell`, `.auth-intro` and `.auth-copy` rules further up the file
   are dead with it, along with their responsive and palette entries. Left in
   place rather than picked out of four separate blocks — they match nothing the
   app renders now. */
html .auth-page { display: flex; min-height: 100vh; flex-direction: column; }
html .auth-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 24px;
    padding: 16px 24px;
    border-bottom: 1px solid var(--line);
    background: #fbfbfa;
}
html .auth-topbar small { color: #a3a39b; font-size: 12.5px; }
html .auth-main { display: flex; flex: 1; align-items: center; justify-content: center; padding: 32px 24px; }
html .auth-column { display: flex; width: 100%; max-width: 412px; flex-direction: column; gap: 16px; }

html .auth-lede { display: flex; flex-direction: column; gap: 5px; }
html .auth-lede h1 { margin: 0; font-size: 22px; font-weight: 700; letter-spacing: -.025em; }
html .auth-lede p { margin: 0; color: #6d6d66; font-size: 13px; }

html .login-card {
    display: flex;
    width: 100%;
    flex-direction: column;
    gap: 14px;
    padding: 18px 20px 20px;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
}
html .login-card .field { display: flex; flex-direction: column; gap: 6px; margin: 0; }
/* Uppercase micro-labels, the same ones every other form in the app uses. The
   generic `.field > span` is sentence case and near-black, which read as body
   copy stacked above each input rather than as its name. */
html .login-card .field > span {
    color: #a3a39b;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
}
html .login-card input[type="email"],
html .login-card input[type="password"],
html .login-card input[type="text"] {
    width: 100%;
    padding: 11px 13px;
    border: 1px solid #e0dfd9;
    border-radius: 9px;
    background: #fdfdfc;
    font-size: 13.5px;
}

/* The reveal button sits inside the field, so the input reserves room for it —
   without the padding a long password runs under the icon. */
html .field__reveal { display: block; position: relative; }
html .field__reveal input { padding-right: 42px !important; }
html .field__reveal button {
    display: flex;
    position: absolute;
    top: 50%;
    right: 5px;
    width: 28px;
    height: 28px;
    align-items: center;
    justify-content: center;
    margin-top: -14px;
    padding: 0;
    border: 0;
    border-radius: 8px;
    background: transparent;
    color: #a3a39b;
    cursor: pointer;
}
html .field__reveal button:hover { background: #f2f1ed; color: var(--text); }
html .field__reveal button[hidden] { display: none; }

html .check-row { margin: 0; color: #55554e; font-size: 13px; }
html .check-row input { width: 16px; height: 16px; flex: 0 0 16px; accent-color: var(--lime); }

/* Wrong credentials, said once and in the palette's terracotta rather than in a
   red the rest of the app never uses. */
html .auth-error {
    display: flex;
    align-items: center;
    gap: 11px;
    margin: 0;
    padding: 11px 14px;
    border: 1px solid #f2ded5;
    border-radius: 10px;
    background: #fbf0ec;
    color: #8a4a2c;
    font-size: 12.5px;
}
html .auth-error i { width: 7px; height: 7px; flex: 0 0 7px; border-radius: 999px; background: var(--danger); }

/* Three cells divided by hairlines, the shape the design gives its stats card. */
html .auth-proof {
    display: grid;
    position: static;
    z-index: auto;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
    padding: 4px 0;
    border: 1px solid var(--line);
    border-radius: 14px;
    background: var(--panel);
    color: inherit;
    font-size: inherit;
    letter-spacing: normal;
    text-transform: none;
}
html .auth-proof > div { display: grid; gap: 2px; padding: 13px 16px; border-right: 1px solid #eeede8; }
html .auth-proof > div:last-child { border-right: 0; }
html .auth-proof span {
    display: block;
    color: #a3a39b;
    font-size: 10.5px;
    font-weight: 600;
    letter-spacing: .07em;
    text-transform: uppercase;
}
html .auth-proof strong { font-size: 15px; font-weight: 700; letter-spacing: -.02em; }

html .security-note {
    display: flex;
    align-items: flex-start;
    justify-content: flex-start;
    gap: 10px;
    margin: 0;
    padding: 12px 15px;
    border-radius: 12px;
    background: var(--lime-dark);
    color: #2f6b55;
    font-size: 12px;
    line-height: 1.55;
    text-align: left;
}
html .security-note svg { flex: 0 0 16px; margin-top: 1px; color: var(--lime); }

html .auth-footer { margin: 0; padding: 14px 26px 18px; }

@media (max-width: 560px) {
    html .auth-main { padding: 20px 15px; }
    html .auth-topbar { padding: 14px 15px; }
    html .auth-topbar small { display: none; }
    /* Three cells at 320px leave each one too narrow for "Never asked". */
    html .auth-proof { grid-template-columns: minmax(0, 1fr); }
    html .auth-proof > div { border-right: 0; border-bottom: 1px solid #eeede8; }
    html .auth-proof > div:last-child { border-bottom: 0; }
}
/* ---------------------------------------------------------------------------
   Phone, from `Budget Overview (mobile).dc.html`.

   Last block in the file on purpose. Two plain-class rules for the chart
   heights sit after every breakpoint (`.chart-wrap--panel { height: 220px }`),
   so the 720px override further up had been losing on source order and never
   applied — the phone was drawing desktop-height charts. Anything here that
   restates a layout property therefore has to outrank both those rules and the
   palette section's `html .foo`, which is what the `html` prefix is for.
   --------------------------------------------------------------------------- */
@media (max-width: 760px) {
    /* The design's own heights. The card sizes to its content: `min-height: 330px`
       came from the desktop palette rules, which the responsive block never
       restated, so a card holding a 120px chart still reserved 330px and opened
       a band of empty white under the figure. */
    html .net-worth-card { min-height: 0; }
    /* Matched selector for selector against the desktop rules, which are
       `html .hero-grid > .net-worth-card > .chart-wrap--inline` — (0,3,1) against
       the (0,1,1) of a plain `html .chart-wrap--inline`, so a shorter selector
       here loses however late it appears. And they set `min-height` on a box that
       is `flex: 1 1 0`, so `min-height` is the lever: `height` alone changes
       nothing while the floor stays at 170px. */
    html .hero-grid > .net-worth-card > .chart-wrap--inline { min-height: 120px; }
    html .hero-grid > .panel > .chart-wrap--panel { min-height: 104px; }

    /* Two columns divided by hairlines, as the design draws them: the 1px grid
       gap over a tinted ground is the rule, so no cell needs its own border and
       the corners stay clean. */
    html .flow-stats {
        overflow: hidden;
        grid-template-columns: 1fr 1fr;
        gap: 1px;
        padding-top: 0;
        border: 0;
        border-radius: 11px;
        background: #eeede8;
    }
    html .flow-stats > div {
        padding: 11px 13px;
        border-left: 0;
        background: #fff;
    }
    html .flow-stats > div:first-child { padding-left: 13px; }
    html .flow-stats span { font-size: 10.5px; font-weight: 600; letter-spacing: .07em; }
    html .flow-stats strong { font-size: 16px; }

    /* The bar the phone navigates by. The design marks a destination with a dot
       rather than a glyph — the same marker the desktop sidebar uses — so the
       two agree, and a row of five symbols stops competing with its own labels
       for the eye. The glyph stays in the markup and is shrunk to the dot, the
       way `.nav-link > span` already does it, rather than being edited out of a
       partial that also has to keep its accessible text. */
    /* Two across, each its own card. On desktop the three tiles share one card
       divided by rules; at this width they stack, and a vertical `border-right`
       between stacked tiles draws a hairline that separates nothing. */
    html .pay-summary {
        grid-template-columns: 1fr 1fr;
        gap: 10px;
        padding: 0;
        border: 0;
        background: transparent;
    }
    html .pay-summary__tile {
        padding: 14px 15px;
        border: 1px solid var(--line);
        border-radius: 14px;
        background: var(--panel);
    }
    html .pay-summary__tile strong { font-size: 20px; }
    html .pay-summary__caption {
        margin: 0;
        padding: 14px 15px;
        border: 1px solid var(--line);
        border-radius: 14px;
        background: var(--panel);
    }

    html .mobile-nav { padding: 9px 6px max(12px, env(safe-area-inset-bottom)); }
    html .mobile-nav a,
    html .mobile-nav button {
        gap: 5px;
        min-height: 48px;
        align-content: center;
        font-size: 0;
    }
    html .mobile-nav a::before,
    html .mobile-nav button::before {
        content: "";
        width: 8px;
        height: 8px;
        border-radius: 999px;
        background: #c9c8c1;
    }
    html .mobile-nav .active::before { background: var(--lime); }
    html .mobile-nav span { font-size: 10.5px; font-weight: 500; }
    html .mobile-nav .active span { font-weight: 700; }
    /* The bar is `justify-content: space-between`, so adding the mark as a first
       child pushed the title to the far right. Mark and title are one group; the
       actions keep the second row they already wrap onto. */
    html .topbar { justify-content: flex-start; gap: 12px; }
    html .topbar > div:not(.topbar-actions) { min-width: 0; flex: 1 1 auto; }

    /* The design leads its header with the brand mark, which the phone otherwise
       loses entirely — the sidebar that carries it is `display: none` here. */
    html .topbar-mark {
        display: flex;
        width: 30px;
        height: 30px;
        flex: 0 0 30px;
        align-items: center;
        justify-content: center;
        border-radius: 9px;
        background: var(--lime);
        color: #fff;
        font-size: 14px;
        font-weight: 700;
    }

    /* The ledger row, from the mobile design: name and amount on one line, then
       date · category · account on a second. Each of those three was taking a line
       of its own, so a single transaction ran to five and four fitted on a screen.

       `.ledger-meta` is `display: contents` on desktop — the category and account
       stay direct children of the row's grid and keep their own columns — and only
       here does it become a box of its own. */
    html .ledger-row {
        grid-template-columns: auto minmax(0, 1fr) auto;
        gap: 4px 8px;
        align-items: center;
        margin: 0;
        padding: 12px 0;
    }
    html .ledger-name { grid-area: 1 / 1 / 2 / 3; }
    html .ledger-amount { grid-area: 1 / 3 / 2 / 4; }
    html .ledger-date { grid-area: 2 / 1 / 3 / 2; display: flex; align-items: center; gap: 6px; font-size: 11px; }
    html .ledger-meta {
        display: flex;
        min-width: 0;
        grid-area: 2 / 2 / 3 / 3;
        align-items: center;
        gap: 8px;
    }
    html .ledger-row > .row-menu,
    html .ledger-row > span:last-child:empty { grid-area: 2 / 3 / 3 / 4; justify-self: end; }
    html .ledger-category { flex: 0 0 auto; }
    html .ledger-category > span { padding: 2px 8px; border-radius: 6px; font-size: 11px; }
    html .ledger-account { overflow: hidden; min-width: 0; font-size: 11px; text-overflow: ellipsis; white-space: nowrap; }
    html .ledger-pending { font-size: 9.5px; }
    html .ledger-row--head { display: none; }

    /* Search first and full width — it is the filter reached for most, and the one
       that needs the room. The pickers pair up underneath. */
    html .ledger-filters { grid-template-columns: 1fr 1fr; gap: 10px; }
    html .ledger-filters .field--search { order: -1; grid-column: 1 / -1; }
    html .ledger-filters .button { grid-column: 1 / -1; }
    html .ledger-active { justify-content: space-between; }
    /* Pills here rather than the desktop chip: the label is dropped to save the
       width, so the shape has to carry "this is removable" on its own. */
    html .ledger-active .filter-chip { max-width: 100%; border-radius: 999px; font-size: 12px; }
    html .ledger-active .filter-chip b { display: none; }

    /* Avatar, name, balance — the mobile design's three columns. The desktop
       template is `html .account-row` (0,1,1) and the collapse rule at the 860px
       break is a plain `.account-row` (0,1,0), so the five-column desktop grid
       with its `minmax(180px, 2fr)` name column survived onto a 390px phone: the
       name was squeezed to "Kia S…", the institution wrapped over four lines and
       the avatar was pushed to the far right. */
    html .account-row {
        grid-template-columns: 32px minmax(0, 1fr) auto 30px;
        gap: 0 11px;
        min-height: 0;
        padding: 11px 0;
    }
    html .account-name { grid-area: 1 / 2 / 2 / 3; min-width: 0; }
    html .account-name strong { overflow: hidden; font-size: 13.5px; text-overflow: ellipsis; white-space: nowrap; }
    html .account-name small { overflow: hidden; font-size: 11.5px; text-overflow: ellipsis; white-space: nowrap; }
    html .account-balance { grid-area: 1 / 3 / 2 / 4; font-size: 14px; white-space: nowrap; }
    html .account-row > .row-menu { grid-area: 1 / 4 / 2 / 5; }
    /* No room for it beside a name and a balance, and it carries no figure of its
       own — the balance it summarises is right there. */
    html .sparkline, html .sparkline--empty { display: none; }

}
