/* Organic — design-system tokens and component classes. This file is the source of truth for the system's look; retune it here and see readme.md. */

@font-face {
  font-family: "Caprasimo";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/caprasimo-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/figtree-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("/fonts/figtree-latin-600-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Figtree";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/figtree-latin-700-normal.woff2") format("woff2");
}

:root {
  --color-bg: #f5ead8;
  --color-surface: #ebddc5;
  --color-text: #201e1d;
  --color-accent: #c67139;
  --color-accent-2: #7a8a5e;
  --color-divider: color-mix(in srgb, #201e1d 16%, transparent);

  /* Tonal ramps — generated in OKLCH on one shared lightness scale, so the
     same step of any role matches the others in visual value. */
  --color-neutral-100: #f9f4ed;
  --color-neutral-200: #eee7db;
  --color-neutral-300: #dcd3c4;
  --color-neutral-400: #c0b6a5;
  --color-neutral-500: #a19786;
  --color-neutral-600: #82796a;
  --color-neutral-700: #645c50;
  --color-neutral-800: #474238;
  --color-neutral-900: #2e2b25;

  --color-accent-100: #fff2eb;
  --color-accent-200: #ffe1d0;
  --color-accent-300: #ffc6a5;
  --color-accent-400: #f6a06b;
  --color-accent-500: #d67f48;
  --color-accent-600: #b2622d;
  --color-accent-700: #8c491a;
  --color-accent-800: #643312;
  --color-accent-900: #402310;

  --color-accent-2-100: #f0fae1;
  --color-accent-2-200: #e1eecc;
  --color-accent-2-300: #ccdbb2;
  --color-accent-2-400: #aebf92;
  --color-accent-2-500: #8fa073;
  --color-accent-2-600: #728157;
  --color-accent-2-700: #56633f;
  --color-accent-2-800: #3d472b;
  --color-accent-2-900: #272e1b;

  --font-heading: "Caprasimo", system-ui, sans-serif;
  --font-heading-weight: 400;
  --font-body: "Figtree", system-ui, sans-serif;

  --space-1: 4.4px;
  --space-2: 8.8px;
  --space-3: 13.2px;
  --space-4: 17.6px;
  --space-6: 26.4px;
  --space-8: 35.2px;

  --radius-sm: 8px;
  --radius-md: 16px;
  --radius-lg: 28px;

  /* Elevation — derived from the ground: soft ink-tinted shadows on a
     light theme, a hairline edge + ambient darkness on a dark one. */
  --shadow-sm: 0 1px 2px color-mix(in srgb, #2e2b25 14%, transparent);
  --shadow-md: 0 3px 10px color-mix(in srgb, #2e2b25 16%, transparent);
  --shadow-lg: 0 12px 32px color-mix(in srgb, #2e2b25 22%, transparent);
}

body {
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
}
h1,
h2,
h3,
h4 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
}

.washed {
  filter: saturate(0.6) contrast(0.85) brightness(1.1) opacity(0.94);
}

/* ══════════════════════════════════════════════════════════════════════════
   Components — built with the tokens above. Plain CSS
   on plain HTML: no JavaScript, no build step. Each class is documented in
   readme.md and demonstrated in foundations/ and components/.
   ══════════════════════════════════════════════════════════════════════ */

*,
*::before,
*::after {
  box-sizing: border-box;
}
body {
  margin: 0;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 400;
}

/* A Closed Event is the sole visual authority on every Organic Role
 * Workspace. Keep the one shared live region available to assistive
 * technology while removing its duplicate card and the stale connectivity
 * alert from the visible terminal state. */
body:has(.event-lock:not([hidden])) [data-live-region] {
  position: fixed !important;
  width: 1px !important;
  height: 1px !important;
  margin: -1px !important;
  padding: 0 !important;
  overflow: hidden !important;
  clip-path: inset(50%) !important;
  white-space: nowrap !important;
}

body:has(.event-lock:not([hidden])) .connectivity-status {
  display: none !important;
}

/* ══════════════════════════════════════════════════════════════════════
   Shell states (docs/agents/design.md, "Shell States.dc.html") — the
   offline band, the checking-result card, and the closed-Event terminal
   notice. Every Role Workspace that loads this file shares these three
   markup hooks (`.connectivity-status`, `.action-feedback[data-state]`,
   `.event-lock`) from `role-workspace.js` and `shared.js`, so the treatment
   belongs here once rather than re-derived per surface.
   ══════════════════════════════════════════════════════════════════════ */

/* Offline (5a). A band, not a toast: it stays in flow so its real height is
   always reserved, and it carries the retry ladder's own copy rather than a
   generic "connection lost". */
.connectivity-status {
  display: flex;
  align-items: flex-start;
  /* --space-4, as the design sets it. */
  gap: var(--space-4);
  margin: 0 0 var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-300);
  color: var(--color-neutral-900);
  font-size: 14px;
  line-height: 1.5;
}
.connectivity-status[hidden] {
  display: none;
}

/*
 * The wifi-off mark `Shell States.dc.html` puts in front of this band — 24px
 * at the system's 2.75 stroke. A band of grey text reads as any other notice;
 * the mark is what says "offline" before the sentence is read, which on a
 * surface whose numbers have just been withdrawn is the whole job.
 *
 * Drawn from CSS rather than markup because `role-workspace.js` builds this
 * band for seven surfaces and two of its three shapes, and a decorative mark
 * should not have to be threaded through all of them.
 */
.connectivity-status::before {
  content: "";
  flex: none;
  /* 5a draws this at 24px — larger than design.md's general 15–20px inline
     guidance, because it leads a band rather than sitting inside a sentence.
     The artboard is the measurement that applies here. */
  width: 24px;
  height: 24px;
  margin-top: 2px;
  /* 5a strokes it `--color-neutral-800` against the band's neutral-900 text,
     so the mark reads as chrome rather than as another word. */
  background-color: var(--color-neutral-800);
  /* Lucide "wifi-off", as a same-origin file and never a data: URI. This app's
     CSP is `img-src 'self'` with no `data:` source, and a mask is fetched under
     img-src — so a data-URI mask silently fails to paint: nothing loads,
     nothing errors, the icon is simply gone. This rule existed twice, once in
     each form, and the dead data-URI copy is what the duplicate carried. */
  -webkit-mask: url("/icons/wifi-off.svg") center / contain no-repeat;
  mask: url("/icons/wifi-off.svg") center / contain no-repeat;
}
.connectivity-message {
  flex: 1;
  min-width: 0;
  /* 5a stacks a heading, an explanation and the retry line at a 6px rhythm. */
  display: grid;
  gap: 6px;
}

/* 5a splits the band in two: a heading that says what is frozen, and an
   explanation of what this particular surface has withdrawn. One flat
   sentence had to carry both, so the first thing a volunteer read was the
   longest thing on the band. */
.connectivity-heading {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 19px;
  color: var(--color-neutral-900);
}
.connectivity-detail {
  max-width: 44ch;
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-neutral-800);
}
/* "Retrying on its own — next attempt in 2s." The ladder in
   `role-workspace.js` is already doing this; without the line, a band that
   offers a Retry button reads as though nothing happens until it is pressed. */
.connectivity-retry-note {
  font-size: 13px;
  color: var(--color-neutral-700);
}
/* No Event resolved yet means no ladder running, so there is no next attempt
   to name. An empty line must not still spend the grid's 6px. */
.connectivity-retry-note:empty {
  display: none;
}
.connectivity-retry {
  flex: none;
  min-height: 44px;
}

/* The header's own offline mark (5a): a small pill beside whatever else
   lives in the header, so a glance up top confirms what the band below
   already says without reading it again. */
/* .tag .tag-neutral composed in markup for display/align-items/the pill
   radius the tail rule already gives every .tag; everything below is the
   genuine delta — Shell States 5a draws this larger and darker than
   .tag-neutral's own 11px/neutral-100 default, in the heading face every
   other pill in the header already uses. */
.header-status-pill {
  gap: 9px;
  min-height: 44px;
  padding: 0 16px;
  background: var(--color-neutral-300);
  color: var(--color-neutral-800);
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 15px;
}
.header-status-pill[hidden] {
  display: none;
}
.header-status-dot {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: currentColor;
}

/* Checking result (5b). A dropped response, so this never claims an outcome
   — it names the action and its target and freezes until the original
   result is known. `renderRecord` in shared.js owns the markup; only the
   look changes here. */
.action-feedback {
  margin: 0 0 var(--space-4);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-neutral-100);
  box-shadow: var(--shadow-sm);
  color: var(--color-text);
  font-size: 14px;
  line-height: 1.5;
}
/* No .action-feedback:focus-visible rule here: the global :focus-visible
   below already covers it — states are built in once, not restyled per
   component (design.md). */
.action-feedback-heading {
  margin: 0 0 6px;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 17px;
}
.action-feedback-status {
  margin: 0 0 var(--space-3);
  font-weight: 600;
}
.action-feedback-detail {
  display: grid;
  grid-template-columns: minmax(6rem, 12rem) minmax(0, 1fr);
  gap: 4px var(--space-4);
  margin: 0;
  min-width: 0;
}
.action-feedback-detail dt {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--color-accent-700);
}
.action-feedback-detail dt,
.action-feedback-detail dd {
  min-width: 0;
  overflow-wrap: anywhere;
}
.action-feedback-detail dd {
  margin: 0;
}
.action-feedback-dismiss {
  min-height: 44px;
  margin-top: var(--space-3);
}
.action-feedback-collapse > summary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: 44px;
  margin: calc(var(--space-4) * -1) calc(var(--space-4) * -1) 0;
  padding: var(--space-2) var(--space-4);
  cursor: pointer;
  font-weight: 600;
  list-style: none;
}
.action-feedback-collapse > summary::-webkit-details-marker {
  display: none;
}
.action-feedback-collapse-cue {
  flex: none;
}
.action-feedback-collapse > summary::after {
  content: "";
  flex: none;
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg);
  transition: transform 120ms ease;
}
.action-feedback-collapse[open] > summary::after {
  transform: rotate(225deg);
}
.action-feedback-collapse[open] > summary {
  margin-bottom: var(--space-3);
}
.action-feedback[data-collapsed="true"] {
  padding-bottom: var(--space-3);
}
.action-feedback[data-collapsed="true"] .action-feedback-heading,
.action-feedback[data-collapsed="true"] .action-feedback-status,
.action-feedback[data-collapsed="true"] .action-feedback-detail {
  display: none;
}

