/* SLASHED — core/layout.css
   @layer slashed.layout
   Layout primitives: section, container, stack, cluster, grid, sidebar, switcher, frame.
   Prefix: .sf-*; local rhythm via --sf-*-gap / sizing tokens.
   SL-005: every @container query in this file hardcodes its breakpoint
   instead of referencing a --sf-* token — var() is not allowed inside an
   @container condition per the CSS spec. This applies framework-wide to
   every @container site below; not re-explained at each one.
   SL-005a: those hardcoded breakpoints are expressed in REM, never em.
   Inside an @container condition a font-relative em resolves against the
   QUERY CONTAINER's own computed font-size — and under SLASHED's default
   fluid type that font-size is inherited from body (a clamp() over 100vw,
   ~16–20px), so an em breakpoint would silently slide with the VIEWPORT and
   break the "responds to its own container width, not the viewport" contract
   (docs/architecture.md). rem resolves against the ROOT (:root/html stays a
   fixed 16px; fluid type is applied to body, not html), so the breakpoint is
   viewport-independent while still honouring user zoom / root-font-size
   preferences. Note this is the OPPOSITE of the @media convention, where em
   and rem both resolve against the root — do not copy "use em for a11y
   breakpoints" from @media into @container. (Matches Tailwind, whose
   container-query breakpoints are rem; cf. issue #497 fluid-cq work.)
   SL-034: a query container cannot be the subject of its own @container
   query — conditions only ever match descendants of the nearest ancestor
   container, never the element that establishes it (self-querying is a
   silent no-op, not an error). Primitives that need to resize THEMSELVES
   (.sf-grid-cols-2/3/4/6, .sf-bento) must therefore rely on an ancestor
   container (.sf-container / .sf-cq / .sf-fluid-cq) rather than declaring
   `container` on themselves. .sf-grid-cols-1-2 etc. already follow this —
   they've never declared their own `container` — so they were unaffected.
   .sf-alternate is a different, unrelated-but-similar-looking pattern: it
   DOES declare `container` on itself, but only to restyle its CHILDREN
   (`.sf-alternate > *`), which is not self-querying and is fine. Not
   re-explained at each site below. */

