/**
 * CSS foundation — the design-system substrate for every surface.
 *
 * Four CubeCSS layers in one file, in cascade order:
 *   1. Tokens      :root custom properties (Utopia fluid type/space
 *                    scales + color-independent structural tokens).
 *   2. Composition Every Layout primitives — spatial relationships
 *                    between siblings only, no appearance.
 *   3. Elements    minimal element baseline: reset-lite, focus ring,
 *                    vertical rhythm. Replaces UA defaults only.
 *   4. Utilities   deliberately thin one-off helpers.
 *
 * Layer rules (docs/frontend-standards.md): composition classes set
 * spacing, never colors/borders; appearance lives in surface
 * stylesheets; utilities are one-off overrides only.
 *
 * Loaded before surface stylesheets in every layout so surface rules
 * always win ties. The fluid clamp() scales are GENERATED by
 * tooling/gen_css_scale.mjs — re-run it when a Utopia config changes
 * and paste the output back; each fluid token carries a static
 * midpoint fallback first so engines without clamp() keep a legible
 * middle size.
 *
 * Color tokens are NOT defined here: published surfaces get them from
 * Themes::Css emission, operator surfaces from the mermaid layer
 * (plan-mermaid-surfaces). Foundation owns only names like
 * --color-text-muted as a contract — consumers must always pass a
 * fallback: var(--color-muted, #555).
 *
 * Structural theme names (--measure, --gutter, --space-block,
 * --line-height) get fallback defaults here matching the historical
 * published.css literals; Themes::Css emission overrides them on
 * published pages.
 */

/* ==================================================================
   Tokens
   ================================================================== */

:root {
  /* ---- public scale — generated by tooling/gen_css_scale.mjs
     Each fluid token ships a static midpoint fallback first so
     engines without clamp() keep a legible middle size. */
  --step--2: 0.7072rem;
  --step--2: clamp(0.6944rem, 0.6875rem + 0.0347vw, 0.72rem);
  --step--1: 0.8667rem;
  --step--1: clamp(0.8333rem, 0.8153rem + 0.0904vw, 0.9rem);
  --step-0: 1.0625rem;
  --step-0: clamp(1rem, 0.9661rem + 0.1695vw, 1.125rem);
  --step-1: 1.3031rem;
  --step-1: clamp(1.2rem, 1.1441rem + 0.2797vw, 1.4063rem);
  --step-2: 1.5989rem;
  --step-2: clamp(1.44rem, 1.3538rem + 0.4309vw, 1.7578rem);
  --step-3: 1.9626rem;
  --step-3: clamp(1.728rem, 1.6007rem + 0.6363vw, 2.1973rem);
  --step-4: 2.4101rem;
  --step-4: clamp(2.0736rem, 1.8911rem + 0.9125vw, 2.7466rem);
  --step-5: 2.9608rem;
  --step-5: clamp(2.4883rem, 2.2321rem + 1.2812vw, 3.4332rem);
  --step-6: 3.6388rem;
  --step-6: clamp(2.986rem, 2.6319rem + 1.7702vw, 4.2915rem);

  /* --space-unit is fluid; --space-unit-N multiplies it, so the
     whole spacing scale tracks the viewport with the type. */
  --space-unit: 0.1328rem;
  --space-unit: clamp(0.125rem, 0.1208rem + 0.0212vw, 0.1406rem);
  --space-unit-1: calc(var(--space-unit) * 1);
  --space-unit-2: calc(var(--space-unit) * 2);
  --space-unit-3: calc(var(--space-unit) * 3);
  --space-unit-4: calc(var(--space-unit) * 4);
  --space-unit-5: calc(var(--space-unit) * 5);
  --space-unit-6: calc(var(--space-unit) * 6);
  --space-unit-8: calc(var(--space-unit) * 8);
  --space-unit-10: calc(var(--space-unit) * 10);
  --space-unit-12: calc(var(--space-unit) * 12);
  --space-unit-16: calc(var(--space-unit) * 16);
  --space-unit-20: calc(var(--space-unit) * 20);
  --space-unit-24: calc(var(--space-unit) * 24);
  --space-unit-32: calc(var(--space-unit) * 32);

  /* ---- Structural tokens (color-independent) ----------------------- */
  --radius-sm: 0.25rem;
  --radius-md: 0.375rem;
  --radius-lg: 0.5rem;
  --radius-xl: 0.75rem;
  --radius-pill: 999px;

  --border-thin: 1px;
  --border-thick: 2px;

  --z-base: 1;
  --z-sticky: 100;
  --z-imposter: 200;
  --z-overlay: 1000;

  /* Theme-emitted structural names — defaults match the historical
     published.css literals so unthemed pages render identically;
     Themes::Css overrides them per channel. */
  --measure: 44rem;
  --gutter: var(--space-unit-12);
  --space-block: var(--space-unit-16);
  --line-height: 1.6;

  /* ---- Composition defaults (overridable per-use) ------------------- */
  --stack-gap: var(--space-unit-6);
  --cluster-gap: var(--space-unit-4);
  --grid-gap: var(--space-unit-8);
  --grid-min-column-width: 16rem;
  --sidebar-gap: var(--space-unit-8);
  --sidebar-min: 13rem;
  --switcher-gap: var(--space-unit-6);
  --switcher-threshold: 30rem;
  --reel-gap: var(--space-unit-4);
  --cover-gap: var(--space-unit-6);
  --cover-min-height: 100vh;
  --frame-ratio: 16 / 9;

  /* ---- Fonts -------------------------------------------------------- */
  --font-sans:
    -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-mono:
    ui-monospace, "SF Mono", "Cascadia Mono", "Roboto Mono", Menlo,
    Consolas, monospace;
}

