/*
 * Beautystores UK — Groupon redemption page.
 *
 * Design direction: the page IS a voucher, so it is drawn as one. A single
 * ticket sits at the centre of the layout — a dark navy stub on top, a
 * perforated tear line with punched notches, and the form below it. The stub
 * starts blank and gets "stamped" with the deal name once the code checks out,
 * which is the moment a wary customer learns they are in the right place.
 *
 * Palette is the Beautystores identity, sampled from the artwork: brand navy
 * #0B1227, white, and brand red #DA0D0D. The identity uses red as punctuation
 * — two small dots, in the A of BEAUTY and the E of STORES — and nothing else.
 * This page honours that literally:
 *
 *   The chrome has no hue at all. Buttons, links, focus rings, checked radios
 *   and active chips are all navy, and affordance is carried by fill, weight,
 *   underline and the focus ring rather than by colour. That leaves every hue
 *   on the page free to mean a state, and nothing else.
 *
 *   Red therefore has exactly one meaning here — something failed — and it is
 *   the brand's own #DA0D0D, so there is one red in the system rather than a
 *   brand red and an error red a worried customer would have to tell apart.
 *   The only other red on the page is the two dots inside the wordmark, at
 *   letterform scale, which is what the identity itself does with it.
 *
 * Green is done, amber is held, graphite is waiting. None of the three carry
 * their meaning on colour alone: see the chip silhouettes near the end of this
 * file, which differ in shape and glyph and survive `filter: grayscale(1)`.
 *
 * Type is a Palatino-class serif for the retailer's voice, the system UI stack
 * for the form (legibility beats personality inside an input), and a monospace
 * stack for the two pieces of real data on the page: the voucher code and the
 * order number. No webfonts: the page has zero runtime dependencies and must
 * render the same on a phone with a poor connection.
 *
 * Mobile is the design, not the fallback. Everything below 560px is the target;
 * the desktop rules at the end only stop the ticket getting wider than it reads.
 */

/* ── Tokens ─────────────────────────────────────────────────────────────── */
:root {
  /* Ground and ink — navy at low saturation, so the porcelain is the brand's
     own hue rather than a neutral grey borrowed from somewhere else. */
  --ground:      #F1F3F8;
  --surface:     #ffffff;
  --field:       #FCFDFF;
  --sunk:        #E4E8F0;   /* inert surfaces: a disabled button */

  --ink:         #0B1227;   /* BRAND NAVY, sampled exact */
  --ink-deep:    #060A16;   /* the far end of the stub gradient */
  --ink-lift:    #1C2747;   /* the near end of it */
  --ink-mid:     #3B4459;   /* running text that is not the headline */
  --ink-soft:    #5C657B;   /* labels, hints, captions */
  --hush:        #6A7386;   /* settled rows: the quietest text that still reads */

  /* Chrome. Deliberately hueless: navy is the interactive colour, so no hue on
     this page can be mistaken for a state. --accent is the surface, --accent-deep
     the press. */
  --accent:      #17244E;
  --accent-deep: #0B1227;
  --accent-wash: #E8ECF6;
  --line:        #DEE3ED;
  --line-strong: #C2CAD9;

  /* Text and rules that sit on the navy stub. */
  --on-dark-soft:  #C6CFE3;
  --on-dark-quiet: #9FAAC4;

  /* States. Each has a fill, an ink for text on that fill, and a hairline. */
  --ok:          #14614A;
  --ok-ink:      #0F4A39;
  --ok-wash:     #E6F2ED;
  --ok-line:     #BFDCD0;

  --warn:        #8A5209;
  --warn-ink:    #5F3A06;
  --warn-wash:   #FCF1DE;
  --warn-line:   #EDD7AD;

  /* Failure, and the only red on the page besides the two dots in the wordmark. */
  --danger:      #DA0D0D;   /* BRAND RED, sampled exact — 5.19:1 on white */
  --danger-ink:  #9E0808;   /* the same red, darkened for text on --danger-wash */
  --danger-wash: #FDECEC;
  --danger-line: #F2BEBE;
  --danger-tint: #FFF6F6;   /* the faintest wash, for rows that need a person */
  --danger-pale: #FFEDED;   /* text on a solid --danger fill */

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --ui: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, "Liberation Mono", monospace;

  --radius: 14px;
  --tap: 52px;              /* every control clears the 44px minimum */
  --pad: 20px;
  --shadow: 0 1px 2px rgba(11, 18, 39, .07), 0 12px 28px -14px rgba(11, 18, 39, .30);
}

/* ── Reset ──────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

/* Several components below set `display` on a class (.btn is block, .help-mail
   is flex). An author rule beats the UA stylesheet's [hidden] at equal
   specificity, so without this the `hidden` property is set and the element
   still renders — which is how the no-answer branch was still showing the
   submit button it had just told the customer not to press. */
[hidden] { display: none !important; }

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

body {
  margin: 0;
  padding: 0 16px calc(32px + env(safe-area-inset-bottom));
  background: var(--ground);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 16px;
  line-height: 1.5;
  overflow-wrap: break-word;
  /* A hairline of brand colour across the very top of every screen. */
  border-top: 4px solid var(--accent);
}

h1, h2, p, ul, fieldset, figure { margin: 0; }
ul { padding: 0; list-style: none; }
fieldset { border: 0; padding: 0; min-width: 0; }
legend { padding: 0; }

a { color: var(--accent); }
a:hover { color: var(--accent-deep); }

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

.skip-link {
  position: absolute;
  left: -9999px;
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 16px;
  background: var(--ink);
  color: #fff;
  border-radius: 8px;
  text-decoration: none;
}
.skip-link:focus {
  left: 16px;
  top: 12px;
  z-index: 10;
}

/* ── Header ─────────────────────────────────────────────────────────────────
 * The Beautystores mark is a single-line wordmark at 9.45:1, so its height is
 * decided by the width it is given, not the other way round. On a phone it
 * takes the whole content column (≈343px at a 375px viewport, so ≈36px tall);
 * from 640px up there is room for the full 416px lockup beside the label, which
 * puts it at 44px and clears the house minimum. Below that the aspect ratio
 * makes 44px impossible — 44px tall is 416px wide — so the mark instead takes
 * the full width of the screen, which is the larger presence of the two.
 * ─────────────────────────────────────────────────────────────────────────── */
