/**
 * Est Est Est Pizza — shared component layer. Loads AFTER tokens.css.
 *
 * Two jobs:
 *
 *   1. Define the canonical primitives (button, field, card, toast, empty
 *      state) once, so new work stops inventing a sixth button.
 *   2. Repair defects that exist across the apps TODAY — chiefly touch
 *      targets — by targeting the class names already in the templates. That
 *      fixes real screens now rather than waiting on a rewrite.
 *
 * Why a button system was needed
 * ------------------------------
 * "A button" was defined five times, five ways:
 *
 *   home .btn-primary   999px radius · 14/26 pad · 15px   · 600 · no min-height
 *   site .primary       999px radius · 14/20 pad · 14.5px · 600 · no min-height
 *   admin .btn          999px radius · 10/18 pad · inherit·  —  · 44px
 *   driver .btn          14px radius · 16/20 pad · 17px   · 700 · 56px
 *   stations .s-done      9px radius ·   —      · 17px   · 800 · 56px
 *
 * The operational apps set a minimum height. The CUSTOMER-facing ones — the
 * screens people actually use on a phone — did not, and measured 34-41px.
 */

/* =====================================================================
   TOUCH TARGETS — the defect, fixed on the classes that ship today.

   WCAG 2.5.5 (AAA) and Apple's HIG both put the floor at 44x44 CSS px.
   Measured on /order.html at 375px wide, 21 controls were under it:
   the Pickup/Delivery toggle at 34px, category nav at 36px, cart at 41px.
   Those are the primary controls on the ordering path, on the device most
   orders come from.

   Height is raised via min-height rather than padding so nothing reflows
   sideways and no existing layout breaks.
   ===================================================================== */
.seg-btn,
.catnav button,
.cart-toggle,
.icon-btn,
.addr-check,
.tab,
.band-link,
/* Added after a 768px audit: the header's own two links measured 41px and
   40px. A tablet is a touch device, and these are the wordmark ("go home")
   and the account link -- header controls are the last thing that should be
   awkward to hit. */
.topbar-link,
.topbar .brand {
  min-height: 44px;
}

/* Icon-only controls need width too — a 32px square close button is the
   hardest thing on the page to hit and the easiest to mis-tap. */
.icon-btn {
  min-width: 44px;
}

/* Text links sitting inline in prose are exempt: WCAG explicitly excludes
   inline links, and padding them out would wreck the paragraph. */

/* =====================================================================
   BUTTON — the canonical primitive.

   `.btn` (admin, driver) and `.primary` (customer cart/sheet) are listed
   alongside it rather than left to restate the base themselves. Those apps
   still override what they deliberately differ on -- the driver's 14px
   radius and 56px thumb target, the customer CTA's space-between layout --
   and because this file loads first, those deltas still win. The difference
   is that the delta is now the ONLY thing the app declares, so reading its
   stylesheet tells you what is intentional about that button instead of
   burying two intentional lines in eight restated ones.
   ===================================================================== */
.ui-btn,
.btn,
.primary {
  --_bg: transparent;
  --_fg: var(--ink);
  --_bd: var(--line);

  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-8);

  /* border-box so 44px means 44px on every page: the homepage does not set
     the global border-box that styles.css gives the others, and its buttons
     were rendering 62px tall -- padding added on top of the floor. */
  box-sizing: border-box;
  min-height: 44px;                /* never below the touch floor */
  padding: var(--space-14) var(--space-28);

  background: var(--_bg);
  color: var(--_fg);
  border: 1px solid var(--_bd);
  border-radius: var(--radius-pill);

  font: var(--weight-semi) var(--text-base)/1 var(--font-body);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;

  transition: filter var(--dur-fast) var(--ease),
              border-color var(--dur-fast) var(--ease),
              transform var(--dur-fast) var(--ease);
}
.ui-btn:hover { filter: brightness(1.08); }
.ui-btn:active { transform: translateY(1px); }
.ui-btn:disabled,
.ui-btn[aria-disabled='true'] {
  opacity: .5;
  cursor: not-allowed;
  filter: none;
  transform: none;
}

