/* bidnwin
 *
 * Colour is declared once, here, as roles. Every SVG the engine generates
 * references these custom properties rather than literal hex, so light and dark
 * are one definition and the charts are theme-agnostic.
 *
 * The categorical slots are 1–3 of the validated palette (blue / orange /
 * aqua): they clear the all-pairs CVD and normal-vision floors in both modes.
 * Aqua sits below 3:1 on the light surface, so every series drawn in it is
 * directly labelled — that is the relief rule, not an oversight.
 *
 * Polarity uses the diverging pair blue ↔ red. Status colours are reserved and
 * always ship with a word beside them; colour never carries meaning alone.
 */

:root {
  color-scheme: light;

  --plane:        #f9f9f7;
  --surface-1:    #fcfcfb;
  --ink:          #0b0b0b;
  --ink-2:        #52514e;
  --muted:        #898781;
  --grid:         #e1e0d9;
  --baseline:     #c3c2b7;
  --border:       rgba(11, 11, 11, 0.10);
  --track:        #ececE6;

  --series-1:     #2a78d6;   /* blue   */
  --series-2:     #eb6834;   /* orange */
  --series-3:     #1baf7a;   /* aqua   */

  --pos:          #2a78d6;   /* diverging: adds    */
  --neg:          #d03b3b;   /* diverging: deducts */
  --neutral-mark: #898781;   /* diverging midpoint / totals */

  --status-good:     #0ca30c;
  --status-warning:  #fab219;
  --status-serious:  #ec835a;
  --status-critical: #d03b3b;
  --status-neutral:  #898781;
  --success-text:    #006300;

  --radius: 10px;
  --pad: 20px;

  /* The stand-in tile for a thing with no photograph. Only the lightness
     and saturation change between themes; the hue comes from the thing's
     own name (see the `tint` filter). */
  --thumb-s:      34%;
  --thumb-top:    93%;
  --thumb-bottom: 84%;
  --thumb-ink-s:  42%;
  --thumb-ink-l:  33%;
}

@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    color-scheme: dark;
    --plane:      #0d0d0d;
    --surface-1:  #1a1a19;
    --ink:        #ffffff;
    --ink-2:      #c3c2b7;
    --muted:      #898781;
    --grid:       #2c2c2a;
    --baseline:   #383835;
    --border:     rgba(255, 255, 255, 0.10);
    --track:      #2c2c2a;

    --series-1:   #3987e5;
    --series-2:   #d95926;
    --series-3:   #199e70;

    --pos:        #3987e5;
    --neg:        #d03b3b;
    --success-text: #0ca30c;

    --thumb-s:      26%;
    --thumb-top:    27%;
    --thumb-bottom: 17%;
    --thumb-ink-s:  40%;
    --thumb-ink-l:  76%;
  }
}

:root[data-theme="dark"] {
  color-scheme: dark;
  --plane:      #0d0d0d;
  --surface-1:  #1a1a19;
  --ink:        #ffffff;
  --ink-2:      #c3c2b7;
  --muted:      #898781;
  --grid:       #2c2c2a;
  --baseline:   #383835;
  --border:     rgba(255, 255, 255, 0.10);
  --track:      #2c2c2a;

  --series-1:   #3987e5;
  --series-2:   #d95926;
  --series-3:   #199e70;

  --pos:        #3987e5;
  --neg:        #d03b3b;
  --success-text: #0ca30c;

  --thumb-s:      26%;
  --thumb-top:    27%;
  --thumb-bottom: 17%;
  --thumb-ink-s:  40%;
  --thumb-ink-l:  76%;
}


* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--plane);
  color: var(--ink);
  font: 15px/1.5 system-ui, -apple-system, "Segoe UI", sans-serif;
  -webkit-font-smoothing: antialiased;
}

a { color: var(--series-1); text-decoration: none; }
a:hover { text-decoration: underline; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}
.skip {
  position: absolute; left: -9999px; top: 0; padding: 10px 14px;
  background: var(--surface-1); z-index: 20;
}
.skip:focus { left: 8px; top: 8px; }

/* ───────────────────────────────────────────────────────────────── topbar */

.topbar {
  display: flex; align-items: center; gap: 18px;
  padding: 12px 24px;
  background: var(--surface-1);
  border-bottom: 1px solid var(--border);
  position: sticky; top: 0; z-index: 10;
  flex-wrap: wrap;
}
.brand {
  display: flex; align-items: center; gap: 9px;
  font-weight: 650; letter-spacing: -0.01em; color: var(--ink);
}
.brand:hover { text-decoration: none; }
.brand-mark {
  width: 15px; height: 15px; border-radius: 4px;
  background: linear-gradient(135deg, var(--series-1), var(--series-3));
}
.search { flex: 1 1 280px; min-width: 200px; }
.search input {
  width: 100%; padding: 8px 12px;
  border: 1px solid var(--border); border-radius: 8px;
  background: var(--plane); color: var(--ink); font: inherit;
}
.search input:focus { outline: 2px solid var(--series-1); outline-offset: 1px; }
.topnav { display: flex; gap: 16px; }
.topnav a { color: var(--ink-2); font-size: 14px; }
.theme-toggle {
  border: 1px solid var(--border); background: var(--plane); color: var(--ink-2);
  border-radius: 8px; width: 34px; height: 34px; cursor: pointer; font-size: 15px;
}

main { max-width: 1180px; margin: 0 auto; padding: 26px 24px 60px; }

/* ───────────────────────────────────────────────────────── page furniture */

.page-head { margin-bottom: 22px; }
.page-head h1 { font-size: 25px; margin: 0 0 4px; letter-spacing: -0.015em; }
.page-head .sub { color: var(--ink-2); margin: 0; font-size: 14px; }
.crumb { font-size: 13px; color: var(--muted); margin: 0 0 6px; }

.panel {
  background: var(--surface-1);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: var(--pad);
  margin-bottom: 20px;
}
.panel > h2 {
  font-size: 13px; text-transform: uppercase; letter-spacing: 0.07em;
  color: var(--muted); margin: 0 0 4px; font-weight: 650;
}
.panel > .panel-note {
  color: var(--ink-2); font-size: 13px; margin: 0 0 16px; max-width: 68ch;
}
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
@media (max-width: 900px) { .grid-2 { grid-template-columns: 1fr; } }

/* ───────────────────────────────────────────────────────────── stat tiles */

.tiles {
  display: grid; gap: 14px; margin-bottom: 20px;
  grid-template-columns: repeat(auto-fit, minmax(168px, 1fr));
}
.tile {
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 15px 17px;
}
.tile .label {
  font-size: 12px; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--muted); font-weight: 650;
}
.tile .value {
  font-size: 27px; line-height: 1.15; margin-top: 6px; letter-spacing: -0.02em;
}
.tile .value .unit { font-size: 14px; color: var(--ink-2); margin-left: 3px; }
.tile .note { font-size: 12.5px; color: var(--ink-2); margin-top: 5px; }
.tile.good  .value { color: var(--success-text); }
.tile.warn  .value { color: var(--ink); }

/* ─────────────────────────────────────────────────────────────── the viz */

.viz { display: block; width: 100%; overflow: visible; }
.viz-label { font: 600 12px system-ui, sans-serif; fill: var(--ink); }
.viz-sub   { font: 11px system-ui, sans-serif; fill: var(--muted); }
.viz-value { font: 600 11.5px system-ui, sans-serif; fill: var(--ink-2); }
.viz-scroll { overflow-x: auto; }

.legend { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 10px; }
.legend span { display: inline-flex; align-items: center; gap: 6px;
               font-size: 12.5px; color: var(--ink-2); }
.swatch { width: 11px; height: 11px; border-radius: 3px; display: inline-block; }

