/* Ambar panel.
 *
 * One stylesheet, served by the app, no framework and no web fonts: the panel
 * holds customer data and must not need a third party to render, nor announce
 * to one when it is being used. The palette and the shapes are the ones drawn
 * in mockups.html; the type is the system stack, which on the phone this is
 * mostly used from is the same face the rest of the device uses.
 *
 * Phone first. The rail is a bar across the top until there is room for a
 * column beside the content.
 */

:root {
  --paper: #f6f8f5;
  --panel: #ffffff;
  --sage: #e9f0ea;
  --line: #dce5dd;
  --ink: #1b241f;
  --ink2: #5a6a60;
  --ink3: #8fa097;
  --pine: #0e5a47;
  --pine-soft: #e1eee8;
  --red: #b3423a;
  --red-soft: #f9e6e4;
  --r: 12px;
  --body: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial,
    sans-serif;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
  font-family: var(--body);
  background: var(--paper);
  color: var(--ink);
  font-size: 15px;
  line-height: 1.45;
  -webkit-text-size-adjust: 100%;
}

h1 { font-size: 22px; font-weight: 700; letter-spacing: -0.01em; }
.sub { color: var(--ink2); font-size: 14px; margin-top: 4px; }

a { color: var(--pine); }

button {
  font: inherit;
  cursor: pointer;
  border: none;
  border-radius: 10px;
  background: var(--ink);
  color: #fff;
  font-weight: 600;
  padding: 11px 16px;
  /* Never below 44px tall once padding is in: this is used with a thumb. */
  min-height: 44px;
}

button:focus-visible,
a:focus-visible,
input:focus-visible {
  outline: 2px solid var(--pine);
  outline-offset: 2px;
}

/* The brand mark, in both the rail and the login card. */
.mark {
  font-weight: 700;
  font-size: 19px;
  letter-spacing: -0.03em;
}

/* Said to a screen reader and to nothing else. For a fact the layout carries
   in a shape -- the inbox's alert dot -- where the row has no words for it.
   Not `display: none`, which is not announced either. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Visible only once it has focus: the first tab of a keyboard user skips the
   navigation instead of walking it on every page. */
.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 8px;
  top: 8px;
  z-index: 2;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 8px;
  padding: 8px 12px;
}

/* ── The signed-in shell ────────────────────────────────────────────────── */

.shell { min-height: 100dvh; }

.rail {
  display: flex;
  align-items: center;
  gap: 14px;
  background: var(--ink);
  color: #fff;
  padding: 10px 14px;
  position: sticky;
  top: 0;
  z-index: 1;
}

.rail nav {
  display: flex;
  gap: 4px;
  flex: 1;
  /* A phone with three or four sections scrolls them rather than wrapping the
     bar onto a second line that pushes the content down. */
  overflow-x: auto;
  scrollbar-width: none;
}