/* In flight: the spinner, background and text from Shell States 5b exactly
   (`--color-accent-200` / `--color-accent-800`, `--radius-lg`, `--shadow-md`). */
.action-feedback[data-state="pending"],
.action-feedback[data-state="checking"] {
  border-radius: var(--radius-lg);
  background: var(--color-accent-200);
  box-shadow: var(--shadow-md);
  color: var(--color-accent-800);
}
.action-feedback[data-state="pending"] .action-feedback-heading,
.action-feedback[data-state="checking"] .action-feedback-heading {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}
.action-feedback[data-state="pending"] .action-feedback-heading::before,
.action-feedback[data-state="checking"] .action-feedback-heading::before {
  content: "";
  flex: none;
  width: 16px;
  height: 16px;
  border: 3px solid var(--color-accent-500);
  border-top-color: transparent;
  border-radius: 999px;
  animation: shell-spin 0.8s linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .action-feedback[data-state="pending"] .action-feedback-heading::before,
  .action-feedback[data-state="checking"] .action-feedback-heading::before {
    animation: none;
  }
}
@keyframes shell-spin {
  to {
    transform: rotate(360deg);
  }
}

/* Settled and safe to keep: the sage ramp, this system's other voice. */
.action-feedback[data-state="committed"] {
  background: var(--color-accent-2-100);
  color: var(--color-accent-2-800);
}

