/* ── composition ───────────────────────────────────────────────────────────
   Owl-selector spacing: .stack spaces CHILDREN, so it never adds a leading or
   trailing gap and never needs a :last-child reset. --stack-space is the knob. */
.stack        { display: flex; flex-direction: column; }
.stack > * + * { margin-block-start: var(--stack-space, var(--space-5)); }
.stack--1 { --stack-space: var(--space-1); }
.stack--2 { --stack-space: var(--space-2); }
.stack--3 { --stack-space: var(--space-3); }
.stack--4 { --stack-space: var(--space-4); }
.stack--5 { --stack-space: var(--space-5); }
.stack--6 { --stack-space: var(--space-6); }
.stack--7 { --stack-space: var(--space-7); }
.stack--8 { --stack-space: var(--space-8); }

/* Horizontal group that wraps: button rows, tag rows, wordmark rows. */
.cluster {
  display: flex; flex-wrap: wrap;
  gap: var(--cluster-space, var(--space-3));
  align-items: var(--cluster-align, center);
}
.cluster--center  { justify-content: center; }
.cluster--end     { justify-content: flex-end; }
.cluster--between { justify-content: space-between; }
.cluster--tight   { --cluster-space: var(--space-2); }
.cluster--loose   { --cluster-space: var(--space-5); }

/* Responsive grid with NO breakpoint: items wrap when they hit --grid-min.
   Preferred over media queries because a section does not know its container width. */
.grid--auto {
  display: grid;
  gap: var(--grid-space, var(--grid-gap, 20px));
  grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-min, 240px), 100%), 1fr));
}
/* Fixed column counts, mobile-first: one column until there is room. --columns is set
   inline by sections from their own settings, matching base.css's existing convention. */
.grid--fixed { display: grid; gap: var(--grid-space, var(--grid-gap, 20px)); grid-template-columns: 1fr; }
@media (min-width: 750px)  { .grid--fixed { grid-template-columns: repeat(min(var(--columns, 4), 2), 1fr); } }
@media (min-width: 990px)  { .grid--fixed { grid-template-columns: repeat(var(--columns, 4), 1fr); } }

/* Bento spans. Capped at the column count by min() so a 4-wide tile in a 3-column
   grid degrades instead of overflowing the row. */
.span-1 { grid-column: span 1; }
.span-2 { grid-column: span min(2, var(--columns, 4)); }
.span-3 { grid-column: span min(3, var(--columns, 4)); }
.span-4 { grid-column: span min(4, var(--columns, 4)); }
.row-1 { grid-row: span 1; }
.row-2 { grid-row: span 2; }
.row-3 { grid-row: span 3; }
.row-4 { grid-row: span 4; }
/* Spans collapse on small screens — a 2x2 bento tile on a phone is just a tall box. */
@media (max-width: 749px) {
  .span-2, .span-3, .span-4 { grid-column: span 1; }
  .row-2, .row-3, .row-4 { grid-row: span 1; }
}

/* ── surface ───────────────────────────────────────────────────────────────
   A panel. Inherits the theme's radius so a square button never sits in a
   rounded card. --surface-pad lets a component be denser without new CSS. */