/* ───────────────────────────────────────────────────────────────── tables */

table { width: 100%; border-collapse: collapse; font-size: 14px; }
th {
  text-align: left; font-size: 11.5px; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--muted); font-weight: 650;
  padding: 8px 10px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
td { padding: 9px 10px; border-bottom: 1px solid var(--grid); vertical-align: top; }
tbody tr:last-child td { border-bottom: none; }
tbody tr:hover { background: color-mix(in srgb, var(--series-1) 5%, transparent); }
.num { text-align: right; font-variant-numeric: tabular-nums; white-space: nowrap; }
.neg { color: var(--neg); }
.pos { color: var(--success-text); }
.table-scroll { overflow-x: auto; margin: 0 calc(var(--pad) * -1) calc(var(--pad) * -1); }
/* A table narrow enough to fit its panel wants none of what `.table-scroll`
   does for a wide one: no 720px floor forcing it sideways, no bleeding to the
   panel edge, and above all no negative bottom margin — which lifted a total
   row clean out of its own rounded box, where `overflow: hidden` then clipped
   it. Scrolls only if it genuinely has to. */
.fits { overflow-x: auto; margin: 0; }
.fits table { min-width: 0; }
.table-scroll table { min-width: 720px; }
.table-scroll th:first-child, .table-scroll td:first-child { padding-left: var(--pad); }
.table-scroll th:last-child,  .table-scroll td:last-child  { padding-right: var(--pad); }

tr.group td { background: color-mix(in srgb, var(--ink) 3%, transparent); font-weight: 600; }
tr.total td { border-top: 2px solid var(--baseline); font-weight: 650; }
.item-no { font-variant-numeric: tabular-nums; color: var(--ink-2); white-space: nowrap; }
.desc { max-width: 46ch; color: var(--ink-2); font-size: 13px; }

/* ─────────────────────────────────────────────────────────────── chips */

.chip {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 600;
  border: 1px solid var(--border); color: var(--ink-2); white-space: nowrap;
}
.chip::before {
  content: ""; width: 7px; height: 7px; border-radius: 50%;
  background: var(--status-neutral);
}
.chip.good::before     { background: var(--status-good); }
.chip.warning::before  { background: var(--status-warning); }
.chip.serious::before  { background: var(--status-serious); }
.chip.critical::before { background: var(--status-critical); }
.chip.neutral::before  { background: var(--status-neutral); }
.chip-plain::before { display: none; }

.tag {
  display: inline-block; padding: 1px 7px; border-radius: 5px;
  background: color-mix(in srgb, var(--series-1) 12%, transparent);
  color: var(--ink-2); font-size: 11.5px; font-weight: 600;
}
/* Which of the two things the network sells. The same word has to mean the
   same colour at the till, on the bill and on the customer's own page, so
   the modifiers live here rather than in one surface's stylesheet. */
.tag-emi   { background: color-mix(in srgb, var(--series-1) 14%, transparent); color: var(--series-1); }
.tag-bnpl  { background: color-mix(in srgb, var(--series-2) 14%, transparent); color: var(--series-2); }
.tag-demo  { background: var(--track); color: var(--ink-2); }

/* A label-and-figure grid. Hairline cells so a row of facts reads as one
   object rather than as several. Defined here because the till, a bill and a
   customer's own page all want the same thing. */
.facts {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: 1px; margin: 0; background: var(--grid);
  border: 1px solid var(--grid); overflow: hidden;
}
.facts > div { background: var(--surface-1); padding: 9px 12px; }
.facts dt { font-size: 10px; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); margin: 0 0 2px; }
.facts dd { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.facts dd.free { color: var(--success-text); }

/* A list of things happening now — a delivery crossing town, an appointment
   this afternoon. One row each, what it is on the left, where it has got to
   on the right. */
.live-list { display: flex; flex-direction: column; }
.live-row {
  display: flex; justify-content: space-between; align-items: flex-start; gap: 16px;
  flex-wrap: wrap; padding: 11px 0; border-top: 1px solid var(--grid);
}
.live-row:first-child { border-top: 0; }
.live-what { font-weight: 600; }
.live-row .desc { margin: 2px 0 0; }
.live-aside { text-align: right; }

/* What went where this month. One measure across a few shops, so one hue:
   the shop's name says which row is which, and a second colour would be
   decoration pretending to carry data. Every row is a link. */
.spend { display: flex; flex-direction: column; }
.spend-row {
  display: grid; grid-template-columns: minmax(7em, 12em) 1fr auto;
  align-items: center; gap: 12px; padding: 8px 0; color: inherit; text-decoration: none;
  border-top: 1px solid var(--grid);
}
.spend-row:first-child { border-top: 0; }
.spend-row:hover { text-decoration: none; }
.spend-row:hover .spend-who { color: var(--series-1); }
.spend-who { font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.spend-track { height: 10px; background: var(--track); }
.spend-bar {
  display: block; height: 100%; background: var(--series-1);
  /* Anchored to the baseline; only the growing end is rounded. */
  border-radius: 0 4px 4px 0;
}
.spend-amt { font-weight: 600; font-variant-numeric: tabular-nums; }
@media (max-width: 460px) {
  .spend-row { grid-template-columns: 1fr auto; }
  .spend-track { display: none; }
}

/* ─────────────────────────────────────────────── a customer's ways to pay */

.methods { display: grid; gap: 14px; grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }
.method {
  display: flex; flex-direction: column; gap: 10px;
  padding: 18px; border: 1px solid var(--border); border-radius: var(--radius);
  background: var(--surface-1);
}
.method-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.method-head h2 { margin: 0 0 3px; font-size: 18px; }
.method-head .desc { margin: 0; max-width: 42ch; }
.method-detail { margin: 0; font-weight: 600; font-variant-numeric: tabular-nums; }
.method-note { margin: 0; font-size: 13px; color: var(--muted); }
.method .actions { margin-top: auto; }

/* ──────────────────────────────────────────────────── a customer's credit */

/* The next thing they owe. It is the one figure on the page somebody opens
   it to see, so it is the largest. */
.next-due .due-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 18px; flex-wrap: wrap; }
.due-figure { font-size: 30px; font-weight: 700; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; margin: 2px 0 3px; }
.due-when { text-align: right; }
.due-date { font-size: 15px; font-weight: 600; font-variant-numeric: tabular-nums; margin-bottom: 5px; }

.loan-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; flex-wrap: wrap; }
.loan-head h2 { margin: 0 0 3px; }
.loan-who .desc { margin: 0; }
.loan-money { display: flex; flex-wrap: wrap; gap: 10px 34px; margin: 15px 0 12px; }
.loan-figure { font-size: 17px; font-weight: 600; font-variant-numeric: tabular-nums; }
.loan-figure.strong { color: var(--ink); font-weight: 700; }
.loan-progress { display: flex; align-items: center; gap: 11px; margin-bottom: 12px; }
.loan-progress .bar { flex: 1 1 auto; min-width: 120px; }
.loan-progress .desc { white-space: nowrap; }
.sched-fold > summary { margin-bottom: 8px; }

/* A schedule is read by finding one row in it: the next one, or a late one.
   Everything else is background. */
.due-table { width: 100%; border-collapse: collapse; font-variant-numeric: tabular-nums; }
.due-table th, .due-table td { padding: 7px 10px; text-align: left; border-bottom: 1px solid var(--grid); }
.due-table th { font-size: 11.5px; font-weight: 600; color: var(--muted); letter-spacing: .04em; text-transform: uppercase; }
.due-table .num { text-align: right; }
.due-table .rn { color: var(--muted); width: 3em; }
.due-table tbody tr:last-child td { border-bottom: 0; }
.due-table tr.is-paid td { color: var(--muted); }
.due-table tr.is-next td { background: color-mix(in srgb, var(--status-warning) 8%, transparent); font-weight: 600; }
.due-table tr.is-late td { background: color-mix(in srgb, var(--status-critical) 8%, transparent); font-weight: 600; }

