/* ChaPayom Shop
   Colour is the shop's own: #104828 is the logo wordmark, #d8e8a0 its leaf.
   Everything here is a tint or shade of those two.
   The chassis is plain modern — one sans, soft neutral surfaces, 14px radii,
   sentence case, weight and size doing the work instead of ornament. */

:root {
  --bg: #f7faf3;
  --auth-bg: #e4ebd8;
  --surface: #ffffff;
  --surface-2: #f0f4ea;
  --card: #ffffff;

  --forest: #104828;
  --forest-mid: #1c6b3c;
  --forest-deep: #0b3319;
  --forest-soft: #e9f5d8;      /* the light tile fill the kit leans on */
  --leaf: #d8e8a0;             /* logo leaf */
  --leaf-bright: #a8e063;      /* the same leaf pushed to the kit's apple green */
  --leaf-deep: #6f9134;

  --brand: #104828;          /* charts read this */
  --gold: #7f9a3c;
  --ink: #11170f;
  --ink-2: #5f6a5c;
  --ink-3: #97a193;
  --rule: #e3e7dd;
  --rule-soft: #edf0e8;

  --good: #1c6b3c;
  --bad: #c0392b;
  /* tinting colours for the calendar: --good/--bad are dark enough to read as
     text but go muddy when diluted, so the fills get their own lighter pair */
  --cal-up: hsl(146 52% 46%);
  --cal-down: hsl(6 76% 62%);
  --good-bg: #e7eee0;
  --bad-bg: #fbeae8;
  --warn: #6d7a33;
  --warn-bg: #f2f6e3;
  /* Cash over is not cash short. Red for money missing, amber for money the
     drawer has too much of — a status pair, so like --good/--bad these stay put
     while the palette moves. --warn is an olive that sits too close to --good to
     carry the difference. */
  --over: #a86a1f;
  --over-bg: #fbf1e0;

  --shadow-sm: 0 1px 2px rgba(17, 23, 15, .04);
  --shadow: 0 4px 16px rgba(17, 23, 15, .05);
  --shadow-lg: 0 16px 44px rgba(17, 23, 15, .16);

  --r-sm: 12px;
  --r: 18px;
  --r-lg: 22px;
  --nav-h: 74px;

  --font: 'IBM Plex Sans Thai', system-ui, -apple-system, sans-serif;
}

:root[data-theme="dark"] {
  --bg: #0f130e;
  --auth-bg: #0b0e0a;
  --surface: #181d16;
  --surface-2: #212719;
  --card: #181d16;

  --forest: #2f7d4d;
  --forest-mid: #3f9260;
  --forest-deep: #0b2415;
  --forest-soft: #1c2b18;
  --leaf: #d8e8a0;
  --leaf-bright: #a8e063;
  --leaf-deep: #b3ca6d;

  --brand: #59a36f;
  --gold: #b3ca6d;
  --ink: #e8ece2;
  --ink-2: #9aa494;
  --ink-3: #6b756a;
  --rule: #2a3026;
  --rule-soft: #232921;
  --cal-up: hsl(146 44% 52%);
  --cal-down: hsl(8 64% 60%);

  --good: #59a36f;
  --bad: #e07b6e;
  --good-bg: #1a2718;
  --bad-bg: #2e1e1b;
  --warn: #b3ca6d;
  --warn-bg: #232919;
  --over: #e0a860;
  --over-bg: #2c2317;

  --shadow-sm: 0 1px 2px rgba(0, 0, 0, .3);
  --shadow: 0 4px 16px rgba(0, 0, 0, .35);
  --shadow-lg: 0 16px 44px rgba(0, 0, 0, .55);
}

* { box-sizing: border-box; }
html { background: var(--bg); -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--ink);
  background: var(--bg);
  min-height: 100vh;
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; -webkit-tap-highlight-color: transparent; border: 0; background: none; }
a { color: var(--forest-mid); }
:focus-visible { outline: 2px solid var(--forest-mid); outline-offset: 2px; border-radius: 8px; }

.icon { width: 21px; height: 21px; flex: none; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
.icon-sm { width: 16px; height: 16px; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }

.kpi strong, .row b, .amount, .total-preview b, .bar-top b, .month-label,
.invest-foot b, .stepper .qty, input[type="number"] { font-variant-numeric: tabular-nums; }

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

.app { min-height: 100vh; padding-bottom: calc(var(--nav-h) + env(safe-area-inset-bottom)); }
.app.auth-locked { display: none; }
.sidebar { display: none; }

.topbar { position: sticky; top: 0; z-index: 20; background: var(--bg); padding: 14px 18px 6px; }
.topline { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.brand { display: flex; align-items: center; gap: 10px; min-width: 0; }
.brand-logo { width: 100px; height: auto; display: block; }
:root[data-theme="dark"] .topbar .brand-logo, :root[data-theme="dark"] .auth-logo { filter: brightness(0) invert(1); }
.brand-copy { display: none; }

.top-actions { display: flex; align-items: center; gap: 4px; }
.chip-btn { display: inline-grid; place-items: center; width: 38px; height: 38px; border-radius: var(--r-sm); color: var(--ink-2); transition: .16s; }
.chip-btn:hover { background: var(--surface-2); color: var(--forest); }

.sync {
  font-size: 11.5px; font-weight: 500; color: var(--ink-2);
  display: inline-flex; align-items: center; gap: 7px; white-space: nowrap;
  background: var(--surface); border: 1px solid var(--rule);
  padding: 7px 12px; border-radius: var(--r-sm);
}
.sync .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--leaf-deep); flex: none; }
.sync.ok .dot { background: var(--good); }
.sync.bad { color: var(--bad); border-color: var(--bad-bg); }
.sync.bad .dot { background: var(--bad); }
.sync.busy .dot { animation: pulse 1.2s ease-in-out infinite; }
@keyframes pulse { 50% { opacity: .25; } }

.month-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 18px; }
.month-row h1 { font-size: 24px; margin: 0; font-weight: 700; letter-spacing: -.025em; }
.month-nav { display: flex; align-items: center; gap: 2px; background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-sm); padding: 3px; }
.month-nav button { width: 30px; height: 30px; border-radius: 7px; color: var(--ink-2); display: grid; place-items: center; }
.month-nav button:hover:not(:disabled) { background: var(--surface-2); color: var(--forest); }
.month-nav button:disabled { opacity: .3; cursor: not-allowed; }
.month-label { font-size: 13px; font-weight: 500; padding: 0 6px; min-width: 100px; text-align: center; position: relative; }
.month-label input { position: absolute; inset: 0; opacity: 0; width: 100%; height: 100%; cursor: pointer; border: 0; padding: 0; min-height: 0; }

.content { padding: 16px 18px 26px; max-width: 1200px; margin: auto; }
.view { display: none; }
.view.active { display: block; animation: rise .22s ease; }
@keyframes rise { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }

/* ---------------- cards ---------------- */

.card { background: var(--card); border: 1px solid var(--rule); border-radius: var(--r-lg); box-shadow: var(--shadow-sm); }
.stack { display: grid; gap: 12px; margin-top: 12px; }
.chart-card, .summary, .form-card, .list-card, .insight, .settings, .panel,
.tally-card { padding: 20px; }

.head { display: flex; justify-content: space-between; align-items: center; gap: 12px; margin-bottom: 18px; }
.head h2, .head h3 { margin: 0; font-size: 17px; font-weight: 600; letter-spacing: -.015em; }
.head .sub { font-size: 12px; color: var(--ink-3); }

/* ---------------- figures ---------------- */

.kpis { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.kpi { padding: 20px; position: relative; }
.kpi > span { font-size: 12.5px; color: var(--ink-2); font-weight: 500; }
.kpi strong { display: block; font-size: 28px; font-weight: 700; margin: 10px 0 4px; line-height: 1.1; letter-spacing: -.035em; }
.kpi small { font-size: 11.5px; color: var(--ink-3); display: block; }

.kpi.feature { background: var(--forest); border-color: var(--forest); color: #fff; grid-column: 1 / -1; padding: 24px; }
.kpi.feature > span { color: rgba(255, 255, 255, .62); }
.kpi.feature small { color: rgba(255, 255, 255, .58); }
.kpi.feature strong { font-size: 44px; font-weight: 700; }
/* a leaf wash bleeding in from the corner, as the kit's promo tiles do */
.kpi.feature { overflow: hidden; }
.kpi.feature:after {
  content: ""; position: absolute; right: -50px; top: -70px;
  width: 190px; height: 190px; border-radius: 50%;
  background: radial-gradient(circle, rgba(168, 224, 99, .22), transparent 70%);
  pointer-events: none;
}

.good { color: var(--good); }
.bad { color: var(--bad); }
.over { color: var(--over); }

.delta {
  display: inline-flex; align-items: center; gap: 5px;
  font-size: 11.5px; font-weight: 500; margin-top: 10px;
  padding: 4px 9px; border-radius: 7px; background: var(--surface-2); color: var(--ink-2);
}
.delta:before { content: ""; border-left: 3.5px solid transparent; border-right: 3.5px solid transparent; }
.delta.up:before { border-bottom: 5px solid currentColor; }
.delta.down:before { border-top: 5px solid currentColor; }
.delta.flat:before { width: 7px; border-top: 1.5px solid currentColor; }
.delta.welcome { background: var(--good-bg); color: var(--good); }
.delta.unwelcome { background: var(--bad-bg); color: var(--bad); }
.kpi.feature .delta.welcome { background: var(--leaf-bright); color: var(--forest-deep); font-weight: 600; }
.kpi.feature .delta.unwelcome { background: rgba(255, 255, 255, .16); color: #fff; }

/* ---------------- rows ---------------- */

.rows { display: grid; }
.row { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; padding: 12px 0; border-bottom: 1px solid var(--rule-soft); font-size: 14px; }
.row:last-child { border-bottom: 0; }
.row span { color: var(--ink-2); }
.row b { white-space: nowrap; font-weight: 600; }
.row.total { font-size: 17px; padding-top: 16px; border-bottom: 0; }
.row.total span { color: var(--ink); font-weight: 600; }
.row.sub-row { padding-top: 0; border-bottom: 0; }
.row.sub-row span { font-size: 11.5px; color: var(--ink-3); }

.pill { padding: 5px 11px; border-radius: 7px; background: var(--surface-2); font-size: 12px; font-weight: 500; color: var(--ink-2); }
.pill.good { background: var(--good-bg); color: var(--good); }
.pill.bad { background: var(--bad-bg); color: var(--bad); }

/* ---------------- target ---------------- */

.goal { margin-top: 18px; }
.goal-bar { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; margin: 10px 0 9px; }
.goal-bar { height: 8px; }
.goal-fill { height: 100%; border-radius: 999px; background: linear-gradient(90deg, var(--forest), var(--leaf-bright)); transition: width .5s ease; }
.goal-meta { display: flex; justify-content: space-between; align-items: center; gap: 10px; font-size: 11.5px; color: var(--ink-3); }
.goal-meta > span:last-child { display: inline-flex; align-items: center; gap: 10px; white-space: nowrap; }
.goal-edit { font-size: 11.5px; font-weight: 500; color: var(--forest); background: var(--forest-soft); border-radius: 7px; padding: 5px 11px; }
.goal-edit:hover { background: var(--forest); color: #fff; }

.stock-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: 18px; padding-top: 14px; border-top: 1px solid var(--rule-soft); font-size: 12px; color: var(--ink-3); }

/* ---------------- proportions ---------------- */

.bars { display: grid; gap: 14px; }
.bar-item { display: grid; gap: 7px; }
.bar-top { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; }
.bar-top b { font-weight: 600; }
.bar-top .pct { color: var(--ink-3); font-size: 11.5px; margin-left: 7px; }
.bar-track { height: 6px; border-radius: 999px; background: var(--surface-2); overflow: hidden; }
.bar-fill { height: 100%; border-radius: 999px; transition: width .5s ease; }

.chart-wrap { height: 255px; position: relative; }

.seg { display: inline-flex; background: var(--surface-2); border-radius: var(--r-sm); padding: 3px; gap: 2px; }
.seg button { font-size: 12px; font-weight: 500; padding: 7px 12px; border-radius: 7px; color: var(--ink-2); }
.seg button.on { background: var(--surface); color: var(--forest); box-shadow: var(--shadow-sm); }
/* dark green on a dark surface — the selected tab was the hardest to read */
:root[data-theme="dark"] .seg button.on { color: var(--leaf); }

/* ---------------- notes ---------------- */

.insight { background: var(--forest-soft); border-color: transparent; }
.insight h3 { margin: 0; font-size: 16px; font-weight: 600; }
.insight p { margin: 9px 0 0; line-height: 1.75; font-size: 13.5px; color: var(--ink-2); }

.notice { display: flex; gap: 11px; align-items: flex-start; padding: 13px 15px; border-radius: var(--r-sm); font-size: 12.5px; line-height: 1.65; margin-top: 14px; background: var(--warn-bg); color: var(--warn); }
.notice .icon { width: 17px; height: 17px; margin-top: 1px; }
.notice b { display: block; margin-bottom: 3px; }

/* ---------------- forms ---------------- */

.form-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px 14px; }
.field { display: grid; gap: 5px; min-width: 0; }
.field.wide { grid-column: 1 / -1; }
.field label { font-size: 12px; color: var(--ink-2); font-weight: 500; }

input, select, textarea {
  width: 100%; border: 1px solid transparent; border-radius: var(--r-sm);
  padding: 9px 13px; background: var(--surface-2); color: var(--ink);
  /* 42 was two pixels short of a fingertip, and a form field is as much a tap
     target as a button is */
  outline: none; min-height: 44px; transition: background-color .16s, border-color .16s;
}
/* the spinners only get in the way — these fields take numbers by keypad */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; }
input::placeholder, textarea::placeholder { color: var(--ink-3); }
input:focus, select:focus, textarea:focus { background: var(--surface); border-color: var(--forest-mid); }

input[type="date"], input[type="month"] {
  -webkit-appearance: none; appearance: none;
  min-width: 0; width: 100%; max-width: 100%; display: block; text-align: left; overflow: hidden;
}
input[type="date"]::-webkit-date-and-time-value,
input[type="month"]::-webkit-date-and-time-value { text-align: left; min-width: 0; max-width: 100%; margin: 0; }
input[type="date"]::-webkit-calendar-picker-indicator,
input[type="month"]::-webkit-calendar-picker-indicator { flex: none; margin-left: auto; opacity: .4; }

select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%235f6a5c' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 13px center; padding-right: 36px;
}

.money-field { position: relative; }
.money-field input { padding-left: 30px; }
.money-field:before { content: "฿"; position: absolute; left: 14px; top: 50%; transform: translateY(-50%); color: var(--ink-3); pointer-events: none; }

