/* ── Cards ──────────────────────────────────────────────────────────────── */
.card {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  padding: var(--space-4);
  margin-block-end: var(--space-4);
}

.card__title {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-muted);
  margin-block-end: var(--space-3);
}

.stack > * + * { margin-block-start: var(--space-3); }

.muted { color: var(--color-text-muted); }
.small { font-size: var(--text-sm); }

/* ── Buttons · §P5 large targets, strong contrast ───────────────────────── */
.button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding: 0 var(--space-4);
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  background: var(--color-action);
  color: var(--color-action-text);
  font: inherit;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
}

.button:hover { background: var(--color-action-hover); }

.button--secondary {
  background: var(--color-surface);
  color: var(--color-text);
  border-color: var(--color-border-strong);
}

.button--secondary:hover { background: var(--color-surface-sunken); }

.button--quiet {
  background: transparent;
  color: var(--color-link);
  border-color: transparent;
  padding: 0 var(--space-2);
}

.button--danger { background: var(--color-alert); }
.button--block { width: 100%; }
.button--large { min-height: var(--tap-target-lg); font-size: var(--text-lg); }

/* ── Forms ──────────────────────────────────────────────────────────────── */
.field { margin-block-end: var(--space-4); }

.field__label {
  display: block;
  font-weight: 600;
  font-size: var(--text-sm);
  margin-block-end: var(--space-1);
}

.field__hint {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
  margin-block-start: var(--space-1);
}

.field__input,
.field__select {
  width: 100%;
  min-height: var(--tap-target);
  padding: var(--space-2) var(--space-3);
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: 1px solid var(--color-border-strong);
  border-radius: var(--radius-md);
}

/*
 * A number typed at a counter, in a hurry, on a cheap phone: big, monospaced
 * and centred so it can be checked at a glance.
 */
.field__input--pin,
.field__input--big {
  min-height: var(--tap-target-lg);
  font-size: var(--text-2xl);
  font-family: var(--font-mono);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

/*
 * A PIN is the same box, masked. It uses text-security rather than
 * type="password", because a password field on a shared till gets autofilled by
 * the browser's password manager with somebody's website password — which is
 * not a PIN, and fails the numeric pattern in front of a queue of customers.
 *
 * ONLY the PIN is masked. A cash float and a drawer count are not secrets, and
 * a seller who cannot read back what they typed will mis-count the drawer.
 */
.field__input--pin {
  letter-spacing: 0.5em;
  -webkit-text-security: disc;
  text-security: disc;
}

.field--inline {
  display: flex;
  gap: var(--space-2);
  align-items: flex-end;
}

.field--check {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.field--check input { width: 1.25rem; height: 1.25rem; }

.form__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin-block-start: var(--space-5);
}

/* ── Flash and errors ───────────────────────────────────────────────────── */
.flash {
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  margin-block-end: var(--space-4);
  border: 1px solid transparent;
}

.flash--notice { background: var(--color-notice-bg); color: var(--color-notice); border-color: currentColor; }
.flash--alert  { background: var(--color-alert-bg);  color: var(--color-alert);  border-color: currentColor; }

.errors {
  background: var(--color-alert-bg);
  color: var(--color-alert);
  border-radius: var(--radius-md);
  padding: var(--space-3) var(--space-4);
  margin-block-end: var(--space-4);
}

.errors ul { margin: 0; padding-inline-start: var(--space-4); }

/* ── Tables ─────────────────────────────────────────────────────────────── */
.table-scroll { overflow-x: auto; }

.table {
  width: 100%;
  border-collapse: collapse;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius-lg);
  overflow: hidden;
}

.table th,
.table td {
  text-align: start;
  padding: var(--space-3);
  border-block-end: 1px solid var(--color-border);
  vertical-align: top;
}

.table th {
  font-size: var(--text-sm);
  text-transform: uppercase;
  letter-spacing: 0.04em;
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
}

.table tr:last-child td { border-block-end: 0; }

/* ── Badges ─────────────────────────────────────────────────────────────── */
.badge {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  color: var(--color-text-muted);
}

.badge--role { background: var(--color-action); color: var(--color-action-text); }
.badge--inactive { background: var(--color-alert-bg); color: var(--color-alert); }
.badge--open { background: var(--color-warning-bg); color: var(--color-warning); }

/* ── Header rows ────────────────────────────────────────────────────────── */
.page-header {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  justify-content: space-between;
  margin-block-end: var(--space-4);
}

.tile-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.row-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
}

.row-actions form { margin: 0; }

.hours-row {
  display: grid;
  grid-template-columns: 3.5rem 1fr 1fr;
  align-items: center;
  gap: var(--space-2);
  margin-block-start: var(--space-2);
}

.hours-row__day {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
}

