/* ALJILD layout primitives — WEB-04
 *
 * Ten objects, each with exactly one job. Pages are composed by nesting them
 * rather than by writing bespoke layout CSS per page, which is how a site
 * drifts: forty one-off rules that nobody dares delete.
 *
 * Rules of the set:
 *   1. A layout owns the space BETWEEN its children, never the space around
 *      itself. Margins on components are what makes spacing unpredictable.
 *   2. Every gap comes from the generated space scale. No magic numbers.
 *   3. Prefer intrinsic behaviour over breakpoints — most of these respond to
 *      available space, not viewport width, so they work in any container.
 *   4. Logical properties throughout, so RTL needs no overrides.
 */


/* ── Stack ────────────────────────────────────────────────────────────────
   Vertical rhythm. The single most used object on the site.
   <div class="l-stack" data-gap="l"> … </div>                              */

.l-stack {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

.l-stack > * {
  margin-block: 0;
}

.l-stack > * + * {
  margin-block-start: var(--stack-gap, var(--space-s));
}

.l-stack[data-gap="3xs"] { --stack-gap: var(--space-3xs); }
.l-stack[data-gap="2xs"] { --stack-gap: var(--space-2xs); }
.l-stack[data-gap="xs"]  { --stack-gap: var(--space-xs); }
.l-stack[data-gap="s"]   { --stack-gap: var(--space-s); }
.l-stack[data-gap="m"]   { --stack-gap: var(--space-m); }
.l-stack[data-gap="l"]   { --stack-gap: var(--space-l); }
.l-stack[data-gap="xl"]  { --stack-gap: var(--space-xl); }
.l-stack[data-gap="2xl"] { --stack-gap: var(--space-2xl); }
.l-stack[data-gap="3xl"] { --stack-gap: var(--space-3xl); }

/* Push everything after this element to the bottom — equal-height cards. */
.l-stack > [data-push-end] {
  margin-block-start: auto;
}


/* ── Center ───────────────────────────────────────────────────────────────
   Horizontal centring with gutters that never collapse.                    */

.l-center {
  box-sizing: content-box;
  margin-inline: auto;
  max-inline-size: var(--center-max, var(--content-max, 1180px));
  padding-inline: var(--center-gutter, var(--space-l));
}

.l-center[data-measure="prose"]   { --center-max: var(--measure-prose); }
.l-center[data-measure="body"]    { --center-max: var(--measure-body); }
.l-center[data-measure="display"] { --center-max: var(--measure-display); }

/* Centre the children too, not just the box. */
.l-center[data-align="center"] {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}


/* ── Cluster ──────────────────────────────────────────────────────────────
   Horizontal grouping that wraps gracefully. Nav, tags, button rows.       */

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

.l-cluster[data-gap="2xs"] { --cluster-gap: var(--space-2xs); }
.l-cluster[data-gap="xs"]  { --cluster-gap: var(--space-xs); }
.l-cluster[data-gap="m"]   { --cluster-gap: var(--space-m); }
.l-cluster[data-gap="l"]   { --cluster-gap: var(--space-l); }
.l-cluster[data-gap="xl"]  { --cluster-gap: var(--space-xl); }

.l-cluster[data-justify="between"] { justify-content: space-between; }
.l-cluster[data-justify="center"]  { justify-content: center; }
.l-cluster[data-justify="end"]     { justify-content: flex-end; }
.l-cluster[data-align="start"]     { --cluster-align: flex-start; }
.l-cluster[data-align="baseline"]  { --cluster-align: baseline; }


/* ── Switcher ─────────────────────────────────────────────────────────────
   Side by side until the container is too narrow, then stacked — with no
   media query. The threshold is a container width, so it behaves correctly
   inside a sidebar as well as at full width.                               */

.l-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--switcher-gap, var(--space-l));
}

.l-switcher > * {
  flex-grow: 1;
  flex-basis: calc((var(--switcher-threshold, 40rem) - 100%) * 999);
}

.l-switcher[data-threshold="narrow"] { --switcher-threshold: 30rem; }
.l-switcher[data-threshold="wide"]   { --switcher-threshold: 55rem; }

/* Weighted split — e.g. a 60/40 gallery and buy column. */
.l-switcher[data-split="60-40"] > :first-child { flex-grow: 1.5; }
.l-switcher[data-split="40-60"] > :last-child  { flex-grow: 1.5; }


/* ── Grid ─────────────────────────────────────────────────────────────────
   Equal columns that reflow on available space, not viewport width.        */

.l-grid {
  display: grid;
  gap: var(--grid-gap, var(--space-l));
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(var(--grid-min, 16rem), 100%), 1fr)
  );
  align-items: start;
}

.l-grid[data-min="s"] { --grid-min: 11rem; }
.l-grid[data-min="m"] { --grid-min: 16rem; }
.l-grid[data-min="l"] { --grid-min: 22rem; }