/* Refused or lost outright — validation, failure, an offline mutation, a
   request the server never saw, or one it blocked. No red exists in this
   palette (design.md); the left edge in the dark end of the terracotta
   ramp is the distinct, serious note instead. */
.action-feedback[data-state="validation"],
.action-feedback[data-state="failure"],
.action-feedback[data-state="not-submitted"],
.action-feedback[data-state="blocked"],
.action-feedback[data-state="offline"],
.action-feedback[data-state="closed-event"] {
  border-left: 4px solid var(--color-accent-700);
  border-radius: var(--radius-sm) var(--radius-lg) var(--radius-lg)
    var(--radius-sm);
  background: var(--color-neutral-100);
}
.action-feedback[data-state="validation"] .action-feedback-status,
.action-feedback[data-state="failure"] .action-feedback-status,
.action-feedback[data-state="not-submitted"] .action-feedback-status,
.action-feedback[data-state="blocked"] .action-feedback-status,
.action-feedback[data-state="offline"] .action-feedback-status,
.action-feedback[data-state="closed-event"] .action-feedback-status {
  color: var(--color-accent-800);
}

/* A record whose anchor row is gone reads as displaced, not as a new kind of
   thing: same card, dashed edge, parked at the end of the workspace. */
.action-feedback[data-anchor="detached"] {
  border-style: dashed;
  outline: 1px dashed var(--color-neutral-400);
  outline-offset: -1px;
}

