/* ==========================================================================
   tokens.css — SOURCE. Brand tokens for BARM (fictional grab-and-go
   sandwich & bakery bar). Do NOT touch the two alias blocks below —
   they're what make base.css, components.css, and admin.html /
   calendar-help.html work without edits on every project.
   ========================================================================== */

:root {
  /* ============ BRAND TOKENS ============
     High-street bakery counter, not artisan-cafe: a deep workwear navy
     (the colour of a shop awning/apron) against a warm proofing-paper
     cream, with a caution-tape yellow doing all the shouting and a
     single stamped red reserved for the signature element only. */
  --ink:          #10233d;   /* awning navy — headings, nav, footer */
  --paper:        #fff9ef;   /* proofing paper cream — page background */
  --paper-alt:    #fdecc0;   /* butter — alternating section background */
  --accent-raw:       #ffc72c; /* counter yellow — buttons, focus, price tags */
  --accent-raw-hover: #e0ac00;
  --stamp-red:    #c8392a;   /* ink-stamp red — signature element ONLY */
  --muted:        #5b5140;   /* warm bread-crust grey-brown */
  --border-raw:   #e7d9b8;

  --font-display: 'Baloo 2', 'Arial Rounded MT Bold', system-ui, sans-serif;
  --font-body:    'Inter', system-ui, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, monospace; /* price tags */

  --radius:       0.6rem;
  --radius-lg:    1rem;

  /* ============ STRUCTURAL TOKENS — reusable as-is ============
     Fixes: --container-pad has a clamp() floor so it doesn't collapse
     on narrow viewports; --nav-height feeds scroll-padding-top so
     anchor jumps don't land under the sticky header. */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.5rem;
  --space-6:  2rem;
  --space-7:  3rem;
  --space-8:  4rem;

  --container-max:   72rem;
  --container-pad:   clamp(1.5rem, 6vw, 5rem);
  --nav-height:       4.5rem;

  /* ============ REQUIRED ALIAS — base.css focus-ring depends on this ============
     Every token file MUST define --accent. base.css uses it for
     :focus-visible outlines; without this alias present, focus rings
     silently fall back to the browser default instead of the brand
     colour. Point it at your real accent token, don't rename it. */
  --accent:        var(--accent-raw);
  --accent-hover:  var(--accent-raw-hover);

  /* ============ GENERIC ALIAS LAYER — powers admin.html / calendar-help.html ============
     Internal/admin pages are built once, against generic names, so the
     same admin template works unmodified across every client site.
     This block must always be present in tokens.css, even though the
     public marketing pages never read these names directly — if it's
     missing, admin pages render with native unstyled inputs and no
     card treatment the moment they're dropped in. Keep every name on
     the left; only the values on the right change per client. */
  --color-accent:        var(--accent);
  --color-accent-hover:  var(--accent-hover);
  --color-bg:            var(--paper);
  --color-bg-alt:        var(--paper-alt);
  --color-text:          var(--ink);
  --color-text-muted:    var(--muted);
  --color-border:        var(--border-raw);
  --color-white:         #ffffff;
  --color-error:         #b3261e;
  --color-success:       #15803d;

  --space-1-alt: var(--space-1); /* aliases kept 1:1 on purpose — */
  --text-sm:     0.875rem;       /* admin.html reads --text-sm directly */
}
/* ==========================================================================
   base.css — SOURCE. Reset + element defaults. Reusable as-is across
   every project — don't edit per client.
   ========================================================================== */

*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Fix: sticky/fixed nav needs scroll-padding-top equal to its height,
     set once globally, or every anchor jump (native fragment nav,
     scrollIntoView, tab links) lands its target underneath the nav. */
  scroll-padding-top: var(--nav-height);
}

body {
  font-family: var(--font-body);
  color: var(--ink);
  background: var(--paper);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  line-height: 1.15;
  font-weight: 600;
}

img, picture, svg, video { display: block; max-width: 100%; }

/* Opt-in, not opt-out: lists default to no markers because most lists
   in a landing page are nav/primitive lists, not real numbered/bulleted
   content. Pages with genuine step lists must opt back in explicitly
   per list (e.g. `ol.help-steps { list-style: decimal; }`) — otherwise
   the numbers silently vanish while the text still reads fine, which
   is easy to miss in review. */
ul, ol { list-style: none; padding: 0; }

a { color: inherit; text-decoration: none; }

button, input, textarea, select { font: inherit; color: inherit; }
button { cursor: pointer; }

/* Fix: some shared layout classes (e.g. .stack, .cluster) set
   display:flex on their own children — that silently beats the
   browser's own [hidden] { display:none } default on any element that
   also carries one of those classes. This override makes [hidden]
   actually win regardless of what else is applied alongside it. */
[hidden] { display: none !important; }

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

/* No skip-to-content link by default — these are simple one-pagers.
   Add one explicitly only if a specific project asks for it. */