.tile {
  background: var(--color-surface-sunken);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}

.gate__aside {
  margin-block-start: var(--space-4);
  text-align: center;
  font-size: var(--text-sm);
  color: var(--color-text-muted);
}

/* ── Catalogue ──────────────────────────────────────────────────────────── */
.toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: flex-end;
  margin-block-end: var(--space-4);
}

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.pill {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-1);
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-2);
  border-radius: var(--radius-sm);
  background: var(--color-surface-sunken);
  white-space: nowrap;
}

.pill--open { background: var(--color-warning-bg); color: var(--color-warning); }
.pill__mark { color: var(--color-action); font-weight: 700; }

/* A currency symbol welded to the left of the box it belongs to, so nobody has
   to wonder whether they are typing shillings or cents. */
.field--prefixed {
  display: flex;
  align-items: stretch;
}

.field__prefix {
  display: flex;
  align-items: center;
  padding: 0 var(--space-3);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-text-muted);
  background: var(--color-surface-sunken);
  border: 1px solid var(--color-border-strong);
  border-inline-end: 0;
  border-start-start-radius: var(--radius-md);
  border-end-start-radius: var(--radius-md);
}

.field--prefixed .field__input {
  border-start-start-radius: 0;
  border-end-start-radius: 0;
}

.definitions { margin: 0; }
.definitions dt { font-family: var(--font-mono); font-size: var(--text-sm); font-weight: 700; }
.definitions dd { margin: 0 0 var(--space-3); font-size: var(--text-sm); color: var(--color-text-muted); }

/*
 * A table with five columns of real content does not fit a phone, and sideways
 * scrolling to read a price list is miserable. Below the breakpoint each row
 * becomes its own card, with the column heading carried in on ::before.
 *
 * Opt in with .table--stacked and give every cell a data-label.
 */
@media (max-width: 48rem) {
  .table--stacked,
  .table--stacked tbody,
  .table--stacked tr,
  .table--stacked td {
    display: block;
    width: 100%;
  }

  .table--stacked thead { display: none; }

  .table--stacked tr {
    border-block-end: 1px solid var(--color-border);
    padding: var(--space-3) 0;
  }

  .table--stacked tr:last-child { border-block-end: 0; }

  .table--stacked td {
    border: 0;
    padding: var(--space-1) var(--space-3);
  }

  .table--stacked td[data-label]::before {
    content: attr(data-label);
    display: block;
    font-size: var(--text-xs);
    text-transform: uppercase;
    letter-spacing: 0.04em;
    color: var(--color-text-muted);
  }

  .table--stacked td:empty { display: none; }
}

/* ── Reports ────────────────────────────────────────────────────────────── */

/* The one number the page exists for. Big enough to read across a counter. */
.headline {
  margin: 0 0 var(--space-3);
  font-size: var(--text-2xl);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/*
 * Two cards that answer the same question of different things — stock about to
 * run out, and money already owed — so they belong beside each other where
 * there is room and stacked where there is not.
 */
.report-pair {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr));
  align-items: start;
}

/* Low is a warning; out is an alert. .variance--off already says "off". */
.variance--low { color: var(--color-warning); font-weight: 700; }

/* ── Connection ─────────────────────────────────────────────────────────── */

/*
 * Sticky, because the seller must not have to scroll to find out that the till
 * is not talking to anything. It sits under the nav and takes no room at all
 * when there is nothing to say.
 */
.connection {
  position: sticky;
  top: 0;
  z-index: 20;
}

.connection__line {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: baseline;
  margin: 0;
  padding: var(--space-2) var(--space-4);
  font-size: var(--text-sm);
}

.connection__line--off {
  background: var(--color-alert-bg);
  color: var(--color-alert);
}

.connection__line--waiting {
  background: var(--color-accent);
  color: var(--color-accent-ink);
}

.connection__line--failed {
  background: var(--color-alert);
  color: var(--color-text-inverse);
}

/*
 * With no connection, the controls that TAKE MONEY are dimmed and refuse the
 * press. Not hidden: a seller who cannot find the pay button assumes the app is
 * broken. Dimmed and unresponsive says "not now", which is the truth.
 */
.is-offline .till-bar__pay,
.is-offline .button--large {
  opacity: 0.45;
  pointer-events: none;
}

/* A form waiting on a retry says so where the seller is already looking. */
.is-sending { opacity: 0.6; }

/* ── The light switch ─────────────────────────────────────────────────────── */