.site-head {
  max-width: 560px;
  margin: 0 auto;
  padding: 18px 0 20px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 12px;
}

.brand {
  display: flex;
  align-items: center;
  width: 100%;
  min-height: 44px;          /* the mark is 36px tall on a phone; the link is not */
  text-decoration: none;
  color: inherit;
}

.brand-logo {
  display: block;
  width: 100%;
  max-width: 416px;
  height: auto;
}

.head-note {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
  line-height: 1.4;
}

@media (min-width: 640px) {
  .site-head {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
  }
  .brand { width: auto; }
  .brand-logo { width: 416px; }   /* 44.0px tall */
  .head-note { text-align: right; }
}

/* ── The ticket ─────────────────────────────────────────────────────────── */
main { max-width: 560px; margin: 0 auto; }

.ticket {
  background: var(--surface);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.stub {
  background: var(--ink);
  background-image: radial-gradient(120% 130% at 12% 0%, var(--ink-lift) 0%, var(--ink-deep) 72%);
  color: #fff;
  border-radius: var(--radius) var(--radius) 0 0;
  padding: 24px var(--pad) 22px;
}

.eyebrow {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .24em;
  text-transform: uppercase;
  color: var(--on-dark-soft);
}

.stub-title {
  margin-top: 8px;
  text-wrap: balance;
  font-family: var(--serif);
  font-size: 30px;
  line-height: 1.12;
  font-weight: 400;
  letter-spacing: -.01em;
}

.stub-sub {
  margin-top: 10px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--on-dark-soft);
  max-width: 34em;
}

/* The proof panel — the "stamp". */
.proof {
  margin-top: 18px;
  padding: 14px 16px;
  background: rgba(255, 255, 255, .07);
  border: 1px solid rgba(255, 255, 255, .30);
  border-radius: 10px;
  animation: stamp .32s cubic-bezier(.2, .9, .3, 1) both;
}

@keyframes stamp {
  from { opacity: 0; transform: scale(.97); }
  to   { opacity: 1; transform: none; }
}

.proof-label {
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--on-dark-soft);
}

.proof-deal {
  margin-top: 5px;
  font-family: var(--serif);
  font-size: 19px;
  line-height: 1.25;
}

.proof-code {
  margin-top: 6px;
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .09em;
  color: var(--on-dark-quiet);
}

/* The tear line. Two punched notches, cut in the page colour. */
.perf {
  position: relative;
  height: 22px;
  background: linear-gradient(var(--ink-deep) 0 50%, var(--surface) 50% 100%);
}

.perf::before,
.perf::after {
  content: "";
  position: absolute;
  top: 0;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: var(--ground);
}
.perf::before { left: -11px; }
.perf::after  { right: -11px; }

.ticket-body {
  padding: 22px var(--pad) 26px;
  border-radius: 0 0 var(--radius) var(--radius);
}

/* ── Steps ──────────────────────────────────────────────────────────────── */
.step-mark {
  font-size: 10.5px;
  font-weight: 600;
  letter-spacing: .17em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 16px;
  padding-bottom: 12px;
  border-bottom: 1px solid var(--line);
}
.step-mark span { color: var(--accent); font-weight: 700; }

/* ── Fields ─────────────────────────────────────────────────────────────── */
.field { margin-bottom: 16px; }
.field:last-child { margin-bottom: 0; }

.label {
  display: block;
  margin-bottom: 6px;
  font-size: 13.5px;
  font-weight: 600;
  letter-spacing: .005em;
}

.optional {
  font-weight: 400;
  font-size: 12px;
  color: var(--ink-soft);
  letter-spacing: .04em;
}

.input {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: 13px 14px;
  font-family: inherit;
  font-size: 16px;          /* 16px keeps iOS from zooming on focus */
  line-height: 1.35;
  color: var(--ink);
  background: var(--field);
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  transition: border-color .15s, box-shadow .15s, background-color .15s;
}

.input::placeholder { color: var(--hush); }

.input:hover { border-color: var(--line-strong); }

.input:focus {
  background: #fff;
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-wash);
  outline: none;
}

.input:focus-visible { outline: none; }

.input[aria-invalid="true"] {
  border-color: var(--danger);
  background: var(--danger-wash);
}

/* A select is a field: same box, same 52px tap dimension. The desk uses two —
   the option a batch is generated for, and the deal an export sends. */
select.input {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 42px;
}
select.input:disabled { background: var(--sunk); color: var(--ink-soft); }
select.input optgroup { font-weight: 700; }

.input-code {
  font-family: var(--mono);
  font-size: 19px;
  letter-spacing: .13em;
  text-transform: uppercase;
  min-height: 58px;
  text-align: center;
  padding-left: 8px;
  padding-right: 8px;
}
.input-code::placeholder { letter-spacing: .1em; font-size: 15px; text-transform: none; }

.input-postcode {
  text-transform: uppercase;
  font-family: var(--mono);
  letter-spacing: .06em;
}

.select {
  appearance: none;
  -webkit-appearance: none;
  padding-right: 42px;
  background-image:
    linear-gradient(45deg, transparent 50%, var(--ink) 50%),
    linear-gradient(135deg, var(--ink) 50%, transparent 50%);
  background-position: calc(100% - 21px) calc(50% + 1px), calc(100% - 15px) calc(50% + 1px);
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
}

.hint {
  margin-top: 6px;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-soft);
}

.hint-code {
  font-family: var(--mono);
  font-size: 12px;
  letter-spacing: .04em;
  color: var(--ink);
  background: var(--ground);
  padding: 2px 5px;
  border-radius: 4px;
  white-space: nowrap;
}

.hint-country {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px dashed var(--line);
}

.row { display: grid; gap: 0; }

/* ── Groups ─────────────────────────────────────────────────────────────── */
.group {
  margin-bottom: 22px;
  padding-top: 4px;
}
.group:last-of-type { margin-bottom: 20px; }

.legend {
  font-family: var(--serif);
  font-size: 18px;
  margin-bottom: 4px;
}

.group-note {
  margin-bottom: 14px;
  font-size: 12.5px;
  color: var(--ink-soft);
}