/* ==========================================================================
   layout.css — SOURCE. Generic layout primitives. Reusable as-is,
   rarely needs edits. Before writing fresh flex/grid for a new section,
   check this file first.

   Canonical breakpoints, used everywhere in this file and components.css:
     max-width: 640px   mobile
     max-width: 960px   tablet & down
     min-width: 961px   desktop & up
   ========================================================================== */

.container {
  max-width: var(--container-max);
  margin-inline: auto;
  /* Fix: --container-pad has a clamp() floor in tokens.css so this
     never collapses to near-zero on narrow viewports. */
  padding-inline: var(--container-pad);
}

.section          { padding-block: var(--space-8); }
.section--alt     { background: var(--paper-alt); }
.section--dark    { background: var(--ink); color: var(--paper); }

.stack            { display: flex; flex-direction: column; }
.stack > * + *     { margin-top: var(--space-4); }
.stack--tight > * + * { margin-top: var(--space-2); }
.stack--loose > * + * { margin-top: var(--space-7); }
/* Fix: margin-top does nothing to inline elements. A footer link list
   built from bare <a> tags inside .stack collapses onto one line
   without this — markup is correct, display:inline just ignores
   margin-top. */
.stack > a        { display: block; }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-7);
  align-items: center;
}
@media (max-width: 960px) {
  .split { grid-template-columns: 1fr; }
}

.grid-auto {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
  gap: var(--space-6);
}

.grid-fixed-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}
@media (max-width: 960px) {
  .grid-fixed-3 { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 640px) {
  .grid-fixed-3 { grid-template-columns: 1fr; }
}
/* ==========================================================================
   components.css — SOURCE. Nav/button/card/form/tab mechanics are
   reusable as-is. Colours, radius values, and the signature element
   are project-specific — replace those, keep the mechanics.
   ========================================================================== */

/* ---------- Nav ----------
   Fix: .nav__bar and .nav__panel are BOTH children of .nav__inner, a
   single shared flex row — not siblings of it. Splitting them as
   siblings under <header> misaligns the nav links from the logo/toggle
   the moment the panel opens. */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: var(--paper);
  border-bottom: 1px solid var(--border-raw);
}
.nav__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--nav-height);
  position: relative; /* .nav__panel anchors to this */
}
.nav__logo {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 1.3rem;
  color: var(--ink);
  letter-spacing: 0.02em;
}
.nav__bar {
  display: none;
  gap: var(--space-6);
}
.nav__bar a { font-weight: 600; }
.nav__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: none;
  padding: var(--space-2);
  color: var(--ink);
}
.nav__toggle svg { width: 1.5rem; height: 1.5rem; }
.nav__panel {
  display: none;
  flex-direction: column;
  gap: var(--space-1);
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  background: var(--paper);
  border-bottom: 1px solid var(--border-raw);
  padding: var(--space-4) 0;
}
.nav__panel.is-open { display: flex; }
/* Fix: a nav CTA button reusing full .btn styling can collide with
   .nav__panel's own link styling depending on load order/specificity.
   Scoping plain nav links to :not(.btn) keeps the CTA button looking
   like a button regardless. */
.nav__panel a:not(.btn) {
  padding: var(--space-2) var(--container-pad);
  font-weight: 500;
}
.nav__panel .btn { margin-inline: var(--container-pad); }

@media (min-width: 961px) {
  .nav__bar { display: flex; align-items: center; }
  .nav__toggle { display: none; }
  .nav__panel { display: none !important; }
}

/* ---------- Buttons ----------
   Fix: inline-flex without justify-content:center pins a full-width
   button's label to the left in a flex column. Centering is part of
   the default, not something each variant re-adds. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius);
  font-weight: 700;
  border: 1.5px solid transparent;
  text-align: center;
  font-family: var(--font-display);
  letter-spacing: 0.01em;
}
.btn--primary {
  background: var(--accent);
  color: var(--ink);
}
.btn--primary:hover { background: var(--accent-hover); }
.btn--outline {
  background: transparent;
  border-color: var(--ink);
  color: var(--ink);
}
.btn--outline:hover { background: var(--ink); color: var(--paper); }
.btn--block { width: 100%; }

/* ---------- Cards ----------
   Fix: an offset "behind" shape using a second independently-curved
   element (its own per-corner border-radius) doesn't stay a constant
   distance from the card if box size or curvature differs even
   slightly — the two curves cross at the corners and leak a hairline
   of the background colour through anti-aliasing. A single box-shadow
   on the card itself gives the same offset/shadow effect with nothing
   to keep in geometric sync. Swap the colour/offset per project;
   don't reintroduce a second shape. */
.card {
  background: var(--color-white);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  box-shadow: 0.4rem 0.4rem 0 var(--accent);
}

