/* ==========================================================================
   Restaurant POS — design system
   --------------------------------------------------------------------------
   Hand-authored, no build step, one file, no framework.

   Why not Tailwind's play CDN (which PROJECT_PLAN section 3 named): it ships
   ~400KB of JavaScript that compiles stylesheets in the browser on every page
   load. On the RM400 Android tablet a restaurant will actually buy, that is a
   visible flash of unstyled text before every screen. A POS is judged in the
   first half second by someone holding plates. This file is ~20KB, cached, and
   paints immediately. The plan's binding constraint -- "do not add a Node build
   pipeline" -- is honoured more strongly by having no toolchain at all.

   Design principles, in priority order:
     1. The total is the hero. At any moment staff and customer must see it.
     2. Thumb first. Primary actions live in the bottom third on a phone.
     3. Calm surfaces, loud actions. Neutral chrome so food names read first.
     4. Legible at arm's length under fluorescent light: 15px floor, real
        contrast, no thin weights.
     5. Nothing animates longer than 150ms and nothing shifts layout.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Warm neutrals rather than blue-grey: hospitality, not enterprise SaaS. */
  --canvas: #f7f6f3;
  --surface: #ffffff;
  --surface-sunken: #f2f0ec;
  --line: #e6e2db;
  --line-strong: #d5cfc5;

  --ink: #1a1918;
  --ink-2: #46423d;
  --ink-3: #6f6a63;
  --ink-4: #9c958c;

  /* One confident green carries brand, selection and "take payment" alike.
     Reads premium, reads appetising, and is at home in the Malaysian market. */
  --brand: #0e7a5f;
  --brand-strong: #0a6650;
  --brand-soft: #e8f5f0;
  --brand-line: #b5ded1;

  /* Saffron: attention without alarm. Sold out, open tables, unbalanced till. */
  --warn: #a35a09;
  --warn-soft: #fdf4e5;
  --warn-line: #f0dcb8;

  /* Voids, negative variance, destructive confirmations. */
  --danger: #b42318;
  --danger-soft: #fdf2f1;
  --danger-line: #f4cdc9;

  --focus: #0e7a5f;

  --radius-sm: 8px;
  --radius: 12px;
  --radius-lg: 16px;
  --radius-pill: 999px;

  /* Hairlines separate most things; shadow is reserved for what floats. */
  --shadow-sm: 0 1px 2px rgba(26, 25, 24, 0.06);
  --shadow: 0 1px 3px rgba(26, 25, 24, 0.08), 0 4px 12px rgba(26, 25, 24, 0.05);
  --shadow-lift: 0 -2px 16px rgba(26, 25, 24, 0.1);

  --font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, "Noto Sans", "Liberation Sans", sans-serif;

  /* Touch targets. 48px is the comfortable floor; 56px for anything a waiter
     hits a hundred times a service. */
  --tap: 48px;
  --tap-lg: 56px;

  --header-h: 56px;
}

/* --------------------------------------------------------------------------
   2. Base
   -------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  font-family: var(--font);
  font-size: 15px;
  line-height: 1.45;
  color: var(--ink);
  background: var(--canvas);
  -webkit-font-smoothing: antialiased;
  /* Staff drag their thumb across a menu grid; stop the browser treating that
     as text selection and popping a context menu mid-service. */
  -webkit-tap-highlight-color: transparent;
}

h1, h2, h3, h4, p, figure, ul, ol, dl, dd {
  margin: 0;
}

ul, ol {
  padding: 0;
  list-style: none;
}

