/* Sakina — dark forest-green theme, matching the approved demo. */

:root{
  /* ⚠️ Black + green, 2026-08-26 (HANDOFF §111). Pure-black ground, panels
     barely lifted off it, green kept as an ACCENT (interactive, positive)
     rather than washed across everything — the "professional, not
     vibe-coded" brief. */
  /* ⚠️ **One green, and it is the vibrant one.** `--accent` used to be a
     duller green than `--green`, so the app carried two greens that read as
     a mistake rather than a hierarchy. Both are the same vibrant green now
     (HANDOFF §113). */
  /* ⚠️ **Secondary text is white, not grey.** Every label, meta line, unit
     and caption used `--muted` at #8a9c93, and he asked for them white on
     screen after screen (HANDOFF §115). All 79 uses are `color:` — no
     borders or fills — so raising it here whitens them everywhere at once.
     Hierarchy now comes from **size and weight**, which were already doing
     most of the work: 11–12px labels against 26px figures.
     `--faint` keeps a genuinely recessive tone for the few places that must
     stay back: input placeholders and out-of-month calendar days. */
  --bg:#000000; --panel:#0b0f0d; --panel2:#121815; --line:#202723;
  --text:#f1f5f2; --muted:#e9efec; --faint:#8a9c93;
  --accent:#3ddc84; --green:#3ddc84;
  --red:#f2726b; --yellow:#e0b45c; --purple:#a855f7; --pink:#f472b6;
  /* Added 2026-08-26: category-bar colours that were referenced but never
     defined, so a Rent & Utilities bar (colour "blue") and every "grid"
     catch-all bar rendered with no fill (HANDOFF §109). --grid is a muted
     neutral for uncategorised spend; --blue completes the palette. */
  --blue:#5aa9e6; --grid:#4a5f52;
  --radius:16px; --shadow:0 8px 30px rgba(0,0,0,.4);
  /* ⚠️ **The status-bar insets, named once.**
     `apple-mobile-web-app-status-bar-style:black-translucent` makes an
     installed copy run *under* the clock and the Dynamic Island, so the top
     of the page has to be pushed clear of it. `env(...)` is 0 in a browser
     tab — which is why a mistake here is invisible in Safari and obvious on
     the Home Screen, and exactly how the double inset below got shipped.
     Named so that ONE element applies it, and so a check can set
     `--safe-top` to a real value and confirm the page moves down by that
     much and no more. */
  --safe-top:env(safe-area-inset-top,0px);
  --safe-bottom:env(safe-area-inset-bottom,0px);
}
*{box-sizing:border-box;margin:0;padding:0}
html{-webkit-text-size-adjust:100%}
body{-webkit-tap-highlight-color:transparent;overscroll-behavior-y:none;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
  background:var(--bg);color:var(--text);display:flex;min-height:100vh;font-size:14px;
  -webkit-font-smoothing:antialiased}

/* ---- Sidebar ---- */
.sidebar{overflow-y:auto;width:230px;background:var(--panel);border-right:1px solid var(--line);
  padding:22px 14px;position:sticky;top:0;height:100vh;display:flex;flex-direction:column;gap:6px;
  flex-shrink:0;z-index:20}
/* The brand is a menu trigger. Hover opens it on a mouse, click/tap opens it
   everywhere else — a hover-only menu would be unreachable on his phone. */
.brand-wrap{position:relative;margin-bottom:6px;border-bottom:1px solid var(--line)}
.brand{display:flex;align-items:center;gap:10px;padding:0 8px 18px;width:100%;
  background:none;border:none;color:inherit;font:inherit;text-align:left;cursor:pointer;
  border-radius:10px}
.brand:hover h1{color:var(--green)}

/* The account chip, top right of every page. It replaces the dropdown that
   used to hang off the brand: people look for their account in the corner,
   not under the logo, and "Sign out" had been buried on the Settings page. */
.topbar{display:flex;justify-content:flex-end;margin:-6px 0 14px}
.account-wrap{position:relative}
.account{display:flex;align-items:center;gap:10px;padding:6px 10px 6px 6px;
  background:var(--panel);border:1px solid var(--line);border-radius:999px;
  color:inherit;font:inherit;cursor:pointer;transition:.15s;
  /* Without this a tap on the name or address selects the text and pops the
     copy/paste bar instead of opening the menu. */
  -webkit-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}
.account:hover,.account[aria-expanded="true"]{border-color:var(--accent);background:var(--panel2)}
.account .avatar{width:30px;height:30px;border-radius:50%;flex-shrink:0;overflow:hidden;
  background:linear-gradient(135deg,var(--accent),var(--purple));
  display:flex;align-items:center;justify-content:center;
  font-weight:700;font-size:13px;color:#fff;text-transform:uppercase}
/* The profile picture fills the circle. object-fit stops a non-square photo
   being stretched, which is what most Google pictures are not. */
.account .avatar img{width:100%;height:100%;object-fit:cover;display:block}
.account .who{display:flex;flex-direction:column;line-height:1.25;text-align:left;min-width:0}
.account .who strong{font-size:13px;font-weight:600;
  max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.account .who small{font-size:11px;color:var(--muted);
  max-width:150px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.account .caret{font-size:9px;color:var(--muted)}

.account-menu{position:absolute;right:0;top:calc(100% + 6px);z-index:60;min-width:210px;
  background:var(--panel2);border:1px solid var(--line);border-radius:12px;
  padding:6px;box-shadow:0 14px 34px rgba(0,0,0,.55);display:flex;flex-direction:column;gap:2px}
.account-menu[hidden]{display:none}
/* ⚠️ 44px, not 40. This menu holds Settings, Connections and **Sign out**,
   it is on every screen at every width, and it had no mobile override at
   all — so the one control here you cannot undo with another click was the
   undersized one. 44px is the documented minimum comfortable target. */
.account-menu button,.account-menu a{display:flex;align-items:center;gap:9px;width:100%;
  min-height:44px;padding:10px 12px;border:none;border-radius:9px;background:none;
  color:var(--muted);font:inherit;font-size:13px;text-align:left;cursor:pointer;
  text-decoration:none}
.account-menu button:hover,.account-menu button:focus-visible,
.account-menu a:hover,.account-menu a:focus-visible{background:var(--panel);color:var(--text)}
.account-menu button.active{color:var(--green)}
.account-menu .ic{width:18px;text-align:center}
/* Sign out is the one thing here you cannot undo with another click, so it
   is separated and coloured rather than sitting flush with the rest. */
.account-menu a.danger{color:var(--red);margin-top:4px;
  border-top:1px solid var(--line);border-radius:0 0 9px 9px;padding-top:11px}
.account-menu a.danger:hover{background:rgba(242,114,107,.12);color:var(--red)}

/* Sign-in / sign-up gate */
/* The sign-in page is centred, so the status bar only bites when the card is
   tall enough to fill the screen — but it does bite then, and somebody can
   install Sakina before ever signing in. Same insets, same reason as .main. */
body.gate{display:flex;align-items:center;justify-content:center;min-height:100dvh;
  padding:calc(24px + env(safe-area-inset-top)) 24px
          calc(24px + env(safe-area-inset-bottom));background:var(--bg)}
.gate-card{width:100%;max-width:380px;background:var(--panel);border:1px solid var(--line);
  border-radius:var(--radius);padding:32px;box-shadow:var(--shadow);text-align:center}
.gate-card.wide{max-width:460px}
.gate-logo{width:64px;height:64px;border-radius:16px;margin-bottom:14px}
.gate-card h1{font-size:22px;margin-bottom:4px}
.gate-sub{font-size:13px;color:var(--muted);margin-bottom:22px;line-height:1.6}
.gate-card .field{text-align:left}
.gate-card .opt{color:var(--muted);font-weight:400;text-transform:none;letter-spacing:0}
.gate-foot{font-size:12px;color:var(--muted);margin-top:20px;line-height:1.6}
.gate-foot a,.linkish{color:var(--green);text-decoration:underline;background:none;
  border:none;padding:0;font:inherit;cursor:pointer}
.consent{display:flex;text-align:left;margin-top:18px;font-size:12px;color:var(--muted);
  line-height:1.6}
.consent label{display:flex;gap:9px;align-items:flex-start;cursor:pointer}
.consent input{margin-top:2px;width:16px;height:16px;flex-shrink:0;accent-color:var(--accent)}
.policy-box{margin-top:18px;border:1px solid var(--line);border-radius:12px;
  background:var(--panel2);text-align:left}
.policy-head{display:flex;justify-content:space-between;align-items:center;
  padding:10px 12px;border-bottom:1px solid var(--line);font-size:13px}
.policy-tabs{display:flex;gap:6px;padding:10px 12px 0}
.policy-tabs .on{color:var(--green);border-color:var(--accent)}
.policy-box .md{max-height:340px;overflow:auto;padding:14px 16px}

/* Rendered Markdown (privacy policy, terms). These are documents someone is
   actually meant to read, so they get real typography rather than a wall of
   raw "##" and "**". */
.md{font-size:13px;line-height:1.7;color:var(--muted)}
.md h2{font-size:16px;color:var(--text);margin:20px 0 8px}
.md h3{font-size:14px;color:var(--text);margin:18px 0 6px}
.md h2:first-child,.md h3:first-child{margin-top:0}
.md p{margin:0 0 10px}
.md strong{color:var(--text)}
.md a{color:var(--green)}
.md code{background:var(--panel2);border-radius:5px;padding:1px 5px;font-size:12px}
.md ul,.md ol{margin:0 0 12px 18px}
.md li{margin-bottom:5px}
.md hr{border:none;border-top:1px solid var(--line);margin:18px 0}
.md blockquote{border-left:3px solid var(--accent);background:rgba(47,169,107,.08);
  padding:9px 13px;border-radius:0 8px 8px 0;margin:0 0 12px}
.md-table{overflow-x:auto;margin:0 0 14px}
.md-table table{width:100%;min-width:0;border-collapse:collapse;font-size:12px}
.md-table th{text-align:left;padding:7px 9px;border-bottom:1px solid var(--line);
  color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.5px}
.md-table td{padding:7px 9px;border-bottom:1px solid var(--line);vertical-align:top}
.md-table tr:last-child td{border-bottom:none}

/* Standalone privacy / terms page (/policy) */
/* display:block matters — the base stylesheet makes <body> a flex row for
   the sidebar layout, which turned this page's header into a full-height
   column beside the text. */
body.doc-page{display:block;background:var(--bg);min-height:100dvh}
.doc-head{position:sticky;top:0;z-index:10;display:flex;align-items:center;gap:14px;
  flex-wrap:wrap;padding:14px 22px;background:rgba(6,9,8,.92);
  -webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);
  border-bottom:1px solid var(--line)}
.doc-brand{display:flex;align-items:center;gap:9px;color:var(--text);
  text-decoration:none;font-weight:700;font-size:15px}
.doc-brand img{width:26px;height:26px;border-radius:7px}
.doc-tabs{display:flex;gap:6px;margin-left:auto}
.doc-tabs .on{color:var(--green);border-color:var(--accent)}
.doc-body{max-width:760px;margin:0 auto;padding:30px 22px 70px}
.doc-body .md{font-size:14px}
@media(max-width:560px){
  .doc-tabs{margin-left:0;width:100%;order:3}
  .doc-body{padding:22px 16px 50px}
}

/* Connections page */
.conn{display:flex;gap:14px;align-items:flex-start;padding:16px;margin-bottom:12px;
  background:var(--panel);border:1px solid var(--line);border-radius:16px}
.conn .dot{width:10px;height:10px;border-radius:50%;flex-shrink:0;margin-top:5px}
.conn .body{flex:1;min-width:0}
.conn h4{font-size:15px;margin-bottom:2px}
.conn .what{font-size:12px;color:var(--muted);margin-bottom:8px}
.conn .how{font-size:12px;color:var(--muted);line-height:1.6;overflow-wrap:anywhere}
.conn .acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:10px}
.conn code{background:var(--panel2);border-radius:5px;padding:1px 5px;font-size:11px}
/* ⚠️ **Dark glyph on the green tile.** The mark inherited near-white text,
   which was fine on the old dull-green gradient and washed out to invisible
   once --accent became the vibrant green — the logo looked gone. The
   gradient also ran green→purple after --purple stopped being a green, so
   it is green→deep-green now. HANDOFF §114. */
.brand .logo{width:34px;height:34px;border-radius:9px;
  background:linear-gradient(135deg,var(--green),#128a4e);color:#04140b;
  display:flex;align-items:center;justify-content:center;font-weight:800;font-size:16px;flex-shrink:0}
.brand h1{font-size:16px;font-weight:700;letter-spacing:.3px}
.nav{display:flex;flex-direction:column;gap:2px;margin-top:8px}
.nav button{display:flex;align-items:center;gap:11px;padding:10px 12px;border-radius:10px;color:var(--muted);
  text-decoration:none;font-weight:500;cursor:pointer;transition:.15s;background:none;border:none;
  font-size:14px;font-family:inherit;text-align:left;width:100%}
.nav button:hover{background:var(--panel2);color:var(--text)}
.nav button.active{background:linear-gradient(135deg,rgba(47,169,107,.22),rgba(31,143,106,.12));color:var(--text)}
.nav button .ic{width:20px;text-align:center;font-size:15px;flex-shrink:0}
.side-foot{margin-top:auto;padding:12px 8px 0;border-top:1px solid var(--line);font-size:11px;color:var(--muted)}
/* ---- Main ---- */
.main{flex:1;padding:26px 34px;max-width:1250px;min-width:0}
.page{display:none;animation:fade .25s ease}
.page.active{display:block}
@keyframes fade{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}
.page-head{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:22px;gap:16px;flex-wrap:wrap}
.page-head h2{font-size:24px;font-weight:700}
.page-head p{color:var(--muted);font-size:13px;margin-top:3px}
.today{color:var(--text);font-size:12px;text-align:right;white-space:nowrap}

/* ---- Grid & cards ---- */
.grid{display:grid;gap:16px}
.g2{grid-template-columns:repeat(2,1fr)}
.g3{grid-template-columns:repeat(3,1fr)}
.g4{grid-template-columns:repeat(4,1fr)}
.card{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);padding:18px;
  box-shadow:var(--shadow);min-width:0}
.card h3{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--text);margin-bottom:12px;
  font-weight:600;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.big{font-size:30px;font-weight:750;letter-spacing:-.5px}
.sub{font-size:12px;color:var(--muted);margin-top:4px}
.up{color:var(--green)} .down{color:var(--red)}
.pill{display:inline-block;padding:3px 9px;border-radius:20px;font-size:11px;font-weight:600;white-space:nowrap}
.pill.g{background:rgba(70,208,137,.15);color:var(--green)}
.pill.r{background:rgba(242,114,107,.15);color:var(--red)}
.pill.y{background:rgba(224,180,92,.15);color:var(--yellow)}
.pill.n{background:var(--panel2);color:var(--muted)}

/* ⚠️ **Both of these are gone at EVERY width, 2026-09-03, on his
   instruction**, and both were already hidden on the phone — the rules used
   to live in the 820px block and have been lifted out, because a rule that
   applies on both sides of the breakpoint does not belong inside a width
   query.

   · `#fnCreditAccounts` — the card list at the top of Spending. ⚠️ With
     Overview's "What you owe" gone as well, **no page lists the individual
     cards any more**. "Owed on cards" on Overview is what is left of them,
     and it is a total. That is his call, but it is worth knowing it is the
     last one rather than one of several.
   · `.rec-head` / `.rec-list` — "Regular payments" under the calendar.

   Hidden, not deleted: the markup is shared and `renderRecurringList` and
   `accountRows` still fill them, so putting either back is deleting a line.
   ⚠️ `.rec-head` is still styled as an eyebrow further down; that rule is
   typography for an element that is not shown, not a contradiction. */
#page-finances #fnCreditAccounts,
#page-finances .rec-head,
#page-finances .rec-list{display:none}

/* ---- Bank and Brokerage: off the switcher, 2026-09-03 ----------------
   ⚠️ **The tab BUTTONS go, and that is enough.** `setFinanceView` starts on
   Overview and marks every other panel `hidden`, so a panel with no button
   is unreachable — nothing needs removing from that function's list, and
   leaving it there means putting a tab back is deleting a selector.

   **Bank** — his instruction.

   **Brokerage** — his instruction *conditionally*: hide it if the total
   gain/loss is not pulled directly from the brokerage. It is not, twice
   over. Sakina computes it (`value − cost basis`, `_shape_holdings`), and
   for his accounts Plaid returns **no holdings at all** — `available:false`,
   zero positions, no cost basis — so the card could only ever have shown
   "—". Checked against the live account before hiding it, not assumed.
   ⚠️ The arithmetic was ALSO wrong and is fixed in the same change (§152):
   it subtracted the cost of *some* positions from the value of *all* of
   them. The fix matters even with the section hidden, because Home's
   portfolio tile and Overview's Investments figure come from the same
   shape, and a brokerage that starts reporting holdings would have started
   reporting a fiction. */
#page-finances .fin-switch button[data-fin="bank"],
#page-finances .fin-switch button[data-fin="brokerage"]{display:none}

/* source badge — says where a number came from.

   ⚠️ **HIDDEN EVERYWHERE, 2026-09-03, on his instruction** — desktop first,
   then the phone. It removes a signal, so why that is safe: a badge only
   ever says "sample" when a source is not connected, and the banner at the
   top of the page appears in exactly that case, names the sources outright
   and links to Connections. The warning is still on screen; it is just not
   said twice. (This was already the phone's own reasoning for hiding the
   badge on Home's cards — that rule is gone now, subsumed by this one.)

   ⚠️ It is a real control, so `display:none` and not `visibility` /
   `opacity`: those would leave a focusable, screen-reader-visible button
   that nobody can see. Everything below still styles it, so putting the
   badges back is deleting one line. */
.src{display:none}
.src{font-size:10px;font-weight:600;padding:2px 7px;border-radius:6px;letter-spacing:.3px;
  text-transform:uppercase;margin-left:auto;white-space:nowrap}
.src.live{background:rgba(70,208,137,.15);color:var(--green)}
.src.sample{background:rgba(224,180,92,.14);color:var(--yellow)}
/* ⚠️ It is a real control now, not a label with a tooltip. `cursor:help`
   promised an explanation that a phone could never show, and 10px with 2px
   of padding is not something you can reliably hit. The sample one is the
   important one - it is the difference between his money and an example -
   so it gets a dotted underline saying "there is more here". */
.src{cursor:pointer;border:1px solid transparent}
.src.sample{text-decoration:underline dotted;text-underline-offset:2px}
.src:focus-visible{outline:2px solid var(--green);outline-offset:2px}
@media(hover:none){
  /* A comfortable tap target without making the badge look like a button
     in the middle of a heading: the padding grows, the type does not. */
  .src{padding:8px 10px;font-size:11px}
}

/* readiness ring */
.ring-wrap{display:flex;align-items:center;gap:20px;flex-wrap:wrap}
.ring{position:relative;width:120px;height:120px;flex-shrink:0}
.ring svg{transform:rotate(-90deg)}
.ring .val{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center}
.ring .val b{font-size:30px;font-weight:750}
.ring .val small{font-size:10px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px}

/* Compact Home tiles — four cards to one screen (HANDOFF §111). Equal, tidy,
   the ring centred with no side metrics. */
.home-cards{margin-top:16px}
.home-tile{display:flex;flex-direction:column}
.home-tile .list{margin-top:2px}
.ring-solo{justify-content:center;gap:0;padding:6px 0 2px}
.home-brk-today{margin-top:2px}
.metric-row{display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--line);
  font-size:13px;gap:12px}
.metric-row:last-child{border:none}
.metric-row .m{color:var(--text)}

