:root {
  color-scheme: dark;
  --ink-black: #0b0f0c;
  /* Text on a bright accent fill — a button, a badge, a "done" chip. Stays
     dark in both themes: the accent is always bright enough that dark text
     reads best on it, in dark mode or light. */
  --on-accent: #0b0f0c;
  --moss-deep: #121a13;
  --moss-line: #1d2a1e;
  --acid: #a8f03c;
  --acid-dim: #5f8f2c;
  --fail: #f0503c;
  --warn: #e0a13c;
  /* Momentum. Brighter and cooler than --warn so an entry that's moving can't
     be mistaken for the amber that marks an email address. */
  --gold: #f5cf3d;
  --plum: #a855f7;
  /* Snapchat's yellow, pulled well clear of --gold (#f5cf3d) so a platform
     heading can never be mistaken for the "in progress" state colour. */
  --snap: #ffe14d;
  --snap-dim: rgba(255, 225, 77, 0.45);
  /* Phone. Nothing else in the palette is cool-toned, which is the point. */
  --dial: #5ad1c8;
  --dial-dim: rgba(90, 209, 200, 0.45);
  --plum-dim: #6d3bb0;
  --bone: #e8efe4;
  --sage: #8fa98f;

  /* Channels only (no rgba() wrapper), so a fill's own opacity can still be
     set at the call site: rgba(var(--tint-rgb), 0.04). Dark theme tints light
     material onto a dark surface; a light theme needs the reverse. */
  --tint-rgb: 232, 239, 228;
  /* The accent's own channels, for the page's background glow. */
  --accent-rgb: 168, 240, 60;

  --font-display: "Michroma", sans-serif;
  --font-body: "Rajdhani", sans-serif;
  --font-mono: "Rajdhani", sans-serif;
  --font-code: "Michroma", sans-serif;
}
/* ================= LIGHT MODE =================
   Baby blue, white, black. A toggle, not a replacement — dark stays the
   default identity; this is what the viewer gets after choosing it, or
   returns to on their next visit if they did.

   Every colour here was checked against what it actually sits on, not
   assumed: state colours tuned for a near-black background come out too
   pale to read on white, and `--acid` on white 4.5:1) had to change; `--acid`
   as button/badge TEXT and `--acid` as a button FILL are different jobs that
   want different weights, which is why the accent's own text colour
   (`--on-accent`) flips to white here instead of staying the dark-mode value.
   ==================================================================== */
:root[data-theme="light"] {
  color-scheme: light;

  --ink-black: #ffffff;
  --moss-deep: #eaf5fc;
  --moss-line: #cfe6f3;

  --acid: #12609a;
  --acid-dim: #bfe0f5;
  /* White reads better than dark text on this accent's weight of blue —
     verified (5.16:1) rather than carried over from the dark theme's value. */
  --on-accent: #ffffff;

  --fail: #b82d24;
  --warn: #8a5906;
  --gold: #7a5f0a;
  --plum: #8226d9;
  --snap: #6b5400;
  --snap-dim: rgba(107, 84, 0, 0.35);
  --dial: #0a6f68;
  --dial-dim: rgba(10, 111, 104, 0.35);
  --plum-dim: #d9c2f7;

  --bone: #12181b;
  --sage: #48555b; /* deepened from #5b6b72 for margin against the tinted local backgrounds it keeps landing on */

  --tint-rgb: 11, 15, 12;
  --accent-rgb: 18, 96, 154; /* matches the deepened --acid, not the original */
}



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

/* Cards below set `display: flex`, which outranks the browser's own rule for
   the hidden attribute — without this, anything the scripts hide (a card panel
   that isn't the open tab, the empty inbox alert) stays on screen. */
[hidden] { display: none !important; }

body {
  background-color: var(--ink-black);
  background-image: radial-gradient(circle at 50% 120%, rgba(var(--accent-rgb), 0.05) 0%, transparent 55%);
  color: var(--bone);
  font-family: var(--font-body);
  font-weight: 500;
  font-size: 1.05rem;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

#bg-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  pointer-events: none;
}

.site-header,
main,
.site-footer {
  position: relative;
  z-index: 1;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

/* ---------- header ---------- */

.site-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.4rem 2.2rem;
  border-bottom: 1px solid var(--moss-line);
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  font: inherit;
  border-radius: 6px;
  transition: opacity 160ms ease;
}

.brand:hover { opacity: 0.75; }
.brand:focus-visible { outline: 2px solid var(--acid); outline-offset: 3px; }

.brand-mark { width: 30px; height: 30px; color: var(--acid); }

.brand-name {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.04em;
}

.header-tag {
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--sage);
}

.header-right {
  display: flex;
  align-items: center;
  gap: 14px;
}

/* A pill switch, not a checkbox — it reads as an action ("go light") rather
   than a setting to configure. The icon is drawn in CSS so it recolours with
   the theme for free, the same as everything else. */
.theme-toggle {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 36px;
  padding: 0 12px 0 8px;
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  background: rgba(var(--tint-rgb), 0.04);
  color: var(--sage);
  font-family: var(--font-code);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
}
.theme-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}
.theme-toggle:hover { border-color: rgba(var(--tint-rgb), 0.3); color: var(--bone); }

/* A small sun/moon, swapped by CSS content rather than JS, so the icon can
   never fall out of sync with the label next to it. */
.theme-toggle-icon {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: currentColor;
  /* The moon's crescent is cut from a solid circle with a second circle
     offset over it — the classic trick, done in one background instead of
     two layered elements. */
  box-shadow: inset 4px -2px 0 0 var(--moss-deep);
}
.theme-toggle[aria-pressed="true"] .theme-toggle-icon {
  /* Sun, once already in light mode: a plain dot reads clearly enough at this
     size without needing rays, and stays crisp instead of fuzzy. */
  box-shadow: none;
}

/* The "waiting on a reply" banner's pale-lavender text was tuned for a
   near-black panel (10.6:1 there). On light mode's pale plum-tinted panel the
   same value comes out close to invisible — verified at ~1.3:1. Deepened for
   this theme only, rather than changing the shared rule and giving dark mode
   back a worse number than it already had. */
:root[data-theme="light"] .pa-head,
:root[data-theme="light"] .pa-chip {
  color: var(--plum);
}
:root[data-theme="light"] .priority-alert {
  background: rgba(130, 38, 217, 0.06);
}
:root[data-theme="light"] .pa-chip {
  background: rgba(130, 38, 217, 0.1);
}

/* The rest of the purple family — the announcement, the cryptic gate line,
   the priority chips and tags. All of it was tuned as pale lavender text plus
   a glowing text-shadow against near-black, verified in a comment right on
   `.card-announce` at "6.7:1 on this background." That background is white
   here, and the same pale values plus a colourful blur read as smudged rather
   than magical. Deepened to `--plum`, and the glow pulled back rather than
   removed outright — a flat colour change would lose the "us talking to you"
   distinction from the ordering flow entirely. */