/* Item summary shown when the voucher offers exactly one option. */
.chosen {
  display: flex;
  align-items: baseline;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: 10px;
  padding: 14px 16px;
  background: var(--ok-wash);
  border: 1px solid var(--ok-line);
  border-radius: 10px;
}
.chosen-name { font-weight: 600; }
.chosen-qty { font-size: 12.5px; color: var(--ok); }

/* Radio cards, shown when the voucher offers a choice. */
.choices { margin-top: 10px; display: grid; gap: 10px; }

.choice {
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: var(--tap);
  padding: 13px 15px;
  background: var(--field);
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  cursor: pointer;
}

.choice:hover { border-color: var(--line-strong); }

.choice input {
  appearance: none;
  -webkit-appearance: none;
  flex: none;
  width: 22px;
  height: 22px;
  margin: 0;
  border: 2px solid var(--line-strong);
  border-radius: 50%;
  background: #fff;
  cursor: pointer;
}

.choice input:checked {
  border-color: var(--accent);
  border-width: 6px;
}

.choice:has(input:checked) {
  border-color: var(--accent);
  background: var(--accent-wash);
}

.choice-text { display: block; }
.choice-name { display: block; font-weight: 600; font-size: 15px; }
.choice-qty { display: block; font-size: 12.5px; color: var(--ink-soft); margin-top: 2px; }

/* ── Buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: block;
  width: 100%;
  min-height: var(--tap);
  padding: 15px 20px;
  font-family: inherit;
  font-size: 16px;
  font-weight: 600;
  letter-spacing: .01em;
  border: 1px solid transparent;
  border-radius: 10px;
  cursor: pointer;
  transition: background-color .15s, color .15s, border-color .15s;
}

.btn-primary {
  margin-top: 18px;
  background: var(--accent);
  color: #fff;
  box-shadow: 0 8px 18px -10px rgba(11, 18, 39, .38);
}
.btn-primary:hover { background: var(--accent-deep); }
.btn-primary:disabled {
  background: var(--sunk);
  color: var(--ink-soft);
  box-shadow: none;
  cursor: progress;
}

.btn-quiet {
  margin-top: 10px;
  background: transparent;
  color: var(--ink-soft);
  border-color: var(--line);
  font-weight: 500;
  font-size: 14.5px;
}
.btn-quiet:hover { color: var(--ink); border-color: var(--line-strong); }

/* ── Errors ─────────────────────────────────────────────────────────────── */
.error {
  margin-top: 16px;
  padding: 13px 15px;
  background: var(--danger-wash);
  border: 1px solid var(--danger-line);
  border-radius: 10px;
  color: var(--danger-ink);
  font-size: 14px;
  line-height: 1.5;
}
.error a { color: var(--danger-ink); }

/* ── Done ───────────────────────────────────────────────────────────────── */
.done-tick {
  width: 46px;
  height: 46px;
  display: grid;
  place-items: center;
  background: var(--ok-wash);
  color: var(--ok);
  border-radius: 50%;
  font-size: 24px;
  line-height: 1;
}

.done-title {
  margin-top: 14px;
  text-wrap: balance;
  font-family: var(--serif);
  font-size: 26px;
  font-weight: 400;
  line-height: 1.2;
}

.done-order {
  margin-top: 14px;
  padding: 13px 15px;
  background: var(--ground);
  border-radius: 10px;
  font-size: 14px;
  color: var(--ink-soft);
}
.done-order strong {
  display: block;
  margin-top: 3px;
  font-family: var(--mono);
  font-size: 18px;
  letter-spacing: .08em;
  color: var(--ink);
}

.done-note { margin-top: 14px; font-size: 15px; color: var(--ink-mid); }

.notice {
  margin-top: 16px;
  padding: 14px 16px;
  background: var(--warn-wash);
  border: 1px solid var(--warn-line);
  border-radius: 10px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--warn-ink);
}
.notice a { color: var(--warn-ink); }
.notice-title {
  display: inline-block;
  padding: 3px 8px;
  background: var(--warn);
  color: var(--warn-wash);
  border-radius: 4px;
  font-weight: 700;
  font-size: 11px;
  letter-spacing: .14em;
  text-transform: uppercase;
  margin-bottom: 5px;
}

/* ── Assurance and help ─────────────────────────────────────────────────── */
.assurance {
  margin-top: 18px;
  padding: 18px var(--pad);
  background: var(--accent-wash);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius);
}

.assurance-lead {
  font-family: var(--serif);
  text-wrap: balance;
  font-size: 17px;
  line-height: 1.35;
  color: var(--accent-deep);
}

.assurance-list {
  margin-top: 12px;
  display: grid;
  gap: 7px;
  font-size: 14px;
  color: var(--ink-mid);
}

.assurance-list li {
  display: flex;
  gap: 9px;
  align-items: flex-start;
}

.assurance-list li::before {
  content: "✓";
  flex: none;
  color: var(--accent);
  font-weight: 700;
  line-height: 1.45;
}

.help {
  margin-top: 18px;
  padding: 18px var(--pad);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  font-size: 14.5px;
  color: var(--ink-mid);
}

.help-title {
  font-family: var(--serif);
  font-size: 17px;
  font-weight: 400;
  margin-bottom: 6px;
  color: var(--ink);
}

/* The one affordance a stuck customer reaches for, so it is a real target
   rather than a link buried mid-sentence. */
.help-mail {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: var(--tap);
  margin-top: 14px;
  padding: 12px 14px;
  background: var(--ground);
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  color: var(--ink);
  font-weight: 600;
  font-size: 15px;
  text-decoration: none;
  word-break: break-word;
  text-align: center;
}
.help-mail:hover { border-color: var(--accent); color: var(--accent-deep); }

/* The support target that replaces the submit button when no answer came back.
   It is an outcome, not a footnote, so it sits where the button was. */
.help-mail-inform {
  margin-top: 18px;
  background: var(--surface);
  border-color: var(--accent);
  color: var(--accent-deep);
}
.help-mail::before { content: "✉"; color: var(--accent); font-weight: 400; }

.site-foot {
  max-width: 560px;
  margin: 26px auto 0;
  font-size: 12px;
  line-height: 1.7;
  color: var(--ink-soft);
  text-align: center;
}
.site-foot a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 8px;
  color: var(--ink-soft);
}