/* credit card */
.cc{background:linear-gradient(135deg,#0f3a2a,#1c5a40 55%,#0d4636);border-radius:16px;padding:20px;
  position:relative;overflow:hidden;min-height:170px;display:flex;flex-direction:column;justify-content:space-between}
.cc:before{content:"";position:absolute;width:180px;height:180px;background:rgba(255,255,255,.06);
  border-radius:50%;top:-60px;right:-40px}
.cc .brand-row{display:flex;justify-content:space-between;align-items:center;position:relative}
.cc .chip{width:36px;height:26px;border-radius:6px;background:linear-gradient(135deg,#e6c86e,#b8963f)}
.cc .num{font-size:17px;letter-spacing:2px;margin:16px 0 4px;white-space:nowrap;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.cc .row2{display:flex;justify-content:space-between;align-items:flex-end;gap:12px}
.cc .bal{font-size:24px;font-weight:750}
.cc small{font-size:10px;color:rgba(255,255,255,.6);text-transform:uppercase;letter-spacing:.5px}

/* lists */
.list .item{display:flex;justify-content:space-between;align-items:center;padding:10px 0;
  border-bottom:1px solid var(--line);gap:12px}
.list .item:last-child{border:none}
.list .left{display:flex;align-items:center;gap:11px;min-width:0}
.list .ic-box{width:34px;height:34px;border-radius:9px;background:var(--panel2);display:flex;
  align-items:center;justify-content:center;font-size:15px;flex-shrink:0}
.list .name{font-weight:600;overflow-wrap:anywhere}
.list .meta{font-size:11px;color:var(--muted);margin-top:2px}
.amt{font-weight:650;white-space:nowrap}

/* tables */
.table-wrap{overflow-x:auto;-webkit-overflow-scrolling:touch}
table{width:100%;border-collapse:collapse;min-width:440px}
th{text-align:left;font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);
  padding:8px 6px;border-bottom:1px solid var(--line);white-space:nowrap}
td{padding:11px 6px;border-bottom:1px solid var(--line);font-size:13px}
tr:last-child td{border:none}
.num-col{text-align:right;white-space:nowrap}
/* A dash where a number would be: "not known", not "zero". */
.muted{color:var(--muted);cursor:help}

/* A number you typed over the live one. Marked so a stale hand-typed
   figure can never sit under a LIVE badge pretending to be real. */

/* Below 480px a 4-7 column table can't fit without side-scrolling even
   with .table-wrap, so the least essential column drops instead of the
   whole table scrolling sideways. Each table marks its own droppable
   column(s) with .col-drop on both the <th> and its matching <td>s. */
@media(max-width:480px){
  table{min-width:0}
  .col-drop{display:none}
}
.muted-cell{color:var(--muted)}
.hold-sub{display:block;font-size:11px;color:var(--muted);margin-top:2px}
.tag{font-size:10px;padding:2px 7px;border-radius:6px;background:var(--panel2);color:var(--muted);
  display:inline-block;white-space:nowrap}

/* progress bars */
.bar{height:8px;background:var(--panel2);border-radius:6px;overflow:hidden;margin-top:6px}
.bar>span{display:block;height:100%;border-radius:6px;transition:width .4s ease}
.budg-row{margin-bottom:14px}
.budg-row:last-child{margin-bottom:0}
.budg-row .top{display:flex;justify-content:space-between;font-size:13px;margin-bottom:2px;gap:10px}

/* tiles */
.tile{background:var(--panel);border:1px solid var(--line);border-radius:14px;overflow:hidden;
  cursor:pointer;transition:.15s;text-align:left;padding:0;font-family:inherit;color:inherit;
  display:flex;flex-direction:column}
.tile:hover,.tile:focus-visible{transform:translateY(-3px);border-color:var(--accent);outline:none}
.tile.static{cursor:default}
.tile.static:hover{transform:none;border-color:var(--line)}
/* A place tile is a link to Google Maps, so it lifts and points like one. */
.tile.link{cursor:pointer;text-decoration:none}
.tile.link:hover,.tile.link:focus-visible{transform:translateY(-3px);border-color:var(--accent)}
.tile.link:focus-visible{outline:2px solid var(--accent);outline-offset:2px}
.tile h4 .go{float:right;color:var(--muted);font-size:12px;font-weight:400;margin-left:6px}
.tile.link:hover h4 .go{color:var(--green)}
.tile .thumb{height:96px;display:flex;align-items:center;justify-content:center;font-size:38px;flex-shrink:0}
.tile .body{padding:13px;display:flex;flex-direction:column;flex:1}
.tile h4{font-size:14px;margin-bottom:5px}
.tile .row{display:flex;justify-content:space-between;align-items:center;margin-top:auto;padding-top:8px;
  font-size:12px;color:var(--muted);gap:8px}
.cost{color:var(--green);font-weight:700;font-size:15px;white-space:nowrap}
.stars{color:var(--yellow);font-size:12px}
.why{font-size:11px;color:var(--muted);margin-top:6px;line-height:1.45;border-left:2px solid var(--accent);
  padding-left:8px}

/* Saved Google Maps places — each row opens the place in Maps */
.saved-link{text-decoration:none;color:inherit;border-radius:10px;
  transition:background .15s}
.saved-link:hover,.saved-link:focus-visible{background:var(--panel2);outline:none}
.saved-link .go{color:var(--muted);font-size:12px;align-self:center}
.saved-link:hover .go{color:var(--green)}

/* Canvas deep links — themed, not the browser's default blue */
.assign-link{color:var(--text);text-decoration:none;border-bottom:1px solid transparent}
.assign-link:hover,.assign-link:focus-visible{color:var(--green);border-bottom-color:var(--green)}
.assign-link .go{color:var(--muted);font-size:11px}
.assign-link:hover .go{color:var(--green)}

/* Options analyzer — one block per position, legs folded away underneath */
.pos{border:1px solid var(--line);border-radius:12px;padding:14px;margin-top:12px;
  background:var(--panel2)}
.pos-head{display:flex;justify-content:space-between;align-items:flex-start;gap:12px;
  flex-wrap:wrap;font-size:13px}
.pos-sym{font-weight:700;font-size:15px}
.pos-pl{font-weight:700;font-size:16px;white-space:nowrap}
.pos-money{display:grid;grid-template-columns:repeat(4,1fr);gap:10px;margin-top:12px}
.mcell{display:flex;flex-direction:column;gap:2px}
.mcell span{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.mcell b{font-size:13px;white-space:nowrap}
.greeks{display:flex;flex-wrap:wrap;gap:8px;margin-top:12px}
.greek{display:flex;flex-direction:column;gap:1px;background:var(--panel);
  border:1px solid var(--line);border-radius:9px;padding:6px 10px;cursor:help}
.greek span{font-size:10px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted)}
.greek b{font-size:13px;white-space:nowrap}
.pos-more{margin-top:12px;border-top:1px solid var(--line);padding-top:10px}
.pos-more summary{cursor:pointer;font-size:12px;color:var(--muted);font-weight:600}
.pos-more summary:hover{color:var(--green)}
.leg{display:flex;justify-content:space-between;gap:12px;flex-wrap:wrap;
  padding:9px 0;border-bottom:1px solid var(--line)}
.leg:last-child{border:none}
.leg-name{font-size:12px;font-weight:600}
.leg-nums{display:flex;gap:14px;flex-wrap:wrap;font-size:11px;color:var(--muted)}
.facts{margin-top:10px;margin-bottom:14px}
.facts .sub{margin-bottom:8px}
table.ladder{font-size:12px}
table.ladder th{font-weight:600;font-size:10px;text-transform:uppercase;letter-spacing:.05em}
table.ladder tr.now{background:rgba(47,169,107,.1)}
.facts h5{font-size:11px;text-transform:uppercase;letter-spacing:.06em;color:var(--muted);
  margin-bottom:6px}
.facts ul{margin:0;padding-left:18px}
.facts li{font-size:12px;line-height:1.65;color:var(--text)}
@media(max-width:640px){.pos-money{grid-template-columns:repeat(2,1fr)}}

/* Account switcher — one tab per account, kept separate on purpose */
.acct-switch{display:flex;gap:10px;margin-bottom:16px;overflow-x:auto;padding-bottom:2px;
  -webkit-overflow-scrolling:touch}
.acct-switch:empty{display:none}
.acct{flex:0 0 auto;display:flex;flex-direction:column;gap:2px;text-align:left;cursor:pointer;
  background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:10px 16px;
  color:var(--muted);font:inherit;transition:border-color .15s,color .15s,background .15s}
.acct:hover{border-color:var(--accent);color:var(--text)}
.acct.on{background:var(--panel2);border-color:var(--accent);color:var(--text)}
.acct-name{font-size:12px;font-weight:600}
.acct-val{font-size:15px;font-weight:700;color:var(--text)}
.acct .acct-val{color:inherit}
.acct.on .acct-val{color:var(--green)}

/* Finances — the switch top left of the page. A segmented control rather
   than the .acct cards below it: those carry a value each, these are just
   four names, and giving them the same weight made the page read as two
   competing tab bars. 44px min height so it is a comfortable phone target. */
/* ⚠️ Underline tabs, not boxes (HANDOFF §111): all five share the row with
   flex:1 so nothing scrolls off the edge, text is white, and the active tab
   is marked by a vibrant green line beneath it. */
.fin-switch{display:flex;gap:2px;margin-bottom:18px;border-bottom:1px solid var(--line)}
.fin-switch button{flex:1 1 0;min-width:0;cursor:pointer;background:none;border:none;
  border-bottom:2px solid transparent;margin-bottom:-1px;padding:12px 4px;min-height:44px;
  color:var(--muted);font:inherit;font-size:13px;font-weight:600;white-space:nowrap;
  transition:color .15s,border-color .15s}
.fin-switch button:hover{color:var(--text)}
.fin-switch button.active{color:var(--text);border-bottom-color:var(--green)}
.fin-switch button:focus-visible{outline:2px solid var(--green);outline-offset:-2px;border-radius:4px}
/* On a phone the four labels do not fit at full size, so Bank fell off the
   right edge behind a scroll. Measured at 375x812: tightening the padding
   and type fits all four, which matters because a control you have to
   discover by scrolling is one most people never find. */
@media(max-width:560px){
  
  .fin-switch button{padding:11px 3px;font-size:12px}
}
/* ⚠️ **The tablet gap.** The 44px overrides live at max-width:760px, but the
   mobile shell — bottom tab bar and sheet — starts at 820px. Between 761px
   and 820px, which includes an iPad mini in portrait at exactly 768px, the
   touch layout was active while every small control was still mouse-sized:
   Refresh data, Disconnect, the meal remove button, Sign out, Delete my
   account. Any pointer without hover gets the comfortable sizes regardless
   of width, which is the real question rather than the screen size. */
@media(hover:none),(max-width:820px){
  .btn.tiny{min-height:44px;padding:8px 14px;font-size:12px}
  .modal .close{width:44px;height:44px}
  .account-menu button,.account-menu a{min-height:46px}
}

/* The sign-up consent rows are where he agrees to the age gate and the
   privacy policy, and they were roughly 19px tall. The nested "how my data
   is handled" button had no padding of its own, so it was a tiny target
   inside a larger one. */
.consent label{min-height:44px;padding:6px 0;line-height:1.5}
.consent input[type=checkbox]{width:20px;height:20px;flex-shrink:0}
.consent .linkish{min-height:44px;padding:0 2px}

@media(max-width:359px){
  .fin-switch button{padding:11px 2px;font-size:11px}
}

/* Age confirmation on first sign-in. Deliberately looks like part of the
   sign-in card rather than a dismissible interstitial - it is a condition
   of creating the account, not a notice. */
.age-gate{margin-top:14px;padding:14px;border:1px solid var(--line);
  border-radius:12px;background:var(--panel2);text-align:left}
.age-gate .age-q{font-size:13px;color:var(--muted);margin:0 0 10px}
.age-gate .age-row{display:flex;gap:10px;align-items:center;font-size:14px;
  cursor:pointer;margin-bottom:12px}
.age-gate .age-row input{width:18px;height:18px;accent-color:var(--accent);
  flex-shrink:0;cursor:pointer}
.age-gate .btn{width:100%;min-height:44px}
.age-gate .btn:disabled{opacity:.5;cursor:not-allowed}

/* Finances — the Overview headline. One number that matters, then the parts
   that explain it. The previous version was three equal stat cards over two
   near-identical stacked lists: four blocks of the same visual weight, so
   nothing led, and a lot of empty page below them. */
.networth{background:linear-gradient(160deg,var(--panel2),var(--panel));
  border:1px solid var(--line);border-radius:16px;padding:22px 24px}
.nw-head{display:flex;align-items:baseline;justify-content:space-between;gap:12px}
.nw-label{font-size:11px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;
  color:var(--muted)}
.nw-when{font-size:11px;color:var(--muted)}
.nw-value{font-size:44px;font-weight:800;letter-spacing:-.02em;line-height:1.1;
  margin-top:6px;color:var(--text)}
.nw-sub{font-size:12px;color:var(--muted);margin-top:2px}
.nw-bar{margin-top:18px;display:flex;flex-direction:column;gap:6px}
.nw-track{display:flex;height:12px;border-radius:7px;overflow:hidden;
  background:var(--panel);border:1px solid var(--line)}
.nw-track .seg{display:block;height:100%}
.nw-track .seg.cash{background:var(--green)}
.nw-track .seg.inv{background:var(--yellow)}
.nw-track .seg.owed{background:var(--red)}
/* Owed sits on its own track, indented, so it reads as "against" the assets
   above rather than as another slice of them. */
.owed-track{width:100%;background:transparent;border-color:transparent}
.nw-key{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;font-size:12px;
  color:var(--text)}
.nw-key-item{display:inline-flex;align-items:center;gap:6px}
.nw-key-item b{color:var(--text);font-weight:600}
.nw-key .dot{width:9px;height:9px;border-radius:3px;display:inline-block}
.nw-key .dot.cash{background:var(--green)}
.nw-key .dot.inv{background:var(--yellow)}
/* Investments figure amber too, so the card matches its bar segment and
   reads as clearly not-cash at a glance. */
.big.inv-fig{color:var(--yellow)}
.nw-key .dot.owed{background:var(--red)}
/* The three Overview stats fall to two columns on a phone, which leaves the
   third stranded beside a gap. Let it span the row so the block reads as
   finished rather than as a layout that ran out. Measured at 375x812. */
@media(max-width:760px){
  #fin-overview .grid.g3.stats > .card:last-child{grid-column:1 / -1}
}
@media(max-width:560px){
  .networth{padding:18px 16px}
  .nw-value{font-size:34px}
  .nw-key{gap:10px}
}

/* Health — stress. The balance between recovery and stress is the answer,
   so it gets the large number; the raw minutes sit in the key beneath. */
.stress-card{background:linear-gradient(160deg,var(--panel2),var(--panel))}
.stress-head{display:flex;align-items:flex-start;justify-content:space-between;gap:16px}
.stress-label{font-size:20px;font-weight:700;color:var(--text);margin-top:4px}
.stress-share{text-align:right;flex-shrink:0}
.stress-share .big{font-size:32px;line-height:1.1;color:var(--green)}
.stress-bar{margin-top:16px}
.stress-track{display:flex;height:12px;border-radius:7px;overflow:hidden;
  background:var(--panel);border:1px solid var(--line)}
.stress-track .seg{display:block;height:100%}
.stress-track .seg.rec{background:var(--green)}
.stress-track .seg.str{background:var(--red)}
.stress-key{display:flex;flex-wrap:wrap;gap:14px;margin-top:12px;font-size:12px;
  color:var(--muted)}
.stress-key .dot.rec{background:var(--green)}
.stress-key .dot.str{background:var(--red)}

/* Resilience is an ordered set of five categories, not a measurement, so it
   is drawn as steps. A percentage bar would invent precision Oura does not
   report. */
.res-scale{display:flex;gap:6px;margin-top:6px}
.res-step{flex:1;height:10px;border-radius:5px;background:var(--panel2);
  border:1px solid var(--line)}
.res-step.on{background:var(--accent);border-color:var(--accent)}
.res-level{margin-top:10px;font-size:20px;font-weight:700;color:var(--text)}

@media(max-width:560px){
  /* The share number and the label collide below about 420px, so the head
     stacks. Measured at 375x812. */
  .stress-head{flex-direction:column;gap:6px}
  .stress-share{text-align:left}
  .stress-share .big{font-size:28px}
  .stress-key{gap:10px}
  .res-scale{gap:4px}
}

/* The signed-out gate. Covers everything on purpose: a dashboard still
   showing yesterday's balances behind a dismissable notice is worse than one
   that plainly says it is stale. Sessions are one day, so this is a daily
   screen, not an error screen - it is styled to look ordinary rather than
   alarming. */
.session-gate{position:fixed;inset:0;z-index:200;display:flex;align-items:center;
  justify-content:center;padding:24px;background:rgba(4,6,5,.94);
  -webkit-backdrop-filter:blur(6px);backdrop-filter:blur(6px)}
.session-gate[hidden]{display:none}
.session-card{width:100%;max-width:360px;text-align:center;background:var(--panel);
  border:1px solid var(--line);border-radius:18px;padding:32px 26px}
/* The real mark rather than the letter, since this is the one screen whose
   whole job is to be reassuring rather than functional. */
.session-card .logo-wrap{position:relative;width:64px;height:64px;margin:0 auto 16px}
.session-card .logo-img{width:64px;height:64px;border-radius:18px;display:block}

/* A small green dot on the corner of the mark, only when it is an update.
   It borrows the language people already know from app stores, which does
   more than a sentence would to say "new version, not a problem". Animated
   once on arrival, then still - a pulsing dot on a screen you see after
   every release becomes irritating fast. */
.update-dot{display:none;position:absolute;top:-4px;right:-4px;width:18px;height:18px;
  border-radius:50%;background:var(--green);border:3px solid var(--panel);
  animation:dot-pop .45s ease-out}
.session-gate.is-update .update-dot{display:block}
@keyframes dot-pop{
  0%{transform:scale(.2);opacity:0}
  70%{transform:scale(1.15);opacity:1}
  100%{transform:scale(1);opacity:1}
}
@media(prefers-reduced-motion:reduce){
  .update-dot{animation:none}
  .session-card{animation:none}
}

/* The card itself eases in. Without it the panel appears as an abrupt cut
   over whatever he was reading, which reads as an error even when the words
   do not. */
.session-card{animation:gate-in .28s ease-out}
@keyframes gate-in{
  from{opacity:0;transform:translateY(10px) scale(.98)}
  to{opacity:1;transform:none}
}
.session-card h2{margin:0 0 8px;font-size:20px}
.session-card p{margin:0 0 20px;color:var(--muted);font-size:14px;line-height:1.5}
.session-card .btn{display:block;width:100%;min-height:48px;line-height:48px;
  padding:0;text-decoration:none}

@media(max-width:560px){
  /* Clear of the bottom tab bar and the phone's home indicator. */
  .session-gate{padding:20px 16px calc(20px + env(safe-area-inset-bottom))}
  .session-card{padding:26px 20px}
}

/* calendar / email */
.cal-item{display:flex;gap:12px;padding:11px 0;border-bottom:1px solid var(--line);align-items:flex-start}
.cal-item:last-child{border:none}
.cal-time{font-size:12px;color:var(--muted);width:74px;flex-shrink:0;font-weight:600}
.cal-bar{width:3px;border-radius:3px;flex-shrink:0;align-self:stretch;min-height:30px}
.cal-body .t{font-weight:600;font-size:13px}
.cal-body .d{font-size:11px;color:var(--muted);margin-top:2px}
.mail{display:flex;gap:12px;padding:11px 0;border-bottom:1px solid var(--line);align-items:flex-start}
.mail:last-child{border:none}
.mail .dot{width:8px;height:8px;border-radius:50%;margin-top:5px;flex-shrink:0}
.mail .from{font-weight:600;font-size:13px}
.mail .subj{font-size:12px;color:var(--muted);margin-top:2px;overflow-wrap:anywhere}
.mail .when{font-size:11px;color:var(--muted);margin-left:auto;flex-shrink:0;padding-left:8px}

/* Flat sections — a heading with a hairline under it, no card frame.
   Used on Priorities (HANDOFF §114) where stacked boxes read as clutter. */
/* Placeholders must stay clearly dimmer than a real value, now that
   secondary text is white — otherwise a hint reads as an entry. */
input::placeholder,textarea::placeholder{color:var(--faint);opacity:1}
/* Days outside the shown month stay recessive. */
.cal-d.out .cal-n{color:var(--faint)}

.budg-click{cursor:pointer;border-radius:8px;transition:background .15s}
.budg-click:hover{background:var(--panel2)}
.budg-click:focus-visible{outline:2px solid var(--green);outline-offset:2px}

.deadline-card .dl-top{display:flex;align-items:center;gap:10px;flex-wrap:wrap}
.deadline-card .dl-title{margin-top:6px;font-size:13px;font-weight:600;color:var(--text);
  line-height:1.4}

.flow{display:grid;grid-template-columns:repeat(2,1fr);gap:26px}
.flow-sec h3{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--text);
  font-weight:700;padding-bottom:9px;margin-bottom:6px;border-bottom:1px solid var(--line)}
@media(max-width:900px){.flow{grid-template-columns:1fr;gap:22px}}

.section-title{font-size:13px;font-weight:700;color:var(--text);margin:26px 0 12px;
  text-transform:uppercase;letter-spacing:.5px}
.banner{background:linear-gradient(135deg,rgba(47,169,107,.16),rgba(31,143,106,.08));border:1px solid var(--line);
  border-radius:12px;padding:11px 16px;font-size:12px;color:var(--muted);margin-bottom:20px;
  display:flex;gap:10px;align-items:center;line-height:1.5}
.banner.warn{background:linear-gradient(135deg,rgba(224,180,92,.14),rgba(224,180,92,.05))}
.banner a{color:var(--green)}
/* display:flex above would otherwise beat the browser's [hidden] rule and
   leave an empty coloured bar on the page. */
.banner[hidden]{display:none}

/* prayer strip */
/* Same black card as everything else — no green tint, no boxes round the
   times. Name white, time gray, the next prayer marked by a thin accent
   underline rather than a filled box (HANDOFF §111). */
.prayer{background:var(--panel);border:1px solid var(--line);border-radius:var(--radius);
  padding:16px 20px;margin-bottom:18px;display:flex;align-items:center;gap:22px;flex-wrap:wrap;box-shadow:var(--shadow)}
.prayer .next{flex-shrink:0}
.prayer .next .lbl{font-size:11px;text-transform:uppercase;letter-spacing:.6px;color:var(--green);font-weight:600}
.prayer .next .name{font-size:22px;font-weight:750;margin:2px 0}
.prayer .next .count{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.prayer .times{display:flex;gap:16px;flex:1;flex-wrap:wrap;justify-content:flex-end}
.prayer .p{text-align:center;padding:2px 2px 6px;min-width:56px;
  border-bottom:2px solid transparent}
.prayer .p.on{border-bottom-color:var(--accent)}
.prayer .p.past{opacity:.4}
.prayer .p .pn{font-size:11px;color:var(--text);text-transform:uppercase;letter-spacing:.5px;font-weight:600}
.prayer .p .pt{font-size:15px;font-weight:600;margin-top:3px;color:var(--muted)}
.prayer .loc{font-size:11px;color:var(--muted);width:100%;margin-top:4px;display:flex;gap:10px;
  align-items:center;flex-wrap:wrap}
.prayer .loc button{background:var(--panel2);border:1px solid var(--line);color:var(--muted);
  border-radius:7px;padding:3px 9px;font-size:11px;cursor:pointer;font-family:inherit}
.prayer .loc button:hover{color:var(--text);border-color:var(--accent)}
.prayer select{background:var(--panel2);border:1px solid var(--line);color:var(--muted);border-radius:7px;
  padding:3px 6px;font-size:11px;font-family:inherit}

/* modal */
.modal-bg{position:fixed;inset:0;background:rgba(0,0,0,.68);display:none;align-items:center;
  justify-content:center;z-index:50;padding:20px}
.modal-bg.open{display:flex}
.modal{background:var(--panel);border:1px solid var(--line);border-radius:18px;max-width:640px;width:100%;
  max-height:86vh;overflow-y:auto;padding:26px;box-shadow:0 20px 60px rgba(0,0,0,.6);animation:fade .2s ease}
/* The page behind the modal shouldn't scroll while it's open — was
   missing entirely before, on any screen size. */
body.modal-open{overflow:hidden}
.modal .m-head{display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:6px;gap:12px}
.modal h2{font-size:21px}
.modal .close{background:var(--panel2);border:none;color:var(--muted);width:32px;height:32px;border-radius:9px;
  font-size:16px;cursor:pointer;flex-shrink:0}
.modal .close:hover{color:var(--text)}
.modal .why-box{background:rgba(47,169,107,.1);border:1px solid var(--line);border-radius:10px;
  padding:10px 14px;font-size:12px;color:var(--muted);margin:12px 0;line-height:1.55}
.modal .facts{display:flex;gap:8px;flex-wrap:wrap;margin:10px 0 4px}
.modal h5{font-size:12px;text-transform:uppercase;letter-spacing:.6px;color:var(--muted);margin:18px 0 8px}
.shop{list-style:none}
.shop li{display:flex;justify-content:space-between;padding:7px 0;border-bottom:1px solid var(--line);
  font-size:13px;gap:12px}
.shop li:last-child{border:none}
.shop .have{color:var(--muted);font-style:italic;white-space:nowrap}
.steps{list-style:none;counter-reset:st}
.steps li{counter-increment:st;display:flex;gap:12px;padding:8px 0;font-size:13px;line-height:1.55}
.steps li:before{content:counter(st);flex-shrink:0;width:24px;height:24px;border-radius:50%;
  background:var(--panel2);color:var(--accent);font-weight:700;font-size:12px;display:flex;
  align-items:center;justify-content:center}
.shop-total{display:flex;justify-content:space-between;font-weight:700;padding-top:10px;margin-top:4px;
  border-top:1px solid var(--line);gap:12px}

/* forms */
.form-row{display:flex;gap:10px;flex-wrap:wrap;align-items:flex-end;margin-bottom:12px}
.field{display:flex;flex-direction:column;gap:5px;flex:1;min-width:110px}
.field label{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:.5px;font-weight:600}
.field input,.field select{background:var(--panel2);border:1px solid var(--line);color:var(--text);
  border-radius:9px;padding:9px 11px;font-size:13px;font-family:inherit;width:100%}
.field input:focus,.field select:focus{outline:none;border-color:var(--accent)}
.btn{background:var(--accent);color:#04150d;border:none;border-radius:9px;padding:10px 18px;
  font-weight:700;font-size:13px;cursor:pointer;font-family:inherit;white-space:nowrap}
.btn:hover{background:var(--green)}
.btn.ghost{background:var(--panel2);color:var(--muted);border:1px solid var(--line)}
.btn.ghost:hover{color:var(--text);border-color:var(--accent);background:var(--panel2)}
.btn.tiny{padding:4px 9px;font-size:11px;font-weight:600}
/* A warning that has to be read before it can be agreed to. Amber rather
   than red: it is a consequence to understand, not an error. */
.warn-box{background:rgba(224,180,92,.10);border:1px solid rgba(224,180,92,.35);
  border-radius:12px;padding:12px 14px;margin-bottom:20px;text-align:left;
  font-size:12.5px;line-height:1.65;color:var(--muted)}
.warn-box strong{color:var(--yellow)}

/* Recent account activity. A quiet two-column ledger: what happened, and
   when. The event and its time belong on one line — stacked, they read as
   twice as many entries as there really are. */
.hist-row{display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  padding:9px 0;border-bottom:1px solid var(--line);font-size:13px}
.hist-row:last-child{border-bottom:none}
.hist-what{color:var(--text);min-width:0;overflow-wrap:anywhere}
.hist-when{color:var(--muted);font-size:11.5px;font-variant-numeric:tabular-nums;
  white-space:nowrap;flex-shrink:0}
/* A failed sign-in is the one entry worth spotting at a glance. */
.hist-row.bad .hist-what{color:var(--yellow)}

/* A one-line explanation under a field that needs one. */
.field-hint{font-size:11.5px;color:var(--muted);line-height:1.5;margin-top:2px}

/* The numbered "how to do this" steps in the connect box. */
.conn-steps{margin:0 0 14px 18px;padding:0;font-size:13px;color:var(--muted);line-height:1.7}
.conn-steps li{margin-bottom:3px}

.form-msg{font-size:12px;margin-top:6px;min-height:16px}
.form-msg.ok{color:var(--green)}
.form-msg.bad{color:var(--red)}

/* misc */
.loading{padding:60px 0;text-align:center;color:var(--muted);font-size:13px}
.chart-host{width:100%;overflow:hidden}
.spinner{display:inline-block;width:14px;height:14px;border:2px solid var(--line);
  border-top-color:var(--accent);border-radius:50%;animation:spin .7s linear infinite;vertical-align:-2px}
@keyframes spin{to{transform:rotate(360deg)}}
.empty{color:var(--muted);font-size:13px;padding:14px 0;text-align:center}
/* Each institution linked under one connection card. Rows rather than a
   comma list, because each one needs its own Disconnect beside it. */
.conn .linked{list-style:none;margin:9px 0 0;padding:0;display:flex;
  flex-direction:column;gap:6px}
.conn .linked li{display:flex;align-items:center;justify-content:space-between;
  gap:10px;background:var(--panel2);border:1px solid var(--line);
  border-radius:9px;padding:7px 10px;font-size:13px}
.conn .linked li span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.conn .linked li .btn{flex-shrink:0}

.toast{position:fixed;bottom:22px;left:50%;transform:translateX(-50%);background:var(--panel2);
  border:1px solid var(--accent);color:var(--text);padding:11px 20px;border-radius:11px;font-size:13px;
  box-shadow:var(--shadow);z-index:80;opacity:0;pointer-events:none;transition:opacity .25s}
.toast.show{opacity:1}
/* A failure stays until it is dismissed. The base toast is pointer-events:none
   so it never blocks a click behind it; a sticky one has to take clicks or it
   could not be dismissed. Left-aligned and wrapped, because an error code on
   the end of a sentence is unreadable centred on one line. */
.toast.sticky{pointer-events:auto;cursor:pointer;text-align:left;line-height:1.5;
  max-width:min(520px,calc(100vw - 32px))}
.toast.sticky::after{content:'Tap to dismiss';display:block;margin-top:6px;
  font-size:11px;color:var(--muted)}

/* ---- Responsive: tablet ---- */
@media(max-width:1000px){
  .g4{grid-template-columns:repeat(2,1fr)}
  .g3{grid-template-columns:repeat(2,1fr)}
  .g2{grid-template-columns:1fr}
  .main{padding:22px 20px}
}

/* ================= MOBILE SHELL =================
   The phone gets a bottom tab bar, because a left rail is unreachable by
   thumb and the old icon strip was 457px wide inside a 375px screen — two
   destinations were simply off-screen. The "More" sheet is the SAME
   <aside class="sidebar"> restyled, not a second nav: app.js binds to #nav,
   #refreshBtn and #syncNote, and duplicating those would let them
   drift apart. Reusing it also brings back the nav labels, "Refresh data"
   and "Last synced", all of which the old phone layout hid.
   ================================================= */
.tabbar{display:none}
.scrim{display:none}

@media(max-width:820px){
  body{flex-direction:column}

  .tabbar{
    /* ⚠️ Eight buttons: seven pages and More. This said repeat(5,1fr) while
       the bar held four, so one column was permanently empty. Count the
       buttons if you add one. */
    display:grid;grid-template-columns:repeat(8,1fr);
    position:fixed;left:0;right:0;bottom:0;z-index:60;
    background:rgba(6,9,8,.9);
    -webkit-backdrop-filter:saturate(1.4) blur(14px);
    backdrop-filter:saturate(1.4) blur(14px);
    border-top:1px solid var(--line);
    padding-bottom:env(safe-area-inset-bottom);
  }
  .tab{
    display:flex;flex-direction:column;align-items:center;justify-content:center;gap:3px;
    min-height:56px;padding:7px 2px 6px;margin:4px 3px;border:none;border-radius:12px;
    background:none;color:var(--muted);font:inherit;font-size:10px;font-weight:600;
    letter-spacing:.2px;cursor:pointer;
    transition:color .12s,background .12s;
  }
  .tabic{width:24px;height:24px;fill:none;stroke:currentColor;stroke-width:1.7;
    stroke-linecap:round;stroke-linejoin:round}
  .tab.active{color:var(--green);background:rgba(47,169,107,.14)}
  .tab.active .tabic{stroke-width:2}
  .tab:active{transform:scale(.94)}
  .tab span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

  /* Eight tabs across a phone. Below this the label needs the smaller size
     or "Priorities" and "Finances" both truncate to nothing useful. */
  @media(max-width:520px){
    .tab{font-size:9px;padding:6px 0 5px;margin:4px 1px;letter-spacing:0}
    .tabic{width:21px;height:21px}
  }

  /* The sidebar becomes a bottom sheet. Same DOM, same IDs, same handlers. */
  .sidebar{
    position:fixed;left:0;right:0;bottom:0;top:auto;width:auto;height:auto;
    max-height:82dvh;overflow-y:auto;overscroll-behavior:contain;
    flex-direction:column;gap:6px;z-index:70;
    border-right:none;border-top:1px solid var(--line);
    border-radius:20px 20px 0 0;
    padding:10px 16px calc(16px + env(safe-area-inset-bottom));
    box-shadow:0 -14px 40px rgba(0,0,0,.55);
    transform:translateY(101%);
    transition:transform .24s cubic-bezier(.32,.72,0,1);
    visibility:hidden;
  }
  body.sheet-open .sidebar{transform:translateY(0);visibility:visible}
  .sidebar::before{
    content:"";display:block;width:38px;height:4px;border-radius:3px;
    background:var(--line);margin:2px auto 12px;flex-shrink:0;
  }
  .brand{padding:0 4px 14px;margin-bottom:4px;border:none}
  .brand div:last-child{display:block}
  .nav{flex-direction:column;margin-top:4px;gap:2px}
  .nav button{min-height:48px;padding:12px;font-size:15px;border-radius:12px}
  .nav button .lbl{display:inline}
  .nav button .ic{font-size:17px;width:24px}
  .side-foot{display:block;margin-top:12px;padding-top:12px}
  .side-foot .btn{min-height:44px;width:100%;padding:0 14px;font-size:13px}

  .scrim{
    display:block;position:fixed;inset:0;z-index:65;
    background:rgba(0,0,0,.5);opacity:0;transition:opacity .2s;
  }
  /* An author `display` rule beats the browser's built-in [hidden]{display:none},
     so without this the scrim stays laid over the whole screen at opacity 0 —
     invisible, but swallowing every tap including the tab bar. Same trap the
     .banner rule fell into earlier; see HANDOFF §8. */
  .scrim[hidden]{display:none}
  body.sheet-open .scrim{opacity:1}
  body.sheet-open{overflow:hidden}

  /* ⚠️ The bottom bar is gone (HANDOFF §119), so nothing is reserved for
     it any more — 86px of blank sat under every page otherwise. */
  .main{padding-top:var(--safe-top);
        padding-bottom:calc(34px + var(--safe-bottom))}
  .toast{bottom:calc(18px + var(--safe-bottom))}
}

/* ---- Responsive: phone layout ---- */
@media(max-width:760px){
  /* ⚠️ **The top inset matters once it is installed to the Home Screen.**
     `apple-mobile-web-app-status-bar-style: black-translucent` (added
     2026-08-19 so the dark page runs edge to edge) makes the page extend
     *under* the status bar. In Safari that is invisible — Safari's own
     chrome sits above the page — but as an installed app the first card is
     hidden behind the clock and the Dynamic Island. He reported it from a
     Home Screen install; the tell was that his screenshot had no address
     bar.

     ⚠️ **`.main` is the ONE element that applies the top inset.** The
     masthead sits inside it and must not add it again: doing so pushed the
     page down by twice the Dynamic Island — invisible in Safari, where the
     inset is 0, and a thick black band on the Home Screen. He reported
     exactly that. */
  .main{padding:calc(10px + var(--safe-top)) 14px calc(34px + var(--safe-bottom))}

  /* Stat cards hold one number each and stay readable 2-up. Tiles and
     content cards carry a paragraph, so they get the full width. */
  .grid.stats{grid-template-columns:repeat(2,1fr);gap:10px}
  .grid.tiles{grid-template-columns:1fr}
  .g2,.g3,.g4{grid-template-columns:1fr}

  .page-head{align-items:flex-start;flex-direction:column;gap:6px}
  .page-head h2{font-size:20px}
  .today{text-align:left}
  .big{font-size:23px}
  .card{padding:14px}
  .section-title{margin:18px 0 10px}

  /* Five prayer times on one legible row — hard rule #1 is the first thing
     he sees, and it was wrapping into a 335px-tall pile. */
  /* Stack the strip: on one row, "Next prayer" ate 150px and squeezed the
     five times into 33px columns. Full width each, next prayer on top. */
  .prayer{padding:14px;gap:12px;flex-direction:column;align-items:stretch}
  .prayer .next{flex-shrink:1;width:100%}
  .prayer .times{display:grid;grid-template-columns:repeat(5,1fr);gap:6px;width:100%;
    flex:none;justify-content:stretch}
  .prayer .p{min-width:0;padding:7px 3px;text-align:center;overflow:hidden}
  /* At 5-up each column is ~60px, so the full-size labels collide —
     "MAGHRIB" and "ISHA" ran into each other. Shrink the label, drop the
     letter-spacing, and let the name clip rather than overlap its neighbour. */
  .prayer .p .pn{font-size:9px;letter-spacing:0;white-space:nowrap;
    overflow:hidden;text-overflow:clip}
  .prayer .p .pt{font-size:13px;white-space:nowrap}
  /* The location row was stacking into three full-width blocks and made the
     strip taller than the readiness card. Keep it on one wrapping line. */
  .prayer .loc{flex-wrap:wrap;gap:8px;align-items:center}
  .prayer .loc button,.prayer .loc select{flex:1 1 auto;min-width:0}
  .ring-wrap{gap:14px}

  /* Touch targets: nothing tappable under 44px, and 16px inputs so iOS
     Safari does not zoom the whole page when a field takes focus. */
  .field input,.field select{font-size:16px;min-height:44px}
  .btn{min-height:44px}
  .btn.tiny{min-height:44px;padding:10px 14px;font-size:12px}
  .prayer .loc button,.prayer .loc select{min-height:44px;padding:10px;font-size:13px}
  .pos-more summary{min-height:44px;display:flex;align-items:center}
  .modal .close{width:44px;height:44px}
  /* Canvas titles were 17px tall — a real miss on a phone. The whole title
     block becomes the tap target instead of just the text. */
  .assign-link{display:flex;align-items:center;min-height:44px}
  .cal-body .d{font-size:12px}
  /* Inline text links inside a sentence still need a thumb-sized target. */
  .sub a{display:inline-block;padding:6px 0;min-height:32px}

  .acct-switch .acct{min-height:52px}
  .pos-money{grid-template-columns:repeat(2,1fr)}
  .greeks{gap:6px}
  .greek{padding:5px 8px}

  /* Recipe modal becomes a bottom sheet, same slide-up language as the
     More sheet — a centered dialog is hard to reach one-handed and wastes
     the screen edges on a phone. */
  .modal-bg{align-items:flex-end;padding:0}
  .modal{max-width:100%;width:100%;max-height:88dvh;border-radius:20px 20px 0 0;
    padding:14px 20px calc(20px + env(safe-area-inset-bottom));
    animation:sheet-up .22s cubic-bezier(.32,.72,0,1)}
  .modal::before{content:"";display:block;width:38px;height:4px;border-radius:3px;
    background:var(--line);margin:2px auto 14px}
}

@keyframes sheet-up{from{transform:translateY(100%)}to{transform:translateY(0)}}

/* Hover lifts stick on touch screens, where there is no pointer to leave. */
@media(hover:none){
  .tile.link:hover{transform:none}
  .acct:hover{border-color:var(--line);color:var(--muted)}
  .acct.on:hover{border-color:var(--accent);color:var(--text)}
}

@media(max-width:359px){
  .grid.stats{grid-template-columns:1fr}
  .prayer .p{padding:6px 2px}
  .tab span{font-size:9px}
}

/* The "or use your Sakina password" rule between Clerk's sign-in box and the
   password form. Hidden until Clerk actually loads, so a copy without Clerk
   configured shows no trace of it. */
.gate-divider{display:flex;align-items:center;gap:10px;margin:18px 0 4px;
  color:var(--muted);font-size:11px;text-transform:uppercase;letter-spacing:.06em}
.gate-divider::before,.gate-divider::after{content:"";flex:1;height:1px;background:var(--line)}
.gate-divider[hidden]{display:none}

/* Clerk's card has its own fixed width (400px) and does not inherit ours, so
   inside a 380px gate card it hangs over both edges. Widen the card when
   Clerk is showing and let its box shrink to fit rather than fighting it. */
#clerkMount[hidden]{display:none}
#clerkMount{display:flex;justify-content:center;width:100%}
#clerkMount > *{max-width:100%}
#clerkMount .cl-rootBox,#clerkMount .cl-card{width:100%;max-width:100%}
body.gate:has(#clerkMount:not([hidden])) .gate-card{max-width:440px}

/* ---------------------------------------------------------------------------
   Liquid glass — added 2026-08-18 on his request.

   ⚠️ **Glass needs something behind it or it is just a flat panel.**
   `backdrop-filter` blurs whatever it is layered over, and the app sat on one
   flat `--bg`, so blurring it would have produced a pixel-identical page and
   a convincing-sounding note saying otherwise. So this adds a soft ambient
   wash first, in the approved greens, and then lets the panels blur it.

   Applied to the panels that are read at a glance — the prayer strip, the
   snapshot and stat cards, the account chip — and deliberately not to dense
   tables or chart bodies, where a moving backdrop behind small text costs
   legibility for nothing.
   --------------------------------------------------------------------------- */

:root{
  /* Nearly-solid dark panels over black — the glass reads as clean elevation,
     not a green tint. HANDOFF §111. */
  --glass:rgba(12,16,14,.72);
  --glass-strong:rgba(12,16,14,.86);
  --glass-line:rgba(120,200,160,.08);
  --glass-sheen:inset 0 1px 0 rgba(200,240,220,.04);
  --glass-blur:blur(16px) saturate(120%);
}

/* The wash: three very low-opacity pools of the accent greens, so the glass
   has something with depth to blur.

   ⚠️ **This was a `body::before` with `position:fixed` and a companion rule
   giving `.sidebar/.main/.topbar` `position:relative; z-index:1`. That rule
   broke the phone layout** — on mobile the sidebar is a fixed slide-in
   drawer, and forcing it to `relative` put 564px of it back into the flow,
   pushing the whole dashboard down past the fold. Caught in the browser at
   375x812, not by reading the change back.

   Layers on `body`'s own background instead. No pseudo-element, no stacking
   context, no `position` touched anywhere — so there is nothing left for it
   to break. `background-attachment:fixed` keeps the wash still while the
   page scrolls, which is what made the pseudo-element tempting. */
body{
  /* One restrained glow instead of three green pools — depth without the
     tie-dye. Pure black everywhere else. HANDOFF §111. */
  background:
    radial-gradient(70rem 48rem at 50% -22%, rgba(47,189,119,.06), transparent 60%),
    var(--bg);
  background-attachment:fixed;
}

/* Only where the browser can actually do it. Without the guard, the
   fallback is a *more* transparent card over an unblurred wash, which is
   less readable than the solid panel it replaced - worse than not trying. */
@supports ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){
  .card,.prayer,.tile,.account-chip,.snap .card{
    background:var(--glass);
    -webkit-backdrop-filter:var(--glass-blur);
    backdrop-filter:var(--glass-blur);
    border-color:var(--glass-line);
    box-shadow:var(--shadow),var(--glass-sheen);
  }
  /* The prayer strip is now the same glass as every other card — no green
     tint of its own (HANDOFF §111); it inherits the `.card,.prayer,…` glass
     rule above, so nothing extra is needed here. */
  /* Dense surfaces stay solid on purpose: small text over a blurred,
     scrolling backdrop is harder to read, and these are the two places the
     numbers matter most. */
  .card .table,.card table,.chart-body{
    -webkit-backdrop-filter:none;backdrop-filter:none;
  }
}

/* ⚠️ Some people turn transparency off at the OS, and some get motion sick
   from it. Both are honoured rather than overridden. */
@media (prefers-reduced-transparency:reduce){
  .card,.prayer,.tile,.account-chip,.snap .card{
    background:var(--panel);
    -webkit-backdrop-filter:none;backdrop-filter:none;
    border-color:var(--line);box-shadow:var(--shadow);
  }
  body{background:var(--bg)}
}

/* ---------------------------------------------------------------------------
   Finances: month KPIs, the recurring calendar, budgets and special budgets.
   --------------------------------------------------------------------------- */

.kpi-months{display:grid;grid-template-columns:repeat(2,1fr);gap:16px}
.kpi-card h3{display:flex;align-items:center;gap:8px}
.kpi-row{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.kpi{display:flex;flex-direction:column;gap:2px;min-width:0}
.kpi-k{font-size:11px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted)}
.kpi-v{font-size:21px;font-weight:750;letter-spacing:-.4px;font-variant-numeric:tabular-nums}
.kpi-d{font-size:11px;color:var(--muted)}
.kpi-d.up{color:var(--green)} .kpi-d.down{color:var(--red)}

/* The calendar. Seven equal columns; the day number, any marks, then the
   day's totals. Kept deliberately plain — it is a projection, and a
   projection dressed up as a statement is the thing being avoided. */
.cal-wrap{overflow-x:auto}
.cal-grid{display:grid;grid-template-columns:repeat(7,minmax(38px,1fr));gap:3px;min-width:280px}
.cal-h{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--muted);
  text-align:center;padding:2px 0 6px}
.cal-d{min-height:58px;border:1px solid var(--line);border-radius:9px;padding:4px 4px 3px;
  display:flex;flex-direction:column;gap:2px;background:var(--panel2)}
.cal-d.out{opacity:.35}
.cal-d.today{border-color:var(--accent);box-shadow:0 0 0 1px var(--accent) inset}
.cal-n{font-size:11px;color:var(--text);font-variant-numeric:tabular-nums}
.cal-marks{display:flex;flex-wrap:wrap;gap:2px;font-size:11px;line-height:1}
.cal-dot{display:inline-flex;align-items:center;justify-content:center;width:15px;height:15px;
  border-radius:50%;background:rgba(255,255,255,.05);font-size:9px}
.cal-t{margin-top:auto;display:flex;flex-direction:column;font-size:10px;
  font-variant-numeric:tabular-nums;line-height:1.25}
.cal-in{color:var(--green)} .cal-out{color:var(--muted)}
/* Daily spend in red, right in the day cell. Blank days carry no number at
   all (HANDOFF §109), so the eye lands only on days money went out. */
.cal-spend{color:var(--red);font-weight:600;font-size:11px}
/* Tappable day cells (HANDOFF §111). */
.cal-d.cal-click{cursor:pointer}
.cal-d.cal-click:hover{border-color:var(--accent)}
.cal-d.cal-click:focus-visible{outline:2px solid var(--green);outline-offset:1px}

/* Special budgets: a bar that fills towards a target. */
.special{border:1px solid var(--line);border-radius:12px;padding:12px 13px;margin-bottom:10px;
  background:var(--panel2)}
.special-top{display:flex;justify-content:space-between;gap:12px;align-items:baseline;
  flex-wrap:wrap}
.special-name{font-weight:650}
.special-fig{font-size:12px;color:var(--muted);font-variant-numeric:tabular-nums}
.special-bar{height:8px;border-radius:99px;background:var(--line);overflow:hidden;margin:9px 0 8px}
.special-bar span{display:block;height:100%;border-radius:99px;
  background:linear-gradient(90deg,var(--accent),var(--green))}
.special-acts{display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.special-add{display:flex;gap:8px;flex-wrap:wrap;margin-top:6px}
.special-add input{flex:1 1 150px;min-width:0;background:var(--panel2);color:var(--text);
  border:1px solid var(--line);border-radius:10px;padding:9px 11px;font-size:14px}
.btn.ghost{background:transparent;color:var(--muted)}

@media (max-width:760px){
  .kpi-months{grid-template-columns:1fr}
  .kpi-v{font-size:18px}
  .cal-grid{grid-template-columns:repeat(7,minmax(34px,1fr))}
  .cal-d{min-height:50px}
}

/* ⚠️ **`hidden` has to actually hide.**
   The attribute works through a user-agent rule of `display:none`, which any
   author rule that sets `display` outranks. `.field` is `display:flex`, so
   `<label class="field" hidden>` stayed on screen with its attribute
   faithfully set to true — the rollover destination selector was visible
   while the mode was "Nothing", offering a choice that did not apply.
   Found by looking at the page, after `hidden` reported `true` and the
   element was plainly still there.

   `!important` is deliberate: this must beat every layout rule in the file,
   including ones not written yet. It is the case the HTML spec names for it. */
[hidden]{display:none !important}

/* The regular-payments list under the Spending calendar. */
.rec-head{margin-top:16px;font-size:12px;font-weight:600;letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted)}
.rec-list{margin-top:8px;border-top:1px solid var(--line)}
.rec-row{display:flex;align-items:center;gap:11px;padding:9px 2px;
  border-bottom:1px solid var(--line)}
.rec-row:last-child{border-bottom:none}
.rec-ic{width:26px;height:26px;flex:0 0 26px;border-radius:8px;background:var(--panel2);
  display:flex;align-items:center;justify-content:center;font-size:13px}
.rec-name{flex:1;min-width:0;display:flex;flex-direction:column;font-size:13px;font-weight:600}
.rec-name i{font-style:normal;font-size:11px;color:var(--muted);font-weight:400}
.rec-when{font-size:12px;color:var(--muted);white-space:nowrap}
.rec-amt{font-size:13px;font-weight:650;font-variant-numeric:tabular-nums;
  min-width:76px;text-align:right}
.rec-amt.up{color:var(--green)}


/* =================================================
   "Add to Home Screen", iPhone only. Sits just above the tab bar, so it
   never covers the navigation, and only ever appears on a phone that can
   actually do it -- see web/js/app.js for the conditions.
   ================================================= */
.a2hs{display:none}

@media(max-width:820px){
  .a2hs{
    display:block;position:fixed;left:10px;right:10px;z-index:65;
    bottom:calc(72px + env(safe-area-inset-bottom));
    background:rgba(21,32,25,.97);
    -webkit-backdrop-filter:saturate(1.4) blur(14px);
    backdrop-filter:saturate(1.4) blur(14px);
    border:1px solid var(--line);border-radius:16px;
    padding:12px 38px 12px 12px;
    box-shadow:0 10px 30px rgba(0,0,0,.5);
  }
  .a2hs[hidden]{display:none}
  .a2hs-body{display:flex;gap:11px;align-items:flex-start}
  .a2hs-icon{border-radius:10px;flex-shrink:0}
  .a2hs strong{display:block;font-size:14px;color:var(--text);margin-bottom:2px}
  .a2hs p{margin:0;font-size:12.5px;line-height:1.45;color:var(--muted)}
  .a2hs b{color:var(--text);font-weight:600}
  .a2hs-x{
    position:absolute;top:6px;right:8px;width:30px;height:30px;
    border:none;background:none;color:var(--muted);font-size:21px;
    line-height:1;cursor:pointer;border-radius:8px;
  }
  .a2hs-x:active{background:rgba(255,255,255,.06)}
  /* The iOS share glyph, drawn rather than fetched: a box with an arrow
     leaving the top. No external image, so the CSP has nothing to allow. */
  .a2hs-share{
    display:inline-block;width:11px;height:13px;vertical-align:-2px;
    border:1.6px solid var(--green);border-top:none;border-radius:0 0 3px 3px;
    position:relative;margin:0 2px;
  }
  .a2hs-share::before{
    content:"";position:absolute;left:50%;top:-7px;width:1.6px;height:9px;
    background:var(--green);transform:translateX(-50%);
  }
  .a2hs-share::after{
    content:"";position:absolute;left:50%;top:-7px;width:6px;height:6px;
    border-left:1.6px solid var(--green);border-top:1.6px solid var(--green);
    transform:translateX(-50%) rotate(45deg);
  }
}


/* A connection that cannot be pressed yet. Deliberately looks inert: same
   shape as a real button so the row does not jump, but flat, muted, and with
   the "not-allowed" cursor so a mouse says no before a click does. */
.btn.soon,
.btn.soon:hover{
  background:var(--panel-alt);color:var(--muted);border:1px solid var(--line);
  cursor:not-allowed;opacity:.75;transform:none;box-shadow:none;
}

/* A Canvas assignment he has ticked off. ⚠️ The row stays exactly where it
   was and keeps its full contrast - only the button changes, which is what
   he asked for after the first version made finished work disappear. */
.btn.assign-done.is-done{
  background:var(--green);
  border-color:var(--green);
  color:#08140f;
  font-weight:600;
}
.btn.assign-done.is-done:hover{background:var(--accent);border-color:var(--accent)}
/* ⚠️ This was `style="flex:0 0 auto;align-self:center"` INLINE, and an
   inline style beats every selector — so the phone's rule putting the
   button on its own line worked only on the rows whose content happened to
   wrap anyway, and the short rows kept it alongside. Two rows one way,
   three the other, in the same list. Fifth time an inline style or a
   specificity mismatch has cost a round here (§122.3, §125.3, §128.2,
   §130.2). Desktop keeps exactly the values it had. */
.assign-act{flex:0 0 auto;align-self:center}

/* =====================================================================
   PHONE HOME, 2026-08-27 (HANDOFF §119)
   ⚠️ **Everything in this block is phone-only, and deliberately so.**
   He asked for a Home redesign "ONLY for the mobile view"; the desktop
   layout — sidebar, cards, grid — is untouched above 820px.

   The bottom tab bar is gone on his instruction. The seven page
   selections sit on one line under the masthead rule instead, and the
   wordmark opens the sheet that still holds "Last synced" and
   "Refresh data".
   ===================================================================== */

/* Above the breakpoint the masthead is an invisible WRAPPER: it exists only
   so the account chip inside it can sit above the rule on a phone. It adds
   nothing here — no border, no padding — and its own brand is hidden, so the
   chip keeps the position it has always had. */
.mmast{display:block}
.mmast-id{display:none}
.mnav{display:none}
.hello{display:none}
.ready-delta{display:none}
/* Emoji are wrapped in `.emo` so the phone can drop them (his instruction,
   mobile only) without taking them off the desktop. */

@media(max-width:820px){

  /* ---- the bar goes; the top takes over ---- */
  .tabbar{display:none}
  /* The bottom padding and the toast are set once, above, now that both
     `.main` rules agree — repeating them here only made source order
     decide the outcome. */

  /* ---- masthead: wordmark left, the account control right, ABOVE the
     rule — his instruction. The date moved out of here to under the name. */
  .mmast{
    display:flex;align-items:center;justify-content:space-between;gap:14px;
    padding:2px 0 10px;
    /* ⚠️ The rule under the masthead is the app's GREEN, on his instruction
       (§131). `--accent` and not a literal, so it follows the one green
       everything else uses — and `--accent`, not `--green`: they are two
       different values, and §113/§114 were both caused by treating them as
       interchangeable. */
    border-bottom:2px solid var(--accent);
  }
  .mmast-id{
    display:flex;align-items:baseline;gap:10px;
    background:none;border:none;padding:0;color:inherit;font:inherit;
    cursor:pointer;-webkit-tap-highlight-color:transparent;
  }
  .mmast-id .ar{font-size:21px;color:var(--green);line-height:1}
  .mmast-id .wm{font-size:13px;font-weight:700;letter-spacing:.3em;
    text-transform:uppercase}
  .mmast .topbar{margin:0}

  /* ---- no emoji on the phone ----
     Hidden rather than deleted: the markup is shared with the desktop
     layout, which keeps them. */
  .emo{display:none}
  .nav button .ic,#accountMenu .ic{display:none}
  .banner > span:first-child{display:none}

  /* ---- the selections: one line, right aligned, under the rule ----
     ⚠️ Seven labels is 45 characters. They fit one row only at this size
     with the tracking near zero; the size follows the viewport so a 320px
     phone still fits them without wrapping or scrolling sideways. */
  /* Centred, on his instruction. */
  .mnav{display:flex;flex-wrap:nowrap;justify-content:center;
    padding:11px 0 0}
  .mnav button{
    background:none;border:none;color:var(--muted);font:inherit;
    font-size:clamp(8px,2.45vw,10px);font-weight:600;letter-spacing:.02em;
    text-transform:uppercase;padding:5px 4px;border-radius:8px;
    white-space:nowrap;cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .mnav button.active{color:var(--green)}

  /* ---- Home: the greeting, then flat sections ---- */
  #page-home .page-head{display:none}
  .hello{display:block;text-align:center;padding:30px 0 0}
  .hello-g{font-size:12px;letter-spacing:.2em;text-transform:uppercase;
    color:var(--muted)}
  .hello-who{font-size:26px;font-weight:650;letter-spacing:-.03em;
    margin-top:8px}
  /* Moved out of the masthead, on his instruction. */
  .hello-date{font-size:13px;color:var(--muted);margin-top:8px;
    font-variant-numeric:tabular-nums}

  /* ⚠️ The cards stop being cards. Same markup, same ids, same handlers —
     only the frame comes off, because he does not want boxes. */
  #page-home .home-cards{display:block}
  #page-home .home-cards .card{
    background:none;border:none;border-radius:0;box-shadow:none;
    padding:0;margin:56px 0 0;
  }
  /* ⚠️ **Titles left, figures centred** — his instruction: "center all the
     data points, not the titles". Titles are `--text`, the whitest tone. */
  #page-home .home-cards .card h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin-bottom:20px;
    display:flex;justify-content:space-between;align-items:baseline;gap:12px;
    text-align:left;
  }
  #page-home .home-cards .card .big{
    font-size:clamp(52px,16vw,72px);font-weight:650;letter-spacing:-.05em;
    line-height:.9;font-variant-numeric:tabular-nums;text-align:center;
  }
  #page-home .home-cards .card .sub{
    font-size:15px;color:var(--muted);margin-top:16px;
    font-variant-numeric:tabular-nums;text-align:center;
  }

  /* Readiness: the ring grows into the section's figure, and keeps its
     circle because the SVG carries a viewBox and no aspect-ratio override. */
  #page-home .ring-wrap.ring-solo{justify-content:center;padding:0}
  #page-home .ring{width:min(46vw,190px);height:min(46vw,190px)}
  #page-home .ring svg{width:100%;height:100%;display:block}
  #page-home .ring .val b{font-size:calc(min(46vw,190px) * .30);font-weight:650;
    letter-spacing:-.03em;line-height:1}
  #page-home .ring .val small{font-size:calc(min(46vw,190px) * .082);
    letter-spacing:.14em}
  .ready-delta{
    display:flex;align-items:baseline;justify-content:center;gap:6px;
    margin-top:18px;
    font-size:15px;font-weight:650;font-variant-numeric:tabular-nums;
  }
  .ready-delta .since{font-weight:400;font-size:14px;color:var(--muted)}

  /* ⚠️ The portfolio figure is WHITE here, not the investments gold.
     `.big.inv-fig` paints it `--yellow` everywhere else; on this page he
     asked for white text, and a single gold number among white ones read as
     a highlight that meant nothing. The gold stays on Finances. */
  #page-home .big.inv-fig{color:var(--text)}

  /* ⚠️ Today's gain only — his instruction. The all-time line is still
     rendered and still correct; it is simply not on the phone's Home. */
  #page-home #homeBrokerTotal{display:none}

  /* Today's priorities: the flat list, with a round dot per urgency in
     place of the vertical bar. Same colour, same meaning. */
  #page-home #homePriorities .item{padding:15px 0;border-top:1px solid var(--line)}
  #page-home #homePriorities .item:first-child{border-top:none}
  /* ⚠️ renderHome writes SIX now, for the desktop layout. The phone showed
     three before this change and shows three after it — the count is hidden
     here rather than branched on in JavaScript, so the two layouts cannot
     quietly drift apart. */
  #page-home #homePriorities .item:nth-child(n+4){display:none}
  /* ⚠️ `!important` earns its place here: renderHome writes the bar's
     height as an inline `style="height:34px"`, and an inline declaration
     beats any stylesheet rule without it. The alternative is changing the
     markup the desktop layout depends on. */
  #page-home #homePriorities .cal-bar{
    width:7px;min-height:0;height:7px!important;border-radius:50%;
    align-self:flex-start;margin-top:7px;
  }

  /* ---- the prayer strip loses its frame too ----
     Same markup and same ids; only the box comes off, and the name grows
     into the section's figure the way the mockup has it. */
  #page-home .prayer{
    background:none;border:none;border-radius:0;box-shadow:0 0 0 0 transparent;
    padding:0;margin-top:56px;display:block;
  }
  #page-home .prayer .next .lbl{
    font-size:10px;font-weight:700;letter-spacing:.26em;color:var(--text);
    text-align:left;
  }
  #page-home .prayer .next .name{
    font-size:clamp(46px,14vw,64px);font-weight:650;letter-spacing:-.05em;
    line-height:.92;margin:18px 0 0;text-align:center;
  }
  #page-home .prayer .next .count{font-size:16px;margin-top:14px;
    text-align:center}
  #page-home .prayer .times{
    justify-content:space-between;gap:5px;margin-top:26px;flex-wrap:nowrap;
  }
  #page-home .prayer .p{
    flex:1;min-width:0;padding:9px 0 0;border-bottom:none;
    border-top:1px solid var(--line);
  }
  #page-home .prayer .p.on{border-top-color:var(--green)}
  #page-home .prayer .p .pn{font-size:9px;letter-spacing:.14em;
    color:var(--muted)}
  #page-home .prayer .p .pt{font-size:12px;margin-top:5px}
  #page-home .prayer .p.on .pn,#page-home .prayer .p.on .pt{color:var(--green)}
  #page-home .prayer .loc{margin-top:18px;font-size:12px;
    justify-content:center}

  /* ---- the account control stops being a pill ----
     It has to stay: Settings, Connections and Sign out hang off it, and
     nothing else on a phone reaches them. Only the frame comes off. */
  .topbar{margin:16px 0 0}
  .account{background:none;border:none;padding:0;border-radius:0}
  .account:hover,.account[aria-expanded="true"]{background:none;border:none}
  .account .avatar{width:26px;height:26px;font-size:12px}
  .account .who strong{font-size:13px}
}

