/* ==========================================================================
   components.css — one section per partial in components/, headed with its
   file name. BEM class names match the component. Role tokens only.
   Ported from the design reference (design_site/css/components.css): only
   the parts the storefront uses so far; later chunks port theirs.
   HQ's own sections and changes are marked "HQ".
   ========================================================================== */

/* --------------------------------------------------------------------------
   components/button.html
   Colours are local custom properties so hover/disabled stay in one place.
   -------------------------------------------------------------------------- */

.button {
  --button-ink: var(--color-ink);
  --button-surface: transparent;
  --button-edge: var(--color-ink);
  --button-surface-hover: var(--color-surface-alt);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
  min-height: var(--control-height);
  min-width: var(--control-height);
  padding: var(--space-s) var(--space-l);
  border: var(--rule-width) solid var(--button-edge);
  border-radius: var(--radius);
  background: var(--button-surface);
  color: var(--button-ink);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-line-height);
  letter-spacing: var(--type-label-tracking);
  text-align: center;
  text-decoration: none;
  text-transform: uppercase;
  transition: background-color var(--motion-fast) var(--motion-ease),
    border-color var(--motion-fast) var(--motion-ease);
}

.button--primary {
  --button-ink: var(--color-on-ink);
  --button-surface: var(--color-ink);
  --button-edge: var(--color-ink);
  --button-surface-hover: var(--color-ink-muted);
}

.button--secondary {
  --button-ink: var(--color-ink);
  --button-surface: transparent;
  --button-edge: var(--color-ink);
  --button-surface-hover: var(--color-surface-alt);
}

.button:hover {
  background: var(--button-surface-hover);
  border-color: var(--button-surface-hover);
}

.button--secondary:hover {
  border-color: var(--button-edge);
}

/* On a shaded campaign photo (home): an outline in the light text colour.
   Not a filled button, so the screen's one filled button stays the only one. */
/* HQ: an outline button on the dark band (the footer's "Open in Maps"). */
.button--on-ink {
  --button-ink: var(--color-on-ink);
  --button-surface: transparent;
  --button-edge: var(--color-on-ink);
  --button-surface-hover: var(--color-line-on-ink);
  --focus-ring: var(--focus-ring-on-ink);
}

.button--on-media {
  --button-ink: var(--color-on-media);
  --button-surface: transparent;
  --button-edge: var(--color-on-media);
  --button-surface-hover: var(--color-media-shade-hover);
  --focus-ring: var(--focus-ring-on-ink);
}

.button--on-media:hover {
  border-color: var(--button-edge);
}


.button:disabled,
.button[aria-disabled="true"] {
  --button-ink: var(--color-disabled-ink);
  --button-surface: var(--color-disabled-surface);
  --button-edge: var(--color-disabled-surface);
  --button-surface-hover: var(--color-disabled-surface);
  cursor: not-allowed;
}

.button--secondary:disabled,
.button--secondary[aria-disabled="true"] {
  --button-surface: transparent;
  --button-edge: var(--color-line);           /* disabled: exempt from 3:1 */
  --button-surface-hover: transparent;
}

/* Main actions fill the width on mobile; natural width from 768px. */
.button--block {
  width: 100%;
}

@media (min-width: 48em) {
  .button--block {
    width: auto;
  }
}

.button__label {
  min-width: 0;
}

.button {
  gap: var(--space-xs);
}

/* Text link: tertiary actions. */
.button--text {
  --button-edge: transparent;
  --button-surface-hover: transparent;
  min-height: var(--tap-min);
  min-width: 0;
  padding-inline: 0;
  text-decoration-line: underline;
  text-decoration-thickness: var(--rule-width);
  text-underline-offset: var(--link-underline-offset);
}

.button--text:hover {
  text-decoration-thickness: var(--focus-width);
}

/* Icon only: 44px target, 20px glyph. The button carries the accessible name. */
.button--icon {
  --button-edge: transparent;
  --button-surface-hover: var(--color-surface-alt);
  width: var(--tap-min);
  height: var(--tap-min);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  padding: 0;
}

/* Busy (the loading component): HTMX adds .htmx-request while a request runs. */
.button__busy {
  display: none;
}

.htmx-request .button__idle {
  display: none;
}

.htmx-request .button__busy {
  display: inline;
}

.button[aria-busy="true"] {
  cursor: progress;
}

/* --------------------------------------------------------------------------
   components/icon.html
   -------------------------------------------------------------------------- */

.icon {
  display: block;
  flex: none;
  width: var(--icon-size);
  height: var(--icon-size);
}

/* --------------------------------------------------------------------------
   components/badge.html
   Labels beside content, never on photos.
   -------------------------------------------------------------------------- */

.badge {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-line-height);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
  white-space: nowrap;
}

/* "Nouveau": accent text, no box. */
.badge--new {
  color: var(--color-accent);
}

.badge--house {
  padding: var(--space-2xs) var(--space-xs);
  border: var(--rule-width) solid var(--color-ink);
  color: var(--color-ink);
}

/* Chunk 26: the product page's mark leads to the house brand's page. Same
   look; the global focus ring shows on it. */
.badge--link {
  text-decoration: none;
}

/* --------------------------------------------------------------------------
   components/price.html
   -------------------------------------------------------------------------- */