/* ---------- Forms ----------
   Fix: inputs/textareas inside a flex or grid layout size to their own
   intrinsic width by default, not their column — width:100% plus
   min-width:0 (to guard against overflow in a tight grid track) is
   required on every field, not assumed. */
.field { margin-bottom: var(--space-4); }
.field label {
  display: block;
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--muted);
  margin-bottom: var(--space-2);
}
.field input,
.field textarea,
.field select {
  width: 100%;
  min-width: 0;
  padding: var(--space-3);
  border: 1.5px solid var(--border-raw);
  border-radius: var(--radius);
  background: var(--color-white);
}
.field input:focus,
.field textarea:focus { outline: none; border-color: var(--accent); }
.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}
@media (max-width: 640px) {
  .field-row { grid-template-columns: 1fr; }
}

/* ---------- Tabs ----------
   Fix (progressive enhancement): content hidden via [hidden] is
   unreachable with no JS and no fallback. Panels are visible (stacked)
   by default; only .js — added by an inline script at the very top of
   <head>, before anything else runs — gates the collapse to a tab
   view. This uses its own class rather than the [hidden] attribute so
   it doesn't collide with base.css's global [hidden] override. */
.tabs__list { display: flex; gap: var(--space-2); flex-wrap: wrap; margin-bottom: var(--space-5); }
.tabs__tab {
  padding: var(--space-2) var(--space-4);
  border-radius: 999px;
  border: 1.5px solid var(--border-raw);
  background: var(--color-white);
  font-weight: 700;
  font-size: 0.9rem;
  font-family: var(--font-display);
}
.tabs__tab[aria-selected="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--ink);
}
.tab-panel + .tab-panel { margin-top: var(--space-6); }
.js .tab-panel:not(.is-active) { display: none; }

/* ---------- Scroll reveal ----------
   Fix: a hidden starting state set unconditionally in CSS
   ([data-reveal]{opacity:0}) means that if the driving script ever
   fails to run, the content is gone permanently — including, on a
   past build, an entire hero headline. The script adds its own
   .reveal-pending class before animating; the [data-reveal] attribute
   alone does nothing visually. */
.reveal-pending { opacity: 0; transform: translateY(1rem); }
.reveal-pending.is-visible {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s ease, transform 0.5s ease;
}

/* ==========================================================================
   BARM — project-specific components. Mechanics above are untouched;
   everything below is this brief's own signature and supporting styles.
   ========================================================================== */

/* ---------- Ink stamp ----------
   A rubber-stamped badge, the kind you'd see thumped onto a paper bag
   behind the counter. Reserved red, used once, overlapping the hero
   photo — never reused as a generic badge component elsewhere. */
.stamp {
  position: absolute;
  width: 7.25rem;
  height: 7.25rem;
  border-radius: 50%;
  border: 3px solid var(--stamp-red);
  outline: 1px solid var(--stamp-red);
  outline-offset: -6px;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: var(--space-3);
  color: var(--stamp-red);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.85rem;
  line-height: 1.2;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  background: rgba(255, 249, 239, 0.6);
  mix-blend-mode: multiply;
  transform: rotate(-9deg);
}
@media (max-width: 640px) {
  .stamp { width: 6rem; height: 6rem; font-size: 0.72rem; }
}

/* ---------- Meal deal board ----------
   Opt-in numbering (base.css defaults ol to no markers) because this
   content genuinely is numbered — real meal deal boards number their
   options, this isn't decoration. */
.meal-deals {
  list-style: decimal;
  padding-left: 1.4rem;
}
.meal-deals li { padding-left: var(--space-2); }
.meal-deals li + li { margin-top: var(--space-3); }
.meal-deals li::marker {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--stamp-red);
}

/* ---------- Price tags ----------
   Chalkboard-mono price, same treatment everywhere a price appears. */
.price-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 0.85rem;
  background: var(--accent);
  color: var(--ink);
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  white-space: nowrap;
}

/* ---------- Counter list (menu items) ---------- */
.counter-item {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: var(--space-3);
  border-bottom: 1px dashed var(--border-raw);
}
.counter-item:last-child { border-bottom: none; }
.counter-item h4 { font-size: 1rem; }
.counter-item p { color: var(--muted); font-size: 0.9rem; margin-top: var(--space-1); }

/* ---------- Hours table ---------- */
.hours-list { font-family: var(--font-mono); font-size: 0.95rem; }
.hours-list .cluster { justify-content: space-between; }

/* ---------- Map embed ----------
   A wrapper div carries the aspect-ratio and overflow:hidden — the
   iframe itself just fills it (width/height 100%). Reserving space on
   an ordinary block element is reliable; relying on aspect-ratio
   directly on a replaced element like an iframe is not. */
.map-embed {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1.5px solid var(--border-raw);
  aspect-ratio: 4 / 3;
}
.map-embed iframe {
  width: 100%;
  height: 100%;
  border: 0;
  display: block;
}