@media(max-width:359px){
  /* ⚠️ At 320px the seven selections still hold one line, but the first
     label clipped off the left edge until the padding came off it. */
  .mnav button{padding:5px 3px;letter-spacing:0}
}

/* =====================================================================
   PHONE FINANCES, 2026-08-27 (HANDOFF §122)
   ⚠️ **Phone only**, exactly as Home was. Desktop Finances keeps its
   cards, its donut and its calendar tiles, and is measured unchanged.

   Nothing is removed from the page — the rollover choice, the special
   budgets, the transaction tables and the trend chart are all still
   here. Only the frames come off, the titles go left and white, the
   figures centre, and the counts and comparisons stop competing with
   the numbers.
   ===================================================================== */

/* Above the breakpoint the ranked category rows do not exist; the donut
   is the breakdown, as it always was. */
#fnCategoryBars,#spCategoryBars{display:none}

@media(max-width:820px){

  /* ---- every card loses its frame ---- */
  #page-finances .fin-view .card,
  #page-finances .networth{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:44px 0 0;
  }
  #page-finances .grid{display:block;gap:0}

  /* ---- titles left and white; figures centred ---- */
  #page-finances .fin-view .card h3,
  #page-finances .nw-label,
  #page-finances .rec-head,
  #page-finances .section-title{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin:0 0 20px;text-align:left;
  }
  #page-finances .fin-view .big,
  #page-finances .nw-value{
    font-size:clamp(46px,14vw,64px);font-weight:650;letter-spacing:-.05em;
    line-height:.9;text-align:center;font-variant-numeric:tabular-nums;
  }
  /* ⚠️ **Only the caption directly under a headline figure is centred.**
     Centring every `.sub` also centred each account's "$9,314 available"
     under a left/right row, and the note above the transactions table —
     both read as floating text with nothing to belong to. `.big + .sub`
     is the caption; everything else stays left. */
  #page-finances .fin-view .card .big + .sub,
  #page-finances .nw-sub{
    font-size:15px;color:var(--muted);margin-top:16px;text-align:center;
  }
  #page-finances .fin-view .card .sub{
    font-size:14px;color:var(--muted);text-align:left;
  }

  /* ---- the counts and comparisons he struck out ----
     The date beside Net worth, the bar's key, the account counts under
     each figure, the item-count pills, the month-on-month percentages and
     the calendar's running total. */
  #page-finances .nw-when,
  #page-finances .nw-key,
  #page-finances #fnStatsRow .card .sub,
  #page-finances .kpi-card h3 .pill,
  #page-finances .kpi-d,
  #page-finances #spCalendarSub{display:none}

  /* The page title repeats what the green selection already says. */
  #page-finances .page-head{display:none}

  /* ⚠️ **Money out is RED**, on his instruction. I had made it white on the
     reasoning that red means over budget or a loss and ordinary spending is
     neither — the same call I got wrong on the calendar. Red reads as
     "money leaving" here, which is what it is. */

  /* ⚠️ The second bar — what is owed — is gone on his instruction. The
     figure is still in the row underneath; only the bar went. */
  #page-finances .nw-bar .owed-track{display:none}
  #page-finances .nw-bar{margin-top:26px}
  #page-finances .nw-track{height:10px;border-radius:5px}

  /* ---- cash · investments · owed on ONE line ---- */
  #page-finances #fnStatsRow{display:flex;margin-top:26px}
  #page-finances #fnStatsRow .card{
    flex:1;min-width:0;margin:0;padding:0 4px;text-align:center;
    border-left:1px solid var(--line);
  }
  #page-finances #fnStatsRow .card:first-child{border-left:none}
  #page-finances #fnStatsRow .card h3{
    font-size:9px;letter-spacing:.12em;color:var(--muted);
    margin-bottom:10px;justify-content:center;text-align:center;
  }
  #page-finances #fnStatsRow .big{
    font-size:clamp(18px,5.6vw,25px);letter-spacing:-.03em;line-height:1.05;
  }
  /* ⚠️ The investments figure is GOLD here, on his instruction
     (2026-09-03) — it was white, and desktop's was not, so the same number
     had two colours depending on the screen. **Home's portfolio figure
     stays white** and that is not an oversight: he asked for white there
     specifically, because one gold number among white ones read as a
     highlight that meant nothing. Finances is where the gold means
     "invested". */

  /* ---- a month's in / out / net, three across ---- */
  #page-finances .kpi-months{display:block}
  #page-finances .kpi-row{gap:0}
  #page-finances .kpi{
    text-align:center;padding:0 4px;border-left:1px solid var(--line);
    align-items:center;
  }
  #page-finances .kpi-row .kpi:first-child{border-left:none}
  #page-finances .kpi-k{font-size:9px;font-weight:700;letter-spacing:.12em}
  #page-finances .kpi-v{
    font-size:clamp(17px,5.2vw,23px);font-weight:650;margin-top:9px;
  }

  /* ---- WHERE IT WENT: ranked rows instead of the donut ----
     ⚠️ The DOT carries the category's colour; the BAR is green, or red
     when that category is over its budget (§113.3). A coloured bar beside
     a red one made an under-budget row read as an overspend. */
  #page-finances #fnCategoryDonut,
  /* Spending's budget bars give way to the same ranked rows — his
     instruction. The trend chart comes off the phone with them. */
  #page-finances #budgetBars,
  #page-finances #spTrendCard{display:none}
  #page-finances #fnCategoryBars,
  #page-finances #spCategoryBars{display:block;margin-top:24px}
  .went .g{padding:13px 0;border-top:1px solid var(--line)}
  .went .g:first-child{border-top:none}
  .went .g .top{display:flex;align-items:baseline;justify-content:space-between;
    gap:12px}
  .went .g .n{font-size:14px;display:flex;align-items:center;gap:9px;min-width:0}
  .went .g .n i{width:9px;height:9px;border-radius:3px;display:block;
    flex-shrink:0}
  .went .g .n span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
  .went .g .v{font-size:14px;font-weight:600;white-space:nowrap;
    font-variant-numeric:tabular-nums}
  .went .g .v .pc{font-weight:400;color:var(--muted);margin-left:7px}
  .went .g .rail{height:4px;border-radius:2px;background:#141a17;margin-top:10px}
  .went .g .rail i{display:block;height:100%;border-radius:2px;
    background:var(--green)}
  .went .g .rail i.over{background:var(--red)}

  /* ---- the calendar: a hairline grid, no tiles ----
     ⚠️ **The daily amounts are RED**, on his instruction (2026-08-27). I had
     made them white, reasoning that red means over budget or a loss
     elsewhere on the page and an ordinary day's coffee is neither. He wants
     red — on the calendar the colour reads as "money out" rather than
     "something is wrong". Today is still marked by its green number and
     green underline. */
  #page-finances .cal-wrap{overflow:visible}
  #page-finances .cal-grid{gap:0;min-width:0;margin-top:6px}
  #page-finances .cal-h{display:none}
  #page-finances .cal-d{
    /* ⚠️ `background:none` too — the base rule paints `--panel2`, so
       without this every day kept a filled tile and the grid still read
       as boxes. */
    min-height:50px;background:none;border:none;
    border-bottom:1px solid var(--line);
    border-radius:0;padding:8px 1px 9px;align-items:center;
  }
  #page-finances .cal-d.out{opacity:1}
  /* An out-of-month day becomes an empty cell that only holds the first
     row's alignment — he asked for the greyed 26–31 to go. */
  #page-finances .cal-d.out .cal-n,
  #page-finances .cal-d.out .cal-t{visibility:hidden}
  #page-finances .cal-d.today{
    border-color:transparent;border-bottom:2px solid var(--green);
    box-shadow:none;
  }
  #page-finances .cal-n{font-size:12px;text-align:center;width:100%}
  #page-finances .cal-d.today .cal-n{color:var(--green);font-weight:700}
  #page-finances .cal-t{margin-top:5px;align-items:center;font-size:10px}
  /* `--red` is what the base rule already sets, so this stops overriding
     it — today included, so every amount reads the same. */
  #page-finances .cal-spend{color:var(--red);font-size:10px}
  #page-finances .cal-d.today .cal-spend{color:var(--red)}

  /* ---- account and category rows, properly separated ----
     ⚠️ `.budg-row` was a 14px margin and nothing else, so three accounts
     ran together as six unrelated lines. A hairline between them, the name
     and the figure on one line, and the caption **left, under the name**
     where it belongs. Used by the account lists and the budget bars alike. */
  #page-finances .budg-row{
    margin:0;padding:14px 0;border-top:1px solid var(--line);
  }
  #page-finances .budg-row:first-child{border-top:none}
  #page-finances .budg-row .top{font-size:15px;margin-bottom:0;gap:14px}
  #page-finances .budg-row .sub{
    font-size:12px;color:var(--muted);text-align:left;margin-top:5px;
  }

  /* ---- the account listings: off the phone's Overview ----
     ⚠️ His instruction. "Where your money sits", "What you owe" and the
     Investments drawer are the same accounts the **Bank** and **Brokerage**
     tabs already list one per line, so nothing is lost by taking them off
     Overview — Overview keeps the three totals.
     ⚠️ Desktop dropped these too on 2026-09-03 (§151.5), so these two are
     now hidden at every width; the rule stays here rather than moving out
     because the desktop one carries its own, different reasoning. */
  #page-finances #fnAccountLists,
  #page-finances #fnBrokerageRow,
  /* The "4 accounts" line under Portfolio Value, struck out. Only the
     count is hidden — when the brokerage reports a previous close, today's
     move takes its place and stays. */
  #page-finances #brPortfolioSub.is-count,
  /* ⚠️ `#brNoHoldings` USED TO BE HIDDEN HERE and that was wrong — see
     §137. He struck out "Individual holdings not shared by this brokerage."
     when it sat under a working list, where it only said what was missing.
     But it is shown *instead of* the list, not beside it, so hiding it left
     an empty Brokerage tab with no positions and no reason — which is what
     he reported. It says what to do now, and it stays. */
  /* The category breakdown comes off Overview; Spending keeps it, which is
     the tab for where money went. Overview on the phone is the totals and
     nothing else.
     ⚠️ `#fnWhereItWentCard` MOVED into the Spending panel on 2026-09-03
     (§151.3) and this rule follows it there, which is why it still reads
     the same on a phone: the card is hidden wherever it sits, and the
     phone's own ranked rows (`#spCategoryBars`) are what Spending shows.
     `#fnCalendarCard` was deleted in the same change — Overview no longer
     has a calendar at any width — so it is no longer named here. */
  #page-finances #fnWhereItWentCard{display:none}
  #page-finances .table-wrap{overflow-x:auto}
  /* ⚠️ 16px, or iOS zooms the page in on focus and leaves it zoomed. */
  #page-finances input,#page-finances select{font-size:16px}

  /* ---- buttons: white text with a green rule under it ----
     ⚠️ His instruction — the filled green pill was the last solid block on
     a page that has no boxes anywhere else, and it pulled the eye harder
     than any figure on the screen. The label carries the action; the green
     line under it says it is pressable.

     Kept deliberately: a real `:active` state and a focus ring. A control
     with no feedback at all is not minimal, it is broken. */
  #page-finances .btn{
    background:none;border:none;border-radius:0;padding:10px 0 8px;
    color:var(--text);border-bottom:2px solid var(--green);
    font-weight:650;letter-spacing:.01em;
  }
  #page-finances .btn:hover{background:none;color:var(--text)}
  #page-finances .btn:active{border-bottom-color:var(--text)}
  #page-finances .btn:focus-visible{
    outline:2px solid var(--green);outline-offset:3px;
  }
  #page-finances .btn.ghost,
  #page-finances .btn.ghost:hover{
    background:none;border:none;border-bottom:2px solid var(--line);
    color:var(--muted);
  }

  /* ---- inputs: an underline, not a filled box ----
     Same reasoning. `--faint` on the placeholder is the one grey the design
     keeps: a hint must not read as a value already entered. */
  #page-finances .field input,
  #page-finances .field select{
    background:none;border:none;border-bottom:1px solid var(--line);
    border-radius:0;padding:9px 2px;color:var(--text);
  }
  #page-finances .field input:focus,
  #page-finances .field select:focus{
    border-bottom-color:var(--green);
  }
  #page-finances .field input::placeholder{color:var(--faint)}

  /* ⚠️ The special-budget inputs are bare `<input>`s in a `.special-add`
     row, not `.field` children, so the rule above never reached them and
     they stayed as filled boxes next to underlined ones. And "Add" was
     sharing their line, which squeezed it against the right edge — it gets
     its own line now. */
  /* ⚠️ A grid, not a wrapping flex row. `flex:1 0 100%` did put Add on its
     own line but also stretched it to the full width, so its green rule ran
     edge to edge — three times the weight of "Save budgets" above it. The
     grid puts the two inputs on one row and the button under them, sized to
     its own text. */
  #page-finances .special-add{
    display:grid;grid-template-columns:1fr 1fr;gap:14px;
  }
  #page-finances .special-add input{
    background:none;border:none;border-bottom:1px solid var(--line);
    border-radius:0;padding:9px 2px;color:var(--text);min-width:0;
  }
  #page-finances .special-add input:focus{border-bottom-color:var(--green)}
  #page-finances .special-add input::placeholder{color:var(--faint)}
  /* ⚠️ `flex:1 0 100%` — the button takes a whole line. `flex:0 0 auto`
     left it sharing the row with both inputs and squeezed against the right
     edge; a wrap only happens if something claims the full width. */
  #page-finances .special-add .btn{
    grid-column:1 / -1;justify-self:start;margin-top:6px;
  }
  #page-finances .field > span,
  #page-finances .field label{
    font-size:12px;color:var(--muted);text-transform:none;letter-spacing:0;
    font-weight:400;
  }

  /* ---- the budget fields become a row, not a stack of filled boxes ----
     `.field` is `display:flex;flex-direction:column`, so the label sits
     above a filled input. Turned on its side here: name left, figure right,
     one hairline under it. The rollover choice and the special-budget form
     keep their controls — a select and a text field still have to look
     like something you can tap. */
  #page-finances #budgetFields .field{
    flex-direction:row;align-items:center;justify-content:space-between;
    gap:14px;padding:14px 0;border-bottom:1px solid var(--line);
  }
  #page-finances #budgetFields .field > span{
    font-size:15px;color:var(--muted);text-transform:none;letter-spacing:0;
    font-weight:400;
  }
  #page-finances #budgetFields .field input{
    width:112px;flex:0 0 112px;background:none;border:none;
    border-bottom:1px solid var(--line);border-radius:0;
    text-align:right;font-weight:600;padding:4px 2px;
  }
  #page-finances #budgetFields .field input:focus{
    border-bottom-color:var(--green);
  }
}