/* ── Wider than a phone ─────────────────────────────────────────────────── */
@media (min-width: 480px) {
  .row {
    grid-template-columns: 1fr 1fr;
    gap: 0 14px;
  }
  .stub-title { font-size: 34px; }
}

@media (min-width: 700px) {
  body { padding-left: 24px; padding-right: 24px; }
  :root { --pad: 28px; }
  .site-head { padding: 26px 0 24px; }
  main { max-width: 580px; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
 * ADMIN — the redemption desk (admin.html only).
 *
 * Same product, different room. The customer page is a ticket held in one
 * hand; this is the worktop it lands on: wider, denser, and read standing up.
 * Every rule below is scoped to `.admin` on <body> or to the `adm-` prefix, so
 * nothing here reaches index.html.
 *
 * Urgency is carried by four signals that survive greyscale and distance —
 * a banded group with a heavy rule and a count above it, a chip that differs
 * in SHAPE and GLYPH as well as colour, heavier type and looser row height in
 * the top band, and the error sentence given the full width of the table.
 * Deliberately no side-tab accent borders anywhere on this page.
 * ═════════════════════════════════════════════════════════════════════════ */

.admin {
  /* "Awaiting" is the one state where nobody needs to do anything yet, so it is
     given graphite rather than a hue — the ledger's three bands then read as a
     luminance ladder (red, graphite, hairline) that survives greyscale. */
  --wait:      #3A4255;
  --wait-wash: #EEF0F5;
}

/* Several admin blocks are grid or flex, which would otherwise win against the
   user-agent rule for [hidden]. The page toggles everything through .hidden. */
.admin [hidden] { display: none !important; }

.admin main,
.admin .site-head,
.admin .site-foot { max-width: 1240px; }

.adm-head-right { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; justify-content: flex-end; }

/* ── Whose session this is ──────────────────────────────────────────────────
   Stated in the header, permanently, because identity was the entire point of
   replacing the shared key and a desk that will not name its operator has
   given that back. Kept to the ink scale rather than a hue: it is a fact about
   the session, not a state anyone has to act on, and every hue on this page is
   already spoken for by a redemption status. */
.adm-session {
  display: flex;
  align-items: center;
  gap: 10px;
  min-width: 0;
}
.adm-session-who {
  min-width: 0;
  max-width: 24ch;
  overflow: hidden;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.25;
  color: var(--ink-mid);
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* A break-glass session is not a name, and must not read like one. */
.adm-session-who.is-anon { font-weight: 500; font-style: italic; color: var(--ink-soft); }

/* The shared key, folded under the sign-in form. Sitting on the gate card
   rather than a panel, so it takes the card's own rule as its divider. */
.adm-breakglass { margin-top: 20px; }
.adm-breakglass .adm-lead {
  margin: 4px 0 14px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--ink-soft);
}
/* Full width, so the quiet button still reads as the action of this fold
   rather than as an afterthought pinned to the left of it. */
.adm-breakglass .btn-quiet { width: 100%; margin-top: 14px; }

/* ── Small controls ─────────────────────────────────────────────────────── */
.adm-mini {
  min-height: 44px;
  padding: 0 14px;
  font-family: inherit;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  background: var(--surface);
  border: 1px solid var(--line-strong);
  border-radius: 8px;
  cursor: pointer;
}
.adm-mini:hover { border-color: var(--accent); color: var(--accent-deep); }
.adm-mini:disabled { color: var(--hush); cursor: progress; }

.adm-mini--wide {
  width: 100%;
  margin-top: 12px;
  background: transparent;
  color: #fff;
  border-color: rgba(255, 255, 255, .34);
}
.adm-mini--wide:hover { color: #fff; border-color: var(--on-dark-soft); }

/* ── The gate ───────────────────────────────────────────────────────────── */
.adm-gate {
  max-width: 460px;
  margin: 20px auto 0;
  padding: 26px 24px 28px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.adm-gate .eyebrow { color: var(--accent); }
.adm-gate-title {
  margin-top: 8px;
  font-family: var(--serif);
  font-size: 29px;
  font-weight: 400;
  line-height: 1.15;
}
.adm-gate-sub {
  margin: 9px 0 20px;
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--ink-mid);
}

/* ── The ops shell ──────────────────────────────────────────────────────────
 *
 * The desk is a platform now rather than one screen: Groupon vouchers today,
 * Groupon settlement beside it, and room for whatever is next. The shell is a
 * stack — a nav, then one section, only one of which is ever shown.
 *
 * Deliberately not a tab component. `aria-current` on a button and `hidden` on
 * a div is the whole mechanism, so adding a section is adding a button and a
 * div and nothing else. There is no state here for a third automation to have
 * to fit into. */
.ops-shell { display: grid; gap: 18px; }

.ops-nav {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 8px;
}

.ops-tab {
  display: grid;
  gap: 2px;
  min-height: var(--tap);
  padding: 9px 16px;
  text-align: left;
  font-family: inherit;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
}
.ops-tab:hover { color: var(--ink); border-color: var(--line-strong); }

/* The section you are in is filled navy, the way the chosen filter chip is.
   One idiom for "this is the one that is on", used in both places. */
.ops-tab[aria-current="true"] {
  color: #fff;
  background: var(--ink);
  border-color: var(--ink);
}

.ops-tab-name { font-size: 14px; font-weight: 700; letter-spacing: -.01em; }
.ops-tab-note {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--hush);
}
.ops-tab[aria-current="true"] .ops-tab-note { color: var(--on-dark-quiet); }

/* ── Settlement ─────────────────────────────────────────────────────────── */
.ops-section { display: grid; gap: 18px; align-content: start; }

/* A file input is a control like any other and has to be thumb-sized. Left as
   the browser's own widget on purpose: a styled label pretending to be one
   loses the file name, and the file name is how an operator checks they picked
   the statement they meant to. */
.adm-file {
  min-height: var(--tap);
  padding: 12px 14px;
  line-height: 1.5;
}
.adm-file::file-selector-button {
  min-height: 34px;
  margin-right: 12px;
  padding: 0 12px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink);
  background: var(--accent-wash);
  border: 1px solid var(--line);
  border-radius: 8px;
  cursor: pointer;
}

/* Each discrepancy gets a heading, a count and its own table. No coloured
   stripe down the side of anything: the band header does that work, as it does
   in the redemption ledger. */
.set-group { padding-top: 18px; border-top: 1px solid var(--line); }
.set-group:first-child { padding-top: 0; border-top: 0; }

.set-group-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 4px;
}