/* Event closed (5c). Terminal: no controls, no sign-in, no retry. The blob
   is the same soft decoration the gate uses, behind the content and never
   over it. */
.event-lock {
  position: relative;
  overflow: hidden;
  max-width: 640px;
  margin: var(--space-6) auto;
  padding: var(--space-8) var(--space-6);
  border-radius: 36px;
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
}
.event-lock::before {
  content: "";
  position: absolute;
  top: -9rem;
  right: -7rem;
  z-index: 0;
  width: 20rem;
  height: 20rem;
  border-radius: 48% 52% 58% 42%;
  background: radial-gradient(
    circle at 35% 35%,
    var(--color-neutral-300),
    transparent 72%
  );
  filter: blur(14px);
  pointer-events: none;
}
.event-lock-scope,
.event-lock-title,
.event-lock-detail,
.event-lock-terminal {
  position: relative;
  z-index: 1;
}
/* 5c opens with a neutral pill naming who is looking at this and at what —
   "Stall Staff · Roti Corner" — so a volunteer on the wrong device knows
   which session ended before reading the sentence that says it ended. */
.event-lock-scope {
  margin: 0 0 var(--space-4);
  font-size: 13px;
}
.event-lock-title {
  margin: 0;
  /* 5c sets this at 52px. The artboard is 720px wide and the real surface is
     the whole screen, so it is a clamp rather than a constant — but the top of
     the range is the design's own figure, not the 40px this used to stop at. */
  font-size: clamp(32px, 5vw, 52px);
  max-width: 20ch;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  line-height: 1.1;
  color: var(--color-text);
}
.event-lock-detail {
  margin: var(--space-4) 0 0;
  max-width: 40ch;
  color: var(--color-neutral-800);
  font-size: 17px;
  line-height: 1.6;
  text-wrap: pretty;
}
/* The quieter second paragraph 5c draws under the first. Only the terminal
   form gets it: a Guest keeps their session and reads on, so telling them
   there is nothing left to do on this device would be false. */
.event-lock-terminal {
  margin: var(--space-4) 0 0;
  max-width: 40ch;
  color: var(--color-neutral-700);
  font-size: 15px;
  line-height: 1.6;
}
.event-lock-terminal[hidden] {
  display: none;
}
.event-lock[hidden] {
  display: none;
}