:root[data-theme="light"] .announce-tag,
:root[data-theme="light"] .announce-text,
:root[data-theme="light"] .cryptic-text,
:root[data-theme="light"] .announce-headline,
:root[data-theme="light"] .ai-title,
:root[data-theme="light"] .ai-why,
:root[data-theme="light"] .card-announce .announce-text,
:root[data-theme="light"] .pa-chip-age,
:root[data-theme="light"] .plum-tag,
:root[data-theme="light"] .link-btn.plum,
:root[data-theme="light"] .tl-row.is-unread .tl-handle {
  color: var(--plum);
}
:root[data-theme="light"] .announce-more {
  color: #ffffff;
  background: var(--plum);
}
:root[data-theme="light"] .announce-more:hover { background: #6b1cae; color: #fff; }
:root[data-theme="light"] .announce-text,
:root[data-theme="light"] .cryptic-text {
  text-shadow: none;
}
:root[data-theme="light"] .announce-text,
:root[data-theme="light"] .cryptic-text {
  animation: none;
  opacity: 1;
}

/* The gate's two fields punch a dark recessed hole into the page — black at
   35% opacity plus a heavy inset shadow, so they read as "carved into" a dark
   surface. On white that same black becomes a solid mid-grey box with a dark
   vignette inside it, which reads as a DISABLED field rather than an inviting
   one — the opposite of what a front door should look like. Light mode gets
   the same idea at a fraction of the strength: a faint tint, a thin shadow. */
:root[data-theme="light"] .gate-ticket,
:root[data-theme="light"] .gate-handle-wrap {
  background: rgba(var(--tint-rgb), 0.035);
  box-shadow: inset 0 1px 3px rgba(var(--tint-rgb), 0.08);
}
:root[data-theme="light"] .gate-ticket:focus {
  box-shadow: inset 0 1px 3px rgba(var(--tint-rgb), 0.08), 0 0 0 3px rgba(var(--accent-rgb), 0.16);
}

/* Two more measured rather than assumed. `.gate-label` uses `--acid-dim` —
   a token that is border-only everywhere else in the sheet — which in light
   mode is a pale border blue, not a text colour: 1.38:1 against white,
   functionally invisible on the two fields that matter most on the page.
   `.gate-foot`'s 0.85 opacity on top of `--sage` (5:1 on its own) pulls it
   under 4.5:1. Both measured after the fact, not eyeballed. */
:root[data-theme="light"] .gate-label {
  color: var(--acid);
}
:root[data-theme="light"] .gate-foot {
  opacity: 1;
}

/* The entry-state colours on the customer's card and the desk's chips: an
   entry marked "in progress" or "unsuccessful" tints both its background AND
   its own text to a pale version of the state colour (`#ffe89a` gold,
   `#ffb3a8` salmon) — legible on a near-black chip, close to invisible on the
   pale tinted chip a light theme gives it (measured at 1.1:1 for the working
   text). Both now read the same deepened `--gold`/`--fail` used everywhere
   else instead of a value that only worked on the old background. */
:root[data-theme="light"] .accounts li.is-working,
:root[data-theme="light"] .tpe.is-working {
  color: var(--gold);
}
:root[data-theme="light"] .accounts li.is-failed,
:root[data-theme="light"] .tpe.is-failed,
:root[data-theme="light"] .acct-notice strong {
  color: var(--fail);
}
/* The branch-count badge ("+2") is fixed blue everywhere else, which is fine
   on a plain or white chip. Inside a working/failed chip in light mode that
   blue sits on a tinted background it wasn't measured against (3.91:1) — so
   here it follows the entry's own state colour instead, the same "state
   decides" rule already applied to the text next to it. */
:root[data-theme="light"] .accounts li.is-working .count-badge {
  color: var(--gold);
  border-color: var(--gold);
}
:root[data-theme="light"] .accounts li.is-failed .count-badge {
  color: var(--fail);
  border-color: var(--fail);
}

/* The success banner's sub-line sits on a blue-tinted background rather than
   the plain panel `--sage` was measured against — 4.33:1 there, just under
   the line. Deepened for this one spot rather than moving `--sage` itself,
   which reads fine everywhere else it's used. */
:root[data-theme="light"] .success-banner-sub {
  color: #425058;
}

/* Same story as the banner sub-line above: `--sage` measured fine against the
   plain panel, and drops under 4.5:1 (4.14) when the toggle sits inside one of
   the state-tinted chips instead. Same fix. */
:root[data-theme="light"] .acct-branch-toggle {
  color: #425058;
}

/* ---------- shared ---------- */

main { flex: 1; width: 100%; max-width: 960px; margin: 0 auto; padding: 0 1.4rem; }

.eyebrow {
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.24em;
  color: var(--acid);
}

/* ---------- lookup view ---------- */

.lookup {
  text-align: center;
  padding: 16vh 0 4rem;
}

.lookup-title {
  font-family: var(--font-display);
  font-size: clamp(1.9rem, 5vw, 3.1rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 1.1rem 0 0.9rem;
}

.lookup-sub { color: var(--sage); font-size: 1.05rem; font-weight: 400; }

.lookup-form {
  display: flex;
  justify-content: center;
  gap: 0.8rem;
  margin-top: 2.6rem;
  flex-wrap: wrap;
}

.lookup-form input {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 4px;
  color: var(--bone);
  font-family: var(--font-code);
  font-size: 0.95rem;
  letter-spacing: 0.12em;
  padding: 0.85rem 1.2rem;
  width: min(300px, 70vw);
  text-transform: uppercase;
}

.lookup-form input::placeholder { color: #3c4a3c; }

.lookup-form input:focus-visible,
button:focus-visible {
  outline: 2px solid var(--acid);
  outline-offset: 2px;
}

.lookup-form button {
  background: var(--acid);
  border: none;
  border-radius: 4px;
  color: var(--on-accent);
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 0.95rem 1.6rem;
  transition: filter 160ms ease, box-shadow 160ms ease;
}

.lookup-form button:hover { box-shadow: 0 0 18px rgba(var(--accent-rgb), 0.4); }

.lookup-form button:hover { filter: brightness(1.12); }

.lookup-error { color: var(--warn); margin-top: 1.4rem; font-size: 0.95rem; }

.lookup-cta {
  margin-top: 2.2rem;
  color: var(--sage);
  font-size: 0.95rem;
}

/* ---------- announcement ---------- */
/*
 * Sits under the "submit an order" line on the home page. Purple so it reads
 * as news rather than as part of the ordering flow, which is all green.
 */

.announce {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 2.6rem;
  padding: 0.85rem 1.4rem;
  max-width: 100%;
  border: 1px solid var(--plum-dim);
  /* Half the one-line height: reads as a pill for a short announcement, as a
     rounded card when a longer one wraps. */
  border-radius: 22px;
  background: rgba(168, 85, 247, 0.08);
  box-shadow: 0 0 26px rgba(168, 85, 247, 0.16);
}

.announce-tag {
  flex-shrink: 0;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: #e2ccff;
  background: rgba(168, 85, 247, 0.22);
  border: 1px solid var(--plum-dim);
  border-radius: 999px;
  padding: 0.2rem 0.6rem;
}

/* Uppercased in CSS, not in the markup, so whoever writes the next
   announcement can type it normally and still get the house style. */
.announce-text {
  color: #d9b3ff;
  font-family: var(--font-code);
  font-size: clamp(0.7rem, 2.2vw, 0.88rem);
  text-transform: uppercase;
  letter-spacing: 0.08em;
  text-shadow: 0 0 14px rgba(168, 85, 247, 0.75), 0 0 34px rgba(168, 85, 247, 0.35);
  animation: announce-glow 3.2s ease-in-out infinite alternate;
}

@keyframes announce-glow {
  from { text-shadow: 0 0 10px rgba(168, 85, 247, 0.5), 0 0 26px rgba(168, 85, 247, 0.2); }
  to { text-shadow: 0 0 18px rgba(168, 85, 247, 0.95), 0 0 42px rgba(168, 85, 247, 0.5); }
}

@media (max-width: 460px) {
  .announce { gap: 0.6rem; padding: 0.75rem 1.1rem; }
}

/* ---------- the cryptic line (front door only) ---------- */
/*
 * Says nothing and means to. It sits under the sign-in form, where the only
 * people who can see it are the ones who haven't got a card open — so it's
 * atmosphere, not information. Anything anyone actually needs to know goes in
 * the announcement, which reaches the cards.
 */

.cryptic {
  margin-top: 3.2rem;
  display: flex;
  justify-content: center;
}

.cryptic-text {
  color: #d9b3ff;
  font-family: var(--font-code);
  font-size: clamp(0.78rem, 2.6vw, 1.05rem);
  text-transform: lowercase;
  letter-spacing: 0.42em;
  /* The tracking pushes the line off-centre; pull back by one gap. */
  text-indent: 0.42em;
  text-shadow: 0 0 16px rgba(168, 85, 247, 0.8), 0 0 40px rgba(168, 85, 247, 0.4);
  animation: cryptic-breathe 4.6s ease-in-out infinite alternate;
}

@keyframes cryptic-breathe {
  from { opacity: 0.55; text-shadow: 0 0 10px rgba(168, 85, 247, 0.4), 0 0 28px rgba(168, 85, 247, 0.16); }
  to { opacity: 1; text-shadow: 0 0 22px rgba(168, 85, 247, 1), 0 0 52px rgba(168, 85, 247, 0.55); }
}

/* ---------- the announcement, on a card ---------- */
/*
 * Purple all the way through — the pill, the rule, the words. Green is the
 * ordering flow; purple is us talking to you, and the two shouldn't be
 * mistaken for each other.
 *
 * The text is #bd82ff, which is 6.7:1 on this background — comfortably past
 * the 4.5:1 that body text needs, so it reads as purple without becoming a
 * thing you have to squint at.
 */

.card-announce {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  width: 100%;
  margin: 0 0 1.6rem;
  padding: 1rem 1.15rem;
  text-align: left;
  border-color: var(--plum);
  background: rgba(168, 85, 247, 0.12);
  border-radius: 12px;
  box-shadow: 0 0 30px rgba(168, 85, 247, 0.22);
}

.card-announce { flex-direction: column; position: relative; }
.announce-head { display: flex; align-items: flex-start; gap: 0.85rem; width: 100%; }
/* Room for the dismiss button, which is pinned to the corner on wide screens
   so it never competes with the thing you actually want them to press. */
.announce-head { padding-right: 5.5rem; }
.announce-body { flex: 1; min-width: 0; }

.announce-headline {
  font-family: var(--font-display);
  font-size: clamp(0.95rem, 2.6vw, 1.15rem);
  line-height: 1.3;
  letter-spacing: -0.01em;
  color: #e7d5ff;
  margin-bottom: 0.35rem;
}

/* The thing they click. Full width and clearly a control — the list under it
   is the point of the announcement, not an extra. */
.announce-more {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  width: 100%;
  margin-top: 0.9rem;
  background: rgba(168, 85, 247, 0.28);
  border: 1px solid var(--plum);
  border-radius: 8px;
  color: #f3e6ff;
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  padding: 0.72rem 0.9rem;
  transition: background 160ms ease, color 160ms ease;
}

.announce-more:hover { background: rgba(168, 85, 247, 0.42); color: #fff; }
.announce-more:focus-visible { outline: 2px solid var(--plum); outline-offset: 2px; }

.announce-chevron { transition: transform 200ms ease; font-size: 0.68rem; }
.card-announce.is-open .announce-chevron { transform: rotate(180deg); }

.announce-items {
  list-style: none;
  width: 100%;
  margin-top: 0.9rem;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
}

.announce-items li {
  border-left: 2px solid var(--plum-dim);
  padding-left: 0.9rem;
}

.ai-title {
  color: #e7d5ff;
  font-size: 0.95rem;
  font-weight: 600;
  line-height: 1.35;
}

/* The reason it changed, set quieter than the change itself. */
.ai-why {
  color: #bd82ff;
  font-size: 0.85rem;
  font-weight: 400;
  line-height: 1.5;
  margin-top: 0.2rem;
}

.card-announce .announce-tag {
  display: inline-block;
  margin-bottom: 0.45rem;
}

.card-announce .announce-text {
  animation: none;
  text-transform: none;
  font-family: var(--font-body);
  font-size: 0.95rem;
  letter-spacing: 0.01em;
  line-height: 1.5;
  color: #bd82ff;
  text-shadow: none;
}

/* The unread signal. It draws the eye to the block on arrival, then settles —
   a dot that pulses forever becomes wallpaper, and the point is to be noticed
   once and then acted on. */
.announce-pulse {
  flex-shrink: 0;
  width: 9px;
  height: 9px;
  margin-top: 0.45rem;
  border-radius: 50%;
  background: var(--plum);
  box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.7);
  animation: announce-ping 1.8s ease-out 6;
}

@keyframes announce-ping {
  0% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.75); }
  70% { box-shadow: 0 0 0 12px rgba(168, 85, 247, 0); }
  100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); }
}

/* An obvious thing to press, rather than a small × you have to find. It sits in
   the corner on a wide screen and drops to the bottom on a narrow one, where
   stacking it above "See what's new" would have put dismiss ahead of the
   primary action. */
.announce-ack {
  position: absolute;
  top: 1rem;
  right: 1.15rem;
  background: none;
  border: 1px solid var(--plum-dim);
  border-radius: 999px;
  color: #a98fc9;
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding: 0.5rem 0.9rem;
  transition: background 160ms ease, border-color 160ms ease, color 160ms ease;
}

.announce-ack:hover { background: rgba(168, 85, 247, 0.2); border-color: var(--plum); color: #e2ccff; }
.announce-ack:focus-visible { outline: 2px solid var(--plum); outline-offset: 3px; }

@media (max-width: 560px) {
  .announce-head { padding-right: 0; }
  .announce-ack {
    position: static;
    width: 100%;
    margin-top: 0.8rem;
  }
}

.text-link {
  background: none;
  border: none;
  color: var(--acid);
  cursor: pointer;
  font-family: var(--font-body);
  font-size: inherit;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.text-link:hover { filter: brightness(1.15); }

/* ---------- submit view ---------- */

.submit { padding: 3rem 0 4rem; max-width: 620px; margin: 0 auto; }

.submit-title {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 4.5vw, 2.4rem);
  line-height: 1.2;
  letter-spacing: -0.01em;
  margin: 1.1rem 0 0.8rem;
}

.submit-sub { color: var(--sage); font-size: 1.0rem; font-weight: 400; max-width: 52ch; }

.submit-form { margin-top: 2.4rem; display: flex; flex-direction: column; gap: 1.8rem; }

.field-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 0.6rem;
}

.field > label,
.field-head label {
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.02em;
  display: block;
  margin-bottom: 0.6rem;
}

.field-head label { margin-bottom: 0; }

.optional { color: var(--sage); font-weight: 300; }

.required {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: var(--acid);
  border: 1px solid var(--acid-dim);
  border-radius: 3px;
  padding: 0.1rem 0.4rem;
  margin-left: 0.4rem;
  vertical-align: middle;
}

.counter {
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--sage);
}

.counter.full { color: var(--acid); }

/* ---------- entry fields (Instagram / TikTok / X / Email) ---------- */
/*
 * Four kinds of entry, each with its own colour and its own name on the label.
 * Two to a row on anything wide enough, so four fields read as one block
 * rather than as a long form.
 */

.field-title {
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 500;
  letter-spacing: 0.02em;
}

.platform-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1rem;
}

@media (max-width: 560px) {
  .platform-grid { grid-template-columns: 1fr; }
}

.platform-label {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--sage);
  margin-bottom: 0.4rem;
}

.is-instagram .platform-label { color: var(--acid); }
.is-tiktok .platform-label { color: var(--plum); }
.is-x .platform-label { color: var(--bone); }
.is-email .platform-label { color: var(--warn); }

/* Sits at 0 until the field has something in it, so an empty platform reads as
   optional rather than as a count you're failing to fill. */
.platform-count {
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  color: var(--sage);
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  padding: 0.05rem 0.45rem;
}

.is-instagram .platform-count.has-any { color: var(--acid); border-color: var(--acid-dim); }
.is-tiktok .platform-count.has-any { color: var(--plum); border-color: var(--plum-dim); }
.is-x .platform-count.has-any { color: var(--bone); border-color: #52604f; }
.is-email .platform-count.has-any { color: var(--warn); border-color: rgba(224, 161, 60, 0.5); }

.chip-input {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 6px;
  padding: 0.6rem;
  cursor: text;
  transition: border-color 160ms ease;
}

.chip-input:focus-within { border-color: var(--acid-dim); }
.is-tiktok .chip-input:focus-within { border-color: var(--plum-dim); }
.is-x .chip-input:focus-within { border-color: #52604f; }
.is-email .chip-input:focus-within { border-color: rgba(224, 161, 60, 0.55); }

.chips { list-style: none; display: flex; flex-wrap: wrap; gap: 0.5rem; }

.chips:not(:empty) { margin-bottom: 0.55rem; }

.chip {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: rgba(var(--accent-rgb), 0.08);
  border: 1px solid var(--acid-dim);
  border-radius: 999px;
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  padding: 0.28rem 0.4rem 0.28rem 0.75rem;
}

.chip button {
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  padding: 0 0.2rem;
}

.chip button:hover { color: var(--acid); }

.is-tiktok .chip {
  background: rgba(168, 85, 247, 0.12);
  border-color: var(--plum-dim);
}

.is-tiktok .chip button:hover { color: var(--plum); }

.is-x .chip {
  background: rgba(var(--tint-rgb), 0.07);
  border-color: #52604f;
}

.is-x .chip button:hover { color: var(--bone); }

.is-email .chip {
  background: rgba(224, 161, 60, 0.1);
  border-color: rgba(224, 161, 60, 0.45);
}

.is-email .chip button:hover { color: var(--warn); }

/* An email is the whole address; the others are handles and read better
   narrower. */
.is-email .chip { font-size: 0.8rem; }

.chip-input input {
  background: none;
  border: none;
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: 0.95rem;
  padding: 0.35rem 0.4rem;
  width: 100%;
  outline: none;
}

.chip-input input::placeholder { color: #3c4a3c; }

.text-field {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 6px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.75rem 0.9rem;
  width: 100%;
}

.text-field:focus-visible { outline: 2px solid var(--acid); outline-offset: 1px; }

.field-note { color: var(--sage); font-size: 0.8rem; margin-top: 0.5rem; }
.field-note.error { color: var(--warn); }

.submit-btn {
  background: var(--acid);
  border: none;
  border-radius: 5px;
  color: var(--on-accent);
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 0.95rem 1.7rem;
  align-self: flex-start;
  transition: filter 160ms ease, box-shadow 160ms ease;
}

.submit-btn:hover { filter: brightness(1.08); box-shadow: 0 0 18px rgba(var(--accent-rgb), 0.4); }

.submit-btn:disabled { background: var(--moss-line); color: var(--sage); cursor: not-allowed; }

/* ---------- confirmation view ---------- */

.confirm { padding: 8vh 0 4rem; max-width: 560px; margin: 0 auto; text-align: center; }

.confirm-mark { color: var(--acid); width: 54px; margin: 0 auto 1.4rem; }
.confirm-mark svg { width: 100%; }

.confirm-title {
  font-family: var(--font-display);
  font-size: clamp(1.5rem, 4.5vw, 2.2rem);
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 1rem 0 0.7rem;
}

.confirm-sub { color: var(--sage); }

.code-plate {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  padding: 1.4rem 1.6rem;
  margin: 2.4rem 0 0.9rem;
}

.code-label {
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.22em;
  color: var(--acid);
}

.code-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  margin-top: 0.7rem;
}

/* Codes are SRP- plus eight characters now, and Michroma is a wide face — sized
   to keep one on a single line down to a narrow phone, and allowed to break at
   the dashes rather than mid-group if it ever can't. */
.code-value {
  font-family: var(--font-code);
  font-size: clamp(0.95rem, 4vw, 1.6rem);
  letter-spacing: 0.06em;
  white-space: nowrap;
}

@media (max-width: 380px) {
  .code-value { white-space: normal; }
  .code-row { flex-direction: column; gap: 0.7rem; }
}

.copy-btn {
  background: none;
  border: 1px solid var(--acid-dim);
  border-radius: 4px;
  color: var(--acid);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  padding: 0.4rem 0.8rem;
  transition: background 160ms ease;
}

.copy-btn:hover { background: rgba(var(--accent-rgb), 0.1); }
.copy-btn.copied { color: var(--on-accent); background: var(--acid); border-color: var(--acid); }

.confirm-hint { color: var(--sage); font-size: 0.85rem; }

.confirm-actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 1.2rem;
  margin-top: 2.6rem;
}

.confirm-links {
  display: flex;
  gap: 1.6rem;
  align-items: center;
}

/* ---------- the card ---------- */

.card-view { padding: 2.4rem 0 4rem; }

.back-link {
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 0.9rem;
  padding: 0.2rem 0;
}

.back-link:hover { color: var(--acid); }

.submit .back-link { display: inline-block; margin-bottom: 1.4rem; }

/* The header over the selected order's timeline. */
.co-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  flex-wrap: wrap;
  gap: 1rem;
  margin: 0 0 1.2rem;
}