.rail .tab {
  color: #ffffffb3;
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  padding: 9px 12px;
  border-radius: 9px;
  white-space: nowrap;
}
.rail .tab.on { background: #ffffff1f; color: #fff; }

.rail .out button {
  background: transparent;
  color: #ffffffb3;
  font-weight: 500;
  font-size: 13px;
  padding: 9px 4px;
}
.rail .out button:hover { color: #fff; }

main { padding: 20px 16px 40px; max-width: 1080px; }

.cards {
  list-style: none;
  display: grid;
  gap: 12px;
  margin-top: 18px;
}

.cards a {
  display: block;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 16px 18px;
  text-decoration: none;
  color: var(--ink);
}
.cards a:hover { border-color: var(--pine); }
.cards b { display: block; font-size: 15px; }
.cards span { display: block; color: var(--ink2); font-size: 13.5px; margin-top: 2px; }

/* ── The alert queue ────────────────────────────────────────────────────── */

.empty {
  margin-top: 18px;
  color: var(--ink2);
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 22px 18px;
  text-align: center;
  font-size: 14px;
}

.queue {
  list-style: none;
  margin-top: 18px;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
}

/* Phone first: the severity dot beside the name, everything else stacked
   under it, and the buttons across the bottom where a thumb reaches them. */
.alert {
  display: grid;
  grid-template-columns: 8px 1fr;
  gap: 6px 12px;
  align-items: start;
  padding: 14px 16px;
  border-bottom: 1px solid var(--line);
}
.alert:last-child { border-bottom: none; }
/* A resolved row stays in the list -- it is the record of what was done --
   but stops competing for attention with the ones that are not. */
.alert.done { background: var(--paper); }
.alert.done .who { opacity: 0.62; }

.sev {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-top: 6px;
  background: var(--ink3);
}
.sev-critical { background: var(--red); }

.alert .ti { font-weight: 600; font-size: 14.5px; }

/* The number is the reason this screen exists: the alert says somebody asked
   for a person, and this is how that person is reached. */
.alert .tel {
  display: inline-block;
  margin-top: 2px;
  font-size: 14px;
  font-weight: 600;
  letter-spacing: 0.01em;
}
.alert .tel.none { color: var(--ink3); font-weight: 500; }

.alert .de { font-size: 13px; color: var(--ink2); margin-top: 4px; }

.alert .meta,
.alert .act {
  grid-column: 2;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.alert .meta { font-size: 12.5px; color: var(--ink2); margin-top: 2px; }

.pill {
  border-radius: 999px;
  padding: 2px 9px;
  font-size: 11.5px;
  font-weight: 600;
  background: var(--sage);
  color: var(--ink2);
}
.pill-open { background: var(--red-soft); color: var(--red); }
.pill-acknowledged { background: var(--pine-soft); color: var(--pine); }

.alert .act { margin-top: 8px; }
.alert .act button { padding: 8px 14px; min-height: 40px; font-size: 13px; }
.alert .act button.ghost { background: var(--sage); color: var(--ink); }
/* The way into the thread. A link and not a button, because it goes somewhere
   while the two beside it change something.

   Sized like them all the same. `margin-right: auto` puts a gap between it
   and "Resolver" only while the three fit on one line, and this row is
   `flex-wrap: wrap` on a screen 360px wide -- so at phone width, which is
   where this panel is read, the gap collapses and a bare 18px of text ends up
   against a 40px button that closes an alert. The floor is the neighbours'. */
.alert .act .open {
  display: inline-flex;
  align-items: center;
  padding: 8px 14px;
  min-height: 40px;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: var(--panel);
  font-size: 13px;
  text-decoration: none;
  margin-right: auto;
}

/* ── The inbox ──────────────────────────────────────────────────────────── */

/* The filters. Chips rather than a `<select>`: three options a thumb can hit
   without opening anything, on the one screen that is used while somebody is
   waiting for an answer. */
.filters { display: flex; gap: 8px; flex-wrap: wrap; }
.chip {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--line);
  background: var(--panel);
  border-radius: 999px;
  padding: 7px 16px;
  /* The same floor the queue's buttons have, and for the same reason: this
     screen is driven with a thumb. */
  min-height: 40px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink2);
  text-decoration: none;
  white-space: nowrap;
}
.chip:hover { border-color: var(--pine); color: var(--pine); }
.chip.on { background: var(--pine); border-color: var(--pine); color: #fff; }
.chip.on:hover { color: #fff; }

.thread { border-bottom: 1px solid var(--line); }
.thread:last-child { border-bottom: none; }

/* The whole row is the link: this is read with a thumb, and a target the size
   of a name is a target that gets missed. */
.thread .row {
  display: grid;
  grid-template-columns: 8px minmax(0, 1fr) auto;
  gap: 4px 12px;
  align-items: start;
  padding: 14px 16px;
  color: inherit;
  text-decoration: none;
}
.thread .row:hover { background: var(--paper); }

/* The alert dot keeps the severity dot's column, so a row of the inbox and a
   row of the queue line up when both are on the screen. `off` holds the space
   rather than removing it: a list whose names start at two different x
   positions is a list that reads as two lists. */
.thread .flag { display: block; }
.thread .dot { display: block; width: 8px; height: 8px; border-radius: 50%; margin-top: 6px; background: var(--red); }
.thread .dot.off { background: transparent; }

.thread .who b { font-size: 14.5px; }
/* One line of the last message, cut with an ellipsis. The API already trims
   it to 80 characters; this is what keeps a single long word from widening
   the row on a narrow phone. */
.thread .who .de {
  /* Stated here rather than inherited from the funnel's `.who .de` two
     hundred lines down: the ellipsis only works on a block, and scoping that
     rule one day would take the truncation with it in silence. */
  display: block;
  margin-top: 4px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.thread .meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  font-size: 12.5px;
  color: var(--ink2);
  white-space: nowrap;
}

/* A thread a person is holding is the one thing on this screen that is
   somebody's job right now, so it is the one pill that fills. */
.pill-human { background: var(--pine); color: #fff; }

.pages { display: flex; gap: 12px; margin-top: 14px; font-size: 13.5px; }
.pages .next { margin-left: auto; }

/* ── One thread ─────────────────────────────────────────────────────────── */

.crumb { font-size: 13.5px; margin-bottom: 10px; }
.crumb a { text-decoration: none; }

.thread-head .tel { font-size: 13.5px; }
.thread-head .tel.none { color: var(--ink3); }
.thread-head .meta {
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 6px;
  white-space: nowrap;
}

/* How much of the 24 h window is left. Quiet while there is time and red once
   there is none: it is the one thing on this screen with a deadline on it, and
   the operator finds out the hard way otherwise -- by having a send refused. */
.window { font-size: 12.5px; color: var(--ink2); }
.window.shut { color: var(--red); font-weight: 600; }

/* Taking the thread, or giving it back. Smaller than a page button because it
   sits in the header beside the pill it changes -- the same exception, and the
   same 40px floor, the alert row's two buttons already make. */
.thread-head .meta button { padding: 8px 14px; min-height: 40px; font-size: 13px; }
.thread-head .meta button.ghost { background: var(--sage); color: var(--ink); }

/* A window onto the thread rather than a page that grows without end. The
   newest message and the box to answer it are what this screen is FOR, and on
   a phone a conversation of fifty put both a full screen below the fold.
   Bounded here; pinned to the newest by htmx's `scroll:` on every swap and by
   `thread.js` on the first paint.

   `contain` so that reaching the top of the log does not carry on into the
   page behind it, which on a touch screen reads as the whole screen lurching. */
.log {
  list-style: none;
  margin-top: 16px;
  display: grid;
  gap: 10px;
  max-height: 58dvh;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Theirs on the left, ours on the right, and a note across the middle. The
   side is what this screen is read by at a glance; the label under it is what
   settles which of us wrote an outbound one. */
.bubble {
  max-width: 82%;
  border-radius: var(--r);
  padding: 9px 12px;
  background: var(--panel);
  border: 1px solid var(--line);
}
.bubble.in { justify-self: start; border-bottom-left-radius: 4px; }
.bubble.out {
  justify-self: end;
  background: var(--pine-soft);
  border-color: var(--pine-soft);
  border-bottom-right-radius: 4px;
}
.bubble.note {
  justify-self: stretch;
  max-width: none;
  background: var(--sage);
  border-style: dashed;
  border-color: var(--ink3);
}

.bubble .tag {
  display: block;
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.bubble .said { margin-top: 3px; white-space: pre-wrap; overflow-wrap: anywhere; }
.bubble time { display: block; margin-top: 4px; font-size: 11.5px; color: var(--ink3); }

/* `photo` and not `placard`: `.placard` is the catalogue's upload CARD, with
   18px of padding, a border and a 620px ceiling, and an image wearing that
   class inherited every one of them here. */
.bubble .photo {
  display: block;
  margin-top: 6px;
  max-width: 100%;
  border-radius: 8px;
}

/* A file the customer sent. It is NOT an image here and must not look like
   one waiting to load: the binary was never downloaded from Meta, whose link
   expires, and the download is F5. The marker says where the file actually
   is. */
.bubble .file {
  display: block;
  margin-top: 6px;
  border: 1px dashed var(--ink3);
  border-radius: 8px;
  padding: 8px 10px;
  font-size: 13px;
}
.bubble .file .de { display: block; color: var(--ink2); font-size: 12.5px; }

.log .more { justify-self: center; font-size: 13.5px; }
.log .empty { justify-self: center; color: var(--ink2); font-size: 13.5px; }

/* The box, and what stands in its place once the window has shut. */
.composer { margin-top: 16px; display: grid; gap: 8px; }
/* Only what differs from the shared `textarea` rule: a lighter ground, so the
   box reads as part of the thread rather than as part of the page.
   **`font: inherit` is deliberately NOT restated here.** The shorthand resets
   `font-size` to the body's 15px and wins on specificity over the generic
   rule's 16px -- below which iOS Safari zooms into the field on focus and
   leaves the form scrolled sideways, which is the note the sibling `input`
   rule already carries. This is the field most likely to be typed into on a
   phone, so it was the worst place in the panel to lose that. The padding and
   the 44px floor come from the same shared rule. */
.composer textarea { background: var(--panel); }
.composer textarea:focus-visible { outline: 2px solid var(--pine); outline-offset: 1px; }
.composer button { justify-self: end; }
/* htmx puts this on the button for the length of the request. Without it the
   second click is a second post, and the only thing between it and a second
   message is the idempotency key. */
.composer button[disabled] { opacity: 0.55; cursor: default; }

.kept { margin-top: 10px; font-size: 13.5px; color: var(--ink2); overflow-wrap: anywhere; }

/* The private note, folded away.

   Everything about it is borrowed from the note bubbles of the log -- sage,
   dashed, and an uppercase line saying the customer cannot see it -- so that
   what writes them looks like what it produces. Nothing about it is borrowed
   from the composer: the ground is different, the button is outlined rather
   than filled, and it is shut until somebody opens it. One box on the screen
   at a time is the point; the rest is so that the open one is never mistaken
   for the other. */
.notebox { margin-top: 14px; }
.notebox > summary {
  cursor: pointer;
  padding: 9px 2px;
  font-size: 13.5px;
  color: var(--ink2);
}
.notebox[open] > summary { color: var(--ink); font-weight: 600; }
.notebox form {
  margin-top: 4px;
  display: grid;
  gap: 8px;
  padding: 12px;
  border: 1px dashed var(--ink3);
  border-radius: var(--r);
  background: var(--sage);
}
.notebox .warn {
  font-size: 11.5px;
  font-weight: 600;
  color: var(--ink2);
  text-transform: uppercase;
  letter-spacing: 0.04em;
}
.notebox textarea { background: var(--panel); }
/* Outlined where the composer's is filled: the two buttons are never side by
   side, so the difference has to survive being seen one at a time. */
.notebox button {
  justify-self: end;
  background: var(--panel);
  color: var(--ink);
  border: 1px solid var(--ink3);
}
.notebox button[disabled] { opacity: 0.55; cursor: default; }
/* Said on the fold itself, because saving shuts it: a confirmation inside the
   body would be behind the thing that just closed over it. */
.notebox > summary .saved { margin-left: 8px; color: var(--pine); font-weight: 600; }

/* ── The catalogue ──────────────────────────────────────────────────────── */

.items { list-style: none; margin-top: 18px; display: grid; gap: 10px; }

.items a {
  display: block;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 14px 16px;
  text-decoration: none;
  color: var(--ink);
}
.items a:hover { border-color: var(--pine); }

.items .hd { display: flex; align-items: center; gap: 10px; justify-content: space-between; }
.items .hd b { font-size: 15px; }
.items .de { color: var(--ink2); font-size: 12.5px; margin-top: 3px; }
.items .amounts { margin-top: 8px; display: flex; gap: 10px; flex-wrap: wrap; }
.items .amount { font-size: 13px; font-weight: 600; }
.items .amount.none { color: var(--ink3); font-weight: 500; }

/* `quoted` reads as the resting state and `listed` as the one that made a
   claim, because the second is the one worth noticing on a list of fifteen.
   `free` is a claim too -- a talk that costs nothing is not the default
   either, and it gets the same noticing color as `listed`. */
.pill-quoted { background: var(--sage); color: var(--ink2); }
.pill-listed { background: var(--pine-soft); color: var(--pine); }
.pill-free { background: var(--pine-soft); color: var(--pine); }

/* Same reading for status: `active` is the resting state, `coming_soon` the
   claim worth noticing -- the bot is refusing to sell that one. */
.pill-active { background: var(--sage); color: var(--ink2); }
.pill-coming_soon { background: var(--pine-soft); color: var(--pine); }

code {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 12px;
}

.crumb { margin-bottom: 10px; font-size: 13px; }
.crumb a { text-decoration: none; }

.edit,
.placard {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 18px;
  margin-top: 18px;
  max-width: 620px;
}
.edit { display: grid; gap: 4px; }
.edit label:first-child { margin-top: 0; }
.edit button { margin-top: 20px; justify-self: start; }

.hint { font-size: 12.5px; color: var(--ink2); margin: 2px 0 6px; }

textarea,
select {
  font: inherit;
  font-size: 16px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 11px 13px;
  width: 100%;
  min-height: 44px;
}
textarea { resize: vertical; line-height: 1.5; }
textarea:focus, select:focus { border-color: var(--pine); }

/* The currency beside its field rather than above it: a product with three
   of them would otherwise be a column of six stacked labels. */
.money { display: grid; grid-template-columns: 56px 1fr; align-items: center; gap: 10px; }
.money .cur {
  margin: 0;
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--ink2);
}

.placard h2 { font-size: 15px; margin-bottom: 10px; }
.upload { margin-top: 14px; }
.upload input[type="file"] {
  font-size: 14px;
  background: none;
  border: none;
  padding: 0;
  min-height: 0;
}
.upload button { margin-top: 12px; }

.placard img {
  max-width: 100%;
  height: auto;
  border-radius: 10px;
  border: 1px solid var(--line);
  display: block;
}

/* ── The funnel ─────────────────────────────────────────────────────────── */

h2 { font-size: 16px; font-weight: 700; letter-spacing: -0.005em; }
h3 { font-size: 13.5px; font-weight: 700; margin: 18px 0 8px; }

.muted { color: var(--ink3); }
.nowrap { white-space: nowrap; }

/* Title on the left, the product picker on the right once there is room. */
.page-head { display: grid; gap: 14px; align-items: end; }
.picker { display: grid; gap: 4px; }
.picker label { margin-top: 0; }
.picker select { min-width: 220px; background: var(--panel); }

.notice,
.error { max-width: 620px; }

/* The four numbers somebody opens this page for. */
.tiles {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  margin-top: 20px;
}
.tile {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 14px 16px;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.tile-label {
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink3);
}
.tile-value {
  font-size: 28px;
  font-weight: 700;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-variant-numeric: tabular-nums;
}
.tile-value small { font-size: 13px; font-weight: 600; color: var(--ink2); letter-spacing: 0; }
.tile-note { font-size: 12.5px; color: var(--ink2); }

.block { margin-top: 26px; min-width: 0; }
.block-head { margin-bottom: 10px; }
.block-head .sub { font-size: 13px; }
.block .empty { margin-top: 0; }

.count {
  display: inline-block;
  vertical-align: 2px;
  margin-left: 4px;
  border-radius: 999px;
  padding: 1px 8px;
  font-size: 12px;
  background: var(--pine-soft);
  color: var(--pine);
}

.split { display: grid; gap: 0 18px; }

/* Tables: a white card with hairlines between rows, figures right-aligned. */
.grid {
  width: 100%;
  border-collapse: separate;
  border-spacing: 0;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  overflow: hidden;
  font-size: 14px;
}
.grid th {
  text-align: left;
  font-size: 11.5px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink3);
  background: var(--sage);
  padding: 9px 14px;
  white-space: nowrap;
}
.grid td { padding: 11px 14px; border-top: 1px solid var(--line); vertical-align: top; }
.grid .num { text-align: right; font-variant-numeric: tabular-nums; }
.grid .amount { display: block; white-space: nowrap; }
.grid a { text-decoration: none; }
.grid a:hover { text-decoration: underline; }
.scroll { overflow-x: auto; border-radius: var(--r); }
.scroll .grid { min-width: 620px; }

.who b { display: block; font-weight: 600; }
.who .de { display: block; font-size: 12.5px; color: var(--ink2); }
.tel { font-weight: 600; white-space: nowrap; font-variant-numeric: tabular-nums; }

.pill-bot { background: var(--pine-soft); color: var(--pine); }
.pill-plain { background: var(--sage); color: var(--ink2); }

/* Phone first: every registrant is a card, each cell labelled from the
   header it would sit under on a wider screen. */
@media (max-width: 839px) {
  .people,
  .people tbody,
  .people tr,
  .people td { display: block; }
  .people { border: none; background: none; overflow: visible; }
  .people thead { display: none; }
  .people tr {
    background: var(--panel);
    border: 1px solid var(--line);
    border-radius: var(--r);
    padding: 12px 14px;
    margin-bottom: 10px;
  }
  .people td {
    border: none;
    padding: 3px 0;
    display: grid;
    grid-template-columns: 96px 1fr;
    gap: 10px;
    align-items: baseline;
    overflow-wrap: anywhere;
  }
  .people td::before {
    content: attr(data-label);
    font-size: 11px;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--ink3);
  }
  .people td > * { justify-self: start; }
  .people td.who { display: block; padding-bottom: 6px; }
  .people td.who::before { content: none; }
}

/* The stages as bars: the width is the count, the percentage the step. */
.bars {
  list-style: none;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 6px 16px;
}
.bar {
  display: grid;
  grid-template-columns: 1fr auto 52px;
  grid-template-areas: "label count rate" "track track track";
  gap: 4px 10px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--line);
}
.bar:last-child { border-bottom: none; }
.bar-label { grid-area: label; font-size: 14px; }
.bar-count { grid-area: count; font-variant-numeric: tabular-nums; }
.bar-rate {
  grid-area: rate;
  text-align: right;
  font-size: 12.5px;
  color: var(--ink2);
  font-variant-numeric: tabular-nums;
}
.bar-track { grid-area: track; height: 8px; border-radius: 999px; background: var(--sage); overflow: hidden; }
.bar-fill { display: block; height: 100%; min-width: 0; border-radius: 999px; background: var(--pine); }

.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}
.stats div {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--r);
  padding: 11px 14px;
}
.stats dt { font-size: 12.5px; color: var(--ink2); }
.stats dd { font-size: 22px; font-weight: 700; font-variant-numeric: tabular-nums; }