/* ───────────────────────────────────────────────────────────── contracts */

.cards { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(340px, 1fr)); }
.card {
  background: var(--surface-1); border: 1px solid var(--border);
  border-radius: var(--radius); padding: 18px; display: block; color: inherit;
}
.card:hover { text-decoration: none; border-color: var(--series-1); }
.card h3 { margin: 0 0 3px; font-size: 16px; letter-spacing: -0.01em; }
.card .no { font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.card .parties { font-size: 13px; color: var(--ink-2); margin: 10px 0 14px; }
.bar { height: 9px; border-radius: 5px; background: var(--track); overflow: hidden; }
.bar > i { display: block; height: 100%; border-radius: 5px; background: var(--series-1); }
.bar > i.over { background: var(--status-warning); }
.card .figures { display: flex; justify-content: space-between; gap: 12px;
                 margin-top: 9px; font-size: 12.5px; color: var(--ink-2); }

.kv { display: grid; grid-template-columns: auto 1fr; gap: 5px 18px; font-size: 13.5px; }
.kv dt { color: var(--muted); }
.kv dd { margin: 0; font-variant-numeric: tabular-nums; }

/* ───────────────────────────────────────────────────────────────── forms */

form.stack { display: grid; gap: 13px; max-width: 460px; }
.field { display: grid; gap: 4px; }
.field label { font-size: 12.5px; color: var(--ink-2); font-weight: 600; }
.field input, .field select, .field textarea {
  padding: 8px 11px; border: 1px solid var(--border); border-radius: 8px;
  background: var(--plane); color: var(--ink); font: inherit;
}
.field .hint { font-size: 12px; color: var(--muted); }
.row2 { display: grid; grid-template-columns: 1fr 1fr; gap: 13px; }
.check { display: flex; align-items: center; gap: 8px; font-size: 13.5px; color: var(--ink-2); }
button.primary {
  padding: 9px 18px; border-radius: 8px; border: none; cursor: pointer;
  background: var(--series-1); color: #fff; font: inherit; font-weight: 600;
  justify-self: start;
}
button.primary:hover { filter: brightness(1.06); }

.notice {
  padding: 11px 14px; border-radius: 8px; font-size: 13.5px; margin-bottom: 16px;
  border: 1px solid var(--border);
  background: color-mix(in srgb, var(--status-good) 10%, transparent);
}
.notice-bad {
  background: color-mix(in srgb, var(--status-critical) 10%, transparent);
}
.notice p { margin: 4px 0 0; }

/* ──────────────────────────────────────────────────────────────── lookup */

.facets { display: flex; gap: 8px; flex-wrap: wrap; margin-bottom: 18px; }
.facets a { font-size: 12.5px; }
.facets a.on .chip { border-color: var(--series-1); color: var(--ink); }
.hits { display: grid; gap: 2px; }
.hit {
  display: grid; grid-template-columns: 104px 1fr auto; gap: 16px;
  padding: 12px 14px; border-radius: 8px; color: inherit; align-items: baseline;
}
.hit:hover { background: color-mix(in srgb, var(--series-1) 6%, transparent);
             text-decoration: none; }
.hit .k { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.05em;
          color: var(--muted); font-weight: 650; }
.hit .t { font-weight: 600; }
.hit .s { font-size: 13px; color: var(--ink-2); }
.hit .d { font-size: 12.5px; color: var(--muted); margin-top: 2px; }
@media (max-width: 700px) { .hit { grid-template-columns: 1fr; gap: 3px; } }

.empty { color: var(--muted); padding: 26px 0; text-align: center; }

/* ────────────────────────────────────────────────────────── the Top Sheet */

.topsheet td, .topsheet th { padding: 7px 10px; }
.topsheet .row-label { color: var(--ink-2); }
.topsheet .rowid {
  color: var(--muted); font-weight: 650; width: 26px;
  font-variant-numeric: tabular-nums;
}
.topsheet tr.generated td { background: color-mix(in srgb, var(--series-1) 6%, transparent); }
.topsheet .gen-flag { font-size: 11px; color: var(--series-1); font-weight: 650; }

.signatures {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 18px; margin-top: 8px;
}
.sig { border-top: 1px solid var(--baseline); padding-top: 8px; font-size: 13px; }
.sig .role { font-size: 11.5px; text-transform: uppercase; letter-spacing: 0.05em;
             color: var(--muted); font-weight: 650; }

.foot {
  max-width: 1180px; margin: 0 auto; padding: 22px 24px 40px;
  border-top: 1px solid var(--border); color: var(--muted); font-size: 12.5px;
}
.foot p { margin: 0; max-width: 78ch; }
code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.92em; }

.tabs { display: flex; gap: 4px; margin-bottom: 18px; flex-wrap: wrap; }
.tabs a {
  padding: 7px 14px; border-radius: 8px; font-size: 13.5px; color: var(--ink-2);
  border: 1px solid transparent;
}
.tabs a.on { background: var(--surface-1); border-color: var(--border); color: var(--ink);
             font-weight: 600; }

/* ────────────────────────────────────────────────────────── notifications */

.bell-count {
  position: absolute; top: -4px; right: -4px; min-width: 16px; height: 16px;
  border-radius: 8px; padding: 0 4px; font-size: 10px; line-height: 16px;
  background: var(--status-critical); color: #fff; text-align: center;
}
#bell { position: relative; }
#bell .bell-count:empty { display: none; }
.toasts {
  position: fixed; right: 18px; bottom: 18px; display: grid; gap: 8px;
  z-index: 50; max-width: 340px;
}
.toast {
  display: grid; gap: 2px; padding: 11px 14px; border-radius: 10px;
  background: var(--surface-1); border: 1px solid var(--border); color: inherit;
  box-shadow: 0 6px 24px rgba(0,0,0,.18); font-size: 13.5px;
  transition: opacity .4s, transform .4s;
}
.toast strong { font-weight: 650; }
.toast span { color: var(--ink-2); }
.toast.gone { opacity: 0; transform: translateY(6px); }

/* The module's own name sits under the platform's, on a module page. */
.brand-sub{display:block;font-size:.62em;font-weight:500;opacity:.62;letter-spacing:.02em;line-height:1}

/* ---------------------------------------------------------------------------
   A plan is a picture of a place: tables on a floor, chairs in a salon,
   rooms, aisles. The renderer is `platform::plan::svg`; every tone carries
   a word as well as a colour, because colour alone is the fastest thing on
   a screen and the least reliable.
   --------------------------------------------------------------------------- */
.plan-wrap { width: 100%; overflow-x: auto; }
.floorplan { width: 100%; height: auto; max-height: 68vh; display: block; }
.plan-grid line { stroke: var(--grid); stroke-width: 1; }
.plan-editing .plan-grid line { stroke-dasharray: 2 4; }

.spot rect, .spot ellipse {
  fill: var(--surface-1); stroke: var(--baseline); stroke-width: 1.5;
  transition: fill .12s, stroke .12s;
}
.spot text { fill: var(--ink); font-family: inherit; }
.spot text.label { font-size: 15px; font-weight: 640; }
.spot text.status, .spot text.line { font-size: 11.5px; fill: var(--ink-2); }