.order-code {
  font-family: var(--font-code);
  font-size: clamp(1.2rem, 3.4vw, 1.7rem);
  letter-spacing: 0.05em;
  margin-top: 0.5rem;
}

/* ---------- serpent card ---------- */

.serpent-card {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 1.4rem 1.6rem 1.2rem;
}

#serpent-svg {
  width: 100%;
  max-width: 560px;
  margin: 0 auto;
  display: block;
}

#serpent-progress {
  transition: stroke-dashoffset 1100ms cubic-bezier(0.6, 0, 0.3, 1);
}

.status-labels {
  list-style: none;
  display: flex;
  justify-content: space-between;
  max-width: 560px;
  margin: 0 auto;
  padding: 0.4rem 0.5rem 0;
}

.status-labels li {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--sage);
  flex: 1;
  text-align: center;
}

.status-labels li:first-child { text-align: left; }
.status-labels li:last-child { text-align: right; }

.status-labels li.done { color: var(--bone); }
.status-labels li.current { color: var(--acid); }

/* ---------- state pill ---------- */

.state-pill {
  display: inline-block;
  margin-top: 0.8rem;
  font-family: var(--font-code);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  padding: 0.38rem 0.8rem;
  border-radius: 999px;
  border: 1px solid;
}

.state-pill.is-active { color: var(--acid); border-color: var(--acid-dim); background: rgba(var(--accent-rgb), 0.08); }
.state-pill.is-complete { color: var(--on-accent); border-color: var(--acid); background: var(--acid); }

/* ---------- message from admin ---------- */

.note-card {
  background: rgba(var(--accent-rgb), 0.06);
  border: 1px solid var(--acid-dim);
  border-left: 3px solid var(--acid);
  border-radius: 8px;
  padding: 1.1rem 1.3rem;
  margin-top: 1.2rem;
}

.note-card .eyebrow { margin-bottom: 0.5rem; }

.note-body {
  color: var(--bone);
  line-height: 1.55;
  white-space: pre-wrap;
}

.gc-more { color: var(--sage); font-size: 0.8rem; margin-top: 0.8rem; }

/* ---------- card header ---------- */

.card-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
}

.ct-id { display: flex; align-items: center; gap: 1rem; }

.ct-avatar {
  flex-shrink: 0;
  width: 54px;
  height: 54px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--acid-dim);
  background: rgba(var(--accent-rgb), 0.08);
  box-shadow: 0 0 22px rgba(var(--accent-rgb), 0.14);
  color: var(--acid);
  font-family: var(--font-display);
  font-size: 1rem;
  letter-spacing: 0.02em;
}

.ct-handle {
  font-family: var(--font-display);
  font-size: clamp(1.2rem, 3.6vw, 1.8rem);
  letter-spacing: -0.01em;
  margin: 0.35rem 0 0.3rem;
  overflow-wrap: anywhere;
}

.ct-sub { color: var(--sage); font-size: 0.85rem; font-weight: 400; }

/* ---------- card tabs ---------- */

.card-tabs {
  display: flex;
  gap: 0.3rem;
  margin: 1.8rem 0 1.6rem;
  border-bottom: 1px solid var(--moss-line);
  overflow-x: auto;
  scrollbar-width: none;
}

.card-tabs::-webkit-scrollbar { display: none; }

.card-tab {
  position: relative;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-shrink: 0;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--sage);
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding: 0.75rem 0.9rem;
  margin-bottom: -1px;
  transition: color 160ms ease, border-color 160ms ease;
}

.card-tab:hover { color: var(--bone); }
.card-tab:focus-visible { outline: 2px solid var(--acid); outline-offset: -2px; }
.card-tab.is-on { color: var(--acid); border-bottom-color: var(--acid); }

.tab-badge {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0;
  color: var(--sage);
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
}

.card-tab.is-on .tab-badge { color: var(--acid); border-color: var(--acid-dim); }

.tab-badge.is-new {
  color: var(--on-accent);
  background: var(--acid);
  border-color: var(--acid);
  font-weight: 700;
}

.card-tab.is-on .tab-badge.is-new { color: var(--on-accent); }

.panel-intro {
  color: var(--sage);
  font-size: 0.9rem;
  font-weight: 400;
  max-width: 60ch;
  margin-bottom: 1.3rem;
}

/* Shown when someone asks for a new order while one is still open. */
.open-order-note {
  background: rgba(168, 85, 247, 0.1);
  border: 1px solid var(--plum-dim);
  border-left: 3px solid var(--plum);
  border-radius: 8px;
  color: #e7d5ff;
  font-size: 0.9rem;
  line-height: 1.5;
  padding: 0.85rem 1rem;
  margin-bottom: 1.2rem;
}

/* ---------- order picker ---------- */

.order-picker {
  list-style: none;
  display: flex;
  gap: 0.5rem;
  flex-wrap: wrap;
  margin-bottom: 1.4rem;
}

.op-chip {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 6px;
  color: var(--bone);
  cursor: pointer;
  font-family: var(--font-body);
  padding: 0.5rem 0.8rem;
  transition: border-color 160ms ease, background 160ms ease;
}

.op-chip:hover { border-color: var(--acid-dim); }
.op-chip:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }
.op-chip.is-on { border-color: var(--acid); background: rgba(var(--accent-rgb), 0.07); }

.op-code {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.05em;
  color: var(--acid);
}

.op-state {
  font-family: var(--font-code);
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--sage);
}

.op-state.is-complete { color: var(--acid); }

.acct-placed { color: var(--sage); font-size: 0.8rem; font-weight: 400; margin-top: 0.5rem; }
.empty-line { color: var(--sage); font-size: 0.9rem; font-weight: 400; margin-top: 0.7rem; }

/* ---------- the thread ---------- */

.thread {
  display: flex;
  flex-direction: column;
  gap: 1rem;
  max-height: 52vh;
  overflow-y: auto;
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 1.3rem 1.4rem;
}

.thread-empty { color: var(--sage); font-size: 0.9rem; font-weight: 400; text-align: center; padding: 1.6rem 0; }

.msg { display: flex; flex-direction: column; max-width: 82%; }
.msg.is-mine { align-self: flex-end; align-items: flex-end; }
.msg.is-desk { align-self: flex-start; align-items: flex-start; }

.msg-bubble {
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 0.75rem 1rem;
  background: var(--ink-black);
}

/* The desk's side is the one that carries news, so it gets the green. */
.msg.is-desk .msg-bubble {
  border-color: var(--acid-dim);
  background: rgba(var(--accent-rgb), 0.07);
}

.msg-body { line-height: 1.5; overflow-wrap: anywhere; }

.msg-meta {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--sage);
  font-size: 0.72rem;
  font-weight: 400;
  margin-top: 0.35rem;
  padding: 0 0.2rem;
}

.msg-about {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.04em;
  color: var(--acid);
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
}

/* ---------- composer ---------- */

.composer { margin-top: 1.2rem; }

.composer textarea {
  width: 100%;
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 1rem;
  line-height: 1.5;
  padding: 0.9rem 1.1rem;
  resize: vertical;
}

.composer textarea::placeholder { color: #3c4a3c; }
.composer textarea:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }

.composer-foot {
  display: flex;
  align-items: center;
  gap: 0.9rem;
  flex-wrap: wrap;
  margin-top: 0.8rem;
}

.composer-about {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  color: var(--sage);
  font-size: 0.8rem;
  font-weight: 400;
}

.composer-about select {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 5px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.85rem;
  padding: 0.35rem 0.5rem;
}

.composer-count { color: var(--sage); font-size: 0.72rem; font-weight: 400; margin-left: auto; }

.composer .submit-btn { width: auto; padding: 0.75rem 1.6rem; }

.composer-error { color: var(--warn); font-size: 0.85rem; margin-top: 0.7rem; }

@media (max-width: 520px) {
  .msg { max-width: 94%; }
  .composer-count { margin-left: 0; }
  .composer .submit-btn { flex: 1; }
}

/* ---------- detail cards ---------- */

.detail-stack {
  display: flex;
  flex-direction: column;
  gap: 1.2rem;
  margin-top: 1.2rem;
}

.count-badge {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--acid);
  border: 1px solid var(--acid-dim);
  border-radius: 999px;
  padding: 0.05rem 0.5rem;
  vertical-align: middle;
  margin-left: 0.4rem;
}

.detail-card {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  padding: 1.5rem 1.6rem;
}

.detail-card h3 {
  font-family: var(--font-code);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--bone);
  margin-bottom: 1.1rem;
}

.history { list-style: none; }

.history li {
  border-left: 2px solid var(--moss-line);
  padding: 0 0 1.1rem 1rem;
  position: relative;
}

.history li::before {
  content: "";
  position: absolute;
  left: -5px;
  top: 4px;
  width: 8px; height: 8px;
  border-radius: 50%;
  background: var(--acid-dim);
}

.history li:first-child::before { background: var(--acid); }
.history li:last-child { padding-bottom: 0; }
.history li.h-failed::before { background: var(--fail); }
.history li.h-failed .h-status { color: var(--fail); }

.history .h-status { font-weight: 400; }
.history .h-when {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--sage);
  margin-top: 0.15rem;
}

.items { list-style: none; }

.items li {
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.4rem 0;
  border-bottom: 1px dashed var(--moss-line);
}

.items li:last-child { border-bottom: none; }

.accounts { list-style: none; display: flex; flex-wrap: wrap; gap: 0.5rem; }

.accounts li {
  background: rgba(var(--tint-rgb), 0.04);
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  color: var(--bone);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  padding: 0.3rem 0.8rem;
}

.accounts li::before { content: "@"; color: var(--sage); }

/* TikTok accounts are purple, Instagram green (the default above). The platform
   is always named alongside, so the colour is a shortcut, never the only
   signal. */


/* An email address carries its own @ — it doesn't want another in front. */
.accounts.is-email li::before,
.accounts.is-phone li::before { content: none; }

/* Only shown while an order can still be trimmed. */
.acct-remove {
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-size: 1rem;
  line-height: 1;
  margin-left: 0.45rem;
  padding: 0 0.1rem;
}

.acct-remove:hover { color: var(--fail); }
.acct-remove:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }

/* ---------- tap targets ---------- */
/*
 * Several controls are deliberately small — an × on a chip shouldn't be the
 * size of the chip. A pseudo-element extends what your thumb can hit without
 * changing what the eye sees or how anything lays out, which keeps the visual
 * density and still clears the 24px floor on a phone.
 */

.acct-remove,
.tpe-cancel,
.chip button,
.announce-more .announce-chevron,
.bs-clear {
  position: relative;
}

.acct-remove::after,
.tpe-cancel::after,
.chip button::after,
.bs-clear::after {
  content: "";
  position: absolute;
  inset: -0.55rem -0.45rem;
}

/* ---------- an entry that's moving ---------- */
/*
 * Yellow, and the only chip on either side that glows. Email addresses are
 * amber and flat; this pulses light. The difference between "nobody has
 * touched this" and "this is moving" was invisible before — a plain chip read
 * as both.
 */

