/* Navee seller mini app — shell.
   Ruled: a POS, not a shopfront. ONE selling surface — a menu with the running
   bill floating at the bottom and the draft in a sheet — instead of tabs, so a
   seller never navigates in order to sell. Native Telegram chrome; one accent
   (#0071e3), spent only on a quantity badge and never on a control that is not
   money.

   Two drawings of the same catalogue: the GRID (for recognising an item) and
   the LIST (for reading it). Both add a line on the same tap, and the order
   behind them is one object.

   Khmer is a first-class script: nothing here trims a line-height on mixed
   text, and no label is shrunk to make a layout fit. */

@font-face {
  font-family: 'Roboto';
  src: url('./fonts/roboto-latin-400_700.ttf') format('truetype');
  font-weight: 400 700;
  font-display: swap;
}
@font-face {
  font-family: 'Hanuman';
  src: url('./fonts/hanuman-khmer-400_700.ttf') format('truetype');
  font-weight: 400 700;
  font-display: swap;
}

:root {
  --accent: #0071e3;
  --bg: #f5f4ef;
  /* NAV-1591: the page the browser shell sits on. The app itself keeps
     --bg; this is only the rung the bounded column floats above. */
  --page-bg: #e6e3db;
  --surface: #ffffff;
  --surface-solid: #ffffff;
  --text: #0a0a0b;
  --muted: #8a8a90;
  --hairline: rgba(0, 0, 0, 0.07);
  --shadow: 0 1px 2px rgba(72, 58, 34, 0.06), 0 14px 30px -18px rgba(72, 58, 34, 0.34);
  /* NAV-1555: the three neutrals warm to the paper. The tray is the site's
     page-2 (#efede6, OKLCH 93.6deg) and the pill a paper-warm white
     (97.4deg); the paper is 97.4deg, so neither drifts off the ground. */
  --tray: #efede6;
  --mono: #6f6f77;
  --release-ink: #686870;
  --mono-thumb: #5c5c64;
  --seg-pill: #fbfaf5;
  --bar: rgba(255, 255, 255, 0.94);
  --scrim: rgba(12, 12, 14, 0.32);
  --radius: 18px;
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
}

/* The warm ladder on the paper ground (NAV-1544): the site's own surface,
   page-2, ink and line. The ground is fixed by the Board's word; the rung above
   it must not be the cool grey the app is retiring. */
@media (prefers-color-scheme: dark) {
  :root {
    --bg: #141210;
  --page-bg: #0c0c0e;
    --page-bg: #0c0c0e;
    --surface: #1b1b17;
    --surface-solid: #1b1b17;
    --text: #f5f4ef;
    --muted: #a7a49a;
    --hairline: rgba(245, 244, 239, 0.141);
    --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 18px 40px -24px rgba(0, 0, 0, 0.9);
    /* The dark tray already warmed with NAV-1544: #23231f is 106.9deg,
       C 0.0073 — kept. Only the pill was still cold (285.8deg). */
    --tray: #23231f;
    --mono: #9a9aa4;
    --release-ink: #84848e;
    --mono-thumb: #9a9aa4;
    --seg-pill: #2f2e27;
    --bar: rgba(29, 29, 25, 0.94);
    --scrim: rgba(0, 0, 0, 0.5);
  }
}

/* Explicit dark: Telegram's own colorScheme decides in the real client, and a
   review render can force it with ?theme=dark. */
html[data-theme='dark'] {
  --bg: #141210;
  --surface: #1b1b17;
  --surface-solid: #1b1b17;
  --text: #f5f4ef;
  --muted: #a7a49a;
  --hairline: rgba(245, 244, 239, 0.141);
  --shadow: 0 1px 2px rgba(0, 0, 0, 0.5), 0 18px 40px -24px rgba(0, 0, 0, 0.9);
  --tray: #23231f;
  --mono: #9a9aa4;
  --release-ink: #84848e;
  --mono-thumb: #9a9aa4;
  --seg-pill: #2f2e27;
  --bar: rgba(29, 29, 25, 0.94);
  --scrim: rgba(0, 0, 0, 0.5);
}

* { box-sizing: border-box; }
[hidden] { display: none !important; }

html, body {
  margin: 0;
  height: 100%;
  background: var(--bg);
  color: var(--text);
  font-family: 'Roboto', 'Hanuman', system-ui, -apple-system, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior: none;
}

/* NAV-1529 · A sheet is open or it is not.
   While any `.sheet-layer` is visible the shell behind it cannot scroll. This
   is the whole fix for the menu that moved under the short shop sheet: the
   gesture had no scroller to land in — the catalogue's `.grid`/`.list` is a
   SIBLING of the layers, not an ancestor — so it chained to the document. The
   settings sheet never showed it because its own tall panes absorbed the same
   drag. The class is derived from the layers' own `hidden` state (app.js), so
   every exit releases it, and it changes no geometry: the frame before the open
   and the frame after the close are identical. `overscroll-behavior` stays
   where it was; the document simply has nothing left to scroll. */
html.is-sheet-locked,
html.is-sheet-locked body { overflow: hidden; }

/* The shell: header, chips, the menu, and a bill that floats over it. The
   page is one flat sheet of paper (NAV-1544): the blue wash that used to run
   across the top third is gone, and the ground is the only page paint. */
.app {
  position: relative;
  height: 100dvh;
  display: flex;
  flex-direction: column;
  padding-top: var(--safe-top);
  background: var(--bg);
}

/* ---------- header ---------- */

/* The header separates with paper, not with a colour: its own paint is the
   ground, fading out under its last few pixels. Where the menu meets it the
   edge is the ground's own value — never a blue shadow, never a hard seam — so
   a catalogue that reaches the header still meets paper. */
.top {
  position: relative;
  z-index: 2;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  /* The accepted 320 header: name column 148, view switch 88, gear 44, with a
     12 px trailing inset. Two 6 px gaps make those five numbers add to 320. */
  gap: 6px;
  padding: 14px 12px 8px 16px;
  background: linear-gradient(to bottom, var(--bg) calc(100% - 9px), transparent);
}

.shop {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.shop-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.015em;
}

/* The dot and the version share the quiet line under the name. The mock's 320
   header trades the last 3 px of type for the gear cell: 14 px there, one
   line, never a wrapped name and never a horizontal scroll. */
.shop-meta {
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 15px;
}

@media (max-width: 340px) {
  .shop-name,
  button.shop-name { font-size: 14px; }
}

/* Two or more shops: the SAME id becomes a native button (the proof reads the
   visible name either way). The target clears 44 px; the chevron says there is
   somewhere to go. With one shop none of this is drawn — a chevron that opens a
   one-item list would be a control that cannot do anything. */
button.shop-name {
  align-self: flex-start;
  max-width: 100%;
  min-height: 44px;
  margin: 0;
  padding: 0;
  display: flex;
  align-items: center;
  gap: 6px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.015em;
  text-align: left;
  overflow: visible;
  white-space: normal;
  text-overflow: clip;
}
button.shop-name:active { background: var(--tray); }

.shop-name-text {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

button.shop-name .chev {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--muted);
}

/* The build this document is. Quiet by construction: 12px mono ink, tabular
   figures, no border and no hit area. The line keeps its 15px whether or not a
   marker was served, so an older cached shell neither draws `vundefined` nor
   moves the header when the label is absent. */