a {
  color: var(--brand-strong);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

img {
  max-width: 100%;
  display: block;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Every price, total and quantity in the product lines up in a column. */
.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

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

/* --------------------------------------------------------------------------
   3. Typography
   -------------------------------------------------------------------------- */
.t-display {
  font-size: 30px;
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.02em;
}

.t-title {
  font-size: 20px;
  line-height: 1.25;
  font-weight: 650;
  letter-spacing: -0.01em;
}

.t-heading {
  font-size: 17px;
  line-height: 1.3;
  font-weight: 600;
}

.t-body {
  font-size: 15px;
}

.t-small {
  font-size: 13px;
}

.t-micro {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.t-muted { color: var(--ink-3); }
.t-faint { color: var(--ink-4); }
.t-danger { color: var(--danger); }
.t-warn { color: var(--warn); }
.t-brand { color: var(--brand-strong); }

/* --------------------------------------------------------------------------
   4. App shell
   -------------------------------------------------------------------------- */
.app-header {
  position: sticky;
  top: 0;
  z-index: 30;
  height: var(--header-h);
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 0 12px;
  background: var(--ink);
  color: #fff;
  padding-top: env(safe-area-inset-top);
}

.app-header__brand {
  display: flex;
  align-items: center;
  gap: 9px;
  color: #fff;
  font-weight: 650;
  letter-spacing: -0.01em;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.app-header__brand:hover {
  text-decoration: none;
}

/* The branch this device rings into. Quieter than the restaurant name -- it is
   a fact to check, not a title -- but always legible. */
.app-header__outlet {
  padding: 2px 8px;
  border-radius: var(--radius-pill);
  background: rgba(255, 255, 255, 0.14);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0;
}

/* A small monogram tile: gives the header an anchor without needing a logo
   file from a restaurant that has not sent one. */
.monogram {
  flex: none;
  width: 30px;
  height: 30px;
  border-radius: 9px;
  display: grid;
  place-items: center;
  background: var(--brand);
  color: #fff;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.01em;
}

.app-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 2px;
}

.app-nav__link {
  display: flex;
  align-items: center;
  gap: 7px;
  height: 40px;
  padding: 0 12px;
  border-radius: var(--radius-sm);
  color: rgba(255, 255, 255, 0.78);
  font-size: 14px;
  font-weight: 500;
  white-space: nowrap;
}

.app-nav__link:hover {
  background: rgba(255, 255, 255, 0.1);
  color: #fff;
  text-decoration: none;
}

.app-nav__link[aria-current="page"] {
  background: rgba(255, 255, 255, 0.14);
  color: #fff;
}

.app-nav__label {
  display: none;
}

@media (min-width: 700px) {
  .app-nav__label { display: inline; }
}

/* On a narrow phone the nav needs the room more than the shop name does --
   the waiter knows which restaurant they are standing in. */
.app-header__brand span:not(.monogram) { display: none; }

@media (min-width: 480px) {
  .app-header__brand span:not(.monogram) { display: inline; }
}

.app-main {
  max-width: 1240px;
  margin: 0 auto;
  padding: 16px 12px 24px;
}

.app-main--narrow {
  max-width: 460px;
}

.app-main--wide {
  max-width: 1400px;
}

@media (min-width: 900px) {
  .app-main { padding: 20px 20px 32px; }
}

.page-head {
  display: flex;
  align-items: flex-end;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.page-head__actions {
  margin-left: auto;
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

/* --------------------------------------------------------------------------
   5. Buttons
   -------------------------------------------------------------------------- */
.btn {
  --btn-bg: var(--surface);
  --btn-fg: var(--ink);
  --btn-border: var(--line-strong);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  padding: 0 16px;
  border: 1px solid var(--btn-border);
  border-radius: var(--radius);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 15px;
  font-weight: 550;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, transform 80ms ease;
  text-decoration: none;
  white-space: nowrap;
}

.btn:hover { text-decoration: none; }

/* A press that you can feel is a press that you trust registered. */
.btn:active:not(:disabled) { transform: scale(0.98); }

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--primary {
  --btn-bg: var(--brand);
  --btn-fg: #fff;
  --btn-border: var(--brand);
}
.btn--primary:hover:not(:disabled) { --btn-bg: var(--brand-strong); --btn-border: var(--brand-strong); }

.btn--dark {
  --btn-bg: var(--ink);
  --btn-fg: #fff;
  --btn-border: var(--ink);
}
.btn--dark:hover:not(:disabled) { --btn-bg: #000; }

.btn--danger {
  --btn-bg: var(--danger);
  --btn-fg: #fff;
  --btn-border: var(--danger);
}

.btn--quiet {
  --btn-border: transparent;
  --btn-bg: transparent;
  --btn-fg: var(--ink-2);
}
.btn--quiet:hover:not(:disabled) { --btn-bg: var(--surface-sunken); }

.btn--lg {
  min-height: var(--tap-lg);
  font-size: 16px;
  font-weight: 600;
  border-radius: var(--radius);
}

/* A quieter button, not a smaller target.
   36px is under the 44px anybody reaches reliably and under the 48 --tap
   declares, and this carries Remove, Retire and the receipt's action bar. It
   reads smaller through type and padding; the box stays a thumb's width. */
.btn--sm {
  min-height: 44px;
  padding: 0 12px;
  font-size: 13.5px;
  border-radius: var(--radius-sm);
}

.btn--block { width: 100%; }

.btn-row {
  display: flex;
  gap: 8px;
}

.btn-row > * { flex: 1; }

/* Icon-only control: square, and a full tap target for real.
   This said "still a full tap target" at 40px while --tap declares 48, and
   these are the ±, note, price and void buttons on every ticket line -- the
   busiest controls in the product, hit by a thumb, at speed, by somebody
   holding plates. The glyph stays 18px; the box around it grew. */
.icon-btn {
  display: inline-grid;
  place-items: center;
  width: var(--tap);
  height: var(--tap);
  flex: none;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--ink-2);
  cursor: pointer;
  transition: background-color 120ms ease, transform 80ms ease;
}

.icon-btn:active { transform: scale(0.94); }
.icon-btn:hover { background: var(--surface-sunken); }
.icon-btn--danger { color: var(--danger); border-color: var(--danger-line); background: var(--danger-soft); }

/* --------------------------------------------------------------------------
   6. Surfaces
   -------------------------------------------------------------------------- */
.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
}

.card__head {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 13px 16px;
  border-bottom: 1px solid var(--line);
}

.card__body { padding: 16px; }

.card__foot {
  padding: 12px 16px;
  border-top: 1px solid var(--line);
  background: var(--surface-sunken);
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}

.stack > * + * { margin-top: 12px; }
.stack-lg > * + * { margin-top: 20px; }

/* --------------------------------------------------------------------------
   7. Badges and chips
   -------------------------------------------------------------------------- */
.badge {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 3px 9px;
  border-radius: var(--radius-pill);
  background: var(--surface-sunken);
  border: 1px solid var(--line);
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-2);
  white-space: nowrap;
}

.badge--brand { background: var(--brand-soft); border-color: var(--brand-line); color: var(--brand-strong); }
.badge--warn { background: var(--warn-soft); border-color: var(--warn-line); color: var(--warn); }
.badge--danger { background: var(--danger-soft); border-color: var(--danger-line); color: var(--danger); }
.badge--dark { background: var(--ink); border-color: var(--ink); color: #fff; }

.dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
  flex: none;
}

/* Toggleable phrase. Used for the kitchen notes a waiter taps instead of
   typing; sized so a thumb hits one and not its neighbour. */
.chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  min-height: 38px;
  padding: 0 13px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14px;
  font-weight: 550;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, color 120ms ease;
}

.chip:hover { border-color: var(--brand); }
.chip:active { transform: scale(0.97); }

.chip[aria-pressed="true"] {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
}

.chip-row {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

/* --------------------------------------------------------------------------
   8. Category rail
   -------------------------------------------------------------------------- */
.rail {
  display: flex;
  gap: 8px;
  overflow-x: auto;
  padding-bottom: 4px;
  margin-bottom: 14px;
  scrollbar-width: none;
  -webkit-overflow-scrolling: touch;
}

.rail::-webkit-scrollbar { display: none; }

.rail__tab {
  flex: none;
  min-height: 42px;
  padding: 0 16px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--ink-2);
  font-size: 14.5px;
  font-weight: 550;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 120ms ease, color 120ms ease, border-color 120ms ease;
}

.rail__tab[aria-selected="true"] {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}

/* --------------------------------------------------------------------------
   9. Menu item grid
   -------------------------------------------------------------------------- */
.item-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: 10px;
}

@media (min-width: 900px) {
  .item-grid { grid-template-columns: repeat(auto-fill, minmax(168px, 1fr)); }
}

.item-tile {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2px;
  min-height: 92px;
  padding: 12px;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color 120ms ease, transform 80ms ease, box-shadow 120ms ease;
}

.item-tile:hover:not(:disabled) {
  border-color: var(--brand);
  box-shadow: var(--shadow);
}

.item-tile:active:not(:disabled) { transform: scale(0.985); }

.item-tile__name {
  font-size: 15px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink);
}

