/* Layout primitives (Rule-21 Part B). Screens are composed from these instead of one-off layouts.
   Each adapts to the space it is given: they wrap and reflow by themselves, with no device breakpoints.
   Tune them per use with a modifier class (for example .l-grid--wide), never with an inline style:
   the content security policy blocks inline styles. */

/* Page column, centred, with a side gutter that respects device safe areas. */
.l-center {
  box-sizing: content-box;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: max(var(--gutter), var(--safe-left)) max(var(--gutter), var(--safe-right));
}
.l-center--narrow {
  max-inline-size: var(--container-narrow);
}

/* A vertical section of a page. */
.l-section {
  padding-block: var(--space-2xl);
}
.l-section--sunken {
  background: var(--color-surface-sunken);
}
.l-section--inverse {
  background: var(--color-surface-inverse);
  color: var(--color-text-inverse);
  /* Every role a component reads is re-pointed, so components need no "on dark" variants. */
  --color-text: var(--color-text-inverse);
  --color-surface-sunken: var(--color-border-inverse);
  --color-text-muted: var(--color-text-inverse-muted);
  --color-border: var(--color-border-inverse);
  --color-border-strong: var(--color-text-inverse);
  --color-primary: var(--color-primary-on-inverse);
  --color-focus: var(--color-primary-on-inverse);
}

/* A band in the brand colour, for the one closing call to action. Roles are re-pointed, as on dark bands. */
.l-section--brand {
  background: var(--color-band);
  color: var(--color-on-band);
  --color-text: var(--color-on-band);
  --color-text-muted: var(--color-on-band);
  --color-primary: var(--color-on-band);
  --color-on-primary: var(--color-band);
  --color-primary-hover: var(--color-primary-soft);
  --color-border-strong: var(--color-on-band);
  --color-focus: var(--color-on-band);
}
.l-section--flush-end {
  padding-block-end: 0;
}
.l-section--compact {
  padding-block: var(--space-xl);
}

/* Stack: children one under another with an even gap. */
.l-stack {
  display: flex;
  flex-direction: column;
  gap: var(--space-m);
}
.l-stack--xs {
  gap: var(--space-xs);
}
.l-stack--l {
  gap: var(--space-l);
}
.l-stack--xl {
  gap: var(--space-xl);
}

/* Cluster: items in a row that wrap when they run out of room. */
.l-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-s) var(--space-m);
}
.l-cluster--between {
  justify-content: space-between;
}
.l-cluster--tight {
  gap: var(--space-xs);
}

/* Grid: as many equal columns as fit, never narrower than the minimum, never wider than the row. */
.l-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: var(--space-l);
}
.l-grid--narrow {
  grid-template-columns: repeat(auto-fit, minmax(min(11rem, 100%), 1fr));
}
.l-grid--wide {
  grid-template-columns: repeat(auto-fit, minmax(min(22rem, 100%), 1fr));
}

/* Sidebar: a side column beside the content; the side drops below when the content gets too narrow. */
.l-sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l) var(--space-xl);
}
.l-sidebar > :first-child {
  flex: 1 1 18rem;
}
.l-sidebar > :last-child {
  flex: 999 1 0;
  min-inline-size: min(60%, 100%);
}

/* Switcher: side by side while there is room for all, otherwise stacked. Never a lonely last item. */
.l-switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-l);
}
.l-switcher > * {
  flex: 1 1 calc((44rem - 100%) * 999);
  min-inline-size: 0;
}

/* Cover: fills at least the screen height and centres its main child. Uses the small viewport height,
   so mobile browser toolbars never hide content (Rule-21 Part B). */
.l-cover {
  display: flex;
  flex-direction: column;
  min-block-size: 100vh;
  min-block-size: 100svh;
}
.l-cover > .l-cover__main {
  margin-block: auto;
}

/* Frame: holds a shape so that media never shifts the page while it loads. */
.l-frame {
  aspect-ratio: 16 / 9;
  overflow: hidden;
}
.l-frame--square {
  aspect-ratio: 1;
}
.l-frame > * {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* Reel: a row that scrolls sideways inside itself, for content that needs two dimensions.
   It must be focusable (tabindex="0") and labelled, so that a keyboard can scroll it. */
.l-reel {
  display: flex;
  gap: var(--space-m);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  padding-block-end: var(--space-xs);
}
.l-reel > * {
  flex: 0 0 auto;
  scroll-snap-align: start;
}

/* Ruled heading: title beside its statement when wide, stacked when narrow. */
.l-heading {
  container-type: inline-size;
  padding-block-start: var(--space-l);
  border-block-start: var(--border-thick) solid var(--color-border-strong);
  margin-block-end: var(--space-xl);
}
.l-heading__inner {
  display: grid;
  gap: var(--space-s);
}
@container (min-width: 52rem) {
  .l-heading__inner {
    grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
    gap: var(--space-xl);
  }
}
