/**
 * Layout primitives (Every Layout style).
 *
 * Single-responsibility, composable layout classes shared across blocks. Each is
 * configured through custom properties whose fallbacks come from theme.json
 * tokens, so the value layer stays in theme.json and the rule layer stays here.
 *
 * Apply by adding the class to a block via Advanced → Additional CSS class(es),
 * or by outputting the class on a custom block's wrapper. Selectors are kept to a
 * single class (low specificity) so they compose without fighting block supports.
 *
 * @see https://every-layout.dev/
 */

/* Measure axiom defaults.
   Body copy is capped for readability; headings are intentionally looser. */
:root {
  --measure-body: var(--wp--custom--measure--body, 66ch);
  --measure-heading: var(--wp--custom--measure--heading, 24ch);

  /* --stack-space: 2.5rem; */
  --stack-space: 1.625rem;
  --site-header-scroll-threshold: 30;
  --site-nav-desktop-breakpoint: 1090px;
  --transition-duration: var(--wp--custom--motion--transition-duration, 380ms);
}

/* Broad text defaults (exception-based): constrain textual flow elements and
   leave structural/layout containers unconstrained. */
:where(body:not(.components-panel__body-title))
  :where(p, li, dt, dd, blockquote, figcaption) {
  max-inline-size: var(--measure-body);
}

::where(body:not(.components-panel__body-title))
  :where(h1, h2, h3, h4, h5, h6) {
  max-inline-size: var(--measure-heading);
}

/* Utility hooks for explicit overrides in block class names. */
.measure {
  max-inline-size: var(--measure-body);
}

.measure-heading {
  max-inline-size: var(--measure-heading);
}

.measure-none {
  max-inline-size: none;
}

/* Footer exception: do not constrain measure inside footer content. */
footer :where(*) {
  max-inline-size: none;
}

footer :where(a) {
  text-decoration: none;
}

footer :where(.cluster) {
  --cluster-space: 1.875rem;
}

/* Cover — a header/footer/centred-region layout that fills a minimum height.
   Knobs: --cover-min-height, --cover-space. Mark the centred child .cover__center. */
.cover {
  display: flex;
  flex-direction: column;
  min-block-size: var(--cover-min-height, 100svh);
  padding-inline: var(--cover-space, var(--wp--preset--spacing--s, 2.5rem));
}

.cover > * {
  margin-block: var(--cover-space, var(--wp--preset--spacing--s, 2.5rem));
}

.cover > :first-child:not(.cover__center) {
  margin-block-start: 0;
}

.cover > :last-child:not(.cover__center) {
  margin-block-end: 0;
}

.cover > .cover__center {
  margin-block-start: auto;
  margin-block-end: 2rem;
}

/* Stack — even vertical rhythm between flow elements.
   Knob: --stack-space. */
.stack {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
}

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

/* Doubled class: WP's own global styles reset margins on any flex/grid-layout
   block's children via `.is-layout-flex > :is(*, div){margin:0}` (specificity
   0,1,1, injected after enqueued stylesheets) — a block using both `.stack`
   and WP's native flex layout support needs to outrank that unconditionally. */
.stack.stack > * + * {
  margin-block-start: var(
    --stack-space,
    var(--wp--custom--rhythm--base, 1.625rem)
  );
}

/* Stack rhythm modifiers — FIXED text-rhythm steps from the design (15 / 26 /
   58px), sourced from theme.json `custom.rhythm`. These are deliberately not the
   fluid `--wp--preset--spacing--*` scale: section padding breathes with the
   viewport, but the space between a heading and its paragraph is a typographic
   relationship and must stay constant. Base (26px) is the default above. */
.stack--small {
  --stack-space: var(--wp--custom--rhythm--small, 0.9375rem);
}

.stack--large {
  --stack-space: var(--wp--custom--rhythm--large, 3.625rem);
}

.stack--start {
  justify-content: flex-start;
}

.stack--end {
  justify-content: flex-end;
}

.stack--center {
  justify-content: center;
}

.stack--between {
  justify-content: space-between;
}

.stack--around {
  justify-content: space-around;
}

.stack--evenly {
  justify-content: space-evenly;
}

