:root{
    --bg:#0A1420;
    --bg-grad: radial-gradient(1200px 800px at 85% -10%, rgba(51,214,166,0.09), transparent 60%),
               radial-gradient(900px 700px at -10% 110%, rgba(240,180,41,0.08), transparent 55%),
               #0A1420;
    --surface:#101E30;
    --surface-2:#16283D;
    --surface-3:#1C3149;
    --border: rgba(234,243,248,0.08);
    --border-strong: rgba(234,243,248,0.16);
    --text:#EAF3F8;
    --text-muted:#7C94AA;
    --text-faint:#4E657C;
    --mint:#33D6A6;
    --mint-dim: rgba(51,214,166,0.14);
    --gold:#F0B429;
    --gold-dim: rgba(240,180,41,0.14);
    --coral:#FF6B57;
    --coral-dim: rgba(255,107,87,0.14);
    --violet:#8B7CF6;
    --violet-dim: rgba(139,124,246,0.14);
    --radius: 14px;
    --shadow: 0 20px 50px -20px rgba(0,0,0,0.6);
  }
  *{box-sizing:border-box;}
  /* Global safety net, not a substitute for sizing icons deliberately.
     Every icon in this app is an inline <svg> with a viewBox but no
     explicit width/height — the browser default for that is 300x150px.
     This has caused the same "giant icon" bug twice now (modal titles,
     then a callout box) each time a new placement didn't get its own
     scoped sizing rule. Every existing rule (.nav-item svg, .btn svg,
     .modal h3 svg, etc.) is a class+element selector, which is MORE
     specific than this bare element selector and keeps winning exactly as
     before — this only catches the case where NO rule exists at all,
     which is precisely the case that kept slipping through. */
  svg{ width:18px; height:18px; }
  /* This blanket default is exactly why the QR code's SVG (from
     QRCodeGen.toSvg, a real content SVG with hundreds of modules, not a
     decorative icon) was getting squeezed to 18x18px and rendering as
     illegible noise — every module smaller than half a pixel. The
     library sets width/height as HTML ATTRIBUTES on its own <svg> tag,
     but a CSS rule always overrides a presentational attribute
     regardless of specificity, so the attribute alone couldn't win here.
     This class gives it a real, fixed DISPLAY size while letting the
     SVG's own viewBox scale proportionally to fill it — needed because,
     unlike an icon, the QR code's native module count (and so its
     natural pixel size) varies with the length of the encoded secret. */
  .qr-code-wrap svg{ width:200px; height:200px; display:block; }
  html,body{margin:0;padding:0;}
  body{
    background: var(--bg-grad);
    color:var(--text);
    font-family:'Inter',sans-serif;
    min-height:100vh;
    -webkit-font-smoothing:antialiased;
  }
  ::selection{ background:var(--mint); color:#052018; }
  ::-webkit-scrollbar{ width:8px; height:8px; }
  ::-webkit-scrollbar-thumb{ background:var(--surface-3); border-radius:8px; }
  ::-webkit-scrollbar-track{ background:transparent; }

  .num{ font-family:'JetBrains Mono',monospace; font-variant-numeric: tabular-nums; letter-spacing:-0.02em; }
  .display{ font-family:'Fraunces',serif; }

  a, button{ font-family:inherit; }
  button{ cursor:pointer; }

  #app{ display:flex; min-height:100vh; }

  /* ---------- SIDEBAR ---------- */
  #sidebar{
    width:300px; flex-shrink:0;
    background: rgba(16,30,48,0.6);
    border-right:1px solid var(--border);
    display:flex; flex-direction:column;
    height:100vh; position:sticky; top:0;
    backdrop-filter: blur(6px);
  }
  .brand{ padding:22px 20px 16px; display:flex; align-items:center; gap:10px; border-bottom:1px solid var(--border); }
  .brand .mark{
    width:34px; height:34px; border-radius:9px; flex-shrink:0;
    box-shadow: 0 6px 16px -4px rgba(51,214,166,0.5);
    object-fit: cover;
  }
  .brand-name{ font-family:'Fraunces',serif; font-size:19px; font-weight:600; line-height:1.1; }
  .brand-sub{ font-size:10.5px; color:var(--text-muted); letter-spacing:.09em; text-transform:uppercase; margin-top:2px; }

  .sidebar-scroll{ flex:1; overflow-y:auto; padding:14px 12px 10px; }
  .nav-item{
    display:flex; align-items:center; gap:10px; padding:9px 10px; border-radius:9px;
    color:var(--text-muted); font-size:13.5px; font-weight:500; cursor:pointer;
    border:1px solid transparent; margin-bottom:2px; transition:.15s;
  }
  .nav-item:hover{ background:var(--surface-2); color:var(--text); }
  .nav-item.active{ background:var(--surface-2); color:var(--text); border-color:var(--border-strong); }
  .nav-item svg{ width:15px; height:15px; flex-shrink:0; opacity:.85; }

  .group-block{ margin-top:16px; }
  .group-head{ display:flex; align-items:center; justify-content:space-between; padding:0 10px 6px; }
  .group-head .gh-left{ display:flex; align-items:center; gap:7px; min-width:0; }
  .group-title{ font-size:10.5px; letter-spacing:.1em; text-transform:uppercase; color:var(--text-faint); font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
  .group-total{ font-size:11px; color:var(--text-muted); }
  .group-total:hover{ color:var(--text); text-decoration:underline; }
  /* Monthly Exposure month-detail modal — each expense/income row links to
     its source wallet (or the Day-to-Day Expense page). Underline is
     transparent by default (reserves the layout space so nothing shifts)
     and revealed on hover, same "hover reveals the affordance" pattern as
     .group-total above. */
  .ted-link-row:hover{ background:var(--surface-2); border-radius:6px; }
  .ted-link-row:hover span{ text-decoration-color:currentColor !important; }
  .ted-link-row:hover .num{ color:var(--text); }
  .group-collapse-btn{ transform:rotate(0deg); transition:transform .2s ease; flex-shrink:0; margin-left:2px; }
  .group-collapse-btn.expanded{ transform:rotate(90deg); }
  .group-body{ overflow:hidden; max-height:1200px; opacity:1; transition:max-height .25s ease, opacity .2s ease; }
  .group-body.collapsed{ max-height:0; opacity:0; }
  .icon-btn{
    background:none; border:none; color:var(--text-faint); padding:3px; border-radius:6px; display:flex; align-items:center; justify-content:center;
  }
  .icon-btn:hover{ color:var(--text); background:var(--surface-3); }
  .icon-btn svg{ width:13px; height:13px; }

  /* Expected Expenses "mark as paid" tick — ticking it links that plan to
     a real Day-to-Day Expense entry (see markExpectedPaid in script.js). */
  .paid-toggle{
    width:22px; height:22px; border-radius:50%; border:1.5px solid var(--border-strong); background:none; padding:0;
    display:flex; align-items:center; justify-content:center; color:transparent; cursor:pointer; transition:.15s; flex-shrink:0;
  }
  .paid-toggle svg{ width:12px; height:12px; }
  .paid-toggle:hover{ border-color:var(--mint); }
  .paid-toggle.is-paid{ background:var(--mint); border-color:var(--mint); color:#052018; }
  .paid-note{ font-size:11px; color:var(--mint); margin-top:2px; }

  .wallet-row{
    display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:9px; cursor:pointer; margin-bottom:1px;
    border:1px solid transparent; transition:.15s;
  }
  .wallet-row:hover{ background:var(--surface-2); }
  .wallet-row.active{ background:var(--surface-2); border-color:var(--border-strong); }
  .wallet-dot{ width:7px; height:7px; border-radius:50%; flex-shrink:0; }
  .wallet-name{ font-size:13px; font-weight:500; flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .wallet-spark{ width:44px; height:20px; flex-shrink:0; opacity:.9; }
  .wallet-val{ font-size:11px; color:var(--text-muted); flex-shrink:0; }

  .add-subwallet{
    display:flex; align-items:center; gap:6px; padding:7px 10px; margin-top:2px;
    color:var(--text-faint); font-size:12px; background:none; border:1px dashed var(--border-strong); border-radius:9px; width:100%;
  }
  .add-subwallet:hover{ color:var(--mint); border-color:var(--mint); }
  .add-subwallet svg{ width:12px; height:12px; }

  .sidebar-foot{ padding:12px; border-top:1px solid var(--border); }
  .currency-picker{ display:flex; gap:4px; background:var(--surface); border-radius:10px; padding:4px; border:1px solid var(--border); }

  .nav-item-nested{ margin-left:8px; font-size:12.5px; }
  .signed-in-row{
    display:flex; align-items:center; gap:9px; padding:8px 10px; border-radius:9px;
    cursor:pointer; margin-top:10px; border:1px solid var(--border); background:var(--surface);
    min-width:0;
  }
  .signed-in-row:hover{ border-color:var(--border-strong); }
  .signed-in-row.expanded{ border-color:var(--border-strong); background:var(--surface-2); }
  .signed-in-row .profile-avatar{ width:26px; height:26px; font-size:11px; margin:0; flex-shrink:0; }
  .signed-in-text{ display:flex; flex-direction:column; min-width:0; line-height:1.25; flex:1; }
  .signed-in-label{ font-size:9.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; }
  .signed-in-email{ font-size:12px; font-weight:600; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
  .signed-in-row:not(.expanded) .signed-in-email{ color:var(--text-faint); letter-spacing:.14em; font-weight:700; }
  .signed-in-chevron{ width:13px; height:13px; flex-shrink:0; color:var(--text-faint); transform:rotate(0deg); transition:transform .16s ease, color .16s ease; }
  .signed-in-chevron svg{ width:100%; height:100%; }
  .signed-in-row.expanded .signed-in-chevron{ transform:rotate(90deg); }
  .signed-in-row:hover .signed-in-chevron{ color:var(--text-muted); }
  .nav-item-signout{ margin-top:6px; color:var(--text-muted); }
  .nav-item-signout:hover{ color:var(--coral); background:var(--coral-dim); }
  .currency-picker button{
    flex:1; background:none; border:none; color:var(--text-faint); font-size:11.5px; font-weight:600; padding:6px 0; border-radius:7px; font-family:'JetBrains Mono',monospace;
  }
  .currency-picker button.active{ background:var(--mint); color:#052018; }

  /* ---------- MAIN ---------- */
  /* flex:1 with no cap meant #main filled 100% of whatever was left after
     the sidebar — fine on a laptop screen, but on a large external
     monitor (24"+) that's often 1800-2200px+ of raw width. Every chart in
     this app (buildChart/buildBarChart/buildDualBarChart) is an SVG drawn
     at a fixed internal viewBox (900x260-ish) and stretched to its
     container's actual width via preserveAspectRatio="none" — deliberate,
     so its date/value axis text (real HTML, not squashed SVG <text> — see
     the comment on buildChart) never distorts at ANY width. But that same
     stretch has no *upper* bound of its own: past a certain container
     width the plotted line/bars visually thin out and the whole chart
     reads as flat and stretched rather than "designed", which is exactly
     what widened on a big external display. A max-width here — well
     within what even a 13" laptop viewport already has room for, so nothing
     changes at laptop sizes — caps every chart (and the rest of the page
     alongside it) at the width it was actually designed to look right at,
     on any screen at or above that size; flex:1 still lets it shrink
     naturally on anything narrower, unchanged. */
  #main{ flex:1; min-width:0; max-width:1400px; padding:26px 34px 60px; }
  .topbar{ display:flex; align-items:center; justify-content:space-between; margin-bottom:26px; gap:16px; flex-wrap:wrap; }
  .topbar-title{ font-family:'Fraunces',serif; font-size:26px; font-weight:600; }
  .topbar-sub{ color:var(--text-muted); font-size:13px; margin-top:3px; }
  .topbar-actions{ display:flex; gap:10px; }

  .btn{
    display:inline-flex; align-items:center; gap:7px; padding:9px 15px; border-radius:9px; font-size:13px; font-weight:600;
    border:1px solid var(--border-strong); background:var(--surface-2); color:var(--text); transition:.15s;
  }
  .btn:hover{ background:var(--surface-3); }
  /* A disabled button previously looked IDENTICAL to an enabled one — same
     colour, same solid mint fill, nothing to distinguish "intentionally
     locked" from "broken." That's exactly what made the passkey/authenticator
     mutual-exclusion buttons look unresponsive rather than deliberately
     inert. :hover is explicitly neutralised too, so hovering a disabled
     button doesn't create a false impression of interactivity. */
  .btn:disabled{ opacity:.4; cursor:not-allowed; filter:grayscale(.3); }
  /* Same reasoning as .btn:disabled above — the disabled USD rate field
     (fixed at 1, since it's the reference currency) had no visual signal
     either. Lower stakes than a button someone's trying to click, but
     cheap to fix and keeps the app consistent. */
  input:disabled{ opacity:.5; cursor:not-allowed; }
  .btn:disabled:hover{ background:var(--surface-2); }
  .btn-primary:disabled:hover{ background:var(--mint); }
  .btn svg{ width:14px; height:14px; }
  .btn-primary{ background:var(--mint); color:#052018; border-color:var(--mint); }
  .btn-primary:hover{ background:#3fe6b4; }
  .btn-ghost{ background:none; border-color:var(--border); color:var(--text-muted); }
  .btn-ghost:hover{ color:var(--text); border-color:var(--border-strong); }
  .btn-danger{ background:none; border-color:var(--coral); color:var(--coral); }
  .btn-danger:hover{ background:var(--coral-dim); }
  .btn-sm{ padding:6px 11px; font-size:12px; }
  .btn-lg{ padding:12px 28px; font-size:14.5px; }

  /* Hero */
  .hero{
    background: linear-gradient(160deg, var(--surface-2), var(--surface));
    border:1px solid var(--border); border-radius:20px; padding:28px 30px; margin-bottom:22px;
    display:flex; align-items:flex-end; justify-content:space-between; gap:30px; flex-wrap:wrap;
    position:relative; overflow:hidden;
  }
  .hero::before{
    content:''; position:absolute; inset:0; pointer-events:none;
    background: radial-gradient(500px 200px at 100% 0%, rgba(51,214,166,0.10), transparent 70%);
  }
  .hero-label{ display:flex; align-items:center; gap:7px; color:var(--text-muted); font-size:11.5px; letter-spacing:.08em; text-transform:uppercase; margin-bottom:10px; }
  .pulse-dot{ width:7px; height:7px; border-radius:50%; background:var(--mint); box-shadow:0 0 0 rgba(51,214,166,.6); animation:pulse 2.2s infinite; }
  @keyframes pulse{
    0%{ box-shadow:0 0 0 0 rgba(51,214,166,.55); }
    70%{ box-shadow:0 0 0 9px rgba(51,214,166,0); }
    100%{ box-shadow:0 0 0 0 rgba(51,214,166,0); }
  }
  .hero-value{ font-family:'JetBrains Mono',monospace; font-size:46px; font-weight:600; letter-spacing:-0.03em; }
  .hero-value .cents{ color:var(--text-muted); font-size:26px; }
  .hero-change{ font-size:13.5px; margin-top:8px; display:flex; align-items:center; gap:6px; }
  .chip{ display:inline-flex; align-items:center; gap:4px; padding:3px 9px; border-radius:20px; font-size:12px; font-weight:600; font-family:'JetBrains Mono',monospace; }
  .chip.up{ background:var(--mint-dim); color:var(--mint); }
  .chip.down{ background:var(--coral-dim); color:var(--coral); }
  .chip.flat{ background:var(--surface-3); color:var(--text-muted); }

  .hero-breakdown{ display:flex; gap:26px; flex-wrap:wrap; }
  .hb-item{ text-align:right; }
  .hb-label{ font-size:10.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.08em; margin-bottom:4px; }
  .hb-value{ font-family:'JetBrains Mono',monospace; font-size:17px; font-weight:600; }

  /* Grid cards for overview */
  .grid{ display:grid; grid-template-columns:repeat(auto-fill, minmax(280px,1fr)); gap:16px; }
  .card{ background:var(--surface); border:1px solid var(--border); border-radius:16px; padding:18px 20px; transition:.15s; cursor:pointer; }
  .spinner{ display:inline-block; width:14px; height:14px; border:2px solid var(--border-strong); border-top-color:var(--mint); border-radius:50%; animation:spin .7s linear infinite; flex-shrink:0; }
  @keyframes spin{ to{ transform:rotate(360deg); } }
  .card:hover{ border-color:var(--border-strong); transform:translateY(-1px); }
  .card.dragging{ opacity:.5; box-shadow:0 8px 24px rgba(0,0,0,.25); transform:scale(1.02); transition:none; }
  .wallet-drag-handle{ display:flex; align-items:center; justify-content:center; width:22px; height:22px; color:var(--text-faint); cursor:grab; touch-action:none; -webkit-user-select:none; user-select:none; }
  .wallet-drag-handle:hover{ color:var(--text-muted); }
  .wallet-drag-handle svg{ width:16px; height:16px; }
  .card-top{ display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
  .card-tag{ font-size:10.5px; letter-spacing:.07em; text-transform:uppercase; color:var(--text-faint); }
  .card-name{ font-family:'Fraunces',serif; font-size:18px; font-weight:600; margin-bottom:2px; }
  .card-value{ font-family:'JetBrains Mono',monospace; font-size:24px; font-weight:600; margin:8px 0 4px; }
  .card-foot{ display:flex; align-items:center; justify-content:space-between; margin-top:10px; }
  .card-spark{ width:100%; margin-top:8px; }
  .card-spark svg{ display:block; }
  .card-updated{ display:flex; justify-content:space-between; align-items:baseline; margin-top:10px; padding-top:8px; border-top:1px solid var(--border); font-size:11px; color:var(--text-faint); }
  .card-updated .num{ color:var(--text-faint); font-size:10.5px; }

  .section-title{ font-family:'Fraunces',serif; font-size:20px; font-weight:600; margin:34px 0 14px; display:flex; align-items:center; gap:10px; flex-wrap:wrap; }
  .section-title .n{ color:var(--text-faint); font-size:13px; font-family:'JetBrains Mono',monospace; font-weight:500; }

  /* "Show N entries" / search controls sitting alongside a section-title
     (Day-to-Day's Recent Entries, each wallet's own All Entries) — a plain
     flex row so the search box and the "Show" select line up on one baseline
     regardless of which (or both) are present. */
  .list-controls{ display:flex; align-items:center; gap:10px; flex-wrap:wrap; font-family:'Inter',sans-serif; font-size:13px; font-weight:400; }
  .list-controls select{ min-width:118px; }
  .search-box{ position:relative; display:flex; align-items:center; }
  /* Icons in ICONS are bare <svg> with only a viewBox — every placement in
     the app must size them explicitly or they fall back to the browser's
     300x150 default; this is that sizing for the search icon. */
  .search-box svg{ position:absolute; left:10px; width:14px; height:14px; color:var(--text-faint); pointer-events:none; }
  .search-box input{ padding-left:32px; width:200px; }
  .search-box input:focus{ width:240px; }

  /* Wallet detail */
  .detail-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:20px; flex-wrap:wrap; margin-bottom:18px; }
  /* min-width:0 overrides the flex default of min-width:auto, which sizes a
     flex item to its content's INTRINSIC width no matter how narrow the
     viewport gets — normally invisible, but .detail-name below is a bare
     <input> with no width/size attribute at a 28px heading font, and a
     browser's default intrinsic width for that is wide (~360px, scaled to
     the font size) since nothing tells it otherwise. Without min-width:0
     here (and on detail-name-row and detail-name itself, below), that
     intrinsic width wins over any viewport constraint and the whole page
     overflows horizontally on any phone-width screen — confirmed via a
     responsive audit at 320/375/414px, all three overflowing to a fixed
     426px page width regardless of actual viewport. flex:1 1 auto lets this
     side of the header take the space .topbar-actions doesn't need, same as
     it already visually did before this fix — this only changes what
     happens once space runs short.
  */
  .detail-head-main{ min-width:0; flex:1 1 auto; }
  .detail-name-row{ display:flex; align-items:center; gap:10px; min-width:0; }
  /* max-width raised from 420px, and overflow/text-overflow added, after a
     real long wallet name (a multi-coin crypto wallet, ~58 characters) was
     found silently clipped mid-word with no ellipsis or affordance that more
     text existed — the underlying name was always intact (editable, and
     shown in full elsewhere, e.g. the grid card which wraps to two lines),
     this was purely the single-line detail-page input visually hiding part
     of it. 480px covers most realistic names outright; text-overflow:ellipsis
     is the fallback for anything longer, so even an extreme name degrades to
     a clear "…" instead of an abrupt cut. Safe to widen: .detail-head is
     flex-wrap, so .topbar-actions (the Delete button) simply wraps to its
     own line if a wider name ever leaves it no room, rather than colliding.
  */
  .detail-name{ font-family:'Fraunces',serif; font-size:28px; font-weight:600; background:none; border:none; color:var(--text); border-bottom:2px solid transparent; padding:2px 0; max-width:480px; width:100%; min-width:0; flex:1 1 auto; overflow:hidden; text-overflow:ellipsis; }
  .detail-name:focus{ outline:none; border-bottom:2px solid var(--mint); }
  .detail-meta{ color:var(--text-muted); font-size:12.5px; margin-top:5px; }

  .stat-row{ display:flex; gap:26px; flex-wrap:wrap; margin:18px 0 6px; }
  .stat{ min-width:120px; }
  .stat-label{ font-size:10.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.08em; margin-bottom:5px; }
  .stat-val{ font-family:'JetBrains Mono',monospace; font-size:19px; font-weight:600; }

  .range-tabs{ display:flex; flex-wrap:wrap; gap:6px; margin:20px 0 14px; }
  .range-tab{
    background:var(--surface); border:1px solid var(--border); color:var(--text-muted); font-size:12px; font-weight:600;
    padding:6px 12px; border-radius:8px; font-family:'JetBrains Mono',monospace;
  }
  .range-tab:hover{ color:var(--text); border-color:var(--border-strong); }
  .range-tab.active{ background:var(--mint); color:#052018; border-color:var(--mint); }

  .chart-wrap{ background:var(--surface); border:1px solid var(--border); border-radius:16px; padding:18px 18px 8px; position:relative; }
  .bar-hit-area{ cursor:pointer; }
  .bar-hit-area:hover{ fill:rgba(234,243,248,0.05); }
  /* buildBarChart's per-bar labels — see the comment on that function for
     why these are real HTML text over the SVG rather than <text> inside
     it. pointer-events:none so they never steal the click meant for the
     .bar-hit-area rect underneath them. */
  .bc-label{
    position:absolute; transform:translateX(-50%); white-space:nowrap;
    pointer-events:none; font-size:10.5px; line-height:1.3;
  }
  .bc-value{ font-family:'JetBrains Mono',monospace; color:rgba(234,243,248,0.78); }
  .bc-month{ font-family:'Inter',sans-serif; color:rgba(124,148,170,0.9); }
  /* buildDualBarChart's per-month value labels (Monthly Exposure) — one
     label per bar now, not one combined label above a touching pair (see
     the comment on that function for why the chart itself moved to a
     diverging, zero-line-split layout). Each is colored to match its own
     bar/legend swatch, same as before, so which number is which still
     needs no re-reading. .bc-val-income is anchored by its OWN bottom edge
     (translateY(-100%), same technique buildBarChart's single-series
     .bc-value already uses) so it grows upward, away from its bar above
     the zero line; .bc-val-expense uses .bc-label's default top-anchor,
     growing downward, away from its bar below the zero line. Because the
     two bars (and now their labels) sit on opposite sides of a shared zero
     line instead of touching each other, neither label can ever collide
     with the other or with its own bar — the collision risk the old
     combined-pair label and its mobile-only stacking fallback existed
     specifically to manage doesn't exist in this layout, at any width. */
  .bc-val-income, .bc-val-expense{ font-family:'JetBrains Mono',monospace; font-weight:600; }
  .bc-val-income{ color:#33D6A6; transform:translateX(-50%) translateY(-100%); }
  .bc-val-expense{ color:#FF6B57; }
  /* buildDualBarChart's scroll mode (see its own comment) — only kicks in
     when a long "All" range has too many months for every candle to keep
     a legible minimum width, so this scrolls independently of the page
     itself rather than the whole chart card being squeezed unreadably
     thin. A little bottom padding keeps the horizontal scrollbar (where
     the browser draws one) from sitting flush against the value labels
     above it. */
  .barchart-scroll{ overflow-x:auto; padding-bottom:4px; -webkit-overflow-scrolling:touch; }
  /* Deliberately NOT a bare ".chart-wrap svg" rule anymore — that used to
     exist here for the sparkline/history charts, but as a blanket
     descendant selector it silently matched ANY svg nested inside a
     .chart-wrap card, including unrelated button icons (.chart-wrap is
     used for nearly every card in this app). Same specificity as .btn
     svg, later in source order, so it kept winning the tie and stretching
     icons to fill their card — the actual cause behind the Legal section's
     giant lock icon. The three real chart-rendering functions
     (buildChart, buildBarChart, buildSparkline) now each set width/height
     directly via inline style on their own <svg> tag, which always wins
     regardless of any class-based rule elsewhere, so nothing here can leak
     onto icons added later the same way this did. */
  .no-data{ padding:60px 10px; text-align:center; color:var(--text-faint); font-size:13px; }

  /* Shown only when buildChart had to clip its own x-axis domain (the
     wallet/account is younger than the selected range, so there's no real
     data to fill the rest of it) — see filterHistoryForRange. Small and
     out of the way on purpose: it's a footnote explaining why the chart's
     span looks shorter than the active range button, not a warning. */
  .chart-range-note{ font-size:11px; color:var(--text-faint); margin-bottom:8px; }

  /* Full chart layout (buildChart's showLabels:true path): a flexible plot
     column (the SVG plus its date-tick row below it) beside a fixed-width
     value-label column. Deliberately real HTML/CSS text here, not SVG
     <text> — the SVG scales non-uniformly on narrow screens (viewBox width
     900 stretched to fit, but height fixed in real px), which squashed
     in-SVG text horizontally into near-illegible slivers on phones. HTML
     text beside/below the SVG has no such problem at any width. */
  .chart-row{ display:flex; align-items:flex-start; gap:8px; }
  .chart-plot-col{ flex:1; min-width:0; }
  .chart-x-row{ position:relative; height:16px; margin-top:4px; }
  .chart-x-row .cxt{
    position:absolute; top:0; transform:translateX(-50%);
    font-family:'JetBrains Mono',monospace; font-size:10.5px; color:rgba(124,148,170,0.9);
    white-space:nowrap;
  }
  .chart-value-col{
    flex-shrink:0; width:54px; box-sizing:border-box;
    position:relative; text-align:right;
  }
  /* Positioned absolutely (not flex/space-between) specifically so the two
     labels can sit OUTSIDE the box's own height — a few px above the plot's
     top edge and a few px below its bottom edge, clear of the grid entirely
     — instead of sharing that height with the grid the way space-between
     would force them to. See buildChart's valueColHtml comment for the
     px values and why. */
  .chart-value-col .cvl{
    position:absolute; right:0;
    font-family:'JetBrains Mono',monospace; font-size:11px; font-weight:600; color:rgba(199,212,224,0.85);
    line-height:1;
  }

  /* Hover/scrub tooltip for the full-size interactive charts (buildChart's
     showLabels:true path). Positioned in JS (handleChartHover) as inline
     left/top in px relative to this .chart-wrap; display toggled the same
     way. Hidden by default so it never flashes on first paint. */
  .chart-tooltip{
    display:none; position:absolute; z-index:5; pointer-events:none;
    background:var(--surface-2); border:1px solid var(--border-strong); border-radius:8px;
    padding:7px 10px; box-shadow:0 6px 18px rgba(0,0,0,0.35);
    font-family:'JetBrains Mono',monospace; white-space:nowrap;
  }
  .chart-tooltip .ct-date{ font-size:10px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.05em; margin-bottom:2px; }
  .chart-tooltip .ct-val{ font-size:13px; font-weight:700; color:var(--text); }
  /* v146: second value line, gain/loss vs. invested capital as of the
     hovered date — only populated on charts that opt in (see
     handleChartHover's showGainLoss check); display:none by default so it
     takes no space on charts that never set it. */
  .chart-tooltip .ct-gain{ display:none; font-size:11px; font-weight:600; margin-top:2px; }

  .entry-form{ display:flex; gap:10px; flex-wrap:wrap; align-items:flex-end; margin-top:18px; background:var(--surface); border:1px solid var(--border); border-radius:14px; padding:16px; }
  /* v138c: the v137 guided-mode toggle (.entry-mode-toggle/.entry-mode-btn)
     was removed along with the mode question itself — see entryFormHtml's
     own comment. .entry-mode-help stays: the single-button form still shows
     one short help line under it, flex-basis:100% to keep it on its own row
     inside .entry-form's flex-wrap layout, same as before. */
  .entry-mode-help{ flex-basis:100%; font-size:11.5px; color:var(--text-faint); line-height:1.55; margin-top:-2px; }
  .field{ display:flex; flex-direction:column; gap:5px; }
  .field label{ font-size:10.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.07em; }
  input, select{
    background:var(--surface-2); border:1px solid var(--border-strong); color:var(--text); border-radius:8px; padding:8px 10px; font-size:13px; font-family:'JetBrains Mono',monospace;
  }
  select{ font-family:'Inter',sans-serif; }
  input:focus, select:focus{ outline:none; border-color:var(--mint); }
  input[type="date"]{ color-scheme: dark; }
  /* The native up/down spin buttons on every type="number" field were
     never themed and reserve their own chunk of the input's width even
     when not visibly drawn — that's what was quietly eating into the
     narrow amount fields below (see .med-row input[type="number"]) and
     clipping "EUR 0.00" down to "EUR 0.0". Nothing in the app relies on
     the native step arrows, so drop them everywhere for a cleaner, fully
     usable text width. */
  input[type="number"]{ -moz-appearance:textfield; }
  input[type="number"]::-webkit-outer-spin-button,
  input[type="number"]::-webkit-inner-spin-button{ -webkit-appearance:none; margin:0; }

  /* European date field: Chromium's native <input type="date"> always
     renders its text in the OS/browser locale (confirmed: the lang="…"
     attribute does NOT override this), so a US-locale browser shows
     MM/DD/YYYY no matter what the page asks for — including while a user
     is actively typing into it or using its native calendar picker, not
     just at rest. An earlier version of this field only fixed the at-rest
     case (a DD/MM/YYYY overlay that stepped aside to reveal the real
     native text during editing); this version instead replaces the
     visible surface entirely with three plain DD / MM / YYYY text
     segments plus a custom calendar button (see euDateInputHtml() /
     initEuDateFields() / euDateOpenCalendar() in script.js) — genuinely
     European in every state, because the browser's own locale-formatted
     text is never shown to the user at all now. The real native input is
     still present at the same id/class (every existing .value read and
     'change' listener elsewhere in the app, plus Playwright's
     page.fill(), keeps working unchanged) but is fully invisible and
     inert to the pointer — it exists only to keep being the source of
     truth script.js already reads/writes everywhere else. */
  .eu-date-wrap{ position:relative; display:inline-flex; align-items:center; gap:2px; background:var(--surface-2); border:1px solid var(--border-strong); border-radius:8px; padding:0 4px 0 10px; height:34px; box-sizing:border-box; }
  .eu-date-wrap:focus-within{ border-color:var(--mint); }
  .eu-date-native{ position:absolute; inset:0; width:100%; height:100%; opacity:0; pointer-events:none; border:0; padding:0; margin:0; }
  .eu-date-seg-group{ display:flex; align-items:center; }
  .eu-date-seg{
    background:transparent; border:0; outline:0; color:var(--text); font-size:13px; font-family:'JetBrains Mono',monospace;
    text-align:center; padding:0;
  }
  .eu-date-seg[data-seg="d"], .eu-date-seg[data-seg="m"]{ width:2.1ch; }
  .eu-date-seg[data-seg="y"]{ width:4.3ch; }
  .eu-date-seg::placeholder{ color:var(--text-faint); }
  .eu-date-sep{ color:var(--text-faint); font-size:13px; font-family:'JetBrains Mono',monospace; }
  .eu-date-cal-btn{ background:none; border:0; color:var(--text-faint); padding:5px; margin-left:auto; border-radius:6px; display:flex; align-items:center; cursor:pointer; flex-shrink:0; }
  .eu-date-cal-btn:hover{ color:var(--text); background:var(--surface-3); }
  .eu-date-cal-btn svg{ width:14px; height:14px; }
  /* Fills the field's own container where one was given an explicit width
     (a modal field, or a med-row's fixed-width date column) — elsewhere
     (e.g. .entry-form .field, which never sized input[type=date]) the wrap
     stays inline-flex/shrink-to-fit, matching pre-existing behavior. */
  .modal .eu-date-wrap{ width:100%; }
  .eu-date-cal-popup{
    position:fixed; z-index:90; background:var(--surface-2); border:1px solid var(--border-strong); border-radius:12px;
    box-shadow:var(--shadow); padding:12px; width:250px; font-family:'Inter',sans-serif;
  }
  .eu-date-cal-header{ display:flex; align-items:center; justify-content:space-between; margin-bottom:10px; }
  .eu-date-cal-title{ font-size:13px; font-weight:600; color:var(--text); }
  .eu-date-cal-nav{ background:none; border:0; color:var(--text-muted); padding:4px; border-radius:6px; cursor:pointer; display:flex; align-items:center; }
  .eu-date-cal-nav:hover{ color:var(--text); background:var(--surface-3); }
  .eu-date-cal-nav svg{ width:13px; height:13px; }
  .eu-date-cal-grid{ display:grid; grid-template-columns:repeat(7,1fr); gap:2px; }
  .eu-date-cal-dow{ font-size:10px; color:var(--text-faint); text-align:center; padding:4px 0; text-transform:uppercase; }
  .eu-date-cal-day{ background:none; border:0; color:var(--text); font-size:12.5px; padding:6px 0; border-radius:6px; cursor:pointer; font-family:'JetBrains Mono',monospace; }
  .eu-date-cal-day:hover{ background:var(--surface-3); }
  .eu-date-cal-day.eu-date-cal-today{ box-shadow:inset 0 0 0 1px var(--border-strong); }
  .eu-date-cal-day.eu-date-cal-selected{ background:var(--mint); color:#052018; font-weight:700; }

  table.entries{ width:100%; border-collapse:collapse; margin-top:16px; font-size:13px; }
  table.entries th{ text-align:left; font-size:10.5px; color:var(--text-faint); text-transform:uppercase; letter-spacing:.06em; padding:8px 10px; border-bottom:1px solid var(--border); }
  table.entries td{ padding:9px 10px; border-bottom:1px solid var(--border); color:var(--text-muted); font-family:'JetBrains Mono',monospace; }
  table.entries tr:hover td{ color:var(--text); }
  table.entries td.desc{ font-family:'Inter',sans-serif; color:var(--text); }
  table.entries tr.month-header-row td{ background:var(--surface-2); color:var(--text-muted); padding:9px 12px; border-bottom:1px solid var(--border-strong); }
  table.entries tr.month-header-row:hover td{ color:var(--text-muted); }
  /* Risk Model's comparison table — highlights whichever fund's tab is
     currently selected below it, same active-state language (surface-2
     background) already used for .wallet-row.active and .nav-item.active. */
  table.entries tr.active td{ background:var(--surface-2); color:var(--text); }
  /* Long-Term Portfolio's merged "All Entries" table (see renderWalletDetail)
     shows two different kinds of row — a real value reading, and a money-in
     contribution (including ones synced automatically from a linked Static
     Expenses wallet) — tagged so the two are never mistaken for each other. */
  table.entries tr.entry-contribution-row td{ background:var(--gold-dim); }
  table.entries tr.entry-withdrawal-row td{ background:var(--coral-dim); }
  .entry-tag{ display:inline-block; font-size:10px; font-weight:600; text-transform:uppercase; letter-spacing:.04em; padding:1px 6px; border-radius:5px; margin-bottom:2px; }
  .entry-tag-contrib{ background:var(--gold-dim); color:var(--gold); }
  .entry-tag-value{ background:var(--surface-2); color:var(--text-faint); }
  .entry-tag-withdrawal{ background:var(--coral-dim); color:var(--coral); }

  .empty-state{ text-align:center; padding:70px 20px; color:var(--text-muted); }
  .empty-state svg{ width:40px; height:40px; opacity:.4; margin-bottom:12px; }

  .modal-bg{ position:fixed; inset:0; background:rgba(5,10,16,0.6); backdrop-filter:blur(3px); display:flex; align-items:center; justify-content:center; z-index:50; }
  .modal{ background:var(--surface-2); border:1px solid var(--border-strong); border-radius:16px; padding:22px; width:360px; max-width:90vw; box-shadow:var(--shadow); }
  /* 480 -> 540: the Expected Expenses month-detail modal's rows gained a
     sixth control (the paid tick, alongside month/name/details/amount/
     delete) and were already tight at 480 with two flex:1 text inputs
     sharing the leftover space — a bit more width keeps both legible
     instead of truncating further. Day-to-Day's own wide modal (4 controls)
     shares this class too; it just gets a little breathing room from it. */
  .modal-wide{ width:540px; }
  .modal h3{ font-family:'Fraunces',serif; margin:0 0 14px; font-size:18px; display:flex; align-items:center; gap:8px; }
  .settings-method-label{ font-size:13px; font-weight:600; margin-bottom:4px; display:flex; align-items:center; gap:6px; }
  .settings-method-label svg{ width:15px; height:15px; flex-shrink:0; }
  /* Same fix as the modal-title icon bug — an <svg> with only a viewBox
     and no explicit width/height falls back to the browser default of
     300x150px. Every icon placement needs an explicit scoped rule; there's
     no such thing as an icon that's "just naturally the right size." */
  .faq-callout-icon svg{ width:22px; height:22px; flex-shrink:0; }
  /* Without this, an inline <svg> with only a viewBox and no explicit
     width/height falls back to the browser default of 300x150px — that's
     the giant lock icon. Every other icon in this app is sized by a rule
     scoped to its container (.nav-item svg, .btn svg, etc.); modal titles
     never had one, so this was a latent bug since the very first TOTP
     modal, not something the WebAuthn work introduced — it just reused the
     same unsized pattern twice more and made it impossible to miss. */
  .modal h3 svg{ width:18px; height:18px; flex-shrink:0; }
  .modal .field{ margin-bottom:12px; width:100%; }
  .modal input, .modal select{ width:100%; }
  .modal-actions{ display:flex; justify-content:flex-end; gap:8px; margin-top:16px; }
  .med-list{ max-height:280px; overflow-y:auto; }
  .med-row{ display:flex; gap:6px; align-items:center; padding:6px 0; }
  .med-row input[type="month"]{ width:108px; flex-shrink:0; font-size:11.5px; padding:6px 7px; }
  .med-row .eu-date-wrap{ width:130px; flex-shrink:0; height:30px; padding:0 3px 0 8px; }
  /* .med-row input[type="text"] below (flex:1; min-width:0, meant for the
     row's free-text note/description field) was also matching the day/
     month/year segment inputs nested in .eu-date-wrap, since they're
     type="text" too — its flex-basis:0% silently overrode each segment's
     own ch-based width, so day/month/year all got squeezed to the same
     equal-thirds width instead of the year's wider 4.3ch, clipping the
     year to 3 digits ("202" instead of "2025"). Pin the segments back to
     their own intrinsic width with a selector specific enough to win. */
  .med-row .eu-date-wrap .eu-date-seg{ flex:none; min-width:0; }
  .med-row .eu-date-seg, .med-row .eu-date-sep{ font-size:11.5px; }
  .med-row .eu-date-cal-btn{ padding:3px; }
  .med-row .eu-date-cal-btn svg{ width:12px; height:12px; }
  .med-row input[type="text"]{ flex:1; min-width:0; }
  .med-row input[type="number"]{ width:98px; flex-shrink:0; }
  .med-row .icon-btn{ flex-shrink:0; }

  .wallet-reorder{ display:flex; flex-direction:column; gap:1px; opacity:0; flex-shrink:0; }
  .wallet-row:hover .wallet-reorder{ opacity:1; }
  .wallet-reorder .icon-btn{ padding:1px; }
  .wallet-reorder .icon-btn svg{ width:10px; height:10px; }
  .group-head-icon{ width:12px; height:12px; color:var(--text-faint); flex-shrink:0; }
  .group-head-icon svg{ width:100%; height:100%; }

  .toast{ position:fixed; bottom:22px; left:50%; transform:translateX(-50%); background:var(--surface-3); border:1px solid var(--border-strong); color:var(--text); padding:10px 18px; border-radius:10px; font-size:13px; box-shadow:var(--shadow); z-index:80; opacity:0; pointer-events:none; transition:.25s; display:flex; align-items:center; gap:12px; }
  .toast.has-action{ pointer-events:auto; }
  .toast-action{ background:none; border:none; color:var(--mint); font-weight:600; font-size:13px; padding:0; cursor:pointer; white-space:nowrap; }
  .toast-action:hover{ text-decoration:underline; }
  .toast.show{ opacity:1; transform:translate(-50%,-4px); }

  @media (max-width: 880px){
    #sidebar{ position:fixed; z-index:40; transform:translateX(-100%); transition:.25s; box-shadow:var(--shadow); }
    #sidebar.open{ transform:translateX(0); }
    #main{ padding:18px 16px 50px; }
    .hero-value{ font-size:34px; }
    .menu-toggle{ display:flex !important; }
  }
  .menu-toggle{ display:none; background:var(--surface-2); border:1px solid var(--border-strong); border-radius:9px; width:38px; height:38px; align-items:center; justify-content:center; color:var(--text); }

  /* Brand statement, closing out the Portfolio Overview page below the
     wallet grid — the same copy that used to live on the pre-login picker
     screen, moved here so it reads as a closing thought once you've
     actually seen your numbers rather than as marketing before you're in.
     No text-shadow/photo treatment needed here (flat surface, not the
     picker's mountain image) but keeps the same Fraunces headline + mint
     kicker for brand consistency. */
  .overview-brand-footer{
    margin:46px 0 10px; padding:34px 20px 4px;
    border-top:1px solid var(--border);
    text-align:center; display:flex; flex-direction:column; align-items:center;
  }
  .overview-brand-footer .obf-headline{
    font-family:'Fraunces',serif; font-weight:600; line-height:1.3;
    font-size:clamp(17px, 2.5vw, 23px);
    max-width:min(90%, 1300px); margin-bottom:14px; color:var(--text);
  }
  .overview-brand-footer .obf-body{
    color:var(--text-muted); font-size:13.5px; max-width:min(84%, 1220px); line-height:1.65;
    text-wrap:balance; text-wrap:pretty;
  }
  .overview-brand-footer .obf-body p{ margin:0 0 12px; }
  .overview-brand-footer .obf-body p:last-child{ margin-bottom:0; }
  .overview-brand-footer .obf-kicker{
    font-family:'Fraunces',serif; font-weight:600; font-size:14px; letter-spacing:.01em;
    color:var(--mint); margin:20px 0 6px;
  }
  @media (max-width:600px){
    .overview-brand-footer{ margin-top:34px; padding-top:26px; }
    .overview-brand-footer .obf-headline{ font-size:18px; max-width:340px; }
    .overview-brand-footer .obf-body{ max-width:340px; font-size:13px; }
    .overview-brand-footer .obf-kicker{ font-size:13px; max-width:320px; }
  }

  /* Profile picker */
  .picker-screen{ width:100%; min-height:100vh; position:relative; overflow:hidden; }
  .picker-bg{
    position:absolute; inset:-30px; z-index:0;
    background-image:var(--picker-bg-image);
    background-size:cover; background-position:26% 2%;
    transform-origin:50% 8%;
    animation:pickerZoom 28s ease-in-out infinite alternate;
    will-change:transform;
  }
  .picker-overlay{
    position:absolute; inset:0; z-index:1;
    /* The mountain photo used to sit behind a vertically-centered single
       screenful of content, so the lighter top of this gradient (opacity
       .28) was mostly off-screen above the logo. The home screen's nav +
       headline now start right at the top of the page, so that stop is
       raised to .64 — dark-navy enough for the headline body text and the
       ghost "Sign Up" button to stay legible against the brighter parts
       of the rock face, closer to the reference design's flatter navy
       background while keeping the same photo for continuity. */
    background:
      linear-gradient(180deg, rgba(10,20,32,.64) 0%, rgba(10,20,32,.82) 45%, var(--bg) 92%),
      linear-gradient(90deg, rgba(10,20,32,.55), rgba(10,20,32,.15) 42%, rgba(10,20,32,.55));
  }
  @keyframes pickerZoom{ from{ transform:scale(1); } to{ transform:scale(1.05); } }
  @media (prefers-reduced-motion: reduce){ .picker-bg{ animation:none; } }
  .picker-content{
    position:relative; z-index:2; min-height:100vh;
    display:flex; flex-direction:column; align-items:center; justify-content:center;
    padding:40px 20px; text-align:center;
  }
  /* Home / landing screen — two-column hero (headline + CTA on the left,
     illustrative wallet-shaped cards on the right), replacing the old
     single centered column. Still sits inside the existing
     .picker-screen/.picker-bg/.picker-overlay wrapper above (the mountain
     photo + dark-navy gradient veil), so the background stays consistent
     with the rest of the app — only the content layout below is new.
     Deliberately light on green: the old version leaned on --mint for the
     hero graphic, the stat-strip icons AND the security banner all at
     once. Here the hero chart uses --violet instead, the portfolio card
     keeps a single small mint sparkline (consistent with the rest of the
     app using mint for "up"), and mint elsewhere is limited to small
     accents (a badge dot, feature icons, the security-row icons). */
  .home-content{
    position:relative; z-index:2; max-width:1180px; margin:0 auto;
    display:grid; grid-template-columns:minmax(0,1fr) minmax(0,440px); gap:56px;
    align-items:center; padding:64px 32px 40px;
  }
  /* Logo sits at the top of the copy column now, not in a separate nav
     row — moved down and enlarged back to its pre-v145 size (72px icon,
     same as the old centered picker screen used) per direct feedback.
     display:flex + width:fit-content keeps this block-level (its own
     line, so the badge below it doesn't ride up alongside it) while
     still shrinking to its own content width — otherwise brandLockup()'s
     own inline justify-content:center would center it across the full
     column width instead of sitting flush with the left edge the
     badge/headline/body below it are aligned to. */
  .home-logo{ display:flex; width:fit-content; margin-bottom:26px; filter:drop-shadow(0 4px 20px rgba(0,0,0,0.5)); }
  .home-badge{
    display:inline-flex; align-items:center; gap:8px; padding:6px 14px;
    border-radius:20px; background:rgba(16,30,48,0.6); border:1px solid var(--border-strong);
    font-size:12px; font-weight:600; color:#C7D4E0; letter-spacing:.01em; margin-bottom:22px;
  }
  .home-badge-dot{ width:6px; height:6px; border-radius:50%; background:var(--mint); flex-shrink:0; }
  .home-headline{ font-size:clamp(32px,4.4vw,50px); line-height:1.1; font-weight:600; margin:0 0 18px; text-shadow:0 2px 16px rgba(0,0,0,0.4); }
  .home-body{ font-size:15.5px; line-height:1.65; color:var(--text-muted); max-width:440px; margin:0 0 30px; }
  .home-cta-row{ display:flex; gap:12px; margin-bottom:32px; flex-wrap:wrap; }
  .home-feature-list{
    display:flex; align-items:center; gap:20px; row-gap:10px; flex-wrap:wrap;
    padding-top:24px; border-top:1px solid var(--border);
  }
  .pss-item{
    display:flex; align-items:center; gap:7px; font-size:12px; font-weight:600; letter-spacing:.01em;
    color:#C7D4E0; text-shadow:0 1px 10px rgba(0,0,0,0.5);
  }
  .pss-item svg{ width:15px; height:15px; color:var(--mint); flex-shrink:0; }
  .home-cards{ display:flex; flex-direction:column; gap:16px; }
  .home-card{ padding:20px 20px 18px; }
  .home-card-head{ display:flex; align-items:flex-start; justify-content:space-between; gap:10px; margin-bottom:14px; }
  .home-card-kicker{ font-size:11px; font-weight:700; letter-spacing:.08em; text-transform:uppercase; color:var(--text-faint); }
  .home-card-sub{ font-size:13px; color:var(--text); margin-top:3px; }
  .home-card-value{ font-size:29px; font-weight:600; margin:2px 0 10px; }
  .home-chip-row{ display:flex; align-items:center; gap:8px; margin-bottom:14px; flex-wrap:wrap; }
  .home-chip{
    width:22px; height:22px; border-radius:50%; display:flex; align-items:center; justify-content:center;
    font-size:10px; font-weight:700; flex-shrink:0;
  }
  .home-chip-label{ font-size:11.5px; color:var(--text-faint); margin-left:2px; }

  /* Security trust row — same four-claim message as before (Zero-Knowledge
     Encryption, 2FA & Passkey, Email Verification, Bank-Level Encryption)
     but as separate icon+label items in a full-width row under the hero,
     rather than one bullet-separated string anchored to the viewport
     bottom — this page now scrolls, so nothing here is absolutely
     positioned. */
  .home-security-row{
    position:relative; z-index:2; max-width:1180px; margin:0 auto; padding:22px 32px 0;
    display:flex; align-items:center; justify-content:center; gap:28px; row-gap:12px; flex-wrap:wrap;
    border-top:1px solid var(--border);
  }
  .home-security-item{ display:flex; align-items:center; gap:8px; font-size:12px; font-weight:600; color:#C7D4E0; }
  .home-security-item svg{ width:15px; height:15px; color:var(--mint); flex-shrink:0; }

  .home-footer-links{ display:flex; justify-content:center; padding:22px 32px 36px; position:relative; z-index:2; }
  .home-footer-links span{
    font-size:11.5px; color:var(--text-faint); cursor:pointer;
    text-decoration:underline; text-underline-offset:3px; text-decoration-color:rgba(124,148,170,0.4);
    transition:.15s;
  }
  .home-footer-links span:hover{ color:#C7D4E0; text-decoration-color:currentColor; }

  @media (max-width:900px){
    .home-content{ grid-template-columns:1fr; gap:40px; padding:40px 22px 30px; }
    .home-cards{ order:2; max-width:440px; }
  }
  @media (max-width:600px){
    .home-headline{ font-size:clamp(28px,8vw,36px); }
    .home-body{ font-size:14.5px; }
    .home-feature-list{ gap:14px; }
    .pss-item{ font-size:11.5px; }
    .home-security-row{ gap:16px; padding:18px 20px 0; }
    .home-security-item{ font-size:11px; }
  }

  .profile-avatar{
    width:56px; height:56px; border-radius:50%; margin:0 auto 12px; display:flex; align-items:center; justify-content:center;
    font-family:'Fraunces',serif; font-size:22px; font-weight:600; color:#052018;
    background:linear-gradient(145deg, var(--mint), #1a9c78);
  }