.ui-btn--primary { --_bg: var(--accent); --_fg: var(--ink-onAccent); --_bd: transparent; }
.ui-btn--ghost   { --_bg: transparent;   --_fg: var(--ink);          --_bd: var(--line); }
.ui-btn--ghost:hover { border-color: var(--line-strong); filter: none; }
.ui-btn--quiet   { --_bg: var(--bg-card); --_fg: var(--ink-dim);     --_bd: var(--line); }
.ui-btn--danger  { --_bg: var(--danger);  --_fg: var(--danger-ink);  --_bd: transparent; }
.ui-btn--go      { --_bg: var(--ok);      --_fg: var(--ok-ink);      --_bd: transparent; }

/* Sizes. `lg` is the kitchen/driver size — read and hit at arm's length,
   with a glove on, in a hurry. */
.ui-btn--sm { min-height: 44px; padding: var(--space-8) var(--space-16); font-size: var(--text-sm); }
.ui-btn--lg { min-height: 56px; padding: var(--space-16) var(--space-24); font-size: var(--text-lg); font-weight: var(--weight-bold); }
.ui-btn--block { width: 100%; }

/* =====================================================================
   FIELD — text inputs, selects, textareas.
   ===================================================================== */
.ui-field {
  width: 100%;
  min-height: 44px;
  padding: var(--space-12) var(--space-16);
  background: var(--bg-card);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  font: var(--weight-normal) var(--text-base)/1.4 var(--font-body);
  transition: border-color var(--dur-fast) var(--ease);
}
.ui-field::placeholder { color: var(--ink-faint); }
.ui-field:hover { border-color: var(--line-strong); }
.ui-field:focus { outline: none; border-color: var(--accent); }
.ui-field[aria-invalid='true'] { border-color: var(--danger); }

.ui-label {
  display: block;
  margin-bottom: var(--space-8);
  font-size: var(--text-sm);
  font-weight: var(--weight-medium);
  color: var(--ink-dim);
}

/* Error text is announced AND visible — colour alone is not an indicator
   (WCAG 1.4.1), so the message carries the meaning. */
.ui-error {
  margin-top: var(--space-8);
  font-size: var(--text-sm);
  color: var(--danger);
}

/* =====================================================================
   CARD
   ===================================================================== */
.ui-card {
  background: var(--bg-card);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-20);
}
.ui-card--interactive {
  cursor: pointer;
  transition: transform var(--dur) var(--ease), border-color var(--dur) var(--ease);
}
.ui-card--interactive:hover { transform: translateY(-2px); border-color: var(--line-strong); }

/* =====================================================================
   EMPTY STATE — a real component, because "nothing here" is a state that
   every list hits and each app was rendering differently (or not at all).
   ===================================================================== */
.ui-empty {
  padding: var(--space-56) var(--space-24);
  text-align: center;
  color: var(--ink-faint);
  font-size: var(--text-base);
}
.ui-empty strong { display: block; color: var(--ink-dim); margin-bottom: var(--space-8); }

/* =====================================================================
   TOAST
   ===================================================================== */
.ui-toast {
  position: fixed;
  left: 50%;
  bottom: var(--space-24);
  transform: translateX(-50%);
  z-index: 90;
  padding: var(--space-12) var(--space-20);
  background: var(--bg-card-hi);
  color: var(--ink);
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-pill);
  font-size: var(--text-sm);
  box-shadow: var(--shadow-pop);
}
.ui-toast[hidden] { display: none; }

/*
 * The floor under every `el.hidden = true` in every app.
 *
 * The `hidden` attribute is only the user agent's `display: none`, and any
 * author rule that sets `display` on the same element wins over it. The POS
 * lock screen (`display: grid`) stayed painted over the kitchen board after
 * the owner's first production sign-in for exactly that reason. `!important`
 * here restores what everyone assumes `hidden` means, in all six apps, from
 * the one file they all load. An element that must show while carrying the
 * attribute does not exist in this codebase, and should not.
 */