.release {
  min-height: 15px;
  line-height: 15px;
  font-size: 12px;
  font-weight: 500;
  font-variant-numeric: tabular-nums;
  color: var(--release-ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* The menu's view switch. Two 44px cells carry a 32x28 pill: the target clears
   the floor while the drawing stays quiet, and the switch lives here — not at
   the end of the category strip, where a scroll would drag it out of reach. */
.seg {
  flex: 0 0 auto;
  display: flex;
  border-radius: 12px;
  background: var(--tray);
}

.seg-btn {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font: inherit;
}

.seg-btn .pill {
  width: 32px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 9px;
  transition: background 0.12s ease;
}

.seg-btn[aria-pressed='true'] { color: var(--text); }
.seg-btn[aria-pressed='true'] .pill {
  background: var(--seg-pill);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.seg-btn svg { width: 15px; height: 15px; display: block; }

/* The one settings cell at the header's trailing edge. 44 x 44, ink-quiet. */
.gear {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font: inherit;
}
.gear:active { background: var(--tray); }
.gear svg { width: 22px; height: 22px; display: block; }

.who {
  flex: 0 0 auto;
  width: 12px;
  height: 15px;
  display: grid;
  place-items: center;
}

.dot {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--muted);
  opacity: 0.5;
}
.dot[data-state='signed-in'] { background: #24c06b; opacity: 1; }
.dot[data-state='refused'] { background: #e0483f; opacity: 1; }
/* A sign-in that is still out is neither signed in nor refused: it is working. */
.dot[data-state='working'] { background: var(--accent); opacity: 1; animation: pulse 1.2s ease-in-out infinite; }

@keyframes pulse {
  0%, 100% { opacity: 0.35; }
  50% { opacity: 1; }
}

/* ---------- sign-in notice ----------
   A persistent line above the menu, not a toast: it carries the progress state,
   the reason a sign-in stopped, and the way to ask again — so the seller is
   never parked on a header of `—` with nothing to tap. */

.notice {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 4px 16px 6px;
  padding: 8px 12px;
  border-radius: 14px;
  background: var(--surface-solid);
  box-shadow: var(--shadow);
  font-size: 13px;
  line-height: 1.4;
}

.notice-text { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }

.spinner {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
  border: 2px solid var(--tray);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin 0.8s linear infinite;
}

@keyframes spin { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .dot[data-state='working'] { animation: none; }
  .spinner { animation-duration: 2.4s; }
  .seg-btn .pill { transition: none; }
}

.notice-retry {
  flex: 0 0 auto;
  min-height: 44px;
  padding: 0 16px;
  border: 0;
  border-radius: 12px;
  background: var(--accent);
  color: #fff;
  font: inherit;
  font-size: 14px;
  font-weight: 600;
}
.notice-retry:disabled { opacity: 0.5; }

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

.chips {
  flex: 0 0 auto;
  display: flex;
  gap: 6px;
  padding: 2px 16px 10px;
  overflow-x: auto;
  scrollbar-width: none;
}
.chips::-webkit-scrollbar { display: none; }

.chip {
  flex: 0 0 auto;
  min-width: 44px;
  height: 44px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 13px;
  font-weight: 600;
  letter-spacing: -0.01em;
}

/* The selected chip is ink, not accent: the accent belongs to money. */
.chip.is-active { background: var(--text); color: var(--bg); }

/* ---------- the menu ---------- */

.screen {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  position: relative;
}

.grid,
.list {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  padding: 0 16px calc(96px + var(--safe-bottom));
}

.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: max-content;
  gap: 10px;
  align-content: start;
}

.tile {
  position: relative;
  height: 142px;
  display: flex;
  flex-direction: column;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: var(--radius);
  background: var(--surface-solid);
  color: var(--text);
  box-shadow: var(--shadow);
  font: inherit;
  text-align: left;
}
.tile:active { transform: scale(0.985); }

/* The photo carries the recognition; where a product has none, the monogram
   does. An empty box would read as a broken image, so the fallback is drawn. */
/* The photo fills whatever the tile's fixed 142 px height leaves after the
   name and price. It used a 16:10 ratio, which pushed the price below the
   clipped edge — a tile that hid its own price was a clipped half-tile. */
.shot {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  overflow: hidden;
  background: var(--tray);
}

.shot img,
.thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.mono {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  font-size: 26px;
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--mono);
  /* NAV-1555: the fixed stop was the last cold grey in the placeholder
     (286.0deg); 135,128,114 is 84.6deg, C 0.0223, within 13deg of the paper.
     One rule draws the grid tile, the list thumb and the settings photo thumb. */
  background: linear-gradient(140deg, var(--tray), rgba(135, 128, 114, 0.14));
}

.tmeta {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 12px 11px;
  min-width: 0;
}

.tname {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.25;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tprice {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.tprice b { color: var(--text); font-weight: 600; }

.badge {
  position: absolute;
  top: 8px;
  right: 8px;
  min-width: 20px;
  height: 20px;
  padding: 0 5px;
  border-radius: 10px;
  background: var(--accent);
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

/* The list: the same catalogue, read instead of recognised. The full name gets
   the row's width and every price sits on one right-hand axis. */
.list { display: flex; flex-direction: column; gap: 8px; }

.row {
  position: relative;
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 62px;
  padding: 8px 12px;
  border: 0;
  border-radius: 16px;
  background: var(--surface-solid);
  color: var(--text);
  box-shadow: var(--shadow);
  font: inherit;
  text-align: left;
}
.row:active { transform: scale(0.99); }

.thumb {
  position: relative;
  flex: 0 0 auto;
  width: 46px;
  height: 46px;
  border-radius: 13px;
  overflow: hidden;
  background: var(--tray);
}
/* The thumbnail's initials are 15 px / 700 — normal text, not large text — so
   the 3:1 tile floor is not enough here. It gets its own stronger ink. */
.thumb .mono { font-size: 15px; color: var(--mono-thumb); }

.rbody {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
}

/* The list is the reading surface: the full name wraps instead of being cut.
   The row grows with it; the price stays on its own right-hand axis. */
.rname {
  font-size: 14.5px;
  font-weight: 600;
  letter-spacing: -0.01em;
  line-height: 1.3;
  overflow-wrap: break-word;
}

.rsub {
  margin-top: 2px;
  font-size: 12px;
  font-weight: 500;
  color: var(--muted);
  overflow-wrap: break-word;
}

.rprice {
  flex: 0 0 auto;
  padding-left: 6px;
  font-size: 14px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.rbadge {
  position: absolute;
  top: 4px;
  left: 4px;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.25);
}

/* A product with no price cannot be sold, so it is drawn but not tappable.
   It stays legible: the CONTAINER is dimmed (flat tray surface, dashed edge,
   no lift) rather than the ink. Dimming the whole tile with opacity dragged
   the monogram — its only recognition cue — under 3:1 (NAV-1382 F2). */
.tile.is-unset, .row.is-unset {
  cursor: default;
  background: var(--tray);
  box-shadow: none;
  outline: 1px dashed rgba(127, 127, 135, 0.45);
  outline-offset: -1px;
}

/* ---------- the bill ----------
   Drawn only when the draft holds something: an empty bar would be a control
   that cannot do anything. The approved drawing (NAV-1505/NAV-1506) makes it a
   now-playing card: full-bleed 76 px + safe area, a two-deep cover, the total
   bold with the unit count muted beneath, and one circular ink action. The
   accent is spent on a single 10 px dot and nowhere else. */

.bar {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  width: auto;
  height: calc(76px + var(--safe-bottom));
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 16px var(--safe-bottom);
  border: 0;
  border-radius: 0;
  background: rgba(255, 255, 255, 0.72);
  -webkit-backdrop-filter: blur(28px) saturate(1.8);
  backdrop-filter: blur(28px) saturate(1.8);
  color: var(--text);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.86),
    0 -20px 48px -22px rgba(10, 10, 11, 0.40),
    0 -2px 0 rgba(10, 10, 11, 0.04);
  font: inherit;
  overflow: visible;
}

/* A soft value jump above the band: it reads as a card lifted over the menu,
   not as a 1 px hairline. It never eats a tap. */
.bar::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 54px;
  background: linear-gradient(to top, rgba(10, 10, 11, 0.11), rgba(10, 10, 11, 0));
  pointer-events: none;
}

@media (prefers-color-scheme: dark) {
  .bar {
    background: rgba(29, 29, 25, 0.62);
    box-shadow:
      inset 0 1px 0 rgba(255, 255, 255, 0.12),
      0 -20px 48px -22px rgba(0, 0, 0, 0.80),
      0 -2px 0 rgba(255, 255, 255, 0.03);
  }
  .bar::before {
    background: linear-gradient(to top, rgba(0, 0, 0, 0.46), rgba(0, 0, 0, 0));
  }
}
html[data-theme='dark'] .bar {
  background: rgba(29, 29, 25, 0.62);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.12),
    0 -20px 48px -22px rgba(0, 0, 0, 0.80),
    0 -2px 0 rgba(255, 255, 255, 0.03);
}
html[data-theme='dark'] .bar::before {
  background: linear-gradient(to top, rgba(0, 0, 0, 0.46), rgba(0, 0, 0, 0));
}

/* Where the material cannot blur, the band is near-solid so the total stays
   readable — the fallback is a sighted surface, not a transparent one. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .bar { background: rgba(255, 255, 255, 0.97); }
  @media (prefers-color-scheme: dark) {
    .bar { background: rgba(29, 29, 25, 0.97); }
  }
  html[data-theme='dark'] .bar { background: rgba(29, 29, 25, 0.97); }
}

/* The cover: the bill's own thumbnails, two deep. A bill with no second photo
   draws a blank card edge — never an invented picture. */
.bar-cover {
  position: relative;
  flex: 0 0 54px;
  width: 54px;
  height: 54px;
}
.bar-cover .art {
  position: absolute;
  overflow: hidden;
  display: grid;
  place-items: center;
  background: var(--tray);
}
.bar-cover .art img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
.bar-cover .art .mono {
  font-size: 15px;
  font-weight: 700;
  color: var(--mono-thumb);
  letter-spacing: -0.01em;
}
.bar-cover .art-back {
  left: 8px;
  top: 8px;
  width: 44px;
  height: 44px;
  border-radius: 11px;
  opacity: 0.96;
  transform: rotate(3deg);
  transform-origin: 50% 50%;
}
.bar-cover .art-back::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(10, 10, 11, 0.16);
}
.bar-cover .art-back.is-empty::after {
  content: '';
  position: absolute;
  inset: 8px;
  border-radius: 5px;
  background: var(--hairline);
}
.bar-cover .art-front {
  left: 0;
  top: 0;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  box-shadow:
    0 0 0 1.5px var(--surface-solid),
    0 7px 16px -8px rgba(10, 10, 11, 0.55);
}
html[data-theme='dark'] .bar-cover .art-front {
  box-shadow:
    0 0 0 1.5px rgba(255, 255, 255, 0.16),
    0 7px 16px -8px rgba(0, 0, 0, 0.85);
}
html[data-theme='dark'] .bar-cover .art-back::after {
  background: rgba(0, 0, 0, 0.38);
}

/* The accent: one marker on the cover, the same accent the tiles use. */
.bar-badge {
  position: absolute;
  right: -3px;
  top: -3px;
  z-index: 2;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 0 2px var(--surface-solid);
}
html[data-theme='dark'] .bar-badge {
  box-shadow: 0 0 0 2px rgba(29, 29, 25, 0.92);
}

/* Two lines: total bold, unit count muted beneath. */
.bar-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  gap: 2px;
  text-align: left;
}
.bar-total {
  min-width: 0;
  font-size: 22px;
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.bar-count {
  font-size: 13px;
  font-weight: 600;
  line-height: 1.15;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* One circular action on the right, filled with ink. */
.bar-go {
  flex: 0 0 48px;
  width: 48px;
  height: 48px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--text);
  color: var(--bg);
  box-shadow: 0 8px 18px -8px rgba(10, 10, 11, 0.55);
}
.bar-go svg { width: 20px; height: 20px; stroke-width: 2.2; }
html[data-theme='dark'] .bar-go {
  box-shadow: 0 8px 18px -8px rgba(0, 0, 0, 0.9);
}

/* The band rises when the first line lands, leaves downward when the sheet
   takes the bottom, and returns the same way after the sheet closes. The
   entrance is a transition (not an animation) so the exit can take over from
   the settled state without a snap. */
.bar.is-enter {
  opacity: 0;
  transform: translateY(28px);
  transition: none;
}
.bar.is-in {
  opacity: 1;
  transform: translateY(0);
  transition:
    transform 240ms cubic-bezier(0.22, 0.9, 0.24, 1),
    opacity 240ms linear;
}
.bar.is-out {
  opacity: 0;
  transform: translateY(28px);
  transition:
    transform 220ms cubic-bezier(0.22, 0.9, 0.24, 1),
    opacity 220ms linear;
}

/* ---------- the draft sheet ---------- */

.sheet-layer { position: absolute; inset: 0; z-index: 20; }

.scrim {
  position: absolute;
  inset: 0;
  background: var(--scrim);
  /* A drag that lands on the scrim moves the sheet's own list or nothing at
     all — never the document. It is not a scroller, and it never becomes the
     shell's gesture (NAV-1529). */
  touch-action: none;
}

.sheet {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  max-height: 82%;
  display: flex;
  flex-direction: column;
  /* 18 px each side puts every row's total on x = 412 at 430 wide, exactly as
     the cart drawing measures it. */
  padding: 8px 18px calc(18px + var(--safe-bottom));
  border-radius: 28px 28px 0 0;
  background: var(--surface-solid);
  box-shadow: 0 -18px 50px -24px rgba(0, 0, 0, 0.4);
}

/* Every sheet layer is choreographed, not flipped: the sheet travels 300 ms up
   and 220 ms down, the scrim fades 200 ms in and 220 ms out. Closing waits for
   the sheet's own `transitionend` and a 400 ms safety timeout, so a missed
   event cannot leave an invisible layer eating taps. When closed the layer is
   `hidden` and, until it opens, it accepts no pointer at all.
 *
 * NAV-1518 · the draft, settings and shop-switcher layers share this one
 * contract (and one JS opener/closer). The settings and shop layers used to
 * flip `hidden` on the same frame with no rule here at all. */
#sheetLayer,
#settingsLayer,
#shopSheetLayer { pointer-events: none; }
#sheetLayer.is-open,
#sheetLayer.is-closing,
#settingsLayer.is-open,
#settingsLayer.is-closing,
#shopSheetLayer.is-open,
#shopSheetLayer.is-closing { pointer-events: auto; }

#sheetLayer .sheet,
#settingsLayer .sheet,
#shopSheetLayer .sheet { transform: translateY(100%); }
#sheetLayer.is-open .sheet,
#settingsLayer.is-open .sheet,
#shopSheetLayer.is-open .sheet {
  transform: translateY(0);
  transition: transform 300ms cubic-bezier(0.22, 0.9, 0.24, 1);
}
#sheetLayer.is-closing .sheet,
#settingsLayer.is-closing .sheet,
#shopSheetLayer.is-closing .sheet {
  transform: translateY(100%);
  transition: transform 220ms cubic-bezier(0.22, 0.9, 0.24, 1);
}

