/*
 * Oxytane — station collection.
 *
 * ## What this is designed against
 *
 * A cheap Android phone, held in one hand, outdoors, in Lagos sun, by somebody who is
 * mid-conversation with a customer. That is the whole brief and it settles most of the
 * decisions below:
 *
 *   - White ground, ink text, nothing subtle. Sunlight eats low contrast first.
 *   - Type starts at 17px and the things that get read aloud are far bigger.
 *   - Every control is at least 56px tall — the app's own floor is 44pt
 *     (mobile-v2/src/theme/metrics.ts) and a forecourt is not a quiet room.
 *   - System fonts only. A webfont is another request that can hang on 2G, and the one
 *     glyph this project fought for (₦) never appears here: the attendant is handed no
 *     prices.
 *
 * Deliberately a single light appearance. This is a daylight tool; a dark variant would
 * be an untested second design nobody asked for.
 *
 * ## The palette
 *
 * Copied by value from mobile-v2/src/theme/colors.ts (ink, inkDeep, teal, tealInk,
 * tealDeep, paper, paperDeep, surface, mute, line, good, badInk). Copied rather than
 * imported on purpose: this page has no build step and no access to the app's module
 * graph, and a second source of truth is honest about that as long as it says where it
 * came from.
 *
 * The two teal rules come across with the values, because they are arithmetic:
 *   - `teal` is 2.73:1 on white, so it never carries meaning on a light surface here.
 *     It appears only on `ink`, where it is 6.32:1.
 *   - Where an accent must be read on white, it is `tealInk` (4.50:1).
 *   - Filled controls are a white label on `tealInk`. Never ink on teal.
 */

:root {
  --ink: #111c27;
  --ink-deep: #0a121a;
  --ink-soft: #1e2c3b;

  --teal: #1dafa1;
  --teal-ink: #12857a;
  --teal-deep: #0e6b62;

  --paper: #f4f7f8;
  --paper-deep: #e7edf1;
  --surface: #ffffff;

  --mute: #4a5a6a;
  --line: #d5dee7;

  --good: #1eb857;
  --bad-ink: #d22e2e;

  --on-ink: #ffffff;
  --on-ink-muted: rgba(255, 255, 255, 0.75);

  /* 56px clears the app's absolute 44pt floor with room for a wet thumb. */
  --target: 56px;
  --gutter: 20px;
  --radius: 14px;

  color-scheme: light;
}

* {
  box-sizing: border-box;
}

html {
  /* No zoom-out on a small screen, and no rubber-banding past the ground colour. */
  -webkit-text-size-adjust: 100%;
  background: var(--surface);
}

body {
  margin: 0;
  padding: 0 var(--gutter) 40px;
  background: var(--surface);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue",
    Arial, sans-serif;
  font-size: 17px;
  line-height: 1.45;
  /* A shared device gets long-pressed by accident constantly. */
  -webkit-tap-highlight-color: transparent;
}

main {
  max-width: 520px;
  margin: 0 auto;
}

/* --- the bar ------------------------------------------------------------ */

.bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 520px;
  margin: 0 auto;
  padding: 14px 0 18px;
  border-bottom: 1px solid var(--line);
}

.wordmark {
  font-size: 15px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink);
}

.bar-action {
  min-height: 44px;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--mute);
  font: inherit;
  font-size: 15px;
  font-weight: 600;
  cursor: pointer;
}

.bar-action:active {
  color: var(--ink);
}

/* --- which counter ------------------------------------------------------
 *
 * Standing on the page rather than inside a view, because it is a fact about the device
 * and the shift rather than about the customer at the counter. */

.counter {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  max-width: 520px;
  margin: 0 auto;
  padding: 12px 0;
  border-bottom: 1px solid var(--line);
  font-size: 15px;
  font-weight: 600;
  color: var(--mute);
}

.counter[hidden] {
  display: none;
}

.counter-change {
  flex: none;
  min-height: 44px;
  padding: 0 4px;
  border: 0;
  background: none;
  color: var(--teal-ink);
  font: inherit;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
}

.counter-change[hidden] {
  display: none;
}

.btn-station {
  text-align: left;
  text-transform: none;
  letter-spacing: 0;
  font-size: 19px;
}

/* --- views -------------------------------------------------------------- */

.view {
  padding-top: 28px;
}