.item-tile__secondary {
  font-size: 12.5px;
  color: var(--ink-3);
  line-height: 1.3;
}

.item-tile__price {
  margin-top: auto;
  padding-top: 8px;
  font-size: 15px;
  font-weight: 650;
  color: var(--ink);
}

.item-tile__thumb {
  width: 100%;
  height: 84px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  margin-bottom: 8px;
  background: var(--surface-sunken);
}

/* Stands in for a dish with no photo. Solid, not dashed: dashed already means
   "sold out" on this screen, and a waiter should not have to tell the two
   apart at a glance. */
.item-tile__thumb--empty {
  display: grid;
  place-items: center;
  color: var(--ink-4);
  box-shadow: inset 0 0 0 1px var(--line);
}

.item-tile--out {
  background: var(--surface-sunken);
  border-style: dashed;
  cursor: not-allowed;
}

.item-tile--out .item-tile__name,
.item-tile--out .item-tile__price {
  color: var(--ink-4);
  text-decoration: line-through;
  text-decoration-thickness: 1px;
}

/* Price and "Sold out" on one row at the foot of the tile. In normal flow, not
   overlaid: the tile is 150px at its narrowest and there is no corner free of
   text on a tile without a photo. */
.item-tile__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  width: 100%;
  padding-top: 8px;
}