/* =====================================================================
   PHONE HOME — ONE SCREEN, 2026-08-27 (HANDOFF §125)
   ⚠️ His instruction: Home must not scroll on a phone. It was 1556px
   against an 812px screen, so this is not a type tweak — the sections
   are compressed and the two money figures share a row.

   ⚠️ **Phone only**, like everything else in the Finances/Home passes.
   Nothing is removed: the prayer strip, the ring, the day-on-day marker,
   the month spend, the portfolio and today's list are all still here.
   ===================================================================== */

@media(max-width:820px){

  /* ---- the fixed furniture, tightened ---- */
  #page-home .hello{padding-top:14px}
  #page-home .hello-g{font-size:10px;letter-spacing:.18em}
  #page-home .hello-who{font-size:19px;margin-top:4px}
  #page-home .hello-date{font-size:11px;margin-top:3px}

  /* ---- ⚠️ the page shares out whatever height is left ----
     He asked for the air back after the greeting and around the prayer, and
     for the blank block at the bottom to go. Hard-coding padding would
     overflow a 812 screen and still leave a gap on a 932 one, so the active
     page is a flex column that fills the viewport and distributes the
     spare space BETWEEN its sections. Tall phone: generous air. Short
     phone: it closes up to nothing and still fits. */
  .main:has(#page-home.active){display:flex;flex-direction:column;
    min-height:100dvh}
  /* ⚠️ **NO auto margin, and NOT `space-between` — §128.**
     Both were attempts to spend the spare height as *air*, and he rejected
     both: `space-between` opened a band above readiness (§127), and a single
     auto margin after the greeting turned that band into one large hole
     under the date. His instruction is that **the gap below the date matches
     the gap above the greeting**, and the height goes into the readiness row
     instead. So the column simply starts at the top and the sections are
     sized to fill it. */
  #page-home.active{
    display:flex;flex-direction:column;justify-content:flex-start;
    flex:1;min-height:0;
  }

  /* ---- sections close up ---- */
  #page-home .prayer,
  #page-home .home-cards .card{margin-top:10px}
  /* ⚠️ 6px, and it matters: at 10px the page came to 814 against an 812
     screen — two pixels of scroll, which is still scroll. Measured, not
     guessed. */
  #page-home .main,.main:has(#page-home.active){padding-bottom:6px}
  #page-home .home-cards .card h3{margin-bottom:10px;font-size:9px;
    letter-spacing:.2em}
  #page-home .prayer .next .lbl{font-size:9px;letter-spacing:.2em}

  /* ---- prayer: the name stays the moment, at half the height ---- */
  #page-home .prayer .next .name{
    font-size:clamp(24px,7.4vw,32px);margin-top:6px;
  }
  #page-home .prayer .next .count{font-size:13px;margin-top:6px}
  #page-home .prayer .times{margin-top:14px}
  #page-home .prayer .p{padding-top:7px}
  #page-home .prayer .p .pt{font-size:11px;margin-top:3px}
  #page-home .prayer .loc{margin-top:10px;font-size:11px}

  /* ---- readiness: the ring beside its marker, not above it ---- */
  #page-home .ring-wrap.ring-solo{justify-content:flex-start;gap:20px}
  #page-home .ring{width:96px;height:96px}
  #page-home .ring .val b{font-size:29px}
  #page-home .ring .val small{font-size:8px;letter-spacing:.1em}
  #page-home .ready-delta{margin-top:0;font-size:13px;justify-content:flex-start}
  #page-home .ready-delta .since{font-size:12px}
  /* The marker sits to the RIGHT of the ring rather than under it — 40px
     of height saved, and the two belong together anyway. */
  #page-home .home-cards .card:has(.ring-solo) .ring-wrap{flex-wrap:nowrap}

  /* ---- ⚠️ readiness, month spend and portfolio share ONE row ----
     His instruction: put the money next to readiness rather than under it.
     ⚠️ **The three-across placement that used to live here is GONE — see
     §130 at the foot of this file.** Three columns left the two money ones
     far shorter than the ring and he struck the gap out; they stack down a
     single right-hand column now. What stays here is the part §130 does
     not restate: the markup is untouched, this is grid placement only, and
     Today's priorities spans the full width underneath. */
  #page-home .home-cards > .card:last-child{margin-top:18px}
  /* ⚠️ `.card .big`, not `.big` — the §119 rule is
     `#page-home .home-cards .card .big`, one class more specific, so a
     shorter selector here lost silently and the figures never shrank. The
     money row stayed 151px tall and the page stayed off the screen. */
  /* ⚠️ Sized for a THIRD of the screen, not half. At clamp(26px,8vw,34px)
     "$17,730" was 115px wide in a 116px column and rendered as "$17,73" —
     clipped, and it looked like a real figure. */
  #page-home .home-cards .card .big{
    font-size:clamp(19px,5.4vw,24px);letter-spacing:-.03em;text-align:left;
  }
  #page-home .home-cards > *{min-width:0}
  #page-home .home-cards .card .sub{
    font-size:12px;margin-top:6px;text-align:left;
  }
  /* ---- today's list, tightened ---- */
  #page-home #homePriorities{margin-top:2px}
  #page-home #homePriorities .item{padding:6px 0;gap:10px}
  #page-home #homePriorities .name{font-size:13px;line-height:1.22}
  #page-home #homePriorities .meta{font-size:11px;margin-top:2px}
  #page-home #homePriorities .pill{font-size:9px;padding:2px 7px}
  #page-home #homePriorities .cal-bar{margin-top:5px}

  /* ---- the last of the height ---- */
  /* A little air under the page selections, where he drew the purple
     line. */
  /* ⚠️ ONE variable drives BOTH gaps, because he asked for them to be
     equal. The greeting reads 6px lower than its own padding — that is the
     nav's bottom padding — so the prayer's margin carries the +6. Change
     `--hgap` and they stay matched; set them separately and they drift. */
  #page-home{--hgap:clamp(24px,3.4vh,40px)}
  #page-home .hello{padding-top:var(--hgap)}
  #page-home .hello-who{font-size:18px}
  #page-home .prayer .times{margin-top:11px}
  /* Enough to separate the prayer block from the row under it without
     re-opening the gap he struck out. */
  #page-home .prayer .loc{margin-top:8px;padding-bottom:18px}

  /* ---- §128: everything shifts up, and readiness gets the height ----
     ⚠️ His instruction: the gap under the date matches the gap above the
     greeting, everything moves up, readiness and the figures beside it get
     bigger, and the "$169 left · 4 days" line goes.

     ⚠️ **Every size that can be traded for height is a VARIABLE**, not a
     literal. There are three cases to satisfy on one page — tall phone,
     short phone, and the sample banner showing or not — and the banner
     rules use `:has()`, which carries an id's specificity. A short-screen
     rule written as a plain declaration LOSES to them silently. Overriding
     variables instead means the cascade order decides, not the selector
     length. §125.3 and §122.3 are the same lesson. */
  #page-home{
    --r:clamp(84px,12.2vh,110px);   /* the readiness ring */
    --rowpad:clamp(9px,1.9vh,20px); /* a priority row's own padding */
    --locpad:clamp(14px,3vh,30px);  /* under the prayer's location line */
    --tailgap:clamp(16px,3vh,30px); /* the priorities heading's clearance */
    --prayname:clamp(27px,8.4vw,36px);
  }
  #page-home .prayer{margin-top:calc(var(--hgap) + 6px)}

  /* ⚠️ **The ring's width comes straight out of the money columns.**
     The readiness column is `auto`, so at 126px it left ~94px for
     "$17,730" and the figure clipped to "$17,73" — §126.3 again, from the
     opposite direction. **Do not grow the ring without re-measuring the
     figures' `scrollWidth`.** The score and its label follow the ring so
     they cannot drift out of proportion with it. */
  #page-home .ring{width:var(--r);height:var(--r)}
  #page-home .ring .val b{font-size:calc(var(--r) * .30)}
  #page-home .ring .val small{font-size:calc(var(--r) * .078);
    letter-spacing:.12em}
  #page-home .ready-delta{font-size:14px}
  #page-home .ready-delta .since{font-size:13px}
  #page-home .home-cards .card h3{font-size:10px;margin-bottom:13px}
  #page-home .home-cards .card .big{font-size:clamp(19px,5.6vw,25px)}
  #page-home .home-cards .card .sub{font-size:13px;margin-top:7px}
  /* The hairlines run the full height of the row rather than stopping at
     each tile's own text — with the ring making the first column much the
     tallest, `start` left two stubs of different lengths. */
  #page-home .home-cards{align-items:stretch}

  /* ---- the rest of the reclaimed height, spent on rhythm ----
     Whatever the row does not take is spread through the page rather than
     left as one blank block. Nothing is added or removed; the existing
     things simply breathe. */
  #page-home .prayer .next .name{font-size:var(--prayname)}
  #page-home .prayer .times{margin-top:14px}
  #page-home .prayer .p{padding-top:10px}
  #page-home .prayer .loc{padding-bottom:var(--locpad)}
  #page-home .home-cards > .card:last-child{margin-top:var(--tailgap)}
  #page-home #homePriorities .item{padding:var(--rowpad) 0}
  #page-home #homePriorities .name{font-size:14px}
  #page-home #homePriorities .meta{font-size:12px}
  /* ⚠️ "$169 left · 4 days" removed on his instruction. **Phone only** — the
     desktop card still carries it, and the maths behind `spent_mtd` is
     untouched; the card has simply stopped explaining itself, exactly as in
     §105 and §108. */
  #page-home #homeSpendSub{display:none}
  /* The banner is the one thing that may or may not be there. It keeps its
     frame — it is what stops sample numbers reading as real — but it is
     tightened so the page still fits on the screen while it is showing. */
  /* ⚠️ The banner KEEPS its frame — it is what stops sample numbers reading
     as real, and this project has been bitten by that. It is only made
     compact, so Home still fits one screen while it is showing. */
  #page-home #homeBanner{padding:9px 11px;font-size:11.5px;line-height:1.4}
  #page-home #homeBanner:not([hidden]){margin-top:16px}
  /* ⚠️ The banner is ~90px of page that may or may not be there, and the
     rhythm above is sized for the case where it is not. When it IS showing
     the page ran 21px past the screen, so the same rhythm closes up rather
     than the banner being shrunk — it is what stops sample numbers reading
     as real, and this project has been bitten by that before. */
  #page-home:has(#homeBanner:not([hidden])){
    --r:clamp(78px,10.2vh,96px);
    --rowpad:6px;
    --locpad:8px;
    --tailgap:10px;
    --prayname:clamp(24px,7.2vw,30px);
  }
}