[hidden] { display: none !important; }
.ui-toast--bad { border-color: var(--danger); color: #ffb0a4; }

/* =====================================================================
   EYEBROW — the small caps label above a heading.

   Both the customer and manager analyses independently asked for this:
   Stitch sets a 12px / .15em / 600 caps label above almost every display
   heading, and it is a large part of why those mockups read as editorial
   rather than as an app. We had the tokens (--text-xs, --tracking-caps)
   but no component, so each surface re-declared it inline.
   ===================================================================== */
.ui-eyebrow {
  display: block;
  margin-bottom: var(--space-8);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--gold, var(--accent-2));
}

/* The same label with a hairline rule running out from it. One small mark
   that does a disproportionate amount of the work of looking editorial
   rather than templated — it gives every section a visible left edge to
   start from, which is what makes a stack of sections read as one composed
   page instead of a list of blocks. Inline-flex so the rule takes whatever
   width is left rather than a guessed one. */
.ui-eyebrow--rule {
  display: flex;
  align-items: center;
  gap: var(--space-14);
}
.ui-eyebrow--rule::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
}

/* Typography hygiene (2026-10-09): headings break into even lines and body
   copy never ends on a lone word ("10% off / online", "Whole pies, half & /
   half"). :where() keeps specificity at zero, so any rule can still override. */
:where(h1, h2, h3, h4, h5, h6) { text-wrap: balance; }
:where(p, li, dd, figcaption, blockquote) { text-wrap: pretty; }

/* =====================================================================
   WORDMARK — the name over the door, and it must be the same door.

   This was two different marks for one restaurant. The marketing header set
   it in the display face, in --ink, with accent-coloured separator dots. The
   ordering app set it in the BODY face at .16em tracking, filled with an
   accent-to-accent-2 gradient clipped to the text, with the dots at 50%
   opacity. A customer moving from the homepage to the order page watched the
   logo change typeface, colour and letter-spacing — which is precisely the
   "five apps that had quietly diverged" problem tokens.css was created to
   end, except this time in a component rather than a variable.

   Canonical here, so there is one. The display face is the right call: the
   wordmark is a NAME, not UI chrome, and Fraunces is what makes it read as a
   sign rather than a nav item.
   ===================================================================== */