/* The price supplies its own spacing when it stands alone, as it does on the
   availability screen. Inside the row, the row owns it. */
.item-tile__foot .item-tile__price {
  margin-top: 0;
  padding-top: 0;
}

/* --------------------------------------------------------------------------
   10. The ticket (running order)
   -------------------------------------------------------------------------- */
.pos-layout {
  display: grid;
  gap: 16px;
}

@media (min-width: 1000px) {
  .pos-layout { grid-template-columns: minmax(0, 1fr) 372px; align-items: start; }
  .pos-ticket { position: sticky; top: calc(var(--header-h) + 20px); }
}

.ticket {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.ticket__head {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 14px;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.ticket__number {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.ticket__lines {
  max-height: min(46vh, 420px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.line {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 2px 10px;
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
}

.line:last-child { border-bottom: 0; }

.line__name {
  font-size: 14.5px;
  font-weight: 550;
  line-height: 1.3;
}

.line__qty {
  display: inline-block;
  min-width: 22px;
  margin-right: 2px;
  font-weight: 700;
  color: var(--brand-strong);
}

.line__total {
  font-size: 14.5px;
  font-weight: 600;
  text-align: right;
}

.line__meta {
  grid-column: 1 / -1;
  padding-left: 24px;
  font-size: 12.5px;
  color: var(--ink-3);
  line-height: 1.4;
}

.line__note {
  font-style: italic;
}

/* A changed price is not an error, so it does not borrow the void's red. It
   still has to be noticeable, because it is the line a customer queries. */
.line__override {
  color: var(--warn);
}

.line__controls {
  grid-column: 1 / -1;
  display: flex;
  gap: 6px;
  margin-top: 7px;
  padding-left: 24px;
}

.line--voided .line__name,
.line--voided .line__total {
  color: var(--ink-4);
  text-decoration: line-through;
}

/* Connection banner. Pinned to the top because a cashier's eyes are on the
   ticket, and sized for reading at arm's length under a queue. */
.conn-banner {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: 12px 16px;
  font-size: 15px;
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  color: #fff;
  background: var(--danger);
  box-shadow: 0 2px 8px rgb(0 0 0 / 0.18);
}

.conn-banner[data-tone="ok"] { background: var(--brand-strong); }

.conn-banner:hover { cursor: pointer; }

/* Totals block. The grand total is the largest number on the screen, always. */
.totals {
  padding: 12px 14px;
  border-top: 1px solid var(--line);
  background: var(--surface-sunken);
}

.totals__row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  font-size: 13.5px;
  color: var(--ink-2);
  padding: 2px 0;
}

.totals__row--credit { color: var(--brand-strong); }

/* Both are single class names, so plain ``.t-danger`` loses to ``.totals__row``
   on source order and the shortfall renders in the same grey as every other
   line. It is the one number on this screen that must stop a thumb. */
.totals__row.t-danger { color: var(--danger); }

/* A totals block sitting inside a payment row rather than under the ticket:
   same figures, quieter, so the per-tender maths reads as a footnote to the
   field above it and not as another bill. */
.totals--inset {
  padding: 8px 0 0;
  border-top: 1px dashed var(--line);
  background: none;
}

.totals__grand {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-top: 8px;
  padding-top: 10px;
  border-top: 1px solid var(--line-strong);
}

.totals__grand dt {
  font-size: 13px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.totals__grand dd {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1;
}

.ticket__actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 8px;
  padding: 12px 14px;
  border-top: 1px solid var(--line);
}

/* --------------------------------------------------------------------------
   11. Empty and error states
   -------------------------------------------------------------------------- */
.empty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 36px 20px;
  text-align: center;
  color: var(--ink-3);
}

.empty__icon {
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  border-radius: var(--radius);
  background: var(--surface-sunken);
  color: var(--ink-4);
  margin-bottom: 2px;
}

.notice {
  display: flex;
  gap: 9px;
  align-items: flex-start;
  padding: 10px 14px;
  font-size: 13.5px;
  line-height: 1.4;
}

.notice--error {
  background: var(--danger-soft);
  color: var(--danger);
  border-bottom: 1px solid var(--danger-line);
}

.notice--info {
  background: var(--warn-soft);
  color: var(--warn);
  border: 1px solid var(--warn-line);
  border-radius: var(--radius);
}

/* A link inside a notice inherits the notice's colour: the default blue is
   unreadable on amber and reads as a different message. */
.notice a {
  color: currentColor;
  text-decoration: underline;
  text-underline-offset: 2px;
  font-weight: 650;
}

/* --------------------------------------------------------------------------
   12. Forms
   -------------------------------------------------------------------------- */
.field { display: block; }
.field + .field { margin-top: 14px; }

.field__label {
  display: block;
  margin-bottom: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-2);
}

.input,
.select,
.textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 16px; /* 16px stops iOS zooming the page on focus. */
  transition: border-color 120ms ease, box-shadow 120ms ease;
}

.textarea { min-height: 72px; resize: vertical; }

.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--brand);
  box-shadow: 0 0 0 3px var(--brand-soft);
}