/* ⚠️ SHORT PHONES (an SE is 667 tall, not 932).
   The two paddings above are the air he asked for, and on a tall phone
   they are right. On a short one the flexible surplus is already spent —
   measured at 12px before the prayer — so a fixed padding is taken
   straight out of the content's own height and pushes Home off the
   screen. They shrink here rather than being fought over. */
/* ⚠️ SHORT PHONES (an SE is 667 tall, not 932).
   The sizes above are what a tall phone can afford. On a short one the
   same numbers push Home off the screen, so every one of them is turned
   down here — including the ring, which grew by his instruction and costs
   height as well as width.

   ⚠️ **Both selectors carry the same block on purpose.** The banner rules
   above use `:has()`, which carries an id's specificity; a plain
   `#page-home` override loses to them however late it appears. The
   `:has()` variant is repeated so the short screen wins in either state. */
@media(max-width:820px) and (max-height:800px){
  #page-home,
  #page-home:has(#homeBanner:not([hidden])){
    --hgap:16px;
    --r:clamp(80px,11vh,94px);
    --rowpad:8px;
    --locpad:10px;
    --tailgap:14px;
    --prayname:clamp(23px,7vw,28px);
  }
  #page-home .prayer .times{margin-top:9px}
  #page-home .prayer .p{padding-top:7px}
  #page-home .home-cards .card h3{margin-bottom:9px}
}
@media(max-width:820px) and (max-height:700px){
  #page-home,
  #page-home:has(#homeBanner:not([hidden])){
    --hgap:10px;
    --r:82px;
    --rowpad:6px;
    --locpad:6px;
    --tailgap:10px;
    --prayname:clamp(21px,6.4vw,25px);
  }
  /* ⚠️ A short screen WITH the banner is the one case that will not fit —
     the banner is ~100px of a 667px page. Everything that can give, gives;
     what is left is recorded in HANDOFF §128 rather than paid for by
     dropping the warning, which is what stops sample numbers reading as
     real. */
  #page-home:has(#homeBanner:not([hidden])){--r:70px;--rowpad:4px}
  #page-home:has(#homeBanner:not([hidden])) .hello-who{font-size:16px}
  #page-home:has(#homeBanner:not([hidden])) .prayer .times{margin-top:7px}
  #page-home:has(#homeBanner:not([hidden])) .prayer .p{padding-top:5px}
  #page-home:has(#homeBanner:not([hidden])) #homeBanner{
    padding:7px 9px;font-size:11px}
}

/* =====================================================================
   PHONE HEALTH — 2026-08-27 (HANDOFF §129)

   His split, in his words: "Home has the 3 circles, stress today, and
   activity today. Vitals has sleep, vitals, and resilience. Body health
   has heart health, stress, readiness history."

   ⚠️ **Phone only, like Home and Finances before it.** Desktop Health is
   NOT redesigned: it has no tabs, keeps its cards, keeps the bar chart of
   stress minutes, keeps the horizontal sleep-stage chart and keeps the
   workouts table. Every rule below is inside `@media(max-width:820px)`,
   and the two elements that exist only for the phone — the tab strip and
   `.phone-only` — are hidden above it.

   ⚠️ **The split hides blocks; it does not move them.** The document
   already ran home → vitals → body, so nothing had to be reordered.
   Reordering would have changed desktop, which is the one thing that must
   not happen.
   ===================================================================== */