.set-group-title { font-size: 14.5px; font-weight: 700; letter-spacing: -.01em; }

.set-count {
  font-size: 15px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
  color: var(--ink);
}
/* Red is failure and punctuation only, never decoration — so it appears here
   exactly when the count is not zero. */
.set-group.is-live .set-count { color: var(--danger); }

.set-group-note {
  margin: 0 0 10px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.set-clear {
  margin: 0 0 4px;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ok);
}

.set-list { display: grid; gap: 6px; }

.set-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.45;
  background: var(--ground);
  border-radius: 10px;
}
.set-group.is-live .set-row { background: var(--danger-tint); }

.set-code {
  font-family: var(--mono);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--ink);
}
.set-meta { color: var(--ink-soft); }
.set-money { font-variant-numeric: tabular-nums; font-weight: 600; color: var(--ink); }

.set-more {
  margin: 8px 0 0;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-soft);
}

.set-history { display: grid; gap: 6px; }
.set-hist-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 4px 10px;
  padding: 10px 12px;
  font-size: 12.5px;
  background: var(--ground);
  border-radius: 10px;
}
.set-hist-name { font-weight: 600; color: var(--ink); word-break: break-word; }

/* ── Desk layout ────────────────────────────────────────────────────────── */
.adm-desk {
  display: grid;
  /* Named at every width, not only inside the two-column query. Without this
     the single grid item keeps min-width:auto, inflates to the table's
     min-content width, and drags <main> and the header past a narrow viewport
     instead of letting .adm-scroll take the overflow. */
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.adm-panel {
  padding: 20px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

.adm-tools { display: grid; gap: 18px; align-content: start; }

.adm-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 16px;
}

.adm-panel-actions {
  display: grid;
  justify-items: end;
  gap: 6px;
}

/* How old is what you are looking at. Goes cold after three minutes so a desk
   whose polling has quietly died looks different from one that is current. */
.adm-checked {
  font-size: 11px;
  font-weight: 600;
  letter-spacing: .04em;
  color: var(--ink-soft);
  white-space: nowrap;
}
.adm-checked.is-cold { color: var(--danger); }

.adm-panel .eyebrow { color: var(--accent); }

.adm-title {
  margin-top: 6px;
  font-family: var(--serif);
  font-size: 25px;
  font-weight: 400;
  line-height: 1.15;
}

.adm-lead {
  margin: 8px 0 18px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--ink-mid);
}

/* ── The tally board ────────────────────────────────────────────────────────
 * Read before anything else, from further away than anything else. */
.adm-tally {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 18px;
}

.adm-tally-loading { font-size: 13.5px; color: var(--ink-soft); }

.adm-plate {
  min-width: 104px;
  padding: 11px 14px 12px;
  background: var(--ground);
  border: 1px solid var(--line);
  border-radius: 10px;
}