.price {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  font-weight: var(--type-price-weight);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.price--large {
  font-size: var(--type-price-large-size);
}

/* --------------------------------------------------------------------------
   components/site_header.html
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: var(--layer-sticky);
  border-bottom: var(--rule-width) solid var(--color-line);
  background: var(--color-canvas);
  transition-property: background-color, border-color, color;
  transition-duration: var(--motion-base);
  transition-timing-function: var(--motion-ease);
}

/* Home, over the opening's photos (18 October 2026): the header lies over
   the photo (no room kept for it), and while the page is at its very top
   (is-at-top, set by site.js) it is transparent with light text. Scrolled,
   or with the menu open, it is the normal header. */
.site-header--over-media {
  margin-bottom: calc((var(--header-height) + var(--rule-width)) * -1);
}

.site-header--over-media.is-at-top:not(:has(.mobile-menu[open])) {
  --focus-ring: var(--focus-ring-on-ink);
  border-bottom-color: transparent;
  background: transparent;
  color: var(--color-on-media);
}

.site-header--over-media.is-at-top:not(:has(.mobile-menu[open])) .language-switcher__item + .language-switcher__item::before,
.site-header--over-media.is-at-top:not(:has(.mobile-menu[open])) .language-switcher__link {
  color: var(--color-on-ink-muted);
}

.site-header--over-media.is-at-top:not(:has(.mobile-menu[open])) .language-switcher__link:hover,
.site-header--over-media.is-at-top:not(:has(.mobile-menu[open])) .language-switcher__link[aria-current="true"] {
  color: var(--color-on-media);
}

/* A message (after a form without JavaScript) stays clear of the header. */
.site-header--over-media + main .messages {
  padding-top: calc(var(--header-height) + var(--space-l));
}

/* Mobile: menu, wordmark, then WhatsApp and the bag on the right. The two
   side columns share the leftover width equally, so the logo sits in the
   middle of the screen (Pinhas, 29 October 2026). */
.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: var(--space-xs);
  min-height: var(--header-height);
}

.site-header__menu {
  margin-inline-start: calc(var(--space-s) * -1);
}

.site-header__wordmark {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  justify-self: center;
}

.logo {
  display: block;
  max-width: 100%;
}

.logo--header {
  width: auto;
  height: var(--logo-header-height);
}

.logo--full {
  width: var(--logo-display-width);
  height: auto;
}

.site-header__nav,
.site-header__switcher {
  display: none;
}

.site-header__tools {
  display: flex;
  align-items: center;
  justify-self: end;
}

.site-header__action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-xs);
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-decoration: none;
  text-transform: uppercase;
  white-space: nowrap;
}

.site-header__action:hover .site-header__label {
  text-decoration-line: underline;
}

.site-header__bag {
  gap: var(--space-2xs);
}

/* Labels are read by screen readers on mobile, shown from 1200px. */
.site-header__label {
  position: absolute;
  width: var(--rule-width);
  height: var(--rule-width);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.site-header__nav-list {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  column-gap: var(--space-m);
}

.site-header__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-decoration: none;
  text-transform: uppercase;
}

.site-header__link:hover,
.site-header__link[aria-current="page"] {
  text-decoration-line: underline;
}

@media (min-width: 75em) {
  .site-header__inner {
    grid-template-columns: auto minmax(0, 1fr) auto;
    gap: var(--space-l);
  }

  .site-header__wordmark {
    justify-self: start;
  }

  .logo--header {
    height: var(--logo-header-height-wide);
  }

  .site-header__menu,
  .site-header__bag-icon {
    display: none;
  }

  .site-header__nav,
  .site-header__switcher {
    display: block;
  }

  .site-header__tools {
    gap: var(--space-l);
  }

  .site-header__label {
    position: static;
    width: auto;
    height: auto;
    overflow: visible;
    clip-path: none;
  }
}

/* --------------------------------------------------------------------------
   components/language_switcher.html
   The list shifts left by the tap padding so FR lines up with the text edge.
   -------------------------------------------------------------------------- */

.language-switcher {
  display: flex;
  align-items: center;
  font-size: var(--type-label-size);
  /* Half the space a centred two-letter code leaves in its 44px target. */
  margin-inline-start: calc((var(--tap-min) - 2 * (var(--type-mono-advance) + var(--type-label-tracking))) / -2);
}

.language-switcher__item {
  display: flex;
  align-items: center;
}

.language-switcher__item + .language-switcher__item::before {
  content: "·" / "";
  color: var(--color-ink-muted);
}

.language-switcher__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--tap-min);
  min-height: var(--tap-min);
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-decoration: none;
  text-transform: uppercase;
}

.language-switcher__link:hover {
  color: var(--color-ink);
}

.language-switcher__link[aria-current="true"] {
  color: var(--color-ink);
  text-decoration-line: underline;
}

.language-switcher--on-ink .language-switcher__item + .language-switcher__item::before,
.language-switcher--on-ink .language-switcher__link {
  color: var(--color-on-ink-muted);
}

.language-switcher--on-ink .language-switcher__link:hover,
.language-switcher--on-ink .language-switcher__link[aria-current="true"] {
  color: var(--color-on-ink);
}