/* ⚠️ EVERY phone-only addition has to be listed here, not just the obvious
   two. `.hring` was left out of the first version and the three ring SVGs
   rendered on DESKTOP — 100px of empty circle above each score, with the
   ring's own "84 / Optimal" stacked above the desktop figure. It is not
   enough to style a phone-only element inside the media query; it must be
   switched OFF outside it. */
.hviews,.phone-only,.hring{display:none}

/* ⚠️ The mirror of `.phone-only`, and it earns its place for the same
   reason: an element the desktop layout adds must be switched OFF
   outside the desktop media query, not merely styled inside it. The
   `.hring` bug (§145) was exactly this mistake in the other direction. */
.desk-only{display:none}

/* ⚠️ These six carried `style="margin-top:16px"` INLINE, and an inline
   style beats every selector — the phone's 40px rhythm applied to every
   section except these, which stayed at 16 and looked broken next to the
   rest. The margin is CSS now, and it is stated **above the breakpoint
   only** so it cannot fight the phone rule: an id selector here would
   out-specify `#page-health .card` and win at every width. Desktop spacing
   is unchanged. */
@media(min-width:821px){
  #page-health .grid.g2,
  #page-health #stressCard,
  #page-health #hStressTrendCard,
  #page-health #hReadyTrendCard,
  #page-health #workoutCard{margin-top:16px}
}

@media(max-width:820px){

  .phone-only{display:block}
  /* The page title repeats what the green selection already says. */
  #page-health .page-head{display:none}

  /* ---- the three sub-pages ----
     ⚠️ **This strip IS `.fin-switch`** — the same component Finances uses,
     not a copy of it. His instruction was to match them, and two stylesheets
     describing the same control drift apart the first time either is
     touched. The only thing added here is the switch that keeps it off
     desktop; everything else — the 11px padding that gives the labels their
     air, the 44px touch target, title case, the white active label over a
     green rule, the 18px beneath — comes from `.fin-switch` itself.

     ⚠️ The first version styled it by hand: no top padding at all, so the
     labels sat hard against the page selections above them, and no
     `min-height`, so the tap target was about 25px against Finances' 44. */
  .hviews{display:flex}

  /* ⚠️ Three rules, one per view. A block with no `data-hv` — the banner,
     the tab strip — is never hidden by any of them, which is what keeps
     the sample-data warning on screen whichever tab is open. */
  #page-health[data-hv-active="home"]   [data-hv]:not([data-hv="home"]),
  #page-health[data-hv-active="vitals"] [data-hv]:not([data-hv="vitals"]),
  #page-health[data-hv-active="body"]   [data-hv]:not([data-hv="body"]){
    display:none;
  }
  #page-places[data-pl-active="coffee"] [data-pl="eats"],
  #page-places[data-pl-active="eats"] [data-pl="coffee"]{display:none}
  #page-canvas[data-cv-active="upcoming"] #assignmentPast,
  #page-canvas[data-cv-active="past"] #cvStats,
  #page-canvas[data-cv-active="past"] #assignmentList{display:none}

  /* ---- every card loses its frame ---- */
  #page-health .card{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:40px 0 0;
  }
  /* ⚠️ `display:contents` on the two-across grids, so each card inside can
     be shown or hidden on its own. Resilience and heart health share one
     grid on desktop and land on DIFFERENT tabs here; with the grid still a
     box, hiding one child would leave the other stranded in half a row. */
  #page-health .grid.g2{display:contents}

  /* ---- titles left and white, figures centred ---- */
  #page-health .card h3,
  #page-health .phone-only h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin:0 0 20px;text-align:left;
  }
  #page-health .fig{
    font-size:clamp(46px,14vw,64px);font-weight:650;letter-spacing:-.05em;
    line-height:.9;text-align:center;font-variant-numeric:tabular-nums;
  }
  #page-health .under{font-size:14px;color:var(--muted);margin-top:14px;
    text-align:center}

  /* ---- HOME: the three circles on ONE line ----
     ⚠️ `display:contents` is wrong here — it would stack the three. The
     row keeps a box and becomes a flex row instead. */
  #page-health .grid.g3{display:flex;gap:0;margin:40px 0 0}
  #page-health .grid.g3 > .card{
    flex:1;min-width:0;margin:0;padding:0 2px;text-align:center;
    border-left:1px solid var(--line);
    display:flex;flex-direction:column;align-items:center;
  }
  #page-health .grid.g3 > .card:first-child{border-left:none}
  #page-health .grid.g3 > .card h3{
    font-size:9px;letter-spacing:.12em;color:var(--muted);margin:0;
    text-align:center;
  }
  /* The figure and its caption are the DESKTOP treatment of these three.
     The ring carries the number here. */
  #page-health .grid.g3 > .card .big,
  #page-health .grid.g3 > .card .sub{display:none}

  #page-health .hring{
    display:block;position:relative;margin-top:12px;flex-shrink:0;
    --r:min(23vw,104px);width:var(--r);height:var(--r);
  }
  /* ⚠️ No `preserveAspectRatio` override, so this stays a CIRCLE. Forcing
     an SVG to fill its box turns the ring into an oval — HANDOFF §113. */
  #page-health .hring svg{width:100%;height:100%;display:block;
    transform:rotate(-90deg)}
  #page-health .hring .track{stroke:var(--line)}
  #page-health .hring .arc{stroke:var(--accent)}
  #page-health .hring .val{position:absolute;inset:0;display:flex;
    flex-direction:column;align-items:center;justify-content:center;gap:2px}
  #page-health .hring .val b{font-size:calc(var(--r) * .30);font-weight:650;
    letter-spacing:-.03em;line-height:1;font-variant-numeric:tabular-nums}
  #page-health .hring .val small{font-size:calc(var(--r) * .085);
    color:var(--muted);letter-spacing:.1em;text-transform:uppercase}

  /* ---- HOME: stress today ---- */
  #page-health .stress-card{margin-top:40px}
  #page-health .stress-head{display:block}
  #page-health .stress-head > div:first-child{
    display:flex;align-items:baseline;justify-content:space-between;gap:12px}
  #page-health .stress-label{
    font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
    color:var(--accent);margin:0;
  }
  #page-health .stress-share{text-align:center;margin-top:0}
  #page-health .stress-share .big{
    font-size:clamp(46px,14vw,64px);font-weight:650;letter-spacing:-.05em;
    line-height:.9;color:var(--text);font-variant-numeric:tabular-nums;
  }
  #page-health .stress-share .sub{font-size:14px;color:var(--muted);
    margin-top:14px}
  #page-health .stress-track{height:10px;border-radius:5px;margin-top:24px;
    background:#141a17}
  #page-health .stress-key{gap:10px 20px;margin-top:16px;font-size:13px}
  #page-health .stress-key b{color:var(--text);font-weight:650}
  /* ⚠️ `.stress-key .dot` has a colour and has never had a SIZE, so the
     legend has always named two colours and shown neither — on desktop
     too. Sized here, phone only, because desktop Health is not in scope
     for this pass. **The desktop legend is still dotless.** */
  #page-health .stress-key .dot{width:8px;height:8px;border-radius:2px;
    display:inline-block;flex-shrink:0}
  #page-health .stress-key .nw-key-item{gap:8px}

  /* ---- HOME: activity today ---- */
  /* `.phone-only` is not a `.card`, so it does not pick up the 40px every
     other section gets from the rule above. */
  #page-health #hActivityToday{margin-top:40px}
  #page-health .acells{display:flex;margin-top:6px}
  #page-health .acells .acell{
    flex:1;min-width:0;text-align:center;padding:0 4px;
    border-left:1px solid var(--line);
  }
  #page-health .acells .acell:first-child{border-left:none}
  #page-health .acells .k{
    font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;
    color:var(--muted);
  }
  #page-health .acells .v{
    font-size:clamp(20px,6.4vw,28px);font-weight:650;margin-top:10px;
    letter-spacing:-.03em;font-variant-numeric:tabular-nums;
  }

  /* ---- VITALS: last night's sleep ----
     The desktop chart is replaced, not restyled — a horizontal bar per
     stage needs a label column this screen does not have. */
  #page-health #sleepChart{display:none}
  #page-health .stages{display:flex;height:12px;border-radius:6px;
    overflow:hidden;background:#141a17;margin-top:22px;gap:2px}
  #page-health .stages i{display:block;height:100%;border-radius:2px}
  #page-health .stage-rows{margin-top:18px}
  #page-health .stage-rows .r{display:flex;align-items:baseline;
    justify-content:space-between;gap:14px;padding:11px 0;
    border-top:1px solid var(--line)}
  #page-health .stage-rows .r:first-child{border-top:none}
  #page-health .stage-rows .r .n{display:flex;align-items:center;gap:9px;
    font-size:14px;color:var(--muted)}
  #page-health .stage-rows .r .n i{width:9px;height:9px;border-radius:3px;
    display:block;flex-shrink:0}
  #page-health .stage-rows .r .v{font-size:14px;font-weight:600;
    white-space:nowrap;font-variant-numeric:tabular-nums}
  #page-health .stage-rows .r .v .pc{font-weight:400;color:var(--muted);
    margin-left:8px}

  /* ---- label → value rows: vitals, resilience parts, heart health ----
     ⚠️ The VALUE stays RIGHT-aligned. A column of readings is only
     scannable when the digits line up; centring is for a section's own
     headline figure, not for a list. Same rule as Finances. */
  #page-health .metric-row{
    padding:14px 0;border-bottom:none;border-top:1px solid var(--line);
    align-items:baseline;gap:16px;font-size:15px;
  }
  #page-health .metric-row:first-child{border-top:none}
  #page-health .metric-row .m{color:var(--muted)}

  /* ---- VITALS: resilience ---- */
  #page-health #hResilienceSub{display:none}
  #page-health .res-scale{display:flex;gap:6px;margin-top:2px}
  #page-health .res-step{flex:1;height:6px;border-radius:3px;
    background:#141a17;display:block}
  #page-health .res-step.on{background:var(--accent)}
  #page-health .res-level{
    font-size:clamp(28px,9vw,38px);font-weight:650;letter-spacing:-.03em;
    margin-top:18px;text-align:center;color:var(--text);
  }
  #page-health #hResilienceParts{margin-top:24px}

  /* ---- BODY HEALTH: the two fortnights ----
     ⚠️ **The stress line, not the stacked columns — his instruction.**
     A share of a day always fills its column, so all fourteen read as
     mostly red however the day went. The two ends are printed underneath
     in place of an axis. */
  #page-health .chart-host{margin-top:6px}
  #page-health #stressChartNote{display:none}
  #page-health .scale{
    display:flex;justify-content:space-between;margin-top:10px;
    font-size:11px;color:var(--muted);font-variant-numeric:tabular-nums;
    text-align:left;
  }

  /* ---- HOME: recent workouts, rows instead of a table ----
     ⚠️ The table is not restyled into something narrower; it is laid out
     again as rows. Five columns cannot line up on a 375px screen without
     one of them wrapping, and a wrapped "168" under "42" reads as a
     different reading rather than the same one. */
  #page-health #workoutCard .table-wrap{overflow:visible}
  #page-health #workoutCard table{display:block;width:100%}
  #page-health #workoutCard thead{display:none}
  #page-health #workoutCard tbody{display:block}
  #page-health #workoutCard tr{
    display:grid;grid-template-columns:1fr auto;
    column-gap:14px;row-gap:4px;align-items:baseline;
    padding:14px 0;border-top:1px solid var(--line);
  }
  #page-health #workoutCard tbody tr:first-child{border-top:none}
  #page-health #workoutCard td{display:block;border:none;padding:0}
  /* 1 date · 2 activity · 3 intensity · 4 minutes · 5 calories */
  #page-health #workoutCard td:nth-child(2){
    grid-column:1;grid-row:1;font-size:15px}
  #page-health #workoutCard td:nth-child(4){
    grid-column:2;grid-row:1;text-align:right;font-size:14px;font-weight:600;
    font-variant-numeric:tabular-nums}
  #page-health #workoutCard td:nth-child(4)::after{content:" min"}
  #page-health #workoutCard td:nth-child(1){
    grid-column:1;grid-row:2;font-size:12px;color:var(--muted)}
  #page-health #workoutCard td:nth-child(5){
    grid-column:2;grid-row:2;text-align:right;font-size:12px;
    color:var(--muted);font-variant-numeric:tabular-nums}
  #page-health #workoutCard td:nth-child(5)::after{content:" cal"}
  /* The intensity tag rides with the date rather than taking a column of
     its own — `col-drop` already hides it at this width on desktop. */
  #page-health #workoutCard td:nth-child(3){display:none}
}


/* =====================================================================
   PHONE HOME — the prayer label, and the row rebuilt (§130)
   ⚠️ Phone only, both. Desktop keeps the "Next prayer" label and keeps its
   own two-column card grid untouched.
   ===================================================================== */
@media(max-width:820px){

  /* He struck out "NEXT PRAYER". The name of the prayer, its countdown and
     the strip underneath already say what this is. */
  #page-home .prayer .next .lbl{display:none}

  /* ---- the readiness row, rebuilt ----
     ⚠️ His words: "I don't like the empty space ... find a way to fill it."

     **The first attempt filled it with decoration and he rejected it** — a
     budget bar under the spend figure and the all-time gain under the
     portfolio, both added purely because there was room. Filler is not a
     design.

     The space was structural: three columns side by side, one of them a
     104px ring and the other two a single figure each, so two of the three
     were always going to come up short. So the row is **two columns, not
     three** — the ring keeps the left, and the two money figures STACK
     down the right, which is exactly the height the ring occupies. Nothing
     was added and nothing was removed; the same four blocks are arranged
     so the height is spent on content.

     It fixes a second thing on the way: the money figures had a third of
     the screen each, which is how "$17,730" came to clip in §126.3. They
     now have half. */
  #page-home .home-cards{
    display:grid;grid-template-columns:auto 1fr;column-gap:14px;row-gap:0;
    align-items:start;
  }
  #page-home .home-cards > .card{grid-column:1 / -1;margin-top:0}
  /* Readiness spans both money rows. */
  #page-home .home-cards > .card:first-child{grid-column:1;grid-row:1 / 3}
  #page-home .home-cards > .spend-card{
    grid-column:2;grid-row:1;
    border-left:1px solid var(--line);padding-left:14px;
  }
  #page-home .home-cards > #homeBrokerTile{
    grid-column:2;grid-row:2;
    border-left:1px solid var(--line);padding-left:14px;
    border-top:1px solid var(--line);padding-top:14px;margin-top:14px;
  }
  #page-home .home-cards > .card:last-child{grid-column:1 / -1;grid-row:3}
  /* ⚠️ With no brokerage linked the tile is `hidden` and its row would sit
     empty, leaving the spend figure marooned at the top of a tall column.
     The spend cell takes both rows in that case. */
  #page-home .home-cards:has(> #homeBrokerTile[hidden]) > .spend-card{
    grid-row:1 / 3;
  }
  /* Half the width instead of a third, so the figures can breathe again. */
  #page-home .home-cards .card .big{font-size:clamp(22px,6.6vw,30px)}
  #page-home #homeBrokerTotal{display:none}
}

/* =====================================================================
   PHONE CANVAS — 2026-08-28 (HANDOFF §132)

   Two states, not four sections: what is still coming and what has passed.
   Canvas does one job, and inventing a third tab to match Health and Meals
   would be padding.

   ⚠️ **Phone only.** Desktop Canvas is NOT redesigned: no tabs, cards keep
   their frames, the four stats keep their `grid g4` row in document order,
   and "Show N past assignments" stays the desktop control. Every rule below
   is inside `@media(max-width:820px)`.

   ⚠️ **The phone reorders by GRID PLACEMENT, not by moving markup.** Next
   Deadline is third in the document and leads on the phone; moving the
   element would have changed desktop, which must not happen.
   ===================================================================== */

@media(max-width:820px){

  /* The page title repeats what the green selection already says. */
  #page-canvas .page-head{display:none}
  /* The desktop control for the past list. The tab replaces it here. */
  #page-canvas #pastToggle{display:none}

  /* ---- the two states ---- */
  #page-canvas[data-cv-active="upcoming"] #assignmentPast,
  #page-canvas[data-cv-active="past"] #cvStats,
  #page-canvas[data-cv-active="past"] #assignmentList{display:none}
  /* ⚠️ `[hidden]` is global and `!important`, so the past block stays hidden
     until `renderAssignments` un-hides it — which it does from the same
     `showingPast` flag the tab sets. This rule is the *other* direction:
     hiding it again while the Upcoming tab is open. */

  /* ---- every card loses its frame ---- */
  #page-canvas .card{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:40px 0 0;
  }
  #page-canvas #cvStats{margin-top:22px}

  /* ---- titles left and white ---- */
  #page-canvas .card h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin:0 0 20px;text-align:left;
  }

  /* ---- the summary: the deadline leads, the three counts share a line ----
     ⚠️ Placement only. `.deadline-card` is the THIRD child in the document
     and desktop must keep it there. */
  #page-canvas #cvStats{
    display:grid;grid-template-columns:1fr 1fr 1fr;column-gap:14px;row-gap:0;
    align-items:start;
  }
  #page-canvas #cvNextCard{grid-column:1 / -1;grid-row:1;margin:0}
  #page-canvas #cvUpcomingCard{grid-column:1;grid-row:2;margin:36px 0 0}
  #page-canvas #cvSoonCard{grid-column:2;grid-row:2;margin:36px 0 0;
    border-left:1px solid var(--line);padding-left:14px}
  #page-canvas #cvBusiestCard{grid-column:3;grid-row:2;margin:36px 0 0;
    border-left:1px solid var(--line);padding-left:14px}
  #page-canvas #cvStats > *{min-width:0}

  /* The next deadline, centred like every other headline figure.
     ⚠️ Sized for a DATE, not a count — "Sat Aug 29" at the money-figure size
     runs off a 320px screen. */
  #page-canvas #cvNextCard .dl-top{display:block;text-align:center}
  #page-canvas #cvNextCard .big{
    font-size:clamp(34px,10.5vw,46px);font-weight:650;letter-spacing:-.04em;
    line-height:1;text-align:center;
  }
  #page-canvas #cvNextCard .tag{
    display:inline-block;margin:14px 0 0;background:none;padding:0;
    font-size:10px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
    color:var(--muted);
  }
  #page-canvas #cvNextCard .dl-title{
    font-size:15px;color:var(--text);text-align:center;margin-top:7px;
    line-height:1.45;
  }

  /* The three counts. ⚠️ **"8 graded · 3 practice or optional" is GONE**, on
     his instruction — he struck the whole line out. The maths behind the
     figure above it is untouched; the card has stopped explaining itself,
     exactly as in §105, §108 and §128. Desktop still carries it. */
  #page-canvas #cvUpcomingSub{display:none}
  #page-canvas #cvStats > .card:not(#cvNextCard) h3{
    font-size:9px;letter-spacing:.12em;color:var(--muted);margin-bottom:10px;
    text-align:center;
  }
  #page-canvas #cvStats > .card:not(#cvNextCard) .big{
    font-size:clamp(22px,7vw,30px);font-weight:650;letter-spacing:-.03em;
    text-align:center;
  }
  #page-canvas #cvStats > .card:not(#cvNextCard) .sub{
    font-size:11px;color:var(--muted);text-align:center;margin-top:7px;
  }

  /* ---- the assignments ---- */
  #page-canvas #canvasNote{display:none}
  /* The day heading: its own line, with the count pushed to the right.
     `.cal-time` is 74px wide on desktop because it holds a clock time; here
     it holds a date and takes the row. */
  #page-canvas #assignmentList .cal-time,
  #page-canvas #assignmentPast .cal-time{
    display:flex;align-items:baseline;gap:10px;width:auto;
    font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
    color:var(--muted);padding-bottom:10px;
    border-bottom:1px solid var(--line);margin-bottom:0;
  }
  #page-canvas .cal-time .pill{margin-left:auto;background:none;padding:0;
    color:var(--faint);letter-spacing:.06em;font-size:10px}
  #page-canvas .cal-item{padding:14px 0;gap:12px}
  #page-canvas .cal-body .t{font-size:15px;line-height:1.35}
  #page-canvas .cal-body .d{font-size:12px;margin-top:5px}
  /* ⚠️ The link is `display:flex;min-height:44px` above — a touch-target fix
     from §? — which puts the title and its arrow on one stretched row and
     leaves a 44px gap when the title wraps. Inline here; the row itself is
     already tall enough to hit. */
  #page-canvas .assign-link{display:inline;min-height:0}
  #page-canvas .assign-link .go{color:var(--accent);font-weight:700}
  #page-canvas .cal-item .pill{
    background:none;border:1px solid var(--line-2);color:var(--muted);
    font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
    padding:3px 8px;border-radius:999px;
  }
  #page-canvas .cal-item .pill.r{border-color:var(--red);color:var(--red)}
  #page-canvas .cal-item .pill.y{border-color:var(--yellow);color:var(--yellow)}

  /* ---- the done control ----
     ⚠️ **It SAYS "Mark done".** §132 replaced the words with a bare ring on
     the reasoning that the label took a third of the row beside a wrapped
     title. That reasoning was about space; from his side a control with no
     words is a control that is gone, and he asked for it back. **Never
     reduce a button to an unlabelled glyph here again.**

     It stays a BUTTON that changes, not a row that gets crossed out — the
     row keeps its place, its contrast and its colour, and only the button
     turns solid green and reads "✓ Done".

     The space problem is solved by putting the button on its OWN line under
     the assignment rather than beside it, which is what a 375px row has
     room for. */
  #page-canvas .cal-item{flex-wrap:wrap}
  /* ⚠️ `padding-left`, NOT `margin-left`. A `flex-basis:100%` item plus a
     15px left margin is 100% + 15px, so every row overflowed and the whole
     page scrolled sideways. Padding is inside the box. HANDOFF §121.3. */
  #page-canvas .assign-act{
    flex:1 0 100%;align-self:flex-start;margin-top:10px;padding-left:15px;
  }
  #page-canvas .assign-done{
    min-height:38px;padding:8px 16px;font-size:12px;font-weight:600;
    border-radius:999px;
  }
}


