/*! mica — custom elements, native behavior, nearly no JavaScript. */

/* Layer order. User's unlayered CSS always wins over all of it. */
@layer mica.tokens, mica.preset, mica.elements, mica.layout;

/* ------------------------------------------------------------------ *
 * Tokens — mica's only opinion. Spacing and size scales.
 * ------------------------------------------------------------------ */
@layer mica.tokens {
  :root {
    --space-2xs: 0.25rem;
    --space-xs: 0.5rem;
    --space-sm: 0.75rem;
    --space-md: 1rem;
    --space-lg: 1.5rem;
    --space-xl: 2.5rem;
    --space-2xl: 4rem;

    --size-xs: 10rem;
    --size-sm: 15rem;
    --size-md: 20rem;
    --size-lg: 30rem;
    --size-xl: 40rem;

    --measure: 60ch;

    --font-body: system-ui, sans-serif;
    --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --line-height: 1.5;

    /* square is the design language; rounding back on is a theme:
       :root { --radius-sm: .25rem; --radius-md: .375rem; --radius-lg: .75rem } */
    --radius-sm: 0px;
    --radius-md: 0px;
    --radius-lg: 0px;
    --radius-full: 9999px;

    /* control heights, shadcn scale: sm 32 / md 36 / lg 40 */
    --control-height-sm: 2rem;
    --control-height: 2.25rem;
    --control-height-lg: 2.5rem;

    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;
    --focus-ring-color: var(--color-accent);

    /* checkmark glyph — SVG URIs can't read custom properties, so this
       ships as a light-dark pair tracking on-primary (white / near-black) */
    --check-glyph: light-dark(
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23fff' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E"),
      url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23151922' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' d='M3.5 8.5l3 3 6-7'/%3E%3C/svg%3E"));

    /* -------------------------------------------------------------- *
     * Color. Two knobs — change the theme by changing the knobs:
     *   --hue: the accent hue (OKLCH degrees)
     *   --chroma: accent intensity
     * Neutrals are faintly tinted toward the accent hue.
     * Components only ever use semantic roles, never raw values.
     * -------------------------------------------------------------- */
    color-scheme: light dark;

    --hue: 263;
    --chroma: 0.21;
    --neutral-chroma: 0;

    /* status hues — knobs, same as the brand hue. statuses deliberately
       do NOT ride --chroma: danger must stay urgent in a muted theme. */
    --danger-hue: 25;
    --success-hue: 150;
    --warn-hue: 48; /* orange — amber reads as mud at solid lightness */
    --status-chroma: 0.18;

    /* Numbered scales — theme-relative (Radix convention): a step means
       the same *thing* in both modes. 1 = app bg … 6–8 = borders …
       9 = solid … 12 = high-contrast text. light-dark() is baked into
       every step, so code written against steps gets dark mode free. */
    --neutral-1:  light-dark(oklch(100%  var(--neutral-chroma) var(--hue)), oklch(14% var(--neutral-chroma) var(--hue)));
    --neutral-2:  light-dark(oklch(97.3% var(--neutral-chroma) var(--hue)), oklch(17% var(--neutral-chroma) var(--hue)));
    --neutral-3:  light-dark(oklch(95.2% var(--neutral-chroma) var(--hue)), oklch(20% var(--neutral-chroma) var(--hue)));
    --neutral-4:  light-dark(oklch(93%   var(--neutral-chroma) var(--hue)), oklch(23% var(--neutral-chroma) var(--hue)));
    --neutral-5:  light-dark(oklch(91%   var(--neutral-chroma) var(--hue)), oklch(26% var(--neutral-chroma) var(--hue)));
    --neutral-6:  light-dark(oklch(89%   var(--neutral-chroma) var(--hue)), oklch(30% var(--neutral-chroma) var(--hue)));
    --neutral-7:  light-dark(oklch(82%   var(--neutral-chroma) var(--hue)), oklch(37% var(--neutral-chroma) var(--hue)));
    --neutral-8:  light-dark(oklch(74%   var(--neutral-chroma) var(--hue)), oklch(46% var(--neutral-chroma) var(--hue)));
    --neutral-9:  light-dark(oklch(55%   var(--neutral-chroma) var(--hue)), oklch(58% var(--neutral-chroma) var(--hue)));
    --neutral-10: light-dark(oklch(50%   var(--neutral-chroma) var(--hue)), oklch(64% var(--neutral-chroma) var(--hue)));
    --neutral-11: light-dark(oklch(44%   var(--neutral-chroma) var(--hue)), oklch(71% var(--neutral-chroma) var(--hue)));
    --neutral-12: light-dark(oklch(18%   var(--neutral-chroma) var(--hue)), oklch(96% var(--neutral-chroma) var(--hue)));

    /* accent scale: chroma tapers at the extremes, peaks at the solid */
    --accent-1:  light-dark(oklch(99%   calc(var(--chroma) * 0.1) var(--hue)), oklch(19% calc(var(--chroma) * 0.15) var(--hue)));
    --accent-2:  light-dark(oklch(97.5% calc(var(--chroma) * 0.15) var(--hue)), oklch(23% calc(var(--chroma) * 0.2) var(--hue)));
    --accent-3:  light-dark(oklch(95%   calc(var(--chroma) * 0.25) var(--hue)), oklch(27% calc(var(--chroma) * 0.35) var(--hue)));
    --accent-4:  light-dark(oklch(92%   calc(var(--chroma) * 0.35) var(--hue)), oklch(31% calc(var(--chroma) * 0.5) var(--hue)));
    --accent-5:  light-dark(oklch(89%   calc(var(--chroma) * 0.45) var(--hue)), oklch(35% calc(var(--chroma) * 0.6) var(--hue)));
    --accent-6:  light-dark(oklch(85%   calc(var(--chroma) * 0.55) var(--hue)), oklch(39% calc(var(--chroma) * 0.7) var(--hue)));
    --accent-7:  light-dark(oklch(79%   calc(var(--chroma) * 0.65) var(--hue)), oklch(46% calc(var(--chroma) * 0.8) var(--hue)));
    --accent-8:  light-dark(oklch(71%   calc(var(--chroma) * 0.8) var(--hue)), oklch(58% calc(var(--chroma) * 0.9) var(--hue)));
    --accent-9:  light-dark(oklch(55%   var(--chroma) var(--hue)), oklch(70% var(--chroma) var(--hue)));
    --accent-10: light-dark(oklch(50%   var(--chroma) var(--hue)), oklch(75% var(--chroma) var(--hue)));
    --accent-11: light-dark(oklch(46%   calc(var(--chroma) * 0.9) var(--hue)), oklch(80% calc(var(--chroma) * 0.9) var(--hue)));
    --accent-12: light-dark(oklch(24%   calc(var(--chroma) * 0.5) var(--hue)), oklch(94% calc(var(--chroma) * 0.3) var(--hue)));

    /* Semantic roles — what components actually use. Defined in terms
       of scale steps: knobs → scales → roles. */
    --color-surface: var(--neutral-1);
    --color-surface-raised: var(--neutral-2);
    /* top-layer panels (dialog, menus, toasts): white in light like the
       page; one step elevated in dark, where shadows can't carry lift */
    --color-surface-overlay: light-dark(var(--neutral-1), var(--neutral-2));
    --color-text: var(--neutral-12);
    --color-text-muted: var(--neutral-11);
    --color-border: var(--neutral-6);
    --color-border-strong: var(--neutral-8);
    --color-accent: var(--accent-9);
    --color-on-accent: light-dark(
      oklch(99% 0.01 var(--hue)),
      oklch(18% 0.02 var(--hue)));

    /* Primary — the action color, decoupled from accent (shadcn-school:
       near-black light, near-white dark; the accent appears only where
       attention is earned: focus, selection, checkmarks). Hover/active
       are derived, so ANY value assigned to --color-primary gets correct
       states free. Colorful primary is a two-line theme:
       :root { --color-primary: var(--accent-9);
               --color-on-primary: var(--color-on-accent); } */
    --color-primary: var(--neutral-12);
    --color-on-primary: var(--neutral-1);
    --color-primary-hover: color-mix(in oklch, var(--color-primary) 90%, var(--color-surface));
    --color-primary-active: color-mix(in oklch, var(--color-primary) 80%, var(--color-surface));

    /* Status roles — the step-3/7/9/11 analogs, no full scales.
       Off-role shades: raw oklch(L var(--status-chroma) var(--*-hue)). */
    --color-danger-surface: light-dark(oklch(95% calc(var(--status-chroma) * 0.25) var(--danger-hue)), oklch(27% calc(var(--status-chroma) * 0.35) var(--danger-hue)));
    --color-danger-border:  light-dark(oklch(79% calc(var(--status-chroma) * 0.65) var(--danger-hue)), oklch(46% calc(var(--status-chroma) * 0.8) var(--danger-hue)));
    --color-danger:         light-dark(oklch(52% var(--status-chroma) var(--danger-hue)), oklch(70% var(--status-chroma) var(--danger-hue)));
    --color-on-danger:      light-dark(oklch(99% 0.01 var(--danger-hue)), oklch(18% 0.02 var(--danger-hue)));
    --color-danger-text:    light-dark(oklch(44% calc(var(--status-chroma) * 0.9) var(--danger-hue)), oklch(80% calc(var(--status-chroma) * 0.9) var(--danger-hue)));

    --color-success-surface: light-dark(oklch(95% calc(var(--status-chroma) * 0.25) var(--success-hue)), oklch(27% calc(var(--status-chroma) * 0.35) var(--success-hue)));
    --color-success-border:  light-dark(oklch(79% calc(var(--status-chroma) * 0.65) var(--success-hue)), oklch(46% calc(var(--status-chroma) * 0.8) var(--success-hue)));
    --color-success:         light-dark(oklch(52% var(--status-chroma) var(--success-hue)), oklch(70% var(--status-chroma) var(--success-hue)));
    --color-on-success:      light-dark(oklch(99% 0.01 var(--success-hue)), oklch(18% 0.02 var(--success-hue)));
    --color-success-text:    light-dark(oklch(44% calc(var(--status-chroma) * 0.9) var(--success-hue)), oklch(80% calc(var(--status-chroma) * 0.9) var(--success-hue)));

    /* warn solid runs lighter than its siblings — amber needs the
       lightness to read as warning, and takes dark text in both modes */
    --color-warn-surface: light-dark(oklch(95% calc(var(--status-chroma) * 0.25) var(--warn-hue)), oklch(27% calc(var(--status-chroma) * 0.35) var(--warn-hue)));
    --color-warn-border:  light-dark(oklch(79% calc(var(--status-chroma) * 0.65) var(--warn-hue)), oklch(46% calc(var(--status-chroma) * 0.8) var(--warn-hue)));
    --color-warn:         light-dark(oklch(78% var(--status-chroma) var(--warn-hue)), oklch(76% var(--status-chroma) var(--warn-hue)));
    --color-on-warn:      oklch(20% 0.03 var(--warn-hue));
    --color-warn-text:    light-dark(oklch(42% calc(var(--status-chroma) * 0.9) var(--warn-hue)), oklch(80% calc(var(--status-chroma) * 0.9) var(--warn-hue)));
  }
}

/* ------------------------------------------------------------------ *
 * Preset — constructive defaults, Kelp-school not Preflight-school:
 * raw HTML should look finished, not like nothing. Zero-specificity
 * (:where) inside a layer: doubly overridable.
 * ------------------------------------------------------------------ */
@layer mica.preset {
  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  html {
    -webkit-text-size-adjust: none;
    text-size-adjust: none;
  }

  :where(body) {
    margin: 0;
    min-block-size: 100svh;
    font-family: var(--font-body);
    line-height: var(--line-height);
    background: var(--color-surface);
    color: var(--color-text);
    accent-color: var(--color-accent);
  }

  /* Vertical rhythm: flow content spaces itself; last child never
     pushes against its container. Stacks override all of this with gap. */
  :where(p, ol, ul, dl, dd, blockquote, pre, table, figure, fieldset,
         details, address, audio, video, iframe) {
    margin-block: 0 var(--flow-space, var(--space-md));
  }
  :where(p, ol, ul, dl, dd, blockquote, pre, table, figure, fieldset,
         details, address, audio, video, iframe):last-child {
    margin-block-end: 0;
  }

  :where(h1, h2, h3, h4, h5, h6) {
    margin-block: 0 var(--space-sm);
    line-height: 1.2;
    text-wrap: balance;
  }
  /* Headings that follow content get breathing room above. */
  :where(h2, h3, h4, h5, h6):where(:not(:first-child)) {
    margin-block-start: var(--space-xl);
  }

  :where(p) {
    text-wrap: pretty;
  }

  /* Media behaves like content, not like text. */
  :where(img, svg, video, canvas, picture) {
    display: block;
    max-inline-size: 100%;
    block-size: auto;
  }

  /* Form controls inherit typography instead of shipping 2009's. */
  :where(button, input, select, textarea) {
    font: inherit;
  }

  :where(pre, code, kbd, samp) {
    font-family: var(--font-mono);
  }

  /* opt in to animating to/from intrinsic sizes (details, etc.) */
  :where(html) {
    interpolate-size: allow-keywords;
  }

  /* Tokenized focus ring — the theming story for focus, day one. */
  :where(:focus-visible) {
    outline: var(--focus-ring-width) solid var(--focus-ring-color);
    outline-offset: var(--focus-ring-offset);
  }

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }
  }
}