#sheetLayer .scrim,
#settingsLayer .scrim,
#shopSheetLayer .scrim { opacity: 0; }
#sheetLayer.is-open .scrim,
#settingsLayer.is-open .scrim,
#shopSheetLayer.is-open .scrim {
  opacity: 1;
  transition: opacity 200ms linear;
}
#sheetLayer.is-closing .scrim,
#settingsLayer.is-closing .scrim,
#shopSheetLayer.is-closing .scrim {
  opacity: 0;
  transition: opacity 220ms linear;
}

@media (prefers-reduced-motion: reduce) {
  .bar.is-in,
  .bar.is-out,
  .bar.is-enter,
  #sheetLayer.is-open .sheet,
  #sheetLayer.is-closing .sheet,
  #sheetLayer.is-open .scrim,
  #sheetLayer.is-closing .scrim,
  #settingsLayer.is-open .sheet,
  #settingsLayer.is-closing .sheet,
  #settingsLayer.is-open .scrim,
  #settingsLayer.is-closing .scrim,
  #shopSheetLayer.is-open .sheet,
  #shopSheetLayer.is-closing .sheet,
  #shopSheetLayer.is-open .scrim,
  #shopSheetLayer.is-closing .scrim {
    animation-duration: 0.001s !important;
    transition-duration: 0.001s !important;
  }
}