.accounts li.is-working,
.tpe.is-working {
  background: rgba(245, 207, 61, 0.12);
  border-color: var(--gold);
  color: #ffe89a;
  box-shadow: 0 0 14px rgba(245, 207, 61, 0.28);
}

.accounts li.is-working::before { color: var(--gold); }
.acct-flag.is-working,
.tpe.is-working .tpe-flag { color: var(--gold); }

/* ---------- an entry we couldn't get ---------- */
/*
 * Red beats the platform colour, on every list, on both sides of the wall.
 * There is no order-level "failed" any more: one username that didn't work is
 * one username to replace, not a verdict on the whole order.
 */

.accounts li.is-failed {
  background: rgba(240, 80, 60, 0.1);
  border-color: var(--fail);
  color: #ffb3a8;
}

/* Only the handle is struck through. A strike on the whole row would run
   through the "couldn't get" label too, and CSS gives a child no way to opt
   back out of an ancestor's text-decoration. */
.accounts li.is-failed .acct-text {
  text-decoration: line-through;
  text-decoration-color: rgba(240, 80, 60, 0.7);
}

.accounts li.is-failed::before { color: var(--fail); }

.acct-flag {
  margin-left: 0.5rem;
  font-family: var(--font-code);
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--fail);
  text-decoration: none;
  vertical-align: middle;
}

.acct-notice {
  background: rgba(240, 80, 60, 0.08);
  border: 1px solid rgba(240, 80, 60, 0.45);
  border-left: 3px solid var(--fail);
  border-radius: 6px;
  color: var(--bone);
  font-size: 0.9rem;
  line-height: 1.5;
  padding: 0.8rem 1rem;
  margin-top: 0.9rem;
}

.acct-notice strong { color: #ffb3a8; font-weight: 600; }

/* An entry the desk has finished, on the customer's card. */
.accounts li.is-done {
  background: rgba(var(--accent-rgb), 0.13);
  border-color: var(--acid);
}

.acct-flag.is-done { color: var(--acid); }

/* Kind heading above each block of chips (the customer's card). */
.acct-group-label {
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin: 1.1rem 0 0.5rem;
}

.acct-group-label:first-of-type { margin-top: 0; }

/* Green means Instagram and purple means TikTok everywhere a platform is
   named — on the order form, the customer's card and the desk alike. */
.acct-group-label.is-instagram { color: var(--acid); }
.acct-group-label.is-tiktok { color: var(--plum); }
.acct-group-label.is-tiktok .count-badge { color: var(--plum); border-color: var(--plum-dim); }
.acct-group-label.is-x { color: var(--bone); }
.acct-group-label.is-x .count-badge { color: var(--bone); border-color: #52604f; }
.acct-group-label.is-email { color: var(--warn); }
.acct-group-label.is-email .count-badge { color: var(--warn); border-color: rgba(224, 161, 60, 0.5); }
.acct-group-label.is-snapchat { color: var(--snap); }
.acct-group-label.is-snapchat .count-badge { color: var(--snap); border-color: var(--snap-dim); }
.acct-group-label.is-phone { color: var(--dial); }
.acct-group-label.is-phone .count-badge { color: var(--dial); border-color: var(--dial-dim); }

/* ---------- adding to an order from the card ---------- */

.add-row {
  display: flex;
  gap: 0.6rem;
  flex-wrap: wrap;
  align-items: center;
  margin-top: 0.9rem;
}

.add-row select {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 6px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.72rem 0.7rem;
}

.add-row .text-field { flex: 1 1 12rem; width: auto; }
.add-row .submit-btn { padding: 0.8rem 1.5rem; align-self: stretch; }

@media (max-width: 520px) {
  .add-row { flex-direction: column; align-items: stretch; }
  .add-row .text-field { flex: 0 0 auto; }
}

/* ---------- footer ---------- */

.site-footer {
  border-top: 1px solid var(--moss-line);
  color: var(--sage);
  font-size: 0.8rem;
  padding: 1.3rem 2.2rem;
  text-align: center;
}

/* ---------- admin ---------- */

.admin-login { text-align: center; padding: 14vh 0 4rem; }

.admin-login-title,
.admin-board-title {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 4.5vw, 2.3rem);
  letter-spacing: -0.01em;
  margin: 0.9rem 0;
}

.admin-board { padding: 3rem 0 4rem; max-width: 740px; margin: 0 auto; }

.board-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-end;
  gap: 1rem;
  flex-wrap: wrap;
}

.admin-board-title { margin: 0.4rem 0 0; }

.board-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; }

.ghost-btn {
  background: none;
  border: 1px solid var(--moss-line);
  border-radius: 5px;
  color: var(--sage);
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 0.85rem;
  padding: 0.5rem 1rem;
  transition: border-color 160ms ease, color 160ms ease;
}

.ghost-btn:hover { border-color: var(--acid-dim); color: var(--acid); }
.ghost-btn.danger:hover { border-color: var(--fail); color: var(--fail); }

/* ---------- admin search ---------- */

.board-search {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  margin-top: 1.6rem;
  padding: 0 0.9rem;
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  transition: border-color 160ms ease, box-shadow 160ms ease;
}

.board-search:focus-within {
  border-color: var(--acid-dim);
  box-shadow: 0 0 0 1px rgba(var(--accent-rgb), 0.12);
}

.bs-icon { width: 17px; height: 17px; flex-shrink: 0; color: var(--sage); }
.board-search:focus-within .bs-icon { color: var(--acid); }

#search-input {
  flex: 1;
  min-width: 0;
  background: none;
  border: none;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 1rem;
  padding: 0.85rem 0;
}

#search-input::placeholder { color: var(--sage); opacity: 0.7; }
#search-input:focus { outline: none; }

/* The native clear affordance duplicates .bs-clear and ignores our styling. */
#search-input::-webkit-search-decoration,
#search-input::-webkit-search-cancel-button { -webkit-appearance: none; appearance: none; }

.bs-hint {
  flex-shrink: 0;
  border: 1px solid var(--moss-line);
  border-radius: 4px;
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1;
  padding: 0.25rem 0.45rem;
}

.bs-clear {
  flex-shrink: 0;
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-size: 1.3rem;
  line-height: 1;
  padding: 0 0.2rem;
}

.bs-clear:hover { color: var(--acid); }
.bs-clear:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; border-radius: 4px; }

/* Search hits, inside order cards. */
.order-card mark {
  background: rgba(var(--accent-rgb), 0.32);
  color: var(--bone);
  border-radius: 2px;
  font-weight: 600;
  padding: 0 0.1em;
}

@media (max-width: 560px) {
  .bs-hint { display: none; }
  /* Keeps the whole placeholder on screen at 375px. */
  #search-input { font-size: 0.95rem; }
}

.board-status {
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  margin: 1.4rem 0;
}

.orders-list { display: flex; flex-direction: column; gap: 1rem; }

.order-card {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  padding: 1.3rem 1.5rem;
}

.oc-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
}

.oc-code {
  font-family: var(--font-mono);
  font-size: 1.15rem;
  font-weight: 500;
  letter-spacing: 0.06em;
}

.demo-tag {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--sage);
  border: 1px solid var(--moss-line);
  border-radius: 3px;
  padding: 0.1rem 0.35rem;
  margin-left: 0.5rem;
  vertical-align: middle;
  /* A two-word tag broken across two lines reads as two tags. */
  white-space: nowrap;
  display: inline-block;
}

.oc-meta { display: block; color: var(--sage); font-size: 0.8rem; margin-top: 0.3rem; }

.oc-current {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--acid);
  white-space: nowrap;
}

.oc-accounts-label {
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  margin-top: 1rem;
}

.oc-accounts { margin: 0.5rem 0 0; }

/* Same green/purple split as the customer's pages. */
.oc-accounts-label.is-instagram { color: var(--acid); }
.oc-accounts-label.is-tiktok { color: var(--plum); }
.oc-accounts-label.is-x { color: var(--bone); }
.oc-accounts-label.is-email { color: var(--warn); }
.oc-accounts-label.is-snapchat { color: var(--snap); }
.oc-accounts-label.is-phone { color: var(--dial); }

.oc-note-label {
  display: block;
  margin-top: 1.2rem;
  font-size: 0.8rem;
  color: var(--sage);
}

/* Both of these were border tokens doing a text job — 2.41:1 measured, well
   under any real threshold. --sage exists precisely for de-emphasized text
   and was sitting unused two lines away. */
.oc-note-hint { color: var(--sage); }
.oc-note-label .oc-note-hint { color: var(--sage); }

.oc-note-label textarea {
  display: block;
  width: 100%;
  margin-top: 0.5rem;
  background: var(--ink-black);
  border: 1px solid var(--moss-line);
  border-radius: 6px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.95rem;
  line-height: 1.4;
  padding: 0.6rem 0.75rem;
  resize: vertical;
}

.oc-note-label textarea:focus-visible { outline: 2px solid var(--acid); outline-offset: 1px; }

.oc-controls {
  display: flex;
  gap: 1rem;
  align-items: flex-end;
  flex-wrap: wrap;
}

.oc-controls label {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  font-size: 0.8rem;
  color: var(--sage);
}

.oc-controls select,
.oc-controls input {
  background: var(--ink-black);
  border: 1px solid var(--moss-line);
  border-radius: 5px;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.55rem 0.7rem;
  min-width: 180px;
}

.oc-controls select:focus-visible,
.oc-controls input:focus-visible { outline: 2px solid var(--acid); outline-offset: 1px; }

.oc-save { padding: 0.6rem 1.4rem; font-size: 0.9rem; }

.oc-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
}

.oc-contact { color: var(--sage); font-size: 0.8rem; margin: 0; }
.oc-contact a { color: var(--acid); }

.oc-row-actions { display: flex; gap: 1rem; }

.link-btn {
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-family: var(--font-body);
  font-size: 0.8rem;
  padding: 0;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.link-btn:hover { color: var(--acid); }
.link-btn.danger:hover { color: var(--fail); }
.link-btn:disabled { opacity: 0.5; cursor: default; }

.archived-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  color: var(--sage);
  font-size: 0.8rem;
  cursor: pointer;
}

.archived-toggle input { accent-color: var(--acid); }

.archived-tag { color: var(--fail); border-color: rgba(240, 80, 60, 0.4); }

.order-card.is-archived { opacity: 0.6; }

.oc-saved {
  color: var(--acid);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  margin-top: 0.6rem;
}

/* ---------- ticket queue ---------- */

.ticket-bar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin-top: 1.8rem;
  padding: 1.3rem 1.5rem;
  border: 1px solid var(--acid-dim);
  border-left: 3px solid var(--acid);
  border-radius: 8px;
  background: linear-gradient(90deg, rgba(var(--accent-rgb), 0.09), rgba(var(--accent-rgb), 0.02));
}

.ticket-bar.is-warm {
  border-color: var(--warn);
  border-left-color: var(--warn);
  background: linear-gradient(90deg, rgba(224, 161, 60, 0.1), rgba(224, 161, 60, 0.02));
}

.ticket-bar.is-hot {
  border-color: var(--fail);
  border-left-color: var(--fail);
  background: linear-gradient(90deg, rgba(240, 80, 60, 0.12), rgba(240, 80, 60, 0.02));
}

.ticket-bar.is-clear {
  border-color: var(--moss-line);
  border-left-color: var(--acid-dim);
  background: var(--moss-deep);
}

.tb-eyebrow {
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
}

.ticket-bar.is-working .tb-eyebrow { color: var(--acid); }
.ticket-bar.is-warm .tb-eyebrow { color: var(--warn); }
.ticket-bar.is-hot .tb-eyebrow { color: var(--fail); }

.tb-headline {
  font-family: var(--font-display);
  font-size: clamp(1.15rem, 3.4vw, 1.6rem);
  margin: 0.45rem 0 0.4rem;
  line-height: 1.25;
}

.tb-code { color: var(--acid); letter-spacing: 0.03em; }
.ticket-bar.is-warm .tb-code { color: var(--warn); }
.ticket-bar.is-hot .tb-code { color: var(--fail); }
.ticket-bar.is-clear .tb-code { color: var(--sage); }

.tb-isup {
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.85em;
  font-weight: 500;
}

.tb-meta { color: var(--sage); font-size: 0.85rem; font-weight: 400; }

.tb-main { flex: 1 1 16rem; min-width: 0; }

/* Grows to fill the line when the actions sit beside the headline, and takes
   the whole line when they wrap under it — right-aligned either way. */
.tb-side {
  display: flex;
  flex: 1 1 19rem;
  flex-direction: column;
  align-items: flex-end;
  gap: 0.7rem;
}

.tb-depth {
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.tb-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; justify-content: flex-end; }

.tb-btn { padding: 0.5rem 1rem; font-size: 0.85rem; }
.tb-btn[hidden] { display: none; }

.queue-tag {
  display: inline-block;
  min-width: 2.1rem;
  margin-right: 0.6rem;
  padding: 0.1rem 0.4rem;
  border: 1px solid var(--moss-line);
  border-radius: 4px;
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.06em;
  text-align: center;
  vertical-align: middle;
}