/* --------------------------------------------------------------------------
   components/site_footer.html
   The dark band. Focus ring flips to canvas so it stays visible on ink.
   -------------------------------------------------------------------------- */

.site-footer {
  --focus-ring: var(--focus-ring-on-ink);
  margin-top: var(--space-section);
  padding-block: var(--space-section) var(--space-xl);
  background: var(--color-ink);
  color: var(--color-on-ink);
}

/* Mobile: help and social side by side; shop and language full width. */
.site-footer__grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-xl) var(--space-m);
}

.site-footer__group--wide,
.site-footer__pair {
  grid-column: 1 / -1;
}

/* Company and Policies: always side by side (Pinhas, 2 November 2026). */
.site-footer__pair {
  display: grid;
  grid-template-columns: subgrid;
  row-gap: var(--space-xl);
}

.site-footer__title {
  margin-bottom: var(--space-s);
  color: var(--color-on-ink-muted);
}

.site-footer__address {
  font-style: normal;
}

.site-footer__hours {
  margin-top: var(--space-s);
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
}

.site-footer__map {
  margin-top: var(--space-m);
}

/* No underline at rest, only under the mouse (Pinhas, 2 November 2026). */
.site-footer__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  text-decoration-line: none;
}

.site-footer__link:hover {
  text-decoration-line: underline;
}

/* The name set in type, not the logo (Pinhas, 22 October 2026). */
.site-footer__wordmark {
  margin-top: var(--space-3xl);
  font-family: var(--type-wordmark-family);
  font-size: var(--type-wordmark-display-size);
  font-weight: var(--type-wordmark-weight);
  line-height: var(--type-wordmark-line-height);
  letter-spacing: var(--type-wordmark-tracking);
  text-transform: uppercase;
}

.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  column-gap: var(--space-l);
  margin-top: var(--space-l);
  padding-top: var(--space-s);
  border-top: var(--rule-width) solid var(--color-line-on-ink);
  color: var(--color-on-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

/* Wide screens: every column in one row, Company and Policies right
   after Language (Pinhas, 2 November 2026). */
@media (min-width: 75em) {
  .site-footer__grid {
    grid-template-columns: none;
    grid-auto-columns: minmax(0, 1fr);
    grid-auto-flow: column;
  }

  .site-footer__group--wide {
    grid-column: auto;
  }

  .site-footer__pair {
    grid-column: span 2;
  }
}

/* --------------------------------------------------------------------------
   components/product_card.html (Chunk 19; the compact variant comes with
   its pages). Nothing sits on the photo. The name's link covers the whole
   card; the save button sits beside the name, above that link.
   -------------------------------------------------------------------------- */

.product-card {
  position: relative;
  display: grid;
  align-content: start;
  gap: var(--space-s);
}

.product-card:has(.product-card__link:focus-visible) {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.product-card__body {
  display: grid;
  align-content: start;
  gap: var(--space-2xs);
}

.product-card__head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: start;
  gap: var(--space-xs);
}

.product-card__name {
  font-family: var(--type-name-family);
  font-size: var(--type-name-size);
  font-weight: var(--type-name-weight);
  line-height: var(--type-name-line-height);
  letter-spacing: 0;
}

.product-card__link {
  text-decoration: none;
}

.product-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
}

.product-card__link:focus-visible {
  outline: none;
}

.product-card__link:hover {
  text-decoration-line: underline;
  text-decoration-thickness: var(--rule-width);
  text-underline-offset: var(--link-underline-offset);
}

.product-card__hint {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  line-height: var(--type-label-line-height);
}

/* Above the stretched link so it stays its own control. */
.product-card__save {
  position: relative;
  z-index: var(--layer-raised);
  margin-block-start: calc(var(--space-s) * -1);
  margin-inline-end: calc(var(--space-s) * -1);
}

.product-card__save .icon--saved,
.product-card__save[aria-pressed="true"] .icon--save {
  display: none;
}

.product-card__save[aria-pressed="true"] .icon--saved {
  display: block;
}

/* --------------------------------------------------------------------------
   components/product_grid.html
   -------------------------------------------------------------------------- */

.product-grid {
  display: grid;
  grid-template-columns: repeat(var(--grid-columns), minmax(0, 1fr));
  column-gap: var(--grid-gap-column);
  row-gap: var(--grid-gap-row);
}

/* One row of four (home): two by two on phones, four in a row from 768px. */
@media (min-width: 48em) {
  .product-grid--row {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}


/* --------------------------------------------------------------------------
   components/load_more.html
   -------------------------------------------------------------------------- */

.load-more {
  display: grid;
  justify-items: center;
  gap: var(--space-s);
  margin-top: var(--space-2xl);
}

.load-more__count {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

/* --------------------------------------------------------------------------
   components/announcement_bar.html
   One line above the header, not sticky.
   -------------------------------------------------------------------------- */

.announcement-bar {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--announcement-height);
  padding-inline: var(--layout-gutter);
  background: var(--color-ink);
  color: var(--color-on-ink);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-line-height);
  letter-spacing: var(--type-label-tracking);
  text-align: center;
  text-transform: uppercase;
  --focus-ring: var(--focus-ring-on-ink);
}