.view[hidden] {
  display: none;
}

.title {
  margin: 0 0 8px;
  font-size: 30px;
  line-height: 1.15;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.eyebrow {
  margin: 0 0 6px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--mute);
}

.lede {
  margin: 0 0 24px;
  font-size: 18px;
  color: var(--mute);
}

/* Several of these are written into and emptied again — "Checking…", "Sent to …". An
   emptied one must take no room, or the screen shifts under a thumb. */
.lede:empty {
  display: none;
}

/* --- fields ------------------------------------------------------------- */

.label {
  display: block;
  margin: 20px 0 8px;
  font-size: 13px;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--mute);
}

.field {
  width: 100%;
  min-height: var(--target);
  padding: 0 14px;
  border: 2px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  font-size: 22px;
  font-weight: 600;
}

.field:focus {
  outline: none;
  border-color: var(--teal-ink);
  /* Not hue alone: the ring thickens as well as changes colour. */
  box-shadow: 0 0 0 3px rgba(18, 133, 122, 0.22);
}

.field::placeholder {
  color: #93a3b2;
  font-weight: 500;
}

.field-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
}

.field-prefix {
  display: flex;
  align-items: center;
  padding: 0 14px;
  border-radius: var(--radius);
  background: var(--paper);
  color: var(--mute);
  font-size: 20px;
  font-weight: 700;
}

.field-grow {
  flex: 1;
  min-width: 0;
}

.field-otp {
  font-size: 32px;
  letter-spacing: 0.32em;
  text-align: center;
}

/* --- the pickup code field ---------------------------------------------- */

.code-row {
  display: flex;
  align-items: stretch;
  gap: 10px;
}

.code-prefix {
  display: flex;
  align-items: center;
  padding: 0 16px;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--on-ink);
  font-size: 30px;
  font-weight: 700;
  /* The code is spoken, so it is set the way it is read: wide, one glyph at a time. */
  letter-spacing: 0.06em;
}

.code-input {
  flex: 1;
  min-width: 0;
  min-height: 68px;
  padding: 0 6px;
  font-size: 36px;
  font-weight: 700;
  letter-spacing: 0.22em;
  /* Letter-spacing is added *after* the last glyph too, so a centred line sits half a
     space left of true centre and the fourth character clips on a narrow phone. The
     indent puts it back. */
  text-indent: 0.22em;
  text-align: center;
  text-transform: uppercase;
}

/* 320–360 pt phones are ordinary here, and four tracked characters plus the `OXY-` slab
   is the widest row on the page. It steps down rather than clipping the last glyph. */
@media (max-width: 380px) {
  .code-prefix {
    padding: 0 10px;
    font-size: 26px;
  }

  .code-input {
    min-height: 62px;
    font-size: 30px;
    letter-spacing: 0.16em;
    text-indent: 0.16em;
  }

  .field-digits {
    min-height: 62px;
    font-size: 34px;
    letter-spacing: 0.2em;
    text-indent: 0.2em;
  }
}

/* --- buttons ------------------------------------------------------------ */

.btn {
  display: block;
  width: 100%;
  min-height: var(--target);
  margin-top: 18px;
  padding: 14px 18px;
  border: 0;
  border-radius: var(--radius);
  font: inherit;
  font-size: 17px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}

.btn-primary {
  background: var(--teal-ink);
  color: var(--on-ink);
}

.btn-primary:active {
  background: var(--teal-deep);
}

.btn-primary:disabled {
  background: var(--paper-deep);
  color: var(--mute);
  cursor: default;
}

.btn-quiet {
  background: var(--surface);
  border: 2px solid var(--line);
  color: var(--ink);
}

.btn-quiet:active {
  background: var(--paper);
}

/* A control that sits inside a row rather than under a screen: sized to its words, cased
   like them, and still 48px tall — above the app's 44pt floor, below the 56px a screen's
   one big control gets, because a row full of them would otherwise be a wall. */
.btn-slim {
  display: inline-block;
  width: auto;
  min-height: 48px;
  margin-top: 0;
  padding: 12px 18px;
  font-size: 16px;
  letter-spacing: 0;
  text-transform: none;
}

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

.btn-row .btn {
  flex: 1;
  font-size: 15px;
}

.btn:focus-visible {
  outline: 3px solid var(--teal-ink);
  outline-offset: 3px;
}