.queue-tag.is-up {
  border-color: var(--acid);
  background: var(--acid);
  color: var(--on-accent);
  font-weight: 700;
}

.working-tag { color: var(--acid); border-color: var(--acid-dim); }

/* ---------- desk tabs & inbox ---------- */

.board-tabs {
  display: flex;
  gap: 0.3rem;
  margin: 1.6rem 0 1.4rem;
  border-bottom: 1px solid var(--moss-line);
  /* Four tabs don't fit across a phone. Scroll the strip rather than letting
     the last one hang off the edge and take the page with it. */
  overflow-x: auto;
  scrollbar-width: none;
}

.board-tabs::-webkit-scrollbar { display: none; }
.board-tab { flex-shrink: 0; }

.board-tab {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  color: var(--sage);
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  padding: 0.7rem 0.9rem;
  margin-bottom: -1px;
  transition: color 160ms ease, border-color 160ms ease;
}

.board-tab:hover { color: var(--bone); }
.board-tab:focus-visible { outline: 2px solid var(--acid); outline-offset: -2px; }
.board-tab.is-on { color: var(--acid); border-bottom-color: var(--acid); }
/* The main nav — Orders/Tickets/Inbox/Announcement — measured 42px, 2px under
   the floor. min-height respects the existing padding/line-height rather than
   fighting it. */
.board-tab { min-height: 44px; }

.panel-controls {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.inbox-note {
  display: block;
  color: var(--sage);
  font-size: 0.85rem;
  font-weight: 400;
  max-width: 68ch;
}

/* main caps this at its own max-width; the board just stops narrowing it. */
.admin-board.is-inbox { max-width: none; }

.inbox-layout {
  display: grid;
  grid-template-columns: minmax(230px, 290px) 1fr;
  gap: 1.2rem;
  align-items: start;
}

/* Grid children size to their content unless told otherwise, and a one-line
   message preview has a very wide min-content. Without this the list column
   grows past its track and the whole board scrolls sideways. */
.inbox-list-wrap,
.thread-pane,
.tl-row,
.tl-row > * {
  min-width: 0;
}

.inbox-status { color: var(--sage); font-size: 0.8rem; margin-bottom: 0.7rem; }

.thread-list {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-height: 66vh;
  overflow-y: auto;
}

.tl-row {
  display: flex;
  flex-direction: column;
  gap: 0.25rem;
  width: 100%;
  text-align: left;
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-left: 3px solid transparent;
  border-radius: 6px;
  color: var(--bone);
  cursor: pointer;
  font-family: var(--font-body);
  padding: 0.7rem 0.85rem;
  transition: border-color 160ms ease, background 160ms ease;
}

.tl-row:hover { border-color: var(--acid-dim); }
.tl-row:focus-visible { outline: 2px solid var(--acid); outline-offset: 2px; }
.tl-row.is-open { border-color: var(--acid-dim); border-left-color: var(--acid); background: rgba(var(--accent-rgb), 0.06); }
.tl-row.is-unread { border-left-color: var(--plum); }

.tl-top { display: flex; align-items: center; gap: 0.5rem; }

.tl-handle {
  font-family: var(--font-mono);
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--acid);
  overflow-wrap: anywhere;
}

.tl-row.is-unread .tl-handle { color: #e2ccff; }

.tl-dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--plum);
  box-shadow: 0 0 8px rgba(168, 85, 247, 0.9);
  flex-shrink: 0;
}