.queue .line {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 8px 14px;
  flex-wrap: wrap;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
}
.queue .line:last-child { border-bottom: none; }
.queue .line b { display: block; font-weight: 600; font-size: 14.5px; }
.line-meta { display: flex; gap: 8px; align-items: center; font-size: 12.5px; color: var(--ink2); }

.form-card { margin-top: 0; margin-bottom: 14px; align-content: start; }
.form-card h3 { margin-top: 0; }

@media (min-width: 640px) {
  .tiles { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .page-head { grid-template-columns: 1fr auto; }
}

@media (min-width: 1080px) {
  .split { grid-template-columns: 1fr 1fr; align-items: start; }
}

/* ── The login ──────────────────────────────────────────────────────────── */

.gate {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 100dvh;
  padding: 20px 16px;
}

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 26px 22px;
  width: 100%;
  max-width: 380px;
}

.card .mark {
  display: block;
  color: var(--pine);
  margin-bottom: 14px;
}

.card form { margin-top: 20px; display: grid; gap: 6px; }

label {
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--ink3);
  margin-top: 10px;
}

input {
  font: inherit;
  /* 16px keeps iOS Safari from zooming into the field on focus and leaving
     the form scrolled sideways. */
  font-size: 16px;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 11px 13px;
  min-height: 44px;
  width: 100%;
}
input:focus { border-color: var(--pine); }