h1,
h2,
h3,
h4,
h5,
h6 {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 var(--space-2);
}
h1 {
  font-size: 42px;
}
h2 {
  font-size: 32px;
}
h3 {
  font-size: 25px;
}
h4 {
  font-size: 20px;
}
h5 {
  font-size: 16px;
}
h6 {
  font-size: 13px;
}
h6 {
  letter-spacing: 0.08em;
  text-transform: uppercase;
}
p {
  margin: 0 0 var(--space-3);
}
a {
  color: var(--color-accent);
  text-underline-offset: 3px;
}
img {
  display: block;
  max-width: 100%;
}
figure {
  margin: 0;
}
figcaption {
  font-size: 11px;
  margin-top: var(--space-1);
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
.text-muted {
  color: color-mix(in srgb, var(--color-text) 55%, transparent);
}
:focus {
  outline: none;
}
:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
::selection {
  background: color-mix(in srgb, var(--color-accent) 30%, transparent);
}

/* — rules — */
.hr {
  height: 1px;
  border: 0;
  margin: var(--space-4) 0;
  background: var(--color-divider);
}

/* — buttons — */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  cursor: pointer;
  text-decoration: none;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 14px;
  line-height: 1.2;
  color: var(
    --color-text
  ); /* matches the .input's 14px —
     the pair sits side by side in sign-up rows */
  background: transparent;
  border: 1px solid transparent;
  padding: var(--space-2) calc(var(--space-3) * 1.2);
  border-radius: var(--radius-md);
}
.btn svg {
  display: block;
}
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}
.btn-primary {
  background: var(--color-accent);
  color: var(--color-bg);
}
.btn-primary:hover {
  background: var(--color-accent-600);
}
.btn-primary:active {
  background: var(--color-accent-700);
}
.btn-secondary {
  border-color: var(--color-divider);
}
.btn-secondary:hover {
  background: color-mix(in srgb, var(--color-text) 7%, transparent);
}
.btn-secondary:active {
  background: color-mix(in srgb, var(--color-text) 14%, transparent);
}
.btn-ghost {
  color: var(--color-accent);
  padding-inline: var(--space-1);
}
.btn-ghost:hover {
  background: color-mix(in srgb, var(--color-accent) 10%, transparent);
}
.btn-ghost:active {
  background: color-mix(in srgb, var(--color-accent) 18%, transparent);
}
.btn-icon {
  width: 36px;
  height: 36px;
  padding: 0;
}
.btn-icon:hover {
  background: var(--color-accent-100);
}
.btn-icon:active {
  background: var(--color-accent-200);
}
.btn-block {
  width: 100%;
  margin-top: var(--space-2);
}

/* — forms — */
.field > label {
  display: block;
  font-size: 12px;
  margin-bottom: 5px;
  color: color-mix(in srgb, var(--color-text) 70%, transparent);
}
.input {
  width: 100%;
  min-height: 36px;
  padding: 6px 10px;
  font: inherit;
  font-size: 14px;
  color: var(--color-text);
  caret-color: var(--color-accent);
  background: var(--color-surface);
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
}
.input:hover {
  border-color: color-mix(in srgb, var(--color-text) 45%, transparent);
}
.input:focus-visible {
  border-color: var(--color-accent);
  outline-offset: 0;
}
textarea.input {
  min-height: 90px;
  resize: vertical;
}
.radio {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  cursor: pointer;
  font-size: 14px;
}
.radio input,
.seg-opt input {
  position: absolute;
  opacity: 0;
  width: 0;
  height: 0;
  pointer-events: none;
}
.radio .dot {
  width: 16px;
  height: 16px;
  flex: none;
  border-radius: 50%;
  border: 1.5px solid var(--color-divider);
}
.radio:hover .dot {
  border-color: var(--color-accent);
}
.radio input:checked + .dot {
  border-color: var(--color-accent);
  background: var(--color-accent);
  box-shadow: inset 0 0 0 4px var(--color-bg);
}
.radio input:focus-visible + .dot {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}
.seg {
  display: inline-flex;
  overflow: hidden;
  border: 1px solid var(--color-divider);
  border-radius: var(--radius-md);
}
.seg-opt {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  font-size: 13px;
  cursor: pointer;
}
.seg-opt + .seg-opt {
  border-left: 1px solid var(--color-divider);
}
.seg-opt:has(input:checked) {
  background: var(--color-accent);
  color: var(--color-bg);
}
.seg-opt:not(:has(input:checked)):hover {
  background: color-mix(in srgb, var(--color-text) 7%, transparent);
}
.seg-opt:has(input:focus-visible) {
  outline: 2px solid var(--color-accent);
  outline-offset: -2px;
}

/* — cards — */
.card {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  padding: var(--space-3);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.card-kicker {
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-accent);
}
.card-title {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 17px;
  line-height: 1.2;
}
.card-body {
  margin: 0;
  font-size: 13px;
  opacity: 0.8;
  flex: 1;
}
.card-meta {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 11px;
  color: color-mix(in srgb, var(--color-text) 50%, transparent);
}
.elev-sm {
  box-shadow: var(--shadow-sm);
}
.elev-md {
  box-shadow: var(--shadow-md);
}
.elev-lg {
  box-shadow: var(--shadow-lg);
}