.announcement-bar__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--announcement-height);
  color: inherit;
  text-decoration: none;
}

.announcement-bar__link:hover {
  text-decoration-line: underline;
  text-decoration-thickness: var(--rule-width);
  text-underline-offset: var(--link-underline-offset);
}

/* --------------------------------------------------------------------------
   components/campaign_split.html, campaign_halves.html (design reference,
   18 October 2026): campaign photos with their title ON the photo, over a
   flat shade. Without photos (visitors, until they exist) the opening is
   campaign--plain: its title and button on the page background.
   -------------------------------------------------------------------------- */

.ph--campaign {
  --ph-ratio: var(--ratio-campaign);
}

.campaign {
  position: relative;
  isolation: isolate;
  color: var(--color-on-media);
}

.campaign__media {
  display: grid;
}

/* The shade covers the whole photo so the text reads on any picture. */
.campaign__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--color-media-shade);
  pointer-events: none;
}

/* Full screen: the photos fill what the header and the bar leave. */
.campaign--screen .campaign__media {
  height: var(--campaign-screen-height);
}

.campaign--screen .ph {
  height: 100%;
  aspect-ratio: auto;
}

/* The house brand's band photo A and the opening's photo 2: a standing person's portrait
   photo is cut top and bottom on a wide screen; keep the top, so the head
   stays in. The others stay centred (Pinhas, 2 November 2026). */
.campaign--screen:not(.campaign--opening) .ph:not(.campaign__second) .ph__image,
.campaign--opening .campaign__second .ph__image {
  object-position: top center;
}

/* The opening starts under the header, which lies over it: it fills the
   screen below the announcement bar. */
.campaign--opening .campaign__media {
  height: calc(100svh - var(--announcement-height));
}

.campaign--opening .campaign__text {
  padding-top: calc(var(--header-height) + var(--space-l));
}

.campaign.campaign--opening .ph__label {
  top: calc(var(--header-height) + var(--space-s));
}

/* Development only (STOREFRONT_PLACEHOLDERS): the grey box's label sits at
   the top, away from the text. */
.campaign .ph__label {
  top: var(--space-s);
  bottom: auto;
}

/* .ph sets its own display further down: the second photo needs the
   stronger selector to stay hidden on phones. */
.campaign .campaign__second {
  display: none;
}

.campaign__text {
  position: absolute;
  inset: 0;
  z-index: var(--layer-raised);
  display: grid;
  gap: var(--space-m);
  padding: var(--space-l) var(--layout-gutter);
}

/* The title and button in the middle (full-screen blocks). */
.campaign__text--centre {
  place-content: center;
  justify-items: center;
  text-align: center;
}

/* The title and button in the bottom-left corner (halves). */
.campaign__text--corner {
  align-content: end;
  justify-items: start;
}

.campaign__title {
  max-width: 20ch;
  color: inherit;
}

.campaign--plain {
  color: var(--color-ink);
}

.campaign--plain .campaign__text {
  position: static;
  padding-block: var(--space-section);
}

@media (min-width: 48em) {
  .campaign--screen .campaign__media {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .campaign .campaign__second {
    display: block;
  }

  .campaign__text--corner {
    padding: var(--space-xl);
  }
}

/* Two halves: stacked with a thin gap on phones, side by side with none. */
.campaign-halves {
  display: grid;
  gap: var(--space-xs);
}

@media (min-width: 48em) {
  .campaign-halves {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0;
  }
}

/* --------------------------------------------------------------------------
   components/campaign_stories.html
   Photos edge to edge, the text under each one (not on it).
   -------------------------------------------------------------------------- */

.campaign-stories {
  display: grid;
  gap: var(--space-xl);
}

.campaign-stories__item {
  display: grid;
  gap: var(--space-m);
}

.campaign-stories__body {
  display: grid;
  justify-items: start;
  gap: var(--space-xs);
  max-width: var(--measure-reading);
  padding-inline: var(--layout-gutter);
}

.campaign-stories__title {
  font-size: var(--type-heading-s-size);
  line-height: var(--type-heading-s-line-height);
  letter-spacing: var(--type-heading-s-tracking);
}

@media (min-width: 48em) {
  .campaign-stories {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 0;
  }
}

/* --------------------------------------------------------------------------
   components/ordering_steps.html
   -------------------------------------------------------------------------- */

.ordering-steps {
  border-top: var(--rule-width) solid var(--color-line);
}

.ordering-steps__step {
  display: grid;
  grid-template-columns: var(--space-2xl) minmax(0, 1fr);
  gap: var(--space-s);
  padding-block: var(--space-m);
  border-bottom: var(--rule-width) solid var(--color-line);
}

.ordering-steps__number {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-body-line-height);
}

@media (min-width: 75em) {
  .ordering-steps {
    display: grid;
    grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: var(--space-l);
    border-top: 0;
  }

  .ordering-steps__step {
    grid-template-columns: minmax(0, 1fr);
    align-content: start;
    border-top: var(--rule-width) solid var(--color-ink);
    border-bottom: 0;
  }
}

/* --------------------------------------------------------------------------
   components/gallery.html
   A scroll-snap row, CSS only: full-bleed on phones, one big photo in the
   left column from 768px (HQ, since the colour thumbnails; the reference
   stacks them). site.js adds one counter and previous/next buttons in a
   row under the strip (nothing on the photo itself).
   -------------------------------------------------------------------------- */