/* Stack cross-axis alignment of children. The .stack--start/end/center set above
   distribute children ALONG the block axis (justify-content, i.e. vertically);
   these align children ACROSS it (align-items, i.e. horizontally) — e.g.
   .stack--align-end pulls each child to the inline-end without any WP layout
   support. Default (no modifier) leaves the flex default of `stretch`. */
.stack--align-start {
  align-items: flex-start;
}

.stack--align-center {
  align-items: center;
}

.stack--align-end {
  align-items: flex-end;
}

/* Opt out of the stack gap for a specific child element. */
.stack.stack > .stack--exception {
  margin-block-start: 0;
}

/* Cluster — wrapping group of items with consistent gaps.
   Knobs: --cluster-space, --cluster-justify, --cluster-align. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--cluster-space, 0.5rem);
  row-gap: var(--cluster-space, 0.5rem);
  justify-content: var(--cluster-justify, flex-start);
  align-items: var(--cluster-align, center);
}

.cluster--between {
  justify-content: space-between;
}

/* Switcher — responsive horizontal-to-vertical layout that stacks when items
   become too narrow, and can force full-width when count exceeds a limit.
   Knobs: --switcher-space, --switcher-threshold. */
.switcher {
  display: flex;
  flex-wrap: wrap;
  column-gap: var(--switcher-space, var(--wp--preset--spacing--xs, 1.5rem));
  /* Row gap only applies once items WRAP (stack on mobile). It should match the
     default Stack rhythm (rhythm-base, 26px) so stacked switcher columns keep the
     same vertical spacing as any other stacked flow — not the smaller horizontal
     column gap. Overridable per instance via --switcher-row-space. */
  row-gap: var(--switcher-row-space, var(--wp--custom--rhythm--base, 1.625rem));
}

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

/* Default item limit: when 5+ items exist, stack all at full width.
   Adjust this selector if you want a different hard limit. */
.switcher > :nth-last-child(n + 5),
.switcher > :nth-last-child(n + 5) ~ * {
  flex-basis: 100%;
}

/* Managing proportions: reweight the first two children for an asymmetric
   split (e.g. 1/3-2/3) instead of the equal default. Only meaningful once the
   items are sharing a row — flex-basis above still governs the stack point. */
.switcher > :nth-child(1) {
  flex-grow: var(--switcher-first-grow, 1);
}

.switcher > :nth-child(2) {
  flex-grow: var(--switcher-second-grow, 1);
}

/* Opt out of stacking entirely for a given instance. */
.switcher.is-not-stacked-on-mobile {
  flex-wrap: nowrap;
}

/* Reverse the STACK order without touching the row order or using a query.
   `wrap-reverse` only flips how wrapped lines stack, so in the row layout order
   is unchanged, but once stacked the last child sits on top (e.g. image above
   text). DOM order stays as authored, so reading/tab order is preserved.
   Use for a content-image split with the image on the RIGHT (image last in DOM):
   image sits right in the row, floats above the text once stacked. */
.switcher--reverse {
  flex-wrap: wrap-reverse;
}

/* Content-image split with the image on the LEFT. `wrap-reverse` can't do this
   one — it would drop the image BELOW the text when stacked. Instead order the
   media child first: `order` governs BOTH the row's main axis AND the wrapped
   column's stack order in one move, so the image sits LEFT in the row and ON TOP
   once stacked — no width query, and independent of DOM order (reading order is
   preserved; only the visual position moves). Targets whichever child holds the
   image (a column wrapper, or the image block placed directly). */
.switcher--media-left > :has(> .wp-block-pad-image-block),
.switcher--media-left > .wp-block-pad-image-block {
  order: -1;
}

/* Sidebar — a media object: a fixed-size lead element (icon, avatar) beside a
   flexible companion (text), top-aligned by default. The lead keeps its own
   intrinsic size; the companion takes the rest and wraps beneath only if it
   can't hold --sidebar-content-min. Knobs: --sidebar-gap, --sidebar-align,
   --sidebar-width (lead basis, defaults to intrinsic), --sidebar-content-min. */
.sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sidebar-gap, 1.25rem);
  align-items: var(--sidebar-align, flex-start);
}