/* =====================================================================
   BUILT BUT NOT SHOWN — 2026-08-28 (HANDOFF §134)
   His instruction: "hide meals, keep the infrastructure but hide it."
   ⚠️ **Nothing is deleted.** The section, its styles, its form and every
   line of JavaScript behind it stay exactly where they were; `HIDDEN_PAGES`
   in app.js is the single switch, and taking a name out of that array
   brings the page straight back.

   This rule is the belt to that braces: even if some route showed the
   section, it cannot paint. `!important` because `.page.active` sets
   `display:block` and would otherwise win.
   ===================================================================== */
.page[data-hidden-page]{display:none !important}


/* =====================================================================
   POSITIONS, GROUPED BY THE ACCOUNT THAT HOLDS THEM — §135
   His instruction: "i want a breakdown of positions for brokerages."
   ⚠️ **Both layouts.** Unlike the phone passes, this is not a restyle —
   it is information the page did not carry. A list of positions that
   cannot say which brokerage each one sits in is incomplete on a desktop
   too, so the grouping is not put behind the breakpoint.

   ⚠️ The heading only appears when there are two or more named accounts;
   a single-account portfolio renders exactly as it did before.
   ===================================================================== */
.hold-group > td{
  padding-top:18px;padding-bottom:8px;
  font-size:10px;font-weight:700;letter-spacing:.18em;text-transform:uppercase;
  color:var(--muted);border-bottom:1px solid var(--line-2);
}
tbody tr.hold-group:first-child > td{padding-top:4px}
.hold-group-v{float:right;letter-spacing:.06em;color:var(--text);
  font-variant-numeric:tabular-nums}

@media(max-width:820px){
  /* The section heading reads as the page's other eyebrows do. */
  #page-finances .hold-group > td{
    padding-top:22px;letter-spacing:.22em;color:var(--text);
    border-bottom-color:var(--line);
  }
  #page-finances .hold-group-v{color:var(--muted);font-weight:600}
}

/* =====================================================================
   PHONE PLACES — 2026-09-02 (HANDOFF §143)

   Two lists of the same shape, one at a time. ⚠️ **Phone only.** Desktop
   Places keeps its tiles and shows both lists in document order; the tab
   strip is `display:none` above 820px and nothing below leaks up.

   ⚠️ **The order is DISTANCE** — `renderPlaces` sorts on it because the
   headings promise "closest first". Nothing here re-orders anything; this
   is presentation only.
   ===================================================================== */

@media(max-width:820px){

  /* ⚠️ The page TITLE goes, the headline STAYS. `.page-head` is hidden
     wholesale on Home, Finances and Canvas, but here it carries the one
     line that says where he is and what he has left to spend — which is
     the constraint the whole page runs on. */
  #page-places .page-head{display:block;margin:0}
  #page-places .page-head h2{display:none}
  #page-places .page-head .today{
    display:flex;align-items:baseline;justify-content:space-between;gap:14px;
    margin:16px 0 0;font-size:12px;color:var(--muted);text-align:left;
  }

  /* ---- the two lists ---- */
  #page-places[data-pl-active="coffee"] [data-pl="eats"],
  #page-places[data-pl-active="eats"] [data-pl="coffee"]{display:none}

  /* ---- headings become eyebrows ---- */
  #page-places .section-title{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin:30px 0 4px;text-align:left;
  }

  /* ---- a tile stops being a tile ---- */
  #page-places .tiles{display:block}
  #page-places .tile{
    background:none;border:none;border-radius:0;box-shadow:0 0 0 0;
    border-top:1px solid var(--line);padding:16px 0;transform:none;
  }
  #page-places .tile:first-child{border-top:none}
  /* ⚠️ `transform` and `border-color` are killed on hover too, or a phone
     that reports hover (an iPad with a trackpad) lifts a row that has no
     card to lift. */
  #page-places .tile:hover,#page-places .tile:focus-visible{
    transform:none;border-color:transparent;border-top-color:var(--line);
  }
  #page-places .tile:focus-visible{outline:2px solid var(--accent);
    outline-offset:2px}
  /* The emoji thumbnail. `.emo` handles the inline ones; this is a whole
     96px block that exists only to hold one. */
  #page-places .tile .thumb{display:none}
  #page-places .tile .body{padding:0}

  /* ⚠️ **`display:contents` on `.row`** so the price becomes a grid item of
     the body and can sit on the NAME's line, top right, where a price
     belongs. Without it the price is stuck at the foot of the row inside
     its own flex container. Same technique as the Health grids. */
  #page-places .tile .body{
    display:grid;grid-template-columns:1fr auto;column-gap:14px;
    align-items:baseline;
  }
  #page-places .tile .body > *{grid-column:1;min-width:0}
  #page-places .tile .row{display:contents}
  #page-places .tile h4{grid-row:1;font-size:16px;font-weight:600;
    line-height:1.3;margin:0}
  #page-places .tile .cost{grid-column:2;grid-row:1;text-align:right;
    font-size:15px;font-weight:650;color:var(--text);
    font-variant-numeric:tabular-nums}
  /* ⚠️ Red only when it does NOT fit what is left — the same meaning red
     carries on Finances. `renderPlaces` adds `.down` for exactly that. */
  #page-places .tile .cost.down{color:var(--red)}
  /* Distance and opening hours, on their own line under the name, because
     the heading promises closest first. */
  #page-places .tile .row > span:first-child{
    grid-row:2;font-size:12px;color:var(--muted);
    font-variant-numeric:tabular-nums;padding:0;
  }
  #page-places .tile .stars{grid-row:3;font-size:12px;margin-top:6px;
    letter-spacing:.06em}
  /* ⚠️ **`.stars` had to be excluded too, and leaving it out was a real bug.**
     `.stars` IS a div, so `div:not(.why):not(.row)` matched it as well as the
     tag wrapper and forced BOTH onto grid-row 4 — the pill printed on top of
     the rating on every place that has a tag. Invisible on the Coffee tab,
     which has none, and obvious on Eats. **A selector is a decision about
     everything it reaches** (§123.4), and this one reached one div further
     than it was written for. */
  #page-places .tile .body > div:not(.why):not(.row):not(.stars){
    grid-row:4;margin-top:8px;
  }
  /* ⚠️ The green left rule comes off. It reads as a quote bar on a page
     that has no boxes, and every row would carry one. */
  #page-places .tile .why{
    grid-row:5;border-left:none;padding-left:0;margin-top:8px;
    font-size:13px;line-height:1.45;
  }
  /* ⚠️ **The arrow stays GREEN and the stars stay YELLOW** — his
     instruction. `.stars` is already `var(--yellow)` app-wide, so it is
     deliberately not restated here; only the arrow needs saying, because
     desktop leaves it muted until hover and there is no hover to wait for. */
  #page-places .tile h4 .go{color:var(--accent);float:none;font-size:13px;
    font-weight:700}
  #page-places .tile .tag{font-size:9px;font-weight:700;letter-spacing:.1em;
    text-transform:uppercase;background:none;border:1px solid var(--line-2);
    color:var(--muted);padding:3px 8px;border-radius:999px}
}

/* =====================================================================
   PHONE PRIORITIES — 2026-09-02 (HANDOFF §144)

   ⚠️ **NO TABS, and that is the decision.** Health has three, Meals four,
   Canvas and Places two — because those pages do several jobs. Priorities
   does ONE: what to do next. `server.py` builds `todos` **from** the
   calendar, the inbox and Canvas, scores them together and sorts by score,
   so the ranked list is not a fourth thing beside the other three — it is
   what they add up to. Putting the calendar behind a tap, on the page whose
   purpose is to show the day, would be tabs for the sake of matching.

   ⚠️ **The ranked list LEADS, and it moves by `order`, not by markup.**
   It is third in the document, under the calendar and the inbox — the
   answer printed below its own working. Moving the element would change
   desktop, which keeps its two-column flow untouched.

   ⚠️ **Phone only**, like every pass since §119.
   ===================================================================== */

@media(max-width:820px){

  /* ---- the ranked list first, its sources under it ---- */
  #page-priorities.active{display:flex;flex-direction:column}
  #page-priorities .page-head{order:0}
  #page-priorities #prioritiesBanner{order:1}
  /* The "Ranked to-dos" section is the LAST `.flow-sec` in the document and
     the only one outside `.flow`. */
  #page-priorities > .flow-sec{order:2;margin-top:0}
  #page-priorities .flow{order:3;margin-top:34px}

  /* ---- the page title goes, the count stays ----
     Same call as Places: `.page-head` carries the one line worth keeping,
     "N emails need action". */
  #page-priorities .page-head{display:block;margin:0}
  #page-priorities .page-head h2{display:none}
  #page-priorities .page-head .today{
    margin:16px 0 0;font-size:12px;color:var(--muted);text-align:left;
  }

  /* ⚠️ **The sample-data banner is REMOVED on the phone — his instruction.**
     ⚠️ **Desktop keeps it**, which is the only reason this is acceptable:
     Google is not connected, so the calendar and inbox below are examples,
     and Home's banner names `bank` and `oura` ONLY — it does not cover
     Google. So on the phone there is now no warning that two of these three
     lists are invented. Recorded rather than quietly done. */
  #page-priorities #prioritiesBanner{display:none}

  /* ---- headings become eyebrows ---- */
  #page-priorities .flow-sec h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);padding-bottom:0;margin:0 0 4px;border-bottom:none;
  }
  #page-priorities .flow{gap:34px}

  /* ---- the ranked to-dos ----
     ⚠️ The NUMBER carries rank and urgency at once, which is the whole
     content of a ranked list; a dot beside it would say the same thing
     twice. `.pill.r/.y/.g` already hold the right colours — only the
     background and padding come off. */
  #page-priorities .list .item{
    align-items:flex-start;padding:14px 0;gap:14px;
    border-bottom:none;border-top:1px solid var(--line);
  }
  #page-priorities .list .item:first-child{border-top:none}
  #page-priorities .list .left{align-items:flex-start;gap:14px}
  #page-priorities .list .pill{
    background:none;padding:0;border-radius:0;
    font-size:13px;font-weight:700;line-height:1.5;min-width:16px;
    font-variant-numeric:tabular-nums;
  }
  #page-priorities .list .name{font-size:15px;line-height:1.35}
  #page-priorities .list .meta{font-size:12px;margin-top:5px;
    font-variant-numeric:tabular-nums}
  /* Where it came from. Quiet on purpose — it answers "why is this here?",
     it is not the point of the row. */
  #page-priorities .list .item > .tag{
    background:none;border:none;padding:0;align-self:flex-start;margin-top:3px;
    font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;
    color:var(--faint);white-space:nowrap;flex-shrink:0;
  }

  /* ---- today's calendar ----
     ⚠️ `.cal-time` KEEPS its 74px column here, unlike on Canvas where the
     same class holds a date and had to take the whole row. Here it holds a
     clock time, and reading down the times is the value of a day list. */
  #page-priorities .cal-item{padding:13px 0;gap:12px;align-items:flex-start;
    border-bottom:none;border-top:1px solid var(--line)}
  #page-priorities .cal-item:first-child{border-top:none}
  #page-priorities .cal-time{font-size:12px;font-weight:600;width:66px;
    padding-top:2px;font-variant-numeric:tabular-nums}
  #page-priorities .cal-body .t{font-size:15px;line-height:1.35}
  #page-priorities .cal-body .d{font-size:12px;margin-top:4px}

  /* ---- inbox ----
     ⚠️ **The SUBJECT is promoted and the sender demoted** — the reverse of
     desktop, where `.from` is the bold line. On a phone the subject is what
     is acted on; the sender qualifies it. */
  #page-priorities .mail{padding:13px 0;gap:12px;
    border-bottom:none;border-top:1px solid var(--line)}
  #page-priorities .mail:first-child{border-top:none}
  #page-priorities .mail .dot{width:7px;height:7px;margin-top:7px}
  #page-priorities .mail .from{font-size:12px;font-weight:400;
    color:var(--muted)}
  #page-priorities .mail .subj{font-size:15px;font-weight:600;
    line-height:1.35;margin-top:3px;color:var(--text)}
  #page-priorities .mail .when{font-size:12px;color:var(--faint);
    padding-top:1px;font-variant-numeric:tabular-nums}
}


/* ---- Billing card (Connections) ------------------------------------------
   Only shown once billing is switched on at the server (app/billing.py). It
   carries no card details — Stripe holds those — just status and the two
   buttons that open Stripe's own pages. */
.bill-card{background:linear-gradient(135deg,rgba(47,169,107,.16),rgba(31,143,106,.08));
  border:1px solid var(--line);border-radius:14px;padding:16px 18px;margin-bottom:16px}
.bill-head{font-size:11px;font-weight:700;letter-spacing:.14em;text-transform:uppercase;
  color:var(--muted);margin-bottom:8px}
.bill-line{font-size:14px;line-height:1.5;color:var(--text);margin:0}
.bill-line.ok b{color:var(--green)}
.bill-line.warn{color:var(--yellow)}
.bill-actions{display:flex;gap:8px;flex-wrap:wrap;margin-top:12px}
.bill-actions:empty{display:none}


/* =====================================================================
   DESKTOP, 2026-09-02 (HANDOFF §150)

   ⚠️ **Every rule in this file's last section is inside
   `@media(min-width:821px)`.** That is not tidiness — it is the proof
   that the phone is untouched. The phone redesign of 2026-08-27 is his
   approved design and none of it may move; scoping the desktop work to
   the other side of the same breakpoint means it *cannot*.

   ── The one decision everything else follows ──────────────────────────

   **The 230px sidebar goes, and desktop adopts the phone's shell:**
   masthead across the top, the page selections under a green rule.
   Sakina had two navigation models — a sidebar of icon buttons on a
   laptop, a masthead and a line of selections on a phone — and moving
   between the two meant learning both. One shell, two densities.

   ⚠️ **What is NOT copied from the phone:** the phone stacks everything
   in one column because it has no choice. A 1440px screen has a choice,
   and stacking there wastes it. The LANGUAGE is shared — no card frames,
   one green, titles left and white, figures large and centred — and the
   LAYOUT is not.

   ⚠️ The sidebar is not deleted. It becomes the same sheet the phone's
   wordmark opens, sliding in from the left, because "Last synced" and
   "Refresh data" live in it and nothing else reaches them.
   ===================================================================== */