.gallery {
  min-width: 0;
}

.gallery__track {
  display: flex;
  margin-inline: calc(var(--layout-gutter) * -1);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scrollbar-width: none;
}

.gallery__slide {
  position: relative;
  flex: 0 0 100%;
  scroll-snap-align: start;
}

/* HQ: the track is focusable (keyboard scrolling). */
.gallery__track:focus-visible {
  outline: var(--focus-ring);
  outline-offset: calc(var(--focus-offset) * -1);
}

/* HQ: added by site.js on phones and tablets: previous, "3 / 8", next. */
.gallery__controls {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-xs);
  margin-top: var(--space-xs);
}

.gallery__previous .icon {
  transform: scaleX(-1);
}

.gallery__counter {
  min-width: 7ch;
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-variant-numeric: tabular-nums;
  text-align: center;
}

@media (min-width: 48em) {
  .gallery__track {
    margin-inline: 0;
  }
}

/* --------------------------------------------------------------------------
   components/photo_thumbs.html (HQ): the product's photos as small
   thumbnails, like the reference's "Complete your look" row.
   -------------------------------------------------------------------------- */

/* Phones: the big photo strip already swipes (with ← → and "3 / 18"), and a
   hidden row's lazy photos aren't downloaded, which keeps the phone's first
   view under 350 KB. The row shows from 768px, as in the reference. */
.photo-thumbs {
  display: none;
  gap: var(--space-s);
  min-width: 0;
}

@media (min-width: 48em) {
  .photo-thumbs {
    display: grid;
  }
}

.photo-thumbs__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: var(--tap-min);
}

.photo-thumbs__arrows {
  display: flex;
}

.photo-thumbs__previous .icon {
  transform: scaleX(-1);
}

.photo-thumbs__row {
  display: flex;
  gap: var(--space-xs);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: none;
  padding: var(--space-2xs);
}

.photo-thumbs__row > li {
  flex: 0 0 var(--thumb-width);
  scroll-snap-align: start;
}

.photo-thumbs__link {
  display: block;
  border: var(--rule-width) solid transparent;
}

.photo-thumbs__link[aria-current="true"] {
  border-color: var(--color-ink);
}

.photo-thumbs__link:focus-visible {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* --------------------------------------------------------------------------
   components/size_selector.html
   States show by mark first, colour second. HQ (Chunk 21): EU sizes only;
   the EU/UK/US switch comes with the size guide.
   -------------------------------------------------------------------------- */

.size-selector {
  display: grid;
  gap: var(--space-s);
  min-width: 0;
}

.size-selector__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(var(--control-height), 1fr));
  gap: var(--space-xs);
}

.size-selector__size {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: var(--control-height);
  border: var(--rule-width) solid var(--color-control-edge-active);
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  cursor: pointer;
  transition: background-color var(--motion-fast) var(--motion-ease);
}

.size-selector__size:hover {
  background: var(--color-surface-alt);
}

.size-selector__size--few::after {
  content: "";
  position: absolute;
  top: var(--space-2xs);
  right: var(--space-2xs);
  width: var(--marker-dot);
  height: var(--marker-dot);
  background: currentColor;
}

.size-selector__size--sold {
  border-color: var(--color-line);
  color: var(--color-ink-muted);
  text-decoration-line: line-through;
  cursor: not-allowed;
}

.size-selector__size--sold:hover {
  background: none;
}

.size-selector__size--ask {
  border-style: dashed;
}

.size-selector__size--ask .size-selector__value::after {
  content: "?";
}

.size-selector__size:has(input:checked) {
  border-color: var(--color-ink);
  background: var(--color-ink);
  color: var(--color-on-ink);
}

.size-selector__size:has(input:focus-visible) {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* One size: no grid, the product's own state by the same marks. */
.size-selector__one {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-xs) var(--space-s);
}

.size-selector__one .size-selector__size {
  padding-inline: var(--space-m);
  cursor: default;
}

.size-selector__one .size-selector__size:hover {
  background: none;
}

.size-selector--one-size .size-selector__size--ask .size-selector__value::after {
  content: none;
}