.card button { margin-top: 20px; width: 100%; }

.error,
.notice {
  margin-top: 16px;
  border-radius: 10px;
  padding: 10px 13px;
  font-size: 13.5px;
}
.error { background: var(--red-soft); color: var(--red); }
.notice { background: var(--pine-soft); color: var(--pine); }

/* ── Room for a column ──────────────────────────────────────────────────── */

@media (min-width: 840px) {
  .shell { display: grid; grid-template-columns: 210px 1fr; }

  .rail {
    flex-direction: column;
    align-items: stretch;
    gap: 6px;
    height: 100dvh;
    padding: 18px 14px;
  }
  .rail nav { flex-direction: column; flex: 1; overflow: visible; margin-top: 14px; }
  .rail .mark { padding: 0 8px; }
  .rail .out { margin-top: auto; }
  .rail .out button { text-align: left; padding: 9px 12px; }

  main { padding: 30px 34px 60px; }
}

/* The enrollments registry: a seat's name and WhatsApp are edited in place,
   and the onboarding buttons sit in the cell they change. */
form.inline { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; margin: 0; }
form.inline input { min-width: 0; flex: 1 1 140px; }
form.inline button { padding: 8px 14px; min-height: 40px; font-size: 13px; }
form.inline button.ghost { background: var(--sage); color: var(--ink); }
input[aria-invalid="true"] { border-color: var(--red); }
form.payment { display: grid; gap: 6px; margin-top: 12px; }
form.payment label { font-size: 13px; color: var(--ink2); margin-top: 6px; }
form.payment button { margin-top: 10px; justify-self: start; }
#payment { margin-top: 14px; }