.input--amount {
  text-align: right;
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  font-size: 17px;
}

.field__hint {
  margin-top: 5px;
  font-size: 12.5px;
  color: var(--ink-3);
}

/* Django renders forms as <p> blocks; make that look deliberate. */
.django-form p { margin: 0 0 14px; }
.django-form label {
  display: block;
  margin-bottom: 5px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-2);
}
.django-form input[type="text"],
.django-form input[type="email"],
.django-form input[type="number"],
.django-form input[type="url"],
.django-form input[type="password"],
.django-form input[type="file"],
.django-form select,
.django-form textarea {
  width: 100%;
  min-height: var(--tap);
  padding: 10px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface);
  font-size: 16px;
}
.django-form textarea { min-height: 72px; }
.django-form input[type="checkbox"] {
  width: 20px;
  height: 20px;
  margin-right: 8px;
  vertical-align: -4px;
  accent-color: var(--brand);
}
.django-form .helptext {
  display: block;
  margin-top: 4px;
  font-size: 12.5px;
  color: var(--ink-3);
}
.django-form ul.errorlist {
  margin: 0 0 6px;
  color: var(--danger);
  font-size: 13px;
}

.switch-row {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: var(--tap);
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
}

.switch-row:last-child { border-bottom: 0; }

/* --------------------------------------------------------------------------
   13. PIN keypad
   -------------------------------------------------------------------------- */