/* Studio scale — compact operator-tool config: narrower viewport
   range, 15px base, tighter ratios, 2px spacing unit (so 4px =
   --space-unit-2, 12px = --space-unit-6, ...). Same mechanism as
   felt's separate admin scale: reader surface and operator tool are
   meant to diverge. */
body.studio {
  /* ---- studio scale — generated by tooling/gen_css_scale.mjs
     Each fluid token ships a static midpoint fallback first so
     engines without clamp() keep a legible middle size. */
  --step--2: 0.7207rem;
  --step--2: clamp(0.7089rem, 0.6853rem + 0.0471vw, 0.7324rem);
  --step--1: 0.8471rem;
  --step--1: clamp(0.8152rem, 0.7515rem + 0.1274vw, 0.8789rem);
  --step-0: 0.9961rem;
  --step-0: clamp(0.9375rem, 0.8203rem + 0.2344vw, 1.0547rem);
  --step-1: 1.1719rem;
  --step-1: clamp(1.0781rem, 0.8906rem + 0.375vw, 1.2656rem);
  --step-2: 1.3793rem;
  --step-2: clamp(1.2398rem, 0.9609rem + 0.5578vw, 1.5188rem);
  --step-3: 1.6242rem;
  --step-3: clamp(1.4258rem, 1.0291rem + 0.7934vw, 1.8225rem);
  --step-4: 1.9133rem;
  --step-4: clamp(1.6397rem, 1.0924rem + 1.0946vw, 2.187rem);
  --step-5: 2.255rem;
  --step-5: clamp(1.8856rem, 1.1469rem + 1.4775vw, 2.6244rem);
  --step-6: 2.6589rem;
  --step-6: clamp(2.1685rem, 1.1877rem + 1.9616vw, 3.1493rem);

  /* --space-unit is fluid; --space-unit-N multiplies it, so the
     whole spacing scale tracks the viewport with the type. */
  --space-unit: 0.1328rem;
  --space-unit: clamp(0.125rem, 0.1094rem + 0.0313vw, 0.1406rem);
  --space-unit-1: calc(var(--space-unit) * 1);
  --space-unit-2: calc(var(--space-unit) * 2);
  --space-unit-3: calc(var(--space-unit) * 3);
  --space-unit-4: calc(var(--space-unit) * 4);
  --space-unit-5: calc(var(--space-unit) * 5);
  --space-unit-6: calc(var(--space-unit) * 6);
  --space-unit-8: calc(var(--space-unit) * 8);
  --space-unit-10: calc(var(--space-unit) * 10);
  --space-unit-12: calc(var(--space-unit) * 12);
  --space-unit-16: calc(var(--space-unit) * 16);
  --space-unit-20: calc(var(--space-unit) * 20);
  --space-unit-24: calc(var(--space-unit) * 24);
  --space-unit-32: calc(var(--space-unit) * 32);
}

/* ==================================================================
   Composition — Every Layout primitives
   Spatial relationships only: no color, border, or font rules here.
   Each gap is a custom property with a token default, overridable
   per-use: <div class="stack" style="--stack-gap: var(--space-unit-12)">
   (per-use var overrides are the allowed inline-style exception).
   ================================================================== */

/* Stack — vertical rhythm. Adjacent siblings separated by a gap. */
.stack {
  display: flex;
  flex-direction: column;
  gap: var(--stack-gap);
}

/* Cluster — horizontal wrap. Items group in a row that wraps. */
.cluster {
  display: flex;
  flex-wrap: wrap;
  gap: var(--cluster-gap);
}

/* Grid — responsive auto-fill columns, no media queries. Columns
   collapse on narrow viewports via min(100%, min-width). A fixed
   column count can be forced with --grid-columns. */
.grid {
  display: grid;
  grid-template-columns: var(
    --grid-columns,
    repeat(auto-fill, minmax(min(100%, var(--grid-min-column-width)), 1fr))
  );
  gap: var(--grid-gap);
}

/* Sidebar — fixed-min side plus fluid main. First child is the
   sidebar (min --sidebar-min), .sidebar__main grows to fill; wraps
   to stacked when space runs out. */
.sidebar {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sidebar-gap);
}
.sidebar > * {
  flex-basis: var(--sidebar-min);
  flex-grow: 1;
}
.sidebar > .sidebar__main {
  flex-basis: 0;
  flex-grow: 999;
  min-width: 0;
}

/* Switcher — row-to-column flip without a media query: children sit
   side by side until the container is narrower than
   --switcher-threshold, then stack at equal width. */