.surface {
  background: var(--color-surface, #f7f7f5);
  border-radius: var(--radius, 4px);
  padding: var(--surface-pad, var(--space-6));
}
.surface--outline { background: transparent; border: 1px solid var(--color-border, #e4e4e4); }
.surface--accent  { background: var(--color-accent, #1f5f4d); color: var(--color-badge-text, #fff); }
.surface--flush   { --surface-pad: 0; }

/* ── media ─────────────────────────────────────────────────────────────────
   An aspect-ratio box that CANNOT collapse. Every image in the library goes in
   one of these, so a missing image leaves a tinted panel rather than a void. */
.media {
  position: relative; display: block; overflow: hidden;
  background: var(--color-surface, #f7f7f5);
  border-radius: var(--radius, 4px);
  aspect-ratio: var(--media-ratio, 1 / 1);
}
.media > img, .media > svg, .media > video {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: var(--media-fit, cover);
}
.media--square    { --media-ratio: 1 / 1; }
.media--portrait  { --media-ratio: 4 / 5; }
.media--tall      { --media-ratio: 3 / 4; }
.media--landscape { --media-ratio: 4 / 3; }
.media--wide      { --media-ratio: 16 / 9; }
.media--ultrawide { --media-ratio: 21 / 9; }
.media--contain   { --media-fit: contain; }
/* Free-height variant for hero bands, where the content sets the height. */
.media--fill { aspect-ratio: auto; height: 100%; }

/* Slow pan / zoom on a still image — the only motion in the library, and it
   respects the OS setting. Cheap way to make a static photo feel considered. */
.media--pan > img  { animation: ui-pan 22s ease-in-out infinite alternate; }
.media--zoom > img { animation: ui-zoom 22s ease-in-out infinite alternate; }
@keyframes ui-pan  { from { transform: scale(1.12) translateX(-3%); } to { transform: scale(1.12) translateX(3%); } }
@keyframes ui-zoom { from { transform: scale(1); } to { transform: scale(1.12); } }

/* ── overlay ───────────────────────────────────────────────────────────────
   Content placed over media, in the 9 positions the reference bento grid uses.
   A scrim is applied only when a tone is set, so text-over-photo stays legible
   without darkening a tile that has no photo. */
.overlay {
  position: absolute; inset: 0;
  display: grid;
  padding: var(--overlay-pad, var(--space-5));
  place-content: center; text-align: center;
}
.overlay--top-left      { place-content: start start;  text-align: start; }
.overlay--top-center    { place-content: start center; }
.overlay--top-right     { place-content: start end;    text-align: end; }
.overlay--center-left   { place-content: center start; text-align: start; }
.overlay--center        { place-content: center; }
.overlay--center-right  { place-content: center end;   text-align: end; }
.overlay--bottom-left   { place-content: end start;    text-align: start; }
.overlay--bottom-center { place-content: end center; }
.overlay--bottom-right  { place-content: end end;      text-align: end; }

.tone-light { color: #fff; }
.tone-dark  { color: var(--color-text, #171717); }
/* Scrim paints at z-index 0 and content at 1 — NOT z-index:-1 on the scrim, which would
   drop it behind the parent .media and hide it under the image it exists to darken. */
.tone-light::before, .tone-dark::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: var(--tone-scrim, linear-gradient(to top, rgba(0,0,0,0.55), rgba(0,0,0,0.05)));
}
.tone-dark::before { --tone-scrim: linear-gradient(to top, rgba(255,255,255,0.65), rgba(255,255,255,0.1)); }
.tone-light > *, .tone-dark > * { position: relative; z-index: 1; }

/* ── prose ─────────────────────────────────────────────────────────────────
   Rich-text output. Constrains measure for readability and fixes the margin
   collapse that makes richtext fields render with a stray leading gap. */
.prose { max-width: var(--prose-measure, 62ch); }
.prose > :first-child { margin-block-start: 0; }
.prose > :last-child  { margin-block-end: 0; }
.prose ul, .prose ol { padding-inline-start: var(--space-5); margin-block: 0 var(--space-4); }
.prose li + li { margin-block-start: var(--space-2); }
.prose a { text-decoration: underline; text-underline-offset: 2px; }
.prose--wide   { --prose-measure: 78ch; }
.prose--center { margin-inline: auto; }

/* ── content primitives ────────────────────────────────────────────────────
   The small typographic pieces every component reaches for. Rendered by
   snippets/eyebrow, badge, section-header, link-arrow. */
.eyebrow {
  display: block;
  font-size: 0.78rem; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--color-text-muted, #6b6b6b);
  margin-block-end: var(--space-2);
}
.tone-light .eyebrow, .tone-dark .eyebrow { color: inherit; opacity: 0.8; }

.badge {
  display: inline-flex; align-items: center; justify-content: center;
  padding: var(--space-1) var(--space-3);
  background: var(--color-accent, #1f5f4d); color: var(--color-badge-text, #fff);
  border-radius: var(--radius, 4px);
  font-size: 0.78rem; line-height: 1.4;
}
.badge--outline { background: transparent; color: inherit; border: 1px solid currentColor; }
.badge--numeral {
  width: 2.25rem; height: 2.25rem; padding: 0;
  border-radius: 50%; font-size: 0.95rem;
}

/* Heading + subheading + optional link. Used by every component that has a title,
   which is what keeps section headings identical across the whole theme. */
.section-header { margin-block-end: var(--space-6); }
.section-header--center { text-align: center; }
.section-header--center .prose { margin-inline: auto; }
.section-header--split {
  display: flex; flex-wrap: wrap; gap: var(--space-4);
  align-items: baseline; justify-content: space-between;
}
.section-header__title { margin-block-end: 0; }
.section-header__text { color: var(--color-text-muted, #6b6b6b); margin-block-start: var(--space-2); }

.link-arrow { display: inline-flex; align-items: center; gap: var(--space-2); text-decoration: none; }
.link-arrow::after { content: "\2192"; transition: transform 0.2s ease; }
.link-arrow:hover::after { transform: translateX(0.2em); }

/* ── spacing utilities ─────────────────────────────────────────────────────
   The ONLY sanctioned way for a component to add space. Deliberately limited to
   the ramp: there is no .pad-13 because there is no 13 in the design system. */
.pad-2 { padding: var(--space-2); }  .pad-4 { padding: var(--space-4); }
.pad-5 { padding: var(--space-5); }  .pad-6 { padding: var(--space-6); }
.pad-7 { padding: var(--space-7); }  .pad-8 { padding: var(--space-8); }
.pad-block-6 { padding-block: var(--space-6); }
.pad-block-7 { padding-block: var(--space-7); }
.pad-block-8 { padding-block: var(--space-8); }
.gap-2 { gap: var(--space-2); }  .gap-3 { gap: var(--space-3); }
.gap-4 { gap: var(--space-4); }  .gap-5 { gap: var(--space-5); }
.gap-6 { gap: var(--space-6); }  .gap-7 { gap: var(--space-7); }

/* Suffixes match Shopify's text_alignment values exactly, so a section pipes the setting
   straight into the class with no mapping step. */
.text-left   { text-align: start; }
.text-center { text-align: center; }
.text-right  { text-align: end; }
.muted       { color: var(--color-text-muted, #6b6b6b); }
.full-bleed  { width: 100vw; margin-inline: calc(50% - 50vw); }

/* ── placeholders ──────────────────────────────────────────────────────────
   The engine's placeholder_svg_tag emits <svg class="placeholder-svg" viewBox="0 0 1 1">
   with no fill, and nothing styled the class — so an unset image rendered as a
   full-width TRANSPARENT VOID rather than an empty frame. Four call sites depend
   on this rule (card-product, card-collection, main-product, blocks/image). */
.placeholder-svg {
  display: block; width: 100%; aspect-ratio: 1 / 1;
  background: var(--color-surface, #f7f7f5);
}
.block-image { min-height: var(--space-8); background: var(--color-surface, #f7f7f5); border-radius: var(--radius, 4px); }
.block-image img { width: 100%; height: auto; display: block; }

/* ── motion ────────────────────────────────────────────────────────────────
   One global opt-out. Any component adding an animation is covered by this and
   must not ship its own prefers-reduced-motion block. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}