.brand-mark {
  font-family: var(--font-display);
  font-weight: var(--weight-bold);
  font-size: var(--text-lead);
  letter-spacing: .04em;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
/* The separator dots. Accent-coloured rather than dimmed, because they are
   the only brand colour in the mark and at 50% opacity they read as dirt on
   the screen rather than as punctuation. */
.brand-mark span { color: var(--accent); margin: 0 var(--space-4); }

/* =====================================================================
   EDITORIAL — the shared vocabulary of the marketing surface.

   The homepage, the seven /pages/* documents and the ordering app were
   each declaring their own section heading, lead paragraph and divider.
   Same three jobs, three spellings, and they had drifted: headings ranged
   34-40px, ledes 15-17px, and only some capped their measure. These are
   the canonical versions.
   ===================================================================== */

/* Section heading. --text-display, not --text-3xl: see the note on those
   tokens for why the fixed ramp tops out too low for this job. */
.ui-display {
  font-family: var(--font-display);
  font-size: var(--text-display);
  line-height: var(--leading-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--ink);
  margin: 0;
  text-wrap: balance;
}
.ui-display--lg { font-size: var(--text-display-lg); }

/* Lead paragraph. Capped at --maxw-text because an uncapped paragraph in a
   1240px container runs to ~150 characters, about double what anyone reads
   comfortably. */
.ui-lede {
  font-size: var(--text-lead);
  line-height: var(--leading-body);
  color: var(--ink-dim);
  max-width: var(--maxw-text);
  margin: 0;
}

/* Hairline divider. A full-strength --line across a wide container reads as
   a hard box edge; fading it at both ends reads as a considered rule. */
.ui-rule {
  height: 1px;
  border: 0;
  margin: 0;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}

/* =====================================================================
   STATUS — one tinted-surface primitive, replacing the per-app rgba()
   guesses that had accumulated (four stylesheets, four different opinions
   on how strong a tint should be).

   Colour NEVER carries the meaning alone (WCAG 1.4.1): these set a tint,
   an edge and a text colour, and the caller still has to write the word.
   ===================================================================== */
.ui-status {
  display: inline-flex;
  align-items: center;
  gap: var(--space-8);
  padding: var(--space-4) var(--space-12);
  border: 1px solid var(--_edge, var(--line));
  border-radius: var(--radius-pill);
  background: var(--_tint, transparent);
  color: var(--_fg, var(--ink-dim));
  font-size: var(--text-xs);
  font-weight: var(--weight-semi);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
}
.ui-status--ok      { --_tint: var(--ok-tint);      --_edge: var(--ok-edge);      --_fg: var(--ok); }
.ui-status--warn    { --_tint: var(--warn-tint);    --_edge: var(--warn-edge);    --_fg: var(--warn); }
.ui-status--danger  { --_tint: var(--danger-tint);  --_edge: var(--danger-edge);  --_fg: var(--danger); }
.ui-status--info    { --_tint: var(--info-tint);    --_edge: var(--info-edge);    --_fg: var(--info); }
.ui-status--special { --_tint: var(--special-tint); --_edge: var(--special-edge); --_fg: var(--special); }
.ui-status--cash    { --_tint: var(--cash-tint);    --_edge: var(--cash-edge);    --_fg: var(--cash); }
.ui-status--accent  { --_tint: var(--accent-tint);  --_edge: var(--accent-edge);  --_fg: var(--accent-2); }

/* =====================================================================
   METER — progress / capacity bar. Used for loyalty progress today and
   for the analytics comparison rows the manager surface wants.

   A plain <div> pair rather than <progress>, which cannot be styled
   consistently across engines without vendor pseudo-elements.
   ===================================================================== */
.ui-meter {
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--data-track);
  overflow: hidden;
}
.ui-meter > i {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: var(--accent);
  /* Width is set inline from real data. Transition so a value that updates
     on poll slides rather than jumping — honoured-reduced-motion aware via
     the global block in tokens.css. */
  transition: width var(--dur-slow) var(--ease);
}

/* Tabular figures. Columns of numbers jitter with proportional digits,
   which makes them hard to compare down a list — a real legibility issue
   on the analytics and shift-total screens, not a typographic nicety. */
.ui-nums { font-variant-numeric: tabular-nums; }

/* =====================================================================
   VISUALLY HIDDEN — for screen-reader-only text. Needed for the icon-only
   buttons that currently rely on aria-label alone.
   ===================================================================== */
.ui-sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* =====================================================================
   SKIP LINK — the first focusable element on any page with a fixed/sticky
   header. Off-screen like .ui-sr-only until it receives keyboard focus,
   then it has to actually be visible and land above everything else —
   the whole point is a keyboard user can see it and use it before tabbing
   through the header's nav on every single page load.
   ===================================================================== */
.ui-skip-link {
  position: fixed;
  top: var(--space-8);
  left: var(--space-8);
  z-index: 1000;
  transform: translateY(-150%);
  padding: var(--space-10) var(--space-16);
  background: var(--accent);
  color: var(--ink-onAccent);
  font-size: var(--text-sm);
  font-weight: var(--weight-semi);
  border-radius: var(--radius-sm);
  text-decoration: none;
  transition: transform var(--dur-fast) var(--ease);
}
.ui-skip-link:focus {
  transform: translateY(0);
  box-shadow: var(--focus-ring);
  outline: none;
}

/* Checkboxes, radios and sliders in the brand accent everywhere (audit
   2026-09-29: Admin's were the browser's default blue). accent-color is
   inherited, so setting it once here covers every app. */
:root { accent-color: var(--accent); }