/* `.btn` sets `display: block`, which outranks the user agent's `[hidden] { display: none }`
   — so a button hidden from script stays on screen unless this says otherwise. The same
   line exists on every other class here that sets a display. */
.btn[hidden] {
  display: none;
}

/* --- notes and problems -------------------------------------------------- */

.note {
  min-height: 22px;
  margin: 10px 2px 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--bad-ink);
}

.note:empty {
  min-height: 0;
}

.problem {
  margin-top: 24px;
  padding: 18px;
  border-radius: var(--radius);
  background: var(--paper);
  /* State is never hue alone: the rule on the leading edge is the same weight whatever
     the problem is, and the words carry the difference. */
  border-left: 6px solid var(--ink);
}

.problem[hidden] {
  display: none;
}

.problem-title {
  margin: 0 0 6px;
  font-size: 20px;
  font-weight: 700;
}

.problem-action {
  margin: 0;
  font-size: 17px;
  color: var(--mute);
}

.problem .btn {
  margin-top: 16px;
}

/* --- the order ----------------------------------------------------------- */

.items {
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--line);
}

.item {
  padding: 14px 2px;
  border-bottom: 1px solid var(--line);
}

/* The row proper. It wraps rather than squeezing: on a 320px phone a long size label and
   a verdict beside it do not both fit, and a clipped verdict is worse than a second line. */
.item-line {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 14px;
}

.item-qty {
  min-width: 62px;
  font-size: 30px;
  font-weight: 700;
  letter-spacing: -0.01em;
}

.item-label {
  flex: 1;
  min-width: 0;
  font-size: 22px;
  font-weight: 600;
}

/* --- this counter's verdict, beside the shelf ----------------------------
 *
 * Deliberately the quietest thing in the row. The attendant is looking at the shelf; this
 * is the ledger's opinion of it, and where the two disagree the shelf wins. So it is set
 * at note size in `mute`, never as a coloured pill and never larger than the size label
 * it sits beside.
 *
 * **The three verdicts are three different words, not three colours.** "Not counted" has
 * to be unmistakable for both of the others — a grey chip that could be read as either
 * would be exactly the fabricated state this project forbids — so the word carries it and
 * only `out` takes any extra weight, because it is the one an attendant should notice
 * without being alarmed by. */

.item-stock {
  margin-left: auto;
  font-size: 15px;
  font-weight: 600;
  color: var(--mute);
  text-align: right;
}

.item-stock-out {
  color: var(--ink);
  font-weight: 700;
}

/* Empty until `availability` answers, and it must take no room while it is. */
.item-action {
  margin-top: 4px;
}

.item-action:empty {
  display: none;
}

/* One per row, so it cannot be a bordered box: three of those stacked bury the hand-over
   list, which is the thing the attendant actually came to this screen to read. It is the
   same borderless text control the bar and the counter line already use — `tealInk` at
   4.50:1, the only colour on this page that carries meaning on white — and it is still
   48px tall, because it is tapped outdoors with one thumb. */
.item-short {
  display: inline-block;
  width: auto;
  min-height: 48px;
  padding: 0 2px;
  border: 0;
  background: none;
  color: var(--teal-ink);
  font: inherit;
  font-size: 16px;
  font-weight: 700;
  text-align: left;
  cursor: pointer;
}

.item-short:active {
  color: var(--teal-deep);
}

.item-short:disabled {
  color: var(--mute);
  cursor: default;
}

.item-short:focus-visible {
  outline: 3px solid var(--teal-ink);
  outline-offset: 2px;
}

.item-state {
  margin: 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--ink);
}

/* --- the stock read failing ---------------------------------------------- */

.stock-note {
  margin: 14px 2px 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--mute);
}

.stock-note:empty {
  display: none;
}

.stock-retry {
  margin-top: 10px;
}

/* --- an empty shelf, and where to send them ------------------------------
 *
 * The same paper panel and the same weight of rule as `.problem`, because it is read the
 * same way and half of what it says is a failure. What is inside it changes; the shape
 * does not. */

.shortfalls {
  margin-top: 24px;
}

.shortfalls:empty {
  display: none;
}

.fall {
  margin-top: 16px;
  padding: 18px;
  border-radius: var(--radius);
  background: var(--paper);
  border-left: 6px solid var(--ink);
}