/* ------------------------------------------------------------------ *
 * Elements — Tier 1. Native elements styled directly; behavior is the
 * browser's. Variants are classes: any collision with app CSS resolves
 * in the user's favor because these live in a layer.
 * ------------------------------------------------------------------ */
@layer mica.elements {
  /* --- button (and things dressed as buttons) ---------------------- */
  :where(button, .btn,
         input:is([type="button"], [type="submit"], [type="reset"])) {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    block-size: var(--control-height);
    padding: 0 var(--space-md);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--neutral-2);
    color: var(--color-text);
    font-size: 0.875rem;
    font-weight: 500;
    text-decoration: none;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s;

    &:hover:not(:disabled, [aria-disabled="true"]) {
      background: var(--neutral-3);
    }
    &:active:not(:disabled, [aria-disabled="true"]) {
      background: var(--neutral-4);
    }

    /* variants */
    &:where(.primary) {
      background: var(--color-primary);
      border-color: transparent;
      color: var(--color-on-primary);

      &:hover:not(:disabled, [aria-disabled="true"]) {
        background: var(--color-primary-hover);
      }
      &:active:not(:disabled, [aria-disabled="true"]) {
        background: var(--color-primary-active);
      }

      /* disabled = same fill at the base rule's reduced opacity — a
         color-mix toward gray was tried and reads as an enabled
         secondary button when primary is near-black */
    }

    &:where(.danger) {
      background: var(--color-danger);
      border-color: transparent;
      color: var(--color-on-danger);

      &:hover:not(:disabled, [aria-disabled="true"]) {
        background: color-mix(in oklch, var(--color-danger) 88%, var(--neutral-12));
      }
      &:active:not(:disabled, [aria-disabled="true"]) {
        background: color-mix(in oklch, var(--color-danger) 76%, var(--neutral-12));
      }
      &:where(:disabled, [aria-disabled="true"]) {
        background: color-mix(in oklch, var(--color-danger) 40%, var(--neutral-6));
      }
    }

    /* deliberately zero rest affordance — a ghost is invisible until
       hover/focus. use .ghost for toolbars and icon rows, not as the
       lone action on a page. */
    &:where(.ghost) {
      background: transparent;
      border-color: transparent;

      &:hover:not(:disabled, [aria-disabled="true"]) {
        background: var(--neutral-3);
      }
      &:active:not(:disabled, [aria-disabled="true"]) {
        background: var(--neutral-4);
      }
    }

    /* sizes (shadcn: h-8 px-3 / h-10 px-6, text-sm throughout) */
    &:where(.small) {
      block-size: var(--control-height-sm);
      padding-inline: var(--space-sm);
    }
    &:where(.large) {
      block-size: var(--control-height-lg);
      padding-inline: var(--space-lg);
    }

    &:where(:disabled, [aria-disabled="true"]) {
      cursor: not-allowed;
      opacity: 0.55;
    }
  }

  /* --- fields: text inputs, textarea, select ----------------------- *
   * One control family with buttons: same radius, same border weight.
   * Focus ring comes from the preset; text fields match :focus-visible
   * even on mouse focus, per spec.
   * ------------------------------------------------------------------ */
  :where(input, textarea, select):where(:not([type="checkbox"],
         [type="radio"], [type="range"], [type="color"], [type="file"],
         [type="button"], [type="submit"], [type="reset"],
         [type="image"])) {
    inline-size: 100%;
    padding: var(--space-xs) var(--space-sm);
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    color: var(--color-text);
    line-height: 1.375; /* textarea rhythm; single-line heights are fixed below */

    &::placeholder {
      color: var(--color-text-muted);
      opacity: 1;
    }

    &:where(:disabled) {
      cursor: not-allowed;
      opacity: 0.55;
      background: var(--neutral-2);
    }

    /* validation — only after the user has interacted (:user-invalid),
       never on pristine fields. First consumer of the status roles. */
    &:where(:user-invalid) {
      border-color: var(--color-danger);
      --focus-ring-color: var(--color-danger);
    }
  }

  /* single-line controls share the fixed control height; text centers
     in the content box (16px field text stays — iOS zoom rule) */
  :where(select:not([multiple], [size]),
         input:not([type="checkbox"], [type="radio"], [type="range"],
           [type="color"], [type="file"], [type="button"],
           [type="submit"], [type="reset"], [type="image"])) {
    block-size: var(--control-height);
    padding-block: 0;
  }

  /* --- customizable select, where the platform allows -------------- *
   * appearance: base-select opts into styleable pickers (Chromium).
   * Elsewhere this whole rule drops (unknown pseudo-element) and the
   * native picker remains — progressive enhancement, zero JS.
   * Both declarations are required for the opt-in, and grouping them
   * means they fail together: never a half-opted-in select.
   * ------------------------------------------------------------------ */
  :where(select),
  ::picker(select) {
    appearance: base-select;
  }

  @supports (appearance: base-select) {
    /* the trigger is a flex row; children default to stretch, which
       top-aligns the value text inside the fixed control height */
    :where(select) {
      align-items: center;
    }

    ::picker(select) {
      border: 1px solid var(--color-border);
      border-radius: var(--radius-md);
      background: var(--color-surface-overlay);
      padding: var(--space-2xs);
      margin-block: var(--space-2xs);
      /* dark surfaces need heavier shadows to register at all */
      box-shadow: 0 8px 24px light-dark(oklch(0 0 0 / 0.15), oklch(0 0 0 / 0.5));
      /* positioning stays the UA's (position-try-order: most-block-size):
         it can open upward on near-ties, but it guarantees no clipping.
         Forcing block-end + flip-block was tried and clips off-viewport
         in tight space — don't fight the picker's positioning. */
      opacity: 1;
      translate: 0 0;
    }

    /* enter animates; close is instant (shadcn behavior) — the
       transition only exists while open, so unmatching :open drops it */
    :where(select):open::picker(select) {
      transition:
        opacity 0.12s,
        translate 0.12s,
        overlay 0.12s allow-discrete,
        display 0.12s allow-discrete;
    }

    @starting-style {
      ::picker(select) {
        opacity: 0;
        translate: 0 -4px;
      }
    }

    :where(select) :where(option) {
      padding: var(--space-xs) var(--space-sm);
      border-radius: var(--radius-sm);
      cursor: pointer;
    }
    :where(select) :where(option):where(:hover, :focus-visible) {
      background: var(--neutral-3);
      outline: none; /* hover-follows-focus pattern; ring is redundant here */
    }
    :where(select) :where(option):checked {
      font-weight: 500;
    }
    :where(select) :where(option)::checkmark {
      color: var(--color-accent);
    }

    :where(select)::picker-icon {
      color: var(--color-text-muted);
      transition: rotate 0.15s;
    }
    :where(select):open::picker-icon {
      rotate: 180deg;
    }

    /* opt-in via select.js: the picker overlays the trigger with the
       selected option kept in place (macOS-native / Base UI behavior).
       JS supplies only --m-sel-index; all geometry lives here.
       offset = index × row (1lh + option padding) + picker padding/border;
       max() keeps the top on-screen for selections deep in long lists. */
    :where(select.picker-aligned)::picker(select) {
      position-area: none;
      margin-block: 0;
      inset-inline-start: calc(anchor(left) - var(--space-2xs) - 1px);
      min-inline-size: calc(anchor-size(width) + 2 * (var(--space-2xs) + 1px));
      inset-block-start: max(
        var(--space-2xs),
        calc(
          anchor(top) - var(--m-sel-index, 0) * (1lh + 2 * var(--space-xs)) -
            var(--space-2xs) - 1px
        )
      );
      /* unfold in place, don't slide */
      translate: 0 0;
    }
  }

  /* textarea grows with content — zero JS */
  :where(textarea) {
    field-sizing: content;
    min-block-size: 3lh;
    resize: vertical;
  }

  /* --- form grouping: label, fieldset, legend ---------------------- *
   * Plain by default (shadcn-school): a fieldset is a titled group,
   * not a bordered box. The legend reads as a small section heading.
   * Space contents with m-vstack or rhythm.
   * ------------------------------------------------------------------ */
  :where(label) {
    font-weight: 500;
  }

  :where(fieldset) {
    border: 0;
    padding: 0;
    margin: 0;
    min-inline-size: 0; /* fieldsets otherwise refuse to shrink */
  }

  :where(legend) {
    font-weight: 600;
    padding: 0;
    margin-block-end: var(--space-md);
  }

  /* a disabled fieldset dims everything it silences */
  :where(fieldset:disabled) {
    color: var(--color-text-muted);

    & :where(label) {
      color: var(--color-text-muted);
      cursor: not-allowed;
    }
  }

  /* --- checkbox, radio, switch: drawn, semantics stay native ------- */
  :where(input:is([type="checkbox"], [type="radio"])) {
    appearance: none;
    inline-size: 1.25rem;
    block-size: 1.25rem;
    margin: 0;
    flex-shrink: 0;
    vertical-align: -0.25em;
    border: 1px solid var(--color-border-strong);
    border-radius: var(--radius-sm);
    background: var(--color-surface) center / contain no-repeat;
    cursor: pointer;
    transition: background-color 0.15s, border-color 0.15s,
      background-position 0.15s;

    &:checked {
      border-color: var(--color-primary);
      background-color: var(--color-primary);
    }

    &:disabled {
      cursor: not-allowed;
      opacity: 0.55;
    }
  }

  :where(input[type="checkbox"]:not(.switch)) {
    &:checked {
      background-image: var(--check-glyph);
    }

    /* indeterminate dash — a gradient, no glyph needed */
    &:indeterminate {
      border-color: var(--color-primary);
      background-color: var(--color-primary);
      background-image: linear-gradient(
        var(--color-on-primary),
        var(--color-on-primary)
      );
      background-size: 55% 2px;
      background-position: center;
      background-repeat: no-repeat;
    }
  }

  /* radio: "square target" — a solid pip in every state. muted pip
     unchecked, bright pip on the primary fill when checked. the round
     radio is a theme:
       input[type="radio"] {
         border-radius: var(--radius-full);
         background-image: radial-gradient(circle closest-side,
           var(--color-on-primary) 40%, transparent 46%);
       } */
  :where(input[type="radio"]) {
    background-image: linear-gradient(
      var(--color-border-strong),
      var(--color-border-strong)
    );
    background-position: center;
    background-size: 8px 8px;
    background-repeat: no-repeat;

    &:checked {
      background-image: linear-gradient(
        var(--color-on-primary),
        var(--color-on-primary)
      );
    }
  }

  /* switch: a checkbox wearing a track; the thumb is a positioned
     gradient (pseudo-elements don't render on inputs). square, per the
     design language — a solid linear-gradient block */
  :where(input[type="checkbox"].switch) {
    inline-size: 2.25rem;
    border-color: transparent;
    border-radius: var(--radius-sm);
    background-color: var(--neutral-7);
    background-image: linear-gradient(white, white);
    background-size: 1rem calc(100% - 4px);
    background-position: 2px 50%;
    background-repeat: no-repeat;

    &:checked {
      background-color: var(--color-primary);
      background-position: calc(100% - 2px) 50%;
      background-image: linear-gradient(
        var(--color-on-primary),
        var(--color-on-primary)
      );
    }
  }

  /* disabled + on: desaturate toward neutral, same recipe as disabled
     .primary buttons — inert, not just faded (placed after the switch
     block so it wins its background-color at equal specificity) */
  :where(input:is([type="checkbox"], [type="radio"])):disabled:is(
      :checked,
      :indeterminate
    ) {
    border-color: transparent;
    background-color: color-mix(in oklch, var(--color-primary) 40%, var(--neutral-6));
  }

  /* labels that wrap a check control become the click target */
  :where(label:has(> input:is([type="checkbox"], [type="radio"]))) {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    cursor: pointer;
  }

  /* a disabled control dims its whole label, not just itself */
  :where(label:has(> input:disabled)) {
    color: var(--color-text-muted);
    cursor: not-allowed;
  }

  /* --- content: tables, lists, code, quotes ------------------------ */
  :where(table) {
    inline-size: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
  }
  :where(caption) {
    caption-side: bottom;
    margin-block-start: var(--space-xs);
    color: var(--color-text-muted);
    font-size: 0.875rem;
    text-align: start;
  }
  :where(th) {
    text-align: start;
    font-weight: 500;
    color: var(--color-text-muted);
  }
  :where(th, td) {
    padding: var(--space-sm);
    border-block-end: 1px solid var(--color-border);
  }
  :where(tbody tr:last-child) :where(th, td) {
    border-block-end: 0;
  }
  :where(tbody tr):hover {
    background: var(--color-surface-raised);
  }

  :where(ul, ol) {
    padding-inline-start: var(--space-lg);
  }
  :where(li) {
    margin-block: var(--space-2xs);
  }
  :where(li)::marker {
    color: var(--color-text-muted);
  }
  :where(dt) {
    font-weight: 500;
  }
  :where(dd) {
    margin-inline-start: 0;
  }

  :where(code, kbd, samp) {
    font-size: 0.875em;
  }
  :where(:not(pre) > code) {
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border);
    padding: 0.125em 0.375em;
    border-radius: var(--radius-sm);
  }
  :where(pre) {
    background: var(--color-surface-raised);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    padding: var(--space-md);
    overflow-x: auto;
  }
  :where(kbd) {
    background: var(--color-surface);
    border: 1px solid var(--color-border-strong);
    border-block-end-width: 2px;
    padding: 0.125em 0.375em;
    border-radius: var(--radius-sm);
    font-size: 0.8em;
  }

  :where(blockquote) {
    border-inline-start: 2px solid var(--color-border-strong);
    padding-inline-start: var(--space-md);
    color: var(--color-text-muted);
  }

  :where(hr) {
    border: 0;
    border-block-start: 1px solid var(--color-border-strong);
    margin-block: var(--space-lg);
  }

  /* --- progress & meter: thin bars (shadcn-school) ------------------ *
   * vendor pseudos must stay in separate rules — an unknown selector
   * in a list invalidates the whole rule.
   * ------------------------------------------------------------------ */
  :where(progress, meter) {
    appearance: none;
    inline-size: 100%;
    block-size: 0.5rem;
    border: 0;
    border-radius: var(--radius-sm);
    overflow: hidden;
  }

  :where(progress) {
    background: color-mix(in oklch, var(--color-primary) 20%, transparent);
  }
  :where(progress)::-webkit-progress-bar {
    background: transparent;
  }
  :where(progress)::-webkit-progress-value {
    background: var(--color-primary);
  }
  :where(progress)::-moz-progress-bar {
    background: var(--color-primary);
  }

  /* meter grades through the status roles */
  :where(meter) {
    background: var(--neutral-4);
  }
  :where(meter)::-webkit-meter-bar {
    background: transparent;
    border: 0;
    block-size: 0.5rem;
  }
  :where(meter)::-webkit-meter-optimum-value {
    background: var(--color-success);
  }
  :where(meter)::-webkit-meter-suboptimum-value {
    background: var(--color-warn);
  }
  :where(meter)::-webkit-meter-even-less-good-value {
    background: var(--color-danger);
  }
  :where(meter):-moz-meter-optimum::-moz-meter-bar {
    background: var(--color-success);
  }
  :where(meter):-moz-meter-sub-optimum::-moz-meter-bar {
    background: var(--color-warn);
  }
  :where(meter):-moz-meter-sub-sub-optimum::-moz-meter-bar {
    background: var(--color-danger);
  }

  /* --- dialog: modal + drawer --------------------------------------- *
   * The browser brings focus trapping, Esc, top layer, ::backdrop, and
   * form[method=dialog] closing. Invoker commands (commandfor/command)
   * make open/close zero-JS. Exit animations: transition-behavior
   * allow-discrete + @starting-style.
   * ------------------------------------------------------------------ */
  :where(dialog) {
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    background: var(--color-surface-overlay);
    color: var(--color-text);
    /* sections carry their own padding; the dialog is a bare frame */
    padding: 0;
    overflow: hidden;
    inline-size: calc(100vw - 2rem);
    max-inline-size: var(--size-lg);
    max-block-size: calc(100svh - 2rem);
    box-shadow: 0 16px 48px light-dark(oklch(0 0 0 / 0.2), oklch(0 0 0 / 0.6));
    opacity: 0;
    scale: 0.95;
    transition:
      opacity 0.15s,
      scale 0.15s,
      translate 0.15s,
      overlay 0.15s allow-discrete,
      display 0.15s allow-discrete;
  }
  /* composition: dialog > header (title + description) / body / footer.
     layout lives on [open] — unconditional display would defeat the
     UA's display:none on closed dialogs */
  :where(dialog[open]) {
    display: flex;
    flex-direction: column;
    opacity: 1;
    scale: 1;

    & > :where(*) {
      margin-block: 0; /* the dialog owns spacing, like a stack */
    }

    /* the body: whatever sits between header and footer. one wrapper
       element; it pads itself and is the scrollable region */
    & > :where(:not(header, footer, button.close)) {
      padding: var(--space-md);
      flex: 1;
      min-block-size: 0;
      overflow-y: auto;
      font-size: 0.875rem; /* body must not outweigh the 14px title */
    }
  }

  /* corner close button — <button class="close" commandfor="…"
     command="close" aria-label="Close">✕</button> (or wrap it in a
     method=dialog form). absolute is safe: the dialog is positioned.
     shared with toasts (popovertarget/popovertargetaction=hide there). */
  :where(dialog, [popover].toast) > :where(button.close) {
    position: absolute;
    inset-block-start: var(--space-sm);
    inset-inline-end: var(--space-sm);
    padding: var(--space-2xs);
    border: 0;
    background: transparent;
    color: var(--color-text-muted);
    line-height: 1;

    &:hover:not(:disabled, [aria-disabled="true"]) {
      background: var(--neutral-3);
      color: var(--color-text);
    }
    &:active:not(:disabled, [aria-disabled="true"]) {
      background: var(--neutral-4);
    }
  }

  :where(dialog) > :where(header) {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    padding: var(--space-md);
    border-block-end: 1px solid var(--color-border);

    /* long titles must not run under the corner X */
    :where(dialog:has(> button.close)) > & {
      padding-inline-end: calc(var(--space-md) + var(--space-xl));
    }

    & > :where(*) {
      margin-block: 0;
    }

    & :where(h1, h2, h3, h4) {
      font-size: 0.875rem;
      font-weight: 500;
    }

    & :where(p) {
      color: var(--color-text-muted);
      font-size: 0.75rem;
      line-height: 1.6;
    }
  }

  :where(dialog) > :where(footer) {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    justify-content: flex-end;
    padding: var(--space-md);
    border-block-start: 1px solid var(--color-border);

    & > :where(*) {
      margin-block: 0;
    }

    /* a method=dialog form is the idiomatic close mechanism — let its
       buttons participate in the footer's row directly */
    & > :where(form[method="dialog" i]) {
      display: contents;
    }
  }
  @starting-style {
    :where(dialog[open]) {
      opacity: 0;
      scale: 0.95;
    }
  }

  :where(dialog)::backdrop {
    background: transparent;
    transition:
      background-color 0.15s,
      overlay 0.15s allow-discrete,
      display 0.15s allow-discrete;
  }
  :where(dialog[open])::backdrop {
    background: oklch(0 0 0 / 0.4);
  }
  @starting-style {
    :where(dialog[open])::backdrop {
      background: transparent;
    }
  }

  /* drawer (shadcn sheet anatomy): inline-end panel, fade + 2.5rem
     nudge rather than a full slide; no section dividers; footer pinned
     to the bottom with stacked actions */
  :where(dialog.drawer) {
    margin-inline: auto 0;
    margin-block: 0;
    block-size: 100svh;
    max-block-size: 100svh;
    inline-size: 75vw;
    max-inline-size: 24rem; /* sheet's max-w-sm */
    border: 0;
    border-inline-start: 1px solid var(--color-border);
    font-size: 0.75rem;
    line-height: 1.6;
    scale: 1;
    translate: 2.5rem 0;
  }
  :where(dialog.drawer[open]) {
    translate: 0 0;

    & > :where(:not(header, footer, button.close)) {
      font-size: inherit; /* panel runs 12/relaxed throughout */
    }
  }
  @starting-style {
    :where(dialog.drawer[open]) {
      translate: 2.5rem 0;
    }
  }

  :where(dialog.drawer) > :where(header) {
    border-block-end: 0;
  }
  :where(dialog.drawer) > :where(footer) {
    margin-block-start: auto;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-xs);
    border-block-start: 0;
  }

  /* --- accordion / disclosure: details + summary -------------------- *
   * shadcn accordion look; exclusivity is <details name="group">.
   * open/close animation via ::details-content + interpolate-size,
   * graceful (instant) where unsupported.
   * ------------------------------------------------------------------ */
  :where(details) {
    border-block-end: 1px solid var(--color-border);
  }

  :where(summary) {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-sm);
    padding-block: var(--space-md);
    font-size: 0.875rem;
    font-weight: 500;
    cursor: pointer;
    list-style: none;

    &:hover {
      text-decoration: underline;
    }

    /* chevron — masked so it rides currentColor-ish tokens */
    &::after {
      content: "";
      inline-size: 1rem;
      block-size: 1rem;
      flex-shrink: 0;
      background: var(--color-text-muted);
      mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' d='m6 9 6 6 6-6'/%3E%3C/svg%3E")
        center / contain no-repeat;
      transition: rotate 0.2s;
    }
  }
  :where(summary)::-webkit-details-marker {
    display: none;
  }
  :where(details[open]) > :where(summary)::after {
    rotate: 180deg;
  }

  /* content: everything after the summary */
  :where(details) > :where(:not(summary)) {
    margin-block: 0 var(--space-md);
    font-size: 0.875rem;
  }

  :where(details)::details-content {
    block-size: 0;
    overflow-y: clip;
    transition:
      block-size 0.2s,
      content-visibility 0.2s allow-discrete;
  }
  :where(details[open])::details-content {
    block-size: auto;
  }

  /* --- popover: panels + menus -------------------------------------- *
   * toggle/light-dismiss/Esc are the browser's (popovertarget). anchored
   * to the invoker where anchor positioning exists; elsewhere the UA's
   * centered fallback applies. items close declaratively via
   * popovertarget/command — zero JS throughout.
   * ------------------------------------------------------------------ */
  :where([popover]) {
    border: 1px solid color-mix(in oklch, var(--color-text) 12%, transparent);
    border-radius: var(--radius-md);
    background: var(--color-surface-overlay);
    color: var(--color-text);
    padding: var(--space-sm);
    inline-size: max-content;
    max-inline-size: min(18rem, calc(100vw - 2rem));
    font-size: 0.75rem;
    line-height: 1.6;
    box-shadow: 0 8px 24px light-dark(oklch(0 0 0 / 0.15), oklch(0 0 0 / 0.5));
    opacity: 1;
    scale: 1;
  }
  /* enter animates; close is instant (house rule for transient layers) */
  :where([popover]:popover-open) {
    transition:
      opacity 0.1s,
      scale 0.1s,
      overlay 0.1s allow-discrete,
      display 0.1s allow-discrete;
  }
  @starting-style {
    :where([popover]:popover-open) {
      opacity: 0;
      scale: 0.95;
    }
  }
  /* anchor to the invoker where the platform can */
  @supports (position-area: block-end) {
    :where([popover]) {
      position-area: block-end span-inline-end;
      position-try-fallbacks: flip-block, flip-inline;
      margin: var(--space-2xs);
    }
  }

  /* menu: a popover of buttons/links; separators are plain hrs */
  :where([popover].menu) {
    padding: var(--space-2xs);
    min-inline-size: 8rem;

    & > :where(button, a) {
      display: flex;
      align-items: center;
      justify-content: flex-start;
      gap: var(--space-xs);
      inline-size: 100%;
      block-size: auto;
      padding: var(--space-xs);
      border: 0;
      border-radius: var(--radius-sm);
      background: transparent;
      color: var(--color-text);
      font-size: 0.75rem;
      font-weight: 400;
      text-align: start;
      text-decoration: none;
      cursor: default;

      /* :not() guards mirror the base button states — an override of
         state must match the state's specificity (house rule) */
      &:hover:not(:disabled, [aria-disabled="true"]),
      &:focus-visible:not(:disabled, [aria-disabled="true"]) {
        background: var(--color-accent);
        color: var(--color-on-accent);
        outline: none; /* the highlight is the focus indicator here */
      }
      &:active:not(:disabled, [aria-disabled="true"]) {
        background: var(--color-accent);
        color: var(--color-on-accent);
      }

      &.danger {
        color: var(--color-danger-text);

        &:hover:not(:disabled, [aria-disabled="true"]),
        &:active:not(:disabled, [aria-disabled="true"]),
        &:focus-visible:not(:disabled, [aria-disabled="true"]) {
          background: var(--color-danger-surface);
          color: var(--color-danger-text);
        }
      }

      &:disabled {
        opacity: 0.5;
        background: transparent;
        color: var(--color-text);
      }
    }

    & > :where(hr) {
      margin-block: var(--space-2xs);
      margin-inline: calc(-1 * var(--space-2xs));
      border-block-start-color: var(--color-border);
    }
  }

  /* --- combobox: m-combobox + combobox.js (Tier 2) ------------------ *
   * without the module: a native datalist — functional autocomplete.
   * with it: styled listbox, filtering, active-descendant keys.
   * positioned within the wrapper (no top layer) so it works everywhere.
   * ------------------------------------------------------------------ */
  :where(m-combobox) {
    display: block;
    position: relative;
  }

  :where(m-combobox) > :where([role="listbox"]) {
    position: absolute;
    inset-block-start: calc(100% + var(--space-2xs));
    inset-inline: 0;
    z-index: 50;
    max-block-size: 15rem;
    overflow-y: auto;
    padding: var(--space-2xs);
    border: 1px solid color-mix(in oklch, var(--color-text) 12%, transparent);
    border-radius: var(--radius-md);
    background: var(--color-surface-overlay);
    box-shadow: 0 8px 24px light-dark(oklch(0 0 0 / 0.15), oklch(0 0 0 / 0.5));
  }

  :where(m-combobox) :where([role="option"]) {
    padding: var(--space-xs);
    border-radius: var(--radius-sm);
    font-size: 0.875rem;
    cursor: default;

    &:hover,
    &[aria-selected="true"] {
      background: var(--color-accent);
      color: var(--color-on-accent);
    }
  }

  /* --- tabs: m-tabs + tabs.js (Tier 2) ------------------------------ *
   * without the module: inert nav, all panels visible in order —
   * complete content. with it: tablist semantics + roving focus.
   * shadcn segmented look: muted track, surface active tab.
   * ------------------------------------------------------------------ */
  :where(m-tabs) {
    display: block;
  }

  :where(m-tabs) > :where(nav) {
    display: inline-flex;
    gap: var(--space-2xs);
    padding: var(--space-2xs);
    background: var(--neutral-3);
    border-radius: var(--radius-md);

    & > :where(button) {
      block-size: var(--control-height-sm);
      padding-inline: var(--space-sm);
      border: 0;
      border-radius: var(--radius-sm);
      background: transparent;
      color: var(--color-text-muted);

      /* :not() guards mirror the base button states (house rule) */
      &:hover:not(:disabled, [aria-disabled="true"]),
      &:active:not(:disabled, [aria-disabled="true"]) {
        background: transparent;
        color: var(--color-text);
      }

      &[aria-selected="true"] {
        background: var(--color-surface);
        color: var(--color-text);
        box-shadow: 0 1px 2px oklch(0 0 0 / 0.08);

        &:hover:not(:disabled, [aria-disabled="true"]),
        &:active:not(:disabled, [aria-disabled="true"]) {
          background: var(--color-surface);
          color: var(--color-text);
        }
      }
    }
  }

  :where(m-tabs) > :where(section) {
    padding-block: var(--space-md);
  }

  /* --- toast: display only (queueing/auto-dismiss are Tier 2) ------- *
   * <div popover="manual" class="toast" role="status"> — manual so it
   * survives light dismiss and other popovers; role=status announces.
   * ------------------------------------------------------------------ */
  :where([popover].toast) {
    position-area: none; /* not anchored — pinned to the corner */
    /* --m-toast-offset comes from toast.js when stacking; 0 without it */
    inset: auto var(--space-lg) calc(var(--space-lg) + var(--m-toast-offset, 0px)) auto;
    margin: 0;
    inline-size: min(22rem, calc(100vw - 2rem));
    max-inline-size: none;
    padding: var(--space-md);
    padding-inline-end: var(--space-2xl); /* room for the corner X */
    translate: 0 0;

    & :where(b) {
      display: block;
      font-weight: 500;
    }
    & :where(span, p) {
      color: var(--color-text-muted);
    }

    /* status edge variants */
    &:where(.success) {
      border-inline-start: 2px solid var(--color-success);
    }
    &:where(.danger) {
      border-inline-start: 2px solid var(--color-danger);
    }
    &:where(.warn) {
      border-inline-start: 2px solid var(--color-warn);
    }
  }
  /* arrives from below rather than zooming; reflow (restacking) eases */
  :where([popover].toast:popover-open) {
    transition:
      opacity 0.1s,
      translate 0.1s,
      inset-block-end 0.15s,
      overlay 0.1s allow-discrete,
      display 0.1s allow-discrete;
  }
  @starting-style {
    :where([popover].toast:popover-open) {
      translate: 0 0.75rem;
    }
  }

  /* --- tooltip: css-only, [data-tip] -------------------------------- *
   * inverted chip (primary on on-primary), shows on hover/focus after a
   * beat, hides instantly. data-tip is visual — pair it with aria-label
   * or visible text for AT.
   * ------------------------------------------------------------------ */
  :where([data-tip]) {
    position: relative;
  }
  :where([data-tip])::after {
    content: attr(data-tip);
    position: absolute;
    inset-block-end: calc(100% + var(--space-xs));
    inset-inline-start: 50%;
    translate: -50% 2px;
    inline-size: max-content;
    max-inline-size: 18rem;
    padding: 0.375rem var(--space-sm);
    border-radius: var(--radius-sm);
    background: var(--color-primary);
    color: var(--color-on-primary);
    font-size: 0.75rem;
    font-weight: 400;
    line-height: 1.4;
    opacity: 0;
    pointer-events: none;
    transition:
      opacity 0.1s,
      translate 0.1s;
    z-index: 10;
  }
  :where([data-tip]:hover, [data-tip]:focus-visible)::after {
    opacity: 1;
    translate: -50% 0;
    transition-delay: 0.3s;
  }

  /* --- validation errors ------------------------------------------- *
   * Tier 1 (no JS): a generic <m-error> after a field shows when the
   * field is :user-invalid. Submit attempts fall back to native bubbles.
   * Tier 2 (mica/field.js): <m-field> suppresses bubbles and activates
   * per-cause <m-error match="..."> messages. Rules below are all
   * zero-specificity; source order resolves them.
   * ------------------------------------------------------------------ */
  :where(m-field) {
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
  }

  /* every rule here is zero-specificity: source order alone resolves */
  :where(m-error) {
    display: none;
    font-size: 0.875rem;
    color: var(--color-danger-text);
  }

  /* Tier-1 fallback: generic (matchless) error after user interaction */
  :where(input:user-invalid, textarea:user-invalid, select:user-invalid)
    ~ :where(m-error:not([match])) {
    display: block;
  }

  /* Tier 2: once m-field upgrades, the module owns visibility */
  :where(m-field:defined) :where(m-error) {
    display: none;
  }
  :where(m-error[active]) {
    display: block;
  }
}