.adm-plate-num {
  display: block;
  font-family: var(--mono);
  font-size: 30px;
  line-height: 1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.adm-plate-label {
  display: block;
  margin-top: 7px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

.adm-plate--loud {
  background: var(--danger);
  border-color: var(--danger);
  color: #fff;
}
.adm-plate--loud .adm-plate-label { color: var(--danger-pale); }

.adm-plate--calm {
  background: var(--ok-wash);
  border-color: var(--ok-line);
  color: var(--ok);
}
.adm-plate--calm .adm-plate-label { color: var(--ok); }

/* A total, not a verdict. The plainest plate there is, named at the call site
   so a figure that simply IS a number is never plated as a pass. */
.adm-plate--fact {
  background: var(--ground);
  border-color: var(--line);
  color: var(--ink);
}

/* "I don't know" has to look like neither a pass nor a failure. */
.adm-plate--unknown {
  background: var(--ink);
  border-color: var(--ink);
  color: #fff;
}
.adm-plate--unknown .adm-plate-label { color: var(--on-dark-soft); }

.adm-tally-verdict {
  margin-left: 4px;
  font-family: var(--serif);
  font-size: 17.5px;
  line-height: 1.3;
}
.adm-tally.is-clear .adm-tally-verdict { color: var(--ok); }
.adm-tally:not(.is-clear) .adm-tally-verdict { color: var(--danger); font-weight: 600; }
/* Neither of the above: old numbers and no numbers are not alarms. */
.adm-tally.is-stale .adm-tally-verdict,
.adm-tally.is-unknown .adm-tally-verdict { color: var(--ink); font-weight: 600; }

.adm-tally-caveat {
  flex-basis: 100%;
  margin-top: 2px;
  font-size: 12px;
  line-height: 1.45;
  color: var(--ink-soft);
}

/* ── Filters ────────────────────────────────────────────────────────────── */
.adm-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
  padding-bottom: 16px;
  border-bottom: 1px solid var(--line);
}

.adm-chipbtn {
  min-height: 44px;
  padding: 0 13px;
  font-family: inherit;
  font-size: 12.5px;
  font-weight: 600;
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: 999px;
  cursor: pointer;
}
.adm-chipbtn:hover { color: var(--ink); border-color: var(--line-strong); }
.adm-chipbtn.is-on {
  color: #fff;
  background: var(--ink);
  border-color: var(--ink);
}

/* ── The ledger ─────────────────────────────────────────────────────────── */
.adm-scroll { overflow-x: auto; }

.adm-table {
  width: 100%;
  min-width: 690px;
  border-collapse: collapse;
}

.adm-caption {
  padding: 14px 0 12px;
  margin: 0;
  font-size: 12.5px;
  color: var(--ink-soft);
  text-align: left;
}

/* Available to a screen reader, absent from the page. */
.adm-vh {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.adm-table thead th {
  padding: 0 10px 9px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
  color: var(--ink-soft);
  text-align: left;
  border-bottom: 1px solid var(--line-strong);
  white-space: nowrap;
}

.adm-col-status { width: 132px; }
.adm-col-when { width: 96px; }

/* Band headers. This is what a coloured side stripe pretends to do, done
   properly: the group is named, counted, and ruled off. */
.adm-band-cell {
  padding: 22px 10px 9px;
  text-align: left;
  vertical-align: baseline;
}

.adm-band-count {
  display: inline-block;
  min-width: 26px;
  margin-right: 9px;
  font-family: var(--mono);
  font-size: 16px;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.adm-band-title {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
}

.adm-band-note {
  margin-left: 10px;
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink-soft);
}

.adm-band--act .adm-band-cell { border-top: 3px solid var(--danger); }
.adm-band--act .adm-band-count,
.adm-band--act .adm-band-title { color: var(--danger); }

.adm-band--wait .adm-band-cell { border-top: 2px solid var(--wait); }
.adm-band--wait .adm-band-count,
.adm-band--wait .adm-band-title { color: var(--wait); }

.adm-band--clear .adm-band-cell { border-top: 1px solid var(--line-strong); }
.adm-band--clear .adm-band-count,
.adm-band--clear .adm-band-title { color: var(--hush); }

/* Rows. Density and weight do as much work here as colour: the top band sits
   taller and darker, the clear band is set light and tight. */
.adm-row td {
  padding: 12px 9px;
  font-size: 13.5px;
  line-height: 1.4;
  vertical-align: top;
  border-top: 1px solid var(--line);
}

.adm-row--act td {
  padding-top: 16px;
  padding-bottom: 16px;
  color: var(--ink);
  background: var(--danger-tint);
  border-top-color: var(--danger-line);
}
.adm-row--act .adm-mono,
.adm-row--act .adm-who-name { font-weight: 700; }

.adm-row--wait td { color: var(--ink); }

.adm-row--clear td { color: var(--hush); }
.adm-row--clear .adm-who-name { font-weight: 500; }

.adm-mono {
  font-family: var(--mono);
  font-size: 12.5px;
  letter-spacing: .04em;
  white-space: nowrap;
}

.adm-who-name { display: block; font-weight: 600; }
/* Secondary lines wrap. A long email was the single largest data-dependent
   contributor to the table's min-content width, which is what decides whether
   the ledger needs an inner scroll. */
.adm-who-mail {
  display: block;
  font-size: 11.5px;
  color: var(--ink-soft);
  overflow-wrap: anywhere;
}
.adm-item-name { display: block; }
.adm-item-variant { display: block; font-size: 11.5px; color: var(--ink-soft); }
.adm-when-rel { display: block; white-space: nowrap; }
.adm-when-abs {
  display: block;
  font-family: var(--mono);
  font-size: 10.5px;
  color: var(--ink-soft);
  white-space: nowrap;
}

/* The error sentence gets the width of the table — it is the instruction. */
.adm-note td {
  padding: 0 10px 14px;
  font-size: 12.5px;
  line-height: 1.5;
}
.adm-note--act td { background: var(--danger-tint); color: var(--danger-ink); }
.adm-note--wait td { color: var(--wait); }
.adm-note--clear td { color: var(--hush); }

.adm-note-label {
  display: inline-block;
  margin-right: 8px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .15em;
  text-transform: uppercase;
}

.adm-flag {
  display: inline-block;
  margin-top: 6px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--danger);
}

.adm-empty {
  padding: 34px 10px;
  font-size: 14px;
  color: var(--ink-soft);
  text-align: center;
}
.adm-emptyrow td { border-top: 1px solid var(--line); }

/* ── Status chips ───────────────────────────────────────────────────────────
 * Five statuses, five silhouettes: filled square, thick-ruled square, dashed
 * pill, faint dashed pill, no chip at all. Each carries a glyph. Print the
 * page in black and white and the ranking still reads. */
.adm-chip {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 4px 9px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .1em;
  text-transform: uppercase;
  white-space: nowrap;
}

.adm-chip-glyph { font-size: 12px; line-height: 1; }

.adm-chip--failed {
  color: #fff;
  background: var(--danger);
  border: 1px solid var(--danger);
  border-radius: 3px;
}

.adm-chip--held {
  color: var(--warn-ink);
  background: var(--warn-wash);
  border: 2px solid var(--warn);
  border-radius: 3px;
  padding: 3px 8px;
}

.adm-chip--pending {
  color: var(--ink-soft);
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: 999px;
}

.adm-chip--created {
  color: var(--hush);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  font-weight: 600;
  padding-left: 0;
}

/* ── The status key ─────────────────────────────────────────────────────── */
.adm-key {
  margin-top: 20px;
  padding-top: 16px;
  border-top: 1px solid var(--line);
  font-size: 13px;
}
.adm-key summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
}
.adm-key summary::marker,
.adm-key summary::-webkit-details-marker { content: ""; display: none; }
.adm-key summary::before {
  content: "▸";
  margin-right: 8px;
  font-size: 11px;
}
.adm-key[open] summary::before { content: "▾"; }
.adm-key-list { display: grid; gap: 12px; margin-top: 8px; }
.adm-key-list > div {
  display: grid;
  gap: 4px 16px;
  align-items: baseline;
}
.adm-key-list dt { justify-self: start; }
.adm-key-list dd {
  margin: 0;
  font-size: 12.5px;
  line-height: 1.55;
  color: var(--ink-mid);
}

/* ── Batch receipt ──────────────────────────────────────────────────────────
 * Drawn as the ticket stub from the customer page: the one dark object in the
 * rail, so the batch id is the hardest thing on screen to overlook. */
.adm-receipt {
  margin-top: 18px;
  padding: 16px 18px 18px;
  background: var(--ink);
  background-image: radial-gradient(120% 130% at 12% 0%, var(--ink-lift) 0%, var(--ink-deep) 72%);
  border-radius: 10px;
  color: #fff;
}

.adm-receipt-label {
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--on-dark-soft);
}

.adm-receipt-id {
  margin-top: 8px;
  font-family: var(--mono);
  font-size: 17px;
  line-height: 1.35;
  letter-spacing: .05em;
  word-break: break-all;
  user-select: all;
}

.adm-receipt-count { margin-top: 7px; font-size: 12px; color: var(--on-dark-soft); }

.adm-input-id { font-family: var(--mono); font-size: 14px; letter-spacing: .04em; }

/* An under-committed batch, said on the stub itself. The wash and the type
   carry it — no stripe, on any edge. */