/* The grip is a tappable close affordance, so its hit area is 44 px tall even
   though the drawing is a quiet 36 x 5 bar: a control the eye cannot measure
   must still clear the floor. */
.grip {
  position: relative;
  flex: 0 0 auto;
  width: 100%;
  height: 44px;
  margin: -8px 0 0;
  border-radius: 12px;
}
.grip::after {
  content: '';
  position: absolute;
  left: 50%;
  top: 50%;
  width: 36px;
  height: 5px;
  border-radius: 3px;
  background: var(--hairline);
  transform: translate(-50%, -50%);
}

/* The sheet's header carries the title and the ITEM COUNT — never a second
   copy of the money. The count is a numeral drawn at render, not stored. */
.sheet-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 0 2px 10px;
}

/* The Navee mark (NAV-1473) sits with the sheet's title, not in the fixed
   header: a header mark clipped the shop name at 320. It is drawing, not a
   control, and it takes no accent. */
.sheet-head-main {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}

.sheet-mark {
  flex: 0 0 auto;
  display: block;
}

.sheet-title {
  min-width: 0;
  margin: 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--text);
  overflow-wrap: anywhere;
}

.sheet-count {
  flex: 0 0 auto;
  font-size: 12px;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.lines {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  list-style: none;
  margin: 0;
  padding: 0;
}

/* Cart v2: a 54 px photo, the line total on the right-hand axis, the unit price
   under the name, and the stepper on the row's own baseline. */
.line {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px 0;
  border-bottom: 1px solid var(--hairline);
}
.line:last-child { border-bottom: 0; }

.line-photo {
  position: relative;
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 14px;
  background: var(--tray);
}
.line-photo img {
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
}
.line-photo .mono {
  font-size: 18px;
  font-weight: 700;
  color: var(--mono-thumb);
}

.line-body {
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 9px;
}

.line-top {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
}

.line-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}

.line-total {
  flex: 0 0 auto;
  font-size: 15px;
  font-weight: 700;
  color: var(--text);
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.line-bot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}

.line-unit {
  flex: 0 1 auto;
  min-width: 0;
  font-size: 12.5px;
  font-weight: 500;
  line-height: 1.2;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  /* A long KHR amount may take a second line at 320 px; a cut word may not. */
  overflow-wrap: normal;
}

/* The stepper is one tray with two 44 px keys and the count between them; the
   remove × is its own 44 px target beside it. */
.stepper {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  height: 44px;
  border-radius: 13px;
  background: var(--tray);
}

.step {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: transparent;
  color: var(--text);
  font: inherit;
}
.step:active { background: var(--seg-pill); }
.step svg { width: 16px; height: 16px; }
.step--remove { color: var(--muted); flex: 0 0 auto; }
.step--remove:active { background: var(--tray); }

/* The count is now the way into a typed quantity: a 44 x 44 target inside the
   stepper's tray. A tap replaces the tray with the field and its ink tick. */
.qty {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 11px;
  background: transparent;
  color: var(--text);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}
.qty:active { background: var(--seg-pill); }

/* While a line is being typed, the row shows only the field and the tick: the
   unit price and the remove × would be two more controls beside a field the
   seller is already using. Escape or blur puts the stepper back unchanged. */
.line.is-editing .line-unit,
.line.is-editing .step--remove { display: none; }
.line.is-editing .line-bot { justify-content: flex-end; }
.qty-edit {
  display: flex;
  align-items: center;
  gap: 8px;
}
.qty-field {
  width: 64px;
  height: 44px;
  padding: 0;
  border: 1.5px solid var(--text);
  border-radius: 12px;
  background: var(--surface-solid);
  color: var(--text);
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  line-height: 44px;
  text-align: center;
  font-variant-numeric: tabular-nums;
  outline: none;
}
.qty-field:focus { border-color: var(--text); }
.qty-tick {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: #0a0a0b;
  color: #ffffff;
}
.qty-tick svg { width: 18px; height: 18px; }

/* The bill's customer row: one line above the total. It is a control, so it
   clears the 44 px floor; an unchosen customer reads as an invitation, a chosen
   one as the name the sale is for. */
