/* ---------- Inter, self-hosted so the shop still looks right offline ---------- */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-latin-1f021a24.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-latin-ext-65edaaef.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304,
    U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0,
    U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* The rupee sign is outside every standard subset, so it ships on its own —
   without this, every price would mix Inter digits with a fallback ₹. */
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("/assets/inter-rupee-f107ddfd.woff2") format("woff2");
  unicode-range: U+20B9;
}

:root {
  --bg: #f7f8fa;
  --surface: #ffffff;
  --surface-sunken: #fafbfc;
  --border: #e6e8ee;
  --border-strong: #d3d7e0;
  --text: #12141a;
  --text-soft: #454b57;
  --muted: #737a88;
  /* The logo's green, as the app wears it (billmyshop lib/theme.dart). */
  --accent: #0b6e4f;
  --accent-hover: #064e38;
  --accent-soft: #ddf3ea;
  --ok: #04795b;
  --ok-soft: #e3f5ef;
  --bad: #c02618;
  --bad-soft: #fdeceb;
  --warn: #8a5300;
  --warn-soft: #fdf2e0;
  --radius: 12px;
  --radius-sm: 8px;
  --shadow-sm: 0 1px 2px rgba(18, 20, 26, .05);
  --shadow: 0 1px 3px rgba(18, 20, 26, .06), 0 4px 12px -4px rgba(18, 20, 26, .05);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  font-size: 14.5px;
  line-height: 1.55;
  font-feature-settings: "cv11", "ss01";
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }

h1, h2, h3 { letter-spacing: -.018em; }

/* ---------- Layout ---------- */
.app { display: flex; min-height: 100vh; }