/* — tags — */
.tag {
  display: inline-flex;
  align-items: center;
  font-size: 11px;
  letter-spacing: 0.02em;
  padding: 3px 10px;
  border-radius: calc(var(--radius-md) * 0.75);
}
.tag-accent {
  background: var(--color-accent-100);
  color: var(--color-accent-800);
}
.tag-accent-2 {
  background: var(--color-accent-2-100);
  color: var(--color-accent-2-800);
}
.tag-neutral {
  background: var(--color-neutral-100);
  color: var(--color-neutral-800);
}
.tag-outline {
  border: 1px solid var(--color-accent);
  color: var(--color-accent);
}

/* — navigation — */
.nav {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border-bottom: none;
}
.nav-brand {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 18px;
  margin-right: auto;
}
.nav a {
  color: inherit;
  text-decoration: none;
  font-size: 14px;
}
.nav a:hover,
.nav a[aria-current="page"] {
  color: var(--color-accent);
}

/* A Role Workspace's own switcher between the routes one role owns
 * (admin.html/my-stall.html/all-stalls.html/overseer-settings.html each
 * carry a `.role-nav` with one or two of these) — a pill link, filled
 * solid only for the route already open. SURF-4f built this identically
 * on three of its four new surfaces and once, slightly differently, on a
 * fourth; one definition here replaces all four page-local copies. */
.role-nav-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid var(--color-accent-200);
  border-radius: 999px;
  color: var(--color-text);
  /* Figtree, stated rather than inherited. Every staff artboard draws this
     cluster as bare `<a>` elements — `Stock.dc.html`'s header is the clearest
     case, where the back pill, the peer pair, Operations and Log out all
     declare no font-family and the one label that wants Caprasimo (the
     service-state pill) says so inline. Some surfaces also compose `.btn` on
     these links, and `.btn` correctly sets `--font-heading` for real buttons,
     so without this declaration the same pill renders in Caprasimo on one
     surface and Figtree on the next. `.btn` itself is right as it stands and
     is not the thing to change. */
  font-family: var(--font-body);
  font-size: 13.5px;
  text-decoration: none;
  white-space: nowrap;
}
.role-nav-link[aria-current="page"] {
  background: var(--color-accent-600);
  border-color: var(--color-accent-600);
  color: var(--color-bg);
}

/* The back pill — the first half of the one navigation pattern every staff
 * artboard draws (DECISIONS.md, "Navigation"): a back or peer link on the
 * left, inside the title group, when the surface has a parent. Stock and Menu
 * point at Stall Queue; Stall Queue points at Stalls Overview.
 *
 * NAVIGATION.md makes this the only chevron in the bar, so `Operations` on the
 * right carries none: it is the hub, not a step back up.
 *
 * Three surfaces had grown byte-equivalent private copies of this (Menu as a
 * delta over `.btn .btn-secondary`, Stock standalone, Stall Queue page-scoped).
 * The values below are theirs; the per-surface copies still win on load order
 * and specificity, so adopting this one costs each of them only a deletion. */
.back-pill {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid var(--color-accent-200);
  border-radius: 999px;
  background: transparent;
  color: var(--color-accent-700);
  /* Figtree — see `.role-nav-link` above. Menu composes this over
     `.btn .btn-secondary`, which is where the two faces diverged. */
  font-family: var(--font-body);
  font-size: 13.5px;
  text-decoration: none;
  white-space: nowrap;
}

/* `Log out`, the one control in that bar this shell owns outright
 * (`role-workspace.js` wires it to the role's own cookie). The artboards draw
 * it last, ghost, with a log-out mark and reading just "Log out" — the role is
 * named beside it already. Ghost means ghost: no border and no fill, which is
 * what separates it from the outlined `Operations` pill next to it.
 *
 * Not composed from `.btn .btn-ghost`: that is a button style and carries the
 * heading face, and the artboards draw this in the body face like the rest of
 * the cluster. */