.keypad {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 10px;
}

.keypad__key {
  min-height: 60px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: 22px;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color 100ms ease, transform 70ms ease;
  box-shadow: var(--shadow-sm);
}

.keypad__key:active { transform: scale(0.95); background: var(--surface-sunken); }

.keypad__key--util {
  font-size: 14px;
  font-weight: 550;
  color: var(--ink-3);
  box-shadow: none;
  background: transparent;
  border-color: transparent;
}

.keypad__key--go {
  background: var(--brand);
  border-color: var(--brand);
  color: #fff;
  font-size: 15px;
}

.keypad__key--go:disabled {
  background: var(--surface-sunken);
  border-color: var(--line);
  color: var(--ink-4);
  cursor: not-allowed;
}

.pin-dots {
  display: flex;
  justify-content: center;
  gap: 12px;
  margin: 18px 0 14px;
  min-height: 16px;
}

.pin-dots__dot {
  width: 13px;
  height: 13px;
  border-radius: 50%;
  border: 1.5px solid var(--line-strong);
  transition: background-color 100ms ease, border-color 100ms ease, transform 100ms ease;
}

.pin-dots__dot--on {
  background: var(--brand);
  border-color: var(--brand);
  transform: scale(1.1);
}

/* Only a device with a real pointer gets told about the keyboard: a tablet has
   no keys to press and the line would just be noise on the till screen. */
.keyboard-hint { display: none; }

@media (hover: hover) and (pointer: fine) {
  .keyboard-hint { display: block; }
}

.staff-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 8px;
}

.staff-chip {
  display: flex;
  align-items: center;
  gap: 9px;
  min-height: var(--tap);
  padding: 8px 12px;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--surface);
  text-align: left;
  cursor: pointer;
  transition: border-color 120ms ease, background-color 120ms ease;
}

.staff-chip[aria-pressed="true"] {
  border-color: var(--brand);
  background: var(--brand-soft);
}

.avatar {
  flex: none;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--ink);
  color: #fff;
  font-size: 12.5px;
  font-weight: 650;
}

.staff-chip[aria-pressed="true"] .avatar { background: var(--brand); }

.staff-chip__name {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.2;
}

.staff-chip__role {
  font-size: 11.5px;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   14. Phone order bar — total and Pay always within thumb reach
   -------------------------------------------------------------------------- */
.order-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  background: var(--surface);
  border-top: 1px solid var(--line);
  box-shadow: var(--shadow-lift);
}

.order-bar__total {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.order-bar__amount {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.02em;
}

@media (min-width: 1000px) {
  .order-bar { display: none; }
}

@media (max-width: 999px) {
  /* Keep the last ticket row clear of the fixed bar. */
  .pos-layout { padding-bottom: 92px; }

  /* The bar already carries Pay; two identical green buttons a thumb apart
     reads as a bug, so the ticket keeps only its secondary action. */
  .ticket__actions { grid-template-columns: 1fr; }
  .ticket__actions .pay-inline { display: none; }

  /* Stacked, a form stretched to the full width of a tablet looks unfinished.
     Cap it at a comfortable reading measure and centre it. */
  .pos-ticket > .ticket,
  .pos-ticket > form.ticket { max-width: 560px; margin: 0 auto; }
}

/* --------------------------------------------------------------------------
   15. Tables
   -------------------------------------------------------------------------- */
.table-wrap {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
}

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}