.spot.free rect, .spot.free ellipse { fill: color-mix(in srgb, var(--status-good) 12%, var(--surface-1)); stroke: var(--status-good); }
.spot.busy rect, .spot.busy ellipse { fill: color-mix(in srgb, var(--status-warning) 20%, var(--surface-1)); stroke: var(--status-warning); }
.spot.soon rect, .spot.soon ellipse { fill: color-mix(in srgb, var(--series-1) 12%, var(--surface-1)); stroke: var(--series-1); }
.spot.idle rect, .spot.idle ellipse { fill: var(--track); stroke: var(--baseline); }
.spot.idle text.label { font-weight: 500; fill: var(--ink-2); }
.spot.gone rect, .spot.gone ellipse { fill: none; stroke: var(--status-critical); stroke-dasharray: 5 4; }
.spot.gone text { fill: var(--status-critical); }

.spot.tap { cursor: pointer; }
.spot.tap:hover rect, .spot.tap:hover ellipse { stroke-width: 2.5; }
.spot.tap:focus { outline: none; }
.spot.tap:focus-visible rect, .spot.tap:focus-visible ellipse { stroke: var(--ink); stroke-width: 3; }
a.spot { text-decoration: none; }

/* The four boxes that say where a spot is, side by side. */
.nudge { display: flex; gap: 4px; align-items: center; }
.nudge input { max-width: 3.6rem; }
tr.row-bad td { background: color-mix(in srgb, var(--status-critical) 8%, transparent); }

/* The key under a plan: what each colour means, in words. */
.plan-key { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px; font-size: 13px; color: var(--ink-2); }
.plan-key span { display: inline-flex; align-items: center; gap: 6px; }
.plan-key i { width: 13px; height: 13px; border-radius: 4px; border: 1.5px solid var(--baseline); background: var(--surface-1); }
.plan-key i.free { background: color-mix(in srgb, var(--status-good) 12%, var(--surface-1)); border-color: var(--status-good); }
.plan-key i.busy { background: color-mix(in srgb, var(--status-warning) 20%, var(--surface-1)); border-color: var(--status-warning); }
.plan-key i.soon { background: color-mix(in srgb, var(--series-1) 12%, var(--surface-1)); border-color: var(--series-1); }
.plan-key i.idle { background: var(--track); }

/* ---------------------------------------------------------------------------
   The shell: one sidebar, one top bar, one phone tab bar, drawn for every
   page by platform::nav::fill. No page writes a menu link.
   --------------------------------------------------------------------------- */
:root { --console: #3d3a8c; }
@media (prefers-color-scheme: dark) { :root:where(:not([data-theme="light"])) { --console: #a9a5f5; } }
:root[data-theme="dark"] { --console: #a9a5f5; }

.shell { display: flex; min-height: 100vh; }
.shell-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.shell-main > main { width: 100%; }

.side {
  flex: none; width: 248px; position: sticky; top: 0; height: 100vh; overflow-y: auto;
  background: var(--surface-1); border-right: 1px solid var(--border);
  display: flex; flex-direction: column;
}
.side-head { padding: 16px 16px 12px; border-bottom: 1px solid var(--border); display: grid; gap: 3px; }
.side-org { display: flex; align-items: center; gap: 9px; font-weight: 650; letter-spacing: -0.01em; color: var(--ink); }
.side-org:hover { text-decoration: none; }
.side-sub { padding-left: 24px; font-size: 12.5px; color: var(--muted); }
.side-tag {
  margin-left: 24px; justify-self: start; padding: 1px 7px; border-radius: 4px;
  font-size: 10.5px; font-weight: 650; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--console); background: color-mix(in srgb, var(--console) 12%, transparent);
}
.brand-mark-console { background: linear-gradient(135deg, var(--console), var(--series-1)); }
.side-groups { flex: 1; padding: 8px; display: grid; gap: 6px; align-content: start; }
.side-label { font-size: 10.5px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted); font-weight: 650; padding: 8px 8px 3px; }
.side-link {
  display: flex; align-items: center; gap: 10px; min-height: 30px; padding: 4px 8px;
  border-radius: 7px; color: var(--ink-2); font-size: 13.5px;
}
.side-link svg { width: 16px; height: 16px; flex: none; }
.side-link:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); color: var(--ink); text-decoration: none; }
.side-link[aria-current="page"] { background: color-mix(in srgb, var(--series-1) 12%, transparent); color: var(--series-1); font-weight: 600; }
.side-admin .side-link[aria-current="page"] { background: color-mix(in srgb, var(--console) 12%, transparent); color: var(--console); }
.side-foot { border-top: 1px solid var(--border); padding: 12px 16px; font-size: 12.5px; color: var(--ink-2); display: grid; gap: 1px; }
.side-foot span + span { color: var(--muted); }

.top-gap { flex: 1 1 auto; }
.shell-brand { display: none; }
.signin { padding: 7px 14px; border-radius: 8px; background: var(--series-1); color: #fff; font-weight: 600; font-size: 14px; }
.signin:hover { text-decoration: none; filter: brightness(1.06); }
.usermenu { position: relative; }
.usermenu > summary { list-style: none; cursor: pointer; }
.usermenu > summary::-webkit-details-marker { display: none; }
.avatar {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  background: var(--track); border: 1px solid var(--border); color: var(--ink-2); font-size: 12.5px; font-weight: 600;
}
.usermenu-panel {
  position: absolute; right: 0; top: 42px; z-index: 40; min-width: 230px; padding: 8px;
  display: grid; gap: 2px; background: var(--surface-1); border: 1px solid var(--border);
  border-radius: 10px; box-shadow: 0 10px 30px rgba(0, 0, 0, 0.14);
}
.usermenu-panel strong { padding: 6px 10px 0; }
.usermenu-who { padding: 0 10px 6px; font-size: 12.5px; color: var(--muted); }
.usermenu-panel a { padding: 8px 10px; border-radius: 7px; color: var(--ink); font-size: 14px; }
.usermenu-panel a:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); text-decoration: none; }
.signout { margin: 0; }
.signout button {
  width: 100%; text-align: left; padding: 8px 10px; border: 0; border-radius: 7px; background: none;
  color: var(--ink); font: inherit; font-size: 14px; cursor: pointer;
}
.signout button:hover { background: color-mix(in srgb, var(--ink) 5%, transparent); }
.side-foot .signout { margin-top: 8px; }
.side-foot .signout button { padding: 6px 0; font-size: 13px; color: var(--ink-2); }
.side-foot .signout button:hover { background: none; color: var(--ink); text-decoration: underline; }

.today-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; }
.today-tile {
  min-height: 96px; display: flex; flex-direction: column; justify-content: space-between; gap: 12px;
  padding: 16px; border-radius: 12px; background: var(--surface-1); border: 1px solid var(--border);
  color: var(--ink); font-weight: 600;
}
.today-tile svg { width: 24px; height: 24px; color: var(--series-1); }
.today-tile:hover { text-decoration: none; border-color: color-mix(in srgb, var(--series-1) 40%, transparent); }

.tabbar { display: none; }
@media (max-width: 860px) {
  .side { display: none; }
  .shell-brand { display: flex; }
  .topbar .topnav { display: none; }
  .tabbar {
    display: flex; position: fixed; left: 0; right: 0; bottom: 0; z-index: 30;
    background: var(--surface-1); border-top: 1px solid var(--border);
    padding: 4px 4px calc(8px + env(safe-area-inset-bottom));
  }
  .tab, .tab-more {
    flex: 1 1 0; min-width: 0;
  }
  .tab {
    min-height: 52px; display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 2px; font-size: 11px; color: var(--muted); list-style: none; cursor: pointer;
  }
  .tab::-webkit-details-marker { display: none; }
  .tab svg { width: 22px; height: 22px; }
  .tab span { max-width: 100%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .tab:hover { text-decoration: none; }
  .tab[aria-current="page"] { color: var(--series-1); font-weight: 600; }
  .tab-more .sheet {
    position: fixed; left: 0; right: 0; bottom: 64px; max-height: 72vh; overflow-y: auto;
    background: var(--surface-1); border-top: 1px solid var(--border); border-radius: 16px 16px 0 0;
    box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.14); padding: 10px 12px 16px; display: grid; gap: 4px;
  }
  .tab-more .side-link { min-height: 44px; }
  main { padding-bottom: 96px; }
}