/* ------------------------------------------------------------------ *
 * Layout primitives (Tier 0)
 *
 * Mechanism: attributes only set custom properties; rules read custom
 * properties. `gap="lg"` and `style="--gap: 2.5rem"` are the same thing.
 * ------------------------------------------------------------------ */
@layer mica.layout {
  /* Custom elements default to display:inline; give ours a sane base. */
  m-vstack,
  m-hstack,
  m-zstack,
  m-center,
  m-box,
  m-grid,
  m-sidecar,
  m-switcher,
  m-reel {
    display: block;
    box-sizing: border-box;
  }

  /* Shared attribute vocabulary -> custom properties */
  :is(m-vstack, m-hstack, m-grid, m-sidecar, m-switcher, m-reel) {
    &[gap="none"] { --gap: 0; }
    &[gap="2xs"]  { --gap: var(--space-2xs); }
    &[gap="xs"]   { --gap: var(--space-xs); }
    &[gap="sm"]   { --gap: var(--space-sm); }
    &[gap="md"]   { --gap: var(--space-md); }
    &[gap="lg"]   { --gap: var(--space-lg); }
    &[gap="xl"]   { --gap: var(--space-xl); }
    &[gap="2xl"]  { --gap: var(--space-2xl); }
  }

  :is(m-vstack, m-hstack) {
    &[align="start"]   { --align: flex-start; }
    &[align="center"]  { --align: center; }
    &[align="end"]     { --align: flex-end; }
    &[align="stretch"] { --align: stretch; }
  }

  /* --- m-vstack: vertical flow with consistent gaps ---------------- */
  m-vstack {
    display: flex;
    flex-direction: column;
    align-items: var(--align, stretch);
    gap: var(--gap, var(--space-md));

    /* the stack owns spacing; preset rhythm yields to gap */
    & > * { margin-block: 0; }
  }

  /* --- m-hstack: one horizontal row; `wrap` to allow wrapping ------ */
  m-hstack {
    display: flex;
    align-items: var(--align, center);
    justify-content: var(--justify, flex-start);
    gap: var(--gap, var(--space-md));

    &[wrap] { flex-wrap: wrap; }

    & > * { margin-block: 0; }

    &[justify="start"]   { --justify: flex-start; }
    &[justify="center"]  { --justify: center; }
    &[justify="end"]     { --justify: flex-end; }
    &[justify="between"] { --justify: space-between; }
  }

  /* --- m-zstack: layering; children occupy the same grid cell ------ */
  m-zstack {
    display: grid;
    align-items: var(--align, stretch);
    justify-items: var(--justify, stretch);

    &[align="start"]   { --align: start; }
    &[align="center"]  { --align: center; }
    &[align="end"]     { --align: end; }
    &[align="stretch"] { --align: stretch; }

    &[justify="start"]   { --justify: start; }
    &[justify="center"]  { --justify: center; }
    &[justify="end"]     { --justify: end; }
    &[justify="stretch"] { --justify: stretch; }

    /* every layer shares one cell; paint order is DOM order.
       per-layer placement is just user CSS: place-self on the child. */
    & > * {
      grid-area: 1 / 1;
    }
  }

  /* --- m-center: intrinsic horizontal centering with a measure ----- */
  m-center {
    max-inline-size: var(--max, var(--measure));
    margin-inline: auto;
    padding-inline: var(--gutter, 0);

    &[max="xs"] { --max: var(--size-xs); }
    &[max="sm"] { --max: var(--size-sm); }
    &[max="md"] { --max: var(--size-md); }
    &[max="lg"] { --max: var(--size-lg); }
    &[max="xl"] { --max: var(--size-xl); }

    &[gutter="sm"] { --gutter: var(--space-sm); }
    &[gutter="md"] { --gutter: var(--space-md); }
    &[gutter="lg"] { --gutter: var(--space-lg); }
  }

  /* --- m-box: padding, an inside for content ----------------------- */
  m-box {
    padding: var(--pad, var(--space-md));

    &[pad="none"] { --pad: 0; }
    &[pad="xs"]   { --pad: var(--space-xs); }
    &[pad="sm"]   { --pad: var(--space-sm); }
    &[pad="md"]   { --pad: var(--space-md); }
    &[pad="lg"]   { --pad: var(--space-lg); }
    &[pad="xl"]   { --pad: var(--space-xl); }
  }

  /* --- m-grid: responsive grid, no media queries ------------------- */
  m-grid {
    display: grid;
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(var(--min, var(--size-sm)), 100%), 1fr)
    );
    gap: var(--gap, var(--space-md));

    &[min="xs"] { --min: var(--size-xs); }
    &[min="sm"] { --min: var(--size-sm); }
    &[min="md"] { --min: var(--size-md); }
    &[min="lg"] { --min: var(--size-lg); }
  }

  /* --- m-sidecar: fixed + flexible pair, stacks when narrow -------- */
  m-sidecar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap, var(--space-md));

    /* the sidecar is the first child by default; `side="end"` flips it */
    & > :first-child {
      flex-basis: var(--side-width, var(--size-xs));
      flex-grow: 1;
    }
    & > :last-child {
      flex-basis: 0;
      flex-grow: 999;
      min-inline-size: var(--content-min, 50%);
    }

    /* side="end": the *last* child is the sidecar (no visual reordering) */
    &[side="end"] > :first-child {
      flex-basis: 0;
      flex-grow: 999;
      min-inline-size: var(--content-min, 50%);
    }
    &[side="end"] > :last-child {
      flex-basis: var(--side-width, var(--size-xs));
      flex-grow: 1;
      min-inline-size: auto;
    }

    &[side-width="xs"] { --side-width: var(--size-xs); }
    &[side-width="sm"] { --side-width: var(--size-sm); }
    &[side-width="md"] { --side-width: var(--size-md); }
  }

  /* --- m-switcher: row that switches to a column below a threshold - */
  m-switcher {
    display: flex;
    flex-wrap: wrap;
    gap: var(--gap, var(--space-md));

    & > * {
      flex-basis: calc((var(--threshold, var(--size-lg)) - 100%) * 999);
      flex-grow: 1;
    }

    &[threshold="sm"] { --threshold: var(--size-sm); }
    &[threshold="md"] { --threshold: var(--size-md); }
    &[threshold="lg"] { --threshold: var(--size-lg); }
    &[threshold="xl"] { --threshold: var(--size-xl); }
  }

  /* --- m-reel: horizontal scroll with snap ------------------------- */
  m-reel {
    display: flex;
    gap: var(--gap, var(--space-md));
    overflow-x: auto;
    scroll-snap-type: inline proximity;

    & > * {
      flex-shrink: 0;
      scroll-snap-align: start;
    }

    &[snap="none"]      { scroll-snap-type: none; }
    &[snap="mandatory"] { scroll-snap-type: inline mandatory; }
  }
}