.sidebar {
  width: 216px;
  flex-shrink: 0;
  background: var(--surface);
  border-right: 1px solid var(--border);
  padding: 16px 12px;
  position: sticky;
  top: 0;
  height: 100vh;
  display: flex;
  flex-direction: column;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px 18px;
}
.brand__mark {
  width: 32px;
  height: 32px;
  flex-shrink: 0;
  border-radius: 9px;
  background: linear-gradient(140deg, #14946a, var(--accent));
  color: #fff;
  display: grid;
  place-items: center;
  font-weight: 700;
  /* Sized for the three or four letters a bill prefix runs to, not just two. */
  font-size: 13px;
  letter-spacing: -.03em;
  overflow: hidden;
}
/* A column, so the shop's name and the subtitle each keep their own line. As
   inline spans they ran together on any name short enough to leave room, and
   the name's ellipsis never took effect. */
.brand__text { min-width: 0; display: flex; flex-direction: column; }
/* Two lines, not an ellipsis. The shop's own name is the one piece of text the
   owner is certain to read, and "Shree Balaji Electr..." tells them their app
   does not know who they are. Clamped at two so a very long name still cannot
   push the navigation down the page. */
.brand__name {
  font-weight: 650;
  font-size: 14px;
  letter-spacing: -.015em;
  line-height: 1.25;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow: hidden;
  overflow-wrap: break-word;
}
.brand__sub { font-size: 11px; color: var(--muted); white-space: nowrap; }

.nav { display: flex; flex-direction: column; gap: 1px; }
.nav__link {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 10px;
  border-radius: var(--radius-sm);
  color: var(--text-soft);
  font-size: 14px;
  font-weight: 500;
  transition: background .12s ease, color .12s ease;
}
.nav__link:hover { background: var(--surface-sunken); color: var(--text); text-decoration: none; }
.nav__link--active { background: var(--accent-soft); color: var(--accent); font-weight: 600; }
/* Each icon on a pale tile of its own colour (.tone-*), as the app's More
   screen draws them: a glance tells selling from buying from money owed. */
.nav__link svg {
  width: 27px; height: 27px; padding: 5px; box-sizing: border-box; flex-shrink: 0;
  border-radius: 8px; color: var(--tone, currentColor); background: var(--tone-wash, transparent);
}
.nav__spacer { margin-top: auto; }

/* Sign out is a button_to form, so it needs the browser chrome stripped off. */
button.nav__link {
  width: 100%;
  border: 0;
  background: none;
  font: inherit;
  font-weight: 500;
  text-align: left;
  cursor: pointer;
}

/* Capped so the billing rows never stretch to silly widths, and centred in the
   space left over — otherwise an ultrawide monitor pins everything to the left
   edge with a third of the screen empty beside it. */
.main {
  flex: 1;
  padding: 26px 30px 64px;
  max-width: 1440px;
  min-width: 0;
  margin-inline: auto;
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.page-head h1 { font-size: 23px; margin: 0; font-weight: 650; }
.page-head .sub { color: var(--muted); font-size: 13px; margin-top: 3px; }
.page-head__actions { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }

/* ---------- Cards & tables ---------- */
.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  margin-bottom: 18px;
  overflow: hidden;
}
.card__head {
  padding: 13px 16px;
  border-bottom: 1px solid var(--border);
  font-weight: 600;
  font-size: 13.5px;
  letter-spacing: -.01em;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
}
.card__body { padding: 16px; }
.card__body--flush { padding: 0; }

.table-wrap { overflow-x: auto; }
table { width: 100%; border-collapse: collapse; font-size: 14px; }
th, td { padding: 11px 14px; text-align: left; border-bottom: 1px solid var(--border); }
th {
  font-size: 11px;
  text-transform: uppercase;
  letter-spacing: .05em;
  color: var(--muted);
  font-weight: 600;
  background: var(--surface-sunken);
  white-space: nowrap;
}
tbody tr:last-child td { border-bottom: 0; }
tbody tr { transition: background .1s ease; }
tbody tr:hover { background: var(--surface-sunken); }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.strong { font-weight: 600; }
.muted { color: var(--muted); }
.small { font-size: 12.5px; }

.empty { padding: 46px 16px; text-align: center; color: var(--muted); }

/* ---------- Tones ----------
   One colour per kind of work, the app's palette (billmyshop lib/palette.dart):
   a strong ink for icons and figures, and a pale wash to sit them on. */
.tone-selling  { --tone: #0b6e4f; --tone-wash: #ddf3ea; }
.tone-buying   { --tone: #2563eb; --tone-wash: #dde8fe; }
.tone-money    { --tone: #ea580c; --tone-wash: #ffe8d9; }
.tone-spending { --tone: #b45309; --tone-wash: #fef0d3; }
.tone-insight  { --tone: #7c3aed; --tone-wash: #ede5ff; }
.tone-people   { --tone: #0891b2; --tone-wash: #d9f3f8; }
.tone-stock    { --tone: #4f46e5; --tone-wash: #e3e3fd; }
.tone-tax      { --tone: #db2777; --tone-wash: #fce3ef; }
.tone-warning  { --tone: #dc2626; --tone-wash: #fde3e3; }
.tone-neutral  { --tone: #475569; --tone-wash: #e9edf2; }

/* ---------- Stats ---------- */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(196px, 1fr)); gap: 14px; margin-bottom: 20px; }
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 17px;
  box-shadow: var(--shadow-sm);
}
.stat__label { font-size: 11.5px; color: var(--muted); text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.stat__value {
  font-size: 26px;
  font-weight: 650;
  margin-top: 6px;
  letter-spacing: -.025em;
  font-variant-numeric: tabular-nums;
}
.stat__note { font-size: 12.5px; color: var(--muted); margin-top: 4px; }
.stat[class*="tone-"] .stat__value { color: var(--tone); }
.stat__icon svg {
  display: block; width: 34px; height: 34px; padding: 8px; box-sizing: border-box; margin-bottom: 10px;
  border-radius: 10px; color: var(--tone); background: var(--tone-wash);
}
/* Today's sales, the figure the day is judged by: the app's green hero card. */
.stat--hero {
  background: linear-gradient(135deg, #14946a, #064e38);
  border: 0;
  color: #fff;
  box-shadow: 0 8px 18px -8px rgba(11, 110, 79, .55);
}
.stat--hero .stat__label, .stat--hero .stat__note { color: rgba(255, 255, 255, .82); }
.stat--hero .stat__icon svg { color: #fff; background: rgba(255, 255, 255, .18); }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: 13.5px;
  font-weight: 550;
  cursor: pointer;
  font-family: inherit;
  white-space: nowrap;
  box-shadow: var(--shadow-sm);
  transition: background .12s ease, border-color .12s ease, box-shadow .12s ease;
  /* An <input type=submit> ignores inline-flex and takes the browser's own
     line-height, so a submit and a link styled as buttons end up different
     heights and sit at different levels in a row. */
  line-height: 1.4;
}
.btn:hover { background: var(--surface-sunken); border-color: var(--muted); text-decoration: none; }
.btn:active { box-shadow: none; }
.btn--primary {
  background: var(--accent);
  border-color: var(--accent);
  color: #fff;
  box-shadow: 0 1px 2px rgba(11, 110, 79, .3);
}
.btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.btn--danger { color: var(--bad); border-color: #f0cbc7; background: var(--surface); }
.btn--danger:hover { background: var(--bad-soft); border-color: var(--bad); }
.btn--small { padding: 5px 10px; font-size: 12.5px; }
.btn--link { border: 0; background: none; box-shadow: none; color: var(--muted); padding: 4px 6px; }
.btn--link:hover { background: var(--bad-soft); color: var(--bad); }

/* ---------- Forms ---------- */
.form-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 15px; }
.field { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.field--wide { grid-column: 1 / -1; }
/* Two to a row, for a card whose fields have long hints under them. Left to
   auto-fit they spread to six across on a wide screen, which strands each hint
   in a column too narrow to read and leaves the last field alone on the next
   row. Overridden back to one column on a phone by the rule further down. */
.form-grid--pairs { grid-template-columns: repeat(2, minmax(0, 1fr)); }
/* Ticks that belong together, kept on one line and top-aligned so hints of
   different lengths do not drag the boxes out of step. */
.print-options { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 15px; align-items: start; }
/* The bill form's quotation-only fields, hidden until Quotation is the status.
   A browser without :has() drops the rule and shows them, as it always did. */
form:not(:has(#invoice_status option[value="quotation"]:checked)) .quotation-only { display: none; }
.field label { font-size: 12.5px; font-weight: 600; color: var(--text-soft); }
.field .hint { font-size: 11.5px; color: var(--muted); }
.line__last-price { display: block; font-size: 11px; color: var(--ok); margin-top: 2px; }

input[type=text], input[type=number], input[type=date], input[type=email],
input[type=password], input[type=search], input[type=tel], input[type=datetime-local],
input[type=time], select, textarea {
  width: 100%;
  padding: 8px 11px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  font-size: 14px;
  font-family: inherit;
  background: var(--surface);
  color: var(--text);
  transition: border-color .12s ease, box-shadow .12s ease;
}
input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px rgba(11, 110, 79, .15);
}
input[type=number] { font-variant-numeric: tabular-nums; }
textarea { resize: vertical; min-height: 70px; }
.checkbox { display: flex; align-items: center; gap: 8px; font-size: 14px; }
.checkbox input { width: auto; accent-color: var(--accent); }

/* Buttons inside a stretching field column should keep their own width. */
.field .btn { align-self: flex-start; }

/* A short control in a field that spans the row. The hint under it wants the
   whole line - squeezed into one grid column it wraps to six - while a two
   option dropdown stretched to the same width just looks broken. */
.input--short { max-width: 220px; }

/* A person's sign-in access on the staff page: its own box, so switching it
   off for someone on leave reads as the decision it is, not a stray tick. */
.access { margin-top: 18px; padding: 12px 14px; border: 1px solid var(--border); border-radius: var(--radius-sm);
  background: var(--surface-sunken); display: grid; gap: 6px; }
.access__head { display: flex; align-items: center; justify-content: space-between; gap: 10px; flex-wrap: wrap; }
.access .hint { margin: 0; }

.form-actions {
  display: flex;
  gap: 10px;
  align-items: center;
  padding: 14px 16px;
  border-top: 1px solid var(--border);
  background: var(--surface-sunken);
}

.filters { display: flex; gap: 10px; align-items: flex-end; flex-wrap: wrap; }
.filters .field { min-width: 150px; }

/* A checkbox needs only its own width; the 150px floor meant for text inputs
   left a gap between it and the buttons. */
.filters .field:has(> .checkbox) { min-width: 0; }

/* ---------- Price lookup ---------- */
.lookup { position: relative; margin-bottom: 18px; max-width: 460px; }
.lookup input[type=search] { padding-left: 12px; }

/* The results float over the page rather than pushing it down, so checking a
   price never disturbs whatever is on screen. */
.lookup__panel {
  position: absolute;
  z-index: 20;
  top: calc(100% + 6px);   /* below the input, not on top of it */
  left: 0;
  right: 0;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  overflow: hidden;
}

.lookup__hit {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 14px;
  padding: 9px 13px;
  color: var(--text);
  border-bottom: 1px solid var(--border);
}
.lookup__hit:last-child { border-bottom: 0; }
.lookup__hit:hover { background: var(--accent-soft); text-decoration: none; }

.lookup__name { font-size: 13.5px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.lookup__price { font-weight: 700; font-variant-numeric: tabular-nums; white-space: nowrap; }
.lookup__meta { white-space: nowrap; }
.lookup__empty { padding: 13px; }

@media (max-width: 620px) {
  .lookup { max-width: none; }
  .lookup__hit { grid-template-columns: minmax(0, 1fr) auto; gap: 4px 10px; }
  .lookup__meta { grid-column: 1 / -1; }
}

/* Dashboard panels share the width evenly and wrap on their own, rather than
   using the billing screen's fixed narrow sidebar column. */
.dash-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(360px, 1fr));
  gap: 18px;
  align-items: start;
}
.dash-grid > * { min-width: 0; }

/* ---------- Ranked bar chart ---------- */
/* One grid for the whole chart, with each row contributing its cells to it.
   A grid per row would size the value column to that row's own text, so a
   short "7 PCS" would widen its track and knock the bars out of line. */
.chart {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 40% auto;
  align-items: center;
  gap: 11px 12px;
}
.chart__row { display: contents; }
.chart__label {
  font-size: 13px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.chart__label a { color: var(--text); }

/* The track shows the scale each bar is read against. */
.chart__track {
  height: 10px;
  border-radius: 5px;
  background: var(--bg);
  overflow: hidden;
}
.chart__bar {
  height: 100%;
  min-width: 3px;
  border-radius: 0 4px 4px 0;   /* rounded data end, square against the baseline */
  transition: width .2s ease;
}
.chart__value {
  font-size: 12.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.filters__spacer { flex: 1; }

/* Narrow screens: the label sits above its bar instead of stealing its width. */
@media (max-width: 620px) {
  .chart { grid-template-columns: 1fr auto; gap: 4px 10px; }
  .chart__label { grid-column: 1 / -1; }
}

/* ---------- Badges & flash ---------- */
.badge {
  display: inline-block;
  padding: 2px 9px;
  border-radius: 999px;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: -.005em;
}
.badge--ok { background: var(--ok-soft); color: var(--ok); }
.badge--bad { background: var(--bad-soft); color: var(--bad); }
.badge--muted { background: var(--bg); color: var(--muted); }
.badge--warn { background: var(--warn-soft); color: var(--warn); }

.flash {
  padding: 12px 15px;
  border-radius: var(--radius-sm);
  margin-bottom: 16px;
  font-size: 13.5px;
  font-weight: 500;
  border: 1px solid;
}
.flash--notice { background: var(--ok-soft); border-color: #b9e3d5; color: var(--ok); }
.flash--alert { background: var(--bad-soft); border-color: #f0cbc7; color: var(--bad); }

.errors {
  background: var(--bad-soft);
  border: 1px solid #f0cbc7;
  color: var(--bad);
  border-radius: var(--radius-sm);
  padding: 13px 15px;
  margin-bottom: 16px;
  font-size: 13.5px;
}
.errors ul { margin: 6px 0 0; padding-left: 18px; }

/* ---------- Billing screen ---------- */
.bill-layout { display: grid; grid-template-columns: 1fr 300px; gap: 18px; align-items: start; }

/* Grid children are min-width:auto by default, so the wide items table would
   push the column past the viewport and scroll the whole page instead of
   scrolling inside its own wrapper. */
.bill-layout > * { min-width: 0; }
.card, .table-wrap { max-width: 100%; }

/* Below this the row cannot stay legible, so the wrapper scrolls instead of
   crushing every column. */
/* Fixed layout so the column widths set on the header are honoured. With
   automatic layout the browser hands the description column the slack it wants
   and squeezes the selects until "COIL" reads as "COI". */
.lines { width: 100%; min-width: 790px; font-size: 13.5px; table-layout: fixed; }
.lines th { padding: 8px 6px; }
.lines td { padding: 5px 6px; vertical-align: middle; border-bottom: 1px solid var(--border); }
.lines input, .lines select { padding: 6px 7px; font-size: 13.5px; }

/* The native dropdown arrow is drawn inside the control, so selects keep a
   little room for it on the right. */
.lines select { padding-right: 16px; }
.lines input[type=number] { text-align: right; }

/* Spinners eat width the amounts need, and nobody nudges a rate one paisa at
   a time with an arrow. */
.lines input[type=number]::-webkit-inner-spin-button,
.lines input[type=number]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; }
.lines input[type=number] { -moz-appearance: textfield; appearance: textfield; }

.lines tbody tr:hover { background: transparent; }
.line__amount { font-variant-numeric: tabular-nums; font-weight: 600; white-space: nowrap; }
.line--removed { display: none; }

.totals { font-size: 13.5px; }
.totals__row { display: flex; justify-content: space-between; padding: 7px 0; gap: 12px; }
.totals__row + .totals__row { border-top: 1px solid var(--border); }
.totals__row span:first-child { color: var(--text-soft); }
.totals__row span:last-child { font-variant-numeric: tabular-nums; font-weight: 550; }
.totals__row--grand {
  border-top: 2px solid var(--border-strong) !important;
  margin-top: 5px;
  padding-top: 12px;
  font-size: 20px;
  letter-spacing: -.025em;
}
.totals__row--grand span { font-weight: 700 !important; color: var(--text) !important; }

.summary-box {
  background: var(--accent-soft);
  border: 1px solid #dfe3fd;
  border-radius: var(--radius);
  padding: 13px 15px;
  font-size: 12.5px;
  color: var(--text-soft);
  line-height: 1.6;
}

/* ---------- Invoice view ---------- */
.invoice-head { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; }
.kv { font-size: 13.5px; margin: 0; }
.kv dt { color: var(--muted); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; font-weight: 600; }
.kv dd { margin: 3px 0 12px; }

/* ---------- Responsive ---------- */

/* Tablet: the totals panel drops below the items rather than squeezing them. */
@media (max-width: 1080px) {
  .bill-layout { grid-template-columns: 1fr; }
  .main { padding: 22px 20px 56px; }
}

/* Phones and small tablets: the sidebar becomes a scrolling bar across the top
   so the whole width goes to the work. */
@media (max-width: 860px) {
  .app { flex-direction: column; }

  .sidebar {
    width: 100%;
    height: auto;
    position: static;
    border-right: 0;
    border-bottom: 1px solid var(--border);
    padding: 10px 12px;
    flex-direction: row;
    align-items: center;
    gap: 10px;
    overflow-x: auto;
  }

  .brand { padding: 0 6px 0 0; flex-shrink: 0; }
  .brand__text { display: none; }

  .nav { flex-direction: row; gap: 4px; }
  .nav__link { white-space: nowrap; padding: 7px 10px; }
  .nav__spacer { margin-top: 0; margin-left: auto; }

  /* Once the app stacks, main is a flex item in a column container and will
     not shrink below its content's minimum on its own — the wide tables would
     stretch it past the viewport instead of scrolling inside their wrappers. */
  .main { padding: 18px 14px 48px; width: 100%; max-width: 100%; }
  .page-head h1 { font-size: 20px; }
  .stats { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 10px; }
  .stat__value { font-size: 21px; }
  .form-grid { grid-template-columns: 1fr; gap: 13px; }
  .print-options { grid-template-columns: 1fr; gap: 13px; }
  .filters .field { min-width: 0; flex: 1 1 100%; }
  .card { border-radius: 10px; }
}

/* Very small phones: the nav keeps only its icons. The button selector is
   spelled out because button.nav__link outranks a bare .nav__link rule. */
@media (max-width: 480px) {
  .nav__link, button.nav__link { padding: 7px 9px; font-size: 0; gap: 0; }
  .nav__link svg { width: 29px; height: 29px; }

  /* Icons alone used to fit across a phone, so the bar could let them spill.
     They no longer do, and spilling moves the whole page sideways instead of
     the bar — so the bar scrolls within its own width again. */
  .sidebar { overflow-x: auto; }
  .nav { flex-shrink: 0; }
  .page-head__actions { width: 100%; }
  .page-head__actions .btn { flex: 1 1 auto; justify-content: center; }
}

/* ---------- Login ---------- */
.auth { display: flex; align-items: center; justify-content: center; min-height: 100vh; padding: 20px; }
.auth .card { width: 100%; max-width: 380px; margin: 0; box-shadow: var(--shadow); }
.auth__brand { text-align: center; margin-bottom: 18px; }
.auth__brand .brand__mark { margin: 0 auto 10px; width: 40px; height: 40px; font-size: 17px; }
/* The product's own logo, which brings its own colour - not the shop tile behind it. */
.auth__brand .brand__mark:has(img) { background: none; width: 52px; height: 52px; }
.auth__brand .brand__mark img { width: 100%; height: 100%; }
.auth__brand h1 { font-size: 19px; margin: 0; font-weight: 650; }
.auth__brand p { color: var(--muted); font-size: 13px; margin: 4px 0 0; }

/* ---------- Landing page ----------
   The public page at the root, shown to anyone who is not signed in. It reuses
   the app's tokens so the product and its shop window cannot drift apart, but
   sets its own rhythm: wider measure, more air, larger type. */
.landing-page { background: var(--surface); }

.lp-wrap { width: 100%; max-width: 1080px; margin: 0 auto; padding: 0 24px; }

.lp-bar {
  position: sticky;
  top: 0;
  z-index: 10;
  background: rgba(255, 255, 255, .86);
  backdrop-filter: saturate(180%) blur(12px);
  border-bottom: 1px solid var(--border);
}
.lp-bar__inner { display: flex; align-items: center; justify-content: space-between; height: 62px; }

.lp-brand { display: flex; align-items: center; gap: 10px; text-decoration: none; color: var(--text); }
.lp-brand__mark { display: flex; }
.lp-brand__mark img { display: block; border-radius: 7px; }
.lp-brand__name { font-weight: 680; font-size: 16px; letter-spacing: -.01em; }

.lp-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 9px 16px;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-size: 14px;
  font-weight: 560;
  text-decoration: none;
  transition: background .12s ease, border-color .12s ease, transform .12s ease;
}
.lp-btn:hover { background: var(--surface-sunken); text-decoration: none; }
.lp-btn--primary { background: var(--accent); border-color: var(--accent); color: #fff; }
.lp-btn--primary:hover { background: var(--accent-hover); border-color: var(--accent-hover); }
.lp-btn--lg { padding: 12px 22px; font-size: 15px; border-radius: 10px; }

.lp-hero { padding: 84px 0 56px; text-align: center; }
.lp-eyebrow {
  margin: 0 0 18px;
  color: var(--accent);
  font-size: 12.5px;
  font-weight: 640;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.lp-hero h1 {
  margin: 0 auto 20px;
  max-width: 780px;
  font-size: clamp(32px, 5.2vw, 54px);
  line-height: 1.08;
  letter-spacing: -.03em;
  font-weight: 700;
}
.lp-lead {
  margin: 0 auto;
  max-width: 60ch;
  color: var(--text-soft);
  font-size: clamp(15.5px, 1.6vw, 18px);
  line-height: 1.6;
}
.lp-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin: 32px 0 16px; }
.lp-note { margin: 0; color: var(--muted); font-size: 13px; }

/* The screenshots are the product's real screens, so they are shown at their
   own scale rather than cropped into a device frame. */
.lp-shot { margin: 8px auto 0; }
.lp-shot img {
  display: block;
  width: 100%;
  height: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.lp-shot--paper img { box-shadow: var(--shadow-sm); }

.lp-section { padding: 72px 0 0; }
.lp-section h2, .lp-split h2 {
  margin: 0 0 14px;
  font-size: clamp(24px, 3vw, 32px);
  letter-spacing: -.02em;
  font-weight: 680;
}
.lp-section h2 { margin-bottom: 26px; }

.lp-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 18px; }
.lp-card {
  padding: 22px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-sunken);
}
.lp-card h3 { margin: 0 0 8px; font-size: 16px; font-weight: 640; letter-spacing: -.01em; }
.lp-card p { margin: 0; color: var(--text-soft); font-size: 14px; line-height: 1.62; }

.lp-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 44px;
  align-items: center;
  padding: 84px 24px 0;
}
.lp-split p { color: var(--text-soft); font-size: 15.5px; line-height: 1.65; }

/* The lead is centred in the hero; here it sits under a left-aligned heading. */
#contact .lp-lead, #price .lp-lead { margin-left: 0; }
#price .lp-actions { justify-content: flex-start; margin-top: 22px; }
.lp-contact { display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 14px; margin: 26px 0 16px; }
.lp-contact__card {
  display: block;
  padding: 16px 18px;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface);
  text-decoration: none;
}
.lp-contact__card:hover { border-color: var(--accent); text-decoration: none; }
.lp-contact__label { display: block; font-size: 11.5px; font-weight: 600; letter-spacing: .05em; text-transform: uppercase; color: var(--muted); }
.lp-contact__value { display: block; margin-top: 5px; font-size: 16px; font-weight: 600; color: var(--text); }
.lp-bar__actions { display: flex; align-items: center; gap: 16px; }
.lp-bar__link { color: var(--text-soft); font-size: 14px; font-weight: 600; text-decoration: none; }
.lp-bar__link:hover { color: var(--accent); }

.year-end { display: flex; gap: 20px; align-items: center; justify-content: space-between; flex-wrap: wrap; }
.year-end__buttons { display: flex; gap: 8px; flex-shrink: 0; }

.lp-foot { margin-top: 84px; padding: 28px 0; border-top: 1px solid var(--border); }
.lp-foot p { margin: 0; color: var(--muted); font-size: 13px; text-align: center; }
.lp-foot a { color: inherit; }

/* Long-form public pages: the privacy policy. One readable column. */
.lp-prose { max-width: 68ch; padding-top: 48px; }
.lp-prose h1 { margin: 0 0 6px; font-size: clamp(28px, 3.5vw, 36px); letter-spacing: -.02em; font-weight: 680; }
.lp-prose h2 { margin: 36px 0 10px; font-size: 20px; letter-spacing: -.01em; font-weight: 650; }
.lp-prose p, .lp-prose li { color: var(--text-soft); font-size: 15.5px; line-height: 1.65; }
.lp-prose .lp-updated { color: var(--muted); font-size: 13px; margin-bottom: 28px; }

@media (max-width: 900px) {
  .lp-grid { grid-template-columns: repeat(2, 1fr); }
  .lp-split { grid-template-columns: 1fr; gap: 28px; padding-top: 64px; }
}

@media (max-width: 620px) {
  .lp-hero { padding: 56px 0 40px; }
  .lp-grid { grid-template-columns: 1fr; }
  .lp-section { padding-top: 56px; }
  .lp-actions .lp-btn { flex: 1 1 100%; }
}

/* Sign-out lands on the landing page, so its confirmation needs room above the
   sticky bar rather than sitting under it. */
.lp-flash { padding-top: 16px; }

/* ---------- The bill's item lines on a phone ----------
   Ten columns will not fit a phone. Left as a table the row is 790px wide in a
   345px window, so reaching Rate or Amount means dragging the table sideways
   with one thumb while billing a customer with the other.

   Each line becomes a card instead: the header row is dropped and every field
   carries its own label, laid out two across so the short numeric fields pair
   up rather than making a column ten fields long. */
@media (max-width: 700px) {
  .table-wrap:has(.lines) { overflow-x: visible; }

  /* min-width is what keeps the row readable as a table; stacked it is exactly
     what forces the 445px of sideways dragging, so it has to go too. */
  .lines, .lines tbody { display: block; width: 100%; min-width: 0; table-layout: auto; }
  .lines thead { display: none; }

  .lines tr.line {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px 12px;
    padding: 12px;
    margin: 0 12px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }

  .lines td { display: block; padding: 0; border: 0; }

  .lines td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 4px;
    font-size: 11px;
    font-weight: 600;
    color: var(--muted);
  }

  /* The two that need the width, and the two that close the card. */
  .lines td:nth-child(1),
  .lines td:nth-child(2),
  .lines td.line__amount,
  .lines td.line__remove { grid-column: 1 / -1; }

  .lines td.line__amount {
    padding-top: 8px;
    border-top: 1px solid var(--border);
    font-size: 16px;
    font-weight: 650;
  }
  .lines td.line__amount::before { display: inline; margin: 0 8px 0 0; font-size: 12px; }
  .lines td.line__amount { text-align: right; }

  .lines td.line__remove { text-align: right; }
  .lines td.line__remove::before { content: none; }

  /* The inputs were sized for a table cell. */
  .lines input[type=text], .lines input[type=number], .lines select { width: 100%; }
  .lines input[type=number] { text-align: left; }
}

/* ---------- A bill opened from a shared link ----------
   Seen by a customer on a phone, usually once, with no account and no sidebar. */
.shared-bill { padding: 32px 24px 48px; max-width: 760px; }
.shared-bill__head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-start;
  justify-content: space-between;
  margin-bottom: 20px;
}
/* The notes above the items - a cancelled bill, or a quotation saying it is not
   one - carry no margin of their own, so they sat flush against the table below
   and read as part of it. Matched to the 18px the cards are spaced by. */
.shared-bill .summary-box { margin-bottom: 18px; }
.shared-bill__head h1 { margin: 4px 0; font-size: 26px; letter-spacing: -.02em; }
.shared-bill__head p { margin: 0; }
.shared-bill__total { display: flex; flex-direction: column; gap: 3px; align-items: flex-end; }
.shared-bill__total strong { font-size: 24px; letter-spacing: -.02em; }
.shared-bill__actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 20px; }

/* Paying the bill you are looking at. The button is the whole point on a
   phone, so it is the widest thing in the card; the code sits under it for
   the computer case rather than competing with it. */
.pay { margin-bottom: 18px; text-align: center; }
.pay__label { margin: 0; font-size: 12px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); }
.pay__amount { margin: 4px 0 14px; font-size: 30px; font-weight: 700; letter-spacing: -.02em; }
.pay__button { display: block; width: 100%; max-width: 340px; margin: 0 auto; padding: 14px 20px; font-size: 16px; }
.pay .hint { max-width: 420px; margin: 10px auto 0; }
.pay__qr { margin-top: 20px; }
.pay__qr img { width: 168px; height: 168px; border: 1px solid var(--border); border-radius: 10px; padding: 8px; background: #fff; }
.shared-bill__foot { margin-top: 22px; }

@media (max-width: 520px) {
  .shared-bill { padding: 22px 16px 40px; }
  .shared-bill__total { align-items: flex-start; }
  .shared-bill__actions .lp-btn { flex: 1 1 100%; }
}

/* The share link on a bill: a field wide enough to read, with its actions beside it. */
.share-row label { display: block; font-size: 12px; font-weight: 600; margin-bottom: 6px; }
.share-row__field { display: flex; gap: 8px; align-items: center; }
.share-row__field input { flex: 1; min-width: 0; font-size: 13px; color: var(--muted); }
.share-row__field .btn { flex-shrink: 0; }
.share-row .hint { display: block; margin-top: 8px; }
/* The send button is the point of this row, so it sits under the link on a
   line of its own rather than competing with Copy and Open for width. */
.share-row__send { display: flex; gap: 10px; align-items: center; margin-top: 10px; }

@media (max-width: 620px) {
  .share-row__field { flex-wrap: wrap; }
  .share-row__field input { flex: 1 1 100%; }
}

/* What a customer sees when a shared link has run out. */
.shared-bill__expired { padding: 48px 0; text-align: center; }
.shared-bill__expired h1 { margin: 0 0 14px; font-size: clamp(24px, 4vw, 34px); letter-spacing: -.02em; }
.shared-bill__expired p { margin: 0 auto 10px; max-width: 46ch; }

/* ---------- What is still owed, on a phone ----------
   Five columns will not fit a 414px window, and left as a table the Remind
   button - the only reason the page exists - sits off the right edge behind a
   sideways drag. The bill's item lines already solve this by stacking, so the
   rows here stack the same way rather than inventing a second answer.

   The number and the button close the card full width: the shopkeeper is
   reading the amount out loud and then pressing send. */
@media (max-width: 700px) {
  .table-wrap:has(.owing) { overflow-x: visible; }

  table:has(.owing), table:has(.owing) tbody { display: block; width: 100%; }
  table:has(.owing) thead { display: none; }

  tr.owing {
    display: grid;
    grid-template-columns: 1fr auto;
    gap: 8px 12px;
    padding: 12px;
    margin: 0 12px 10px;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
  }

  tr.owing td { display: block; padding: 0; border: 0; text-align: left; }

  tr.owing td::before {
    content: attr(data-label);
    display: block;
    margin-bottom: 3px;
    font-size: 11px;
    font-weight: 600;
    color: var(--muted);
  }

  /* The bill number reads as one token or not at all - broken over three lines
     it is unusable for reading out to a customer. */
  tr.owing td:first-child { white-space: nowrap; }

  tr.owing td.owing__due {
    grid-column: 1;
    padding-top: 8px;
    border-top: 1px solid var(--border);
    font-size: 17px;
    font-weight: 650;
  }

  tr.owing td.owing__ask {
    grid-column: 2;
    align-self: end;
    padding-top: 8px;
    border-top: 1px solid var(--border);
  }
  tr.owing td.owing__ask::before { display: none; }
  tr.owing td.owing__ask .btn { width: 100%; }
}

/* Label and value, side by side. The app reaches for a table nearly everywhere,
   but a shop's settings are pairs rather than rows and a one-column table reads
   as a table with something missing. */
.pairs { display: grid; grid-template-columns: auto 1fr; gap: 8px 16px; margin: 0; }
.pairs dt { color: var(--muted); font-size: 13px; }
.pairs dd { margin: 0; text-align: right; font-weight: 550; }


/* Signature, the way Vyapar offers it: a dashed box to sign in, Create or Upload. */
.signature-box {
  border: 1.5px dashed var(--border-strong); border-radius: var(--radius-sm);
  background: var(--surface-sunken); min-height: 120px;
  display: flex; flex-direction: column; align-items: center; justify-content: center; padding: 10px;
}
.signature-box__empty { color: var(--text-soft); display: flex; flex-direction: column; align-items: center; gap: 6px; }
.signature-box__pen { font-size: 22px; width: 44px; height: 44px; border-radius: 50%; background: var(--surface);
  box-shadow: var(--shadow-sm); display: flex; align-items: center; justify-content: center; color: var(--accent); }
.signature-box__image { max-height: 90px; max-width: 100%; }
.signature-box__pad { width: 100%; max-width: 600px; }
.signature-box__pad canvas { width: 100%; height: auto; background: #fff; border: 1px solid var(--border);
  border-radius: var(--radius-sm); touch-action: none; cursor: crosshair; }
.signature-box__actions, .signature-box__choices { display: flex; gap: 8px; margin-top: 8px; }
.signature-box__choices .btn { min-width: 110px; justify-content: center; }
/* The display rules above would otherwise beat the hidden attribute. */
.signature-box [hidden], .signature-box__choices[hidden] { display: none; }

/* The accountant's login reads and changes nothing; the server refuses any
   change whatever is on screen. This only stops offering what would be
   refused: links that open a form, and every form that posts - a button or a
   whole form, like recording a payment - except signing out. */
.reading-only a[href$="/new"], .reading-only a[href*="/new?"], .reading-only a[href$="/edit"]:not([href$="/password/edit"]),
.reading-only form[method="post"]:not([action$="/session"]):not([action$="/email_verification"]) { display: none; }

/* Signing up: the sign-in card, a little wider for six fields. */
.auth .card.signup { max-width: 440px; }
.signup .field { margin-bottom: 12px; }
.signup__pair { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.signup__submit { width: 100%; justify-content: center; margin-top: 4px; }
.signup__small { display: block; margin-top: 10px; text-align: center; }
.signup__trap { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.auth__switch { text-align: center; margin-top: 16px; font-size: 13.5px; color: var(--muted); }

/* A signed-up shop's trial, and an address still to confirm. */
.account-banner { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 10px; padding: 11px 14px;
  margin-bottom: 14px; border-radius: var(--radius-sm); font-size: 13.5px;
  background: var(--accent-soft); color: var(--text); border: 1px solid #d9ddfb; }
.account-banner--over { background: var(--warn-soft); border-color: #f3dcb4; }
.verify-banner { justify-content: space-between; background: var(--surface); border-color: var(--border); }
.verify-banner form { display: contents; }
.account-banner .code-input, .card .code-input { width: 11ch; letter-spacing: 3px; font-variant-numeric: tabular-nums; }