/* An application's conversation, and a folded form. */
.note-item { padding: 10px 0; border-top: 1px solid var(--border); }
.note-item:first-of-type { border-top: 0; }
.note-body { margin: 4px 0; white-space: pre-wrap; }
.note-applicant .note-body { color: var(--ink); }
.note-doc { margin-top: 4px; }
.note-ask { margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--border); }
.check { display: flex; gap: 8px; align-items: center; font-size: 14px; }
.fold { margin-top: 14px; }
.fold > summary { cursor: pointer; color: var(--series-1); font-weight: 600; }
.fold[open] > summary { margin-bottom: 10px; }
table.facts th { text-align: left; font-weight: 500; color: var(--muted); width: 36%; }

/* A link that looks like a button, a row of controls above a list. */
.button { display: inline-flex; align-items: center; justify-content: center; padding: 7px 14px; border-radius: 8px;
  border: 1px solid var(--border); background: var(--surface-1); color: var(--ink); font-weight: 600; font-size: 14px; }
.button:hover { text-decoration: none; border-color: color-mix(in srgb, var(--series-1) 40%, transparent); }
.button.primary { background: var(--series-1); border-color: var(--series-1); color: #fff; }
.button.small { padding: 4px 10px; font-size: 13px; }
.toolbar { display: flex; gap: 12px; flex-wrap: wrap; justify-content: space-between; align-items: center; margin-bottom: 12px; }
.actions { display: flex; gap: 10px; flex-wrap: wrap; align-items: center; }
.row-quiet > td { opacity: .6; }

/* Forms in parts: what is always there, and what opens when it is wanted. */
fieldset.group { border: 0; border-top: 1px solid var(--border); margin: 0; padding: 14px 0 0; display: grid; gap: 12px; min-width: 0; }
fieldset.group:first-of-type { border-top: 0; padding-top: 0; }
fieldset.group > legend { font-weight: 650; padding: 0 0 6px; }
.group-toggle:has(> .check input:not(:checked)) > :not(legend):not(.check) { display: none; }
.pack-ticks { display: flex; flex-wrap: wrap; gap: 6px 16px; }

/* An on/off switch that is a real button in a form. */
.switch { display: inline-flex; align-items: center; gap: 6px; border: 1px solid var(--border); border-radius: 999px;
  padding: 2px 10px 2px 3px; background: var(--surface-1); font: inherit; font-size: 12.5px; color: var(--muted); cursor: pointer; }
.switch span { width: 16px; height: 16px; border-radius: 50%; background: var(--track); border: 1px solid var(--border); }
.switch.on { color: var(--series-1); border-color: color-mix(in srgb, var(--series-1) 45%, transparent); }
.switch.on span { background: var(--series-1); border-color: var(--series-1); }
.switch:focus-visible { outline: 2px solid var(--series-1); outline-offset: 2px; }
.order-buttons { white-space: nowrap; }
.order-buttons form { display: inline; }

/* Sets of sections to add. */
.packs { display: grid; gap: 8px; }
.pack { display: flex; justify-content: space-between; align-items: center; gap: 12px; padding: 8px 0; border-top: 1px solid var(--border); }
.pack:first-child { border-top: 0; }
.pack-added strong { color: var(--muted); }

/* A decision table, as its version shows it. */
.rule-table code { white-space: pre-wrap; word-break: break-word; font-size: 12.5px; }
.rule-table th.rule-in, .rule-table td.rule-in { background: color-mix(in srgb, var(--series-1) 5%, transparent); }
.rule-table th.rule-out { color: var(--ink); }
textarea.code { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; width: 100%; }
ul.problems { margin: 0 0 12px; padding-left: 18px; color: var(--critical, #b42318); }

/* Editing a decision table in place. */
.rule-edit td { vertical-align: top; padding: 4px 6px; }
.rule-edit input.cell { width: 100%; min-width: 9rem; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12.5px; padding: 4px 6px; }
.rule-edit input.cell-short { min-width: 6rem; }
.rule-edit input.cell-label { width: 100%; min-width: 12rem; font-size: 13px; padding: 4px 6px; }
.rule-edit th .linkish { padding: 0 4px; }
.cell-note { display: block; font-size: 11.5px; line-height: 1.3; min-height: 0; }
.cell-ok { color: var(--good, #067647); }
.cell-bad { color: var(--critical, #b42318); }
.try-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 10px 14px; }


/* ── Demo polish: one base for native controls, and layouts that hold on a phone ──
   `:where()` keeps these at zero specificity, so `.field`, `.primary`,
   `.linkish` and every module's own rules still win. */
:root { --line: var(--border); --panel: var(--surface-1); }
:where(button, input, select, textarea) { font: inherit; color: inherit; }
:where(button:not([class])) {
  padding: 6px 12px; border-radius: 8px; border: 1px solid var(--border);
  background: var(--surface-1); color: var(--ink); font-weight: 600; font-size: 13.5px; cursor: pointer;
}
:where(button:not([class])):hover { border-color: color-mix(in srgb, var(--series-1) 40%, transparent); }
:where(select, input:not([type=checkbox], [type=radio], [type=hidden], [type=submit])) {
  padding: 6px 10px; border: 1px solid var(--border); border-radius: 8px; background: var(--plane);
}
form.stack, .field { align-content: start; }
form.stack > button { justify-self: start; }
.grid-2 > * { min-width: 0; }
.grid-2 .table-scroll table { min-width: 0; }
.cards { grid-template-columns: repeat(auto-fill, minmax(min(100%, 300px), 1fr)); }
form.search, div.search { display: flex; gap: 8px; flex-wrap: wrap; align-items: center; }
form.search input, div.search input { flex: 1 1 200px; width: auto; }
td.actions { white-space: nowrap; }
td.actions .actions { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; }
td.actions form { display: inline-block; }
.hint { font-size: 12px; color: var(--muted); font-weight: 400; }
.status { display: inline-block; padding: 2px 9px; border-radius: 999px; font-size: 12px; font-weight: 600;
  color: var(--ink-2); background: color-mix(in srgb, var(--status-neutral) 14%, transparent); }
.status.placed, .status.pending, .status.draft { background: color-mix(in srgb, var(--status-warning) 22%, transparent); color: var(--ink); }
.status.accepted, .status.ordered, .status.paid, .status.posted { background: color-mix(in srgb, var(--series-1) 14%, transparent); color: var(--ink); }
.status.ready, .status.settled, .status.received, .status.completed { background: color-mix(in srgb, var(--status-good) 16%, transparent); color: var(--success-text); }
.status.cancelled { background: color-mix(in srgb, var(--status-critical) 14%, transparent); color: var(--neg); }
td, .tile .value, .kv dd { font-variant-numeric: tabular-nums; }
.table-scroll:not(:last-child) { margin-bottom: 14px; }
.table-card { text-align: left; font: inherit; }
.module-choice { padding: 8px 0; border-top: 1px solid var(--border); }
.module-choice:first-of-type { border-top: 0; }
.module-parts { margin: 6px 0 0 1.6rem; }
pre.json { max-height: 360px; overflow: auto; font-size: 12px; background: var(--plane); padding: 10px; border-radius: 8px; }
@media (max-width: 520px) { .row2 { grid-template-columns: 1fr; } }

/* Product photos */
.item-thumb { width: 34px; height: 34px; object-fit: cover; border-radius: 6px; vertical-align: middle; margin-right: 8px; }
.item-photo { width: 100%; max-width: 360px; aspect-ratio: 1; object-fit: cover; border-radius: 10px; display: block; margin-bottom: 12px; }
.shop-photo { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 8px; margin-bottom: 8px; background: var(--plane); }
.shop-photo.thumb-none { font-size: 30px; }

/* A button that reads as a link: remove, cancel, send again. */
button.linkish { background: none; border: 0; padding: 0; color: var(--series-1); font-weight: 500; cursor: pointer; text-decoration: underline; text-underline-offset: 2px; }
button.linkish:hover { color: var(--neg); }

/* An offer in the online shop and on the counter. */
.offer-tag { display:inline-block; align-self:start; padding:2px 9px; border-radius:999px; font-size:12px; font-weight:600;
  background: color-mix(in srgb, var(--status-good) 16%, transparent); color: var(--success-text); }

/* An element the page hides stays hidden, whatever a class says. */
[hidden] { display: none !important; }

/* ───────────────────────────────────────────────── forms: sized to what they hold
   A form is a reading column, never the whole panel. A box is as wide as what
   goes in it: a date is a date wide, a number a number wide, a name a line.
   Side-by-side fields collapse to one column on a phone. */
form.stack { max-width: 520px; }
.field input, .field select, .field textarea { width: 100%; max-width: 34em; min-width: 0; box-sizing: border-box; }
.field input[type="date"], .field input[type="time"] { max-width: 11.5em; }
.field input[inputmode="decimal"], .field input[inputmode="numeric"], .field input[type="number"] { max-width: 9em; text-align: right; font-variant-numeric: tabular-nums; }
.field input[inputmode="tel"] { max-width: 13em; }
.field input[maxlength="9"], .field input[maxlength="10"] { max-width: 10em; }
.field select { width: auto; max-width: 100%; }
.field textarea { min-height: 4.5em; }
.field label { display: flex; align-items: baseline; gap: 6px; flex-wrap: wrap; }
.field label .hint { font-weight: 400; }
/* A tooltip: the label says what the box is for; the title says what is expected. */
.field label[title] { cursor: help; }
.field label[title]::after { content: "?"; display: inline-grid; place-items: center; width: 14px; height: 14px; border-radius: 50%; font-size: 10px; font-weight: 700; color: var(--muted); border: 1px solid var(--border); margin-left: 2px; }
.row2, .row3 { display: grid; gap: 13px; align-items: start; }
.row2 { grid-template-columns: 1fr 1fr; }
.row3 { grid-template-columns: 1fr 1fr 1fr; }
.grid-3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; align-items: start; }
.grid-3 > * { min-width: 0; }
.grid-2 form.stack, .grid-3 form.stack { max-width: none; }
.sub-row > td { padding: 6px 10px 12px; background: color-mix(in srgb, var(--ink) 2%, transparent); }
.sub-row details > summary { margin: 2px 0 6px; }
.sub-row form.stack { max-width: none; }
form.inline, .inline { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.inline input, .inline select { padding: 6px 9px; border: 1px solid var(--border); border-radius: 8px; background: var(--plane); color: var(--ink); font: inherit; width: auto; max-width: 14em; }
.inline input[type="date"] { max-width: 11.5em; }
.inline label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--ink-2); }
.stats { display: flex; flex-wrap: wrap; gap: 16px 28px; }
.stat .stat-label { font-size: 12px; color: var(--muted); text-transform: uppercase; letter-spacing: .04em; }
.stat .stat-value { font-size: 20px; font-weight: 600; font-variant-numeric: tabular-nums; }
@media (max-width: 900px) { .grid-3 { grid-template-columns: 1fr; } .row3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .row3 { grid-template-columns: 1fr; } .field input, .field select { max-width: 100%; } }

/* ───────────────────────────────────────── a grid: a spreadsheet's habits
   One item to a row, columns across, the whole thing scrolling sideways
   rather than wrapping. A cell is its input; the borders are the table's. */
table.grid { border-collapse: separate; border-spacing: 0; min-width: 62em; font-variant-numeric: tabular-nums; }
table.grid th {
  position: sticky; top: 0; z-index: 1; background: var(--plane);
  font-size: 12px; font-weight: 600; color: var(--ink-2); text-align: left;
  padding: 7px 8px; border-bottom: 1px solid var(--border); white-space: nowrap;
}
table.grid th.num { text-align: right; }
table.grid th .hint { font-weight: 400; color: var(--muted); font-size: 11px; }
table.grid td { padding: 0; border-bottom: 1px solid var(--border); }
table.grid td.rn {
  text-align: right; padding: 0 8px; color: var(--muted); font-size: 12px;
  background: color-mix(in srgb, var(--ink) 3%, transparent); user-select: none;
}
table.grid td input {
  width: 100%; max-width: none; border: 0; border-radius: 0; background: transparent;
  padding: 8px 9px; font: inherit; font-size: 14px; color: var(--ink);
}
table.grid td input.num { text-align: right; }
table.grid td input:focus {
  outline: 2px solid var(--series-1); outline-offset: -2px;
  background: var(--plane); position: relative; z-index: 2;
}
table.grid td input::placeholder { color: color-mix(in srgb, var(--muted) 55%, transparent); }
table.grid tr:hover td { background: color-mix(in srgb, var(--ink) 2%, transparent); }
table.grid td button.linkish { padding: 0 8px; text-decoration: none; font-size: 16px; color: var(--muted); }
table.grid td button.linkish:hover { color: var(--neg); }

/* A heading row: a number and a title, nothing measured against it. The
   sheet is read by its headings, so the page shows one as the sheet does. */
table.grid tr.hd td { background: color-mix(in srgb, var(--series-1) 7%, transparent); }
table.grid tr.hd td.rn { color: var(--series-1); font-weight: 700; }
table.grid tr.hd td input[name="description"] { font-weight: 650; letter-spacing: .01em; }
table.grid tr.hd td input[name="unit"],
table.grid tr.hd td input[name="quantity"],
table.grid tr.hd td input[name="rate"] { opacity: .35; }

/* What the item could be, offered under the cell being typed in. */
.sheet { position: relative; }
.suggest {
  position: absolute; z-index: 30; min-width: 24em; max-width: 34em; max-height: 15em; overflow-y: auto;
  background: var(--plane); border: 1px solid var(--border); border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, .14); padding: 4px;
}
.suggest button.linkish {
  display: block; width: 100%; text-align: left; padding: 6px 8px; border-radius: 6px;
  text-decoration: none; font-size: 13px; color: var(--ink);
}
.suggest button.linkish:hover, .suggest button.linkish:focus, .suggest button.linkish.on {
  background: color-mix(in srgb, var(--series-1) 12%, transparent); color: var(--ink);
}
.suggest .desc { display: block; color: var(--muted); font-size: 12px; }

/* Recording a measurement without leaving the page: while it is in flight
   the block it came from is held still and says so. */
.mbook { position: relative; }
.mbook.busy, .mbook[data-panel].busy { opacity: .55; pointer-events: none; }
.mbook > .notice { margin: 0 0 10px; }
.working { display: inline-flex; align-items: center; gap: 6px; color: var(--muted); font-size: 13px; }
.spinner {
  width: 13px; height: 13px; border-radius: 50%; display: inline-block;
  border: 2px solid color-mix(in srgb, var(--series-1) 30%, transparent);
  border-top-color: var(--series-1); animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .spinner { animation-duration: 2.4s; } }

/* Anything posting in the background: held still while it is in flight, so
   a second tap does nothing and the page does not move under a thumb.
   One rule for every module — see /static/live.js. */
[data-panel].busy { opacity: .6; pointer-events: none; }
.live-notice { margin: 0 0 10px; }
.pos-ticket > .notice { margin: 0 0 10px; }

/* Where you are, beside the organisation's name. Three pages into the
   books a person needs the way back without reaching for the browser. */
.crumbs {
  display: flex; align-items: center; gap: 6px; min-width: 0; overflow: hidden;
  font-size: 13px; color: var(--muted); white-space: nowrap;
}
.crumbs a { color: var(--muted); text-decoration: none; }
.crumbs a:hover { color: var(--ink); text-decoration: underline; }
.crumbs [aria-current="page"] { color: var(--ink); font-weight: 600; overflow: hidden; text-overflow: ellipsis; }
.crumb-sep { color: color-mix(in srgb, var(--muted) 50%, transparent); }
/* On a phone the trail is one step: the way back, and nothing else. */
@media (max-width: 720px) {
  .crumbs { font-size: 12px; }
  .crumbs > a:not(:nth-last-child(3)), .crumbs > .crumb-sep:not(:nth-last-child(2)) { display: none; }
  .crumbs > a:nth-last-child(3)::before { content: "\2039\00a0"; }
}

/* ───────────────────────────────── an organisation's own colour
   One property, set on the shell from what the organisation chose, and
   every shade mixed from it. Nothing to keep in step: change the one and
   the rest follow. Where nobody has chosen, `--accent` is unset and the
   fallback is the stylesheet's own green, so an organisation that has
   never opened the Identity page looks exactly as it did.

   The steps are the same idea as a tonal ramp — 100 lightest through 900
   darkest — mixed against the page's own ground and ink so they sit right
   in the light theme and the dark one without being written twice. */
.brand, .side, .topbar { --accent-base: var(--accent, var(--series-1)); }
:root {
  --accent-100: color-mix(in oklab, var(--accent, var(--series-1)) 12%, var(--plane));
  --accent-200: color-mix(in oklab, var(--accent, var(--series-1)) 24%, var(--plane));
  --accent-400: color-mix(in oklab, var(--accent, var(--series-1)) 55%, var(--plane));
  --accent-600: var(--accent, var(--series-1));
  --accent-800: color-mix(in oklab, var(--accent, var(--series-1)) 70%, var(--ink));
}

/* The mark itself, where the plain square used to be. */
.brand-logo {
  height: 24px; width: auto; max-width: 120px; border-radius: 3px;
  object-fit: contain; display: block;
}

/* A typeface, at last: the system's own, in an order that gets a decent
   one on a Nepali laptop, a Windows desktop and an Android phone alike,
   and that has Devanagari where the page needs it. Nothing is downloaded:
   a web font is a second round trip before anybody can read anything, and
   that is expensive on a village connection. */
:root {
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Noto Sans", "Noto Sans Devanagari", "Mangal", Arial, sans-serif;
  --font-heading: var(--font);
}
body { font-family: var(--font); }
h1, h2, h3, h4 { font-family: var(--font-heading); letter-spacing: -0.01em; }

/* ───────────────────────────────── the directory, as a stranger meets it
   A page that opens with the question rather than with a list: how many
   places there are, what you are looking for, and the kinds of place to
   start from when you cannot think of a word. */
.find-hero {
  padding: 40px 0 28px; text-align: center; max-width: 720px; margin: 0 auto;
}
.find-count { margin: 0 0 6px; color: var(--muted); font-size: 13px; letter-spacing: .02em; }
.find-hero h1 { margin: 0; font-size: clamp(26px, 5vw, 40px); line-height: 1.1; text-wrap: balance; }
.find-also { margin: 4px 0 0; color: var(--muted); font-size: clamp(15px, 2.6vw, 20px); }
.find-search { display: flex; gap: 8px; margin: 20px auto 0; max-width: 560px; }
.find-search input {
  flex: 1; min-width: 0; max-width: none; padding: 12px 14px; font-size: 16px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-1); color: var(--ink);
}
.find-search input:focus { outline: 2px solid var(--accent, var(--series-1)); outline-offset: -1px; }
.find-search button { padding: 12px 20px; font-size: 15px; border-radius: 10px; }
.find-try { margin: 14px 0 0; display: flex; gap: 6px; justify-content: center; align-items: center; flex-wrap: wrap; }

/* The kinds of place: a name, its other name, and how many there are. */
.kinds { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 10px; }
.kind {
  display: flex; flex-direction: column; gap: 2px; padding: 14px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-1);
  text-decoration: none; color: var(--ink); transition: border-color .12s, background .12s;
}
.kind:hover { border-color: var(--accent, var(--series-1)); background: var(--accent-100, var(--surface-1)); text-decoration: none; }
.kind.hit { border-color: var(--accent, var(--series-1)); }
.kind-name { font-weight: 600; font-size: 15px; }
.kind-also { color: var(--muted); font-size: 13px; }
.kind-count { margin-top: 6px; color: var(--accent, var(--series-1)); font-weight: 700; font-size: 18px; font-variant-numeric: tabular-nums; }

/* "List your business" sits in the public bar, before signing in. */
.list-yours {
  padding: 7px 12px; border: 1px solid var(--border); border-radius: 8px;
  font-size: 13px; text-decoration: none; color: var(--ink); white-space: nowrap;
}
.list-yours:hover { border-color: var(--accent, var(--series-1)); text-decoration: none; }
@media (max-width: 640px) { .list-yours { display: none; } }

/* ───────────────────────────────── one thing, on a page of its own
   A shop page is a wall of small cards, which is right for choosing and
   wrong for deciding. This is the deciding page: the picture, then what it
   costs and what the price is made of. */
.item-page { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.2fr); gap: 24px; margin: 8px 0 20px; }
@media (max-width: 720px) { .item-page { grid-template-columns: 1fr; } }
.item-figure {
  border: 1px solid var(--border); border-radius: 12px; overflow: hidden;
  background: var(--surface-1); aspect-ratio: 4 / 3; display: grid; place-items: center;
}
.item-figure img { width: 100%; height: 100%; object-fit: cover; }
.item-noimg { font-size: 64px; }
.item-facts h1 { margin: 0; font-size: clamp(22px, 4vw, 32px); line-height: 1.15; }
.item-also { margin: 2px 0 0; color: var(--muted); font-size: 18px; }
.item-price { margin: 16px 0 0; font-size: 34px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1; }
.item-cur { font-size: 18px; font-weight: 600; color: var(--muted); margin-right: 4px; }
.item-per { font-size: 15px; font-weight: 400; color: var(--muted); }
.item-was { margin: 4px 0 0; color: var(--muted); font-size: 14px; text-decoration: line-through; }
.item-buy { display: flex; gap: 8px; align-items: center; margin: 16px 0 0; }
.item-buy input { max-width: 5em; text-align: center; padding: 10px; font-size: 16px; }
.item-buy button { padding: 10px 22px; font-size: 15px; }
.item-desc { margin: 16px 0 0; max-width: 60ch; }