.tl-preview {
  color: var(--bone);
  font-size: 0.8rem;
  font-weight: 400;
  /* One line only — the whole message is a click away. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.tl-meta { color: var(--sage); font-size: 0.72rem; }
.tl-quiet { color: var(--sage); font-style: italic; }

.thread-pane {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 1.3rem 1.4rem;
  min-height: 18rem;
}

.thread-placeholder { color: var(--sage); font-size: 0.9rem; text-align: center; padding: 4rem 0; }

.tp-head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
  margin-bottom: 1.1rem;
}

.tp-handle {
  font-family: var(--font-display);
  font-size: 1.1rem;
  margin: 0.35rem 0 0.3rem;
  overflow-wrap: anywhere;
}

.tp-sub { color: var(--sage); font-size: 0.8rem; font-weight: 400; }

.tp-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

.tp-orders {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  margin-bottom: 1rem;
}

.tp-order {
  background: var(--ink-black);
  border: 1px solid var(--moss-line);
  border-left: 3px solid var(--acid);
  border-radius: 6px;
  padding: 0.6rem 0.8rem;
}

.tp-order.is-complete { border-left-color: var(--sage); }
.tp-order.is-archived { opacity: 0.65; }

.tp-order-head {
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  flex-wrap: wrap;
  margin-bottom: 0.5rem;
}

.tp-order-code {
  font-family: var(--font-mono);
  font-size: 0.85rem;
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--acid);
}

.tp-order.is-complete .tp-order-code { color: var(--bone); }

.tp-order-state {
  font-family: var(--font-code);
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  color: var(--sage);
}

.tp-order-count { color: var(--sage); font-size: 0.72rem; margin-left: auto; }

/* ---------- an entry, with the x that marks it ---------- */

.tp-entries { list-style: none; display: flex; flex-wrap: wrap; gap: 0.45rem; }

.tpe {
  display: inline-flex;
  align-items: center;
  gap: 0.15rem;
  background: rgba(var(--tint-rgb), 0.04);
  border: 1px solid var(--moss-line);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  padding: 0.2rem 0.5rem;
}

.tpe.is-email,
.tpe.is-phone { font-size: 0.72rem; }

.tpe.is-failed {
  background: rgba(240, 80, 60, 0.1);
  border-color: var(--fail);
  color: #ffb3a8;
}

.tpe.is-failed .tpe-handle {
  text-decoration: line-through;
  text-decoration-color: rgba(240, 80, 60, 0.7);
}

/* The whole chip is the target — click a username, then say what happened. */
/* The username is the link now — it opens a DM on Instagram, the profile
   elsewhere. It has to look like part of the chip, not like a 1996 hyperlink,
   so it takes the chip's own colour and only underlines when you're on it. */
.tpe-link {
  color: inherit;
  text-decoration: none;
  cursor: pointer;
}

.tpe-link:hover { text-decoration: underline; text-underline-offset: 3px; }
.tpe-link:focus-visible { outline: 2px solid var(--acid); outline-offset: 3px; border-radius: 3px; }

/* The chevron beside it opens the state picker. Small on purpose — marking is
   the secondary action; going to look at the account is the primary one. */
.tpe-pick {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  color: var(--sage);
  cursor: pointer;
  font-size: 0.6rem;
  line-height: 1;
  margin-left: 0.15rem;
  padding: 0.35rem 0.3rem;
  border-radius: 4px;
  transition: color 140ms ease, background 140ms ease;
}

.tpe-pick:hover { color: var(--bone); background: rgba(var(--tint-rgb), 0.1); }
.tpe-pick:focus-visible { outline: 2px solid var(--acid); outline-offset: 1px; }

.tpe-flag {
  font-family: var(--font-code);
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  color: var(--sage);
  text-decoration: none;
}

.tpe.is-done { background: rgba(var(--accent-rgb), 0.14); border-color: var(--acid); }
.tpe.is-done .tpe-flag { color: var(--acid); }
.tpe.is-failed .tpe-flag { color: var(--fail); }

/* The chip while it's open. */
.tpe.is-picking {
  background: var(--moss-deep);
  border-color: var(--acid-dim);
  gap: 0.35rem;
  flex-wrap: wrap;
  border-radius: 10px;
  padding: 0.4rem 0.5rem;
}

.tpe.is-picking .tpe-handle { color: var(--bone); }

.tpe-act,
.tpe-cancel {
  border-radius: 999px;
  cursor: pointer;
  font-family: var(--font-code);
  font-size: 0.5rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  padding: 0.26rem 0.6rem;
  white-space: nowrap;
}

.tpe-done { background: var(--acid); border: 1px solid var(--acid); color: var(--on-accent); font-weight: 700; }
.tpe-done:hover { filter: brightness(1.1); }

.tpe-fail { background: rgba(240, 80, 60, 0.16); border: 1px solid var(--fail); color: #ffb3a8; }
.tpe-fail:hover { background: var(--fail); color: var(--on-accent); font-weight: 700; }

.tpe-working { background: rgba(245, 207, 61, 0.16); border: 1px solid var(--gold); color: #ffe89a; }
.tpe-working:hover { background: var(--gold); color: var(--on-accent); font-weight: 700; }

.tpe-undo { background: none; border: 1px solid var(--moss-line); color: var(--sage); }
.tpe-undo:hover { color: var(--bone); border-color: var(--sage); }

.tpe-cancel {
  background: none;
  border: none;
  color: var(--sage);
  font-size: 0.95rem;
  line-height: 1;
  padding: 0.1rem 0.3rem;
}

.tpe-cancel:hover { color: var(--bone); }

/* On the order board the chips sit in the card, not in a panel. */
.oc-entries { margin: 0.5rem 0 0; }

/* The pane already has a panel background; the thread inside it doesn't need
   a second one. */
.thread-pane .thread { background: var(--ink-black); max-height: 44vh; }

@media (max-width: 860px) {
  .inbox-layout { grid-template-columns: 1fr; }
  .thread-list { max-height: 32vh; }
}

/* ---------- writing the announcement (admin) ---------- */

.broadcast-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: 1.6rem;
  align-items: start;
}

@media (max-width: 860px) {
  .broadcast-layout { grid-template-columns: 1fr; }
}

.broadcast-form { display: flex; flex-direction: column; gap: 1.3rem; }
.broadcast-form textarea.text-field { resize: vertical; line-height: 1.5; }
.bc-optional { color: var(--sage); font-size: 0.72rem; font-weight: 400; text-transform: none; letter-spacing: 0; }

.broadcast-preview {
  background: var(--moss-deep);
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 1.2rem 1.3rem;
  /* Follows you down the form, so it stays visibly attached to the fields
     you're typing in rather than reading as a separate section. */
  position: sticky;
  top: 1rem;
}

/* Both columns are labelled, because "what changed" and a purple box side by
   side don't say on their own that one is the other. */
.bc-col-head { margin-bottom: 1rem; }
.bc-col-sub {
  color: var(--sage);
  font-size: 0.8rem;
  font-weight: 400;
  margin-top: 0.35rem;
  max-width: 46ch;
}

@media (max-width: 860px) {
  .broadcast-preview { position: static; }
}

.bc-stage { margin-top: 0.9rem; }
.bc-empty { color: var(--sage); font-size: 0.85rem; font-weight: 400; padding: 1.2rem 0; text-align: center; }
.bc-live { color: var(--acid); font-size: 0.8rem; margin-top: 0.9rem; }

/* The preview is a picture of the banner, not a control. */
.broadcast-preview .announce-ack { cursor: default; }
.broadcast-preview .announce-ack:hover { background: none; border-color: var(--plum-dim); color: #a98fc9; }

@media (prefers-reduced-motion: reduce) {
  .cryptic-text { animation: none; opacity: 1; }
  .announce-pulse { animation: none; }
}

/* ---------- the update rows (admin) ---------- */

.bc-row { display: flex; gap: 1rem; flex-wrap: wrap; }
.bc-tag-field { flex: 0 1 8rem; }
.bc-headline-field { flex: 1 1 16rem; }

.bc-items {
  list-style: none;
  display: flex;
  flex-direction: column;
  gap: 0.7rem;
  margin: 0.8rem 0;
}

.bc-item {
  display: flex;
  align-items: flex-start;
  gap: 0.7rem;
  background: var(--ink-black);
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  padding: 0.7rem 0.8rem;
}

.bc-item-n {
  flex-shrink: 0;
  width: 1.4rem;
  height: 1.4rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--moss-line);
  color: var(--sage);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  margin-top: 0.35rem;
}

.bc-item-fields { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 0.45rem; }
.bc-item-fields .text-field { padding: 0.55rem 0.7rem; font-size: 0.9rem; }
.bc-why { color: var(--sage); }
.bc-item-x { flex-shrink: 0; margin-top: 0.5rem; font-size: 1.1rem; line-height: 1; }
.bc-items-hint { margin-bottom: 0.2rem; }

/* ---------- reading a username ---------- */
/*
 * Handles are shown in caps with the letters pushed apart. Lowercase in a
 * condensed face makes l/I, o/a and rn/m genuinely hard to tell apart, and
 * these are strings that have to be read exactly right — a misread handle is
 * work done on the wrong account.
 *
 * Display only: the stored value stays lowercase, which is what the platforms
 * use. Email addresses are left alone — the local part of an address can in
 * principle be case-sensitive, and an address in caps reads worse, not better.
 */

.accounts li,
.chip,
.tpe .tpe-handle,
.acct-text {
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.accounts.is-phone li,
.tpe.is-phone .tpe-handle,
.accounts.is-email li,
.is-email .chip,
.tpe.is-email .tpe-handle {
  text-transform: none;
  letter-spacing: 0.03em;
}

/* Caps are wider; give the chips a little more room so they don't feel packed. */
.accounts li { padding: 0.32rem 0.85rem; }
.chip { padding: 0.3rem 0.45rem 0.3rem 0.8rem; }
.tpe { padding: 0.22rem 0.55rem; }

/* The flags sit next to a capitalised handle and shouldn't compete with it. */
.acct-flag,
.tpe-flag { letter-spacing: 0.14em; }

/* ---------- reviewing what's been completed ---------- */

.oc-done-at { color: var(--sage); }

/* Completed within minutes of arriving, with nothing marked done. Amber, not
   red — it's a question, not a verdict. */
.oc-done-at.is-quick {
  color: var(--warn);
  border-bottom: 1px dotted var(--warn);
}

/* The ticket bar's Start button, once it's been pressed. Holds its place so
   Complete can't slide under the cursor, but reads as a status, not a button. */
.tb-btn.is-marker {
  background: none;
  border: 1px dashed var(--moss-line);
  color: var(--sage);
  box-shadow: none;
  cursor: default;
  opacity: 1;
}

/* ---------- orders that hit the success target ---------- */
/*
 * Green, not purple: this is work that went well and wants signing off, not a
 * customer waiting on you.
 */

.ready-alert {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1rem;
  padding: 0.9rem 1.2rem;
  border: 1px solid var(--acid-dim);
  border-left: 3px solid var(--acid);
  border-radius: 8px;
  background: rgba(var(--accent-rgb), 0.07);
}

.ready-alert .pa-head { color: var(--acid); }

.ra-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  background: rgba(var(--accent-rgb), 0.12);
  border: 1px solid var(--acid-dim);
  border-radius: 999px;
  color: var(--bone);
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  padding: 0.3rem 0.75rem;
}

.ra-chip:hover { border-color: var(--acid); background: rgba(var(--accent-rgb), 0.2); }
.ra-chip .pa-chip-age { color: var(--acid); font-size: 0.72rem; }

.ready-tag { color: var(--acid); border-color: var(--acid-dim); }
.order-card.is-ready { border-color: var(--acid-dim); }

/* The one action that writes off whatever never landed. */
.link-btn.go { color: var(--acid); }

/* ---------- customers waiting on a reply (admin) ---------- */

.priority-alert {
  display: flex;
  align-items: center;
  gap: 1rem;
  flex-wrap: wrap;
  margin-top: 1.8rem;
  padding: 0.9rem 1.2rem;
  border: 1px solid var(--plum-dim);
  border-left: 3px solid var(--plum);
  border-radius: 8px;
  background: rgba(168, 85, 247, 0.09);
}

.pa-head {
  color: #d9bcff;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.pa-chips { display: flex; gap: 0.45rem; flex-wrap: wrap; }

.pa-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.4rem;
  background: rgba(168, 85, 247, 0.14);
  border: 1px solid var(--plum-dim);
  border-radius: 999px;
  color: #e2ccff;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  letter-spacing: 0.04em;
  padding: 0.25rem 0.75rem;
  transition: border-color 160ms ease, background 160ms ease;
}

.pa-chip:hover { border-color: var(--plum); background: rgba(168, 85, 247, 0.24); }
.pa-chip-age { color: #a98fc9; font-size: 0.72rem; }

.plum-tag { color: #d9bcff; border-color: var(--plum-dim); }
.plum-tag.is-granted { background: rgba(168, 85, 247, 0.18); border-color: var(--plum); }

.link-btn.plum { color: #d9bcff; }
.link-btn.plum:hover { color: var(--plum); }

.order-card.is-asking { border-color: var(--plum-dim); }

.oc-wait.is-warm { color: var(--warn); }
.oc-wait.is-hot { color: var(--fail); }

.order-card.is-upnow { border-color: var(--acid-dim); }

.order-card.is-pinged {
  border-color: var(--acid);
  box-shadow: 0 0 0 2px rgba(var(--accent-rgb), 0.25);
}

/* The sort control shares the ghost-button look but needs its own dark menu. */
select.ghost-btn { background: var(--moss-deep); cursor: pointer; }
select.ghost-btn option { background: var(--moss-deep); color: var(--bone); }

@media (max-width: 560px) {
  .ticket-bar { flex-direction: column; align-items: stretch; }
  /* Stacked, the flex-basis above would become a row height — drop it. */
  .tb-main,
  .tb-side { flex: 0 0 auto; align-items: stretch; }
  .tb-depth { text-align: left; }
  .tb-actions { justify-content: flex-start; }
  .tb-btn { flex: 1 1 auto; }
}

@media (max-width: 560px) {
  .oc-controls select,
  .oc-controls input { min-width: 100%; }
  .oc-controls label { width: 100%; }
}

/* ---------- responsive & motion ---------- */

@media (max-width: 720px) {

  .lookup { padding-top: 10vh; }
}

/* Header tag crowds the brand on small screens. */
@media (max-width: 640px) {
  .header-tag { display: none; }
  .site-header { padding: 1.2rem 1.4rem; }
}

@media (prefers-reduced-motion: reduce) {
  #serpent-progress { transition: none; }
  /* Keeps the glow, drops the pulse. */
  .announce-text { animation: none; }
}

/* ---------- touch sizing ---------- */
/*
 * Last in the file on purpose. These are overrides, and several of the rules
 * they beat are defined further down than where this block reads naturally —
 * putting it anywhere else means it quietly loses and the targets stay 17px.
 */

@media (max-width: 767px) {
  .announce-ack { padding: 0.7rem 1.1rem; }
  .brand { padding: 0.25rem 0; }
  .text-link { padding: 0.3rem 0; }

  .board-tab { padding: 0.85rem 0.8rem; }

  /* The title and the Refresh/Lock pair were sharing a row and crowding each
     other. Give the heading its own line. */
  .board-head { flex-direction: column; align-items: stretch; gap: 0.9rem; }
  .board-actions { justify-content: flex-start; }

  /* The username chips are the main thing you press here. */
  .tpe-pick { padding: 0.35rem 0.2rem; }
  .tpe { padding: 0.3rem 0.6rem; }
  .tpe-act, .tpe-cancel { padding: 0.45rem 0.7rem; }

  /* Row actions: Resolve, Archive, Delete, and the links in a card footer. */
  .link-btn { padding: 0.45rem 0; }
  .oc-row-actions { gap: 0.35rem 1.1rem; }

  .pa-chip, .ra-chip { padding: 0.5rem 0.85rem; }

  /* A 13px checkbox is not a target. */
  .archived-toggle { padding: 0.4rem 0; }
  .archived-toggle input { width: 18px; height: 18px; }
}

/* ---------- the waiting list, on a customer's card ---------- */
/*
   Reserve has to read as "queued", not as "written off". It sits below the
   active ten under its own heading, dimmed rather than struck through — a
   strike means we tried and couldn't, which is the one thing it doesn't mean.
*/
.pool-waiting {
  margin-top: 26px;
  padding-top: 18px;
  border-top: 1px solid var(--moss-line);
}
.pool-waiting > summary {
  cursor: pointer;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  /* Thumb-sized: this is the one control on a long card. */
  min-height: 44px;
  list-style: none;
}
.pool-waiting > summary::-webkit-details-marker { display: none; }
.pw-title {
  font-family: var(--font-display);
  font-size: 1.05rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--sage);
}
/* The label is CSS-only so the open and closed wording can't drift apart. */
.pw-hint { color: var(--sage); font-size: 0.85rem; }
.pw-hint::after { content: "tap to see them"; }
.pool-waiting[open] .pw-hint::after { content: "tap to hide"; }
.accounts.is-waiting li {
  opacity: 0.55;
  border-style: dashed;
}
.accounts.is-waiting li .acct-text { text-decoration: none; }

/* ---------- cutting a ticket ---------- */
.mint-form { margin: 0 0 18px; }
.mint-row { display: flex; gap: 10px; flex-wrap: wrap; align-items: stretch; }
.mint-row .gate-handle-wrap { flex: 1 1 220px; margin-bottom: 0; }
.mint-btn {
  flex: 0 0 auto;
  background: var(--acid);
  border: 1px solid var(--acid);
  color: var(--on-accent);
  font-family: var(--font-body);
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  padding: 0 22px;
  border-radius: 12px;
  cursor: pointer;
  min-height: 52px;
}
.mint-btn[disabled] { opacity: 0.55; cursor: default; }
.mint-error { color: var(--fail); font-size: 0.9rem; margin: 10px 0 0; }
@media (max-width: 560px) {
  .mint-btn { flex: 1 1 100%; }
}

/* ---------- the ticket list, on the desk ---------- */
.req-filter {
  display: flex;
  gap: 8px;
  margin: 0 0 14px;
  flex-wrap: wrap;
}
.req-tab {
  background: transparent;
  border: 1px solid var(--moss-line);
  color: var(--sage);
  font-family: var(--font-body);
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  padding: 8px 16px;
  border-radius: 999px;
  cursor: pointer;
  /* Same 44px as every other control on this panel — the desk is worked on a
     phone and a filter you miss is a filter you stop using. */
  min-height: 44px;
}
.req-tab.is-on {
  color: var(--on-accent);
  background: var(--acid);
  border-color: var(--acid);
}

/* The minted code. Loud on purpose — it is the one thing on this panel that
   cannot be recovered for the customer if it's missed. */
.req-flash {
  border: 1px solid var(--acid);
  background: rgba(var(--accent-rgb), 0.08);
  border-radius: 12px;
  padding: 14px 16px;
  margin: 0 0 14px;
}
.rf-line { margin: 0 0 10px; color: var(--bone); font-size: 0.95rem; }
.rf-row { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.req-dismiss {
  background: transparent;
  border: 1px solid var(--moss-line);
  color: var(--sage);
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
  min-height: 36px;
}

.req-list { list-style: none; margin: 14px 0 0; padding: 0; }
.req-row {
  display: flex;
  align-items: flex-start;
  gap: 14px;
  flex-wrap: wrap;
  padding: 16px;
  margin-bottom: 12px;
  border: 1px solid var(--moss-line);
  border-radius: 12px;
  background: var(--moss-deep);
}
.req-main { flex: 1 1 260px; min-width: 0; }
.req-who {
  margin: 0;
  font-family: var(--font-code);
  font-size: 1rem;
  color: var(--bone);
  overflow-wrap: anywhere;
}
.req-meta { margin: 4px 0 10px; color: var(--sage); font-size: 0.9rem; }

.req-entries { display: flex; flex-wrap: wrap; gap: 6px; }
.req-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 5px 10px;
  border: 1px solid var(--moss-line);
  border-radius: 8px;
  font-size: 0.9rem;
  color: var(--bone);
  overflow-wrap: anywhere;
}
.req-chip-kind {
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  color: var(--sage);
}
.req-chip-error { color: var(--fail); font-size: 0.9rem; }

.req-actions { display: flex; gap: 8px; flex-wrap: wrap; }
.req-accept,
.req-decline {
  font-family: var(--font-body);
  font-size: 0.95rem;
  letter-spacing: 0.04em;
  padding: 10px 18px;
  border-radius: 8px;
  cursor: pointer;
  /* Thumb-sized. The desk is worked on a phone. */
  min-height: 44px;
}
.req-accept {
  background: var(--acid);
  border: 1px solid var(--acid);
  color: var(--on-accent);
}
.req-decline {
  background: transparent;
  border: 1px solid var(--moss-line);
  color: var(--sage);
}
.req-decline.is-armed {
  border-color: var(--fail);
  color: var(--fail);
}
.req-accept[disabled],
.req-decline[disabled] { opacity: 0.5; cursor: default; }

.req-code,
.req-code-big {
  font-family: var(--font-code);
  color: var(--acid);
  overflow-wrap: anywhere;
}
.req-code-big { font-size: 1.05rem; }
.req-declined { color: var(--sage); font-size: 0.9rem; }
.req-copy {
  background: transparent;
  border: 1px solid var(--moss-line);
  color: var(--bone);
  border-radius: 6px;
  padding: 6px 12px;
  cursor: pointer;
  min-height: 36px;
}

@media (max-width: 560px) {
  .req-row { flex-direction: column; align-items: stretch; }
  /* The 260px basis above is a WIDTH for the row layout. Once the row stacks it
     becomes a height, which floors every request at 260px tall and opens a gap
     between the usernames and the buttons. */
  .req-main { flex: 0 0 auto; }
  .req-actions { width: 100%; }
  .req-accept, .req-decline { flex: 1 1 0; }
}

/* ---------- entries waiting for a pool slot, on the desk ---------- */
.oc-waiting {
  margin: 10px 0 0;
  border: 1px solid var(--moss-line);
  border-radius: 10px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.015);
}
.oc-waiting > summary {
  cursor: pointer;
  color: var(--sage);
  font-size: 0.9rem;
  letter-spacing: 0.04em;
  min-height: 32px;
  display: flex;
  align-items: center;
}
.oc-waiting-note { margin: 8px 0 10px; color: var(--sage); font-size: 0.85rem; }
.oc-waiting-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}
.oc-waiting-list li {
  display: inline-flex;
  align-items: baseline;
  gap: 6px;
  padding: 4px 9px;
  border: 1px dashed var(--moss-line);
  border-radius: 7px;
  opacity: 0.6;
  font-size: 0.85rem;
  overflow-wrap: anywhere;
}
.ocw-kind { font-size: 0.68rem; letter-spacing: 0.08em; color: var(--sage); }
.ocw-handle { color: var(--bone); }
.tp-waiting { margin: 6px 0 0; color: var(--sage); font-size: 0.85rem; opacity: 0.8; }

/* ---------- the closing notice ---------- */
/*
   The last page anyone sees, and the only one left. Quiet rather than loud:
   nothing here is a control, because there is nothing to do except read it.
*/
.closing {
  max-width: 620px;
  margin: 0 auto;
  padding: 56px 20px 90px;
}
.closing-title {
  font-family: var(--font-display);
  font-size: clamp(1.6rem, 6vw, 2.5rem);
  line-height: 1.15;
  letter-spacing: 0.02em;
  color: var(--bone);
  margin: 0 0 26px;
}
.closing-lede {
  font-size: 1.15rem;
  line-height: 1.6;
  color: var(--bone);
  margin: 0 0 20px;
}
/* The one line that tells someone what happens next. */
.closing-key {
  border-left: 2px solid var(--acid);
  padding-left: 16px;
  margin: 26px 0 30px;
}
/* A signature, not a sentence — display face, spaced out, sitting quietly
   under the rule. */
/* A signature, not a sentence — display face, spaced out, sitting quietly
   under the rule.
   Each half is its own unbreakable unit, so a narrow screen can only ever
   break BETWEEN the two names. Michroma is wide: left to itself the line
   wrapped as "HOUSE SLYTHERIN / THE" over "SYNDICATE", which reads as a
   mistake rather than a signature. */
.closing-signoff {
  border-top: 1px solid var(--moss-line);
  padding-top: 22px;
  margin: 0;
  color: var(--sage);
  font-family: var(--font-display);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  line-height: 2;
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
}
.sig-part { white-space: nowrap; }
.sig-sep {
  color: var(--acid-dim);
  padding: 0 9px;
}
/* On a phone the line can't hold both names, and a wrapped line ending in a
   dangling slash reads as a mistake. Below this width they stack deliberately
   instead, as two lines of a signature, and the slash goes. */
@media (max-width: 480px) {
  .closing-signoff { display: block; }
  .sig-sep { display: none; }
  .sig-part { display: block; }
}

/* ---------- the door ---------- */
/*
   Invite-only, and it should feel like it. The page is mostly dark and mostly
   empty: a sigil, two fields, and a sentence that tells anyone without a ticket
   to leave. The theatre is in the restraint — a busy page reads as a shop,
   and this isn't one.
*/
.gate {
  max-width: 460px;
  margin: 0 auto;
  padding: 40px 20px 90px;
  text-align: center;
}

.gate-sigil {
  width: clamp(140px, 42vw, 190px);
  margin: 0 auto 6px;
  color: var(--acid);
}
.gate-sigil svg { width: 100%; height: auto; display: block; }

/* Two rings turning against each other, slowly enough to read as breathing
   rather than loading. */
.sigil-ring { transform-origin: 60px 60px; animation: sigil-turn 48s linear infinite; }
.sigil-ring-2 { animation: sigil-turn 31s linear infinite reverse; }
@keyframes sigil-turn { to { transform: rotate(360deg); } }

@media (prefers-reduced-motion: reduce) {
  .sigil-ring, .sigil-ring-2 { animation: none; }
}

.gate-title {
  font-family: var(--font-display);
  font-size: clamp(1.7rem, 7vw, 2.6rem);
  line-height: 1.12;
  letter-spacing: 0.02em;
  color: var(--bone);
  margin: 8px 0 14px;
}
.gate-sub {
  color: var(--sage);
  font-size: 1.0rem;
  line-height: 1.6;
  margin: 0 auto 30px;
  max-width: 34ch;
}

.gate-form { display: block; text-align: left; }

.gate-label {
  display: block;
  font-family: var(--font-display);
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--acid-dim);
  margin: 0 0 8px;
}

/* The ticket field is the centrepiece: monospaced, wide-tracked, engraved into
   the page rather than sitting on it. */
.gate-ticket {
  width: 100%;
  box-sizing: border-box;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--moss-line);
  border-radius: 12px;
  color: var(--bone);
  font-family: var(--font-code);
  font-size: clamp(0.95rem, 4.4vw, 1.25rem);
  letter-spacing: 0.1em;
  text-align: center;
  text-transform: uppercase;
  padding: 18px 12px;
  min-height: 60px;
  box-shadow: inset 0 1px 12px rgba(0, 0, 0, 0.55);
  transition: border-color 0.2s, box-shadow 0.2s;
}
.gate-ticket::placeholder { color: var(--sage); opacity: 0.4; letter-spacing: 0.1em; }
.gate-ticket:focus {
  outline: none;
  border-color: var(--acid);
  box-shadow: inset 0 1px 12px rgba(0, 0, 0, 0.55), 0 0 0 3px rgba(var(--accent-rgb), 0.13);
}