.cust-row {
  flex: 0 0 auto;
  width: 100%;
  min-height: 50px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px 2px;
  border: 0;
  border-top: 1px solid var(--hairline);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.cust-row:active { background: var(--tray); }
.cust-label {
  flex: 0 0 auto;
  font-size: 14px;
  font-weight: 500;
  color: var(--muted);
}
.cust-tail {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 4px;
}
.cust-value {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 14.5px;
  font-weight: 600;
  text-align: right;
}
.cust-row.is-empty .cust-value { color: var(--muted); font-weight: 500; }
.cust-chev {
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  color: var(--muted);
}

.tot {
  flex: 0 0 auto;
  display: flex;
  justify-content: flex-end;
  align-items: baseline;
  padding: 14px 2px 4px;
  border-top: 1px solid var(--hairline);
}
.cust-row:not([hidden]) + .tot { border-top: 0; }

.tot-val {
  font-size: 24px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

/* The sheet's one filled shape: ink (#0A0A0B), never the blue accent. The
   amount is drawn at render beside the word, so no total is ever stored in the
   label. A 52 px target clears the floor under a busy thumb. */
.charge {
  flex: 0 0 auto;
  width: 100%;
  min-height: 52px;
  margin-top: 10px;
  padding: 15px 18px;
  border: 0;
  border-radius: 16px;
  background: #0a0a0b;
  color: #ffffff;
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  letter-spacing: -0.01em;
  font-variant-numeric: tabular-nums;
  text-align: center;
}
.charge:active { transform: scale(0.995); }
.charge[disabled] { opacity: 0.72; }
/* On the dark sheet an ink fill still needs its edge; the fill is unchanged
   and the text stays white. Explicit light wins over the system preference. */
@media (prefers-color-scheme: dark) {
  .charge { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
}
html[data-theme='dark'] .charge { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
html[data-theme='light'] .charge { box-shadow: none; }

/* ---------- the shop picker sheet ----------
   The draft sheet's own sibling: same layer, scrim, grip, radius and material.
   It is a list and, when lines are at stake, one question with an explicit
   destructive action and a way to keep the bill. */

.shop-list { list-style: none; margin: 0; padding: 0; }

.shop-option {
  width: 100%;
  min-height: 52px;
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 6px 8px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.shop-option:active { background: var(--tray); }

.shop-option-name {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}

.shop-option-tag {
  flex: 0 0 auto;
  padding: 3px 8px;
  border-radius: 999px;
  background: var(--tray);
  color: var(--text);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.02em;
  white-space: nowrap;
}

.shop-more {
  flex: 0 0 auto;
  margin: 10px 8px 0;
  font-size: 12px;
  line-height: 1.4;
  color: var(--release-ink);
}

.shop-actions {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 8px;
}

.shop-blocked {
  margin: 0 0 2px;
  font-size: 14px;
  line-height: 1.45;
}

.shop-confirm,
.shop-cancel {
  min-height: 44px;
  border: 0;
  border-radius: 12px;
  font: inherit;
  font-size: 14px;
  font-weight: 700;
}
.shop-confirm { background: #b3261e; color: #fff; }
.shop-cancel { background: var(--tray); color: var(--text); font-weight: 600; }

/* ---------- the customer picker ----------
   The draft sheet's sibling again. Walk-in is a row, not an absence, so the
   seller can always say "nobody" without a hidden gesture; the chosen row
   carries a drawn check, never a word. */

.customer-list { list-style: none; margin: 0; padding: 0; }

.customer-option {
  width: 100%;
  min-height: 56px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 8px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.customer-option:active { background: var(--tray); }
.customer-option.is-current { background: var(--tray); }

.customer-option-body {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.customer-option-name {
  font-size: 15.5px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.customer-option-phone {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.cust-check {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  color: var(--accent);
}

/* ---------- the post-Charge invoice card ----------
   A sheet because it is read, not edited: the receipt of the sale the seller
   just made. The document's parts stay in the bot card's order — number,
   customer, frozen lines, total, paid/due — and the two payment acts sit under
   it, one per row, exactly as the bot draws them. */

.invoice-head {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 0 2px 8px;
}
.invoice-number {
  flex: 0 0 auto;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.invoice-customer {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 8px 2px 12px;
  border-bottom: 1px solid var(--hairline);
}
.inv-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.08em;
  color: var(--muted);
}
.inv-name {
  font-size: 16px;
  font-weight: 600;
  line-height: 1.35;
  overflow-wrap: anywhere;
}
.inv-phone {
  font-size: 13px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.inv-lines { list-style: none; margin: 0; padding: 0; }
.inv-line {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: 10px;
  padding: 11px 2px;
  border-bottom: 1px solid var(--hairline);
}
.inv-line:last-child { border-bottom: 0; }
.inv-line-body { min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.inv-line-name {
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.3;
  overflow-wrap: anywhere;
}
.inv-line-meta {
  font-size: 12.5px;
  font-weight: 500;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}
.inv-line-total {
  flex: 0 0 auto;
  font-size: 14.5px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.inv-total {
  flex: 0 0 auto;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  padding: 12px 2px 4px;
  border-top: 1px solid var(--hairline);
}
.inv-total-label { font-size: 14px; font-weight: 600; color: var(--muted); }
.inv-total-val {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.inv-figures {
  flex: 0 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 4px 12px;
  padding: 4px 2px 10px;
}
.inv-fig-label { font-size: 13px; font-weight: 500; color: var(--muted); }
.inv-fig-val {
  font-size: 13.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  text-align: right;
  white-space: nowrap;
}

.inv-actions {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 6px;
}
.inv-pay {
  width: 100%;
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 14px;
  background: var(--tray);
  color: var(--text);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  text-align: center;
}
.inv-pay:active { transform: scale(0.995); }
.inv-pay[disabled] { opacity: 0.62; }
.inv-actions .charge { margin-top: 2px; }

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

.toast {
  position: absolute;
  left: 12px;
  right: 12px;
  bottom: calc(16px + var(--safe-bottom));
  z-index: 30;
  padding: 10px 14px;
  border-radius: 14px;
  background: rgba(16, 17, 20, 0.92);
  color: #fff;
  font-size: 13px;
  line-height: 1.4;
  box-shadow: var(--shadow);
}

/* An empty catalogue says why it is empty instead of drawing nothing.
 *
 * NAV-1518 · the Board's word (2026-11-06): the mark, the heading, the one
 * line and the Add New button are ONE block, optically centred in the region
 * below the header — not stacked low. #productsEmpty owns that region, so it
 * takes the leftover height and centres its content. The 16 px clear space
 * below the button (plus the device safe area) is what makes the block read
 * a few pixels above the geometric centre, exactly as the approved stills
 * measure it: 390 px → block ink centre ≈447 against a 66–844 region whose
 * midpoint is 455; 320 px → ≈310 against 317.
 *
 * The empty grid/list siblings leave the flow while the empty block is shown
 * (the shell's `.grid { display: grid }` would otherwise beat `[hidden]`,
 * giving the empty state a flex share and bottom-anchoring the block again).
 * The `hidden` attribute is still the state; this only makes it paint. */
#grid[hidden],
#list[hidden] { display: none; }

.empty {
  flex: 1 1 auto;
  min-height: 0;
  margin-top: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 0 24px calc(16px + var(--safe-bottom));
  text-align: center;
}

/* The empty shop's one way out: the same filled `.settings-primary` object as
   the Add button inside Settings, at the card's 44 px and the block's full
   measure. It is not a second kind of primary. */
#productsEmpty .empty-add {
  display: block;
  width: 100%;
  height: 44px;
  min-height: 44px;
  margin: 18px 0 0;
  padding: 0 18px;
  font-size: 16px;
  line-height: 44px;
  text-align: center;
}

/* The mark is the empty screen's only illustration; the two ruled lines stay
   exactly as they are. It is drawing, not a control. */
.empty-mark {
  display: block;
  margin: 0 auto 14px;
}

.empty-title {
  margin: 0 0 6px;
  font-size: 17px;
  font-weight: 600;
}

.empty-body {
  margin: 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
}

/* Where the client cannot composite transparency the ladder is the same
   ladder, made opaque: the ground, the surface and the bar's own base are
   declared here too, so this block can never be a different shape from the
   other sites (and never a different ground). */
@media (prefers-reduced-transparency: reduce) {
  :root {
    --bg: #f5f4ef;
    --surface: #ffffff;
    --surface-solid: #ffffff;
    --bar: #ffffff;
    /* NAV-1555: the fifth tray site. The warm step keeps the same gap below
       the light tray that #e6e6ea held below #ececf0. */
    --tray: #eae7df;
  }
  @media (prefers-color-scheme: dark) {
    :root {
      --bg: #141210;
      --surface: #1b1b17;
      --surface-solid: #1b1b17;
      --bar: #1d1d19;
      --tray: #23231f;
    }
  }
  html[data-theme='dark'] {
    --bg: #141210;
    --surface: #1b1b17;
    --surface-solid: #1b1b17;
    --bar: #1d1d19;
    --tray: #23231f;
  }
}

/* ---------- the settings sheet (NAV-1491) ----------
   One sheet, pushed panes. The home is four 58 px rows with SVG icons; a pane
   is the same sheet with a back cell and its own body. No tab row, no bottom
   navigation, and the bill behind it is never touched. */

.settings-sheet { max-height: 88%; }

.settings-head {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 2px 2px 10px;
}

.settings-back {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  margin-left: -10px;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--text);
  font: inherit;
}
.settings-back:active { background: var(--tray); }
.settings-back svg { width: 22px; height: 22px; }

.settings-title-wrap {
  flex: 1 1 auto;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.settings-eyebrow {
  margin: 0;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  color: var(--muted);
}

.settings-title {
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.proposed-pill {
  flex: 0 0 auto;
  padding: 3px 7px;
  border: 1px dashed var(--muted);
  border-radius: 8px;
  font-size: 9px;
  font-weight: 600;
  letter-spacing: 0.06em;
  color: var(--muted);
  white-space: nowrap;
}

.settings-home {
  display: flex;
  flex-direction: column;
  padding: 2px 0 4px;
}

.settings-row {
  width: 100%;
  min-height: 58px;
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 7px 2px;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.settings-row:last-child { border-bottom: 0; }
.settings-row:active { background: var(--tray); }

.settings-row-icon {
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  color: var(--muted);
}
.settings-row-icon svg { width: 22px; height: 22px; }

.settings-row-label { flex: 1 1 auto; min-width: 0; font-size: 16px; font-weight: 600; }

.settings-chev { flex: 0 0 18px; display: grid; place-items: center; color: var(--muted); }
.settings-chev svg { width: 16px; height: 16px; }

.settings-pane {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 12px;
  padding: 2px 0 4px;
}

.settings-line { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.settings-note { margin: 2px 0 0; font-size: 12.5px; line-height: 1.45; color: var(--muted); }
.settings-empty { margin: 8px 0; font-size: 14px; line-height: 1.5; color: var(--muted); }

.settings-list { list-style: none; margin: 0; padding: 0; }

.settings-item {
  width: 100%;
  min-height: 58px;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 7px 2px;
  border: 0;
  border-bottom: 1px solid var(--hairline);
  background: transparent;
  color: var(--text);
  font: inherit;
  text-align: left;
}
.settings-item:last-child { border-bottom: 0; }
.settings-item:active { background: var(--tray); }

.settings-item-thumb {
  position: relative;
  flex: 0 0 46px;
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 12px;
  background: var(--tray);
}
.settings-item-thumb img { width: 100%; height: 100%; display: block; object-fit: cover; }
.settings-item-thumb .mono { font-size: 16px; font-weight: 700; color: var(--mono-thumb); }

.settings-item-body { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.settings-item-name { font-size: 15px; font-weight: 600; overflow-wrap: anywhere; }
.settings-item-sub { font-size: 12.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.settings-item-chev { flex: 0 0 18px; display: grid; place-items: center; color: var(--muted); }
.settings-item-chev svg { width: 16px; height: 16px; }

.settings-primary {
  flex: 0 0 auto;
  width: 100%;
  min-height: 52px;
  margin-top: 6px;
  padding: 14px 18px;
  border: 0;
  border-radius: 16px;
  background: #0a0a0b;
  color: #fff;
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: center;
}
.settings-primary:active { transform: scale(0.995); }
.settings-primary[disabled] { opacity: 0.72; }
@media (prefers-color-scheme: dark) {
  .settings-primary { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
}
html[data-theme='dark'] .settings-primary { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
html[data-theme='light'] .settings-primary { box-shadow: none; }

/* ---------- Reports (NAV-1518) ----------
   One pane in the settings sheet, no new layer: the family switch, the ruled
   range segment, the « range » step row, then the figures or the ranked list.
   The values are the approved stills' own (NAV-1515); the two segment strings
   are the bot ledger's ruled words copied into copy.js. */

.reports-pane { gap: 10px; }

.report-families,
.report-ranges {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 12px;
  background: var(--tray);
}

.report-fam,
.report-range {
  flex: 1 1 0;
  min-width: 0;
  height: 44px;
  padding: 0 4px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.report-ranges .report-range { font-size: 11.5px; }
/* Khmer's ruled weekly label is a little longer than English's. At 320 px the
   three range chips hold 92 px each, and at 11.5 px the word ends in an
   ellipsis — a half-word at the edge is a fail. 10.5 px keeps the whole ruled
   word inside its chip without changing it. */
@media (max-width: 360px) {
  html[lang='km'] .report-ranges .report-range { font-size: 10.5px; }
}
.report-fam.is-on,
.report-range.is-on {
  background: var(--seg-pill);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}

.report-pager {
  display: flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
}
.report-arrow {
  flex: 0 0 44px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 20px;
  line-height: 1;
}
.report-arrow:active { background: var(--tray); }
.report-range-text {
  flex: 1 1 auto;
  min-width: 0;
  text-align: center;
  font-size: 15px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.report-body { display: flex; flex-direction: column; }
.report-figures { display: flex; flex-direction: column; }
.report-fig {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  padding: 8px 2px;
  border-bottom: 1px solid var(--hairline);
}
.report-fig:last-child { border-bottom: 0; }
.report-fig-label {
  font-size: 13.5px;
  font-weight: 500;
  color: var(--muted);
}
.report-fig-value {
  font-size: 18px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.report-fig.is-total .report-fig-label { color: var(--text); font-weight: 600; }
.report-fig.is-total .report-fig-value { font-size: 28px; letter-spacing: -0.02em; }

.report-caveat {
  margin: 2px 0 0;
  font-size: 12px;
  line-height: 1.45;
  color: var(--muted);
}

.report-list { list-style: none; margin: 0; padding: 0; }
.report-row {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto auto;
  align-items: baseline;
  gap: 5px;
  padding: 10px 2px;
  border-bottom: 1px solid var(--hairline);
  font-size: 14px;
}
.report-row:last-child { border-bottom: 0; }
.report-qty { font-weight: 700; font-variant-numeric: tabular-nums; }
.report-x, .report-eq { color: var(--muted); }
.report-name { font-weight: 500; overflow-wrap: anywhere; }
.report-value {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.report-empty {
  margin: 14px 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}

.report-retry { margin-top: 8px; }

.field { display: flex; flex-direction: column; gap: 7px; }
.field-label { font-size: 13.5px; font-weight: 500; line-height: 1.4; color: var(--muted); }
.field-money { position: relative; display: flex; align-items: center; }
.field-input {
  width: 100%;
  min-height: 52px;
  padding: 12px 14px;
  border: 0;
  border-radius: 14px;
  background: var(--tray);
  color: var(--text);
  font: inherit;
  font-size: 16px;
  font-weight: 500;
}
.field-input::placeholder { color: var(--muted); }
.field-input:focus-visible { outline: 2px solid var(--text); outline-offset: 2px; }
.field-money .field-input { padding-right: 56px; font-variant-numeric: tabular-nums; }
.field-currency { position: absolute; right: 14px; font-size: 13px; font-weight: 600; color: var(--muted); }
.field-eyebrow { margin: 0; font-size: 12px; font-weight: 600; color: var(--muted); }

.photo-row { display: flex; align-items: center; gap: 8px; }
.photo-thumb {
  position: relative;
  flex: 0 0 64px;
  width: 64px;
  height: 64px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border: 1px dashed var(--hairline);
  border-radius: 14px;
  background: var(--tray);
}
.photo-thumb img { width: 100%; height: 100%; display: block; object-fit: cover; }
.photo-thumb .mono { font-size: 18px; font-weight: 700; color: var(--mono-thumb); }
.photo-thumb svg { width: 24px; height: 24px; color: var(--muted); }
.photo-btn {
  flex: 1 1 0;
  min-height: 48px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: var(--tray);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
}
.photo-btn:active { background: var(--seg-pill); }
.photo-btn[disabled] { opacity: 0.6; }

.lang-switch { display: flex; gap: 6px; padding: 4px; border-radius: 16px; background: var(--tray); }
.lang-option {
  flex: 1 1 0;
  min-height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 10px 12px;
  border: 0;
  border-radius: 12px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
}
.lang-option .lang-check { width: 17px; height: 17px; opacity: 0; }
.lang-option[aria-pressed='true'] {
  background: var(--surface-solid);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.lang-option[aria-pressed='true'] .lang-check { opacity: 1; }

.about-mark {
  width: 82px;
  height: 82px;
  display: grid;
  place-items: center;
  align-self: center;
  margin-top: 6px;
  border-radius: 22px;
  background: #0a0a0b;
  color: #fff;
}
.about-mark svg { width: 52px; height: 52px; }
.about-name {
  display: flex;
  align-items: center;
  align-self: center;
  gap: 8px;
  margin: 2px 0 0;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-align: center;
}
.about-version { align-self: center; margin: 0; font-size: 13.5px; color: var(--muted); font-variant-numeric: tabular-nums; }
.about-line {
  align-self: center;
  max-width: 290px;
  margin: 4px 0 0;
  font-size: 14px;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}

/* ---------- the shops set (NAV-1536) ----------
   The Add New foot cell, the create pane (a state of the shop-switcher sheet),
   the Shops row and pane, a shop's own pane and its two field panes. It reuses
   the app's own objects and tokens: one filled primary, one sheet shape, one
   icon language, no new colour, and no accent on a control. */

/* ---------- the Add New cell (switcher foot, shops pane foot) ---------- */
.shop-add { margin-top: 10px; }
.shops-add { margin-top: 10px; }

/* ---------- the create pane, a state of the shop-switcher sheet ---------- */
.shop-create {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 2px 0 4px;
}

.shop-create .settings-head { padding: 2px 2px 4px; }

.currency-switch {
  display: flex;
  gap: 2px;
  padding: 2px;
  border-radius: 12px;
  background: var(--tray);
}

.currency-option {
  flex: 1 1 0;
  min-width: 0;
  height: 44px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 7px;
  padding: 0 8px;
  border: 0;
  border-radius: 10px;
  background: transparent;
  color: var(--muted);
  font: inherit;
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.02em;
}
.currency-option.is-on {
  background: var(--seg-pill);
  color: var(--text);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.12);
}
.currency-check { width: 15px; height: 15px; }

/* ---------- the shops pane ---------- */
.shops-hint { margin: 0; font-size: 13px; line-height: 1.45; color: var(--muted); }
.shops-list { list-style: none; margin: 0; padding: 0; }

.shop-item .settings-item-name { font-size: 15.5px; font-weight: 600; }
.shop-item .shop-option-tag { margin-right: 2px; }

/* ---------- a shop's own pane ---------- */
.shop-read {
  display: flex;
  flex-direction: column;
  border-bottom: 1px solid var(--hairline);
  padding-bottom: 4px;
  margin-bottom: 2px;
}

.shop-read-row {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 44px;
  padding: 4px 2px;
}

.shop-read-icon {
  flex: 0 0 28px;
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  color: var(--muted);
}
.shop-read-icon svg { width: 21px; height: 21px; }

.shop-read-value {
  flex: 1 1 auto;
  min-width: 0;
  font-size: 15.5px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.shop-cells { display: flex; flex-direction: column; }
.shop-cells .settings-row.is-action .settings-chev { visibility: hidden; }

/* ---------- the two field panes ---------- */
.shop-field-pane { display: flex; flex-direction: column; gap: 14px; }
.shop-field-pane .settings-primary { margin-top: 2px; }

/* The guard replaces the form; the head stays and the block follows it. */
.shop-create.is-guard { flex: 0 0 auto; overflow: visible; }

/* ------------------------------------------------------------------
   NAV-1591 · the browser shell — the cleared drawing (NAV-1588/1589)

   At 768 and up the app is a bounded column, centred on the page: at most
   1100 px, a 24 px gutter, a 24 px top and bottom inset. Below 768 the app
   is the app that serves today, untouched.

   At 900 and up the menu becomes the list the drawing shows: two columns
   at home, one column beside the 420 px till rail. At phone width the till
   is still the bottom sheet. Nothing inside a screen is redesigned; only
   the frame and the columns move. */

@media (min-width: 768px) {
  html,
  body {
    background: var(--page-bg);
  }

  .app {
    width: min(1100px, calc(100vw - 48px));
    margin: 24px auto;
    height: calc(100dvh - 48px);
    border-radius: 22px;
    overflow: hidden;
    border: 1px solid rgba(0, 0, 0, 0.06);
    box-shadow:
      0 1px 2px rgba(16, 16, 20, 0.06),
      0 30px 80px -40px rgba(16, 16, 20, 0.35);
  }

  /* The drawing's own insets: a 24 px working gutter inside the column, and
     the header's quieter 18/22/10/24. At phone width these lines do not run. */
  .top { padding: 18px 22px 10px 24px; }
  .chips { padding-left: 24px; padding-right: 24px; }
  .grid,
  .list { padding-left: 24px; padding-right: 24px; }
}

@media (min-width: 900px) {
  .grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .list {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-auto-rows: max-content;
    gap: 8px 14px;
    align-content: start;
  }

  /* The till, docked: #sheetLayer is the app's own layer; only its box and
     the box around the menu move. The rows, stepper, customer row, total and
     Charge are the draft sheet's own. The class is set from `draftOpen`. */
  body.is-till #sheetLayer {
    position: absolute;
    inset: 0;
    pointer-events: none;
  }
  body.is-till #sheetLayer .scrim { display: none; }
  body.is-till #sheetLayer .sheet {
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: auto;
    width: 420px;
    max-height: none;
    border-radius: 0;
    transform: none !important;
    box-shadow: -1px 0 0 var(--hairline);
    background: var(--surface-solid);
    padding-left: 26px;
    padding-right: 26px;
  }
  body.is-till #sheetLayer .grip { display: none; }
  body.is-till #sheetLayer .sheet-head { padding-top: 26px; }

  body.is-till .top,
  body.is-till .notice,
  body.is-till .chips,
  body.is-till #screen,
  body.is-till .bar,
  body.is-till .empty { margin-right: 420px; }

  body.is-till .list {
    display: flex;
    flex-direction: column;
  }
}

/* ------------------------------------------------------------------
   NAV-1591 · the browser sign-in screen — the cleared drawing

   Shown only on the browser origin (`business.*`) when the page has no
   Mini App `initData`. The card is the drawing's: a bounded 820 px shell,
   the two doors side by side, and one dashed frame that is ours around a
   control that is Telegram's. English until the Board's ear rules a Khmer
   column; `km` stays null in the ledger. */

.signin-page {
  min-height: 100dvh;
  display: grid;
  place-items: center;
  padding: 56px 24px;
  background:
    radial-gradient(120% 60% at 50% -10%, rgba(0, 113, 227, 0.10), transparent 70%),
    var(--bg);
}

.signin-shell { width: min(820px, 100%); }

.signin-card {
  background: var(--surface-solid);
  border-radius: 26px;
  box-shadow:
    0 1px 2px rgba(16, 16, 20, 0.05),
    0 40px 90px -60px rgba(16, 16, 20, 0.45);
  border: 1px solid var(--hairline);
  padding: 36px 40px 32px;
}

.signin-head { display: flex; align-items: center; gap: 16px; }
.signin-mark { flex: 0 0 auto; border-radius: 14px; }
.signin-eyebrow {
  margin: 0 0 2px;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.signin-head h1 {
  margin: 0;
  font-size: 26px;
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.signin-lede {
  margin: 18px 0 0;
  max-width: 480px;
  font-size: 15px;
  line-height: 1.5;
  color: var(--muted);
}

.signin-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.25fr) minmax(0, 1fr);
  gap: 0 36px;
  margin-top: 28px;
}
.signin-door-col { min-width: 0; }
.signin-fallback {
  min-width: 0;
  padding-left: 36px;
  border-left: 1px solid var(--hairline);
  display: flex;
  flex-direction: column;
  justify-content: center;
}

/* The frame is the drawing's whole point: Telegram's widget is not ours to
   paint, so the slot is declared and the note says who fills it. */
.signin-frame {
  position: relative;
  padding: 18px 16px 16px;
  border: 1.5px dashed rgba(0, 0, 0, 0.16);
  border-radius: 18px;
  background: var(--bg);
}
.signin-frame-label {
  position: absolute;
  top: -8px;
  left: 14px;
  padding: 0 6px;
  background: var(--surface-solid);
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.signin-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 66px;
  text-align: center;
}
.signin-slot iframe { display: block; margin: 0 auto; }
.signin-placeholder {
  max-width: 260px;
  font-size: 12.5px;
  line-height: 1.4;
  color: var(--muted);
}
.signin-waiting {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 66px;
  font-size: 13px;
  font-weight: 600;
  color: var(--text);
}

.signin-door {
  width: 100%;
  min-height: 52px;
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 0 18px;
  border: 0;
  border-radius: 14px;
  background: #0a0a0b;
  color: #ffffff;
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  letter-spacing: -0.005em;
  cursor: pointer;
}
.signin-door .signin-tg { width: 20px; height: 20px; display: block; }
.signin-note {
  margin: 10px 2px 0;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--muted);
}

/* Waiting: the same button's place holds a spinner and the app's own line. */
.signin-working {
  display: none;
  width: 100%;
  min-height: 52px;
  margin-top: 12px;
  align-items: center;
  justify-content: center;
  gap: 10px;
  border-radius: 14px;
  background: var(--tray);
  color: var(--text);
  font-size: 15px;
  font-weight: 600;
}
.signin-working .spinner { width: 18px; height: 18px; }
.signin-waiting .spinner { width: 18px; height: 18px; }

.signin-error {
  display: none;
  align-items: flex-start;
  gap: 9px;
  margin: 0 0 16px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(224, 72, 63, 0.10);
  color: #a4261f;
  font-size: 13px;
  line-height: 1.4;
}
.signin-error-dot {
  flex: 0 0 auto;
  width: 8px;
  height: 8px;
  margin-top: 5px;
  border-radius: 50%;
  background: #e0483f;
}

.signin-card[data-state='ready'] .signin-error { display: none; }
.signin-card[data-state='waiting'] .signin-door { display: none; }
.signin-card[data-state='waiting'] .signin-working { display: flex; }
.signin-card[data-state='waiting'] .signin-slot { display: none; }
.signin-card[data-state='waiting'] .signin-waiting { display: flex; }
.signin-card[data-state='refused'] .signin-error { display: flex; }
.signin-card[data-state='refused'] .signin-door { background: var(--tray); color: var(--text); }
.signin-card[data-state='refused'] .signin-continue-label { display: none; }
.signin-card[data-state='refused'] .signin-retry-label { display: inline; }
.signin-retry-label { display: none; }

.signin-fallback h2 {
  margin: 0;
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -0.01em;
}
.signin-fallback p {
  margin: 6px 0 16px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--muted);
}
.signin-fallback-btn {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--surface-solid);
  color: var(--text);
  font: inherit;
  font-size: 13.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  box-shadow: 0 1px 2px rgba(16, 16, 20, 0.04);
}

.signin-eyebrow-line {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--muted);
}
.signin-eyebrow-line::before,
.signin-eyebrow-line::after {
  content: '';
  flex: 1 1 auto;
  height: 1px;
  background: var(--hairline);
}

.signin-foot {
  margin: 18px 0 0;
  text-align: center;
  font-size: 12px;
  color: var(--muted);
}

html[data-theme='dark'] .signin-door { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
html[data-theme='dark'] .signin-error { background: rgba(224, 72, 63, 0.18); color: #ff938b; }
html[data-theme='dark'] .signin-frame { background: rgba(255, 255, 255, 0.03); border-color: rgba(255, 255, 255, 0.16); }

/* The browser origin has no Telegram client, so nothing writes `data-theme`;
   the system scheme is the one that decides. The same three overrides follow
   the tokens the media query already switched. */
@media (prefers-color-scheme: dark) {
  .signin-door { box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.16); }
  .signin-error { background: rgba(224, 72, 63, 0.18); color: #ff938b; }
  .signin-frame { background: rgba(255, 255, 255, 0.03); border-color: rgba(255, 255, 255, 0.16); }
}

@media (max-width: 760px) {
  .signin-page { padding: 24px 16px; align-items: start; }
  .signin-card { padding: 24px 20px 22px; border-radius: 22px; }
  .signin-head h1 { font-size: 22px; }
  .signin-grid { grid-template-columns: 1fr; gap: 24px; margin-top: 22px; }
  .signin-fallback {
    padding-left: 0;
    border-left: 0;
    border-top: 1px solid var(--hairline);
    padding-top: 22px;
  }
}