/*
 * Day, auto or night, as a wooden lever in a slot.
 *
 * Three positions rather than two, because a two-way switch would have to drop
 * "auto" — and auto is the default, so a phone already set to dark opens the
 * shop dark without anybody being asked.
 *
 * The plate is the same board the cards are, so the colours on it are the ones
 * already measured against that wood: the unselected positions take
 * --color-on-plaque-muted and the selected one --color-on-plaque. The knob is
 * DARKER than the plate rather than proud of it — the chosen position reads as
 * pushed in, and light lettering keeps working on it because it is darker than
 * the surface those two colours were measured against.
 */
.lightswitch {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

/* The fieldset is a grouping element and nothing else; the slot does the layout. */
.lightswitch__group {
  min-width: 0;
}

/*
 * `max-content` with three equal tracks: the slot is exactly as wide as three of
 * its widest word, so it fits its content instead of being padded out to an
 * invented minimum — and the tracks stay equal, which is what lets the knob be
 * a third of the slot and slide by whole steps.
 */
.lightswitch__slot {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  align-content: stretch;
  width: max-content;
  min-height: var(--tap-target);
  padding: 4px;
  border: 1px solid var(--plaque-edge-dark);
  border-radius: var(--radius-md);
  background:
    linear-gradient(var(--plaque-veil), var(--plaque-veil)),
    var(--plaque-image) center / cover no-repeat;
  box-shadow: inset 0 1px 0 var(--plaque-edge-lit), var(--shadow-card);
}

.lightswitch__knob {
  position: absolute;
  inset-block: 4px;
  inset-inline-start: 4px;
  width: calc((100% - 8px) / 3);
  border-radius: calc(var(--radius-md) - 2px);
  background: var(--switch-socket);
  box-shadow:
    inset 0 2px 3px rgb(0 0 0 / 55%),
    inset 0 -1px 0 var(--plaque-edge-lit);
}

/* The knob follows the checked position rather than being told where to go by
   JavaScript, so it is right on first paint and with the controller asleep. */
.lightswitch__slot:has(input[value="system"]:checked) .lightswitch__knob {
  translate: 100% 0;
}

.lightswitch__slot:has(input[value="night"]:checked) .lightswitch__knob {
  translate: 200% 0;
}

.lightswitch__detent {
  position: relative;
  display: grid;
  place-items: center;
  padding-inline: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-on-plaque-muted);
  white-space: nowrap;
  cursor: pointer;
}

/* The radio covers its whole detent, so the target is the wood and not the
   word. Opacity rather than display, so it still takes focus. */
.lightswitch__detent input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.lightswitch__detent:has(input:checked) {
  color: var(--color-on-plaque);
  font-weight: 600;
}

.lightswitch__detent:has(input:focus-visible) {
  outline: 3px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

@media (prefers-reduced-motion: no-preference) {
  .lightswitch__knob { transition: translate 140ms ease-out; }
}

/* A photograph behind a control is the first thing to go for somebody who has
   asked for more contrast. */
@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .lightswitch__slot { background: var(--color-surface-sunken); }
  .lightswitch__detent { color: var(--color-text-muted); }
  .lightswitch__detent:has(input:checked) { color: var(--color-text); }
  .lightswitch__knob { background: var(--color-surface); }
}

/* ── The basket ───────────────────────────────────────────────────────────── */

/*
 * The shop's own basket on a board, rather than the word "Basket" in a box.
 *
 * Same board as the cards and the light switch, so it belongs to the same shop —
 * and it is darker than the wall behind it, which is what stops a wooden button
 * on a wooden topbar from disappearing.
 *
 * It grows when there is something in it: empty it is a square with a basket on
 * it, and filling it puts the count alongside. Nothing moves position, so the
 * one thing that changes on the page is the thing that changed.
 */
.basket {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--tap-target);
  padding-inline: var(--space-3);
  border: 1px solid var(--plaque-edge-dark);
  border-radius: var(--radius-md);
  background:
    linear-gradient(var(--plaque-veil), var(--plaque-veil)),
    var(--plaque-image) center / cover no-repeat;
  box-shadow: inset 0 1px 0 var(--plaque-edge-lit), var(--shadow-card);
  text-decoration: none;
}

.basket:hover {
  border-color: var(--plaque-edge-lit);
}

/*
 * A chip, not bare figures on the wood: --color-accent measures 4.05:1 as text
 * on the day board and fails. On the chip it is --color-accent-ink at 8.62:1,
 * which palette_spec already checks. The accent is the right colour either way —
 * tokens.css calls it "something the shop should look at now".
 */
.basket__count {
  display: grid;
  place-items: center;
  min-width: 1.5rem;
  padding: 0 var(--space-1);
  border-radius: 999px;
  background: var(--color-accent);
  color: var(--color-accent-ink);
  font-size: var(--text-sm);
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  line-height: 1.5;
}

@media (prefers-contrast: more), (prefers-reduced-transparency: reduce) {
  .basket { background: var(--color-surface-sunken); }
}