.size-selector__state {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

.size-selector--one-size {
  display: grid;
  gap: var(--space-s);
}

.size-selector__key {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-xs) var(--space-m);
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

.size-selector__key-item {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.size-selector__key .size-selector__size {
  width: var(--space-xl);
  min-height: var(--space-xl);
  font-size: var(--type-label-size);
  cursor: default;
}

.size-selector__key .size-selector__size:hover {
  background: none;
}

.size-selector__key .size-selector__size--few::after {
  top: var(--space-2xs);
  right: var(--space-2xs);
}

/* HQ: the visible legend (the reference hides it and repeats a label). */
.size-selector__legend {
  margin-bottom: var(--space-s);
}

.size-selector__optional {
  color: var(--color-ink-muted);
  text-transform: none;
  letter-spacing: 0;
}

/* HQ: "Guide des tailles" sits at the start, under the legend. */
.size-selector__guide {
  justify-self: start;
}

/* HQ: a sold-out radio is disabled; its box shows no hover. */
.size-selector__size:has(input:disabled) {
  cursor: not-allowed;
}

/* --------------------------------------------------------------------------
   components/product_actions.html (Chunk 21: no sticky bar yet)
   -------------------------------------------------------------------------- */

.product-actions {
  display: grid;
  gap: var(--space-s);
}

.product-actions__row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: end;
  gap: var(--space-s);
}

.product-actions__status {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
}

.product-actions__status a {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
}

.product-actions__status:empty {
  display: none;
}

/* --------------------------------------------------------------------------
   components/selection_item.html (Chunk 22)
   -------------------------------------------------------------------------- */

.selection-list {
  border-top: var(--rule-width) solid var(--color-line);
}

.selection-item {
  display: grid;
  grid-template-columns: var(--thumb-width) minmax(0, 1fr);
  gap: var(--space-s);
  padding-block: var(--space-m);
  border-bottom: var(--rule-width) solid var(--color-line);
}

.selection-item__body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  justify-items: start;
  gap: var(--space-xs);
  min-width: 0;
}

.selection-item__name {
  font-family: var(--type-name-family);
  font-size: var(--type-name-size);
  font-weight: var(--type-name-weight);
  line-height: var(--type-name-line-height);
  letter-spacing: 0;
}

.selection-item__name a {
  /* The tap area grows to 44px without moving the layout. */
  display: inline-block;
  padding-block: var(--space-s);
  margin-block: calc(var(--space-s) * -1);
  text-decoration: none;
}

.selection-item__name a:hover {
  text-decoration-line: underline;
}

.selection-item__controls {
  display: flex;
  justify-self: stretch;
  min-width: 0;
  flex-wrap: wrap;
  align-items: end;
  gap: var(--space-s);
}

.selection-item__size {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  flex: 0 1 auto;
  gap: var(--space-2xs);
  min-width: 0;
  max-width: 100%;
}

/* A native select grows to its longest option; keep it inside the item. */
.selection-item__size select {
  max-width: 100%;
}

/* No size yet: the dashed edge of the "ask" state. */
.selection-item__size:has(option[value=""]:checked) select {
  border-style: dashed;
}

/* --------------------------------------------------------------------------
   components/selection_summary.html (Chunk 22)
   -------------------------------------------------------------------------- */

.selection-summary {
  display: grid;
  align-content: start;
  gap: var(--space-s);
  padding: var(--space-l) var(--space-m);
  background: var(--color-surface-alt);
}

.selection-summary__rows {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: baseline;
  gap: var(--space-xs) var(--space-m);
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
}

.selection-summary__rows dd {
  text-align: right;
}

.selection-summary__note {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

/* HQ: the thumbnail frame, and the controls row's update button (shown
   only without JavaScript). */
.selection-item__thumb {
  min-width: 0;
}

.selection-item__controls > .button {
  min-height: var(--control-height);
}

/* --------------------------------------------------------------------------
   components/size_chart.html (Chunk 23, written out in size_guide.html)
   -------------------------------------------------------------------------- */

.size-chart {
  max-width: 100%;
  overflow-x: auto;
}

.size-chart__table {
  width: 100%;
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  font-variant-numeric: tabular-nums;
}

.size-chart__caption {
  padding-bottom: var(--space-s);
  text-align: left;
}

.size-chart__table th,
.size-chart__table td {
  padding: var(--space-xs) var(--space-s) var(--space-xs) 0;
  border-bottom: var(--rule-width) solid var(--color-line);
  text-align: left;
  white-space: nowrap;
}

.size-chart__table thead th {
  /* Headers wrap so the table fits a phone; figures never wrap. */
  white-space: normal;
  color: var(--color-ink-muted);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
  vertical-align: bottom;
}

.size-chart__table tbody th {
  font-weight: var(--type-label-weight);
}

/* --------------------------------------------------------------------------
   components/delivery_regions.html (Chunk 23: the owner's text per region)
   -------------------------------------------------------------------------- */

.delivery-regions {
  display: grid;
  gap: var(--space-l);
}

.delivery-regions__item {
  display: grid;
  align-content: start;
  gap: var(--space-xs);
  padding-top: var(--space-m);
  border-top: var(--rule-width) solid var(--color-ink);
}

.delivery-regions__name {
  font-size: var(--type-heading-s-size);
  line-height: var(--type-heading-s-line-height);
  letter-spacing: var(--type-heading-s-tracking);
}

@media (min-width: 75em) {
  .delivery-regions {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --------------------------------------------------------------------------
   components/brand_band (Chunk 26, written out in house_brand.html): the
   house brand's dark band.
   -------------------------------------------------------------------------- */

.brand-band {
  --focus-ring: var(--focus-ring-on-ink);
  padding-block: var(--space-section);
  background: var(--color-ink);
  color: var(--color-on-ink);
}

.brand-band__inner {
  display: grid;
  gap: var(--space-m);
}

.brand-band__label {
  color: var(--color-on-ink-muted);
}

.brand-band__title {
  font-size: var(--type-display-size);
  line-height: var(--type-display-line-height);
  letter-spacing: var(--type-display-tracking);
}

.brand-band__text {
  max-width: var(--measure-reading);
}

/* --------------------------------------------------------------------------
   components/error_page.html (Chunk 24)
   -------------------------------------------------------------------------- */

.error-page {
  display: grid;
  justify-items: start;
  gap: var(--space-m);
  max-width: var(--measure-reading);
  padding-block: var(--space-section) 0;
}

.error-page__code {
  color: var(--color-ink-muted);
}

.error-page__title {
  font-size: var(--type-display-size);
  line-height: var(--type-display-line-height);
  letter-spacing: var(--type-display-tracking);
}

.error-page__more {
  margin-top: var(--space-l);
  color: var(--color-ink-muted);
}

.error-page__links {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--space-l);
}

.error-page__link {
  display: inline-flex;
  align-items: center;
  min-height: var(--tap-min);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
}

/* HQ: the actions row, and the name on the standalone 500 page. */
.error-page__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s);
}