.gate-handle-wrap {
  display: flex;
  align-items: stretch;
  margin-bottom: 22px;
  border: 1px solid var(--moss-line);
  border-radius: 12px;
  background: rgba(0, 0, 0, 0.35);
  overflow: hidden;
  transition: border-color 0.2s, box-shadow 0.2s;
}
.gate-handle-wrap:focus-within {
  border-color: var(--acid);
  box-shadow: 0 0 0 3px rgba(var(--accent-rgb), 0.13);
}
.gate-at {
  display: flex;
  align-items: center;
  padding: 0 4px 0 16px;
  color: var(--sage);
  font-family: var(--font-code);
  font-size: 1rem;
}
.gate-handle {
  flex: 1 1 auto;
  min-width: 0;
  background: transparent;
  border: none;
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 1.05rem;
  padding: 15px 16px 15px 2px;
  min-height: 52px;
}
.gate-handle:focus { outline: none; }
.gate-handle::placeholder { color: var(--sage); opacity: 0.4; }

.gate-label + .gate-ticket { margin-bottom: 20px; }

.gate-btn {
  width: 100%;
  background: var(--acid);
  border: 1px solid var(--acid);
  color: var(--on-accent);
  font-family: var(--font-display);
  font-size: 0.8rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border-radius: 12px;
  padding: 0 20px;
  min-height: 54px;
  cursor: pointer;
  transition: filter 0.2s;
}
.gate-btn:hover:not([disabled]) { filter: brightness(1.08); }
.gate-btn[disabled] { opacity: 0.55; cursor: default; }

.gate-foot {
  margin: 26px auto 0;
  max-width: 34ch;
  color: var(--sage);
  font-size: 0.9rem;
  line-height: 1.6;
  opacity: 0.85;
}

/* ---------- one person, several ways to reach them ---------- */
/*
   A plain entry stays a pill in the chip flow. One carrying branches takes a
   full row instead and becomes a small block: the primary on top, the other
   contacts folded underneath. Twenty targets each with four contacts would be
   eighty lines otherwise, and the primary is what someone is scanning for.
*/
.accounts li.has-branches {
  flex: 1 1 100%;
  border-radius: 12px;
  padding: 0.5rem 0.7rem;
}
.acct-head { display: inline-flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
.accounts li.has-branches .acct-head { display: flex; width: 100%; }

.acct-branch-toggle {
  margin-left: auto;
  background: transparent;
  border: 1px solid var(--moss-line);
  color: var(--sage);
  border-radius: 999px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.04em;
  padding: 0 0.55rem;
  /* Thumb-sized without inflating the row it sits in. */
  min-height: 30px;
  min-width: 38px;
  cursor: pointer;
}
.acct-branch-toggle.is-open { border-color: var(--sage); color: var(--bone); }

.acct-branches {
  list-style: none;
  margin: 0.55rem 0 0;
  padding: 0.5rem 0 0 0.2rem;
  border-top: 1px dashed var(--moss-line);
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
}
.acct-branches li {
  background: none;
  border: none;
  border-radius: 0;
  padding: 0;
  display: flex;
  align-items: baseline;
  gap: 0.6rem;
  font-size: 0.8rem;
}
/* The branch rows sit inside a coloured entry; they must not inherit its state
   colour, or a red target would make its phone number look failed too. */
.accounts li.is-failed .acct-branches li .ab-handle,
.accounts li.is-done .acct-branches li .ab-handle,
.accounts li.is-working .acct-branches li .ab-handle {
  color: var(--bone);
  text-decoration: none;
}
.ab-kind {
  flex: 0 0 auto;
  min-width: 5.5rem;
  color: var(--sage);
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
.ab-handle { color: var(--bone); overflow-wrap: anywhere; }
.ab-remove {
  margin-left: auto;
  background: none;
  border: none;
  color: var(--sage);
  font-size: 1rem;
  line-height: 1;
  cursor: pointer;
  padding: 0 0.35rem;
  min-height: 30px;
  min-width: 30px;
}
.ab-remove:hover { color: var(--fail); }

/* The "@" marker is drawn by `.accounts li::before`. Two places it must not
   appear once an entry becomes a block:
     - on the block itself, where the flex head would strand it on its own line
       above the handle;
     - on the branch rows, which name their kind in words and include phone
       numbers and email addresses that take no "@" at all.
   It goes back on the handle instead, where it belongs. */
.accounts li.has-branches::before,
.acct-branches li::before { content: none; }

.accounts li.has-branches .acct-text::before { content: "@"; color: var(--sage); }
.accounts.is-email li.has-branches .acct-text::before,
.accounts.is-phone li.has-branches .acct-text::before { content: none; }

/* ---------- branches on the desk ---------- */
/*
   A chip with branches takes a full row and stacks them underneath, each one a
   live link. They carry no state colour: the mark belongs to the person, so a
   red target must not make its phone number look like a dead number.
*/
.tpe.has-branches {
  /* `.tpe` is a row flex; without switching axis the branch list sits BESIDE
     the handle instead of under it, and both get squeezed into narrow columns
     that wrap a phone number one digit per line. */
  flex-direction: column;
  align-items: stretch;
  flex: 1 1 100%;
  border-radius: 10px;
  padding: 0.4rem 0.6rem;
}
.tpe-row { display: inline-flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.tpe.has-branches .tpe-row { display: flex; width: 100%; }

.tpe-branches {
  display: flex;
  flex-direction: column;
  gap: 0.2rem;
  margin-top: 0.4rem;
  padding-top: 0.35rem;
  border-top: 1px dashed var(--moss-line);
}
.tpe-branch {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
  color: var(--bone);
  text-decoration: none;
  font-size: 0.72rem;
  padding: 0.2rem 0;
  min-height: 28px;
  overflow-wrap: anywhere;
}
a.tpe-branch:hover .tb-handle { color: var(--acid); text-decoration: underline; }
.tb-kind {
  flex: 0 0 auto;
  min-width: 4.2rem;
  color: var(--sage);
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
/* Never inherit the entry's state colour or strike-through. */
.tpe.is-failed .tpe-branch .tb-handle,
.tpe.is-done .tpe-branch .tb-handle,
.tpe.is-working .tpe-branch .tb-handle { color: var(--bone); text-decoration: none; }

/* The attach picker sits above the kind picker in the add card. */
#c-add-attach[hidden] { display: none; }

/* ---------- a card with nothing on it yet ---------- */
.card-empty { padding: 6px 0 2px; }
.card-empty h3 {
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: 0.02em;
  color: var(--bone);
  margin: 0 0 12px;
}
.card-empty p {
  margin: 0 0 12px;
  color: var(--sage);
  line-height: 1.62;
  font-size: 1rem;
}
.card-empty strong { color: var(--acid); font-weight: 600; }

/* First order ever, distinct from a later empty one: the heading takes the
   acid colour and rises in with a beat of its own, so it reads as an
   occasion rather than the same neutral state repeated. */
.card-empty.is-welcome h3 {
  color: var(--acid);
  animation: rise 420ms var(--ease) both;
}
.card-empty-hint {
  border-left: 2px solid var(--moss-line);
  padding-left: 14px;
  font-size: 0.9rem;
}

/* ================= TOUCH TARGETS =================
   Apple's floor is 44pt and it is not arbitrary — below it, hit rates fall off
   a cliff for anyone not looking directly at their thumb. Both surfaces here
   are worked one-handed on a phone, and the desk's mark button, at 21px, was
   the single most-pressed control in the system.

   Where a control is visually small on purpose (a chip's ×, a disclosure), the
   BOX stays small and the touchable area is extended past it with a pseudo
   element, so nothing grows but everything is catchable.
   ============================================================ */

.tap-ext { position: relative; }
.tap-ext::after {
  content: "";
  position: absolute;
  /* Centre a 44px square on the control without disturbing layout. */
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}

/* --- primary controls: actually 44 --- */
.submit-btn,
.ghost-btn,
.gate-btn,
.mint-btn,
.req-accept,
.req-decline,
.req-copy,
.req-dismiss,
.tb-btn,
.text-link,
#c-signout,
#c-add-btn {
  min-height: 44px;
}

select.ghost-btn,
#c-add-platform,
#c-add-attach {
  min-height: 44px;
}

/* The brand mark doubles as "back to the card". */
.brand { min-height: 44px; display: inline-flex; align-items: center; }

/* Chips on the desk: the whole chip is the hit area for its link, and the mark
   button gets a real one of its own. */
.tpe { min-height: 40px; }
.tpe-handle { display: inline-flex; align-items: center; min-height: 38px; }
.tpe-pick {
  position: relative;
  min-width: 34px;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.tpe-pick::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}
.tpe-branch { min-height: 40px; }

/* The customer's remove × was 16px — a target you have to aim at, next to
   entries you would not want to delete by accident. */
.acct-remove,
.ab-remove {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  min-height: 30px;
}
.acct-remove::after,
.ab-remove::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 44px;
  height: 44px;
  transform: translate(-50%, -50%);
}

.acct-branch-toggle { min-height: 34px; position: relative; }
.acct-branch-toggle::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}