.logout-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 0 15px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: var(--color-accent-700);
  font-family: var(--font-body);
  font-size: 13px;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
}
.logout-link:hover {
  background: var(--color-accent-100);
  color: var(--color-accent-800);
}
.logout-link svg {
  flex: none;
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2.75;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.logout-link[hidden] {
  display: none;
}

/* Stall Queue's and Stalls Overview's own "open the stall-selection
 * control" buttons — byte-identical page-local rules until now, one of
 * which (#change-stalls) had `.clipped` composed in its markup and this
 * same block was silently overriding it anyway, on ID specificity. */
#change-stall,
#change-stalls {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid var(--color-accent-200);
  border-radius: 999px;
  background: none;
  color: var(--color-accent-700);
  font: inherit;
  font-size: 13px;
  cursor: pointer;
}

/* — tables — */
.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 14px;
}
.table th {
  text-align: left;
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: color-mix(in srgb, var(--color-text) 60%, transparent);
  padding: var(--space-2);
  border-bottom: 1px solid var(--color-divider);
}
.table td {
  padding: var(--space-2);
  border-bottom: 1px solid color-mix(in srgb, var(--color-text) 8%, transparent);
}
.table tbody tr:hover {
  background: color-mix(in srgb, var(--color-text) 4%, transparent);
}

/* — dialog — */
.dialog-backdrop {
  position: fixed;
  inset: 0;
  display: grid;
  place-items: center;
  padding: var(--space-4);
  background: color-mix(in srgb, var(--color-neutral-900) 50%, transparent);
}
.dialog {
  width: min(440px, 100%);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
  box-shadow: var(--shadow-lg);
}
.dialog-title {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 20px;
}
.dialog-body {
  font-size: 14px;
  opacity: 0.85;
}
.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--space-2);
  margin-top: var(--space-2);
}

/* — rounded frame: everything softens, small controls go pill — */
.card,
.dialog {
  border-radius: calc(var(--radius-lg) * 1.15);
}
.btn,
.tag,
.seg,
.input {
  border-radius: 999px;
}
.input {
  padding-inline: 14px;
}

/* ── the peer pair ──
 *
 * NAVIGATION.md's header pattern: "Peers are a segmented pair with the current
 * one filled, not a link pointing sideways" — Menu ⇄ Stock, Operations ⇄ Event
 * setup, Stall Queue ⇄ Stalls Overview.
 *
 * Measured off `Operations.dc.html`, which is the artboard that actually draws
 * one: the current peer is a filled `--color-accent-600` pill with `--color-bg`
 * text, the other is a plain `--color-accent-700` link, and there is no trough
 * behind the pair. An earlier pass here invented an accent-100 trough with the
 * current option raised out of it — closer to a tab strip than to what the
 * design draws, and wider, which cost the header a row it did not have.
 *
 * Deliberately not `.seg`, which is this system's *form* control: a bordered
 * radio group that answers a question. A peer switch is navigation — two links,
 * one of which is where you already are — so it is marked with
 * `aria-current="page"` rather than a checked input.
 */
.peer-pair {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-1);
  max-width: 100%;
}

.peer-option {
  display: inline-flex;
  align-items: center;
  /* So a long surface name shortens rather than widening the bar. */
  min-width: 0;
  /* The 44px touch floor holds here too: these are real destinations, and
   * every staff surface's own control-size check counts them. */
  min-height: 44px;
  padding: 0 17px;
  /* No outline on either half. The markup composes `role-nav-link peer-option`
     and `.role-nav-link` brings a 1px `--color-accent-200` border with it, so
     the non-current half painted a faint pill the artboards do not draw:
     `Stock.dc.html`'s pair is two bare elements, the current one filled
     `--color-accent-600` and the other plain text, with no border on either.
     Reported by the Operations agent and confirmed against that artboard. */
  border: 0;
  border-radius: 999px;
  color: var(--color-accent-700);
  /* Figtree — see `.role-nav-link`. */
  font-family: var(--font-body);
  font-size: 13.5px;
  text-decoration: none;
}

.peer-option:hover {
  background: var(--color-accent-100);
  color: var(--color-accent-800);
}

/* Where you already are: filled, so the pair reads as a position rather than
 * as two buttons one of which happens to be selected. */
.peer-option[aria-current="page"] {
  background: var(--color-accent-600);
  color: var(--color-bg);
}

.peer-option[aria-current="page"]:hover {
  background: var(--color-accent-600);
  color: var(--color-bg);
}