@media(min-width:821px){

  /* ---- the shell ---------------------------------------------------- */

  /* ⚠️ `body` is a flex row in the base stylesheet so the sidebar can sit
     beside main. With the sidebar out of the flow that row has one child,
     and `display:block` is what lets `.main` centre itself. */
  body{display:block}

  .main{max-width:1240px;margin:0 auto;padding:0 40px 90px}

  /* The sidebar keeps every rule it had — it is still a column with the
     brand on top and "Last synced" at the bottom — and becomes a drawer.
     Same DOM, same ids, same handlers as the phone's sheet. */
  .sidebar{
    position:fixed;left:0;top:0;height:100vh;z-index:70;
    transform:translateX(-101%);visibility:hidden;
    transition:transform .24s cubic-bezier(.32,.72,0,1);
    box-shadow:14px 0 40px rgba(0,0,0,.5);
  }
  body.sheet-open .sidebar{transform:translateX(0);visibility:visible}
  .scrim{
    display:block;position:fixed;inset:0;z-index:65;
    background:rgba(0,0,0,.5);opacity:0;transition:opacity .2s;
  }
  /* An author `display` rule beats the browser's built-in
     [hidden]{display:none}, so without this the scrim lies over the whole
     screen at opacity 0 — invisible, and swallowing every click. Same trap
     as HANDOFF §8, and it has to be repeated here because the phone's copy
     is inside its own media query. */
  .scrim[hidden]{display:none}
  body.sheet-open .scrim{opacity:1}

  /* ---- masthead: the wordmark left, the account control right --------
     ⚠️ `.mmast` was an invisible wrapper above 820px, existing only so the
     account chip could sit above the rule on a phone. It is the masthead
     on both sides of the breakpoint now. */
  .mmast{
    display:flex;align-items:center;justify-content:space-between;gap:24px;
    padding:22px 0 13px;
    /* `--accent`, not `--green`: they are two different values and
       HANDOFF §113/§114 were both caused by treating them as the same. */
    border-bottom:2px solid var(--accent);
  }
  .mmast-id{
    display:flex;align-items:baseline;gap:12px;
    background:none;border:none;padding:0;color:inherit;font:inherit;
    cursor:pointer;
  }
  .mmast-id .ar{font-size:24px;color:var(--green);line-height:1}
  .mmast-id .wm{font-size:14px;font-weight:700;letter-spacing:.34em;
    text-transform:uppercase}
  .mmast-id:hover .wm{color:var(--green)}
  .mmast .topbar{margin:0}

  /* ---- the selections ------------------------------------------------
     ⚠️ Left-aligned, not centred. The phone centres seven short labels
     because they fill its width; at 1240px centring leaves two wide empty
     margins and the eye has to hunt for where the row starts. */
  .mnav{display:flex;gap:26px;padding:15px 0 0}
  .mnav button{
    background:none;border:none;color:var(--muted);font:inherit;
    font-size:11px;font-weight:600;letter-spacing:.16em;
    text-transform:uppercase;padding:4px 0;cursor:pointer;
    border-bottom:2px solid transparent;
  }
  .mnav button:hover{color:var(--text)}
  .mnav button.active{color:var(--green)}
  .mnav button:focus-visible{outline:2px solid var(--green);outline-offset:3px}

  .desk-only{display:block}

  /* ==================================================================
     HOME
     Two columns, and the one thing that made it work: `.home-cards` is
     `display:contents`, so the four tiles stop being children of a grid
     of their own and become items of the page's grid alongside `.prayer`.
     Without that the prayer block and the readiness ring could not share
     a row — they sit at different depths in the markup.

     ⚠️ Every position below is stated as an explicit row and column.
     `#homeBanner` is hidden on an account with everything connected, and
     `display:none` takes a grid item out of the grid entirely — auto
     placement would then slide every row up by one.
     ================================================================== */

  /* ⚠️ `.active`, and it is not decoration. `.page{display:none}` is a class
     selector; `#page-home{display:grid}` is an id one and beats it, so Home
     rendered on TOP of every other page — the whole dashboard was visible
     under Finances. Sixth time specificity has cost a round here. */
  #page-home.active{
    display:grid;
    grid-template-columns:minmax(0,1.15fr) minmax(0,.5fr) minmax(0,.5fr);
    column-gap:40px;align-items:start;
  }
  #page-home .page-head{display:none}
  #page-home .hello{grid-column:1/-1;grid-row:1}
  #page-home #homeBanner{grid-column:1/-1;grid-row:2;margin-top:26px}
  #page-home .prayer{grid-column:1;grid-row:3}
  #page-home .home-cards{display:contents}
  #page-home .home-cards > .card:first-child{grid-column:2/4;grid-row:3}
  #page-home .home-cards > #homeNetTile{grid-column:2;grid-row:4}
  #page-home .home-cards > #homeBrokerTile{grid-column:3;grid-row:4}
  #page-home .home-cards > #homeExpTile{grid-column:2/4;grid-row:5}
  #page-home .home-cards > .card:last-child{grid-column:1;grid-row:4/6}
  /* ⚠️ MTD spend is gone from Home on his instruction — Finances → Spending
     is where that figure lives, and Home was carrying it a second time. It
     is HIDDEN, not deleted: the phone's Home still shows it. */
  #page-home .home-cards > .spend-card{display:none}

  /* ---- the greeting ----
     It spans the width because it has something to span. A centred line in
     a 1160px column with nothing either side of it reads as stranded; two
     hairlines fading out to the edges make it the page's title. */
  #page-home .hello{
    display:grid;grid-template-columns:minmax(0,1fr) auto minmax(0,1fr);
    align-items:center;column-gap:32px;padding:40px 0 0;
  }
  #page-home .hello::before,#page-home .hello::after{content:"";height:1px}
  #page-home .hello::before{grid-column:1;grid-row:1;
    background:linear-gradient(to right,transparent,var(--accent))}
  #page-home .hello::after{grid-column:3;grid-row:1;
    background:linear-gradient(to left,transparent,var(--accent))}
  #page-home .hello-line{
    grid-column:2;grid-row:1;display:flex;align-items:baseline;gap:.28em;
    white-space:nowrap;font-size:clamp(28px,3.2vw,46px);letter-spacing:-.03em;
    line-height:1.05;
  }
  #page-home .hello-g{font-size:1em;font-weight:400;color:var(--muted);
    letter-spacing:inherit;text-transform:none}
  #page-home .hello-g::after{content:","}
  #page-home .hello-who{font-size:1em;font-weight:650;color:var(--green);
    margin:0;letter-spacing:inherit}
  #page-home .hello-date{grid-column:1/-1;grid-row:2;text-align:center;
    font-size:14px;color:var(--muted);margin-top:15px;
    font-variant-numeric:tabular-nums}

  /* ---- the frames come off, exactly as they did on the phone ---- */
  #page-home .prayer,
  #page-home .home-cards .card{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:44px 0 0;
  }
  #page-home .home-cards .card h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin-bottom:16px;
    display:flex;justify-content:center;align-items:baseline;gap:16px;
  }
  #page-home .home-cards .card .big{
    font-size:clamp(28px,2.6vw,36px);font-weight:650;letter-spacing:-.04em;
    line-height:1;text-align:center;font-variant-numeric:tabular-nums;
  }
  /* ⚠️ White, not the investments gold — the same call he made on the
     phone. One gold number among white ones reads as a highlight that
     means nothing. The gold stays on Finances. */
  #page-home .big.inv-fig{color:var(--text)}
  #page-home .home-cards .card .sub{text-align:center;margin-top:12px}
  /* Both of these say what they are without a title: a ring with a score in
     it, and a list of what is due. Removed on his instruction. */
  #page-home .home-cards > .card:first-child h3,
  #page-home .home-cards > .card:last-child h3{display:none}
  /* The day's move sits beside the title now; the line under the figure
     would say it twice. */
  #page-home #homeBrokerToday,#page-home #homeBrokerTotal{display:none}
  #page-home .home-cards .card h3 .hd-r{
    letter-spacing:.1em;font-weight:600;font-size:10px;
  }
  #page-home .home-cards .card h3 .hd-r b{font-weight:600}

  /* ---- readiness: the ring, and the three readings beside it ---- */
  /* ⚠️ `flex-direction:row` is not redundant. `.home-tile` is
     `display:flex;flex-direction:column` in the base stylesheet, so setting
     `display:flex` here changed nothing and the ring sat ON TOP of the three
     readings — 297px of card where 150 was wanted, and a matching hole
     beside the prayer times. Restating `display` is not restating direction. */
  #page-home .home-cards > .card:first-child{
    display:flex;flex-direction:row;align-items:center;gap:34px;
  }
  #page-home .ring-wrap.ring-solo{padding:0;flex:0 0 auto}
  #page-home .ring{width:132px;height:132px}
  #page-home .ring svg{width:100%;height:100%;display:block}
  #page-home .ring .val b{font-size:40px;font-weight:650;letter-spacing:-.03em;
    line-height:1}
  #page-home .ring .val small{font-size:11px;letter-spacing:.14em}
  .ready-rows{flex:1;min-width:0}
  .ready-rows .rr{
    display:flex;align-items:baseline;justify-content:space-between;gap:20px;
    padding:13px 0;border-top:1px solid var(--line);
  }
  .ready-rows .rr:first-child{border-top:none}
  .ready-rows .rr .n{font-size:14px;color:var(--muted)}
  /* ⚠️ RIGHT-aligned, and it stays that way. A column of readings is only
     scannable when the digits line up; centring is for a figure that is a
     section's own headline, which these are not. */
  .ready-rows .rr .v{font-size:14px;font-weight:600;white-space:nowrap;
    font-variant-numeric:tabular-nums}
  .ready-rows .rr .v .u{font-weight:400;color:var(--muted);margin-left:6px}

  /* ---- net worth beside the portfolio, divided by a hairline ---- */
  #page-home .home-cards > #homeBrokerTile{
    border-left:1px solid var(--line);padding-left:40px;
  }

  /* ---- expenses today: the hero, and the day's expenses beside it ----
     ⚠️ The one block on the page that is not purely centred. The figure is
     the hero and the list is what it is made of, so the KPI centres over
     ITSELF and the list keeps its left edge. */
  #page-home #homeExpTile{
    display:grid;grid-template-columns:auto minmax(0,1fr);gap:34px;
    align-items:start;
  }
  #page-home #homeExpTile .exp-kpi{text-align:center}
  #page-home #homeExpTile .big{color:var(--red)}
  .exp-row{
    display:flex;align-items:baseline;justify-content:space-between;gap:20px;
    padding:12px 0;border-top:1px solid var(--line);
  }
  .exp-row:first-child{border-top:none}
  /* Set at the hero's weight, not at caption size — his instruction. The
     two halves of the block read as one statement. */
  .exp-row .n{font-size:17px;color:var(--text)}
  .exp-row .n .s{display:block;font-size:12px;color:var(--muted);margin-top:4px}
  .exp-row .v{font-size:17px;font-weight:650;white-space:nowrap;
    font-variant-numeric:tabular-nums}
  .exp-row.more .n{font-size:13px;color:var(--muted)}
  .exp-empty{font-size:14px;color:var(--muted);padding:12px 0}

  /* ---- the prayer block ---- */
  #page-home .prayer{display:block}
  /* It says what it is: a prayer name over a countdown. */
  #page-home .prayer .next .lbl{display:none}
  #page-home .prayer .next .name{
    font-size:clamp(40px,4.2vw,58px);font-weight:650;letter-spacing:-.04em;
    line-height:1;margin:0;
  }
  #page-home .prayer .next .count{font-size:14px;color:var(--muted);margin-top:12px}
  #page-home .prayer .times{justify-content:space-between;gap:5px;margin-top:26px;
    flex-wrap:nowrap}
  #page-home .prayer .p{flex:1;min-width:0;padding:9px 0 0;border-bottom:none;
    border-top:1px solid var(--line)}
  #page-home .prayer .p.on{border-top-color:var(--green)}
  #page-home .prayer .p .pn{font-size:10px;letter-spacing:.14em;color:var(--muted)}
  #page-home .prayer .p .pt{font-size:16px;margin-top:8px}
  #page-home .prayer .p.on .pn,#page-home .prayer .p.on .pt{color:var(--green)}
  /* "Your current location" said nothing the pill under it does not. */
  #page-home .prayer .loc{display:none}

  /* ---- today's priorities, as a flat list ---- */
  #page-home #homePriorities .item{padding:14px 0;border-top:1px solid var(--line);
    background:none;border-radius:0}
  #page-home #homePriorities .item:first-child{border-top:none}

  /* ==================================================================
     THE OTHER FIVE PAGES

     ⚠️ Scoped to five page ids by name, deliberately. A bare
     `.card{background:none}` would also reach Settings, Connections, the
     session gate and the recipe modal — none of which he has seen a design
     for, and all of which are frames doing a job. HANDOFF §123.4: a broad
     selector is a decision about everything it reaches.

     Meals is NOT in the list. It is built and hidden (§134); restyling a
     page nobody can open is work that cannot be checked.
     ================================================================== */

  #page-finances,#page-health,#page-places,#page-priorities,#page-canvas{
    /* One place to change what "a page section" is spaced by. */
    --sec:44px;
  }

  /* The selection above already says which page this is. */
  #page-finances .page-head,#page-health .page-head,#page-places .page-head,
  #page-priorities .page-head,#page-canvas .page-head{display:none}

  /* ---- the view switcher, on every page that has one ----
     ⚠️ `.hviews`, `#plSwitch`'s wrapper and `#cvSwitch`'s are switched OFF
     outside the phone query by `.hviews,.phone-only,.hring{display:none}`.
     Health's strip carries the class `.hviews`; showing it here is what
     gives desktop the same three sub-pages he approved on the phone. The
     handlers were never phone-only — they set `data-hv-active` at any
     width — so only the CSS had to change. */
  #page-finances .fin-switch,
  #page-health .hviews,#page-places .hviews,#page-canvas .hviews{
    display:flex;gap:2px;margin:30px 0 0;border-bottom:1px solid var(--line);
    background:none;border-radius:0;padding:0;flex-wrap:wrap;
  }
  #page-finances .fin-switch button,
  #page-health .hviews button,#page-places .hviews button,
  #page-canvas .hviews button{
    background:none;border:none;border-bottom:2px solid transparent;
    margin-bottom:-1px;padding:12px 22px;min-height:44px;border-radius:0;
    color:var(--muted);font:inherit;font-size:13px;font-weight:600;
    white-space:nowrap;cursor:pointer;
    /* ⚠️ The strip's buttons are `flex:1` in the base stylesheet, which
       spread five labels evenly across 1160px and made a tab strip look
       like a table header. They size to their words now. */
    flex:0 0 auto;
  }
  #page-finances .fin-switch button.active,
  #page-health .hviews button.active,#page-places .hviews button.active,
  #page-canvas .hviews button.active{
    color:var(--text);border-bottom-color:var(--green);background:none;
  }
  #page-finances .fin-switch button:hover,
  #page-health .hviews button:hover,#page-places .hviews button:hover,
  #page-canvas .hviews button:hover{color:var(--text)}

  /* Health, Places and Canvas hide their other sub-pages exactly as the
     phone does. The rules are repeated rather than moved out of the phone
     block, because a rule that applies at BOTH widths is a rule that can be
     broken for the phone by a desktop change — the one thing that must not
     happen. */
  #page-health[data-hv-active="home"]   [data-hv]:not([data-hv="home"]),
  #page-health[data-hv-active="vitals"] [data-hv]:not([data-hv="vitals"]),
  #page-health[data-hv-active="body"]   [data-hv]:not([data-hv="body"]){
    display:none;
  }
  #page-places[data-pl-active="coffee"] [data-pl="eats"],
  #page-places[data-pl-active="eats"] [data-pl="coffee"]{display:none}
  #page-canvas[data-cv-active="upcoming"] #assignmentPast,
  #page-canvas[data-cv-active="past"] #cvStats,
  #page-canvas[data-cv-active="past"] #assignmentList{display:none}

  /* ---- the frames come off ---- */
  #page-finances .fin-view .card,#page-finances .networth,
  #page-health .card,#page-places .card,#page-priorities .card,
  #page-canvas .card{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:var(--sec) 0 0;
  }
  /* ⚠️ A card inside a grid gets its space from the grid's `gap`; a margin
     on top of that is the gap counted twice, and the second column starts
     lower than the first. */
  #page-finances .grid > .card,#page-health .grid > .card,
  #page-places .grid > .card,#page-priorities .grid > .card,
  #page-canvas .grid > .card{margin-top:0}
  #page-finances .grid,#page-health .grid,#page-places .grid,
  #page-priorities .grid,#page-canvas .grid{gap:34px 40px;margin-top:var(--sec)}

  /* ---- titles left and white, as eyebrows ---- */
  #page-finances .fin-view .card h3,#page-health .card h3,
  #page-places .card h3,#page-priorities .card h3,#page-canvas .card h3,
  #page-finances .nw-label{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin-bottom:18px;
    display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  }
  /* ---- figures large and tabular ---- */
  #page-finances .fin-view .big,#page-health .card .big,
  #page-canvas .card .big,#page-priorities .card .big{
    font-size:clamp(28px,2.6vw,36px);font-weight:650;letter-spacing:-.04em;
    line-height:1;font-variant-numeric:tabular-nums;
  }
  #page-finances .nw-value{
    font-size:clamp(40px,4.2vw,58px);font-weight:650;letter-spacing:-.04em;
    line-height:1;font-variant-numeric:tabular-nums;
  }
  #page-finances .fin-view .sub,#page-health .card .sub{
    font-size:14px;color:var(--muted);margin-top:12px;
  }

  /* ---- label → value rows lose their fill and gain a hairline ----
     ⚠️ The VALUE stays right-aligned. A column of readings is only
     scannable when the digits line up. */
  #page-health .metric-row,#page-finances .metric-row,
  #page-priorities .metric-row,#page-canvas .metric-row{
    background:none;border-radius:0;padding:13px 0;
    border-top:1px solid var(--line);
  }
  #page-health .metric-row:first-child,#page-finances .metric-row:first-child,
  #page-priorities .metric-row:first-child,#page-canvas .metric-row:first-child{
    border-top:none;
  }

  /* ---- lists ---- */
  #page-priorities .list .item,#page-canvas .list .item,
  #page-places .list .item{
    background:none;border-radius:0;padding:14px 0;
    border-top:1px solid var(--line);
  }
  #page-priorities .list .item:first-child,#page-canvas .list .item:first-child,
  #page-places .list .item:first-child{border-top:none}

  /* ---- no emoji ----
     ⚠️ Hidden, never deleted. The markup is shared with the phone, which
     hides them the same way. The ★ ratings and the ↗ that says a tile opens
     Google Maps are DATA, not decoration, and are not `.emo`. */
  #page-finances .emo,#page-health .emo,#page-places .emo,
  #page-priorities .emo,#page-canvas .emo{display:none}

  /* ---- Places: the tiles become rows ----
     ⚠️ A four-across grid of picture cards is the one place the old desktop
     layout still looks like a different app. The thumbnail was a coloured
     box with an emoji in it — it carried no information at all — so it goes,
     and each place becomes a row divided by a hairline. */
  #page-places .tiles{display:block;gap:0}
  #page-places .tile{
    display:flex;align-items:baseline;gap:20px;
    background:none;border:none;border-radius:0;box-shadow:none;
    padding:16px 0;border-top:1px solid var(--line);
  }
  #page-places .tiles .tile:first-child{border-top:none}
  #page-places .tile:hover{background:none;transform:none}
  #page-places .tile .thumb{display:none}
  /* ⚠️ `flex-direction:row` again, and for the same reason it was needed on
     Home's readiness card: `.tile .body` is
     `display:flex;flex-direction:column` in the base stylesheet, so writing
     `display:flex` here changed NOTHING and every place printed as four
     stacked lines. Restating `display` does not restate `direction`. */
  #page-places .tile .body{flex:1;min-width:0;display:flex;flex-direction:row;
    align-items:baseline;gap:20px;flex-wrap:wrap}
  #page-places .tile h4{font-size:16px;font-weight:600;flex:0 0 auto;margin:0}
  /* `float:right` inside a row that is only as wide as its own text puts the
     arrow on the name's line anyway; the float just adds a gap. */
  #page-places .tile h4 .go{float:none;margin-left:8px}
  #page-places .tile .stars{font-size:13px;flex:0 0 auto}
  #page-places .tile .why{
    flex:1;min-width:140px;font-size:13px;color:var(--muted);
    background:none;border:none;border-left:none;padding:0;margin:0;
  }
  /* `margin-left:auto` rather than trusting `.why` to grow: it pins the
     distance and the price to the right edge, so the prices line up as a
     column down the page instead of landing wherever the sentence ended. */
  #page-places .tile .row{
    flex:0 0 auto;display:flex;align-items:baseline;gap:18px;
    margin:0 0 0 auto;padding-top:0;font-size:13px;color:var(--muted);
  }
  #page-places .tile .cost{font-weight:650;color:var(--green)}

  /* ---- Priorities: the ranked list comes first ----
     ⚠️ `order`, not a move in the markup. The document order is what the
     phone lays out and what a screen reader follows, and reordering the
     HTML would change both. The phone's own block does exactly this. */
  /* ⚠️ `.active` again — the seventh time. `#page-priorities{display:flex}`
     outranks `.page{display:none}`, so Priorities rendered underneath
     Canvas. **A `display` on a page id must always carry `.active`.** */
  #page-priorities.active{display:flex;flex-direction:column}
  #page-priorities .flow-sec{order:-1}
  #page-priorities .page-head{order:-3}
  #page-priorities .banner{order:-2}

  /* ---- Canvas and Priorities: the sections lose their frames too ----
     `.flow-sec` and `.flow` are these two pages' own containers; the `.card`
     rule above does not reach them. */
  #page-priorities .flow-sec,#page-canvas .flow-sec{
    background:none;border:none;border-radius:0;box-shadow:none;padding:0;
    margin:var(--sec) 0 0;
  }
  #page-priorities .flow-sec h3,#page-canvas .flow-sec h3{
    font-size:10px;font-weight:700;letter-spacing:.26em;text-transform:uppercase;
    color:var(--text);margin-bottom:18px;
    display:flex;justify-content:space-between;align-items:baseline;gap:16px;
  }

  /* ==================================================================
     WHAT HE ASKED TAKEN OFF, 2026-09-03

     Seven screenshots, all of the same kind of thing: a line under a figure
     restating what the figure already said, or a column of numbers beside a
     chart that has grid lines. ⚠️ **None of this changes any maths** — the
     same rule as HANDOFF §19. The cards simply stop explaining themselves.
     ================================================================== */

  /* "3 accounts" / "4 accounts" / "2 cards" under the three Overview
     figures, and "151 graded · 0 practice or optional" under Canvas's. */
  #page-finances #fnCashSub,#page-finances #fnBrokerageSub,
  #page-finances #fnOwedSub,#page-canvas #cvUpcomingSub{display:none}

  /* "−77% vs last month" under each of this month's three totals. */
  #page-finances .kpi-d{display:none}

  /* "$0 available" under every bank account, and
     "$13 of $10,000 · 0% used" under every card.
     ⚠️ `.budg-row .sub` only ever appears in an ACCOUNT row — the budget
     category rows use `.bar`, not `.sub`, so no limit is being hidden. */
  #page-finances .budg-row .sub{display:none}

  /* The red "owed" bar under the net-worth rail. The bar shows what he HAS;
     the figure stays in the key beside Cash and Investments. The phone
     already does exactly this — see the rule in the 820px block. */
  #page-finances .nw-bar .owed-track{display:none}

  /* ⚠️ Overview's whole ACCOUNT LISTING goes — "Where your money sits",
     "Investments" and "What you owe" (2026-09-03, second pass). Nothing is
     lost: the Bank tab lists every bank account, Brokerage lists every
     brokerage account, and Spending opens with the cards. Overview is the
     totals and the two months now, which is what the phone has shown since
     §122 — the same rule for `#fnAccountLists` is in the 820px block.

     This supersedes hiding the investments rail and key on their own: they
     live inside `#fnBrokerageRow`, so the row taking them with it is the
     shorter true statement. */
  #page-finances #fnAccountLists,
  #page-finances #fnBrokerageRow{display:none}

  /* "8 ITEMS" / "70 ITEMS" beside this month and last. The phone dropped
     these in §122; the count of transactions is not what either card is
     for. */
  #page-finances .kpi-card h3 .pill{display:none}

  /* The "Owed" entry in the net-worth key. The red bar went earlier today;
     the key is what remains of it, and the figure is still its own headline
     under "Owed on cards". Cash and Investments stay — they are what the
     rail is made of. */
  #page-finances .nw-key-item.key-owed{display:none}

  /* The live / sample badges were listed here page by page while this was
     a desktop-only change. He asked for them off the phone as well, so the
     one rule that covers both sides of the breakpoint lives at the top of
     the file beside `.src`'s own styles — a rule that applies at every width
     does not belong inside a width query. */
}

/* ---------- Big purchases: the split KPI, and set-aside transactions ------
   Added 2026-09-07 on his instruction. Two rules only, both outside any
   width query on purpose: the swipe and the styling behave identically at
   every width, and a rule that applies on both sides of 820px does not
   belong inside one (the same reasoning as the `.src` note above). */

/* ⚠️ **Two figures in the space one used to have.** The card does not grow;
   the figures shrink to share it. `.kpi-stack .big` is two classes, so it
   beats both the base `.big{font-size:30px}` and the phone override
   `.big{font-size:23px}` wherever they sit in the file — specificity, not
   order, which is what §122.3 and §125.3 were each about. */
.kpi-stack{display:flex;flex-direction:column;justify-content:center;gap:0}
.kpi-stack .kpi-part + .kpi-part{margin-top:10px;padding-top:10px;border-top:1px solid var(--line)}

/* ⚠️ **`#page-finances .fin-view` is why this selector is so long.** The
   figures on this page are sized by `#page-finances .fin-view .big` - one id
   and two classes - so a plain `.kpi-stack .big` loses silently and both
   figures stay full size. Measured: 36px before this rule, 36px after the
   short version, which is CLAUDE.md #25 happening for the eighth time in
   this project. The label margin has to come down too, or two eyebrows at
   18px each make the card taller than the two beside it. */
#page-finances .fin-view .kpi-stack .big{
  font-size:clamp(17px,1.5vw,21px);line-height:1.1;
}
#page-finances .fin-view .kpi-stack h3{margin-bottom:6px}
/* ⚠️ **Side by side on the phone, stacked on desktop** - his instruction,
   2026-09-07, after seeing the stacked version take 138px against its
   neighbours' 89px. The phone draws these stats one per row at 64px, so two
   figures stacked inside one row either dwarf the card or shrink to 16px and
   read as broken. Two columns is the same answer Home already gives for
   MTD Spend and Portfolio (§125.2), and it puts the height back.

   ⚠️ The divider turns with the axis: the base rule's `border-top` has to be
   unset here, not just added to, or the row carries both a rule above the
   second figure and one beside it. */
@media(max-width:820px){
  #page-finances .fin-view .kpi-stack{flex-direction:row;align-items:stretch}
  #page-finances .fin-view .kpi-stack .kpi-part{flex:1 1 0;min-width:0}
  #page-finances .fin-view .kpi-stack .kpi-part + .kpi-part{
    margin-top:0;padding-top:0;border-top:none;
    margin-left:14px;padding-left:14px;border-left:1px solid var(--line);
  }
  #page-finances .fin-view .kpi-stack .big{font-size:clamp(20px,7vw,30px)}
  #page-finances .fin-view .kpi-stack h3{margin-bottom:6px}
}

/* ⚠️ **A third sanctioned use of `--faint`, and it is deliberate.**
   `Markdowns for AI/CLAUDE.md` says --faint exists for exactly two things,
   input placeholders and out-of-month calendar days, and warns against
   reaching for it to make a label "secondary". This is not that: he asked
   for excluded rows to read as light grey and italic, and "set aside" is a
   state of the row rather than a hierarchy between rows. Recorded so the
   next reader sees a decision and not a slip. */
.txn-row{touch-action:pan-y}
.txn-row.txn-excluded td{color:var(--faint);font-style:italic}
/* The amount keeps its own colour rule elsewhere (red for money out), so it
   has to be overridden explicitly or an excluded row stays half-red. */
.txn-row.txn-excluded td.num-col{color:var(--faint)}
.txn-row.txn-swiping{transition:none}
.txn-row{transition:transform .18s ease}

/* ---- the desktop control that makes the drag discoverable ----------------
   Added 2026-09-07. He asked "how does one exclude it on the computer?",
   which was the answer: the right-drag works with a mouse and nothing on
   screen says so. A gesture nobody can find is not a feature.

   ⚠️ **Desktop only, and hidden rather than absent on the phone.** The
   column is in the shared markup (`.emo` is hidden the same way and for the
   same reason), so the phone keeps the swipe and never draws this. */
.txn-act{display:none}

@media(min-width:821px){
  #page-finances #fin-credit .txn-act{
    display:table-cell;width:1%;white-space:nowrap;text-align:right;
    padding-left:12px;
  }
  #page-finances #fin-credit .txn-ex-btn{
    background:none;border:0;padding:2px 0;cursor:pointer;
    font:inherit;font-size:11px;letter-spacing:.08em;text-transform:uppercase;
    color:var(--faint);text-align:right;
    /* ⚠️ **Fixed width, because the label changes and the column is right
       aligned.** "Set aside" is wider than "Include", so without this the
       control slides sideways the moment you press it and a second click
       lands on nothing. Found by clicking it twice, not by reading it. */
    min-width:76px;
    /* ⚠️ `visibility`, not `display`. The cell has to keep its width whether
       the control shows or not, or every row's Amount column shifts sideways
       as the mouse moves down the table. */
    visibility:hidden;
  }
  /* Revealed on hover, and on keyboard focus - the control is a real button
     and tabbing to something invisible is a dead end. */
  #page-finances #fin-credit tr.txn-row:hover .txn-ex-btn,
  #page-finances #fin-credit .txn-ex-btn:focus-visible{visibility:visible}
  #page-finances #fin-credit .txn-ex-btn:hover{color:var(--text)}
  /* An excluded row says so without needing to be hovered, because the row
     being grey is the only other clue and "Include" is what undoes it. */
  #page-finances #fin-credit tr.txn-excluded .txn-ex-btn{visibility:visible}
}