.sidebar > :first-child {
  flex-grow: 0;
  flex-shrink: 0;
  flex-basis: var(--sidebar-width, auto);
}

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

/* Grid — auto-fit tracks that reflow intrinsically as space runs out; no
   breakpoint needed. Knobs: --grid-columns (explicit override), --grid-min,
   --grid-gap. */
.grid {
  display: grid;
  grid-template-columns: var(
    --grid-columns,
    repeat(auto-fit, minmax(min(var(--grid-min, 16rem), 100%), 1fr))
  );
  column-gap: var(--grid-gap, var(--wp--preset--spacing--m));
  row-gap: var(--grid-row-gap, var(--wp--preset--spacing--s));
}

.grid > * {
  min-inline-size: 0;
}

/* Grid rows modifier — opt-in subgrid so each child shares the grid's row
   tracks, keeping media, headings and body copy aligned across columns even
   when content length differs (a heading that wraps, a taller logo). Pure
   progressive enhancement: without subgrid support each child just stacks
   normally (ragged rows, still valid). Knobs: --grid-rows (how many internal
   rows each child spans; 2 = media + text), --grid-row-gap (gap between them,
   overriding the parent grid's larger inter-track gap; matches the Stack's `s`
   default so a Grid and a Switcher instance of the same content read alike).

   Deliberately scoped to `.grid.grid--rows` — subgrid needs a grid parent, so
   this must NOT engage when the same modifier rides on a flex primitive (the
   Switcher, i.e. the columns block at <=3 columns), where it would turn each
   child into a mis-sized grid. There, alignment comes from the content instead
   (e.g. a fixed logo band). */
/* Each child is a UNIT (media + text), so the space BETWEEN units has to exceed
   the space WITHIN one or the grouping doesn't read — items stop looking like
   pairs and become an undifferentiated run. That matters most in the single
   column at phone widths, where there are no columns to separate them.
   Applied outside the @supports below because it holds either way: with subgrid
   this is the gap between one unit's text and the next unit's media, and in the
   no-subgrid fallback it's simply the gap between items. */
.grid.grid--rows {
  --grid-row-gap: var(--wp--preset--spacing--l, 6.5rem);
}

@supports (grid-template-rows: subgrid) {
  .grid.grid--rows > * {
    display: grid;
    grid-template-rows: subgrid;
    grid-row: span var(--grid-rows, 2);
    /* Deliberately its OWN knob, not --grid-row-gap. Sharing that variable made
       the within-unit gap identical to the between-unit gap by construction, so
       no amount of tuning could ever separate the two. */
    row-gap: var(--grid-rows-gap, var(--wp--preset--spacing--s));
  }

  /* The child is a .stack in the fallback; its adjacent-sibling margins would
     double up on the subgrid row-gap, so neutralise them once subgrid drives
     the rhythm. */
  .grid.grid--rows > .stack > * + * {
    margin-block-start: 0;
  }
}

/* Center — horizontally centred, max-width constrained content column.
   Knobs: --center-max, --center-gutters. */
.center {
  box-sizing: content-box;
  margin-inline: auto;
  max-inline-size: var(
    --center-max,
    var(--wp--style--global--content-size, 60ch)
  );
  padding-inline: var(--center-gutters, 0);
}

/* Frame — lock media to a fixed aspect ratio regardless of its natural size,
   cropping to fill with object-fit. Knob: --frame-ratio. The child selector is
   doubled (.frame.frame) so it outranks a nested media block's own single-class
   `img` rule, which is equal specificity otherwise. */
.frame {
  aspect-ratio: var(--frame-ratio, 3 / 2);
  overflow: hidden;
}

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

/* Icon — size an inline SVG to the accompanying text's cap height so it scales
   and aligns with the label. Knob: --icon-size. Pair the icon and text inside a
   `.with-icon` container to lay them out inline with a gap. */
.icon {
  inline-size: var(--icon-size, 1cap);
  block-size: var(--icon-size, 1cap);
  flex-shrink: 0;
}

.with-icon {
  display: inline-flex;
  align-items: center;
  gap: var(--icon-gap, 0.5em);
}