.error-page__name {
  padding-top: var(--space-l);
  font-family: var(--type-wordmark-family);
  font-weight: var(--type-wordmark-weight);
  letter-spacing: var(--type-wordmark-tracking);
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   components/empty_state.html
   -------------------------------------------------------------------------- */

.empty-state {
  display: grid;
  justify-items: start;
  gap: var(--space-m);
  max-width: var(--measure-reading);
  padding-block: var(--space-2xl);
}

.empty-state__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-s);
}

.empty-state__title {
  font-size: var(--type-heading-s-size);
  line-height: var(--type-heading-s-line-height);
  letter-spacing: var(--type-heading-s-tracking);
}

/* --------------------------------------------------------------------------
   components/notice.html
   -------------------------------------------------------------------------- */

.notice {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: var(--space-xs) var(--space-s);
  padding: var(--space-xs) 0 var(--space-xs) var(--space-s);
  border-left: var(--notice-rule-width) solid var(--color-ink);
}

.notice__text {
  font-size: var(--type-mono-size);
  line-height: var(--type-mono-line-height);
}

.notice--error {
  border-left-color: var(--color-error);
}

.notice--error .notice__icon {
  color: var(--color-error);
}

.notice__list {
  margin-top: var(--space-2xs);
  padding-left: var(--space-m);
  list-style: disc;
}

.notice__list a,
.notice__action {
  display: flex;
  align-items: center;
  width: max-content;
  max-width: 100%;
  min-height: var(--tap-min);
}

/* --------------------------------------------------------------------------
   components/quantity_stepper.html
   -------------------------------------------------------------------------- */

.quantity-stepper {
  display: grid;
  gap: var(--space-2xs);
}

.quantity-stepper__controls {
  display: flex;
  width: max-content;
  border: var(--rule-width) solid var(--color-control-edge);
}

.quantity-stepper__button {
  display: flex;
  align-items: center;
  justify-content: center;
  width: var(--control-height);
  height: var(--control-height);
}

.quantity-stepper__button:hover {
  background: var(--color-surface-alt);
}

.quantity-stepper__button:disabled {
  color: var(--color-disabled-ink);
  cursor: not-allowed;
}

.quantity-stepper__input {
  width: var(--control-height);
  min-height: var(--control-height);
  padding: 0;
  border: 0;
  border-inline: var(--rule-width) solid var(--color-control-edge);
  text-align: center;
  appearance: textfield;
}

.quantity-stepper__input::-webkit-inner-spin-button,
.quantity-stepper__input::-webkit-outer-spin-button {
  appearance: none;
}

/* --------------------------------------------------------------------------
   components/request_code.html
   -------------------------------------------------------------------------- */

.request-code {
  display: grid;
  gap: var(--space-xs);
  padding-block: var(--space-l);
  border-block: var(--rule-width) solid var(--color-line);
}

.request-code__value {
  font-family: var(--font-mono);
  font-size: var(--type-price-display-size);
  font-weight: var(--type-price-weight);
  line-height: var(--type-display-line-height);
  letter-spacing: var(--type-label-tracking);
}

.request-code__text {
  max-width: var(--measure-reading);
}

/* --------------------------------------------------------------------------
   components/form_field.html
   -------------------------------------------------------------------------- */

.form-field {
  display: grid;
  gap: var(--space-2xs);
  min-width: 0;
  border: 0;
}

.form-field__label {
  padding: 0;
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-line-height);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
}

.form-field__optional {
  color: var(--color-ink-muted);
  font-weight: var(--type-mono-weight);
  text-transform: none;
  letter-spacing: 0;
}

.form-field__input {
  width: 100%;
}

textarea.form-field__input {
  min-height: calc(var(--control-height) * 3);
  resize: vertical;
}

.form-field__help {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

.form-field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-xs);
  color: var(--color-error);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

.form-field--invalid .form-field__input {
  border-color: var(--color-error);
}

/* Radio cards: two large boxes, selected = filled ink. */
.form-field__cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--card-min-width)), 1fr));
  gap: var(--space-xs);
  margin-top: var(--space-2xs);
}

.form-field__card {
  display: grid;
  align-content: start;
  gap: var(--space-2xs);
  min-height: var(--control-height);
  padding: var(--space-s) var(--space-m);
  border: var(--rule-width) solid var(--color-control-edge);
  cursor: pointer;
}