.adm-receipt-warn {
  margin-top: 10px;
  padding: 10px 12px;
  font-size: 12px;
  line-height: 1.5;
  color: #fff;
  background: rgba(255, 255, 255, .09);
  border-radius: 6px;
}

/* ── What an option can stand behind ────────────────────────────────────────
 * Shown before a number is typed, because the number IS a stock commitment:
 * Groupon read the codes on an option's tab as that option's whole allocation.
 * Three facts side by side rather than one figure — what is available, what is
 * already promised, and what is therefore left — so an operator can see which
 * of the three is the surprise. */
.adm-headroom {
  margin: -4px 0 16px;
  padding: 13px 14px 14px;
  background: var(--accent-wash);
  border: 1px solid var(--line-strong);
  border-radius: 10px;
}
.adm-headroom.is-bad {
  background: var(--warn-wash);
  border-color: var(--warn-line);
}
.adm-headroom-head { margin-bottom: 10px; }
.adm-headroom-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}
.adm-headroom-note {
  margin-top: 10px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-mid);
}

/* The figure that decides the next action, in the one weight that says so.
   No colour is carrying this on its own: it is larger and it is labelled. */
.adm-stat--lead .adm-stat-num { font-size: 24px; }
.adm-stat--lead .adm-stat-label { color: var(--ink); }

/* ── What an export would actually send ─────────────────────────────────── */
.adm-confirm-list {
  margin: 11px 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 5px;
  font-size: 13px;
  line-height: 1.5;
  color: var(--danger-ink);
}
.adm-confirm-count {
  font-family: var(--mono);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}
.adm-confirm-none { color: var(--danger-ink); }

/* ── Export: the irreversible button, and its confirm ───────────────────── */
.btn-live {
  background: var(--danger);
  font-size: 15px;
  line-height: 1.35;
  box-shadow: none;
}
.btn-live:hover { background: var(--danger-ink); }
.btn-live:disabled { background: var(--sunk); color: var(--ink-soft); }

.adm-confirm {
  margin-top: 16px;
  padding: 16px 18px 18px;
  background: var(--danger-wash);
  border: 2px solid var(--danger);
  border-radius: 10px;
}

.adm-confirm-title {
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--danger);
}

.adm-confirm-body {
  margin-top: 7px;
  font-size: 13.5px;
  line-height: 1.55;
  color: var(--danger-ink);
}
.adm-confirm-body strong { font-family: var(--mono); font-size: 12.5px; word-break: break-all; }


/* ── Deals: setting a campaign up ───────────────────────────────────────────
 * Step one of three, and the panel someone touches once a campaign rather than
 * every day — so it is dense and mostly folded away. Each deal is one summary
 * line that answers "is this live and how many codes are left" from across the
 * desk, with everything else behind a fold, which keeps the redemption tally
 * below it the first large thing on the screen.
 *
 * No side-tab accent borders here either: state is carried by the chip's shape
 * and glyph, by a full-width tinted block, and by weight. */
.adm-deallist {
  display: grid;
  gap: 12px;
  margin-bottom: 18px;
}

.adm-deal {
  padding: 15px 16px 16px;
  background: var(--field);
  border: 1px solid var(--line);
  border-radius: 10px;
}

/* A stopped deal recedes without going quiet enough to miss. */
.adm-deal.is-off { background: var(--ground); }
.adm-deal.is-off .adm-deal-name { color: var(--ink-mid); }

.adm-deal-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 10px;
  flex-wrap: wrap;
}

.adm-deal-name {
  font-family: var(--serif);
  font-size: 18.5px;
  font-weight: 400;
  line-height: 1.2;
}

/* Live and stopped, in the two shapes the ledger's chips already use. Stopped
   is amber and not red: an operator turning a deal off is doing the right
   thing on purpose, and red on this page means something failed. */
.adm-chip--live {
  color: var(--ok);
  background: var(--ok-wash);
  border: 1px solid var(--ok-line);
  border-radius: 999px;
}

.adm-chip--off {
  color: var(--warn-ink);
  background: var(--warn-wash);
  border: 2px solid var(--warn);
  border-radius: 3px;
  padding: 3px 8px;
}

.adm-deal-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin-top: 7px;
  font-size: 12px;
  color: var(--ink-soft);
}
.adm-deal-meta .adm-mono { font-size: 11.5px; color: var(--ink); }
.adm-deal-dot { color: var(--line-strong); }

.adm-deal-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 20px;
  margin-top: 12px;
}

.adm-stat-num {
  display: block;
  font-family: var(--mono);
  font-size: 19px;
  line-height: 1;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.adm-stat-label {
  display: block;
  margin-top: 5px;
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* "Couldn't count" is not "none". It gets a sentence, never a zero. */
.adm-deal-unknown {
  padding: 9px 11px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: 8px;
}

.adm-deal-stopped {
  margin-top: 11px;
  padding: 10px 12px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--warn-ink);
  background: var(--warn-wash);
  border: 1px solid var(--warn-line);
  border-radius: 8px;
}

.adm-deal-acts {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 13px;
}

.adm-mini--stop {
  color: var(--warn-ink);
  background: var(--warn-wash);
  border-color: var(--warn);
}
.adm-mini--stop:hover { color: var(--warn-ink); border-color: var(--warn-ink); }

/* Stopping a live campaign is a second step. Starting one is not — only one of
   the two directions can surprise a customer mid-checkout. */
.adm-deal-confirm {
  margin-top: 12px;
  padding: 13px 14px 14px;
  background: var(--warn-wash);
  border: 2px solid var(--warn);
  border-radius: 10px;
}
.adm-deal-confirm-body {
  font-size: 13px;
  line-height: 1.5;
  color: var(--warn-ink);
}
.adm-deal-confirm .adm-deal-acts { margin-top: 11px; }

/* ── Folds ──────────────────────────────────────────────────────────────── */
.adm-fold {
  margin-top: 14px;
  padding-top: 12px;
  border-top: 1px solid var(--line);
  font-size: 13px;
}
.adm-fold summary {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  font-weight: 600;
  color: var(--accent);
  cursor: pointer;
}
.adm-fold summary::marker,
.adm-fold summary::-webkit-details-marker { content: ""; display: none; }
.adm-fold summary::before { content: "▸"; margin-right: 8px; font-size: 11px; }
.adm-fold[open] summary::before { content: "▾"; }
.adm-fold-body { padding-top: 4px; }

/* The deals panel's own "create a deal" fold sits on the panel, not a card. */
#new-deal { margin-top: 4px; }

/* ── Options ────────────────────────────────────────────────────────────── */
.adm-optlist {
  display: grid;
  gap: 11px;
  margin: 0 0 4px;
  padding: 0;
  list-style: none;
}

.adm-opt {
  display: grid;
  gap: 7px;
  justify-items: start;
  padding-bottom: 12px;
  border-bottom: 1px dashed var(--line);
}
.adm-optlist > .adm-opt:last-child { padding-bottom: 0; border-bottom: 0; }
.adm-opt-meta { font-size: 11.5px; color: var(--ink-soft); }

/* SKU, stock, codes made, not sent, live, redeemed, and what it can still take
   — the whole answer to "what is this option doing", on one line each. */
.adm-opt-stats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  width: 100%;
}