.switcher {
  display: flex;
  flex-wrap: wrap;
  gap: var(--switcher-gap);
}
.switcher > * {
  flex-grow: 1;
  flex-basis: calc((var(--switcher-threshold) - 100%) * 999);
}

/* Cover — min-height container with header/main/footer regions;
   .cover__main is pushed to the vertical center. */
.cover {
  display: flex;
  flex-direction: column;
  gap: var(--cover-gap);
  min-height: var(--cover-min-height);
  padding: var(--space-unit-8);
}
.cover > .cover__main {
  margin-block: auto;
}

/* Frame — fixed-ratio media container. */
.frame {
  aspect-ratio: var(--frame-ratio);
  overflow: hidden;
}
.frame > img,
.frame > video {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

/* Reel — horizontal scroll-snap row. */
.reel {
  display: flex;
  gap: var(--reel-gap);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-block: var(--space-unit-2);
}
.reel > * {
  scroll-snap-align: start;
  flex: 0 0 auto;
}

/* Imposter — overlay positioned over a positioned parent (or the
   viewport with .imposter--fixed). */
.imposter {
  position: absolute;
  inset: 0;
}
.imposter--fixed {
  position: fixed;
}

/* Center — intrinsic horizontal centering with a max-width and
   symmetric gutter. */
.center {
  box-sizing: content-box;
  max-width: var(--measure);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Icon — inline icon + label alignment. */
.icon {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-unit-2);
}
.icon > svg {
  flex: none;
  align-self: center;
}

/* ==================================================================
   Elements — minimal baseline. Replaces UA defaults only; authored
   appearance lives in surface stylesheets.
   ================================================================== */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  margin: 0;
  font-size: var(--step-0);
}

/* Vertical rhythm comes from composition gaps, never UA margins. */
h1,
h2,
h3,
h4,
h5,
h6,
p,
ul,
ol,
dl,
blockquote,
figure,
fieldset,
legend {
  margin: 0;
}
fieldset {
  padding: 0;
  border: 0;
}
legend {
  padding: 0;
}

img,
video {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Media features are honored at the token/element layer: reduced
   motion drops scroll-behavior smoothness here, not per component. */
@media (prefers-reduced-motion: no-preference) {
  html {
    scroll-behavior: smooth;
  }
}
@media (prefers-reduced-motion: reduce) {
  .reel {
    scroll-snap-type: none;
  }
}

/* Focus: a consistent visible ring for keyboard users on every
   surface. Surfaces may restyle :focus-visible but never remove it. */
:focus-visible {
  outline: var(--border-thick) solid var(--color-focus, currentColor);
  outline-offset: 2px;
}

/* Form controls inherit type; buttons keep pointer affordance. */
input,
button,
select,
textarea {
  font: inherit;
}
button,
[type="submit"],
select,
summary {
  cursor: pointer;
}
[disabled],
[aria-disabled="true"] {
  cursor: not-allowed;
}

/* ==================================================================
   Utilities — deliberately thin. One-off overrides only; not a
   utility framework. Composition gap overrides ride the gap custom
   properties so no inline style is needed.
   ================================================================== */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.measure {
  max-width: var(--measure);
}
.measure-sm {
  max-width: 25rem;
}
.measure-md {
  max-width: 50rem;
}
.measure-lg {
  max-width: 75rem;
}

.mx-auto {
  margin-inline: auto;
}

.text-start {
  text-align: left;
}
.text-center {
  text-align: center;
}
.text-end {
  text-align: right;
}

.text-sm {
  font-size: var(--step--1);
}
.text-xs {
  font-size: var(--step--2);
}

.weight-normal {
  font-weight: 400;
}
.weight-medium {
  font-weight: 500;
}
.weight-semibold {
  font-weight: 600;
}
.weight-bold {
  font-weight: 700;
}

.mono {
  font-family: var(--font-mono);
}

.truncate {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.pre-wrap {
  white-space: pre-wrap;
}

.min-w-0 {
  min-width: 0;
}

.list-reset {
  list-style: none;
  padding: 0;
  margin: 0;
}

/* Gap retunes for .stack/.cluster/.switcher without an inline style:
   class="stack gap-4". */
.gap-2 {
  --stack-gap: var(--space-unit-2);
  --cluster-gap: var(--space-unit-2);
  --switcher-gap: var(--space-unit-2);
}
.gap-3 {
  --stack-gap: var(--space-unit-3);
  --cluster-gap: var(--space-unit-3);
  --switcher-gap: var(--space-unit-3);
}
.gap-4 {
  --stack-gap: var(--space-unit-4);
  --cluster-gap: var(--space-unit-4);
  --switcher-gap: var(--space-unit-4);
}
.gap-6 {
  --stack-gap: var(--space-unit-6);
  --cluster-gap: var(--space-unit-6);
  --switcher-gap: var(--space-unit-6);
}
.gap-8 {
  --stack-gap: var(--space-unit-8);
  --cluster-gap: var(--space-unit-8);
  --switcher-gap: var(--space-unit-8);
}