@layer slashed.layout {

  /* Section */
  .sf-section     { padding-block: var(--sf-section-pad); }
  .sf-section--xs { --sf-section-pad: var(--sf-section-pad--xs); }
  .sf-section--s  { --sf-section-pad: var(--sf-section-pad--s); }
  .sf-section--m  { --sf-section-pad: var(--sf-section-pad--m); }
  .sf-section--l  { --sf-section-pad: var(--sf-section-pad--l); }
  .sf-section--xl { --sf-section-pad: var(--sf-section-pad--xl); }
  .sf-section--2xl { --sf-section-pad: var(--sf-section-pad--2xl); }

  .sf-section--guttered { padding-inline: var(--sf-gutter); }
  .sf-section--guttered .sf-container { padding-inline: 0; }
  /* .sf-content-grid carries the gutter in its own edge tracks
     (minmax(gutter,1fr)), not in padding — so unlike .sf-container it can't be
     de-duplicated by zeroing its padding (it has none). Left alone, the
     section's padding boxes the grid in: content ends up double-guttered and
     .sf-full-bleed stops at the padding edge instead of the section edge.
     Drop the section's own padding so the grid spans edge-to-edge and its
     tracks provide the single gutter; full-bleed then reaches the true edge.
     Only when the content grid is the SOLE direct child: dropping the section
     padding is right for the grid but would strip the gutter from any non-grid
     sibling (a heading, a plain block) that legitimately relies on it — and
     those two wants are physically irreconcilable (the gutter *is* the section
     padding that full-bleed must escape). So we restrict to the unambiguous
     case; a mixed section keeps its padding and behaves exactly as before this
     rule existed. Direct-child scope also stops a nested grid deeper in the
     section from stripping the gutter. */
  .sf-section--guttered:has(> .sf-content-grid):not(:has(> :not(.sf-content-grid))) {
    padding-inline: 0;
  }

  .sf-section-group > .sf-section + .sf-section { padding-block-start: 0; }

  /* Header — block padding on the standard spacing scale. Headers usually
     want lighter vertical rhythm than .sf-section, so these map to
     --sf-space-* directly. Only block padding is set; any inline gutter
     (from .sf-section--guttered, a container, or the element itself) is
     left intact. */
  .sf-header--xs { padding-block: var(--sf-space-xs); }
  .sf-header--s  { padding-block: var(--sf-space-s); }
  .sf-header--m  { padding-block: var(--sf-space-m); }
  .sf-header--l  { padding-block: var(--sf-space-l); }
  .sf-header--xl { padding-block: var(--sf-space-xl); }

  /* Collapse modifier */
  .sf-section--collapse:has(+ .sf-section--collapse) {
    padding-block-end: calc(var(--sf-section-pad) / 2);
  }
  .sf-section--collapse + .sf-section--collapse {
    padding-block-start: calc(var(--sf-section-pad) / 2);
  }

  .sf-divider {
    inline-size:        100%;
    border:             none;
    border-block-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);
    margin-block:       var(--sf-divider-gap);
  }
  .sf-divider--vertical {
    inline-size:          auto;
    border-block-start:   none;
    border-inline-start:  var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);
    margin-block:         0;
    margin-inline:        var(--sf-divider-gap);
    align-self:           stretch;
  }

  .sf-divider--soft   { --sf-divider-color: var(--sf-color-border--subtle); }
  .sf-divider--strong { --sf-divider-color: var(--sf-color-border--strong); }
  .sf-divider--dashed { --sf-divider-style: dashed; }
  .sf-divider--dotted { --sf-divider-style: dotted; }

  .sf-divider--gradient {
    border:        none;
    block-size:    var(--sf-divider-width);
    background:    linear-gradient(to right, transparent, var(--sf-divider-color), transparent);
  }

  /* Divide — rules between direct children, reusing .sf-divider's tokens.
     Unlike .sf-divider (a standalone separator element), .sf-divide is
     applied to the container and needs no extra markup per gap. */
  .sf-divide > * + * {
    border-block-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);
  }
  .sf-divide--vertical > * + * {
    border-block-start:  none;
    border-inline-start: var(--sf-divider-width) var(--sf-divider-style) var(--sf-divider-color);
  }


  /* Container */
  .sf-container {
    container:      sf-layout / inline-size;
    width:          100%;
    max-width:      var(--sf-container-default);
    margin-inline:  auto;
    padding-inline: var(--sf-gutter);
  }
  .sf-container--narrow { max-width: var(--sf-container-narrow); }
  .sf-container--prose  { max-width: var(--sf-container-prose); }
  .sf-container--wide   { max-width: var(--sf-container-wide); }
  .sf-container--full   { max-width: var(--sf-container-full); }

  /* .sf-cq: CQ scope without .sf-container's max-width/centering.
     Use when a CQ-dependent primitive needs a container ancestor but no layout chrome. */
  .sf-cq {
    container-type: inline-size;
  }

  /* Overlay — absolute-fill layout helper for overlays/backdrops. */
  .sf-overlay {
    position: absolute;
    inset:    0;
  }

  
  /* .sf-fluid-cq: opt a subtree into a CONTAINER-relative fluid scale (issue
     #497). By default --sf-text-* / --sf-space-* interpolate against 100vw (the
     viewport); inside .sf-fluid-cq they interpolate against 100cqi (this box's
     inline size), so type + spacing track the container the way the layout
     primitives (.sf-grid-cols-*, .sf-content-grid, .sf-bento) already do. Use
     on nested / narrow contexts (sidebars, cards, 1/3 columns) where a
     viewport-driven scale would size text as if it spanned the full page.

     Why the tokens are RE-DECLARED (not just --sf-fluid-width flipped): the
     --sf-text-* / --sf-space-* tokens are computed at :root, so their
     var(--sf-fluid-width) is substituted there (100vw) and the *resolved*
     length inherits down — overriding --sf-fluid-width lower in the tree can't
     retroactively rewrite an already-computed inherited value. The scale is
     therefore re-declared in-scope so var(--sf-fluid-width) re-resolves to
     100cqi. It is re-declared on the direct children, not the element itself:
     a query container's own cq units resolve against its ANCESTOR container, so
     the re-computation must happen one level in — children compute against
     .sf-fluid-cq and deeper descendants inherit that resolved value.

     The formulas below are character-identical to their :root twins in
     core/tokens.css (both read var(--sf-fluid-width)); keep the two copies in
     sync if the generative formula ever changes (cf. themes.css SL-001). */
  .sf-fluid-cq { container-type: inline-size; }
  .sf-fluid-cq > * {
      --sf-fluid-width: 100cqi;
      --sf-text-2xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -3) * 1rem)) * var(--sf-text-scale));
      --sf-text-xs: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -2) * 1rem)) * var(--sf-text-scale));
      --sf-text-s: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), -1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), -1) * 1rem)) * var(--sf-text-scale));
      --sf-text-m: calc(clamp(calc(var(--sf-text-base-min) * 1rem), calc((var(--sf-text-base-max) - var(--sf-text-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * 1rem), calc(var(--sf-text-base-max) * 1rem)) * var(--sf-text-scale));
      --sf-text-l: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-scale));
      --sf-text-xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-scale));
      --sf-text-2xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 3) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 3) * 1rem)) * var(--sf-text-scale));
      --sf-text-3xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 4) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 4) * 1rem)) * var(--sf-text-scale));
      --sf-text-4xl: calc(clamp(calc(var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc((var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) - var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-base-min) * pow(var(--sf-text-ratio-min), 5) * 1rem), calc(var(--sf-text-base-max) * pow(var(--sf-text-ratio-max), 5) * 1rem)) * var(--sf-text-scale));
      --sf-text-display-s: calc(clamp(calc(var(--sf-text-display-base-min) * 1rem), calc((var(--sf-text-display-base-max) - var(--sf-text-display-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * 1rem), calc(var(--sf-text-display-base-max) * 1rem)) * var(--sf-text-display-scale));
      --sf-text-display-m: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 1) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 1) * 1rem)) * var(--sf-text-display-scale));
      --sf-text-display-l: calc(clamp(calc(var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc((var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) - var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-text-display-base-min) * pow(var(--sf-text-ratio-min), 2) * 1rem), calc(var(--sf-text-display-base-max) * pow(var(--sf-text-ratio-max), 2) * 1rem)) * var(--sf-text-display-scale));
      --sf-space-2xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -3) * 1rem)) * var(--sf-space-scale));
      --sf-space-xs: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -2) * 1rem)) * var(--sf-space-scale));
      --sf-space-s: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), -1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), -1) * 1rem)) * var(--sf-space-scale));
      --sf-space-m: calc(clamp(calc(var(--sf-space-base-min) * 1rem), calc((var(--sf-space-base-max) - var(--sf-space-base-min)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * 1rem), calc(var(--sf-space-base-max) * 1rem)) * var(--sf-space-scale));
      --sf-space-l: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 1) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 1) * 1rem)) * var(--sf-space-scale));
      --sf-space-xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 2) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 2) * 1rem)) * var(--sf-space-scale));
      --sf-space-2xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 3) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 3) * 1rem)) * var(--sf-space-scale));
      --sf-space-3xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 4) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 4) * 1rem)) * var(--sf-space-scale));
      --sf-space-4xl: calc(clamp(calc(var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc((var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) - var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5)) / (var(--sf-fluid-max-vw) - var(--sf-fluid-min-vw)) * (var(--sf-fluid-width) - var(--sf-fluid-min-vw) * 1rem) + var(--sf-space-base-min) * pow(var(--sf-space-ratio-min), 5) * 1rem), calc(var(--sf-space-base-max) * pow(var(--sf-space-ratio-max), 5) * 1rem)) * var(--sf-space-scale));
  }


  /* Stack & gap */
  .sf-stack {
    display:        flex;
    flex-direction: column;
    gap:            var(--sf-stack-gap);
  }
  .sf-stack--xs  { gap: var(--sf-space-xs); }
  .sf-stack--s   { gap: var(--sf-space-s); }
  .sf-stack--m   { gap: var(--sf-space-m); }
  .sf-stack--l   { gap: var(--sf-space-l); }
  .sf-stack--xl  { gap: var(--sf-space-xl); }
  .sf-stack--2xl { gap: var(--sf-space-2xl); }

  .sf-stack--center  { align-items: center; }
  .sf-stack--end     { align-items: flex-end; }
  .sf-stack--stretch { align-items: stretch; }

  .sf-gap { gap: var(--sf-gap); }
  .sf-gap--xs  { gap: var(--sf-space-xs); }
  .sf-gap--s   { gap: var(--sf-space-s); }
  .sf-gap--m   { gap: var(--sf-space-m); }
  .sf-gap--l   { gap: var(--sf-space-l); }
  .sf-gap--xl  { gap: var(--sf-space-xl); }
  .sf-gap--2xl { gap: var(--sf-space-2xl); }

  
  /* Box */
  .sf-box {
    padding: var(--sf-box-padding);
    outline: var(--sf-box-border-width) solid var(--sf-box-border-color);
  }

  
  /* Center */
  .sf-center {
    box-sizing:      content-box;
    width:           auto;
    margin-inline:   auto;
    max-inline-size: var(--sf-center-max);
    padding-inline:  var(--sf-center-gutter);
  }

  .sf-center--intrinsic {
    display:        flex;
    flex-direction: column;
    align-items:    center;
  }

  /* Place-center — the box-neutral centring primitive. Unlike .sf-center (which
     centres ITSELF as a max-width wrapper) this centres an element's CONTENT on
     both axes, and unlike the flow primitives' --center modifiers it imposes no
     row/column/wrap semantics: a plain element becomes a centring box. It is
     the framework's named form of the community `display:grid; place-items:
     center` idiom (cf. Tailwind's place-items-center). Give the box a size
     (min-block-size / height) for the block-axis centring to have room. */
  .sf-place-center {
    display:     grid;
    place-items: center;
  }


  /* Cluster */
  .sf-cluster {
    display:         flex;
    flex-wrap:       wrap;
    gap:             var(--sf-cluster-gap);
    align-items:     var(--sf-cluster-align);
    justify-content: var(--sf-cluster-justify);
  }
  .sf-cluster--xs      { gap: var(--sf-space-xs); }
  .sf-cluster--s       { gap: var(--sf-space-s); }
  .sf-cluster--m       { gap: var(--sf-space-m); }
  .sf-cluster--l       { gap: var(--sf-space-l); }
  .sf-cluster--xl      { gap: var(--sf-space-xl); }
  .sf-cluster--2xl     { gap: var(--sf-space-2xl); }

  .sf-cluster--no-wrap  { flex-wrap: nowrap; }
  .sf-cluster--center   { justify-content: center; }
  .sf-cluster--end      { justify-content: flex-end; }
  .sf-cluster--between  { justify-content: space-between; }

  
  /* Sidebar */
  .sf-sidebar {
    display:   flex;
    flex-wrap: wrap;
    gap:       var(--sf-sidebar-gap);
  }

  .sf-sidebar > :first-child {
    flex-basis: var(--sf-sidebar-width);
    flex-grow:  1;
  }

  .sf-sidebar > :last-child {
    flex-basis:      0;
    flex-grow:       999;
    min-inline-size: var(--sf-sidebar-min-width);
  }

  .sf-sidebar--right > :first-child {
    flex-basis:      0;
    flex-grow:       999;
    min-inline-size: var(--sf-sidebar-min-width);
  }

  .sf-sidebar--right > :last-child {
    flex-basis: var(--sf-sidebar-width);
    flex-grow:  1;
  }

  .sf-sidebar--narrow { --sf-sidebar-width: 12rem; }
  .sf-sidebar--wide   { --sf-sidebar-width: 26rem; }

  
  /* Switcher */
  .sf-switcher {
    display:   flex;
    flex-wrap: wrap;
    gap:       var(--sf-switcher-gap);
  }

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

  .sf-switcher--no-wrap  { flex-wrap: nowrap; overflow-x: auto; overflow-inline: auto; }
  .sf-switcher--vertical { flex-direction: column; }

  
  /* Grid & icon */
  .sf-grid {
    display:               grid;
    grid-template-columns: repeat(auto-fill, minmax(min(var(--sf-grid-min), 100%), 1fr));
    gap:                   var(--sf-grid-gap);
  }

  .sf-grid--fit {
    grid-template-columns: repeat(auto-fit, minmax(min(var(--sf-grid-min), 100%), 1fr));
  }

  .sf-grid--xs { --sf-grid-min: var(--sf-grid-min-xs); }
  .sf-grid--s  { --sf-grid-min: var(--sf-grid-min-s); }
  .sf-grid--m  { --sf-grid-min: var(--sf-grid-min-m); }
  .sf-grid--l  { --sf-grid-min: var(--sf-grid-min-l); }
  .sf-grid--xl { --sf-grid-min: var(--sf-grid-min-xl); }
  .sf-grid--2xl { --sf-grid-min: var(--sf-grid-min-2xl); }

  .sf-grid--dense { grid-auto-flow: dense; }

  /* Grid-flex — flexbox alternative to .sf-grid for item counts that
     don't divide evenly: leftover last-row items stretch to fill the
     row by default, or stay fixed-width and centered with --center.
     CSS Grid keeps orphans pinned to their track; flex does not. */
  .sf-grid-flex {
    display:   flex;
    flex-wrap: wrap;
    gap:       var(--sf-grid-gap);
  }
  .sf-grid-flex > * {
    flex: 1 1 min(var(--sf-grid-min), 100%);
  }

  .sf-grid-flex--center { justify-content: center; }
  .sf-grid-flex--center > * {
    flex-grow:  0;
    flex-basis: min(var(--sf-grid-min), 100%);
  }

  .sf-grid-flex--xs  { --sf-grid-min: var(--sf-grid-min-xs); }
  .sf-grid-flex--s   { --sf-grid-min: var(--sf-grid-min-s); }
  .sf-grid-flex--m   { --sf-grid-min: var(--sf-grid-min-m); }
  .sf-grid-flex--l   { --sf-grid-min: var(--sf-grid-min-l); }
  .sf-grid-flex--xl  { --sf-grid-min: var(--sf-grid-min-xl); }
  .sf-grid-flex--2xl { --sf-grid-min: var(--sf-grid-min-2xl); }

  .sf-icon {
    display:        inline-block;
    inline-size:    var(--sf-icon-size, var(--sf-icon-m));
    block-size:     var(--sf-icon-size, var(--sf-icon-m));
    flex-shrink:    0;
    vertical-align: text-bottom;
    fill:           currentcolor;
  }
  .sf-icon--xs  { --sf-icon-size: var(--sf-icon-xs); }
  .sf-icon--s   { --sf-icon-size: var(--sf-icon-s); }
  .sf-icon--m   { --sf-icon-size: var(--sf-icon-m); }
  .sf-icon--l   { --sf-icon-size: var(--sf-icon-l); }
  .sf-icon--xl  { --sf-icon-size: var(--sf-icon-xl); }
  .sf-icon--2xl { --sf-icon-size: var(--sf-icon-2xl); }

  .sf-icon--boxed {
    inline-size:    calc(var(--sf-icon-size, var(--sf-icon-m)) + var(--sf-icon-box-pad) * 2);
    block-size:     calc(var(--sf-icon-size, var(--sf-icon-m)) + var(--sf-icon-box-pad) * 2);
    padding:        var(--sf-icon-box-pad);
    border:         var(--sf-icon-box-border);
    border-radius:  var(--sf-icon-box-radius);
    background:     var(--sf-icon-box-bg);
    box-sizing:     border-box;
  }

  
  /* Cover */
  .sf-cover {
    display:        flex;
    flex-direction: column;
    min-height:     var(--sf-cover-min-height);
    padding-block:  var(--sf-cover-padding);
  }

  .sf-cover > .sf-cover__center {
    margin-block: auto;
  }

  .sf-cover--min { min-height: 50dvh; }

  .sf-cover--max { min-height: 0; max-block-size: 100dvh; }
  .sf-cover--padding-s { padding-block: var(--sf-space-xl); }
  .sf-cover--padding-l { padding-block: var(--sf-space-4xl); }

  
  /* Frame */
  .sf-frame {
    aspect-ratio:    var(--sf-frame-ratio);
    overflow:        hidden;
    display:         flex;
    justify-content: center;
    align-items:     center;
  }

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

  .sf-frame--square   { aspect-ratio: var(--sf-ratio-square); }
  .sf-frame--video    { aspect-ratio: var(--sf-ratio-video); }
  .sf-frame--cinema   { aspect-ratio: var(--sf-ratio-cinema); }
  .sf-frame--portrait { aspect-ratio: var(--sf-ratio-portrait); }
  .sf-frame--4-3      { aspect-ratio: var(--sf-ratio-4-3); }
  .sf-frame--3-2      { aspect-ratio: var(--sf-ratio-3-2); }
  .sf-frame--golden   { aspect-ratio: var(--sf-ratio-golden); }


  /* Background layer — absolutely-positioned cover media that sits behind a
     parent's content. The parent is auto-promoted to a positioned, isolated
     stacking context via :has(), so .sf-bg-layer composes natively under .sf-scrim
     (background → scrim gradient → content). Works as a bare <img class="sf-bg-layer">
     or as a wrapper with a nested > img / > video. */
  :where(:has(> .sf-bg-layer)) {
    position:  relative;
    isolation: isolate;
  }

  .sf-bg-layer {
    position:        absolute;
    inset:           var(--sf-bg-layer-inset);
    inline-size:     calc(100% - 2 * var(--sf-bg-layer-inset));
    block-size:      calc(100% - 2 * var(--sf-bg-layer-inset));
    object-fit:      var(--sf-bg-layer-fit);
    object-position: var(--sf-bg-layer-position);
    border-radius:   var(--sf-bg-layer-radius);
    z-index:         var(--sf-bg-layer-z);
    pointer-events:  none;
  }

  .sf-bg-layer > :is(img, video, picture) {
    inline-size:     100%;
    block-size:      100%;
    object-fit:      var(--sf-bg-layer-fit);
    object-position: var(--sf-bg-layer-position);
    border-radius:   var(--sf-bg-layer-radius);
    pointer-events:  none;
  }

  .sf-bg-layer > picture > img {
    inline-size:     100%;
    block-size:      100%;
    object-fit:      var(--sf-bg-layer-fit);
    object-position: var(--sf-bg-layer-position);
    border-radius:   var(--sf-bg-layer-radius);
    pointer-events:  none;
  }


  .sf-reel {
    display:               flex;
    block-size:            var(--sf-reel-height);
    gap:                   var(--sf-reel-gap);
    overflow-x:                 auto;
    overflow-inline:            auto;
    scroll-snap-type:           inline mandatory;
    scroll-padding-inline:      var(--sf-reel-gap);
    overscroll-behavior-inline: contain;
    scrollbar-width:       thin;
    scrollbar-color:       var(--sf-scrollbar-thumb) var(--sf-scrollbar-track);
  }

  .sf-reel::-webkit-scrollbar        { block-size: 6px; }
  .sf-reel::-webkit-scrollbar-track  { background: var(--sf-scrollbar-track); border-radius: var(--sf-radius-full); }
  .sf-reel::-webkit-scrollbar-thumb  { background: var(--sf-scrollbar-thumb); border-radius: var(--sf-radius-full); }

  .sf-reel > * {
    flex:              0 0 var(--sf-reel-item-width);
    scroll-snap-align: start;
  }

  
  /* Physical left (not inset-inline-start): translate() uses the physical axis,
     so logical + translate breaks centering in RTL layouts. */
  .sf-imposter {
    position:          absolute;
    inset-block-start: 50%;
    left:              50%;
    translate:         -50% -50%;
  }

  .sf-imposter--fixed {
    position: fixed;
  }

  .sf-imposter--contain {
    max-inline-size: calc(100% - var(--sf-imposter-margin) * 2);
    max-block-size:  calc(100% - var(--sf-imposter-margin) * 2);
    overflow:        auto;
  }

  
  .sf-alternate {
    display:   grid;
    gap:       var(--sf-alternate-gap);
    container: sf-alternate / inline-size;
  }

  .sf-alternate > * {
    display:     grid;
    gap:         var(--sf-alternate-inner-gap);
    align-items: center;
  }

  @container sf-alternate (min-width: 48rem) {
    .sf-alternate > * {
      grid-template-columns: 1fr 1fr;
    }
    .sf-alternate > :nth-child(even) > :first-child { order: 2; }
    .sf-alternate > :nth-child(even) > :last-child  { order: 1; }
  }

  
  .sf-pancake {
    display:             grid;
    grid-template-rows:  auto 1fr auto;
    min-height:          100dvh;
  }

  
  .sf-grid-cols-1 {
    display: grid;
    gap:     var(--sf-grid-gap);
  }

  
  .sf-grid-cols-2, .sf-grid-cols-3, .sf-grid-cols-4, .sf-grid-cols-6 {
    display: grid;
    gap:     var(--sf-grid-gap);
  }

  @container (min-width: 30rem) {
    .sf-grid-cols-4 { grid-template-columns: repeat(2, 1fr); }
    .sf-grid-cols-6 { grid-template-columns: repeat(3, 1fr); }
  }

  @container (min-width: 48rem) {
    .sf-grid-cols-2 { grid-template-columns: repeat(2, 1fr); }
    .sf-grid-cols-3 { grid-template-columns: repeat(3, 1fr); }
    .sf-grid-cols-4 { grid-template-columns: repeat(4, 1fr); }
    .sf-grid-cols-6 { grid-template-columns: repeat(6, 1fr); }
  }

  
  .sf-grid-cols-1-2, .sf-grid-cols-2-1,
  .sf-grid-cols-1-3, .sf-grid-cols-3-1 {
    display: grid;
    gap:     var(--sf-grid-gap);
  }

  @container (min-width: 48rem) {
    .sf-grid-cols-1-2 { grid-template-columns: 1fr 2fr; }
    .sf-grid-cols-2-1 { grid-template-columns: 2fr 1fr; }
    .sf-grid-cols-1-3 { grid-template-columns: 1fr 3fr; }
    .sf-grid-cols-3-1 { grid-template-columns: 3fr 1fr; }
  }

  .sf-equal {
    column-width: var(--sf-equal-min-col);
    column-gap:   var(--sf-equal-gap);
    column-rule:  var(--sf-equal-rule-width) var(--sf-equal-rule-style) var(--sf-equal-rule-color);
  }
  .sf-equal > * { break-inside: avoid; }

  .sf-equal--2 { column-count: 2; }
  .sf-equal--3 { column-count: 3; }
  .sf-equal--4 { column-count: 4; }
  .sf-equal--6 { column-count: 6; }

  
  .sf-content-grid {
    display: grid;
    /* Establish the same NAMED inline-size query container as .sf-container
       (`sf-layout`), not just an anonymous one. .sf-content-grid is a
       section-level wrapper that REPLACES .sf-container when you need
       breakout/full-bleed — but .sf-container carries the CQ scope that
       .sf-grid-cols-* / .sf-bento rely on, and dropping it silently killed
       those primitives inside a content grid. Matching the name too means a
       user's `@container sf-layout (…)` rule keeps matching across the swap, so
       the two wrappers are genuinely interchangeable (anonymous
       `@container (…)` queries already matched either — the framework's own
       primitives use those — but a name-targeted query would not have).
       Safe re SL-034: .sf-content-grid's own tracks are fixed (they never
       @container-query themselves), so becoming a query container can't create
       a self-query. Safe re full-bleed: inline-size containment doesn't change
       track resolution — the `full` track still reaches the wrapper's edges. */
    container: sf-layout / inline-size;
    grid-template-columns:
      [full-start]
      minmax(var(--sf-gutter), 1fr)
      [breakout-start]
      minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2))
      [content-start]
      min(var(--sf-content-width), 100% - var(--sf-gutter) * 2)
      [content-end]
      minmax(0, calc((var(--sf-breakout-width) - var(--sf-content-width)) / 2))
      [breakout-end]
      minmax(var(--sf-gutter), 1fr)
      [full-end];
  }

  .sf-content-grid > *              { grid-column: content; }
  .sf-content-grid > .sf-breakout   { grid-column: breakout; }
  .sf-content-grid > .sf-full-bleed { grid-column: full; }

  .sf-bento {
    display:               grid;
    grid-template-columns: repeat(var(--sf-bento-cols, var(--sf-bento-cols-default)), 1fr);
    grid-auto-rows:        minmax(var(--sf-bento-row, var(--sf-bento-row-default)), auto);
    grid-auto-flow:        dense;
    gap:                   var(--sf-bento-gap);
  }

  @container (max-width: 29.99rem) {
    .sf-bento { grid-template-columns: 1fr; }
  }

  @container (min-width: 30rem) and (max-width: 47.99rem) {
    .sf-bento { grid-template-columns: repeat(2, 1fr); }
  }

  /* Container column modifiers */
  .sf-bento--2       { --sf-bento-cols: 2; }
  .sf-bento--3       { --sf-bento-cols: 3; }
  .sf-bento--6       { --sf-bento-cols: 6; }

  /* Container row height modifiers — named after the --sf-bento-row-* token
     they set, not just "tall"/"compact", so they can't be mistaken for the
     child span modifier below. */
  .sf-bento--row-compact { --sf-bento-row: var(--sf-bento-row-compact); }
  .sf-bento--row-tall    { --sf-bento-row: var(--sf-bento-row-tall); }

  /* Child span modifiers — go on an item inside .sf-bento, never on
     .sf-bento itself. .sf-bento-tall (this item spans 2 rows) is not an
     alias of .sf-bento--row-tall above (every row in the grid is taller). */
  .sf-bento-wide     { grid-column: span 2; }
  .sf-bento-full     { grid-column: 1 / -1; }
  .sf-bento-tall     { grid-row:    span 2; }
  .sf-bento-featured { grid-column: span 2; grid-row: span 2; }

  /* A spanning child can't request more columns than the 1-column mobile
     grid has, or CSS Grid adds an implicit column to satisfy the span,
     breaking the single-column layout the query above exists to guarantee.
     Placed after the modifiers above (equal specificity) so it wins on
     source order regardless of query-match state. */
  @container (max-width: 29.99rem) {
    .sf-bento-wide, .sf-bento-featured { grid-column: span 1; }
  }

  
  .sf-subgrid      { display: grid; grid-template-columns: subgrid; }
  .sf-subgrid-rows { display: grid; grid-template-rows:    subgrid; }

}
