/* ---------------------------------------------------------------
   Kisan Bhandar — Hisaab
   Mobile-first PWA. Dark by default, light via prefers-color-scheme.
   --------------------------------------------------------------- */

:root {
  --bg:        #0b1120;
  --bg-2:      #111a2e;
  --card:      #16213a;
  --card-2:    #1c2a47;
  --line:      #24344f;
  --text:      #e8eefc;
  --text-2:    #9fb0cd;
  --text-3:    #6d809e;
  --brand:     #14b8a6;
  --brand-dk:  #0f766e;
  --good:      #34d399;
  --warn:      #fbbf24;
  --bad:       #f87171;
  --info:      #60a5fa;
  --purple:    #a78bfa;
  --radius:    14px;
  --radius-lg: 20px;
  --safe-b:    env(safe-area-inset-bottom, 0px);
  --nav-h:     62px;
  --top-h:     56px;
}

@media (prefers-color-scheme: light) {
  :root {
    --bg:     #f4f6fb;
    --bg-2:   #ffffff;
    --card:   #ffffff;
    --card-2: #eef2f9;
    --line:   #dde4ef;
    --text:   #101a2c;
    --text-2: #4d5f7c;
    --text-3: #7c8ba3;
    --brand:  #0f766e;
    --good:   #047857;
    --warn:   #b45309;
    --bad:    #b91c1c;
    --info:   #1d4ed8;
    --purple: #6d28d9;
  }
}

html[data-theme="dark"]  { color-scheme: dark; }
html[data-theme="light"] { color-scheme: light; }

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* The browser's own [hidden] rule is display:none, but any class here that sets
   display (.topbar is flex, .nav is grid) outranks it — so hiding those elements
   from JS would silently do nothing. This puts [hidden] back in charge. */
[hidden] { display: none !important; }

html, body {
  margin: 0; padding: 0;
  background: var(--bg);
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Noto Sans Devanagari", sans-serif;
  font-size: 16px;
  line-height: 1.45;
  overscroll-behavior-y: none;
}

/* Room for the bottom bar — but ONLY when the bar is actually there.
   This was unconditional, so every screen that hides the nav (welcome, setup)
   carried ~62px of dead space below the fold and scrolled with nothing in it.
   A first screen that scrolls when it is nearly empty reads as unfinished. */