.table th {
  text-align: left;
  padding: 10px 14px;
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
  background: var(--surface-sunken);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.table td {
  padding: 11px 14px;
  border-bottom: 1px solid var(--line);
  vertical-align: middle;
}

.table tbody tr:last-child td { border-bottom: 0; }
.table tbody tr:hover td { background: #fbfaf8; }

.table .right,
.table th.right { text-align: right; font-variant-numeric: tabular-nums; }

/* Let the first column take the slack so numbers and actions stay together on
   the right, instead of a price drifting into the middle of an empty row. */
.table--menu td:first-child,
.table--menu th:first-child { width: 100%; }
.table--menu td:not(:first-child) { white-space: nowrap; }

.table__sub {
  display: block;
  font-size: 12.5px;
  color: var(--ink-3);
}

/* --------------------------------------------------------------------------
   16. Stats
   -------------------------------------------------------------------------- */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 10px;
}

.stat {
  padding: 14px 16px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
}

.stat__label {
  font-size: 11.5px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

/* What a headline figure is made of, when the figure alone is misleading:
   "expected 420.00" reads differently once it says "after 80.00 paid out". */
.stat__note {
  margin: 6px 0 0;
  line-height: 1.35;
}

.stat__value {
  margin-top: 5px;
  font-size: 25px;
  font-weight: 700;
  letter-spacing: -0.02em;
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}

.stat--accent { background: var(--brand-soft); border-color: var(--brand-line); }
.stat--accent .stat__value { color: var(--brand-strong); }
.stat--warn { background: var(--warn-soft); border-color: var(--warn-line); }
.stat--warn .stat__value { color: var(--warn); }

/* --------------------------------------------------------------------------
   17. Tables (dining) board
   -------------------------------------------------------------------------- */
.table-board {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(132px, 1fr));
  gap: 10px;
}

.table-card {
  display: flex;
  flex-direction: column;
  gap: 3px;
  min-height: 104px;
  padding: 13px;
  text-align: left;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--shadow-sm);
  cursor: pointer;
  transition: border-color 120ms ease, transform 80ms ease;
}

.table-card:active { transform: scale(0.985); }
.table-card:hover { border-color: var(--brand); }

.table-card--busy {
  background: var(--warn-soft);
  border-color: var(--warn-line);
}

/* No table at all: a walk-in. Its own colour and full width above the board,
   because it is a different act rather than a table with a funny name -- and
   a waiter reaching for it is not scanning the room. */
.table-card--takeaway {
  width: 100%;
  min-height: 84px;
  background: var(--brand-soft);
  border-color: var(--brand-line);
}

.table-card--takeaway .table-card__name {
  display: flex;
  align-items: center;
  gap: 8px;
  color: var(--brand-strong);
}

.table-card__name {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.table-card__status {
  margin-top: auto;
  font-size: 12.5px;
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   18. HTMX feedback
   -------------------------------------------------------------------------- */
/* A hairline progress bar under the header. Staff need to know the tap landed
   without anything moving on screen. */
#htmx-progress {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0;
  background: var(--brand);
  z-index: 60;
  opacity: 0;
  transition: width 180ms ease, opacity 180ms ease;
}

body.htmx-request #htmx-progress {
  width: 70%;
  opacity: 1;
}

.htmx-indicator { opacity: 0; transition: opacity 120ms ease; }
.htmx-request .htmx-indicator,
.htmx-request.htmx-indicator { opacity: 1; }

[aria-busy="true"] { cursor: progress; }

/* --------------------------------------------------------------------------
   19. Utilities — a deliberately short list
   -------------------------------------------------------------------------- */
.row { display: flex; align-items: center; gap: 8px; }
.row--wrap { flex-wrap: wrap; }
.grow { flex: 1; min-width: 0; }
.right { text-align: right; }
.center { text-align: center; }
.hide { display: none !important; }
.mt-0 { margin-top: 0; }
.mt-1 { margin-top: 8px; }
.mt-2 { margin-top: 16px; }
.mt-3 { margin-top: 24px; }
.mb-1 { margin-bottom: 8px; }
.mb-2 { margin-bottom: 16px; }
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}
[x-cloak] { display: none !important; }

