/* FORGE components -- the shared token layer (B5, 2026-09-24).

   THE ONLY WAY TO SKIN A COMPONENT IS A CUSTOM PROPERTY. Every `--fc-*` token
   below reads the design-system contract first (design_systems.REQUIRED_VARS:
   --color-accent, --radius-md, --font-body ...) and falls back to a neutral
   that passes WCAG AA on white, so a component dropped on a bare page is
   still legible, and a page that links any tokens.css re-skins all of them.
   No component CSS names a colour, a font or a radius directly.

   CONTRAST THAT HOLDS UNDER ANY SKIN (W3d, 2026-09-24). The first cut trusted
   the skin's pairs -- --color-accent-contrast over --color-accent, the accent
   as text over the surface -- and the live Heindl build showed what that
   trust costs: an orange accent with a white contrast token is 3.8:1, so
   every button, badge and pressed chip on the parts page failed AA. Two
   tokens are therefore DERIVED here rather than read, where the browser can
   do the arithmetic (relative colour syntax, Chromium 119+ / Safari 16.4+ /
   Firefox 128+), with the skin's own token as the fallback everywhere else:
     --fc-accent-contrast   black or white over the accent, by CIE lightness:
                            L* 49.44 is the lightness where black and white
                            both clear 4.5:1, so one of the two ALWAYS reads.
     --fc-accent-text       the accent when it is TEXT on a surface: pulled
                            45% toward the text colour in lch, so it keeps
                            its hue but sits on the text's side of the
                            surface (an orange on white becomes a deep rust,
                            a gold on near-black a pale gold).
   What CSS cannot check -- a muted token typed for the canvas and read on a
   card, a text token over an alt surface -- _shared/contrast.js measures on
   mount and repairs, leaving its trail in data-fc-contrast-* attributes. */