/* A fixed column count where the design genuinely requires one. */
.l-grid[data-cols="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.l-grid[data-cols="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.l-grid[data-cols="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)); }

@media (max-width: 900px) {
  .l-grid[data-cols="3"],
  .l-grid[data-cols="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 520px) {
  .l-grid[data-cols="2"],
  .l-grid[data-cols="3"],
  .l-grid[data-cols="4"] { grid-template-columns: 1fr; }
}

/* Equal-height rows so prices and buttons line up across a row. */
.l-grid[data-stretch] { align-items: stretch; }


/* ── Sidebar ──────────────────────────────────────────────────────────────
   Main content with a companion column that collapses when there is not
   enough room for both.                                                    */

.l-sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sidebar-gap, var(--space-xl));
}

.l-sidebar > :first-child {
  flex-basis: var(--sidebar-width, 18rem);
  flex-grow: 1;
}

.l-sidebar > :last-child {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: var(--sidebar-content-min, 60%);
}

/* Sidebar on the trailing side instead. */
.l-sidebar[data-side="end"] > :first-child {
  flex-basis: 0;
  flex-grow: 999;
  min-inline-size: var(--sidebar-content-min, 60%);
}

.l-sidebar[data-side="end"] > :last-child {
  flex-basis: var(--sidebar-width, 18rem);
  flex-grow: 1;
  min-inline-size: 0;
}


/* ── Frame ────────────────────────────────────────────────────────────────
   Media held to an aspect ratio. Reserves space before the image loads,
   which is what keeps CLS at zero.                                         */

.l-frame {
  aspect-ratio: var(--frame-ratio, 4 / 5);
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.l-frame > img,
.l-frame > video {
  inline-size: 100%;
  block-size: 100%;
  object-fit: var(--frame-fit, cover);
}

.l-frame[data-ratio="square"]    { --frame-ratio: 1; }
.l-frame[data-ratio="portrait"]  { --frame-ratio: 4 / 5; }
.l-frame[data-ratio="tall"]      { --frame-ratio: 3 / 4; }
.l-frame[data-ratio="landscape"] { --frame-ratio: 3 / 2; }
.l-frame[data-ratio="wide"]      { --frame-ratio: 16 / 9; }

/* Product shots are objects on a ground — contain, never crop the item. */
.l-frame[data-fit="contain"] { --frame-fit: contain; }


/* ── Cover ────────────────────────────────────────────────────────────────
   A region with something centred in it, optionally with a header or footer
   pinned to the edges.                                                     */

.l-cover {
  display: flex;
  flex-direction: column;
  min-block-size: var(--cover-min, 60vh);
  padding: var(--cover-pad, var(--space-l));
}

.l-cover > * {
  margin-block: var(--space-l);
}

.l-cover > [data-cover-centre] {
  margin-block: auto;
}

.l-cover > :first-child:not([data-cover-centre]) { margin-block-start: 0; }
.l-cover > :last-child:not([data-cover-centre])  { margin-block-end: 0; }


/* ── Reel ─────────────────────────────────────────────────────────────────
   Horizontal scroll strip with snap. For a related-products row on a phone,
   where a wrapped grid would push the footer a screen away.                */

.l-reel {
  display: flex;
  gap: var(--reel-gap, var(--space-m));
  overflow-x: auto;
  overscroll-behavior-inline: contain;
  scroll-snap-type: inline mandatory;
  scrollbar-width: thin;
  padding-block-end: var(--space-xs);
}

.l-reel > * {
  flex: 0 0 var(--reel-item, 16rem);
  scroll-snap-align: start;
}

.l-reel::-webkit-scrollbar { block-size: 6px; }
.l-reel::-webkit-scrollbar-thumb { background: var(--border); }


/* ── Bleed ────────────────────────────────────────────────────────────────
   Break out of the content column to full width. See the note in
   components.css: no clipping anywhere, because clip kills sticky.         */

.l-bleed {
  inline-size: 100vw;
  max-inline-size: 100vw;
  margin-inline-start: calc(50% - 50vw);
  margin-inline-end: calc(50% - 50vw);
}


/* ── Section ──────────────────────────────────────────────────────────────
   Vertical page rhythm. The only object allowed to set outer padding.      */

.l-section {
  padding-block: var(--section-pad, var(--space-3xl));
}

.l-section[data-pad="s"]  { --section-pad: var(--space-xl); }
.l-section[data-pad="m"]  { --section-pad: var(--space-2xl); }
.l-section[data-pad="l"]  { --section-pad: var(--space-3xl); }
.l-section[data-pad="xl"] { --section-pad: var(--space-4xl); }
.l-section[data-pad="none"] { --section-pad: 0; }


/* ── Reduced motion ───────────────────────────────────────────────────── */

@media (prefers-reduced-motion: reduce) {
  .l-reel { scroll-behavior: auto; scroll-snap-type: none; }
}