body { padding-bottom: 0; }
body:has(#nav:not([hidden])) { padding-bottom: calc(var(--nav-h) + var(--safe-b)); }

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
a { color: var(--brand); }

/* ---------- Boot splash ---------- */
.boot {
  position: fixed; inset: 0; z-index: 999;
  display: grid; place-content: center; justify-items: center; gap: 14px;
  background: var(--bg);
}
.boot-logo {
  width: 72px; height: 72px; border-radius: 22px;
  background: linear-gradient(135deg, #14b8a6, #0f766e);
  color: #fff; display: grid; place-items: center;
  font-size: 34px; font-weight: 700;
}
.boot-text { color: var(--text-3); font-size: 14px; }
.boot.err .boot-text { color: var(--bad); max-width: 300px; text-align: center; }

/* ---------- Top bar ---------- */
/* Same 720px centred column as `.view`. Left full-width, the shop name sat
   hard against the window edge while the content floated in the middle — and
   the gap grew with the browser. */
.topbar {
  position: sticky; top: 0; z-index: 40;
  height: var(--top-h);
  max-width: 720px; margin: 0 auto;
  display: flex; align-items: center; gap: 6px;
  padding: 0 8px;
  background: color-mix(in srgb, var(--bg) 88%, transparent);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--line);
}
.tb-title {
  flex: 1; min-width: 0; font-size: 18px; font-weight: 650; padding-left: 6px;
  display: flex; align-items: center; gap: 9px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tb-mark {
  flex: 0 0 28px; width: 28px; height: 28px; border-radius: 9px;
  background: linear-gradient(135deg, #14b8a6, #0f766e);
  color: #fff; font-size: 14px; font-weight: 700;
  display: grid; place-items: center;
}
.tb-name {
  font-size: 17px; font-weight: 680; letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Who is signed in. Deliberately quiet — it is there to be checked, not read
   every time, and it must never compete with the shop name. */
.tb-user {
  margin-left: auto; flex: 0 1 auto;
  font-size: 12.5px; font-weight: 600; color: var(--text-3);
  padding: 3px 9px; border-radius: 999px;
  background: var(--card-2); border: 1px solid var(--line);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  max-width: 40%;
}
.tb-back {
  width: 38px; height: 38px; border-radius: 10px;
  font-size: 26px; line-height: 1; color: var(--text-2);
}
.tb-back:active { background: var(--card); }
.tb-action {
  padding: 7px 13px; border-radius: 10px;
  background: var(--card); color: var(--brand);
  font-size: 14px; font-weight: 600;
}

/* ---------- View ---------- */
.view { padding: 12px 12px 20px; max-width: 720px; margin: 0 auto; }
/* The welcome tour manages its own full-height layout. */
.view:has(.wel) { padding: 0; max-width: none; }
.stack { display: flex; flex-direction: column; gap: 12px; }

/* A screen with little on it should fill the window rather than leave a strip
   of background under it. Long screens are unaffected — this is a minimum,
   not a height. The subtractions account for whichever chrome is on screen. */
.view > .stack { min-height: calc(100dvh - 32px); }
body:has(#topbar:not([hidden])) .view > .stack { min-height: calc(100dvh - var(--top-h) - 32px); }
body:has(#nav:not([hidden])) .view > .stack {
  min-height: calc(100dvh - var(--top-h) - var(--nav-h) - var(--safe-b) - 32px);
}
body.has-devbar .view > .stack { min-height: calc(100dvh - var(--top-h) - 38px - 32px); }
body.has-devbar:has(#nav:not([hidden])) .view > .stack {
  min-height: calc(100dvh - var(--top-h) - var(--nav-h) - var(--safe-b) - 38px - 32px);
}

/* The trailing spacer exists so the last card clears the FAB. With no FAB it
   is just dead height at the bottom of a short page. */
body:has(#fab[hidden]) .spacer { display: none; }

/* ---------- Bottom nav ---------- */
/* Centred on the same column as the content, and with exactly as many columns
   as there are buttons. It was `repeat(5, 1fr)` while mini mode has three, so
   the three sat in the left 60% with a hole beside them. `grid-auto-columns`
   adapts to whichever nav is rendered instead of hard-coding the longer one. */
.nav {
  position: fixed; left: 50%; transform: translateX(-50%); bottom: 0; z-index: 45;
  width: 720px; max-width: 100%;
  height: calc(var(--nav-h) + var(--safe-b));
  padding-bottom: var(--safe-b);
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: color-mix(in srgb, var(--bg-2) 94%, transparent);
  backdrop-filter: blur(12px);
  border-top: 1px solid var(--line);
}
.nav-btn {
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 2px;
  color: var(--text-3); font-size: 11px;
}
.nav-btn .nav-ico { font-size: 19px; line-height: 1; filter: grayscale(1) opacity(.7); }
.nav-btn.on { color: var(--brand); }
.nav-btn.on .nav-ico { filter: none; }

/* ---------- FAB ---------- */
.fab {
  position: fixed; right: 16px; z-index: 46;
  bottom: calc(var(--nav-h) + var(--safe-b) + 14px);
  width: 58px; height: 58px; border-radius: 50%;
  background: linear-gradient(135deg, #14b8a6, #0f766e);
  color: #fff; font-size: 32px; font-weight: 300; line-height: 1;
  box-shadow: 0 8px 22px rgba(15,118,110,.45);
}
.fab:active { transform: scale(.94); }

/* ---------- Cards ---------- */
.card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 14px;
}
.card.tight { padding: 10px 12px; }
.card.flush { padding: 0; overflow: hidden; }
.card-h {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  margin-bottom: 10px;
}
.card-h h3 { margin: 0; font-size: 14px; font-weight: 650; color: var(--text-2); letter-spacing: .02em; }
.card-h .link { font-size: 13px; color: var(--brand); font-weight: 600; }

.sec-title {
  font-size: 12px; font-weight: 700; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .07em;
  margin: 6px 2px -2px;
}

/* ---------- Hero (today) ---------- */
.hero {
  background: linear-gradient(150deg, #0f766e 0%, #115e59 55%, #134e4a 100%);
  border: none; color: #fff; border-radius: var(--radius-lg); padding: 16px;
}
.hero .h-lbl { font-size: 12px; opacity: .8; letter-spacing: .05em; text-transform: uppercase; }
.hero .h-amt { font-size: 34px; font-weight: 700; letter-spacing: -.02em; margin: 2px 0 10px; }
.hero-split { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.hero-split > div {
  background: rgba(255,255,255,.13); border-radius: 10px; padding: 8px 9px;
}
.hero-split .s-l { font-size: 11px; opacity: .82; }
.hero-split .s-v { font-size: 15px; font-weight: 650; }

/* ---------- Box tiles ---------- */
.boxes { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.box {
  background: var(--card); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 11px 10px; text-align: left;
}
.box .b-ico { font-size: 16px; }
.box .b-l { font-size: 11px; color: var(--text-3); margin-top: 3px; }
.box .b-v { font-size: 17px; font-weight: 700; margin-top: 1px; letter-spacing: -.01em; }
.box.locked { border-color: color-mix(in srgb, var(--purple) 45%, var(--line)); }

/* ---------- Welcome carousel ---------- */
/* Fits the viewport instead of scrolling. A first screen that scrolls when it
   has almost nothing on it reads as unfinished — and on a phone the buttons
   end up below the fold, which is the one thing that must not happen here. */
/* Fills the window so a sparse card does not leave a strip of background, but
   a MINIMUM rather than a fixed height — fixing it clipped the taller cards
   instead of merely preventing an empty scroll. */
/* ONE screen, never a scroll — and `svh`, not `dvh`, is the whole trick.
   `dvh` is the viewport as it is RIGHT NOW, which grows when the phone's
   address bar slides away. Sizing to it means the layout fits only while the
   bar is hidden and overflows the moment it returns — a scrollbar that appears
   and disappears as you move your thumb. `svh` is the SMALLEST the viewport
   ever gets, so a layout that fits it fits always.

   `height` and not `min-height`: min-height permits growth, and growth here is
   the bug. Nothing is clipped to achieve it — every size below scales with
   svh, so a short screen gets smaller type rather than a hidden button. */
.wel {
  height: calc(100svh - var(--safe-b)); overflow: hidden;
  display: flex; flex-direction: column;
  max-width: 430px; margin: 0 auto; padding: 0 20px 14px;
}
body.has-devbar .wel { height: calc(100svh - 38px - var(--safe-b)); }
.wel-top { display: flex; align-items: center; padding: clamp(6px, 1.4svh, 12px) 0 4px; }
.wel-top .seg { width: auto; margin-left: auto; padding: 2px; }
.wel-top .seg button { padding: 6px 12px; font-size: 12.5px; }
.wel-skip { font-size: 13px; color: var(--text-3); padding: 6px 2px; }

/* Takes whatever height is left and centres the card in it, so a short first
   card and a taller third one both sit comfortably. */
.wel-stage {
  flex: 1; min-height: 0; overflow: hidden; display: flex; flex-direction: column;
  justify-content: center; padding: clamp(4px, 1svh, 8px) 0;
}
.wel-slide { animation: welIn .32s cubic-bezier(.2,.8,.3,1); }

/* The footer keeps the same height whether it holds one button or three, so
   the dots and the card above do not jump as you move between them. */
.wel-foot { min-height: clamp(92px, 16svh, 132px); justify-content: flex-end; }
@keyframes welIn { from { opacity: 0; transform: translateX(14px); } to { opacity: 1; transform: none; } }

/* The question still outweighs the name — but the name is the same size on
   every screen that shows it as a subject, because a brand that shrinks
   between two consecutive screens reads as two different apps. */
.wel-lockup { display: flex; align-items: center; justify-content: center; gap: 9px; }
.wel-mark {
  width: 34px; height: 34px; border-radius: 11px;
  background: linear-gradient(135deg, #14b8a6, #0f766e);
  display: grid; place-items: center; color: #fff; font-size: 17px; font-weight: 700;
}
.wel-brand {
  font-size: 17px; font-weight: 700; letter-spacing: .01em; color: var(--text-2);
}

/* Full strength: the language screen and card one, the two places the brand is
   the subject rather than chrome. */
.wel-lockup.big { gap: 13px; }
.wel-lockup.big .wel-mark {
  width: clamp(46px, 7svh, 56px); height: clamp(46px, 7svh, 56px);
  border-radius: 17px; font-size: clamp(23px, 3.6svh, 28px);
}
.wel-lockup.big .wel-brand {
  font-size: clamp(25px, 3.9svh, 31px); color: var(--text); letter-spacing: -.015em;
}

/* Room to breathe under the wordmark. At 18px it sat close enough to the
   question to read as one block, and the name lost its own line. */
.lang-mark { margin-bottom: clamp(26px, 6svh, 44px); }

/* Sits above centre. This screen has no dots and no footer beneath it, so
   dead-centre put the wordmark low — the page looked bottom-heavy with a wide
   empty band above. Padding at the foot, rather than anchoring to the top:
   the block moves up by half of it, which is a nudge and not a jump. */
.lang-stage { padding-bottom: clamp(44px, 13svh, 104px); }

/* One question in two languages, both the same size — nobody on this screen
   has told us yet which one they read, so neither can be the caption. The
   English is a shade quieter only so the pair reads as one label rather than
   two competing headings. */
.lang-ask { text-align: center; }
.lang-line {
  font-size: clamp(16.5px, 2.4svh, 19px); font-weight: 650;
  letter-spacing: -.01em; line-height: 1.35;
}
.lang-line.alt { color: var(--text-2); margin-top: 3px; }
/* Two ceilings, not one. `10.5vw` keeps it from running off a narrow screen,
   `5.4svh` keeps it from eating a short one — `min()` takes whichever bites
   first, and the 26px floor stops it shrinking into illegibility. */
.wel-slogan {
  text-align: center; font-weight: 800; letter-spacing: -.025em;
  font-size: clamp(26px, min(10.5vw, 5.4svh), 44px); line-height: 1.12;
  margin-top: clamp(12px, 3.2svh, 26px); text-wrap: balance;
  background: linear-gradient(135deg, #2dd4bf, #0f766e);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
/* Devanagari sits lower and needs a touch more room above the line. */
html[lang="hi"] .wel-slogan { line-height: 1.3; }
.wel-sub {
  text-align: center; font-size: clamp(14px, 2.2svh, 17px); color: var(--text);
  margin-top: clamp(11px, 2.7svh, 22px);
  line-height: 1.45; font-weight: 500; max-width: 19em; margin-left: auto; margin-right: auto;
}
.wel-rule { height: 3px; width: 46px; border-radius: 99px; background: var(--brand); margin: clamp(12px, 3svh, 24px) auto 0; opacity: .5; }
.wel-h { font-size: clamp(18px, 2.9svh, 23px); font-weight: 700; letter-spacing: -.02em; text-align: center; }
.wel-p { font-size: clamp(12.5px, 1.9svh, 14.5px); color: var(--text-2); text-align: center; margin-top: clamp(5px, 1svh, 8px); line-height: 1.5; }

/* four khatas, 2x2 */
.wel-grid {
  display: grid; grid-template-columns: 1fr 1fr;
  gap: clamp(7px, 1.3svh, 10px); margin-top: clamp(10px, 2.5svh, 20px);
}
.wel-tile {
  background: var(--card); border: 1px solid var(--line); border-radius: 15px;
  padding: clamp(10px, 1.9svh, 15px) 13px; text-align: left;
}
.wel-tile .ti { font-size: clamp(19px, 2.9svh, 23px); }
.wel-tile .tn { font-size: clamp(13px, 1.8svh, 14px); font-weight: 650; margin-top: clamp(4px, .9svh, 7px); }
.wel-tile .tw { font-size: clamp(10.5px, 1.5svh, 11.5px); color: var(--text-3); margin-top: 3px; line-height: 1.35; }

/* A small honest preview of the real daily screen. It is the tallest thing in
   the tour, so it is the first to overflow — every measurement inside it
   scales with svh, the mock included, or card 3 alone would need a scrollbar. */
.wel-phone {
  margin: clamp(10px, 2.2svh, 18px) auto 0; width: clamp(196px, 44svh, 232px);
  border-radius: 22px; padding: clamp(5px, 1svh, 8px);
  background: var(--bg-2); border: 1px solid var(--line);
  box-shadow: 0 16px 40px rgba(0,0,0,.22);
}
.wel-screen { background: var(--bg); border-radius: 16px; padding: clamp(7px, 1.4svh, 11px) 10px; }
.wel-row { display: flex; justify-content: space-between; font-size: clamp(10.5px, 1.6svh, 12px); padding: clamp(2px, .55svh, 4px) 0; }
.wel-row .k { color: var(--text-3); }
.wel-row .v { font-weight: 650; font-variant-numeric: tabular-nums; }
.wel-card {
  background: var(--card); border: 1px solid var(--line); border-radius: 10px;
  padding: clamp(6px, 1.1svh, 8px) 10px; margin-bottom: clamp(5px, .9svh, 7px);
}
.wel-cap { font-size: 9.5px; font-weight: 700; color: var(--text-3); letter-spacing: .06em; text-transform: uppercase; margin-bottom: clamp(2px, .5svh, 4px); }
.wel-tot { border-top: 1px solid var(--line); margin-top: 5px; padding-top: 6px; font-size: clamp(11.5px, 1.8svh, 13.5px); }

.wel-dots { display: flex; gap: 7px; justify-content: center; padding: clamp(8px, 2svh, 16px) 0 clamp(8px, 1.7svh, 14px); }
.wel-dots i {
  width: 7px; height: 7px; border-radius: 99px; background: var(--line);
  transition: width .2s, background .2s;
}
.wel-dots i.on { width: 22px; background: var(--brand); }

.wel-foot { display: flex; flex-direction: column; gap: 9px; }
.wel-note { text-align: center; font-size: 12px; color: var(--text-3); margin-top: 2px; }

/* ---------- A day's entries, folded ----------
   Eleven rows inline pushed the totals and the close button below two screens
   of scroll. Collapsed shows what you glance at — how many, how much; opened
   shows the rows and their ✏️, which is what you occasionally need. */
.day-fold { margin-bottom: 10px; }
.day-fold > summary {
  cursor: pointer; list-style: none;
  display: flex; align-items: center; gap: 10px;
  padding: 9px 11px; border-radius: 10px;
  background: var(--card-2); border: 1px solid var(--line);
  font-size: 13.5px;
}
.day-fold > summary::-webkit-details-marker { display: none; }
.day-fold > summary::after { content: '▾'; color: var(--text-3); font-size: 12px; }
.day-fold[open] > summary::after { content: '▴'; }
.day-fold[open] > summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; }
.df-n { flex: 1; color: var(--text-2); }
.df-v { font-weight: 650; font-variant-numeric: tabular-nums; }
.df-rows {
  border: 1px solid var(--line); border-top: none;
  border-radius: 0 0 10px 10px; padding: 2px 11px;
}

/* ---------- Searchable person picker ----------
   A <select> of forty customers cannot be searched and scrolls past the fold,
   and forty customers is week three of a shop. Type two letters of a name or
   four digits of a number instead. Under a handful of people the list shows
   whole, so a new shop never has to search to find its only customer. */
.picker { position: relative; }
.picker-list {
  margin-top: 6px; max-height: 232px; overflow-y: auto;
  border-radius: 11px; border: 1px solid var(--line);
  background: var(--card-2);
}
.picker-list:empty { display: none; border: none; }
.picker-row {
  display: block; width: 100%; text-align: left;
  padding: 9px 12px; border-bottom: 1px solid var(--line);
  background: none; color: var(--text);
}
.picker-row:last-child { border-bottom: none; }
.picker-row:active { background: var(--card); }
.picker-row.add { color: var(--brand); font-weight: 620; }
.pk-n { display: block; font-size: 14.5px; }
.pk-s { display: block; font-size: 11.5px; color: var(--text-3); margin-top: 1px; }

/* ---------- ＋ New customer / mahajan ----------
   Three fields that appear together, boxed so they read as "you are creating a
   person" rather than as more of the entry above them. */
.new-person {
  margin-top: 10px; padding: 11px; border-radius: 11px;
  background: var(--card-2); border: 1px solid var(--line);
  display: flex; flex-direction: column; gap: 8px;
}
.new-person .hint { margin: 0; }

/* ---------- Sign up / log in ---------- */
/* A fixed +91 beside the field, so nobody types the country code themselves
   and fails validation for it. */
.phone-in { display: flex; align-items: stretch; gap: 8px; }
.phone-in > span {
  display: grid; place-items: center; padding: 0 11px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--card-2); color: var(--text-2);
  font-size: 15px; font-variant-numeric: tabular-nums;
}
.phone-in .input { flex: 1; min-width: 0; }

/* A percentage, with the sign attached. The field held a bare number at 26px:
   the loudest thing on the step, and no unit to say what it meant.

   Full row, but SHORT. It started at 26px type in a standard 12px-padded box,
   which made it the tallest and loudest control on the step — for an answer
   that is almost always the default. The width stays full so it lines up with
   the fields above and below; only the height comes down. */
.pct-in { display: flex; align-items: stretch; gap: 7px; }
.pct-in .input {
  flex: 1; min-width: 0;
  padding-top: 2px; padding-bottom: 2px; font-size: 15px; line-height: 1.2;
}
/* `align-items: stretch` on the row keeps the % box exactly as tall as the
   input, so the two never drift apart when the padding changes. */
.pct-in > span {
  flex: 0 0 auto; display: grid; place-items: center; padding: 0 13px;
  border: 1px solid var(--line); border-radius: 10px;
  background: var(--card-2); color: var(--text-2); font-size: 14px;
}

/* Collapsed unless there is a code to show — most people were not invited,
   and a join-code box on every signup is a question they cannot answer. */
.invite-box {
  border: 1px solid var(--line); border-radius: 11px;
  padding: 10px 12px; margin-top: 12px; background: var(--card-2);
}
.invite-box > summary {
  cursor: pointer; font-size: 13.5px; font-weight: 600; color: var(--text-2);
  list-style: none;
}
.invite-box > summary::-webkit-details-marker { display: none; }
.invite-box > summary::after { content: ' ▾'; color: var(--text-3); }
.invite-box[open] > summary::after { content: ' ▴'; }

/* ---------- How to run this (screens/rules.js) ----------
   Generous line height and a gap between rules: this is the one page in the
   app meant to be READ rather than scanned, and cramped rules do not get read. */
.rule-list { margin: 4px 0 0; padding-left: 18px; }
.rule-list li {
  font-size: 13.5px; line-height: 1.75; color: var(--text-2);
  margin-bottom: 11px;
}
.rule-list li:last-child { margin-bottom: 0; }

/* ---------- Dev bar (?dev=1 only) ---------- */
#devbar {
  position: fixed; top: 0; left: 0; right: 0; z-index: 200;
  display: flex; align-items: center; gap: 6px;
  padding: 5px 8px; height: 38px;
  background: #1e1b4b; color: #c7d2fe;
  border-bottom: 1px solid #4338ca;
  font-size: 12px; overflow-x: auto; white-space: nowrap;
}
#devbar .dev-tag {
  font-weight: 800; letter-spacing: .08em; font-size: 10px;
  background: #4338ca; color: #fff; padding: 3px 7px; border-radius: 5px;
}
#devbar button, #devbar select {
  background: #312e81; color: #e0e7ff; border: 1px solid #4338ca;
  border-radius: 7px; padding: 5px 9px; font-size: 12px; cursor: pointer;
  flex: 0 0 auto;
}
#devbar button.on { background: #6366f1; color: #fff; border-color: #818cf8; }
#devbar .dev-jump { max-width: 120px; }
#devbar .dev-lbl { margin-left: 5px; }
/* The version actually running. A stale page has been mistaken for a broken
   fix more than once, and no finding means anything without it. */
#devbar .dev-ver {
  flex: 0 0 auto; font-size: 11px; font-weight: 700; letter-spacing: .02em;
  color: #a5b4fc; padding: 3px 6px; border-radius: 5px; background: #1e1b4b;
  border: 1px solid #4338ca;
}
/* Running code and cached code disagree — the page is out of date and every
   result taken from it is worthless. */
#devbar .dev-ver.stale { color: #fff; background: #b45309; border-color: #f59e0b; }

/* The bar is one fixed 38px row — four other rules hard-code that height, so
   it must not wrap. It scrolls sideways instead, but the scrollbar is
   invisible on Windows, so buttons that fell off the end simply looked
   missing. Drop the words and keep the icons before that can happen: seven
   controls fit a narrow window, and every one stays reachable. */
@media (max-width: 620px) {
  #devbar { gap: 4px; padding: 5px 6px; }
  #devbar .dev-lbl { display: none; }
  #devbar .dev-tag { display: none; }
  #devbar .dev-jump { max-width: 92px; }
}

/* Block labels — W1, S3 — written by util.js `dbg()` and present only under
   ?dev=1. They sit OUTSIDE the flow (absolute, pointer-events off) so adding
   one cannot change the layout being judged; a label that shifted the box
   would be measuring itself. `:has()` gives the parent its positioning
   context, so no wrapper element is needed at any call site. */
:has(> .dbg-id) { position: relative; }
.dbg-id {
  position: absolute; top: 0; left: 0; transform: translate(-3px, -9px);
  font: 700 9px/1 ui-monospace, SFMono-Regular, Menlo, monospace;
  letter-spacing: .05em; background: #7c3aed; color: #fff;
  padding: 3px 5px; border-radius: 5px; z-index: 60; pointer-events: none;
  box-shadow: 0 1px 4px rgba(0,0,0,.4);
}

body.has-devbar { padding-top: 38px; }
body.has-devbar .topbar { top: 38px; }

/* Phone-sized frame, so a laptop shows what a phone would */
body.dev-frame #view,
body.dev-frame .sheet { max-width: 390px; margin-left: auto; margin-right: auto; }
/* The bar is sticky and in normal flow, so it centres with auto margins. It had
   `left:50%; transform:translateX(-50%)` copied from the fixed nav, where the
   transform shifted it half its width off to the left. */
body.dev-frame .topbar {
  max-width: 390px;
  border-left: 1px solid var(--line); border-right: 1px solid var(--line);
}
/* Fixed, so width + translate. `right: 0` used to survive from the base rule,
   which made the computed width half the VIEWPORT rather than 390px — so the
   nav drifted out of line with the content as the window was resized. */
body.dev-frame .nav {
  width: 390px; right: auto;
  border-left: 1px solid var(--line); border-right: 1px solid var(--line);
}
body.dev-frame .fab { right: calc(50% - 195px + 16px); }

/* ---------- बचत — the outcome, not a register ----------
   Set apart from the four khata cards on purpose. Sale & purchase, udhaari,
   expense and stock are the work; this is what the work produces, and it is
   what the app is named after. As card five in the same list it read like one
   more chore rather than the reason for the other four. */
.bachat {
  display: block; width: 100%; text-align: center;
  padding: 20px 16px 17px;
  background: linear-gradient(160deg, #0f766e 0%, #115e59 55%, #134e4a 100%);
  border: none; color: #fff;
}
.bachat:active { filter: brightness(1.08); }
.bachat-q {
  font-size: 14.5px; font-weight: 600; opacity: .82; letter-spacing: .01em;
}
.bachat-amt {
  font-size: 38px; font-weight: 760; letter-spacing: -.03em;
  line-height: 1.15; margin: 4px 0 2px;
  font-variant-numeric: tabular-nums;
}
.bachat-sub { font-size: 12.5px; opacity: .78; }
.bachat-foot {
  font-size: 11.5px; opacity: .85; margin-top: 9px;
  padding-top: 9px; border-top: 1px solid rgba(255,255,255,.18);
}
.bachat-foot.mut { opacity: .6; }
.bachat-foot.warnc { color: #fde68a; opacity: 1; }

/* ---------- Khata cards (the four registers) ---------- */
.khata {
  display: block; width: 100%; text-align: left;
  border-left: 3px solid var(--tone, var(--brand));
  padding: 13px 14px 12px;
}
.khata:active { background: var(--card-2); }
.khata-h { display: flex; align-items: center; gap: 10px; }
.khata-ico {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 10px;
  display: grid; place-items: center; font-size: 16px;
  background: color-mix(in srgb, var(--tone) 18%, transparent);
}
.khata-t { flex: 1; min-width: 0; }
.khata-title { font-size: 15px; font-weight: 650; }
.khata-sub { font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
.khata-big { display: flex; align-items: baseline; gap: 7px; margin: 9px 0 2px; }
.khata-amt { font-size: 27px; font-weight: 700; letter-spacing: -.02em; }
.khata-lbl { font-size: 11.5px; color: var(--text-3); text-transform: uppercase; letter-spacing: .05em; }
.khata-rows { margin-top: 6px; }
.khata-rows .kv { padding: 5px 0; font-size: 13.5px; }
.khata-rows .kv + .kv { border-top: 1px solid var(--line); }
.khata-foot { margin-top: 8px; }

/* ---------- Daily page ---------- */
.day-sec { margin-bottom: 12px; }
.day-num {
  display: inline-grid; place-items: center;
  width: 20px; height: 20px; border-radius: 6px; margin-right: 7px;
  background: var(--card-2); color: var(--text-2);
  font-size: 11px; font-weight: 700;
}
.day-line {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 0; border-bottom: 1px solid var(--line); font-size: 14px;
}
.day-line:last-of-type { border-bottom: none; }
.day-line .dl-main { flex: 1; min-width: 0; }
.day-line .dl-sub { font-size: 11.5px; color: var(--text-3); margin-top: 1px; }
.day-line .dl-x { width: 26px; height: 26px; border-radius: 8px; color: var(--bad); font-size: 13px; }
.day-line .dl-x:active { background: color-mix(in srgb, var(--bad) 15%, transparent); }

/* ---------- Rows / lists ---------- */
.row {
  display: flex; align-items: center; gap: 11px;
  padding: 11px 13px;
  border-bottom: 1px solid var(--line);
  width: 100%; text-align: left; background: none;
}
.row:last-child { border-bottom: none; }
.row:active { background: var(--card-2); }
.row-ico {
  width: 34px; height: 34px; flex: 0 0 34px; border-radius: 10px;
  display: grid; place-items: center; font-size: 15px;
  background: var(--card-2);
}
.row-main { flex: 1; min-width: 0; }
.row-t { font-size: 15px; font-weight: 550; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.row-s { font-size: 12px; color: var(--text-3); margin-top: 1px; }
.row-r { text-align: right; flex: 0 0 auto; }
.row-amt { font-size: 15px; font-weight: 650; letter-spacing: -.01em; }
.row-sub { font-size: 11px; color: var(--text-3); margin-top: 1px; }
.chev { color: var(--text-3); font-size: 19px; margin-left: 2px; }

/* ---------- Colours ---------- */
.pos { color: var(--good); }
.neg { color: var(--bad); }
.mut { color: var(--text-3); }
.warnc { color: var(--warn); }
.infoc { color: var(--info); }
.purp { color: var(--purple); }

/* ---------- Pills / badges ---------- */
.pill {
  display: inline-block; padding: 2px 8px; border-radius: 99px;
  font-size: 11px; font-weight: 650; letter-spacing: .01em;
  background: var(--card-2); color: var(--text-2);
}
.pill.good { background: color-mix(in srgb, var(--good) 20%, transparent); color: var(--good); }
.pill.warn { background: color-mix(in srgb, var(--warn) 20%, transparent); color: var(--warn); }
.pill.bad  { background: color-mix(in srgb, var(--bad) 20%, transparent);  color: var(--bad); }
.pill.info { background: color-mix(in srgb, var(--info) 20%, transparent); color: var(--info); }

/* ---------- Alerts ---------- */
.alert {
  display: flex; gap: 10px; align-items: flex-start;
  border-radius: var(--radius); padding: 12px 13px;
  border: 1px solid; font-size: 13.5px; line-height: 1.4;
}
.alert .a-ico { font-size: 16px; line-height: 1.2; }
.alert b { display: block; margin-bottom: 2px; font-size: 14px; }
.alert.warn { background: color-mix(in srgb, var(--warn) 12%, var(--bg)); border-color: color-mix(in srgb, var(--warn) 40%, transparent); color: var(--text); }
.alert.bad  { background: color-mix(in srgb, var(--bad) 12%, var(--bg));  border-color: color-mix(in srgb, var(--bad) 40%, transparent);  color: var(--text); }
.alert.good { background: color-mix(in srgb, var(--good) 12%, var(--bg)); border-color: color-mix(in srgb, var(--good) 40%, transparent); color: var(--text); }
.alert.info { background: color-mix(in srgb, var(--info) 12%, var(--bg)); border-color: color-mix(in srgb, var(--info) 40%, transparent); color: var(--text); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  padding: 13px 16px; border-radius: 12px;
  font-size: 15px; font-weight: 620;
  background: var(--card-2); color: var(--text);
  border: 1px solid var(--line);
}
.btn:active { transform: scale(.985); }
.btn.primary { background: var(--brand-dk); color: #fff; border-color: transparent; }
.btn.danger  { background: color-mix(in srgb, var(--bad) 16%, transparent); color: var(--bad); border-color: color-mix(in srgb, var(--bad) 35%, transparent); }
.btn.ghost   { background: transparent; }
.btn.block   { display: flex; width: 100%; }
.btn.sm      { padding: 8px 12px; font-size: 13px; border-radius: 10px; }
.btn[disabled] { opacity: .45; pointer-events: none; }
.btn-row { display: flex; gap: 9px; }
.btn-row > * { flex: 1; }

/* ---------- Quick actions grid ---------- */
.qa { display: grid; grid-template-columns: repeat(4, 1fr); gap: 9px; }
.qa button {
  background: var(--card); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 12px 4px 10px; display: flex; flex-direction: column; align-items: center; gap: 5px;
}
.qa button:active { background: var(--card-2); }
.qa .q-ico { font-size: 20px; line-height: 1; }
.qa .q-lbl { font-size: 10.5px; color: var(--text-2); text-align: center; line-height: 1.25; }

/* ---------- The way in (screens/auth.js) ----------
   Its own page, sized like the welcome tour it arrives from, so crossing from
   card three to the form does not feel like landing in a different app. */
.auth {
  min-height: calc(100svh - var(--safe-b));
  display: flex; flex-direction: column;
  max-width: 430px; margin: 0 auto; padding: 0 20px 20px;
}
body.has-devbar .auth { min-height: calc(100svh - 38px - var(--safe-b)); }

/* Back · lockup · an empty span the same width as the back button, so the
   wordmark is centred on the PAGE and not on the space left over beside the
   arrow. */
.auth-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: clamp(6px, 1.4svh, 12px) 0 clamp(12px, 3svh, 22px);
}
.auth-back {
  flex: 0 0 auto; width: 34px; height: 34px; font-size: 26px; line-height: 1;
  color: var(--text-2); background: none; border: 0; padding: 0;
  display: grid; place-items: center;
}
.auth-back:active { color: var(--text); }

/* Not vertically centred. A form centred in the viewport jumps upward the
   moment the keyboard opens; anchored to the top it simply stays put. */
.auth-body { flex: 1; }
.auth-h { font-size: 27px; font-weight: 750; letter-spacing: -.02em; margin: 0; }
/* 13px so it holds one line on a phone. A sub-line that wraps stops being a
   sub-line and starts being a paragraph. */
.auth-p { font-size: 13px; color: var(--text-2); margin: 7px 0 22px; line-height: 1.5; }
.auth-go { padding: 15px; margin-top: 18px; }

/* The other door, set apart by a rule: it leaves this form entirely. */
.auth-alt { margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line); }

/* A plain text link, not a button. For the secondary way out of a form —
   "Forgot your PIN?" — which as a full-width ghost button carried the same
   visual weight as the action itself, while leading somewhere that cannot
   help you yet. */
.btn-link {
  display: inline; padding: 0; background: none; border: 0;
  font-size: 12px; color: var(--text-3); text-decoration: underline;
  text-underline-offset: 2px;
}
.btn-link:active { color: var(--text-2); }

/* Tucked under the right edge of the PIN box, close enough to belong to it.
   The field's own 13px bottom margin left it floating in the middle of a gap,
   attached to nothing. */
.auth-forgot {
  display: flex; justify-content: flex-end;
  margin: -9px 0 2px;
}

/* A long link, shown so it can be checked before it is sent. Wraps anywhere —
   a reset token is 32 characters with no spaces in it, and without this it
   pushes the sheet sideways. */
.code-line {
  font: 12px/1.55 ui-monospace, SFMono-Regular, Menlo, monospace;
  background: var(--bg-2); border: 1px solid var(--line); border-radius: 10px;
  padding: 10px 12px; color: var(--text-2);
  overflow-wrap: anywhere; word-break: break-all;
}

/* A question in the setup wizard. Heavier than a field label, because these
   are decisions rather than blanks — and one of them cannot be undone. */
.ob-q { font-size: 15px; font-weight: 650; line-height: 1.4; margin-bottom: 10px; }

/* The habit list on the last setup screen, folded. It is the least urgent
   thing on the last screen between someone and their first entry — worth
   offering, not worth four lines of reading before you can leave. */
.ob-fold > summary {
  cursor: pointer; list-style: none; display: flex; align-items: center; gap: 8px;
}
.ob-fold > summary::-webkit-details-marker { display: none; }
.ob-fold > summary::after {
  content: '▾'; margin-left: auto; color: var(--text-3); font-size: 12px;
}
.ob-fold[open] > summary::after { content: '▴'; }

/* Setup's field labels are questions too — "How much to set aside", "Taken
   from" — not the quiet captions they are everywhere else in the app, where a
   label sits above a box whose purpose is already obvious. Someone answering
   these for the first time reads the label before the field, so it gets full
   text colour and a size to match. */
.ob-wrap .field > label {
  font-size: 14.5px; font-weight: 650; color: var(--text); margin-bottom: 7px;
}

/* ---------- Forms ---------- */
.field { margin-bottom: 13px; }
.field > label {
  display: block; font-size: 12.5px; font-weight: 600;
  color: var(--text-2); margin-bottom: 5px;
}
.field .hint { font-size: 11.5px; color: var(--text-3); margin-top: 5px; line-height: 1.35; }
.input, select.input, textarea.input {
  width: 100%; padding: 12px 13px;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: 11px; font-size: 16px; color: var(--text);
  appearance: none;
}
.input:focus { outline: 2px solid color-mix(in srgb, var(--brand) 55%, transparent); outline-offset: -1px; border-color: transparent; }
textarea.input { min-height: 66px; resize: vertical; }
select.input {
  background-image: linear-gradient(45deg, transparent 50%, var(--text-3) 50%),
                    linear-gradient(135deg, var(--text-3) 50%, transparent 50%);
  background-position: calc(100% - 18px) 50%, calc(100% - 13px) 50%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
  padding-right: 34px;
}
.amount-in {
  font-size: 30px !important; font-weight: 700; letter-spacing: -.02em;
  text-align: right; padding: 14px 15px !important;
}
/* Half-width twin of .amount-in — still clearly a money field, but two fit on
   a row. 16px minimum, or iOS zooms the page when the field is focused. */
.sale-in {
  font-size: 21px !important; font-weight: 700; letter-spacing: -.02em;
  text-align: right; padding: 11px 12px !important;
}
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.three { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }

/* segmented control */
.seg { display: flex; background: var(--bg-2); border: 1px solid var(--line); border-radius: 11px; padding: 3px; gap: 3px; }
.seg button {
  flex: 1; padding: 9px 6px; border-radius: 8px;
  font-size: 13.5px; font-weight: 600; color: var(--text-3);
}
.seg button.on { background: var(--brand-dk); color: #fff; }

/* chips */
.chips { display: flex; flex-wrap: wrap; gap: 7px; }
.chip {
  padding: 8px 13px; border-radius: 99px;
  background: var(--bg-2); border: 1px solid var(--line);
  font-size: 13.5px; color: var(--text-2);
}
.chip.on { background: var(--brand-dk); border-color: transparent; color: #fff; font-weight: 600; }

/* toggle */
.tgl-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 11px 0; }
.tgl-row .t-l { font-size: 14.5px; }
.tgl-row .t-h { font-size: 11.5px; color: var(--text-3); margin-top: 2px; }
.tgl { width: 46px; height: 27px; flex: 0 0 46px; border-radius: 99px; background: var(--line); position: relative; transition: background .15s; }
.tgl::after { content: ""; position: absolute; top: 3px; left: 3px; width: 21px; height: 21px; border-radius: 50%; background: #fff; transition: transform .15s; }
.tgl.on { background: var(--brand); }
.tgl.on::after { transform: translateX(19px); }

/* ---------- Sheet (bottom modal) ---------- */
.sheet-bg {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(2,6,16,.62);
  animation: fade .16s ease;
}
.sheet {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 91;
  max-height: 92dvh; overflow-y: auto;
  background: var(--bg-2);
  border-radius: 22px 22px 0 0;
  border-top: 1px solid var(--line);
  padding: 8px 16px calc(20px + var(--safe-b));
  animation: up .2s cubic-bezier(.2,.8,.3,1);
  max-width: 720px; margin: 0 auto;
}
.sheet-grab { width: 38px; height: 4px; border-radius: 99px; background: var(--line); margin: 4px auto 12px; }
.sheet-h { display: flex; align-items: center; justify-content: space-between; margin-bottom: 14px; }
.sheet-h h2 { margin: 0; font-size: 19px; font-weight: 680; }
.sheet-x { width: 32px; height: 32px; border-radius: 9px; background: var(--card-2); color: var(--text-2); font-size: 17px; }
@keyframes up   { from { transform: translateY(100%); } to { transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

/* ---------- Toast ---------- */
.toast-root {
  position: fixed; left: 0; right: 0; z-index: 120;
  bottom: calc(var(--nav-h) + var(--safe-b) + 16px);
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  pointer-events: none;
}
.toast {
  background: #0f172a; color: #fff;
  border: 1px solid #334155;
  padding: 11px 17px; border-radius: 99px;
  font-size: 14px; font-weight: 550;
  box-shadow: 0 8px 26px rgba(0,0,0,.4);
  animation: up .18s ease;
  max-width: 88vw; text-align: center;
}
.toast.good { border-color: var(--good); }
.toast.bad  { border-color: var(--bad); }

/* ---------- Empty state ---------- */
.empty { text-align: center; padding: 34px 20px; color: var(--text-3); }
.empty .e-ico { font-size: 36px; opacity: .5; }
.empty .e-t { font-size: 15px; margin-top: 10px; color: var(--text-2); }
.empty .e-s { font-size: 13px; margin-top: 4px; }

/* ---------- Ledger table ---------- */
.led { width: 100%; border-collapse: collapse; font-size: 13.5px; }
.led th {
  text-align: left; font-size: 11px; font-weight: 700; color: var(--text-3);
  text-transform: uppercase; letter-spacing: .05em;
  padding: 9px 11px; border-bottom: 1px solid var(--line);
}
.led td { padding: 10px 11px; border-bottom: 1px solid var(--line); vertical-align: top; }
.led tr:last-child td { border-bottom: none; }
.led .num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.led .void { opacity: .45; text-decoration: line-through; }

/* ---------- Misc ---------- */
.kv { display: flex; justify-content: space-between; gap: 12px; padding: 7px 0; font-size: 14px; }
.kv + .kv { border-top: 1px solid var(--line); }
.kv .k { color: var(--text-2); }
.kv .v { font-weight: 620; font-variant-numeric: tabular-nums; }
.kv.big .v { font-size: 18px; }
.kv.total { border-top: 2px solid var(--line); margin-top: 3px; padding-top: 10px; }

.bar { height: 7px; border-radius: 99px; background: var(--card-2); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 99px; background: var(--brand); }
.bar > i.warn { background: var(--warn); }
.bar > i.bad  { background: var(--bad); }

.mono { font-variant-numeric: tabular-nums; }
.small { font-size: 12.5px; color: var(--text-3); line-height: 1.45; }
.center { text-align: center; }
.spacer { height: 6px; }
.divider { height: 1px; background: var(--line); margin: 4px 0; }
.hidden { display: none !important; }