[data-forge-component], .fc-composition {
  --fc-bg: var(--color-surface, #ffffff);
  --fc-bg-alt: var(--color-surface-alt, #f3f4f6);
  --fc-text: var(--color-text, #111827);
  --fc-muted: var(--color-text-muted, #4b5563);     /* 7.5:1 on white */
  --fc-accent: var(--color-accent, #1d4ed8);         /* 6.7:1 on white */
  --fc-accent-contrast: var(--color-accent-contrast, #ffffff);
  --fc-accent-2: var(--color-accent-2, #0f172a);
  --fc-accent-2-contrast: var(--color-accent-contrast, #ffffff);
  --fc-accent-text: var(--fc-accent);                /* derived below where the browser can */
  /* THE FILL (W35b, 2026-09-25): the accent as a FIELD -- buttons, badges, a
     pressed chip, the current-page rule, a price-list section bar -- is the
     brand's TRUE colour, not the text-safe tint. O'Betty's wordmark red has to
     be lightened to read as TEXT on its charcoal (it came out pink), but as a
     field under white text it is already 5.9:1. art_director writes
     --color-accent-fill only when it tinted the text accent; every other skin
     falls through to the accent itself, so an old tokens.css (Heindl's
     yellow under black) renders exactly as before. */
  --fc-accent-fill: var(--color-accent-fill, var(--fc-accent));
  --fc-accent-fill-contrast: var(--color-accent-fill-contrast, var(--fc-accent-contrast));
  --fc-border: var(--color-border, #cbd5e1);
  --fc-font: var(--font-body, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif);
  --fc-font-display: var(--font-display, inherit);
  /* the mono face is the COMPONENTS' (W24, 2026-09-24): part numbers, SKUs
     and prices in tables are what a monospace face aligns, and the design
     skill allows it nowhere else. tokens.css declares --font-mono inside
     [data-forge-component] only (art_director._tokens_css), so a producer
     rule that reaches for var(--font-mono) on a label or a button resolves
     to nothing and inherits the body face; here it resolves. */
  --fc-font-mono: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
  --fc-size-sm: var(--size-sm, 0.875rem);
  --fc-size: var(--size-base, 1rem);
  --fc-size-lg: var(--size-lg, 1.25rem);
  --fc-space-xs: var(--space-xs, 0.5rem);
  --fc-space-sm: var(--space-sm, 0.75rem);
  --fc-space-md: var(--space-md, 1.25rem);
  --fc-space-lg: var(--space-lg, 2rem);
  --fc-radius: var(--radius-md, 8px);
  --fc-radius-sm: var(--radius-sm, 4px);
  --fc-radius-pill: var(--radius-pill, 999px);
  --fc-border-w: var(--border-w, 1px);
  --fc-shadow: var(--shadow-card, 0 1px 2px rgba(0, 0, 0, 0.08));
  --fc-tap: 44px;                 /* the minimum tap target, everywhere */
  --fc-focus: var(--color-accent-2, var(--fc-accent));
  font-family: var(--fc-font);
  font-size: var(--fc-size);
  color: var(--fc-text);
  line-height: var(--leading-body, 1.5);
  box-sizing: border-box;
}
/* the derivations: only where the browser understands them; a browser that
   does not keeps the skin's own tokens (and the guard still measures) */
@supports (color: lch(from red calc((49.44 - l) * infinity) 0 0)) {
  [data-forge-component], .fc-composition {
    --fc-accent-contrast: lch(from var(--fc-accent) calc((49.44 - l) * infinity) 0 0);
    --fc-accent-2-contrast: lch(from var(--fc-accent-2) calc((49.44 - l) * infinity) 0 0);
    --fc-accent-fill-contrast: lch(from var(--fc-accent-fill) calc((49.44 - l) * infinity) 0 0);
  }
}
@supports (color: color-mix(in lch, red 55%, blue)) {
  [data-forge-component], .fc-composition {
    --fc-accent-text: color-mix(in lch, var(--fc-accent) 55%, var(--fc-text));
  }
}
[data-forge-component] *, [data-forge-component] *::before, [data-forge-component] *::after {
  box-sizing: inherit;
}
[data-forge-component] :focus-visible {
  outline: 3px solid var(--fc-focus);
  outline-offset: 2px;
}
[data-forge-component] img { max-width: 100%; height: auto; display: block; }

/* the visually-hidden idiom: read by assistive tech, drawn nowhere */
.fc-sr-only {
  position: absolute !important; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

/* buttons: one shape, two weights; never smaller than the tap target */
.fc-btn {
  min-height: var(--fc-tap); min-width: var(--fc-tap);
  padding: 0 var(--fc-space-md);
  display: inline-flex; align-items: center; justify-content: center; gap: var(--fc-space-xs);
  font: inherit; font-weight: 600; cursor: pointer;
  border: var(--fc-border-w) solid var(--fc-accent-fill);
  border-radius: var(--fc-radius);
  background: var(--fc-accent-fill); color: var(--fc-accent-fill-contrast);
  text-decoration: none;
}
.fc-btn--ghost { background: transparent; color: var(--fc-accent-text); }
.fc-btn:disabled, .fc-btn[aria-disabled="true"] { opacity: 0.55; cursor: not-allowed; }
.fc-btn--icon { padding: 0; width: var(--fc-tap); }

/* chips: a pressed chip is filled, an idle chip is outlined. A chip that is
   a LABEL (the fitment tag on a card) is 2rem tall; a chip that is a TARGET
   (a filter button, a category link) is the shared 44px minimum, and it is
   said here with a selector that OUTRANKS the label rule whatever order the
   two arrive in. WHY (W24, 2026-09-24): the mounts each ship base.css
   inside their own file -- forge-components.css, forge-nav.css,
   forge-garage.css -- and a page links them in mount order, so a later
   copy of `.fc-chip { min-height: 2rem }` (0,1,0) overrode an earlier
   `.fc-chip--button { min-height: 44px }` (0,1,0) on the live Heindl build:
   every filter chip measured 32px on a phone, and it was the critic's last
   fault in every round. `.fc-chip:is(a, button, [role="button"])` is
   (0,2,0): the cascade order between the copies no longer decides it. */
.fc-chip {
  display: inline-flex; align-items: center; gap: 0.35em;
  min-height: 2rem; padding: 0.25em 0.75em;
  border: var(--fc-border-w) solid var(--fc-border);
  border-radius: var(--fc-radius-pill);
  background: var(--fc-bg-alt); color: var(--fc-text);
  font-size: var(--fc-size-sm); line-height: 1.2;
}
.fc-chip:is(a, button, [role="button"]) {
  min-height: var(--fc-tap); min-width: var(--fc-tap);
  padding: 0 var(--fc-space-sm);
  justify-content: center; cursor: pointer;
}

/* form controls share the tap height and the border token */
.fc-field { display: flex; flex-direction: column; gap: 0.35rem; min-width: 0; }
.fc-field > label, .fc-label { font-weight: 600; font-size: var(--fc-size-sm); }
.fc-input, .fc-select {
  min-height: var(--fc-tap); padding: 0 var(--fc-space-sm);
  font: inherit; color: var(--fc-text); background: var(--fc-bg);
  border: var(--fc-border-w) solid var(--fc-border); border-radius: var(--fc-radius);
  width: 100%;
}
.fc-muted { color: var(--fc-muted); }
.fc-composition { display: grid; gap: var(--fc-space-lg); }

/* filter-chips: search first (it is the faster tool), chips wrap beneath */
.fc-filters { display: grid; gap: var(--fc-space-sm); }
.fc-filters__search { max-width: 32rem; }
.fc-filters__chips { display: flex; flex-wrap: wrap; gap: var(--fc-space-xs); }
/* the 44px floor comes from base.css (`.fc-chip:is(a, button, ...)`), where
   it outranks the label chip whatever order the mounts' CSS files load in;
   this rule only sets the type */
.fc-chip--button {
  font: inherit; font-size: var(--fc-size-sm); font-weight: 600; cursor: pointer;
}
.fc-chip--button[aria-pressed="true"] {
  background: var(--fc-accent-fill); color: var(--fc-accent-fill-contrast); border-color: var(--fc-accent-fill);
}
.fc-chip__count {
  display: inline-block; min-width: 1.5em; padding: 0 0.4em;
  border-radius: var(--fc-radius-pill);
  background: var(--fc-bg); color: var(--fc-text);
  font-size: 0.85em; text-align: center;
}
.fc-chip--button[aria-pressed="true"] .fc-chip__count { background: var(--fc-accent-fill-contrast); color: var(--color-accent-fill, var(--fc-accent-text)); }
.fc-chip--button[data-fc-empty="true"] { opacity: 0.6; }

/* product-grid: cards in an auto-fill grid; one column on a phone */
.fc-grid__head {
  display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between;
  gap: var(--fc-space-xs); margin-bottom: var(--fc-space-md);
}
.fc-grid__title { margin: 0; font-family: var(--fc-font-display); font-size: var(--fc-size-lg); }
.fc-grid__count { margin: 0; color: var(--fc-muted); font-size: var(--fc-size-sm); }
.fc-grid__list {
  list-style: none; margin: 0; padding: 0;
  display: grid; gap: var(--fc-space-md);
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
}
.fc-card {
  display: flex; flex-direction: column; min-width: 0;
  background: var(--fc-bg);
  border: var(--fc-border-w) solid var(--fc-border);
  border-radius: var(--fc-radius);
  box-shadow: var(--fc-shadow);
  overflow: hidden;
}
.fc-card[hidden] { display: none; }
.fc-card__media { aspect-ratio: 4 / 3; background: var(--fc-bg-alt); }
.fc-card__media img { width: 100%; height: 100%; object-fit: cover; }
.fc-card__placeholder {
  width: 100%; height: 100%; display: grid; place-items: center;
  color: var(--fc-muted); font-size: var(--fc-size-sm);
}
.fc-card__body { padding: var(--fc-space-sm) var(--fc-space-md); flex: 1; display: grid; gap: var(--fc-space-xs); align-content: start; }
.fc-card__name { margin: 0; font-size: var(--fc-size); font-weight: 600; line-height: 1.3; }
.fc-card__price { margin: 0; font-size: var(--fc-size-lg); font-weight: 700; }
.fc-card__meta { margin: 0; display: flex; flex-wrap: wrap; gap: var(--fc-space-xs); align-items: center; }
.fc-card__note { margin: 0; font-size: var(--fc-size-sm); }
.fc-card__actions { padding: 0 var(--fc-space-md) var(--fc-space-md); }
.fc-card__actions .fc-btn { width: 100%; }
.fc-btn--add[data-fc-in-basket="true"] { background: var(--fc-accent-2); border-color: var(--fc-accent-2); color: var(--fc-accent-2-contrast); }
.fc-status { font-size: var(--fc-size-sm); font-weight: 600; color: var(--fc-muted); }
.fc-status[data-status="in_stock"] { color: var(--fc-accent-text); }
/* a vehicle card (W27, 2026-09-24): the inventory mount hands the grid a row
   with `vehicle`, `year`, `mileage_label` and `was_price`; the template shows
   the year and the mileage where a part shows its fitment, and the WAS price
   struck through beside the NOW price. Nothing here names a colour. */
.fc-card__was { font-size: var(--fc-size-sm); font-weight: 400; margin-left: var(--fc-space-xs); }
.fc-status[data-status="new"] { color: var(--fc-accent-text); }
.fc-grid__empty {
  margin: var(--fc-space-md) 0 0; padding: var(--fc-space-md);
  border: var(--fc-border-w) dashed var(--fc-border); border-radius: var(--fc-radius);
  color: var(--fc-muted); text-align: center;
}
.fc-grid__empty[hidden] { display: none; }
/* the MENU card (W30, 2026-09-25): a dish has no fitment and no status
   to show, so the meta row carries what the page said OF the dish -- the
   dietary flags and the size prices -- and the one action is a LINK to the
   ordering host the facts pinned (never a button into a list: a diner
   orders where the restaurant takes orders). An anchor dressed as a button
   keeps the button's shape from base.css; only the underline is refused. */
.fc-chip--dietary { text-transform: capitalize; }
.fc-chip--size { font-variant-numeric: tabular-nums; }
.fc-card__suffix { font-size: var(--fc-size-sm); font-weight: 400; }
.fc-card__actions .fc-btn--order { text-decoration: none; }
/* the MENU, set by section (W34, 2026-09-25): a restaurant prints its
   sauces and sodas as a PRICE LIST, not as fifty cards with an empty frame
   each. template.menu.html sets every section under its own heading --
   dish cards for what has a photo or a real description (and a card with
   no photo has NO media frame at all), a name ... price list for the rest,
   in two columns where there is room and one on a phone, and one Order
   online link under the list instead of one per line. Only tokens: the
   list is a surface panel like a card, so the contrast guard reads it the
   same way; the leader is decoration and is hidden from assistive tech. */
.fc-grid--menu { display: grid; gap: var(--fc-space-lg); }
.fc-grid--menu .fc-grid__head { margin-bottom: 0; }
.fc-menu__section { display: grid; gap: var(--fc-space-md); min-width: 0; }
.fc-menu__section[hidden], .fc-menu__section [data-fc-menu-part][hidden] { display: none; }
.fc-menu__heading {
  margin: 0; padding-bottom: var(--fc-space-xs);
  font-family: var(--fc-font-display); font-size: var(--fc-size-lg); line-height: 1.2;
  border-bottom: calc(var(--fc-border-w) * 2) solid var(--fc-accent-fill);
}
.fc-pricelist {
  list-style: none; margin: 0;
  padding: var(--fc-space-sm) var(--fc-space-md);
  background: var(--fc-bg); color: var(--fc-text);
  border: var(--fc-border-w) solid var(--fc-border);
  border-radius: var(--fc-radius);
  columns: 2 18rem; column-gap: var(--fc-space-lg);
}
.fc-pricelist__row {
  break-inside: avoid; display: block;
  padding: var(--fc-space-xs) 0;
}
.fc-pricelist__row[hidden] { display: none; }
.fc-pricelist__line { display: flex; align-items: baseline; gap: 0.5em; }
.fc-pricelist__name { flex: 0 1 auto; min-width: 0; overflow-wrap: anywhere; font-weight: 600; }
.fc-pricelist__leader {
  flex: 1 1 1.5rem; min-width: 1.5rem;
  border-bottom: 2px dotted var(--fc-border); transform: translateY(-0.25em);
}
.fc-pricelist__price { flex: none; white-space: nowrap; font-weight: 700; font-variant-numeric: tabular-nums; }
.fc-pricelist__note { display: block; font-size: var(--fc-size-sm); }
/* THE PHOTO STAYS WITH ITS ROW (P1, owner's ruling 2026-09-26): "It helps
   anyone who doesn't read so well select their dog." A row that has a photo
   -- one set in a price list because its section is mostly lines -- still
   shows that photo, as a thumbnail to the left of its name and price, never
   left behind for a gallery. Rows without one are laid out as before. */
.fc-pricelist__row--photo {
  display: grid; grid-template-columns: 4.5rem minmax(0, 1fr);
  column-gap: var(--fc-space-sm); align-items: center;
}
.fc-pricelist__row--photo > :not(.fc-pricelist__photo) { grid-column: 2; }
.fc-pricelist__photo {
  grid-column: 1; grid-row: 1 / span 3; width: 4.5rem; height: auto;
  aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--fc-radius);
}
.fc-menu__order { margin: 0; }
.fc-menu__order .fc-btn--order { text-decoration: none; }