/* --- the orders list, opened out ---------------------------------------- */
/* A tbody per order, so each row and its panel share an Alpine scope. That
   makes every order its own row group, which is also why the borders below are
   set per group rather than relying on tbody tr:last-child. */
.t-nowrap { white-space: nowrap; }

.table--orders .orders__disclose {
  width: 34px;
  padding-right: 0;
  color: var(--ink-4);
}

.orow { cursor: pointer; }
.orow:hover td { background: #fbfaf8; }
.orow:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}
.orow .icon { transition: transform 0.15s ease; display: block; }
.orow.is-open .icon { transform: rotate(90deg); }
.orow.is-open td { background: var(--surface-sunken); }
/* The number stays a link and must not look like part of the row's own
   click target. */
.orow__no { text-decoration: none; }
.orow__no:hover { text-decoration: underline; }

/* A hundred rows with no breaks reads as one block, and the question asked of
   this screen is nearly always about a particular day. */
.daybreak td {
  background: var(--surface-sunken);
  font-size: 12px;
  font-weight: 650;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink-3);
  padding: 7px 12px;
}

.odetail td { background: var(--surface-sunken); padding: 0; }
.odetail:hover td { background: var(--surface-sunken); }
.odetail__wait { padding: 14px 16px; margin: 0; }

.summary {
  display: grid;
  gap: 18px;
  grid-template-columns: minmax(0, 1.4fr) minmax(260px, 1fr);
  padding: 16px;
  border-top: 1px solid var(--line);
}
@media (max-width: 760px) {
  .summary { grid-template-columns: 1fr; }
}

/* Shared by the panel's column headings, so "3 items" and "Paid" carry the
   same weight and the two columns read as a pair. */
.sblock h4,
.sblock__head {
  margin: 0 0 6px;
  font-size: 11px;
  font-weight: 650;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-3);
}

.sline {
  display: grid;
  grid-template-columns: 34px 1fr auto;
  gap: 2px 6px;
  padding: 7px 0;
  border-bottom: 1px solid var(--line);
  font-size: 14px;
}
.sline:last-child { border-bottom: 0; }
.sline--voided { opacity: 0.55; text-decoration: line-through; }
.sline--voided .sline__meta { text-decoration: none; }
.sline__qty { color: var(--ink-3); }
.sline__name { display: flex; flex-direction: column; gap: 1px; }
.sline__total { font-variant-numeric: tabular-nums; }
.sline__meta { font-size: 12px; color: var(--ink-3); }
.sline__note { font-style: italic; }
.sline__override { color: var(--warn); }

.srow { margin: 0 0 12px; font-size: 14px; }
.srow > div { display: flex; justify-content: space-between; gap: 12px; padding: 3px 0; }
.srow dt, .srow dd { margin: 0; }
.srow dd { font-variant-numeric: tabular-nums; }
.srow--credit { color: var(--brand-strong); }
.srow--total {
  border-top: 1px solid var(--line-strong);
  margin-top: 4px;
  padding-top: 6px !important;
  font-weight: 650;
}

.sblock {
  border-top: 1px solid var(--line);
  padding-top: 10px;
  margin-bottom: 12px;
}
.sblock--danger h4 { color: var(--danger); }

.sitem {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  padding: 4px 0;
  font-size: 14px;
}
.sitem > span:first-child { display: flex; flex-direction: column; gap: 1px; }
.sitem .num { font-variant-numeric: tabular-nums; white-space: nowrap; }
.sitem__meta { font-size: 12px; color: var(--ink-3); }
.sblock--danger .sitem .num { color: var(--danger); }
.sitem--kept {
  border-top: 1px solid var(--line);
  margin-top: 4px;
  padding-top: 6px;
  font-weight: 650;
}
.sblock--danger .sitem--kept .num { color: var(--ink); }

.sactions { display: flex; gap: 8px; margin-top: 12px; }