.form-field__card-title {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
  font-weight: var(--type-label-weight);
}

.form-field__card-text {
  color: var(--color-ink-muted);
  font-size: var(--type-mono-size);
}

.form-field__card:has(input:checked) {
  border-color: var(--color-ink);
  background: var(--color-ink);
  color: var(--color-on-ink);
}

.form-field__card:has(input:checked) .form-field__card-text {
  color: var(--color-on-ink-muted);
}

.form-field__card:has(input:focus-visible) {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

.form-field__check {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: start;
  gap: var(--space-s);
  min-height: var(--tap-min);
  padding-block: var(--space-xs);
  font-size: var(--type-mono-size);
  cursor: pointer;
}

.form-field__check input {
  width: var(--space-l);
  height: var(--space-l);
  accent-color: var(--color-ink);
}

/* An input with a unit after it (back office price). */
.form-field__affix {
  display: flex;
  align-items: center;
  gap: var(--space-xs);
}

.form-field__suffix {
  font-family: var(--font-mono);
  font-size: var(--type-mono-size);
}

/* --------------------------------------------------------------------------
   components/turnstile_slot.html
   -------------------------------------------------------------------------- */

.turnstile-slot {
  display: flex;
  align-items: center;
  justify-content: center;
  width: min(100%, var(--turnstile-width));
  height: var(--turnstile-height);
  border: var(--rule-width) dashed var(--color-control-edge);
}

.turnstile-slot__label {
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
}

/* --------------------------------------------------------------------------
   components/mobile_menu.html (HQ)
   A <details> instead of the reference's <dialog>: it opens and closes with
   no JavaScript. The summary is the header's menu button and stays visible
   above the panel, so tapping it again closes the menu. site.js only adds
   Escape and closing after a link is followed.
   -------------------------------------------------------------------------- */

.mobile-menu > summary {
  list-style: none;
}

.mobile-menu > summary::-webkit-details-marker {
  display: none;
}

.mobile-menu__close-icon,
.mobile-menu[open] .mobile-menu__open-icon {
  display: none;
}

.mobile-menu[open] .mobile-menu__close-icon {
  display: block;
}

.mobile-menu__panel {
  position: fixed;
  inset: var(--header-height) 0 0;
  z-index: var(--layer-floating);
  overflow-y: auto;
  padding: var(--space-l) var(--layout-gutter) var(--space-2xl);
  border-top: var(--rule-width) solid var(--color-line);
  background: var(--color-canvas);
  color: var(--color-ink);
  animation: panel-from-left var(--motion-base) var(--motion-ease);
}

html:has(.mobile-menu[open]) {
  overflow: hidden;
}

/* The panel starts under the header: with the menu open, the announcement
   bar (home) goes, so the header sits at the very top. */
html:has(.mobile-menu[open]) .announcement-bar {
  display: none;
}

.mobile-menu__link {
  hyphens: auto;
  hyphenate-limit-chars: 10 4 4;
  display: block;
  padding-block: var(--space-s);
  border-bottom: var(--rule-width) solid var(--color-line);
  font-family: var(--font-display);
  font-size: var(--type-heading-size);
  font-weight: var(--type-heading-weight);
  line-height: var(--type-heading-line-height);
  letter-spacing: var(--type-heading-tracking);
  text-decoration: none;
}

.mobile-menu__group {
  display: grid;
  justify-items: start;
  gap: var(--space-s);
  margin-top: var(--space-xl);
}

@media (min-width: 75em) {
  .mobile-menu {
    display: none;
  }
}

@keyframes panel-from-left {
  from { transform: translateX(-100%); }
}

/* --------------------------------------------------------------------------
   components/photo.html (HQ; the reference's placeholder.html with a real
   image). The frame keeps its ratio while the photo loads, on the stone
   tone. 3:4 photos fill it; ones far from 3:4 are shown whole.
   -------------------------------------------------------------------------- */

.ph {
  --ph-ratio: var(--ratio-product);
  display: block;
  width: 100%;
  aspect-ratio: var(--ph-ratio);
  overflow: hidden;
  background: var(--color-placeholder);
}

.ph__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.ph--whole .ph__image {
  object-fit: contain;
}

/* HQ (16 October 2026): the reference's placeholder boxes, shown only with
   STOREFRONT_PLACEHOLDERS on (development): a small label in the empty
   slot. */
.ph:has(> .ph__label) {
  position: relative;
}

.ph__label {
  position: absolute;
  bottom: var(--space-s);
  left: var(--space-s);
  color: var(--color-placeholder-label);
  font-family: var(--font-mono);
  font-size: var(--type-label-size);
  font-weight: var(--type-label-weight);
  line-height: var(--type-label-line-height);
  letter-spacing: var(--type-label-tracking);
  text-transform: uppercase;
}

/* --------------------------------------------------------------------------
   components/messages.html (HQ): Django's messages as notices.
   -------------------------------------------------------------------------- */

.messages {
  display: grid;
  gap: var(--space-xs);
  padding-top: var(--space-l);
}

/* HQ: Django draws the radio inside the card; hide it as the reference does
   (still focusable and read: the card shows focus and the checked state). */
.form-field__card input {
  position: absolute;
  width: var(--rule-width);
  height: var(--rule-width);
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