/* A checkbox is 18px however it is styled; the label around it is the target. */
.archived-toggle {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 44px;
}

.pa-chip, .ra-chip { min-height: 44px; display: inline-flex; align-items: center; }
/* Missed the first time: .pa-chip (waiting on a reply) and .ra-chip (ready to
   resolve) are the same shape, styled separately, and only one of the pair
   got the touch-target fix. */

/* Resolve / Move up / Archive / Delete. Text links, but one of them deletes an
   order — a 31px target next to a destructive action is a mis-tap waiting to
   happen. */
.link-btn {
  position: relative;
  min-height: 34px;
  display: inline-flex;
  align-items: center;
}
.link-btn::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}

/* Inline links in prose keep their size; the ones that act like buttons don't. */
.tp-telegram,
.oc-telegram,
a.text-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 34px;
}
.tp-telegram::after,
.oc-telegram::after,
a.text-link::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}

.tpe-handle { min-height: 44px; }
.tpe-branch { min-height: 44px; }

/* Every select, not just the ones with a class. The status dropdown on each
   order card had none and sat at 41px. */
select { min-height: 44px; }

/* The customer's Telegram link on an order card — 17px, and the thing the desk
   taps to start a conversation. */
.oc-contact a,
.oc-contact .link-btn {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-height: 32px;
}
.oc-contact a::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: max(100%, 44px);
  height: 44px;
  transform: translate(-50%, -50%);
}

/* ================= WIDER SCREENS =================
   The card was a phone layout stretched to fill a laptop: 915px-wide bars with
   their contents pinned to the left, and prose running to 86 characters a line
   when comfortable reading stops around 75.

   Nothing here changes the phone. It stops the desktop looking like an
   accident.
   ============================================================ */

@media (min-width: 900px) {
  /* A measure, not a width. Everything the customer reads sits inside it. */
  .card-view { max-width: 780px; margin-left: auto; margin-right: auto; }
  .card-empty p, .acct-placed, .gate-sub, .pool-waiting .acct-placed { max-width: 68ch; }

  /* A branched entry is a card, not a banner. Sitting them side by side reads
     as a set of people rather than a stack of rules across the page. */
  .accounts li.has-branches { flex: 0 1 340px; }
  .tpe.has-branches { flex: 0 1 320px; }

  /* Chips have room to breathe once they aren't fighting for space. */
  .accounts { gap: 0.6rem; }
}

@media (min-width: 1200px) {
  .accounts li.has-branches { flex: 0 1 360px; }
}

/* ================= MOTION AND FEEL =================
   Everything here is small on purpose. The difference between software that
   feels cheap and software that feels considered is rarely a big animation —
   it is that nothing ever jumps, every press answers, and the thing you just
   did is obvious without hunting for it.

   All of it is off for anyone who has asked for reduced motion.
   ============================================================ */

:root {
  /* One easing for everything that moves, so the whole product moves the same
     way. Fast out, settle in — the shape of a real object stopping. */
  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
  --quick: 140ms;
  --settle: 320ms;
}

/* ---- Arrival ---- */

/* The card comes in rather than snapping in. It is the moment the door opens,
   and it is the only place a flourish is warranted. */
.card-view:not([hidden]) { animation: rise var(--settle) var(--ease) both; }
.gate:not([hidden]) { animation: rise 420ms var(--ease) both; }

@keyframes rise {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* Entry blocks stagger in behind it, barely — enough to read as a list being
   dealt rather than a list appearing. */
.accounts li { animation: deal 260ms var(--ease) both; }
.accounts li:nth-child(2) { animation-delay: 20ms; }
.accounts li:nth-child(3) { animation-delay: 40ms; }
.accounts li:nth-child(4) { animation-delay: 60ms; }
.accounts li:nth-child(5) { animation-delay: 80ms; }
.accounts li:nth-child(n+6) { animation-delay: 100ms; }

@keyframes deal {
  from { opacity: 0; transform: translateY(4px) scale(0.985); }
  to   { opacity: 1; transform: none; }
}

/* ---- The thing you just did ---- */

/* A newly added entry says so for a moment. Without it, adding something to a
   list of twenty is an act with no visible result. */
.accounts li.is-new {
  animation: deal 260ms var(--ease) both, landed 1.6s var(--ease) 260ms;
}
@keyframes landed {
  0%   { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.5); }
  35%  { box-shadow: 0 0 0 4px rgba(var(--accent-rgb), 0.16); }
  100% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0); }
}

/* An entry marked done, the first time this browser sees it — a small win on
   its own, distinct from adding something or hitting the two-target. A quick
   scale-and-settle rather than a ring, so it doesn't read as the same event
   as `.is-new` above. */
.accounts li.is-landed {
  animation: land-pop 560ms var(--ease) both;
}
@keyframes land-pop {
  0%   { transform: scale(1); }
  40%  { transform: scale(1.045); box-shadow: 0 0 20px -2px rgba(var(--accent-rgb), 0.55); }
  100% { transform: scale(1); }
}


/* ---- Press ---- */

/* Every control acknowledges the press itself, before the network answers. On
   a slow connection this is the difference between "it's working" and pressing
   it again. */
.submit-btn,
.ghost-btn,
.gate-btn,
.mint-btn,
.req-accept,
.req-decline,
.tpe-pick,
.acct-remove,
.ab-remove,
.acct-branch-toggle,
.link-btn {
  transition: transform var(--quick) var(--ease), filter var(--quick) var(--ease),
    background-color var(--quick) var(--ease), border-color var(--quick) var(--ease),
    color var(--quick) var(--ease);
}
.submit-btn:active:not([disabled]),
.gate-btn:active:not([disabled]),
.mint-btn:active:not([disabled]),
.req-accept:active:not([disabled]) { transform: scale(0.975); }

.ghost-btn:active:not([disabled]),
.tpe-pick:active,
.acct-remove:active,
.ab-remove:active,
.acct-branch-toggle:active { transform: scale(0.94); }

/* ---- Hover, on things that have one ---- */

.tpe:hover { border-color: rgba(var(--tint-rgb), 0.22); }
.accounts li:hover .acct-remove { color: var(--fail); }
.acct-remove, .ab-remove { color: var(--sage); }

/* ---- Focus ---- */

/* One focus ring, everywhere, and only for keyboards. A visible ring on every
   mouse click reads as a bug; no ring at all locks out anyone on a keyboard. */
:focus-visible {
  outline: 2px solid var(--acid);
  outline-offset: 2px;
  border-radius: 6px;
}
:focus:not(:focus-visible) { outline: none; }

/* ---- State changes ---- */

/* When the desk marks an entry, the colour arrives rather than cuts. */
.accounts li, .tpe {
  transition: border-color var(--settle) var(--ease),
    background-color var(--settle) var(--ease), color var(--settle) var(--ease);
}

/* Success is the one state that gets a little light behind it. It is the thing
   the customer is waiting for. */
.accounts li.is-done { box-shadow: 0 0 18px -6px rgba(var(--accent-rgb), 0.45); }

/* ---- Disclosures ---- */

.acct-branches, .oc-waiting-list { animation: unfold 220ms var(--ease) both; }
@keyframes unfold {
  from { opacity: 0; transform: translateY(-4px); }
  to   { opacity: 1; transform: none; }
}

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

/* ---------- the arrangement is met ---------- */
/*
   Two entries landing is a verbal agreement with the customer, not a system
   rule, and hitting it closes nothing on its own — the desk still resolves it
   by hand. Up to now the only sign of that on the card was two chips quietly
   turning green. This is the one moment worth marking: acid-toned rather than
   the red/gold vocabulary used elsewhere, so it reads as "you got what you
   came for" rather than another status flag.
*/
.success-banner {
  display: flex;
  align-items: flex-start;
  gap: 0.85rem;
  padding: 1rem 1.15rem;
  margin: 0 0 1rem;
  border: 1px solid var(--acid);
  border-radius: 12px;
  background: rgba(var(--accent-rgb), 0.1);
  box-shadow: 0 0 26px rgba(var(--accent-rgb), 0.16);
  animation: rise var(--settle) var(--ease) both;
}
.success-banner-mark {
  flex: 0 0 auto;
  width: 26px;
  height: 26px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--acid);
  color: var(--on-accent);
  font-size: 0.9rem;
  font-weight: 700;
}
.success-banner-title {
  margin: 0 0 0.2rem;
  font-family: var(--font-display);
  font-size: 0.95rem;
  color: var(--bone);
}
.success-banner-sub {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.5;
  color: var(--sage);
}

/* ---------- hitting the target, on the desk ---------- */
.order-card.is-celebrating {
  animation: desk-celebrate 2.2s var(--ease) both;
}
@keyframes desk-celebrate {
  0%   { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0.5), 0 0 18px -6px rgba(var(--accent-rgb), 0); border-color: var(--acid); }
  25%  { box-shadow: 0 0 0 6px rgba(var(--accent-rgb), 0.14), 0 0 30px -4px rgba(var(--accent-rgb), 0.45); border-color: var(--acid); }
  100% { box-shadow: 0 0 0 0 rgba(var(--accent-rgb), 0), 0 0 18px -6px rgba(var(--accent-rgb), 0); }
}

.desk-toast {
  position: fixed;
  left: 50%;
  bottom: 28px;
  z-index: 40;
  transform: translate(-50%, 12px);
  opacity: 0;
  pointer-events: none;
  max-width: min(92vw, 420px);
  padding: 12px 20px;
  border-radius: 999px;
  border: 1px solid var(--acid);
  background: var(--moss-deep);
  color: var(--bone);
  font-family: var(--font-body);
  font-size: 0.92rem;
  text-align: center;
  box-shadow: 0 8px 30px -8px rgba(0, 0, 0, 0.4), 0 0 24px -4px rgba(var(--accent-rgb), 0.3);
  transition: transform 260ms var(--ease), opacity 260ms var(--ease);
}
.desk-toast.is-in { opacity: 1; transform: translate(-50%, 0); pointer-events: auto; }
.desk-toast.is-out { opacity: 0; transform: translate(-50%, 8px); }

@media (prefers-reduced-motion: reduce) {
  .order-card.is-celebrating { animation: none; box-shadow: 0 0 0 2px var(--acid); }
}

/* ---------- entry state wins, always ---------- */
/*
 * Colour on a username means one thing: what I've done about it. Plain is
 * untouched, gold is contacted, green landed, red couldn't be got. Platform
 * used to tint these too, which meant a TikTok chip marked as contacted stayed
 * purple — two meanings competing for one channel, and the more important one
 * losing. Platform now lives in the labelled heading above each block.
 *
 * These sit last in the file on purpose: same specificity as anything above,
 * so source order decides, and state is what should decide.
 */

.accounts li.is-working,
.tpe.is-working {
  background: rgba(245, 207, 61, 0.12);
  border-color: var(--gold);
  color: #ffe89a;
  box-shadow: 0 0 14px rgba(245, 207, 61, 0.28);
}
.accounts li.is-working::before { color: var(--gold); }
.acct-flag.is-working,
.tpe.is-working .tpe-flag { color: var(--gold); }

.accounts li.is-done,
.tpe.is-done {
  background: rgba(var(--accent-rgb), 0.13);
  border-color: var(--acid);
  color: var(--bone);
  box-shadow: none;
}
.accounts li.is-done::before { color: var(--acid); }
.acct-flag.is-done,
.tpe.is-done .tpe-flag { color: var(--acid); }

.accounts li.is-failed,
.tpe.is-failed {
  background: rgba(240, 80, 60, 0.1);
  border-color: var(--fail);
  color: #ffb3a8;
  box-shadow: none;
}
.accounts li.is-failed::before { color: var(--fail); }
.accounts li.is-failed .acct-text,
.tpe.is-failed .tpe-handle {
  text-decoration: line-through;
  text-decoration-color: rgba(240, 80, 60, 0.7);
}
.acct-flag,
.tpe.is-failed .tpe-flag { color: var(--fail); }
.acct-flag.is-done { color: var(--acid); }
.acct-flag.is-working { color: var(--gold); }