/* ───────────────────────────────── the front page, as panels
   Every panel declared its size and the grid honours it: a figure takes a
   quarter, a list takes a half, a table takes the row. Nothing here knows
   what any panel contains. */
.dash { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 12px; align-items: start; }
.dash > .dash-small { grid-column: span 1; }
.dash > .dash-wide  { grid-column: span 2; }
.dash > .dash-full  { grid-column: span 4; }
@media (max-width: 1000px) {
  .dash { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .dash > .dash-wide, .dash > .dash-full { grid-column: span 2; }
}
@media (max-width: 560px) {
  .dash { grid-template-columns: 1fr; }
  .dash > .dash-small, .dash > .dash-wide, .dash > .dash-full { grid-column: span 1; }
}
.dash-head { display: flex; justify-content: space-between; align-items: baseline; gap: 12px; flex-wrap: wrap; margin: 0 0 14px; }
.dash-head h1 { margin: 0; font-size: clamp(20px, 3vw, 26px); }
.dash-also { margin: 0; color: var(--muted); }
.dash-figure { margin: 0; font-size: 26px; font-weight: 700; font-variant-numeric: tabular-nums; line-height: 1.1; }
.dash .panel h2 { font-size: 13px; text-transform: uppercase; letter-spacing: .04em; color: var(--muted); margin: 0 0 8px; }

/* A place somebody deals with: its mark, its name, and what it holds of
   theirs. */
.place-head { display: flex; align-items: center; gap: 10px; }
.place-logo { height: 28px; width: auto; max-width: 72px; object-fit: contain; border-radius: 4px; }
.place-card h3 { margin: 0; }
.place-kv { margin-top: 8px; }

/* A thing somebody searched for, shown as the thing: the picture first,
   then what it is, then what it costs and who has it. A row in a table
   tells you none of that. */
.finds { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: 12px; }
.find-item {
  display: flex; flex-direction: column; gap: 3px; padding: 10px;
  border: 1px solid var(--border); border-radius: 10px; background: var(--surface-1);
  text-decoration: none; color: var(--ink);
}
.find-item:hover { border-color: var(--accent, var(--series-1)); text-decoration: none; }
.find-photo {
  width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: 7px;
  background: color-mix(in srgb, var(--ink) 4%, transparent); margin-bottom: 4px;
}
.find-photo.thumb-none { font-size: 30px; }
.find-name { font-weight: 600; line-height: 1.25; }
.find-desc {
  color: var(--muted); font-size: 13px; line-height: 1.35;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.find-price { font-weight: 700; font-variant-numeric: tabular-nums; margin-top: 2px; }
/* The whole card opens the item, so the picture and name are not links of
   their own inside it. */
.shop-open { display: contents; color: inherit; text-decoration: none; }
.shop-item:hover .shop-open strong { text-decoration: underline; }

/* ── A thing with no photograph ──────────────────────────────────────────
   Every shelf in this application shows the same stand-in: the till's item
   grid, the shop, the item page and the directory search. It used to be a
   grey letter on a flat ground, which on a dark screen reads as a picture
   that failed to load rather than a thing nobody has photographed yet.

   The tile takes its hue from the thing's own name, so a wall of them
   reads as a set. `--tint` is set on the element; everything else comes
   from the theme. Sizing stays with whichever grid owns the tile — this
   rule is appearance only, and adds nothing about width or shape. */
.thumb-none {
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  letter-spacing: 0.02em;
  line-height: 1;
  text-transform: none;
  background: linear-gradient(155deg,
    hsl(var(--tint, 218) var(--thumb-s) var(--thumb-top)),
    hsl(var(--tint, 218) var(--thumb-s) var(--thumb-bottom)));
  color: hsl(var(--tint, 218) var(--thumb-ink-s) var(--thumb-ink-l));
}

/* ── The Loop mark ───────────────────────────────────────────────────────
   A payment method people are meant to recognise, so it is shown the way
   its owner shows it: a ring and the wordmark, in Loop's own indigo. Drawn
   rather than fetched — a till at a stall may have no network, and a logo
   that arrives late or not at all is worse than one that is always there.

   The brand colour is stated in oklch as Loop states it, with an sRGB hex
   first for anything that cannot read oklch. */
:root {
  --loop-accent: #4f46e5;
  --loop-accent: oklch(0.50 0.22 265);
  --loop-ink: #14162b;
  --loop-ink: oklch(0.16 0.03 260);
}
@media (prefers-color-scheme: dark) {
  :root:where(:not([data-theme="light"])) {
    --loop-accent: #8b87f8;
    --loop-accent: oklch(0.70 0.17 265);
    --loop-ink: #ffffff;
  }
}
:root[data-theme="dark"] {
  --loop-accent: #8b87f8;
  --loop-accent: oklch(0.70 0.17 265);
  --loop-ink: #ffffff;
}

.loopmark { display: inline-flex; align-items: center; gap: 8px; vertical-align: middle; }
.loopmark-ring {
  width: 17px; height: 17px; border-radius: 50%; flex: none;
  border: 3.5px solid var(--loop-accent);
}
.loopmark-wm {
  font-weight: 800; letter-spacing: 1.5px; font-size: 15px; line-height: 1;
  color: var(--loop-ink);
}
/* On the payment panel's own heading the mark stands in for the word, so it
   carries the heading's size rather than its own. */
h2 .loopmark-wm { font-size: inherit; letter-spacing: 1.2px; }
h2 .loopmark-ring { width: 0.72em; height: 0.72em; border-width: 0.16em; }
.terminal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 6px;
}

/* ── Filling in a missing thing, where you are ───────────────────────────
   A purchase order wants a vendor that has not been added yet. Sending
   somebody to the vendors page and back loses the order they were halfway
   through typing, so the vendor form comes to them instead. Behaviour is
   in live.js (`data-opens`, `data-from`, `data-close`); this is the look. */
dialog.sheet {
  padding: 0;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--surface-1);
  color: var(--ink);
  width: min(460px, calc(100vw - 32px));
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.28);
}
dialog.sheet::backdrop { background: rgba(0, 0, 0, 0.45); }
.sheet-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 14px 16px; border-bottom: 1px solid var(--border);
}
.sheet-head h2 { margin: 0; font-size: 16px; }
.sheet-head form { margin: 0; }
.sheet-body { padding: 16px; }
.sheet-body .actions { display: flex; gap: 10px; align-items: center; margin-top: 4px; }
/* The button that opens one sits beside the box it fills in. */
.picker { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.picker > select { flex: 1 1 auto; min-width: 0; }

/* The platform mark inside somebody else's storefront: a way back to the
   directory that does not compete with the shop's own name. */
.home-mark {
  display: inline-flex; align-items: center; flex: none;
  padding: 4px; border-radius: 8px; opacity: 0.75;
  text-decoration: none;
}
.home-mark:hover { opacity: 1; background: color-mix(in srgb, var(--ink) 7%, transparent); }

/* Whoever took the picture, where its licence asks to be told. Quiet, and
   directly under the photograph it belongs to. */
.photo-credit { margin: 6px 0 0; font-size: 12px; color: var(--muted); line-height: 1.35; }

/* Which way of having a thing, on the card where it is chosen. */
.shop-way { width: 100%; margin-bottom: 6px; }

/* What comes with what: on the shelf as a promise, in the basket as a fact. */
.combo-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.combo-list li { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }
.earned {
  margin-top: 14px; padding: 12px 14px; border-radius: var(--radius);
  border: 1px solid color-mix(in srgb, var(--status-good) 35%, var(--border));
  background: color-mix(in srgb, var(--status-good) 8%, transparent);
}
.earned h3 { margin: 0 0 8px; font-size: 14px; }
.earned ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
.earned li { display: flex; gap: 8px; align-items: baseline; flex-wrap: wrap; }

/* A key shown once. Wide, selectable, and impossible to mistake for prose. */
.key-once {
  margin: 8px 0 0; padding: 10px 12px; border-radius: 8px;
  background: var(--plane); border: 1px solid var(--border);
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 13px;
  overflow-x: auto; user-select: all;
}
tr.off { opacity: 0.55; }

/* What a place takes at the counter: Loop, QR, Card. Said on the card so a
   customer choosing between two shops knows before they walk. */
.takes { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin: 6px 0 0; }
.pay-tag {
  display: inline-block; padding: 1px 8px; border-radius: 999px;
  font-size: 11.5px; font-weight: 600; letter-spacing: 0.02em;
  border: 1px solid var(--border); color: var(--ink-2);
  background: color-mix(in srgb, var(--ink) 4%, transparent);
}