.adm-opt-warn {
  padding: 8px 10px;
  font-size: 12px;
  line-height: 1.5;
  color: var(--warn-ink);
  background: var(--warn-wash);
  border: 1px solid var(--warn-line);
  border-radius: 8px;
}

/* THE option name, rendered as stored.
 *
 * `pre-wrap` is the whole point: it keeps every space the value actually
 * carries instead of collapsing runs of them the way HTML normally would, so
 * what is on screen is character for character what will be matched against
 * Groupon's file. The frame gives those spaces edges to be seen against. */
.adm-exact {
  display: inline-block;
  max-width: 100%;
  padding: 4px 9px;
  font-family: var(--mono);
  font-size: 13px;
  line-height: 1.4;
  color: var(--ink);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  background: var(--surface);
  border: 1px dashed var(--line-strong);
  border-radius: 6px;
}

.adm-opt-note {
  margin-top: 11px;
  padding-top: 10px;
  border-top: 1px dashed var(--line);
  font-size: 12px;
  line-height: 1.5;
  color: var(--ink-soft);
}

.adm-optform {
  margin-top: 16px;
  padding-top: 14px;
  border-top: 1px solid var(--line);
}

.adm-optform-title {
  margin-bottom: 12px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
}

.adm-textarea {
  min-height: 84px;
  padding: 12px 14px;
  line-height: 1.45;
  resize: vertical;
}

/* ── The preview: what the server would actually store ──────────────────── */
.adm-preview {
  display: grid;
  gap: 7px;
  margin-top: 9px;
  padding: 11px 12px 12px;
  background: var(--ground);
  border: 1px solid var(--line);
  border-radius: 8px;
}
.adm-preview.is-bad {
  background: var(--danger-wash);
  border-color: var(--danger-line);
}

.adm-preview-line {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px;
}

.adm-preview-label {
  font-size: 9px;
  font-weight: 700;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink-soft);
}

/* A repair happened and is being reported; a caution has been left alone and
   is being pointed at. They must not look like the same kind of statement. */
.adm-preview-fix,
.adm-preview-warn,
.adm-preview-msg {
  font-size: 12.5px;
  line-height: 1.5;
}
.adm-preview-fix { color: var(--ok-ink); }
.adm-preview-fix::before { content: "\2713\00a0"; font-weight: 700; }
.adm-preview-warn { color: var(--warn-ink); }
.adm-preview-warn::before { content: "!\00a0"; font-weight: 700; }
.adm-preview-msg { color: var(--danger-ink); font-weight: 600; }

.adm-flash { margin: 0 0 14px; }
.adm-flash .adm-preview-line { margin-bottom: 4px; }

.adm-skucheck {
  margin-top: 7px;
  font-size: 12.5px;
  line-height: 1.5;
  color: var(--ink-soft);
}
.adm-skucheck.is-good { color: var(--ok-ink); font-weight: 600; }
.adm-skucheck.is-good::before { content: "\2713\00a0"; }
.adm-skucheck.is-bad { color: var(--danger-ink); font-weight: 600; }
.adm-skucheck.is-bad::before { content: "\2715\00a0"; }

/* ── Money, taken in pounds because nobody should convert to pence ──────── */
.adm-money { position: relative; }
.adm-money-mark {
  position: absolute;
  top: 0;
  left: 15px;
  height: var(--tap);
  display: flex;
  align-items: center;
  font-size: 16px;
  color: var(--ink-soft);
  pointer-events: none;
}
.adm-money-input { padding-left: 30px; font-variant-numeric: tabular-nums; }

/* ── Alerts ─────────────────────────────────────────────────────────────── */
.adm-alert {
  display: flex;
  gap: 10px;
  margin-top: 16px;
  padding: 12px 14px;
  border-radius: 10px;
  font-size: 13.5px;
  line-height: 1.5;
}
.adm-alert::before { font-weight: 700; line-height: 1.45; }

.adm-alert--bad {
  color: var(--danger-ink);
  background: var(--danger-wash);
  border: 1px solid var(--danger-line);
}
.adm-alert--bad::before { content: "✕"; }

.adm-alert--ok {
  color: var(--ok-ink);
  background: var(--ok-wash);
  border: 1px solid var(--ok-line);
}
.adm-alert--ok::before { content: "✓"; }

/* ── Wider than a phone ─────────────────────────────────────────────────── */
@media (min-width: 760px) {
  .adm-key-list > div { grid-template-columns: 168px minmax(0, 1fr); }
  /* auto-fit rather than a fixed count: a third section slots in without this
     rule being touched. */
  .ops-nav { grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); }
  .adm-deallist { grid-template-columns: repeat(auto-fill, minmax(330px, 1fr)); }
}

/* Two columns only once the ledger clears the table's rendered min-content
   width with the rail beside it. Measured in a real viewport, not read off the
   declared min-width: min-content is 727px, the rail and gutters take 444px,
   so 1171px is the floor and this leaves ~50px of headroom above it. Below
   this the rail drops under the ledger and the table gets the whole width. */
@media (min-width: 1220px) {
  .adm-desk { grid-template-columns: minmax(0, 1fr) 330px; }
  .adm-panel { padding: 24px; }
  /* Setup spans both columns. In the 330px rail an option name — the one thing
     on this page that has to be read character for character — would wrap
     three times. */
  .adm-deals { grid-column: 1 / -1; }
}