.primary, .secondary, .danger, .ghost {
  border-radius: var(--r-sm); padding: 11px 18px; font-weight: 500; font-size: 14px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: background-color .16s, color .16s, border-color .16s, transform .12s;
}
.primary:active, .secondary:active, .danger:active, .ghost:active { transform: scale(.99); }
.primary { background: var(--forest); color: #fff; width: 100%; margin-top: 16px; min-height: 46px; }
.primary:hover { background: var(--forest-mid); }
.primary:disabled { opacity: .5; cursor: progress; }
.secondary { background: var(--forest-soft); color: var(--forest); }
.secondary:hover { background: var(--forest); color: #fff; }
.danger { background: var(--bad-bg); color: var(--bad); }
.ghost { background: var(--surface-2); color: var(--ink-2); }
.ghost:hover { background: var(--rule); color: var(--ink); }
.actions { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.hint { font-size: 12px; color: var(--ink-3); line-height: 1.7; margin: 16px 0 0; }

.total-preview {
  display: flex; justify-content: space-between; align-items: center;
  margin-top: 18px; padding: 15px 17px; border-radius: var(--r);
  background: var(--forest-soft); font-size: 13px; font-weight: 500; color: var(--forest);
}
.total-preview b { font-size: 23px; letter-spacing: -.03em; font-weight: 600; }

.quick { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 5px; }
.quick button { font-size: 12.5px; font-weight: 500; padding: 8px 13px; border-radius: 8px; background: var(--surface-2); color: var(--ink-2); }
.quick button:hover { background: var(--forest-soft); color: var(--forest); }

/* ---------------- cash check ---------------- */

/* the sum is presented, not asked for */
.expect {
  display: grid; gap: 2px; margin: 14px 0 16px;
  padding: 14px 16px; border-radius: var(--r);
  background: var(--forest-soft); color: var(--forest);
}
.expect span { font-size: 12px; font-weight: 500; }
.expect b { font-size: 26px; font-weight: 700; letter-spacing: -.03em; }
.expect small { font-size: 11px; color: var(--leaf-deep); }

.count-field label { font-size: 14px; color: var(--ink); font-weight: 600; }
.count-field input { min-height: 54px; font-size: 22px; font-weight: 600; }
.count-field .money-field:before { font-size: 18px; }

.verdict {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  margin-top: 14px; padding: 14px 16px; border-radius: var(--r);
}
.verdict span { font-size: 14px; font-weight: 600; }
.verdict b { font-size: 24px; font-weight: 700; letter-spacing: -.03em; }
.verdict.ok { background: var(--good-bg); color: var(--good); }
.verdict.off { background: var(--bad-bg); color: var(--bad); }
.verdict.over { background: var(--over-bg); color: var(--over); }

.float-log { margin-top: 14px; padding: 12px 14px; border-radius: var(--r); background: var(--surface-2); }
.float-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 8px; }
.float-head span { font-size: 12px; font-weight: 600; color: var(--ink-2); }
.float-row { display: grid; grid-template-columns: 1fr auto auto; gap: 10px; align-items: center; padding: 7px 0; border-bottom: 1px solid var(--rule-soft); }
.float-row:last-child { border-bottom: 0; }
.float-row span { font-size: 12.5px; color: var(--ink-2); }
.float-row b { font-size: 14px; font-weight: 600; }
.float-empty { font-size: 12px; color: var(--ink-3); padding: 4px 0; }

.tweak { margin-top: 16px; }
.tweak summary { cursor: pointer; font-size: 12.5px; color: var(--ink-3); list-style: none; }
.tweak summary::-webkit-details-marker { display: none; }
.tweak summary:before { content: "▸ "; }
.tweak[open] summary:before { content: "▾ "; }

/* ---------------- lists ---------------- */

.toolbar { display: flex; gap: 8px; margin-bottom: 10px; }
.toolbar .search { position: relative; flex: 1; }
.toolbar .search .icon { position: absolute; left: 12px; top: 50%; transform: translateY(-50%); color: var(--ink-3); width: 16px; height: 16px; }
/* the kit's search is a full pill */
.toolbar .search input { padding-left: 38px; min-height: 42px; border-radius: 999px; }
.toolbar .search .icon { left: 15px; }
.toolbar select { max-width: 150px; min-height: 44px; border-radius: 999px; padding-left: 15px; }

.list { display: grid; gap: 2px; }
.item { padding: 13px 12px; display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center; border-radius: var(--r-sm); transition: background-color .14s; }
.item:hover { background: var(--surface-2); }
.item-main { min-width: 0; text-align: left; background: none; }
.item-main b { display: block; font-size: 14px; font-weight: 500; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.item-main small { color: var(--ink-3); font-size: 11.5px; display: block; margin-top: 2px; }
.item-side { display: flex; align-items: center; gap: 10px; }
.item .amount { font-weight: 600; font-size: 14px; white-space: nowrap; }
.item .amount.over { color: var(--over); }
.icon-btn { border-radius: 8px; padding: 7px; color: var(--ink-3); display: grid; place-items: center; }
.icon-btn:hover { background: var(--bad-bg); color: var(--bad); }
.tag { font-size: 11px; font-weight: 500; padding: 2px 8px; border-radius: 6px; background: var(--surface-2); }

.empty { text-align: center; color: var(--ink-3); padding: 36px 14px; font-size: 13.5px; line-height: 1.75; }
.empty .icon { width: 28px; height: 28px; color: var(--rule); margin-bottom: 9px; }

/* ---------------- bottom nav ---------------- */

.bottom-nav {
  position: fixed; z-index: 30; left: 0; right: 0; bottom: 0;
  /* Columns follow the number of buttons rather than the owner app's six —
     the staff page has four, and a fixed six left two dead columns on the right. */
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr;
  background: var(--surface); border-top: 1px solid var(--rule);
  padding: 6px 8px; padding-bottom: max(6px, env(safe-area-inset-bottom));
}
.nav-btn {
  color: var(--ink-3); border-radius: var(--r-sm); padding: 8px 1px;
  font-size: 9.5px; font-weight: 500; white-space: nowrap;
  display: grid; gap: 4px; place-items: center; min-height: 56px; transition: .16s;
}
.nav-btn.active { background: var(--forest); color: #fff; }
:root[data-theme="dark"] .nav-btn.active { color: #06231a; }

/* ---------------- toast ---------------- */

.toast {
  position: fixed; z-index: 60; left: 16px; right: 16px;
  bottom: calc(var(--nav-h) + 14px + env(safe-area-inset-bottom));
  opacity: 0; pointer-events: none; transform: translateY(6px);
  background: var(--ink); color: var(--bg);
  border-radius: var(--r); padding: 13px 16px; transition: .2s;
  display: flex; align-items: center; gap: 14px; font-size: 13.5px;
  max-width: 440px; margin: 0 auto; box-shadow: var(--shadow-lg);
}
.toast.show { opacity: 1; transform: none; pointer-events: auto; }
.toast span { flex: 1; }
.toast button { color: var(--leaf); font-weight: 600; font-size: 13px; white-space: nowrap; }

/* ---------------- sheet ---------------- */

.backdrop { position: fixed; inset: 0; z-index: 70; background: rgba(11, 35, 21, .42); backdrop-filter: blur(2px); display: grid; place-items: end center; opacity: 0; pointer-events: none; transition: opacity .2s; }
.backdrop.show { opacity: 1; pointer-events: auto; }
.sheet {
  width: min(450px, 100%); background: var(--surface);
  border-radius: var(--r-lg) var(--r-lg) 0 0; padding: 22px 20px calc(22px + env(safe-area-inset-bottom));
  transform: translateY(100%); transition: transform .26s cubic-bezier(.32, .72, 0, 1);
  max-height: 92vh; overflow-y: auto; box-shadow: var(--shadow-lg);
}
.backdrop.show .sheet { transform: none; }
.sheet-grip { width: 36px; height: 4px; border-radius: 999px; background: var(--rule); margin: -6px auto 16px; }
.sheet h3 { margin: 0 0 6px; font-size: 18px; font-weight: 600; letter-spacing: -.015em; }
.sheet p { margin: 0 0 18px; color: var(--ink-2); font-size: 13.5px; line-height: 1.65; }

/* ---------------- sign in ---------------- */

/* The page background, not the brand green: the card is what should carry the
   colour here. --bg rather than a literal, so it follows the palette and does
   not strand a light screen behind a dark card in dark mode. */
.auth-screen {
  position: fixed; inset: 0; z-index: 100; display: grid; place-items: center;
  padding: 20px; overflow: auto; background: var(--auth-bg);
}
.auth-screen.hidden { display: none; }
.auth-card {
  width: min(380px, 100%); background: var(--surface);
  border: 1px solid var(--rule-soft);
  border-radius: var(--r-lg); padding: 28px 24px 24px;
  /* the heavy drop was needed against the dark green; on a pale background it
     only muddies the edge, so the border does the separating now */
  box-shadow: 0 12px 32px -18px rgba(0,0,0,.22);
}
.auth-brand { display: grid; place-items: center; text-align: center; margin-bottom: 18px; }
.auth-card h1 { font-size: 21px; margin: 0; font-weight: 600; letter-spacing: -.02em; }
.auth-card p { color: var(--ink-2); margin: 2px 0 0; font-size: 13px; line-height: 1.55; }
.auth-brand p span { white-space: nowrap; }
.auth-card .field { margin-top: 14px; }
.auth-card input { min-height: 48px; }
.auth-card .primary { margin-top: 18px; min-height: 50px; font-size: 15px; }

/* label on the left, its shortcut on the right — the link belongs to the field
   it acts on, not to the gap above the submit button */
.field-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.field-head .link-btn { margin: 0; padding: 0; font-size: 12px; }

/* silent until it has something to say, so the form does not carry a gap */
.auth-error { color: var(--bad); font-size: 13px; margin-top: 10px; text-align: center; line-height: 1.5; }
.auth-error:empty { display: none; }
.pw-wrap { position: relative; }
.pw-wrap input { padding-right: 46px; }
.pw-toggle { position: absolute; right: 5px; top: 50%; transform: translateY(-50%); padding: 9px; color: var(--ink-3); border-radius: 8px; }
.pw-toggle:hover { color: var(--forest); }

/* ---------------- investment editor ---------------- */

.invest-list { display: grid; gap: 8px; }
.invest-row { display: grid; grid-template-columns: 1fr 128px auto; gap: 8px; align-items: center; }
.invest-row input { min-height: 40px; }
.invest-foot { display: flex; justify-content: space-between; align-items: center; gap: 10px; margin-top: 14px; font-size: 12.5px; color: var(--ink-2); }
.invest-foot b { font-size: 18px; color: var(--ink); font-weight: 600; }
.invest-foot .ghost { padding: 9px 14px; font-size: 12.5px; }
.invest-detail { margin-top: 16px; border-top: 1px solid var(--rule-soft); padding-top: 14px; }
.invest-detail summary { cursor: pointer; font-size: 12.5px; font-weight: 500; color: var(--forest); list-style: none; }
.invest-detail summary::-webkit-details-marker { display: none; }
.invest-detail summary:before { content: "▸ "; }
.invest-detail[open] summary:before { content: "▾ "; }

/* ---------------- menu tally ---------------- */

.menu-list { display: grid; gap: 2px; max-height: 46vh; overflow-y: auto; margin-top: 10px; }
.menu-row { display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: center; padding: 10px 12px; border-radius: var(--r-sm); }
.menu-row.on { background: var(--forest-soft); }
.menu-row b { display: block; font-size: 14px; font-weight: 500; }
.menu-row small { color: var(--ink-3); font-size: 11.5px; }
.stepper { display: flex; align-items: center; gap: 6px; }
.stepper button { width: 34px; height: 34px; border-radius: 9px; background: var(--surface-2); color: var(--forest); display: grid; place-items: center; }
.stepper button:hover:not(:disabled) { background: var(--forest); color: #fff; }
.stepper button:disabled { opacity: .35; }
.stepper .qty { min-width: 24px; text-align: center; font-weight: 600; }
.picked { display: flex; flex-wrap: wrap; gap: 6px; margin-top: 11px; }
.picked span { font-size: 12px; font-weight: 500; padding: 5px 10px; border-radius: 7px; background: var(--forest-soft); color: var(--forest); }

/* ---------------- wide ---------------- */

@media (min-width: 860px) {
  .app { display: grid; grid-template-columns: 226px 1fr; padding-bottom: 0; }
  .sidebar { display: flex; position: sticky; top: 0; height: 100vh; flex-direction: column; padding: 22px 14px; background: var(--surface); border-right: 1px solid var(--rule); }
  /* The shop name was sharing a 197px row with a 124px logo, which left it 41px
     and a border to be truncated inside — "ชาพะยอม" came out as "ชา…". Below the
     logo it gets the whole sidebar. */
  .sidebar .brand { margin-bottom: 28px; padding: 0 10px; flex-direction: column; align-items: flex-start; gap: 0; }
  .sidebar .brand-logo { width: 124px; }
  .sidebar .brand-shop {
    max-width: 100%; border-left: 0; padding-left: 0; margin: 7px 0 0; font-size: 12px;
  }

  /* Settings is a column of forms, not a dashboard: stretched to 1200px the tab
     row gave four short words 285px each and every full-width button in a card
     became a metre long. */
  #settings { max-width: 760px; }
  :root[data-theme="dark"] .sidebar .brand-logo { filter: brightness(0) invert(1); }
  .side-nav { display: grid; gap: 3px; }
  .side-nav .nav-btn { display: flex; justify-content: flex-start; gap: 12px; font-size: 13.5px; padding: 11px 13px; min-height: 0; }
  .side-nav .nav-btn.active { background: var(--forest); color: #fff; }
  .side-foot { margin-top: auto; color: var(--ink-3); font-size: 11px; line-height: 1.7; padding: 0 12px; }
  .topbar { padding: 20px 30px 6px; }
  .topbar .brand { display: none; }
  .content { padding: 20px 30px 44px; }
  .bottom-nav { display: none; }
  .kpis { grid-template-columns: repeat(3, 1fr); gap: 12px; }
  .kpi.feature { grid-column: 1 / -1; }
  .kpi.feature strong { font-size: 54px; }
  .kpi strong { font-size: 30px; }
  .stack.two { grid-template-columns: 1.6fr 1fr; }
  .stack.three { grid-template-columns: 1fr 1fr; }
  .split { display: grid; grid-template-columns: 370px 1fr; gap: 12px; align-items: start; }
  .chart-wrap { height: 325px; }
  .toast { left: auto; right: 30px; bottom: 26px; }
  .month-row h1 { font-size: 27px; }
}

@media (max-width: 859px) {
  .kpi.wide { grid-column: 1 / -1; }
}

/* Phones do the real work here, so the first screen has to carry the whole
   picture: takings, profit, orders, spend and progress against target, with no
   scrolling. Everything below is about buying back vertical space. */
@media (max-width: 859px) {
  .content { padding: 12px 14px 20px; }
  .chart-card, .summary, .form-card, .list-card, .insight, .settings, .panel,
  .tally-card { padding: 15px; }
  .stack { gap: 10px; margin-top: 10px; }
  .head { margin-bottom: 12px; }
  .split { display: grid; gap: 10px; }
  .month-row { margin-top: 12px; }
  .month-row h1 { font-size: 20px; }
  .topbar { padding: 12px 14px 4px; }
  .brand-logo { width: 88px; }
  .sync .label { display: none; }
  .sync { padding: 7px; }

  /* takings lead, the other three run as a compact strip beneath */
  .kpis { grid-template-columns: repeat(3, 1fr); gap: 8px; }
  .kpi { padding: 12px 10px; }
  .kpi > span { font-size: 10.5px; line-height: 1.3; }
  .kpi strong { font-size: 17px; margin: 5px 0 2px; letter-spacing: -.03em; }
  .kpi small { font-size: 10px; line-height: 1.35; }
  .kpi.wide { grid-column: auto; }
  /* the month-on-month pills are the first thing to go — they are on the
     takings card already, and detail lives one tap away */
  .kpi:not(.feature) .delta { display: none; }

  .kpi.feature { padding: 16px; }
  .kpi.feature > span { font-size: 12px; }
  .kpi.feature strong { font-size: 32px; margin: 6px 0 3px; }
  .kpi.feature small { font-size: 11px; }
  .kpi.feature .delta { margin-top: 7px; padding: 3px 8px; }

  .chart-wrap { height: 172px; }
  .goal { margin-top: 10px; }
  .goal-bar { margin: 8px 0 7px; }

  /* title and view switch each get their own line rather than fighting for one */
  .chart-card > .head { flex-direction: column; align-items: stretch; gap: 10px; }
  .chart-card > .head h2 { font-size: 16px; }
  .seg { width: 100%; justify-content: space-between; }
  .seg button { flex: 1; white-space: nowrap; padding: 7px 4px; font-size: 11.5px; }

  /* short numeric fields sit two to a row rather than one per line */
  .form-grid { grid-template-columns: 1fr 1fr; gap: 10px; }
  .field label { font-size: 11px; }
  input, select, textarea { min-height: 40px; padding: 8px 12px; font-size: 14.5px; }
  .primary { min-height: 44px; margin-top: 12px; }
  .total-preview { margin-top: 12px; padding: 11px 14px; }
  .total-preview b { font-size: 20px; }

  .item { padding: 10px; }
  .rows .row { padding: 9px 0; }
  .bars { gap: 11px; }

  .invest-row { grid-template-columns: 1fr 96px auto; gap: 6px; }
  .toolbar { flex-wrap: nowrap; margin-bottom: 8px; }
  .toolbar select { max-width: 120px; }
}

@media (max-width: 380px) {
  .kpi strong { font-size: 16px; }
  .kpi > span { font-size: 10px; }
  .kpi small { font-size: 9.5px; line-height: 1.3; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
}

/* ---------------- SaveCost brand ---------------- */

.brand-mark { width: 26px; height: 26px; color: var(--forest); stroke-width: 1.9; }
.brand-name { font-size: 19px; font-weight: 700; letter-spacing: -.03em; color: var(--forest); }
.brand-shop {
  font-size: 12.5px; color: var(--ink-2); font-weight: 500;
  padding-left: 10px; margin-left: 2px; border-left: 1px solid var(--rule);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 40vw;
}
.brand-shop:empty { display: none; }

.auth-mark {
  width: 60px; height: 60px; margin: 0 auto 16px; border-radius: 20px;
  display: grid; place-items: center;
  background: var(--forest); color: var(--leaf);
}
.auth-mark .icon { width: 30px; height: 30px; stroke-width: 1.8; }

.auth-switch { margin: 14px 0 0; text-align: center; font-size: 13.5px; color: var(--ink-2); }
.auth-switch button {
  color: var(--forest-mid); font-weight: 600; padding: 4px 2px;
  text-decoration: underline; text-underline-offset: 3px;
}

/* import preview */
/* pre-line so a body that separates "what happens" from "how to undo it" with a
   blank line actually shows one; every other body is a single paragraph and is
   unaffected */
.sheet p#modalBody { max-height: 46vh; overflow-y: auto; line-height: 1.7; white-space: pre-line; }
.import-warn { color: var(--bad); font-weight: 600; }

/* weekday toggles — a shop can be shut on more than one day */
.day-chips { display: flex; gap: 6px; flex-wrap: wrap; }
/* Seven chips at min-width 40 plus six gaps overflow a 375px phone by a pixel,
   so the last one wrapped onto its own line — and being flex:1 it then stretched
   to the full width. "ส" was a button seven times the size of "ศ" beside it.
   A seven-column grid cannot wrap, so it cannot happen. */
#closedDays { display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; }
#closedDays .day-chip { min-width: 0; }
.day-chip {
  flex: 1 1 0; min-width: 40px; min-height: 44px; padding: 0 4px;
  border-radius: var(--r-sm); border: 1px solid var(--rule);
  background: var(--surface); color: var(--ink-2);
  font-size: 13.5px; font-weight: 600; transition: .14s;
}
.day-chip:hover { border-color: var(--forest-mid); color: var(--forest); }
.day-chip.on {
  background: var(--forest); border-color: var(--forest); color: #fff;
}

/* expense lifespan + payment source */
.tag.spread { background: var(--warn-bg); color: var(--warn); padding: 1px 7px; border-radius: 999px; font-size: 10.5px; }
.tag.cashtag { background: var(--forest-soft); color: var(--forest); padding: 1px 7px; border-radius: 999px; font-size: 10.5px; }
.check-row { display: flex; align-items: center; gap: 10px; font-size: 14px; font-weight: 500; cursor: pointer; min-height: 44px; }
.check-row input { width: 20px; height: 20px; accent-color: var(--forest); flex: none; }
#monthChips .day-chip { font-size: 12.5px; min-width: 58px; }
.custom-days { display: flex; align-items: center; gap: 8px; margin-top: 10px; font-size: 13.5px; color: var(--ink-2); }
.custom-days input { width: 84px; text-align: center; }

/* expense form polish: a scale you can read at a glance */
.quick { display: grid; grid-template-columns: repeat(auto-fit, minmax(74px, 1fr)); gap: 8px; margin-top: 10px; }
.quick button {
  min-height: 44px; border-radius: var(--r-sm); border: 1px solid transparent;
  background: var(--surface-2); color: var(--ink); font-size: 14px; font-weight: 600;
  font-variant-numeric: tabular-nums; transition: .14s;
}
.quick button:hover { border-color: var(--forest-mid); color: var(--forest); }
#monthChips .day-chip { white-space: nowrap; }
#monthsNote:empty, #weighRow[style*="none"] { display: none; }
.check-row { min-height: 40px; }


/* tighten the expense form: three amounts per row, no dead space */
.quick { grid-template-columns: repeat(3, 1fr); }
@media (min-width: 560px) { .quick { grid-template-columns: repeat(6, 1fr); } }
#weighRow { margin-top: 6px !important; }
#monthsNote { margin: 6px 0 0; }
.field .check-row + .hint { margin-top: 4px; }


/* one row, always: five amounts share the width and shrink to fit rather than
   wrapping a lone chip onto a second line */
.quick {
  display: flex; gap: 8px; margin-top: 10px;
  overflow-x: auto; scrollbar-width: none; -webkit-overflow-scrolling: touch;
}
.quick::-webkit-scrollbar { display: none; }
.quick button { flex: 1 1 0; min-width: 0; padding: 0 6px; font-size: 14px; }

/* password recovery */
.link-btn { display: block; margin: -4px auto 12px; color: var(--forest-mid); font-size: 13px; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; padding: 6px; }
.auth-error.ok { color: var(--good); }
.auth-error.ok { color: var(--good); }
.paste-row { margin: 4px 0 14px; display: grid; gap: 8px; }
.paste-row label { font-size: 12.5px; color: var(--ink-2); line-height: 1.5; }

/* a field and the button that acts on it must not touch */
form .field + button, form .field + .actions, .form-card .field:last-of-type + button { margin-top: 14px; }
#newPassForm .field { margin-bottom: 14px; }
.staff-body .empty { color: var(--ink-3); font-size: 13.5px; text-align: center; padding: 18px 0; }
.staff-body .empty { color: var(--ink-3); font-size: 13.5px; text-align: center; padding: 18px 0; }

/* delivery, one box per platform */
.deli-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.deli-grid > label { display: grid; gap: 5px; }
.deli-grid > label > span { font-size: 12px; color: var(--ink-2); font-weight: 500; }
.deli-grid > label > span { font-size: 12px; color: var(--ink-2); font-weight: 500; }

/* delivery opens in a sheet so the form stays one screen */
.deli-open {
  width: 100%; min-height: 46px; display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 0 14px; border-radius: var(--r-sm); border: 1px solid var(--rule);
  background: var(--surface-2); text-align: left; transition: .14s;
}
.deli-open:hover { border-color: var(--forest-mid); }
.deli-open b { font-size: 16px; font-variant-numeric: tabular-nums; }
.deli-open span { font-size: 12px; color: var(--ink-2); }
#deliSheet .deli-grid { margin-bottom: 4px; }
/* ---------------- the year ---------------- */

.year-nav {
  display: flex; align-items: center; justify-content: center; gap: 4px;
  background: var(--surface); border: 1px solid var(--rule); border-radius: var(--r-sm);
  padding: 4px; margin-bottom: 12px;
}
.year-nav b { font-size: 15px; font-weight: 700; min-width: 88px; text-align: center; font-variant-numeric: tabular-nums; }
.year-nav button { width: 34px; height: 34px; border-radius: 8px; color: var(--ink-2); display: grid; place-items: center; }
.year-nav button:hover:not(:disabled) { background: var(--surface-2); color: var(--forest); }
.year-nav button:disabled { opacity: .3; cursor: not-allowed; }

.year-table { display: grid; gap: 2px; }
.year-row {
  display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: 8px; align-items: center;
  width: 100%; text-align: right; padding: 12px 10px; border-radius: var(--r-sm);
  background: none; border: 0; font: inherit; color: inherit;
}
.year-row > span:first-child { text-align: left; display: grid; gap: 2px; }
.year-row b { font-size: 14px; font-weight: 600; }
.year-row small { display: block; font-size: 10.5px; color: var(--ink-3); font-weight: 400; }
.year-row:not(.head) { cursor: pointer; transition: .14s; font-variant-numeric: tabular-nums; }
.year-row:not(.head):hover { background: var(--surface-2); }
.year-row.head { font-size: 11.5px; color: var(--ink-3); font-weight: 600; padding-bottom: 6px; cursor: default; }
.year-row.head > span:first-child { text-align: left; }

/* the month picker means nothing on a page that shows the whole year */
.app.year-view .month-nav { display: none; }
.bottom-nav .nav-btn .icon { width: 19px; height: 19px; }

/* the year page, compacted: header carries the picker, tiles share a row,
   and the summary is a line under the table rather than a card of its own */
.year-nav { display: none; margin: 0; padding: 3px; }
.app.year-view .year-nav { display: flex; }
.year-nav b { min-width: 62px; font-size: 13.5px; }
.year-nav button { width: 30px; height: 30px; }
.year-kpis { grid-template-columns: repeat(3, 1fr); }
.year-kpis .kpi { padding: 13px 12px; }
.year-kpis .kpi strong { font-size: 19px; margin: 5px 0 2px; }
.year-kpis .kpi > span { font-size: 11.5px; }
.year-kpis .kpi small { font-size: 10px; }
.app.year-view .chart-wrap { height: 168px; }
.year-row { padding: 9px 10px; }
.year-note { margin: 10px 0 0; font-size: 12.5px; color: var(--ink-2); line-height: 1.6; }

/* the year's sales tile wears the same green as the dashboard's, but has to
   stay one of three in a row rather than spanning the width */
/* Laid out like the overview: the headline spans the width, the supporting
   figures sit in a row beneath. Three tiles used to share one row here to save
   height, but a fourth left an orphan hanging on its own. */
.year-kpis .kpi.feature { grid-column: 1 / -1; padding: 16px 16px; }
.year-kpis .kpi.feature strong { font-size: 30px; margin: 6px 0 3px; }
.year-kpis .kpi.feature > span { font-size: 12.5px; }
.year-kpis .kpi.feature small { font-size: 11.5px; }
.year-kpis .kpi.feature:after { right: -40px; top: -56px; width: 150px; height: 150px; }

/* A slim rule under each row, as wide as that month's share of the best one:
   the shape of the year reads at a glance and nothing crosses the figures.
   A full-height tint was tried first and swamped them — most months are within
   a few percent of each other, so it just filled every row. */
.year-row { position: relative; }
.year-row:not(.head):after {
  content: ""; position: absolute; left: 10px; right: 10px; bottom: 3px; height: 4px;
  border-radius: 999px; background: var(--surface-2);
}
.year-row:not(.head):before {
  content: ""; position: absolute; left: 10px; bottom: 3px; height: 4px; z-index: 1;
  width: calc((100% - 20px) * var(--fill-n, 0)); border-radius: 999px;
  /* the same sweep the monthly goal bar uses, so the two read as one idea */
  background: linear-gradient(90deg, var(--forest), var(--leaf-bright));
  transition: width .3s ease;
}
.year-row:not(.head):hover { background: var(--surface-2); }

/* the summary reads as three facts rather than one long sentence */
.year-note { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 14px; }
.year-chip {
  flex: 1 1 auto; display: grid; gap: 1px; padding: 8px 12px;
  background: var(--surface-2); border-radius: var(--r-sm); min-width: 96px;
}
.year-chip small { font-size: 10.5px; color: var(--ink-3); }
.year-chip b { font-size: 13.5px; font-weight: 600; }
.year-chip i { font-style: normal; font-size: 11.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.year-chip i { font-style: normal; font-size: 11.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }

/* the shop's logo */
.logo-row { display: flex; align-items: center; gap: 14px; }
.logo-preview {
  width: 76px; height: 76px; flex: none; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--rule);
  display: grid; place-items: center; overflow: hidden;
}
.logo-preview img { width: 100%; height: 100%; object-fit: contain; }
.logo-preview span { font-size: 11px; color: var(--ink-3); }
.logo-actions { display: grid; gap: 8px; flex: 1; }
.logo-actions button { width: 100%; }

/* an uploaded logo can be any shape, so it is fitted rather than trusted */
.brand-logo { max-width: 108px; max-height: 40px; width: auto; height: auto; object-fit: contain; }

/* colour picker: each swatch shows the pair the palette is built from */
/* Six palettes on one row whatever the screen: a fixed width wrapped 5+1 on a
   phone, which read as a mistake rather than a choice. */
.palette-row { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; }
.palette-row button {
  display: grid; gap: 6px; justify-items: center;
  background: none; padding: 0; transition: transform .16s;
}
.palette-row .sw-face {
  width: 100%; aspect-ratio: 1; border-radius: 50%;
  box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .07), var(--shadow-sm);
  transition: box-shadow .18s, transform .18s;
}
.palette-row .sw-name {
  font-size: 10.5px; font-weight: 500; color: var(--ink-3);
  white-space: nowrap; transition: color .16s;
}
.palette-row button:hover { transform: translateY(-2px); }

/* the ring is drawn in the palette's own accent, so the selected state says
   which colour was chosen rather than just that something was */
.palette-row button.on .sw-face {
  box-shadow: 0 0 0 2.5px var(--surface), 0 0 0 4.5px var(--sw), var(--shadow-sm);
}
.palette-row button.on .sw-name { color: var(--ink); font-weight: 700; }

@media (max-width: 380px) {
  .palette-row { gap: 7px; }
  .palette-row .sw-name { font-size: 9.5px; }
}

/* ---------------- calendar ----------------

   The chart says how the month went; the calendar says which days. Cells are
   tinted by --w, the day's profit as a fraction of the month's best day, so a
   slow stretch reads as a pale band without anyone comparing numbers. */

[hidden] { display: none !important; }

.calendar { padding-top: 2px; }

.cal-heads, .cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-heads { margin-bottom: 6px; }
.cal-heads span {
  text-align: center; font-size: 11px; font-weight: 600;
  color: var(--ink-3); letter-spacing: .02em;
}

.cal-cell {
  aspect-ratio: 1 / 1.12; border-radius: 11px; padding: 5px 2px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 1px; background: var(--surface-2); border: 1px solid transparent;
  text-align: center; overflow: hidden; transition: transform .13s, box-shadow .13s;
}
.cal-cell.empty { background: none; }
.cal-cell.blank { background: color-mix(in oklab, var(--surface-2) 55%, var(--card)); }
.cal-cell.blank b { color: var(--ink-3); font-weight: 500; }

/* the day number is a label, not a figure — let the money carry the weight */
.cal-cell b { font-size: 10.5px; font-weight: 500; color: var(--ink-3); line-height: 1.2; }
.cal-cell.up b, .cal-cell.down b { color: var(--ink-2); }
.cal-cell span {
  font-size: 12.5px; font-weight: 700; line-height: 1.2;
  font-variant-numeric: tabular-nums; letter-spacing: -.025em;
}
.cal-cell i {
  font-style: normal; font-size: 9.5px; font-weight: 500;
  color: var(--ink-3); line-height: 1.1;
}
/* the cup line wraps and loses its unit in a cell this narrow — keep every
   line on one row and let it shrink instead */
.cal-cell b, .cal-cell span, .cal-cell i { white-space: nowrap; max-width: 100%; }

/* Mixed into the card rather than --surface-2: that token is a green-grey, and
   pushing red through it lands on clay. oklab keeps the middle of the ramp as
   clean as its ends, which sRGB interpolation does not. The floor keeps a
   barely-profitable day tinted rather than blank. */
.cal-cell.up   { background: color-mix(in oklab, var(--cal-up)   calc(11% + var(--w) * 44%), var(--card)); }
.cal-cell.down { background: color-mix(in oklab, var(--cal-down) calc(11% + var(--w) * 40%), var(--card)); }
/* --forest is dark in both themes, which vanishes against a dark-mode cell;
   --good and --bad already flip per theme, so read against either background */
.cal-cell.up span   { color: var(--good); }
.cal-cell.down span { color: var(--bad); }
.cal-cell.up:hover, .cal-cell.down:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
/* today gets a ring rather than a fill, so it reads without competing with the
   profit tint underneath it */
.cal-cell.today { box-shadow: inset 0 0 0 1.5px var(--forest); }
:root[data-theme="dark"] .cal-cell.today { box-shadow: inset 0 0 0 1.5px var(--leaf-deep); }

/* the month's verdict, above the grid where it is read first */
.cal-sum {
  display: flex; align-items: baseline; flex-wrap: wrap; gap: 4px 12px;
  padding: 0 2px 10px; margin-bottom: 8px; border-bottom: 1px solid var(--rule-soft);
}
.cal-sum-side {
  display: flex; align-items: center; flex-wrap: wrap; gap: 3px 12px;
  font-size: 11.5px; color: var(--ink-3);
}
.cal-sum-side span { display: inline-flex; align-items: center; gap: 4px; }
.cal-sum-side .sw { width: 9px; height: 9px; border-radius: 3px; flex: none; }
.cal-sum-side .sw.up { background: var(--cal-up); }
.cal-sum-side .sw.down { background: var(--cal-down); }

/* a day the shop was shut reads differently from one that has not happened */
.cal-cell.closed { background: var(--surface-2); }
.cal-cell.closed b { color: var(--ink-3); }
.cal-cell.future { background: color-mix(in oklab, var(--surface-2) 40%, var(--card)); }
.cal-cell.future b { color: color-mix(in oklab, var(--ink-3) 55%, transparent); }

.cal-key {
  display: flex; align-items: center; flex-wrap: wrap; gap: 4px 12px;
  margin-top: 10px; font-size: 11px; color: var(--ink-3); line-height: 1.5;
}
.cal-key span { display: inline-flex; align-items: center; gap: 5px; }
.cal-key .sw { width: 10px; height: 10px; border-radius: 3px; flex: none; }
.cal-key .sw.closed { background: var(--surface-2); }
.cal-key .sw.future { background: color-mix(in oklab, var(--surface-2) 40%, var(--card)); border: 1px solid var(--rule-soft); }
.cal-key em { font-style: normal; margin-left: auto; }

/* five modes no longer fit a phone in one row — let the segment scroll */
@media (max-width: 430px) {
  .seg { max-width: 100%; overflow-x: auto; scrollbar-width: none; }
  .seg::-webkit-scrollbar { display: none; }
  .seg button { padding: 7px 9px; white-space: nowrap; }
  .cal-cell span { font-size: 11px; }
  .cal-cell i { font-size: 9px; }
}

/* ---------------- menu management (POS) ----------------

   A list the owner edits at a desk, not a till screen: rows stay compact so a
   long menu is scannable, and the controls that reorder sit together on the
   right rather than hiding behind a swipe. */

.menu-bar { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
.menu-bar .tally-search { flex: 1; min-width: 0; }
.menu-bar .primary { flex: none; width: auto; padding: 11px 14px; font-size: 13px; }

.menu-list { display: grid; gap: 14px; }
.menu-group h3 {
  font-size: 11.5px; font-weight: 600; color: var(--ink-3); margin: 0 0 5px;
  letter-spacing: .02em; display: flex; align-items: center; gap: 6px;
}
.menu-group h3 span {
  font-weight: 500; color: var(--ink-3); background: var(--surface-2);
  border-radius: 999px; padding: 1px 7px; font-size: 10.5px;
}

.menu-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 4px; border-bottom: 1px solid var(--rule-soft);
}
.menu-item:last-child { border-bottom: 0; }
.menu-item.off { opacity: .5; }
.menu-main { flex: 1; min-width: 0; }
.menu-main b {
  display: block; font-size: 14px; font-weight: 500; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.menu-main small { font-size: 11.5px; color: var(--ink-3); }

.menu-tools { display: flex; gap: 3px; flex: none; }
.icon-btn {
  min-width: 32px; height: 32px; border-radius: 8px; font-size: 13px; font-weight: 600;
  background: var(--surface-2); color: var(--ink-2); line-height: 1; padding: 0 7px;
}
.icon-btn:disabled { opacity: .3; }
.icon-btn.edit { background: var(--forest); color: #fff; }
.menu-item.off .icon-btn[data-act="toggle"] { color: var(--ink-3); }

.cat-suggest { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 7px; }
.cat-suggest .chip {
  padding: 5px 10px; border-radius: 999px; font-size: 11.5px; font-weight: 500;
  background: var(--surface-2); color: var(--ink-2);
}

/* the month switcher steers the books, not the product list */
.app.menu-view .month-label,
.app.menu-view #monthPrev,
.app.menu-view #monthNext { display: none; }

.menu-back { padding: 5px 10px; font-size: 12.5px; font-weight: 500; margin-left: -6px; }
/* long Thai hints wrapped past the card's padding */
.menu-list + .hint { overflow-wrap: anywhere; }

/* ---------------- the till (POS) ----------------

   Built for a wet hand and a queue: every target is at least 48px, the running
   total never leaves the screen, and the destructive controls sit away from the
   one that gets pressed hundreds of times a day. */

.pos-wrap { display: grid; gap: 14px; }
.pos-tools { display: flex; gap: 8px; margin-bottom: 10px; }
.pos-tools .tally-search { flex: 1; min-width: 0; }
.pos-tools .secondary { flex: none; padding: 11px 14px; font-size: 13px; white-space: nowrap; }

.pos-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(104px, 1fr)); gap: 8px; }
.pos-card {
  /* photo on top, name and price under it — the same shape whether or not the
     product has a picture, so the rows line up.
     On --surface-2 the card sat at almost exactly the page's own tone and the
     text block under each photo dissolved into it; the card surface plus a
     hairline lifts it off the page instead. */
  padding: 0; overflow: hidden; border-radius: 12px;
  background: var(--surface); border: 1px solid var(--rule-soft);
  box-shadow: var(--shadow-sm);
  display: flex; flex-direction: column;
  text-align: left; transition: transform .1s, background .12s;
}
.pos-card-img {
  width: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block;
  background: var(--rule-soft);
}
.pos-card-img.blank {
  display: grid; place-items: center;
  font-size: 26px; font-weight: 700; color: var(--ink-3); opacity: .5;
}
.pos-card b {
  font-size: 13px; font-weight: 600; color: var(--ink); line-height: 1.3;
  padding: 8px 9px 0;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.pos-card .pos-price {
  font-size: 12.5px; font-weight: 700; color: var(--forest);
  font-variant-numeric: tabular-nums; padding: 3px 9px 9px; margin-top: auto;
}
.pos-card:active { transform: scale(.96); }
/* the tap must answer before the network does */
.pos-card.hit { animation: posHit .28s ease; }
@keyframes posHit {
  0% { background: var(--forest); }
  100% { background: var(--surface); }
}
.pos-card.hit b, .pos-card.hit .pos-price { animation: posHitText .28s ease; }
@keyframes posHitText { 0% { color: #fff; } 100% { color: inherit; } }

/* ---- the cart: a side panel on a tablet, a sheet on a phone ---- */

.pos-cart { background: var(--card); border: 1px solid var(--rule); border-radius: var(--r-lg); padding: 14px; }
.pos-cart .sheet-grip { display: none; }
/* The bill number is what the head is for; ประวัติบิล was the loudest thing in
   it, a pale pill bigger than the title next to it. */
.pos-cart-head { display: flex; align-items: center; gap: 8px; margin-bottom: 4px; }
.pos-cart-head b { font-size: 16px; font-weight: 700; letter-spacing: -.02em; }
.pos-cart-head .sub { font-size: 11.5px; color: var(--ink-3); }
/* The close button belongs to the phone sheet; bill history does not, and it was
   being hidden alongside it — unreachable on desktop entirely. */
.pos-cart-head .ghost { margin-left: auto; padding: 4px 9px; font-size: 15px; }
.pos-cart-head #posSheetClose { display: none; }
.pos-cart-head #posHistory {
  background: transparent; color: var(--ink-2);
  font-size: 12px; font-weight: 600; padding: 6px 4px;
  text-decoration: underline; text-underline-offset: 3px;
}
.pos-cart-head #posHistory:hover { color: var(--forest); background: transparent; }
.pos-cart-head #posSheetClose {
  margin-left: 0; flex: none; width: 32px; height: 32px; padding: 0;
  border-radius: 50%; font-size: 14px; line-height: 1;
}

.pos-cart-list { max-height: 42vh; overflow-y: auto; margin-bottom: 10px; }
/* One line reads left to right as: what it is · how many · what it costs. The
   count and the money are one cluster on the right, so the amounts stack into a
   column the eye can add up instead of drifting apart across the row. */
.pos-line { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--rule-soft); }
.pos-line:last-child { border-bottom: 0; }
.pos-line-main { flex: 1; min-width: 0; }
.pos-line-main b { display: block; font-size: 14px; font-weight: 600; line-height: 1.35; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pos-line-main small { display: block; margin-top: 2px; font-size: 11.5px; color: var(--ink-3); font-variant-numeric: tabular-nums; }
.pos-line-side { display: flex; align-items: center; gap: 12px; flex: none; }
.pos-line-total { min-width: 62px; text-align: right; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }

/* a rule of its own, so the total is not just the next line in the list */
.pos-sum {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-bottom: 12px; padding-top: 12px; border-top: 1px solid var(--rule);
}
.pos-sum span { font-size: 13px; color: var(--ink-2); font-weight: 500; }
.pos-sum b { font-size: 28px; font-weight: 700; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
/* taking the money is the job; ล้าง is the escape hatch and is sized like one */
.pos-cart-foot .actions { display: flex; gap: 10px; }
.pos-cart-foot .primary { flex: 1; min-height: 52px; font-size: 16px; font-weight: 700; }
.pos-cart-foot .ghost { flex: none; min-height: 52px; padding-inline: 18px; font-size: 13.5px; }
/* undo sits apart from รับเงิน on purpose */
.pos-void { width: 100%; margin-top: 10px; color: var(--bad); font-size: 12.5px; }

/* ---- phone: cart lives in a sheet behind a floating bar ---- */

@media (max-width: 819px) {
  .pos-cart {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    border-radius: 18px 18px 0 0; border-bottom: 0; padding: 8px 16px 18px;
    transform: translateY(102%); transition: transform .22s ease;
    box-shadow: 0 -12px 34px rgba(0,0,0,.16); max-height: 82vh; overflow-y: auto;
  }
  .pos-cart.show { transform: none; }
  .pos-cart .sheet-grip { display: block; }
  .pos-cart-head #posSheetClose { display: block; }
  .pos-cart-list { max-height: 46vh; }

  .pos-bar {
    position: fixed; left: 10px; right: 10px; z-index: 35;
    bottom: calc(var(--nav-h) + env(safe-area-inset-bottom) + 8px);
    display: none; align-items: center; gap: 10px;
    padding: 13px 16px; border-radius: 14px;
    background: var(--forest); color: #fff; box-shadow: var(--shadow);
  }
  .pos-bar.show { display: flex; }
  .pos-bar span { font-size: 13px; color: rgba(255,255,255,.75); }
  .pos-bar b { margin-left: auto; font-size: 17px; font-weight: 700; font-variant-numeric: tabular-nums; }
  .pos-bar i { font-style: normal; font-size: 11.5px; color: rgba(255,255,255,.75); }
}

/* ---- tablet and up: menu and cart side by side ---- */

@media (min-width: 820px) {
  .pos-wrap { grid-template-columns: minmax(0, 1.9fr) minmax(280px, 1fr); align-items: start; }
  .pos-cart { position: sticky; top: 88px; }
  .pos-bar { display: none; }
}

/* ---- the payment sheet ---- */

.pay-head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 12px; }
.pay-head h3 { margin: 0; }
.pay-head b { font-size: 28px; font-weight: 700; letter-spacing: -.03em; color: var(--forest); font-variant-numeric: tabular-nums; }
#payModes { width: 100%; margin-bottom: 14px; }
#payModes button { flex: 1; }
.pay-quick { display: flex; flex-wrap: wrap; gap: 6px; margin-bottom: 12px; }
.pay-quick .chip {
  padding: 11px 14px; border-radius: 10px; font-size: 13.5px; font-weight: 600;
  background: var(--surface-2); color: var(--ink); font-variant-numeric: tabular-nums;
}
.pay-quick .chip.on { background: var(--forest); color: #fff; }
.pay-change {
  display: flex; align-items: baseline; justify-content: space-between;
  background: var(--good-bg); border-radius: 10px; padding: 11px 14px; margin: 12px 0 4px;
}
.pay-change span { font-size: 13px; color: var(--ink-2); font-weight: 500; }
.pay-change b { font-size: 24px; font-weight: 700; color: var(--good); font-variant-numeric: tabular-nums; }
.pay-change b.short { color: var(--bad); }

/* ---------------- shared bits the POS pages lean on ----------------

   These live in ChaPayom's stylesheet already; SaveCost never had them because
   it has no staff screen. Defined here rather than borrowed so the two apps do
   not silently depend on each other's CSS. */

.tally-search {
  width: 100%; padding: 11px 13px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid transparent;
  font: inherit; font-size: 14px; color: var(--ink);
}
.tally-search:focus { outline: none; border-color: var(--leaf-deep); background: var(--surface); }

.tally-cats { display: flex; gap: 6px; overflow-x: auto; padding: 10px 0; scrollbar-width: none; }
.tally-cats::-webkit-scrollbar { display: none; }
.tally-cats .chip {
  flex: none; padding: 7px 13px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
  background: var(--surface-2); color: var(--ink-2); white-space: nowrap;
}
.tally-cats .chip.on { background: var(--forest); color: #fff; }

/* the month switcher steers the books, not the till */
.app.pos-view .month-label,
.app.pos-view #monthPrev,
.app.pos-view #monthNext { display: none; }

/* ---------------- bill history ---------------- */

.bills-list { display: grid; gap: 14px; margin-top: 12px; }
.bills-group h3 {
  font-size: 11.5px; font-weight: 600; color: var(--ink-3); margin: 0 0 5px;
  display: flex; align-items: center; gap: 6px;
}
.bills-group h3 span {
  font-weight: 500; background: var(--surface-2); border-radius: 999px;
  padding: 1px 7px; font-size: 10.5px;
}
.bill-row {
  display: flex; align-items: center; gap: 10px;
  padding: 9px 2px; border-bottom: 1px solid var(--rule-soft);
}
.bill-row:last-child { border-bottom: 0; }
.bill-row.void { opacity: .5; }
.bill-row.void .bill-total { text-decoration: line-through; }
.bill-main { flex: 1; min-width: 0; }
.bill-main b { font-size: 13.5px; font-weight: 600; display: flex; align-items: baseline; gap: 7px; }
.bill-time { font-size: 11px; font-weight: 500; color: var(--ink-3); }
.bill-main small { font-size: 11.5px; color: var(--ink-3); }
.bill-main small .queued { font-style: normal; color: var(--warn); font-weight: 600; }
.bill-total { flex: none; font-size: 14px; font-weight: 700; font-variant-numeric: tabular-nums; }
.bill-void { flex: none; color: var(--bad); font-size: 11.5px; }
.bill-flag { flex: none; font-size: 11px; color: var(--ink-3); }

/* ---------------- product photos ---------------- */

.menu-thumb {
  flex: none; width: 40px; height: 40px; border-radius: 9px; overflow: hidden;
  background: var(--surface-2); display: grid; place-items: center;
}
.menu-thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.menu-thumb span { font-size: 15px; font-weight: 700; color: var(--ink-3); }

.img-row { display: flex; align-items: center; gap: 12px; }
.img-preview {
  flex: none; width: 76px; height: 76px; border-radius: 12px; overflow: hidden;
  background: var(--surface-2); display: grid; place-items: center;
}
.img-preview img { width: 100%; height: 100%; object-fit: cover; display: block; }
.img-preview span { font-size: 11px; color: var(--ink-3); }
.img-actions { display: grid; gap: 6px; }
.img-actions button { padding: 8px 12px; font-size: 12.5px; }

/* a photo makes the card taller; the name and price stay legible on top of it */

/* ---------------- product options ---------------- */

.opt-group { margin-bottom: 16px; }
.opt-group h4 {
  font-size: 12.5px; font-weight: 600; margin: 0 0 7px; color: var(--ink-2);
  display: flex; align-items: baseline; gap: 7px;
}
.opt-group h4 i { font-style: normal; font-size: 10.5px; font-weight: 500; color: var(--bad); }
.opt-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.opt-choices .chip {
  padding: 11px 14px; border-radius: 10px; font-size: 13.5px; font-weight: 500;
  background: var(--surface-2); color: var(--ink); display: inline-flex; align-items: baseline; gap: 5px;
}
.opt-choices .chip em { font-style: normal; font-size: 11px; color: var(--ink-3); }
.opt-choices .chip.on { background: var(--forest); color: #fff; }
.opt-choices .chip.on em { color: rgba(255,255,255,.7); }

.opt-picks { display: flex; flex-wrap: wrap; gap: 6px; }
.opt-picks .chip {
  padding: 8px 12px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
  background: var(--surface-2); color: var(--ink-2);
}
.opt-picks .chip.on { background: var(--forest); color: #fff; }

.opt-admin { display: grid; gap: 14px; }
.opt-admin-group h4 {
  font-size: 12.5px; font-weight: 600; margin: 0 0 6px;
  display: flex; align-items: baseline; gap: 7px;
}
.opt-admin-group h4 i { font-style: normal; font-size: 10.5px; font-weight: 500; color: var(--ink-3); }
.opt-admin-choices { display: flex; flex-wrap: wrap; gap: 6px; }
.opt-admin-chip {
  display: inline-flex; align-items: center; gap: 5px;
  background: var(--surface-2); border-radius: 999px; padding: 4px 5px 4px 11px;
  font-size: 12.5px; color: var(--ink);
}
.opt-admin-chip b { font-weight: 600; color: var(--forest); font-size: 11.5px; }
.opt-admin-chip button {
  width: 24px; height: 24px; border-radius: 50%; font-size: 10.5px;
  background: var(--surface); color: var(--ink-3);
}
.opt-admin-add {
  padding: 7px 13px; border-radius: 999px; font-size: 12.5px; font-weight: 500;
  background: var(--good-bg); color: var(--forest);
}

/* ---------------- PromptPay ---------------- */

.pp-qr {
  width: 150px; height: 150px; flex: none; border-radius: 10px; overflow: hidden;
  background: #fff; display: grid; place-items: center; font-size: 11px; color: #666;
}
.pp-qr canvas { display: block; }
.pp-qr.big { width: 100%; max-width: 260px; height: auto; aspect-ratio: 1; margin: 0 auto; }
.pp-qr.expired { opacity: .22; }

.pp-check { display: flex; gap: 14px; align-items: flex-start; margin-top: 4px; }
.pp-check-body { flex: 1; min-width: 0; }
.pp-check-body b { display: block; font-size: 13.5px; margin-bottom: 4px; }
.pp-check-body p { font-size: 12px; color: var(--ink-2); line-height: 1.6; margin: 0 0 10px; }
.pp-check-body .primary { width: 100%; }
#ppState.ok { color: var(--good); font-weight: 600; }

/* the customer reads the amount from arm's length, so it leads */
.pay-qr-wrap { text-align: center; margin-bottom: 10px; }
.pay-qr-meta {
  display: flex; align-items: baseline; justify-content: center; gap: 12px; margin-top: 10px;
}
.pay-qr-meta span { font-size: 12px; color: var(--ink-3); }
.pay-qr-meta b { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--ink-2); }
.pay-qr-meta b.out { color: var(--bad); }
#payModes button:disabled { opacity: .4; }

/* ---------------- shift close ---------------- */

.shift {
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: 12px 14px; margin-bottom: 14px;
}
.shift-head { display: flex; align-items: baseline; gap: 8px; margin-bottom: 8px; }
.shift-head b { font-size: 13.5px; font-weight: 700; }
.shift-head span { font-size: 11.5px; color: var(--ink-3); margin-left: auto; text-align: right; }
.shift-rows { display: grid; gap: 2px; }
.shift-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 4px 0; font-size: 13px;
}
.shift-row span { color: var(--ink-2); display: inline-flex; align-items: baseline; gap: 6px; }
.shift-row i {
  font-style: normal; font-size: 10px; font-weight: 600; color: var(--forest);
  background: var(--good-bg); border-radius: 999px; padding: 1px 7px;
}
.shift-row b { font-variant-numeric: tabular-nums; font-weight: 600; }
.shift-row.drawer b { color: var(--forest); }
.shift-row.total {
  border-top: 1px solid var(--rule); margin-top: 4px; padding-top: 7px;
}
.shift-row.total span { font-weight: 600; color: var(--ink); }
.shift-row.total b { font-size: 15px; font-weight: 700; }

/* ---------------- staff + PIN ---------------- */

.staff-list { display: grid; gap: 2px; margin-bottom: 10px; }
.staff-row {
  display: flex; align-items: center; gap: 8px;
  padding: 8px 0; border-bottom: 1px solid var(--rule-soft);
}
.staff-row:last-child { border-bottom: 0; }
.staff-main { flex: 1; min-width: 0; display: flex; align-items: baseline; gap: 7px; }
.staff-main b { font-size: 14px; font-weight: 500; }
.staff-main i {
  font-style: normal; font-size: 10px; font-weight: 600; color: var(--forest);
  background: var(--good-bg); border-radius: 999px; padding: 1px 8px;
}

.pos-seller {
  font-size: 11.5px; font-weight: 600; padding: 4px 10px; border-radius: 999px;
  background: var(--good-bg); color: var(--forest);
}
.pos-seller.unset { background: var(--bad-bg); color: var(--bad); }

.pin-who { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 12px; }
.pin-who .chip {
  padding: 5px 11px; border-radius: 999px; font-size: 12px;
  background: var(--surface-2); color: var(--ink-2);
}
.pin-dots { display: flex; justify-content: center; gap: 14px; margin: 6px 0 18px; }
.pin-dots span {
  width: 13px; height: 13px; border-radius: 50%;
  background: var(--surface-2); border: 1px solid var(--rule);
}
.pin-dots span.on { background: var(--forest); border-color: var(--forest); }

.pin-pad { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.pin-pad button {
  min-height: 56px; border-radius: 12px; font-size: 21px; font-weight: 600;
  background: var(--surface-2); color: var(--ink); font-variant-numeric: tabular-nums;
}
.pin-pad button:active { background: var(--forest); color: #fff; }

/* One action, so it takes the whole row. .actions is a two-column grid, which
   left ยกเลิก sitting in the left half looking like a leftover keypad cell —
   and once the error line stopped reserving space when empty, it ended up
   pressed against the pad as well. */
#pinSheet .actions { grid-template-columns: 1fr; margin-top: 16px; }
#pinSheet .actions .ghost { min-height: 48px; font-size: 14.5px; }

/* the lock: everything except the till goes away */
body.staff-mode .bottom-nav button:not([data-view="pos"]) { display: none; }
body.staff-mode .bottom-nav { grid-auto-columns: 1fr; }
body.staff-mode .topbar .top-actions .chip-btn { display: none; }

/* the only door out of staff mode, so it says what it does rather than being an
   icon the staff would have to guess at */
/* the checkbox label carries the consequence on its second line, so the choice
   does not depend on reading the paragraph underneath it */
.check-row span small {
  display: block; font-size: 11.5px; font-weight: 400;
  color: var(--ink-3); line-height: 1.5; margin-top: 2px;
}
#staffManagerWarn { color: var(--bad); margin: 10px 0 0; }

.staff-exit { display: none; }
body.staff-mode .staff-exit {
  display: inline-flex; align-items: center; white-space: nowrap;
  padding: 7px 13px; border-radius: 999px; font-size: 12.5px; font-weight: 600;
  background: var(--surface-2); color: var(--ink-2); border: 1px solid var(--rule);
}
body.staff-mode .staff-exit:hover { background: var(--surface); color: var(--forest); }

/* ---------------- receipt ---------------- */

.pos-after { display: grid; gap: 6px; margin-top: 10px; }
.pos-after .ghost { width: 100%; font-size: 12.5px; }
.pos-void { margin-top: 0 !important; }

.receipt {
  background: var(--surface-2); border-radius: var(--r-sm);
  padding: 16px; margin-bottom: 16px; font-variant-numeric: tabular-nums;
}
.rcpt-head { text-align: center; margin-bottom: 12px; }
.rcpt-head b { display: block; font-size: 16px; font-weight: 700; margin-bottom: 3px; }
.rcpt-head span { display: block; font-size: 11.5px; color: var(--ink-3); }
.rcpt-items { border-top: 1px dashed var(--rule); padding-top: 10px; }
.rcpt-line { display: flex; justify-content: space-between; gap: 10px; font-size: 13px; padding: 3px 0; }
.rcpt-line span { min-width: 0; }
.rcpt-line b { flex: none; font-weight: 600; }
.rcpt-total {
  display: flex; justify-content: space-between; align-items: baseline;
  border-top: 1px dashed var(--rule); margin-top: 10px; padding-top: 10px;
}
.rcpt-total span { font-size: 13px; color: var(--ink-2); }
.rcpt-total b { font-size: 20px; font-weight: 700; }
.rcpt-foot {
  display: flex; justify-content: center; gap: 10px; flex-wrap: wrap;
  margin-top: 10px; font-size: 11.5px; color: var(--ink-3);
}

/* ---------------- Google sign-in ---------------- */

.auth-or {
  display: flex; align-items: center; gap: 12px;
  margin: 18px 0 2px; font-size: 11.5px; color: var(--ink-3);
}
.auth-or::before, .auth-or::after {
  content: ""; flex: 1; height: 1px; background: var(--rule);
}
.google-btn {
  width: 100%; min-height: 48px; border-radius: var(--r-sm);
  display: flex; align-items: center; justify-content: center; gap: 10px;
  background: var(--surface); border: 1px solid var(--rule);
  font-size: 14.5px; font-weight: 500; color: var(--ink);
  box-shadow: var(--shadow-sm); transition: .16s;
}
.google-btn:hover { background: var(--surface-2); }
.google-btn:disabled { opacity: .55; }
.google-btn svg { flex: none; }

/* ---------------- the staff page ----------------

   Styles for staff.html, which is a separate page with no session of its own.
   Ported from ChaPayom so both apps offer the same counter screen.

   Note `.tally-*` here is the staff tally, distinct from `.menu-*` above, which
   is the owner's product editor. They look similar and are not the same thing. */
.tally-card .head h2 { flex: none; }
.tally-card .head .sub {
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.tally-top {
  display: flex; align-items: stretch; gap: 8px; margin-bottom: 10px;
}
.tally-total, .tally-value {
  flex: 1; border-radius: var(--r-sm); padding: 10px 12px;
  display: flex; align-items: baseline; gap: 6px;
}
.tally-total { background: var(--forest); color: #fff; }
.tally-value { background: var(--surface-2); }
.tally-total span, .tally-value span { font-size: 11.5px; font-weight: 500; }
.tally-total span { color: rgba(255,255,255,.66); }
.tally-value span { color: var(--ink-2); }
.tally-total b, .tally-value b {
  font-size: 24px; font-weight: 700; letter-spacing: -.03em;
  font-variant-numeric: tabular-nums; margin-left: auto;
}
.tally-value b { color: var(--forest); }
.tally-total small { font-size: 11.5px; color: rgba(255,255,255,.66); }
.tally-row {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 2px; border-bottom: 1px solid var(--rule-soft);
}
.tally-name { min-width: 0; flex: 1; }
.tally-name b {
  display: block; font-size: 13.5px; font-weight: 500; color: var(--ink);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.tally-name small { font-size: 11px; color: var(--ink-3); }
.staff-body .app.tally-view .content {
  flex: 1; min-height: 0; display: flex; flex-direction: column; padding-bottom: 12px;
}
.staff-body .app.tally-view #tab-tally { flex: 1; min-height: 0; display: flex; }
.staff-body .app.tally-view .tally-card {
  flex: 1; min-height: 0; display: flex; flex-direction: column;
}
.staff-body .app.tally-view .tally-list { max-height: none; flex: 1; min-height: 0; }
.staff-body .app.tally-view #tallySave { margin-top: auto; }
.staff-body .app.tally-view #tallySave:disabled { opacity: .45; }
.staff-body .app.tally-view .topline .brand { display: none; }
.staff-body .app.tally-view .topline { justify-content: flex-end; min-height: 0; }
.staff-body .app.tally-view .month-row { margin-top: 2px; }
.staff-body .app.tally-view .tally-card .head { margin-bottom: 2px; }
.tally-name small { flex: none; }
.tally-row { padding: 5px 2px; }
.tally-row.counted { padding-inline: 8px; }
/* the totals bar shrinks so the list gets the difference */
.tally-total, .tally-value { padding: 8px 11px; }
.tally-total b, .tally-value b { font-size: 21px; }
.tally-card .hint { margin: 6px 0 8px; }

/* The staff card carried no padding of its own — its text sat on the border.
   The tally-view layout below sets its own vertical padding for the fixed
   column, so only the sides need restating there. */
.staff-body .app.tally-view .tally-card { padding-left: 16px; padding-right: 16px; }

/* the group header carries its own edit affordance now */
.opt-admin-group h4 { gap: 7px; }
.opt-admin-edit {
  margin-left: auto; padding: 3px 10px; border-radius: 999px;
  font-size: 11px; font-weight: 600;
  background: var(--surface-2); color: var(--ink-2);
}
.opt-admin-edit:hover { background: var(--good-bg); color: var(--forest); }

/* ---------------- settings tabs ----------------

   A segmented control rather than a list of links: four is few enough to show
   at once, and seeing all four is what tells someone the thing they want is one
   tap away rather than somewhere further down. */

.set-tabs {
  display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; gap: 2px;
  background: var(--surface-2); border-radius: var(--r-sm); padding: 3px;
  margin-bottom: 14px; position: sticky; top: 8px; z-index: 5;
}
.set-tabs button {
  padding: 9px 6px; border-radius: 8px; font-size: 13px; font-weight: 500;
  color: var(--ink-2); white-space: nowrap; transition: .16s;
}
.set-tabs button.on {
  background: var(--surface); color: var(--forest);
  font-weight: 600; box-shadow: var(--shadow-sm);
}
/* the first card in a tab no longer needs the stack's top margin */
#settings [data-set-group]:not([hidden]) + [data-set-group] { margin-top: 12px; }

/* ---------------- which tabs show on the bar ---------------- */

.tab-toggles { display: flex; flex-wrap: wrap; gap: 6px; }
.tab-toggles .chip {
  padding: 8px 14px; border-radius: 999px; font-size: 13px; font-weight: 500;
  background: var(--surface-2); color: var(--ink-3);
  border: 1px solid transparent; transition: .16s;
}
.tab-toggles .chip.on { background: var(--forest); color: #fff; }
/* locked tabs read as fixed, not as broken */
.tab-toggles .chip.locked { opacity: .55; }
.tab-toggles .chip.locked.on { background: var(--forest-mid); }
/* a hidden tab is a state you can undo; a locked one is not. They were the same
   pale chip, so the outline and the label separate them. */
.tab-toggles .chip:not(.on):not(.locked) {
  background: transparent; border-style: dashed; border-color: var(--rule);
}
.tab-toggles .chip i {
  font-style: normal; font-size: 10.5px; font-weight: 600;
  margin-left: 6px; opacity: .75;
}
#tabToggleReset { width: 100%; margin-top: 10px; }

/* ---------------- option sheet, reworked ----------------

   The counter reads this while someone waits, so the three things it has to
   answer fast are: what is still required, what a choice costs, and what the
   total will be. Everything else gets out of the way. */

.opt-price { text-align: right; }
.opt-price b { display: block; font-size: 28px; font-weight: 700; letter-spacing: -.03em; color: var(--forest); font-variant-numeric: tabular-nums; }
.opt-price small { display: block; font-size: 11px; color: var(--ink-3); margin-top: 2px; font-variant-numeric: tabular-nums; }

.opt-group h4 i.need {
  font-style: normal; font-size: 10.5px; font-weight: 600;
  color: var(--bad); background: var(--bad-bg); border-radius: 999px; padding: 2px 8px;
}
.opt-group h4 i.picked {
  font-style: normal; font-size: 10.5px; font-weight: 700;
  color: #fff; background: var(--forest); border-radius: 999px;
  min-width: 18px; text-align: center; padding: 1px 6px;
}

/* Bigger targets and a real border on the unselected state — the old fill-only
   chips were nearly invisible against the sheet on a bright counter. */
.opt-choices .chip {
  min-height: 46px; padding: 10px 15px; border-radius: 12px;
  font-size: 14.5px; font-weight: 500; gap: 7px;
  background: var(--surface); color: var(--ink);
  border: 1.5px solid var(--rule);
}
.opt-choices .chip em {
  font-style: normal; font-size: 12px; font-weight: 600; color: var(--forest);
  font-variant-numeric: tabular-nums;
}
.opt-choices .chip.on {
  background: var(--forest); color: #fff; border-color: var(--forest);
  box-shadow: var(--shadow-sm);
}
.opt-choices .chip.on em { color: rgba(255,255,255,.78); }

/* A toggle group was briefly drawn as a switch built from inset shadows. On a
   real phone it rendered as a grey dot with no track, which read as broken — so
   these stay ordinary chips like every other choice. */

/* the footer stays put so the total and the button never scroll away */
.opt-foot {
  position: sticky; bottom: 0; background: var(--surface);
  padding-top: 12px; margin-top: 4px;
  box-shadow: 0 -10px 16px -12px rgba(0,0,0,.18);
}
.opt-qty { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.opt-qty > span { font-size: 13.5px; font-weight: 500; color: var(--ink-2); }
.stepper.big button { width: 46px; height: 46px; border-radius: 12px; font-size: 22px; }
.stepper.big b {
  min-width: 52px; text-align: center; font-size: 20px; font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.stepper.big { display: flex; align-items: center; gap: 4px; }
.opt-foot .actions { display: flex; gap: 8px; }
.opt-foot .ghost { flex: none; padding-inline: 20px; }
.opt-foot .primary { flex: 1; min-height: 52px; font-size: 15.5px; }

#optSheet .sheet { max-height: 88vh; display: flex; flex-direction: column; }

/* The sheet is opened from a grid of photos and then covers it, so the picture
   comes along — it is the fastest confirmation that the right drink was tapped.
   align-self keeps it from stretching against the baseline-aligned head. */
.opt-thumb {
  width: 56px; height: 56px; flex: none; align-self: center;
  border-radius: 12px; object-fit: cover; background: var(--rule-soft);
}
#optSheet .pay-head { align-items: center; }
#optSheet .pay-head h3 { flex: 1; min-width: 0; }
#optGroups { flex: 1; overflow-y: auto; min-height: 0; }

/* ---------------- expense categories ---------------- */

.link-inline {
  margin-left: 8px; font-size: 11.5px; font-weight: 600;
  color: var(--forest); text-decoration: underline; text-underline-offset: 2px;
}
.cat-list { display: grid; gap: 2px; max-height: 46vh; overflow-y: auto; }
.cat-row {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 2px; border-bottom: 1px solid var(--rule-soft);
}
.cat-row:last-child { border-bottom: 0; }
.cat-dot { width: 12px; height: 12px; border-radius: 50%; flex: none; }
.cat-row b { flex: 1; min-width: 0; font-size: 14px; font-weight: 500;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cat-row .icon-btn { flex: none; }

/* ---------------- SaveCost wordmark ----------------

   A wide wordmark, not a square badge, so it needs more width than the old
   icon-plus-text lockup and has to beat the max-width set for that lockup
   earlier in this file.

   It is white-filled with a black keyline, which already reads on either
   theme. The dark-mode `brightness(0) invert(1)` inherited from ChaPayom's
   flat mark would flatten it to a solid white blob, so it is switched off. */
.brand-logo {
  width: 128px; max-width: none; max-height: none; height: auto; display: block;
}
/* Sized for the wordmark, but a shop that uploads its own logo can send any
   shape through here, so it is still fitted rather than stretched. */
.auth-logo {
  width: 168px; max-width: 100%; max-height: 78px; height: auto;
  object-fit: contain; display: block; margin: 0 auto 8px;
}
:root[data-theme="dark"] .topbar .brand-logo,
:root[data-theme="dark"] .sidebar .brand-logo,
:root[data-theme="dark"] .auth-logo { filter: none; }

@media (max-width: 380px) { .brand-logo { width: 112px; } }

/* ---------------- the customer's own screens ----------------

   /s/<slug> and /q/<token>. Same tokens as the shop app so the two read as one
   product, but this page is opened once by a stranger on shop wifi — nothing
   here may cost a round trip that the menu does not need. */

.order-body { background: var(--bg); }
.order-wrap { max-width: 560px; margin: 0 auto; padding: 16px 14px 108px; }

.order-boot { display: grid; place-items: center; gap: 14px; padding: 25vh 0; color: var(--ink-3); }
.spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid var(--rule); border-top-color: var(--forest);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.order-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.order-logo { width: 52px; height: 52px; border-radius: 14px; object-fit: contain; background: var(--surface); flex: none; }
.order-head h1 { font-size: 20px; margin: 0; letter-spacing: -.02em; }
.order-head p { margin: 2px 0 0; font-size: 12.5px; color: var(--ink-2); }
.order-foot { font-size: 11.5px; color: var(--ink-3); line-height: 1.7; text-align: center; margin: 18px 0 0; }

.order-state { display: grid; place-items: center; gap: 12px; text-align: center; padding: 18vh 6px 0; }
.order-state-icon { font-size: 46px; line-height: 1; }
.order-state h1 { font-size: 21px; margin: 0; }
.order-state p { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.7; }
.order-state button { margin-top: 8px; min-width: 180px; }

/* the cart bar is the only thing pinned to the screen while choosing */
.order-bar {
  position: fixed; left: 12px; right: 12px; bottom: 12px; z-index: 30;
  max-width: 536px; margin: 0 auto;
  display: flex; align-items: center; gap: 12px;
  padding: 10px 10px 10px 16px; border-radius: 16px;
  background: var(--forest); color: #fff;
  box-shadow: 0 12px 30px -10px rgba(0,0,0,.45);
  transition: transform .18s ease;
}
.order-bar[hidden] { display: none; }
.order-bar span { font-size: 13px; color: rgba(255,255,255,.72); }
.order-bar b { font-size: 20px; font-weight: 700; letter-spacing: -.02em; margin-left: auto; font-variant-numeric: tabular-nums; }
.order-bar .primary { width: auto; margin: 0; min-height: 42px; padding-inline: 18px; background: #fff; color: var(--forest); font-size: 14px; }
.order-bar.bump { transform: scale(1.02); }

/* ---- paying ---- */

.pay-screen { display: grid; gap: 14px; padding-top: 6px; }
.pay-amount { text-align: center; }
.pay-amount span { display: block; font-size: 13px; color: var(--ink-2); }
.pay-amount b {
  display: block; font-size: 44px; font-weight: 700; letter-spacing: -.04em;
  color: var(--forest); font-variant-numeric: tabular-nums; line-height: 1.1;
}
/* white, edge to edge, nothing overlapping: a bank app has to read this in one go */
.pay-qr { background: #fff; border-radius: 18px; padding: 14px; display: grid; place-items: center; }
.pay-qr svg { width: 100%; height: auto; display: block; }
.pay-to { text-align: center; font-size: 13px; color: var(--ink-2); margin: 0; }
.pay-save { width: 100%; font-size: 13px; }
.pay-timer {
  text-align: center; font-size: 13px; font-weight: 600; color: var(--ink-2);
  font-variant-numeric: tabular-nums;
}
.pay-timer.urgent { color: var(--bad); }
.pay-done { min-height: 54px; font-size: 16px; }

/* ---- following the queue ---- */

.track { text-align: center; padding-top: 10px; }
.track-shop { font-size: 13px; color: var(--ink-2); margin: 0; }
.track-label { font-size: 13px; color: var(--ink-2); margin: 14px 0 0; }
.track-no {
  font-size: 108px; font-weight: 700; letter-spacing: -.06em; line-height: 1;
  color: var(--forest); font-variant-numeric: tabular-nums; margin: 2px 0 6px;
}
.track.is-ready .track-no { color: var(--good); }
.track-hint { font-size: 14px; color: var(--ink-2); margin: 0 0 18px; min-height: 20px; }

.track-steps { display: flex; gap: 6px; margin-bottom: 18px; }
.track-step { flex: 1; display: grid; gap: 5px; }
.track-step span { display: block; height: 5px; border-radius: 999px; background: var(--rule); }
.track-step.on span { background: var(--forest); }
.track-step small { font-size: 10.5px; color: var(--ink-3); }
.track-step.on small { color: var(--forest); font-weight: 600; }

.track-bill {
  background: var(--surface); border: 1px solid var(--rule-soft);
  border-radius: var(--r-lg); padding: 14px; text-align: left;
}
.track-row { display: flex; justify-content: space-between; align-items: baseline; gap: 10px; padding: 4px 0; font-size: 13.5px; }
.track-row span { color: var(--ink-2); }
.track-row b { font-variant-numeric: tabular-nums; }
.track-items { margin-top: 10px; padding-top: 10px; border-top: 1px solid var(--rule-soft); display: grid; gap: 6px; }
.track-item { display: flex; justify-content: space-between; gap: 10px; font-size: 12.5px; color: var(--ink-2); }
.track-item em { font-style: normal; color: var(--ink-3); }
.track-item b { font-variant-numeric: tabular-nums; color: var(--ink); }
.track-receipt { display: block; margin-top: 12px; text-align: center; min-height: 44px; line-height: 44px; border-radius: var(--r-sm); text-decoration: none; }

@media (max-width: 380px) { .track-no { font-size: 88px; } }

/* ---------------- kitchen screen ----------------

   Read at arm's length by someone holding a milk jug: big queue numbers, one
   obvious button per card, and a colour that says how long this person has been
   waiting without anyone having to read the clock. */

.kds-head { display: flex; gap: 8px; align-items: center; margin-bottom: 12px; }
.kds-head .tally-cats { flex: 1; min-width: 0; padding: 0; }
.kds-head .secondary { flex: none; padding: 9px 14px; font-size: 13px; }
.tally-cats .chip em { font-style: normal; opacity: .7; margin-left: 3px; }

.kds-arm { display: grid; place-items: center; gap: 12px; text-align: center; padding: 12vh 10px 0; }
.kds-arm-icon { font-size: 44px; }
.kds-arm h2 { margin: 0; font-size: 20px; }
.kds-arm p { margin: 0; color: var(--ink-2); font-size: 13.5px; line-height: 1.8; }
.kds-arm .primary { margin-top: 6px; max-width: 320px; }

.kds-empty { text-align: center; color: var(--ink-3); font-size: 13.5px; padding: 40px 10px; }

.kds-grid { display: grid; gap: 10px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); }

.kds-card {
  background: var(--surface); border: 1px solid var(--rule-soft);
  border-left: 4px solid var(--good);
  border-radius: var(--r-lg); padding: 13px 14px;
  display: flex; flex-direction: column; gap: 8px;
}
/* how long they have been standing there, without reading a number */
.kds-card.fresh { border-left-color: var(--good); }
.kds-card.warm  { border-left-color: var(--warn); }
.kds-card.hot   { border-left-color: var(--bad); }
.kds-card.is-void { opacity: .6; }

.kds-card header { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.kds-no { font-size: 22px; font-weight: 700; letter-spacing: -.02em; }
.kds-clock { font-size: 12.5px; color: var(--ink-2); font-variant-numeric: tabular-nums; }
.kds-card.hot .kds-clock { color: var(--bad); font-weight: 600; }
.kds-meta { margin: 0; font-size: 12.5px; color: var(--ink-2); }

.kds-unverified {
  display: flex; align-items: center; gap: 8px; flex-wrap: wrap;
  background: var(--over-bg); color: var(--over);
  border-radius: var(--r-sm); padding: 8px 10px; font-size: 12.5px; font-weight: 600;
}
.kds-unverified span { flex: 1; min-width: 0; }
.kds-unverified .secondary { flex: none; padding: 6px 11px; font-size: 12px; min-height: 0; }

.kds-items { list-style: none; margin: 0; padding: 0; display: grid; gap: 5px; }
.kds-items li { font-size: 14px; line-height: 1.45; }
.kds-items b { font-variant-numeric: tabular-nums; margin-right: 4px; }
.kds-items em { font-style: normal; display: block; font-size: 12px; color: var(--ink-3); }
.kds-noitems { color: var(--ink-3); font-size: 12.5px; }
.kds-note { margin: 0; font-size: 12.5px; color: var(--ink-2); background: var(--surface-2); border-radius: 8px; padding: 7px 9px; }
.kds-voided { margin: 0; font-size: 12.5px; font-weight: 600; color: var(--bad); }

.kds-actions { display: flex; gap: 8px; margin-top: auto; padding-top: 4px; }
.kds-actions .primary { flex: 1; margin: 0; min-height: 46px; font-size: 14.5px; }
/* the destructive one is deliberately not next to the thumb's resting place */
.kds-actions .kds-cancel { flex: none; padding-inline: 14px; font-size: 12.5px; color: var(--bad); }

.cancel-reasons, .soldout-list { display: grid; gap: 2px; margin-top: 10px; max-height: 38vh; overflow-y: auto; }
.cancel-reasons .check-row, .soldout-list .check-row { padding: 7px 2px; font-size: 13.5px; }

/* ---------------- receipt ---------------- */

.rcpt {
  background: var(--surface); border: 1px solid var(--rule-soft);
  border-radius: var(--r-lg); padding: 20px 18px; margin-top: 10px;
}
.rcpt-top { text-align: center; display: grid; gap: 2px; margin-bottom: 14px; }
.rcpt-top b { font-size: 18px; letter-spacing: -.02em; }
.rcpt-top span { font-size: 12px; color: var(--ink-3); }
.rcpt-no {
  display: flex; align-items: baseline; justify-content: center; gap: 10px;
  padding: 10px 0 14px; border-bottom: 1px dashed var(--rule);
}
.rcpt-no span { font-size: 13px; color: var(--ink-2); }
.rcpt-no b { font-size: 38px; font-weight: 700; letter-spacing: -.03em; color: var(--forest); font-variant-numeric: tabular-nums; }
.rcpt-lines { display: grid; gap: 8px; padding: 14px 0; }
.rcpt-line { display: flex; justify-content: space-between; gap: 12px; font-size: 13.5px; }
.rcpt-line em { font-style: normal; display: block; font-size: 11.5px; color: var(--ink-3); }
.rcpt-line b { font-variant-numeric: tabular-nums; white-space: nowrap; }
.rcpt-total {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 12px 0; border-top: 1px dashed var(--rule); border-bottom: 1px dashed var(--rule);
}
.rcpt-total span { font-size: 13px; color: var(--ink-2); }
.rcpt-total b { font-size: 24px; font-weight: 700; letter-spacing: -.03em; font-variant-numeric: tabular-nums; }
.rcpt-meta { margin: 14px 0 0; display: grid; gap: 7px; }
.rcpt-meta div { display: flex; justify-content: space-between; gap: 12px; font-size: 12.5px; }
.rcpt-meta dt { color: var(--ink-2); margin: 0; }
.rcpt-meta dd { margin: 0; text-align: right; }
.rcpt-foot { font-size: 11px; color: var(--ink-3); text-align: center; margin: 16px 0 0; line-height: 1.6; }
.rcpt #back { width: 100%; margin-top: 12px; }

/* the kitchen tab strip scrolls; fade the edge so a clipped chip reads as more
   to scroll rather than as a broken layout */
.kds-head .tally-cats {
  -webkit-mask-image: linear-gradient(to right, #000 88%, transparent);
          mask-image: linear-gradient(to right, #000 88%, transparent);
  padding-right: 10px;
}

/* ---------------- refunds the shop still owes ---------------- */

.refund-card { border-left: 4px solid var(--bad); }
.refund-row {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px solid var(--rule-soft);
}
.refund-row:last-child { border-bottom: 0; }
.refund-main { flex: 1; min-width: 0; }
.refund-main b { display: block; font-size: 14px; }
.refund-main small { font-size: 11.5px; color: var(--ink-3); }
.refund-amount { font-weight: 700; font-variant-numeric: tabular-nums; color: var(--bad); }

/* ---------------- self-order settings ---------------- */
/* the read-only link sits directly above its own buttons, and .field carries no
   bottom margin of its own */
#selfLinkRow .field { margin-bottom: 12px; }
/* The two link buttons belong together; the board is a separate errand and gets
   a rule and real space so the three do not read as one block of buttons. */
.self-links { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.self-links a {
  min-height: 46px; display: grid; place-items: center; text-align: center;
  text-decoration: none; line-height: 1.3;
}
.self-links .self-board {
  grid-column: 1 / -1; margin-top: 8px; padding-top: 18px;
  border-top: 1px solid var(--rule-soft); border-radius: 0;
  background: transparent; color: var(--forest); font-weight: 600;
}
.self-links .self-board:hover { background: transparent; text-decoration: underline; text-underline-offset: 4px; }


.slug-row { display: flex; align-items: center; gap: 0; }
.slug-row span {
  flex: none; padding: 0 4px 0 13px; font-size: 14px; color: var(--ink-3);
  background: var(--surface-2); border-radius: var(--r-sm) 0 0 var(--r-sm);
  align-self: stretch; display: grid; place-items: center;
}
.slug-row input { border-radius: 0 var(--r-sm) var(--r-sm) 0; }
.self-qr { display: grid; place-items: center; background: #fff; border-radius: var(--r-sm); padding: 14px; margin-top: 12px; }
.self-qr svg, .self-qr canvas { width: 180px; height: 180px; }

/* ---------------- the board on the wall ----------------

   Read from three metres by someone holding a bag. Dark by default: a white
   screen at full brightness in a shop is what people dim until it stops being
   readable at all. */

.board-body {
  background: var(--board-bg, #0d1a13); color: #fff;
  min-height: 100dvh; overflow: hidden;
}
.board { height: 100dvh; display: flex; flex-direction: column; padding: 2.2vh 2vw; }

.board-boot, .board-arm {
  flex: 1; display: grid; place-content: center; justify-items: center;
  gap: 16px; text-align: center;
}
.board-arm h1 { font-size: clamp(24px, 4vw, 44px); margin: 0; }
.board-arm p { margin: 0; color: var(--board-dim, #9bb0a3); font-size: clamp(14px, 1.6vw, 19px); line-height: 1.7; }
.board-arm small { font-size: .8em; }
.board-arm .primary { max-width: 340px; min-height: 56px; font-size: 18px; }

.board-head { display: flex; align-items: center; justify-content: center; gap: 14px; margin-bottom: 2vh; }
.board-head img { height: clamp(30px, 4vh, 54px); width: auto; object-fit: contain; }
.board-head h1 { margin: 0; font-size: clamp(18px, 2.4vw, 34px); font-weight: 600; letter-spacing: -.02em; }

.board-cols { flex: 1; display: grid; grid-template-columns: 1fr 1fr; gap: 2vw; min-height: 0; }
.board-col {
  background: var(--board-panel, #16281d); border: 1px solid var(--board-rule, #24382c);
  border-radius: 22px; padding: 2vh 1.4vw; display: flex; flex-direction: column; min-height: 0;
}
.board-col h2 {
  margin: 0 0 1.4vh; text-align: center; font-weight: 600;
  font-size: clamp(15px, 1.9vw, 26px); color: var(--board-dim, #9bb0a3);
  letter-spacing: .04em;
}
.board-col.is-ready h2 { color: var(--board-ready, #8fdc63); }

.board-nums {
  flex: 1; min-height: 0; overflow: hidden;
  /* centred while the day is quiet, top-aligned once the column fills — `safe`
     keeps the first row reachable instead of overflowing off the top */
  display: flex; flex-wrap: wrap; align-content: safe center;
  justify-content: center; gap: .6vw 1.2vw;
  font-variant-numeric: tabular-nums; line-height: 1;
}
/* Each number is its own tile. Set side by side as bare digits, "2 1 5 4 3"
   reads as one five-digit number from across the room — which is the one thing
   this screen must never do. */
/* font-size now comes from fitNumbers() in queue.js, which measures the column
   instead of guessing from the viewport. The clamp stays as the value used for
   the first paint and if the script never runs. */
.board-nums { font-size: clamp(38px, 6.4vw, 104px); }
.board-nums span {
  font-size: 1em; font-weight: 700; letter-spacing: -.03em;
  padding: .12em .3em; border-radius: .22em; min-width: 1.6em; text-align: center;
  background: rgba(255,255,255,.05); border: 2px solid transparent;
}
.board-nums.making span { color: var(--board-making, #b9d4ab); }
.board-nums.ready  span {
  color: var(--board-ready, #8fdc63);
  border-color: color-mix(in srgb, var(--board-ready, #8fdc63) 34%, transparent);
  background: color-mix(in srgb, var(--board-ready, #8fdc63) 12%, transparent);
}
/* the one that just landed is the one somebody is looking for */
.board-nums.ready span.newest { animation: boardPop 1.2s ease; }
@keyframes boardPop {
  0%   { transform: scale(.7); opacity: 0; }
  40%  { transform: scale(1.08); opacity: 1; }
  100% { transform: scale(1); }
}
.board-none { font-size: clamp(30px, 5vw, 72px); color: var(--board-rule, #24382c); margin: auto; }

.board-foot { text-align: center; margin: 1.6vh 0 0; font-size: clamp(11px, 1.1vw, 15px); color: var(--board-dim, #9bb0a3); opacity: .75; }

/* a whole-screen acknowledgement, for the person who is not looking at it yet */
.board-flash .board-col.is-ready {
  animation: boardFlash 1.4s ease;
}
@keyframes boardFlash {
  0%, 100% { background: var(--board-panel, #16281d); }
  25%      { background: color-mix(in srgb, var(--board-ready, #8fdc63) 22%, var(--board-panel, #16281d)); }
}

@media (max-width: 700px) {
  .board-cols { grid-template-columns: 1fr; }
  .board-nums span { font-size: clamp(40px, 15vw, 90px); }
}

/* ---------------- self-order share on the year page ---------------- */

.year-self {
  display: grid; grid-template-columns: 1fr auto; gap: 2px 10px;
  align-items: baseline; margin-bottom: 12px; padding: 11px 13px;
  background: var(--forest-soft); border-radius: var(--r-sm);
}
.year-self span { font-size: 13px; font-weight: 500; color: var(--forest); }
.year-self b { font-size: 18px; font-weight: 700; font-variant-numeric: tabular-nums; color: var(--forest); }
.year-self small { grid-column: 1 / -1; font-size: 11.5px; color: var(--ink-2); }

/* the option group the customer still has to answer */
.opt-group.needs .opt-group-head b { color: var(--bad); }
.opt-group.needs .opt-choices {
  border-radius: var(--r-sm);
  animation: optNeeds 1.1s ease;
}
@keyframes optNeeds {
  0%, 100% { box-shadow: 0 0 0 0 transparent; }
  20%      { box-shadow: 0 0 0 3px var(--bad-bg); }
  60%      { box-shadow: 0 0 0 3px var(--bad-bg); }
}

/* ---------------- branch switcher ----------------
   Hidden entirely for the nine accounts in ten that have one shop. */
.shop-switch {
  max-width: 42vw; padding: 5px 26px 5px 10px; border-radius: 999px;
  font-size: 12.5px; font-weight: 500; color: var(--ink-2);
  background-color: var(--surface-2); border: 1px solid var(--rule);
  min-height: 0; margin-left: 8px;
}
.shop-switch:disabled { opacity: .5; }

/* ---------------------------------------------------------------------------
   /admin — the support console.

   Deliberately plainer than the shop app. This screen is somebody else's books;
   it should feel like a tool, not like the product, so nobody forgets whose
   money they are looking at. The banner never scrolls away. */

.admin-banner {
  position: sticky; top: 0; z-index: 30;
  background: var(--bad-bg); color: var(--bad);
  border-bottom: 1px solid var(--bad);
  padding: 9px 14px; font-size: 12px; font-weight: 500;
  text-align: center; line-height: 1.6;
}

.admin { max-width: 940px; margin: 0 auto; padding: 16px 14px 60px; }

.admin-login { max-width: 340px; margin: 12vh auto 0; }
.admin-login h1 { font-size: 22px; margin: 0 0 4px; letter-spacing: -.02em; }
.admin-login .hint { margin: 0 0 18px; }
.admin-login button, .admin-login .btn-link { width: 100%; margin-top: 14px; }
.admin-login .btn-link { display: block; text-align: center; text-decoration: none; box-sizing: border-box; }

.admin-top {
  display: flex; align-items: center; gap: 10px;
  padding: 4px 0 16px; border-bottom: 1px solid var(--rule); margin-bottom: 16px;
}
.admin-top button { flex: none; white-space: nowrap; }
.admin-top b {
  font-size: 17px; letter-spacing: -.01em; min-width: 0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.admin-who {
  margin-left: auto; font-size: 12px; color: var(--ink-3);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* on a phone the signed-in address is the least useful thing in the row and was
   eating the space the shop name needs */
@media (max-width: 480px) { .admin-who { max-width: 34vw; } }

.admin-search { display: flex; gap: 8px; }
.admin-search input {
  flex: 1; min-width: 0; padding: 11px 13px; font: inherit; font-size: 14px;
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--surface); color: var(--ink);
}
.admin-search input:focus { outline: 2px solid var(--forest); outline-offset: -1px; }
/* .primary is width:100%, and flex:none takes its basis from that width — the
   button claimed the whole row and squeezed the search field to 40px. */
.admin-search button { flex: 0 0 auto; width: auto; margin-top: 0; padding: 0 22px; }
.admin-search-hint { margin: 8px 0 0; }

.admin-stats {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
  gap: 10px; margin: 18px 0 6px;
}
.admin-stat {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r-sm); padding: 12px 14px;
}
.admin-stat b { display: block; font-size: 22px; letter-spacing: -.02em; }
.admin-stat span { font-size: 12px; color: var(--ink-3); }
.admin-stat.warn b { color: var(--warn); }
.admin-stat.bad b  { color: var(--bad); }

.admin-h2 { font-size: 13px; color: var(--ink-2); margin: 22px 0 8px; font-weight: 600; }
.admin-rows { display: grid; gap: 6px; }
.admin-row {
  display: grid; gap: 2px; text-align: left; width: 100%;
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r-sm); padding: 11px 14px; min-height: 44px;
  font: inherit; color: var(--ink); cursor: pointer;
}
.admin-row:hover { border-color: var(--forest); }
.admin-row b { font-size: 14px; overflow-wrap: anywhere; }
.admin-row span { font-size: 12px; color: var(--ink-3); overflow-wrap: anywhere; }
.admin-row i { font-style: normal; font-size: 12px; color: var(--ink-3); }
.admin-row i.warn { color: var(--warn); }
.admin-row i.bad  { color: var(--bad); font-weight: 600; }

.admin-card {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 14px; margin-top: 12px;
}
.admin-card-head { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.admin-card-head b { font-size: 14.5px; overflow-wrap: anywhere; }
.admin-meta { margin: 6px 0 0; font-size: 12px; color: var(--ink-3); line-height: 1.7; }
.admin-shops { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 11px; }
.admin-shops button {
  padding: 8px 12px; font: inherit; font-size: 13px; cursor: pointer;
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--surface-2); color: var(--ink);
}
.admin-shops button:hover { border-color: var(--forest); color: var(--forest); }
.admin-shops em { font-style: normal; color: var(--ink-3); font-size: 12px; }

.admin-grid { display: grid; grid-template-columns: 1fr; gap: 12px; }
.admin-panel {
  background: var(--surface); border: 1px solid var(--rule);
  border-radius: var(--r); padding: 14px 16px;
}
.admin-panel h2 { font-size: 13px; margin: 0 0 10px; color: var(--ink-2); font-weight: 600; }
.admin-panel dl { margin: 0; display: grid; gap: 7px; }
.admin-panel dl > div { display: flex; gap: 12px; align-items: baseline; font-size: 13px; }
.admin-panel dt { color: var(--ink-3); flex: none; min-width: 118px; }
.admin-panel dd { margin: 0; overflow-wrap: anywhere; }
.admin-panel dd .bad { color: var(--bad); }
.admin-panel .hint { margin: 0 0 10px; }

/* traffic lights — support should read a colour, not interpret a count */
.admin-lights { display: grid; gap: 2px; }
.admin-light {
  display: grid; grid-template-columns: 10px 1fr auto; align-items: center;
  gap: 10px; padding: 9px 2px; font-size: 13px;
  border-bottom: 1px solid var(--rule-soft);
}
.admin-light:last-child { border-bottom: 0; }
.admin-light > span { width: 10px; height: 10px; border-radius: 50%; }
.admin-light b { font-weight: 400; }
.admin-light small { font-size: 12px; color: var(--ink-3); text-align: right; }
.admin-light.good > span { background: var(--good); }
.admin-light.warn > span { background: var(--warn); }
.admin-light.bad  > span { background: var(--bad); }
.admin-light.bad  b { font-weight: 600; color: var(--bad); }

.admin-tools { display: flex; flex-wrap: wrap; gap: 8px; }
.admin-tools button { flex: none; }

.admin-log { margin: 0; padding: 0; list-style: none; display: grid; gap: 7px; font-size: 12.5px; }
.admin-log li { color: var(--ink-2); line-height: 1.6; overflow-wrap: anywhere; }
.admin-log b { font-weight: 600; color: var(--ink); }

.admin-reveal {
  margin: 12px 0 10px; padding: 9px 12px; font-size: 12.5px;
  background: var(--bad-bg); color: var(--bad); border-radius: var(--r-sm);
}
.admin-table { width: 100%; border-collapse: collapse; font-size: 12.5px; }
.admin-table th, .admin-table td { padding: 6px 8px; text-align: right; border-bottom: 1px solid var(--rule-soft); }
.admin-table th { color: var(--ink-3); font-weight: 500; }
.admin-table th:first-child, .admin-table td:first-child { text-align: left; }

@media (min-width: 760px) {
  .admin-grid { grid-template-columns: 1fr 1fr 1fr; }
  .admin-panel.wide { grid-column: 1 / -1; }
}

/* ---------------------------------------------------------------------------
   Brands — a franchise reading its branches' books.

   The notice that says "somebody else can see your takings" is styled as a
   warning and not as a hint on purpose. It is the single most consequential
   sentence in the settings screen. */

.brand-notice {
  display: grid; gap: 5px; margin-bottom: 12px;
  padding: 11px 13px; border-radius: var(--r-sm);
  background: var(--warn-bg); border: 1px solid var(--warn);
  font-size: 13px; line-height: 1.65;
}
.brand-notice b { color: var(--ink); }
.brand-notice span { color: var(--ink-2); font-size: 12.5px; }

/* small inline text actions — แก้ชื่อ / ลบกลุ่ม sit inside a heading row where a
   full button would outweigh the heading itself. Scoped, because the app's own
   .link-btn is a centred block and would break the row. */
.brand-group-head .link-btn {
  display: inline; margin: 0; padding: 3px 2px;
  font-size: 12.5px; font-weight: 500; color: var(--forest-mid);
}
.brand-group-head .link-btn.danger-link { color: var(--bad); }

.brand-group {
  margin: 0 0 12px; padding: 12px 14px;
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--surface-2);
}
.brand-group-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; font-size: 13px; }
.brand-group-head span { color: var(--ink-3); }
.brand-group-head b { font-size: 14.5px; margin-right: auto; overflow-wrap: anywhere; }

.brand-members { margin: 9px 0 0; padding-left: 18px; font-size: 13px; color: var(--ink-2); }
.brand-members li { line-height: 1.8; overflow-wrap: anywhere; }
.brand-members i { font-style: normal; color: var(--ink-3); font-size: 12px; }
.brand-empty { margin: 9px 0 0; font-size: 12.5px; color: var(--ink-3); }

/* the state that started all this: a group exists but this shop never joined it */
.brand-join {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  margin-top: 11px; padding-top: 11px; border-top: 1px solid var(--rule);
  font-size: 12.5px; color: var(--ink-2);
}
.brand-join span { flex: 1; min-width: 150px; line-height: 1.6; }
.brand-join button { flex: none; }

.invite-link {
  margin: 4px 0 0; padding: 11px 12px; border-radius: var(--r-sm);
  background: var(--surface-2); border: 1px solid var(--rule);
  font-size: 12.5px; line-height: 1.6; overflow-wrap: anywhere;
  user-select: all;                 /* one tap selects the whole link */
}

.brand-warn {
  margin: 0 0 12px; padding: 10px 12px; border-radius: var(--r-sm);
  background: var(--warn-bg); color: var(--ink-2);
  font-size: 12.5px; line-height: 1.7;
}

.app.brands-view .month-nav { display: none; }

.brand-lead { margin: 0 0 12px; font-size: 13px; color: var(--ink-2); line-height: 1.75; }

/* Phones get one block per branch and wide screens get the table. The table
   version had two of its five columns off the right edge of a phone with
   nothing to say so, which is why the page read as incomplete. */
.brand-cards { display: grid; gap: 12px; }
.brand-card {
  border: 1px solid var(--rule); border-radius: var(--r-sm);
  background: var(--surface-2); padding: 13px 15px;
}
.brand-card-head { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.brand-card-head b { font-size: 15px; overflow-wrap: anywhere; }
/* the shared .pill uses --surface-2, which is this card's own background — the
   chip was invisible until it got a surface of its own */
.brand-card-head .pill { background: var(--surface); border: 1px solid var(--rule); }
.brand-card-sub { margin: 3px 0 10px; font-size: 12px; color: var(--ink-3); }
.brand-card dl, .brand-total dl { margin: 0; display: grid; gap: 7px; }
.brand-card dl > div, .brand-total dl > div {
  display: flex; align-items: baseline; gap: 12px; font-size: 13.5px;
}
.brand-card dt, .brand-total dt { color: var(--ink-2); flex: 1; min-width: 0; }
.brand-card dd, .brand-total dd { margin: 0; font-weight: 600; text-align: right; white-space: nowrap; }
.brand-card dl > div.rule, .brand-total dl > div.rule {
  border-top: 1px solid var(--rule); padding-top: 8px; margin-top: 1px;
}
.brand-card i, .brand-total i { font-style: normal; font-weight: 400; color: var(--ink-3); }
.brand-card i.warn { color: var(--warn); }
.brand-card i.bad  { color: var(--bad); font-weight: 600; }

.brand-total {
  margin-top: 12px; padding: 13px 15px;
  border: 1px solid var(--forest); border-radius: var(--r-sm);
}
.brand-total > b { display: block; font-size: 13px; margin-bottom: 10px; }

.brand-table-wrap { display: none; overflow-x: auto; -webkit-overflow-scrolling: touch; }
@media (min-width: 760px) {
  .brand-cards { display: none; }
  .brand-table-wrap { display: block; }
  /* the table carries its own totals row at this width; the block below it was
     the same four numbers a second time */
  .brand-total { display: none; }
}
.brand-table { width: 100%; min-width: 480px; border-collapse: collapse; font-size: 13px; }
.brand-table th, .brand-table td {
  padding: 10px 10px; text-align: right; border-bottom: 1px solid var(--rule-soft);
  white-space: nowrap;
}
.brand-table th { font-size: 12px; color: var(--ink-3); font-weight: 500; }
/* On a phone the table has to scroll sideways, and a scrolled-away branch name
   turns every row into anonymous numbers. The name column stays put. */
.brand-table th:first-child, .brand-table td:first-child {
  text-align: left; white-space: normal;
  position: sticky; left: 0; z-index: 1;
  background: var(--surface); min-width: 130px;
  box-shadow: 1px 0 0 var(--rule-soft);
}
.brand-table tfoot td:first-child { box-shadow: 1px 0 0 var(--rule); }
.brand-table td:first-child b { display: block; font-weight: 600; }
.brand-table td small { display: block; font-size: 11.5px; color: var(--ink-3); margin-top: 2px; }
.brand-table i { font-style: normal; color: var(--ink-3); }
.brand-table i.warn { color: var(--warn); }
.brand-table i.bad { color: var(--bad); font-weight: 600; }
.brand-table tfoot td {
  border-bottom: 0; border-top: 1px solid var(--rule);
  font-weight: 600; color: var(--ink-2); font-size: 12.5px;
}

/* the invitation page */
.join-card { max-width: 420px; margin: 6vh auto 0; }
.join-card h1 { font-size: 20px; margin: 0 0 2px; letter-spacing: -.02em; }
.join-brand { margin: 0 0 16px; font-size: 15px; font-weight: 600; color: var(--forest); }
.join-terms {
  margin: 0 0 18px; padding: 13px 15px; border-radius: var(--r-sm);
  background: var(--surface); border: 1px solid var(--rule);
  font-size: 13px; line-height: 1.75;
}
.join-terms b { display: block; margin-bottom: 6px; }
.join-terms ul { margin: 0; padding-left: 18px; color: var(--ink-2); }
.join-terms ul b { display: inline; }
.join-card select { width: 100%; }
.join-card .primary { margin-top: 14px; }
.join-card .btn-link {
  display: block; text-align: center; text-decoration: none;
  margin-top: 10px; box-sizing: border-box; width: 100%;
}
.join-state { display: grid; place-items: center; gap: 10px; text-align: center; padding: 14vh 16px 0; }
.join-state h1 { font-size: 20px; margin: 0; }
.join-state p { margin: 0; color: var(--ink-2); font-size: 14px; line-height: 1.75; }
.join-state .btn-link {
  display: inline-block; margin-top: 10px; min-width: 200px;
  text-align: center; text-decoration: none; box-sizing: border-box;
}
/* the unused state: present, but as close to nothing as a card can be */
.card.brand-idle > .hint:last-child { display: none; }
.card.brand-idle .actions { margin-top: 2px; }

/* ---------------------------------------------------------------------------
   Tap targets.

   Measured every button in the app at 375px. A batch of small controls sat at
   20–32px tall — under the 44px a fingertip actually covers — and several of
   them are destructive (the ลบ buttons in every list). Making them visually
   bigger would loosen lists that are deliberately dense, so the ones that must
   stay small get an invisible hit area instead: the button looks the same and
   catches presses 44px tall.

   Where the button is alone in a row and nothing depends on it being small, it
   just gets bigger. */

.icon-btn, .goal-edit, .menu-back, .link-inline,
.brand-group-head .link-btn, .pos-cart-head .ghost,
.seg button, .set-tabs button, .chip, .tally-cats .chip {
  position: relative;
}
.icon-btn::after, .goal-edit::after, .menu-back::after, .link-inline::after,
.brand-group-head .link-btn::after, .pos-cart-head .ghost::after,
.seg button::after, .set-tabs button::after, .chip::after, .tally-cats .chip::after {
  content: ''; position: absolute; inset: 50% 0 auto 0;
  height: 44px; transform: translateY(-50%);
}

/* The first version also widened the area by 6px a side. That put "แก้ชื่อ" on
   top of "ลบกลุ่ม", and "ประวัติบิล" on top of the ✕ that empties the cart —
   a press aimed at one would land on whichever came later in the DOM. Two of
   those three neighbours are destructive, so the widening is gone entirely:
   height only, and narrow controls get real padding instead. */
.brand-group-head .link-btn { padding: 6px 7px; }
.link-inline { padding: 6px 7px; margin-left: 4px; }

/* These sit inline beside a label with clear space above and below, so they get
   both: a slightly bigger box and the invisible area on top of it. */
.goal-edit { min-height: 34px; padding: 6px 12px; }

/* Same role, same height. secondary/ghost were landing on 37, 38 and 44
   depending on which card they were in, which is the kind of thing that reads
   as sloppy without anyone being able to say why. */
.card.settings .ghost, .card.settings .secondary, .kds-head .secondary { min-height: 44px; }

/* A button that wraps to two lines beside two that do not makes the row look
   broken. Three actions on one line at 375px is one too many — they stack
   evenly instead. */
@media (max-width: 430px) {
  /* .actions is a fixed two-column grid, so the third button sat alone on row
     two and the longest label wrapped to 56px beside two 44px neighbours. One
     column per row at this width: every action the same size, in reading order,
     the primary one first. */
  #brandActions { grid-template-columns: 1fr; gap: 8px; }
  #brandActions button { min-height: 44px; }
}

/* .primary carries margin-top:16px for the common case of a save button sitting
   alone under a form. Inside a row of actions that margin belongs to nobody: it
   inflated the flex line to 68px, and the ghost beside it stretched to 64 while
   the primary stayed 52. Same row, same height. */
.actions { align-items: stretch; }
.actions .primary { margin-top: 0; }

/* an ✕ 29px wide is a miss waiting to happen */
#cartClose, .pos-cart-head .ghost[aria-label] { min-width: 44px; }

/* Cart quantity steppers are 34px because the cart line is dense and they look
   right at that size — so they keep the size and get the area. The pair sits
   with a gap between them, so height only, same as everywhere else. */
/* 34px wide with a 44px-tall area is the compromise: these two sit side by side,
   so widening the *area* would make − and + overlap each other, which is the one
   place a stray tap changes a number. The visible box grows a little instead. */
.stepper button { position: relative; min-width: 40px; }
.stepper button::after {
  content: ''; position: absolute; inset: 50% 0 auto 0;
  height: 44px; transform: translateY(-50%);
}
#cartClose { position: relative; }
#cartClose::after {
  content: ''; position: absolute; inset: 50% 0 auto 0;
  height: 44px; transform: translateY(-50%);
}

/* branches inside one account — the list is a reminder of which one you are
   standing in, not a switcher; the switcher lives in the header */
.branch-list { margin: 0 0 12px; padding: 0; list-style: none; display: grid; gap: 6px; }
.branch-list li {
  padding: 10px 13px; border-radius: var(--r-sm);
  border: 1px solid var(--rule); background: var(--surface-2);
  font-size: 13.5px; overflow-wrap: anywhere;
}
.branch-list li.on { border-color: var(--forest); }
.branch-list i { font-style: normal; font-size: 12px; color: var(--ink-3); }