.fall-head {
  margin: 0 0 8px;
  font-size: 20px;
  font-weight: 700;
}

/* The write did not land, or was never confirmed. Never the same line as the redirect. */
.fall-state {
  margin: 0 0 10px;
  font-size: 17px;
  font-weight: 700;
  color: var(--bad-ink);
}

.fall-lede {
  margin: 0;
  font-size: 17px;
  font-weight: 600;
  color: var(--mute);
}

.fall-list {
  margin: 10px 0 0;
  padding: 0;
  list-style: none;
}

/* Read aloud across a forecourt, so the name is set at the size of something spoken. */
.fall-counter {
  padding: 14px 0 4px;
  border-top: 1px solid var(--line);
}

.fall-name {
  margin: 0;
  font-size: 20px;
  font-weight: 700;
}

.fall-address {
  margin: 4px 0 0;
  font-size: 17px;
  color: var(--ink-soft);
}

.fall-meta {
  margin: 6px 0 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--mute);
}

.fall .btn {
  margin-top: 16px;
}

.fall-waitlist:empty {
  display: none;
}

/* --- on the list ----------------------------------------------------------
 *
 * Two audiences, one block. `.wait-state` is the attendant's confirmation — short, and the
 * thing they glance at to know the customer is listed rather than hoping. `.wait-say` is
 * the sentence they read out to the customer, so it is set at the size of something spoken
 * across a forecourt rather than the size of a caption.
 *
 * Neither is teal: `#1DAFA1` is 2.73:1 on this paper and never carries meaning. A failure
 * in this block uses `.fall-state` above, which is the same red the rest of the panel
 * already fails in. */

/* A failure inside this block follows the panel's own red line, and needs the space above
   it that a first line in the panel does not. */
.fall-waitlist .fall-state {
  margin-top: 14px;
}

.wait-state {
  margin: 14px 0 0;
  font-size: 18px;
  font-weight: 700;
  color: var(--ink);
}

.wait-say {
  margin: 6px 0 0;
  font-size: 20px;
  line-height: 1.35;
  color: var(--ink);
}

/* --- the check ------------------------------------------------------------
 *
 * The four digits the customer speaks are typed here and compared in Postgres; this page
 * is never told what the right answer is. So the panel is a question, not a display —
 * which is why it is the darkest surface on the screen and the only place the attendant's
 * attention is asked to stop. */

.check {
  margin-top: 28px;
  padding: 20px;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--on-ink);
}

.check-ask {
  display: block;
  margin: 0 0 14px;
  font-size: 18px;
  font-weight: 600;
  color: var(--on-ink-muted);
}

.field-digits {
  min-height: 68px;
  padding: 0 6px;
  border-color: rgba(255, 255, 255, 0.32);
  background: var(--ink-deep);
  color: var(--on-ink);
  font-size: 40px;
  font-weight: 700;
  letter-spacing: 0.28em;
  /* See the note on .code-input: cancel the trailing letter-space so four glyphs sit at
     true centre instead of half a space to the left. */
  text-indent: 0.28em;
  text-align: center;
}

.field-digits::placeholder {
  color: rgba(255, 255, 255, 0.28);
  font-weight: 700;
}

.field-digits:focus {
  border-color: var(--teal);
  box-shadow: 0 0 0 3px rgba(29, 175, 161, 0.3);
}

/* On the ink panel, where badInk would be 2.1:1. */
.note-on-ink {
  color: #ff9d9d;
}

.expiry {
  min-height: 22px;
  margin: 18px 2px 0;
  font-size: 16px;
  font-weight: 700;
  color: var(--bad-ink);
}

.expiry:empty {
  min-height: 0;
  margin-top: 0;
}

.final {
  margin: 20px 0 0;
  font-size: 15px;
  font-weight: 600;
  color: var(--mute);
}

/* --- support ------------------------------------------------------------- */

.support {
  max-width: 520px;
  margin: 32px auto 0;
  padding-top: 18px;
  border-top: 1px solid var(--line);
  font-size: 15px;
  color: var(--mute);
  text-align: center;
}

.support[hidden] {
  display: none;
}

.support a {
  color: var(--teal-ink);
  font-weight: 700;
}

/* --- motion -------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  * {
    animation: none !important;
    transition: none !important;
  }
}
