/*
 * @malevich/components — aggregate stylesheet.
 *
 * Cascade layer order is established here. Consumers may extend with
 * additional layers; @layer user lives outside this file and wins by
 * order.
 */

@layer malevich.reset, malevich.tokens, malevich.base, malevich.components,
  malevich.tweaks, user;

/* ===== ./src/runtime/behaviors/copyable.css ===== */
/*
 * Copyable behavior modifier — shared styles.
 *
 * Renders a small overlay button injected by `initCopyable()` (or a
 * per-component `.{block}__copy` slot if the component prefers to own
 * its placement).
 *
 * Components that opt in (Code, Code block, …) provide
 * `position: relative` on the host so the button can anchor itself.
 */

@layer malevich.components {
  [data-copyable="true"] {
    position: relative;
  }

  .malevich-copyable__button {
    --copy-bg: var(--color-surface-raised);
    --copy-bg-hover: var(--color-surface-canvas);
    --copy-color: var(--color-ink-regular);
    --copy-color-hover: var(--color-ink-strong);
    --copy-border: var(--color-border-default);

    position: absolute;
    inset-block-start: var(--space-inset-element-s);
    inset-inline-end: var(--space-inset-element-s);

    display: inline-flex;
    align-items: center;
    justify-content: center;

    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);

    padding: 0;
    margin: 0;

    background-color: var(--copy-bg);
    color: var(--copy-color);

    border: var(--border-width-hairline) solid var(--copy-border);
    border-radius: var(--radius-button);

    cursor: pointer;

    opacity: 0;
    transition:
      opacity var(--motion-fast) var(--motion-easing-default),
      background-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default);
  }

  [data-copyable="true"]:hover .malevich-copyable__button,
  [data-copyable="true"]:focus-within .malevich-copyable__button,
  .malevich-copyable__button:focus-visible {
    opacity: 1;
  }

  .malevich-copyable__button:hover {
    background-color: var(--copy-bg-hover);
    color: var(--copy-color-hover);
  }

  .malevich-copyable__button:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  [data-copyable="true"][data-copied="true"] .malevich-copyable__button {
    color: var(--color-success);
    opacity: 1;
  }

  @media (prefers-reduced-motion: reduce) {
    .malevich-copyable__button {
      transition: none;
    }
  }
}



/* Foundations */
/* ===== ./src/foundations/typography/typography.css ===== */
/*
 * Typography — foundation
 *
 * Adjacent-selector defaults per ADR-0009. The role utility classes
 * (.font-display-hero, .font-heading-title, etc.) are generated
 * automatically by @malevich/core's emit pipeline from semantic font
 * tokens — this component only adds the HTML element defaults that
 * map standard tags inside <main>/<article> to sensible roles.
 *
 * Defaults:
 *   main h1, article h1 → heading-title
 *   main h2, article h2 → heading-section
 *   main h3, article h3 → heading-subsection
 *   main h4, article h4 → heading-group
 *   main p,  article p  → body-regular
 *   main p.lead         → body-lead
 *   main small,
 *   main figcaption     → caption
 *
 * To override (e.g. landing-page H1 should be display-hero), apply
 * the role utility class explicitly:
 *
 *   <h1 class="font-display-hero">A semantic design system.</h1>
 */

@layer malevich.components {
  main h1,
  article h1 {
    font-family: var(--font-heading-title-family);
    font-size: var(--font-heading-title-size);
    font-weight: var(--font-heading-title-weight);
    line-height: var(--font-heading-title-line-height);
    letter-spacing: var(--font-heading-title-letter-spacing);
  }

  main h2,
  article h2 {
    font-family: var(--font-heading-section-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-heading-section-weight);
    line-height: var(--font-heading-section-line-height);
    letter-spacing: var(--font-heading-section-letter-spacing);
  }

  main h3,
  article h3 {
    font-family: var(--font-heading-subsection-family);
    font-size: var(--font-heading-subsection-size);
    font-weight: var(--font-heading-subsection-weight);
    line-height: var(--font-heading-subsection-line-height);
    letter-spacing: var(--font-heading-subsection-letter-spacing);
  }

  main h4,
  article h4 {
    font-family: var(--font-heading-group-family);
    font-size: var(--font-heading-group-size);
    font-weight: var(--font-heading-group-weight);
    line-height: var(--font-heading-group-line-height);
    letter-spacing: var(--font-heading-group-letter-spacing);
  }

  main p,
  article p {
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  main p.lead,
  article p.lead {
    font-family: var(--font-body-lead-family);
    font-size: var(--font-body-lead-size);
    font-weight: var(--font-body-lead-weight);
    line-height: var(--font-body-lead-line-height);
    letter-spacing: var(--font-body-lead-letter-spacing);
  }

  main small,
  article small,
  main figcaption,
  article figcaption {
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }
}


/* ===== ./src/foundations/spinner/spinner.css ===== */
/*
 * Spinner — foundation
 *
 * Determinate-less loading indicator. CSS-only — no JavaScript.
 * Uses a single rotating ring; no DOM scaffolding required from the
 * runtime.
 *
 *   <span class="spinner" role="status" aria-label="Loading"></span>
 *   <span class="spinner -s" role="status" aria-label="Loading"></span>
 *   <span class="spinner -l" role="status" aria-label="Loading"></span>
 *   <span class="spinner -inverse" role="status" aria-label="Loading"></span>
 */

@layer malevich.components {
  .spinner {
    --spinner-size: var(--size-control-m);
    --spinner-track: var(--color-border-muted);
    --spinner-indicator: var(--color-accent);
    --spinner-thickness: var(--border-width-emphasis);
    --spinner-duration: 900ms;

    display: inline-block;
    inline-size: var(--spinner-size);
    block-size: var(--spinner-size);

    border-radius: 50%;
    border: var(--spinner-thickness) solid var(--spinner-track);
    border-top-color: var(--spinner-indicator);

    animation: malevich-spinner-rotate var(--spinner-duration) linear infinite;
    flex-shrink: 0;
  }

  .spinner.-s {
    --spinner-size: var(--size-control-s);
    --spinner-thickness: var(--border-width-focus);
  }

  .spinner.-l {
    --spinner-size: var(--size-control-l);
  }

  .spinner.-xl {
    --spinner-size: var(--size-control-xl);
  }

  .spinner.-inverse {
    --spinner-track: var(--color-border-on-inverse, var(--color-border-muted));
    --spinner-indicator: var(--color-ink-inverse);
  }

  .spinner.-muted {
    --spinner-indicator: var(--color-ink-subtle);
  }

  @keyframes malevich-spinner-rotate {
    to { transform: rotate(360deg); }
  }

  @media (prefers-reduced-motion: reduce) {
    .spinner {
      animation-duration: 2400ms;
    }
  }
}


/* ===== ./src/foundations/skeleton/skeleton.css ===== */
/*
 * Skeleton — foundation
 *
 * Layout placeholder rendered while content loads. CSS-only — uses a
 * shimmer gradient animation. Authors compose multiple skeletons to
 * approximate the final layout.
 *
 *   <div class="skeleton" style="inline-size: 80%;"></div>
 *   <div class="skeleton -circle" style="aspect-ratio: 1;"></div>
 *   <div class="skeleton -rect" style="aspect-ratio: 16/9;"></div>
 *
 * Authors size each skeleton inline because dimensions track the
 * final content layout.
 */

@layer malevich.components {
  .skeleton {
    --skeleton-base: var(--color-surface-raised);
    --skeleton-highlight: var(--color-surface-canvas);
    --skeleton-duration: 1600ms;

    display: block;
    border-radius: var(--radius-button);

    background:
      linear-gradient(
        90deg,
        var(--skeleton-base) 0%,
        var(--skeleton-highlight) 50%,
        var(--skeleton-base) 100%
      );
    background-size: 200% 100%;
    background-repeat: no-repeat;

    animation: malevich-skeleton-shimmer var(--skeleton-duration) ease-in-out infinite;
  }

  .skeleton.-circle {
    border-radius: 50%;
  }

  .skeleton.-rect {
    border-radius: var(--radius-card);
  }

  .skeleton.-pill {
    border-radius: var(--radius-pill);
  }

  .skeleton.-text {
    block-size: var(--font-body-regular-size);
    border-radius: var(--radius-tag);
  }

  .skeleton.-muted {
    --skeleton-base: var(--color-surface-canvas);
    --skeleton-highlight: var(--color-surface-raised);
  }

  @keyframes malevich-skeleton-shimmer {
    0%   { background-position: 100% 0; }
    100% { background-position: -100% 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    .skeleton {
      animation: none;
      background: var(--skeleton-base);
    }
  }
}


/* ===== ./src/foundations/dots/dots.css ===== */
/*
 * Dots — foundation
 *
 * Inline loading indicator: three dots pulsing in sequence. CSS-only.
 * Smaller and quieter than Spinner — designed to live inside running
 * text or button labels.
 *
 *   <span class="dots" role="status" aria-label="Loading">
 *     <span class="dots__item"></span>
 *     <span class="dots__item"></span>
 *     <span class="dots__item"></span>
 *   </span>
 */

@layer malevich.components {
  .dots {
    --dots-size: var(--space-inset-element-s);
    --dots-gap: var(--space-inset-element-s);
    --dots-color: var(--color-ink-regular);
    --dots-duration: 1200ms;

    display: inline-flex;
    align-items: center;
    gap: var(--dots-gap);
    vertical-align: middle;
  }

  .dots__item {
    inline-size: var(--dots-size);
    block-size: var(--dots-size);
    border-radius: 50%;
    background-color: var(--dots-color);
    opacity: 0.3;
    animation: malevich-dots-pulse var(--dots-duration) ease-in-out infinite;
  }

  .dots__item:nth-child(1) { animation-delay: 0ms; }
  .dots__item:nth-child(2) { animation-delay: 200ms; }
  .dots__item:nth-child(3) { animation-delay: 400ms; }

  .dots.-accent {
    --dots-color: var(--color-accent);
  }

  .dots.-subtle {
    --dots-color: var(--color-ink-subtle);
  }

  .dots.-inverse {
    --dots-color: var(--color-ink-inverse);
  }

  .dots.-l {
    --dots-size: var(--space-inset-element-m);
    --dots-gap: var(--space-inset-element-m);
  }

  @keyframes malevich-dots-pulse {
    0%, 80%, 100% { opacity: 0.3; transform: scale(0.8); }
    40%           { opacity: 1;   transform: scale(1); }
  }

  @media (prefers-reduced-motion: reduce) {
    .dots__item {
      animation: none;
      opacity: 0.6;
    }
  }
}


/* ===== ./src/foundations/image/image.css ===== */
/*
 * Image — foundation
 *
 * Responsive image with optional <picture> source set. CSS-only — no
 * runtime, no JavaScript.
 *
 * Per answered design question: native <picture>, loading="eager"
 * default, opt-in lazy via data-lazy="true". The component is the
 * <img>; <picture> is an author wrapper choice.
 *
 *   <img class="image" src="hero.jpg" alt="…" width="1200" height="600" />
 *
 *   <picture>
 *     <source srcset="hero.avif" type="image/avif" />
 *     <source srcset="hero.webp" type="image/webp" />
 *     <img class="image" src="hero.jpg" alt="…" width="1200" height="600" />
 *   </picture>
 *
 *   <img class="image -rounded" src="avatar.jpg" alt="…" data-lazy="true" />
 */

@layer malevich.components {
  .image {
    display: block;
    max-inline-size: 100%;
    block-size: auto;

    /* Prevent CLS — authors should set width/height attributes too,
     * which sets the intrinsic ratio. This rule keeps that ratio when
     * the rendered size is constrained.
     */
    object-fit: cover;
    object-position: center;
  }

  .image[data-lazy="true"] {
    /* Marker for tooling; browsers handle native loading via
     * loading="lazy" attribute, not CSS. Authors pair data-lazy="true"
     * with loading="lazy" on the <img>.
     */
  }

  .image.-rounded {
    border-radius: var(--radius-card);
  }

  .image.-pill {
    border-radius: var(--radius-pill);
  }

  .image.-circle {
    border-radius: 50%;
    aspect-ratio: 1;
  }

  .image.-cover {
    object-fit: cover;
    inline-size: 100%;
    block-size: 100%;
  }

  .image.-contain {
    object-fit: contain;
  }

  .image.-bordered {
    border: var(--border-width-hairline) solid var(--color-border-default);
  }

  .image.-shadow {
    box-shadow: var(--shadow-raised);
  }
}


/* ===== ./src/foundations/icon/icon.css ===== */
/*
 * Icon — foundation
 *
 * The visual chrome. Authors write a placeholder element:
 *
 *   <i class="icon" data-icon="check"></i>
 *
 * The icon adapter runtime swaps the placeholder's innerHTML with the
 * SVG fetched from a registered icon pack (e.g. @malevich/icons-default).
 * Without a registered pack, the element stays empty — CSS still
 * applies (sized box reserved, currentColor binding ready).
 *
 * Per the answered design question recorded with this component:
 * function-based adapter — getIcon(name, size) -> SVG string.
 */

@layer malevich.components {
  .icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;

    inline-size: var(--icon-inline-size);
    block-size: var(--icon-inline-size);

    color: currentColor;
    fill: currentColor;
    stroke: currentColor;

    line-height: 1;
    vertical-align: var(--icon-baseline);
  }

  .icon > svg {
    inline-size: 100%;
    block-size: 100%;
  }

  /* Size variants — overrideable */

  .icon.-s {
    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);
  }

  .icon.-m {
    inline-size: var(--size-control-m);
    block-size: var(--size-control-m);
  }

  .icon.-l {
    inline-size: var(--size-control-l);
    block-size: var(--size-control-l);
  }

  .icon.-xl {
    inline-size: var(--size-control-xl);
    block-size: var(--size-control-xl);
  }

  /* Tone variants */

  .icon.-accent { color: var(--color-accent); }
  .icon.-danger { color: var(--color-danger); }
  .icon.-success { color: var(--color-success); }
  .icon.-warning { color: var(--color-warning); }
  .icon.-info { color: var(--color-info); }
  .icon.-muted { color: var(--color-ink-subtle); }
}


/* ===== ./src/foundations/avatar/avatar.css ===== */
/*
 * Avatar — element
 *
 * User/entity representation. Supports initials, image, or icon content.
 * CSS-only — no JavaScript, no tweak slots.
 *
 *   <span class="avatar -accent">KM</span>
 *   <span class="avatar -l"><img src="/u.jpg" alt="Kazimir Malevich" /></span>
 *   <span class="avatar -accent"><svg aria-hidden="true">…</svg></span>
 */

@layer malevich.components {
  .avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex: 0 0 auto;

    /* Default size = medium */
    width: var(--size-control-m);
    height: var(--size-control-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border-radius: var(--radius-avatar);

    /* Initials typography — defaults to body-support. */
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    text-transform: uppercase;
    overflow: hidden;
    user-select: none;
  }

  /* Image content stretches edge-to-edge. */
  .avatar > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
  }

  /* Icon content (SVG) inherits avatar text color, sized via em. */
  .avatar > svg {
    width: 60%;
    height: 60%;
    display: block;
    fill: currentColor;
  }

  /* ----- Variants ----- */

  .avatar.-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
  }

  /* Bone — warm raised surface */
  .avatar.-bone {
    background-color: var(--color-surface-float);
    color: var(--color-ink-strong);
  }

  .avatar.-neutral {
    background-color: var(--color-border-muted);
    color: var(--color-ink-strong);
  }

  /* ----- Sizes ----- */

  .avatar.-s {
    width: var(--size-control-s);
    height: var(--size-control-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .avatar.-l {
    width: var(--size-control-l);
    height: var(--size-control-l);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  .avatar.-xl {
    width: var(--size-control-xl);
    height: var(--size-control-xl);
    font-family: var(--font-display-title-family);
    font-size: var(--font-display-title-size);
    font-weight: var(--font-display-title-weight);
    line-height: var(--font-display-title-line-height);
    letter-spacing: var(--font-display-title-letter-spacing);
  }
}


/* ===== ./src/foundations/divider/divider.css ===== */
/*
 * Divider — element (display)
 *
 * Visual separator between content blocks. CSS-only — no JavaScript,
 * no tweak slots.
 *
 * Semantic HTML: <hr class="divider"> for horizontal,
 * <hr class="divider -vertical"> for vertical (CSS rotates the
 * native rule).
 *
 *   <hr class="divider" />
 *   <hr class="divider -vertical" />
 *   <hr class="divider -strong" />
 *   <hr class="divider -muted" />
 */

@layer malevich.components {
  .divider {
    border: 0;
    margin: 0;

    background-color: var(--color-border-default);

    block-size: var(--border-width-hairline);
    inline-size: 100%;
  }

  .divider.-vertical {
    block-size: auto;
    inline-size: var(--border-width-hairline);
    align-self: stretch;
    min-block-size: var(--size-control-m);
  }

  .divider.-strong {
    background-color: var(--color-border-strong);
  }

  .divider.-muted {
    background-color: var(--color-border-muted);
  }

  .divider.-emphasis {
    block-size: var(--border-width-emphasis);
  }

  .divider.-vertical.-emphasis {
    block-size: auto;
    inline-size: var(--border-width-emphasis);
  }
}



/* Elements — interactive */
/* ===== ./src/elements/interactive/button/button.css ===== */
/*
 * Button — element
 *
 * Styles cover both pre-runtime markup:
 *   <button class="button">Save</button>
 *
 * and post-runtime markup (after initButton expansion):
 *   <button class="button" data-malevich-ready="true">
 *     <span class="button__bg" data-tweak-layer="background" hidden></span>
 *     <span class="button__glow" data-tweak-layer="glow" hidden></span>
 *     <span class="button__content">
 *       <span class="button__label">Save</span>
 *     </span>
 *     <span class="button__fx" data-tweak-layer="effects" hidden></span>
 *   </button>
 */

@layer malevich.components {
  .button {
    /* Reset native button defaults */
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    border: var(--border-width-hairline) solid transparent;
    background: transparent;
    color: inherit;
    cursor: pointer;
    user-select: none;

    /* Layout */
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-gap-elements-s);

    /* Default size = medium */
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);
    min-height: var(--size-control-m);

    /* Typography — semantic font tokens (body-support default) */
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    text-decoration: none;
    white-space: nowrap;

    /* Surface */
    border-radius: var(--radius-button);

    /* Motion */
    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default),
      box-shadow var(--motion-fast) var(--motion-easing-default);
  }

  .button:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
  }

  .button:disabled,
  .button[aria-disabled="true"] {
    cursor: not-allowed;
    background-color: var(--button-background-disabled);
    color: var(--button-text-disabled);
    border-color: var(--button-border-disabled);
  }

  /* Content wrapper sits above tweak layers */
  .button__content {
    position: relative;
    z-index: 1;
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
  }

  .button__label {
    display: inline-block;
  }

  /* Tweak layers — inert until a tweak unhides them */
  .button__bg,
  .button__glow,
  .button__fx {
    position: absolute;
    inset: 0;
    pointer-events: none;
    border-radius: inherit;
    z-index: 0;
  }

  .button__fx {
    z-index: 2;
  }

  /* ----- Variants -----
   *
   * v1.0 names: primary, secondary, ghost, danger, success.
   * v0.1.0 names: accent (= primary), neutral (= secondary) retained
   * as aliases via :is() until v0.2.0 codemod migration completes.
   */

  .button.-primary,
  .button.-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
    border-color: var(--color-accent);
  }
  .button.-primary:hover:not(:disabled):not([aria-disabled="true"]),
  .button.-accent:hover:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--color-accent-strong);
    border-color: var(--color-accent-strong);
  }
  .button.-primary:active:not(:disabled):not([aria-disabled="true"]),
  .button.-primary[data-active="true"]:not(:disabled):not([aria-disabled="true"]),
  .button.-accent:active:not(:disabled):not([aria-disabled="true"]),
  .button.-accent[data-active="true"]:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--button-background-accent-active);
    border-color: var(--button-background-accent-active);
  }

  .button.-secondary,
  .button.-neutral {
    background-color: transparent;
    color: var(--color-ink-strong);
    border-color: var(--color-border-strong);
  }
  .button.-secondary:hover:not(:disabled):not([aria-disabled="true"]),
  .button.-neutral:hover:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
  }
  .button.-secondary:active:not(:disabled):not([aria-disabled="true"]),
  .button.-secondary[data-active="true"]:not(:disabled):not([aria-disabled="true"]),
  .button.-neutral:active:not(:disabled):not([aria-disabled="true"]),
  .button.-neutral[data-active="true"]:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
    opacity: 0.85;
  }

  .button.-ghost {
    background-color: transparent;
    color: var(--color-ink-strong);
    border-color: transparent;
  }
  .button.-ghost:hover:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--button-background-ghost-hover);
  }
  .button.-ghost:active:not(:disabled):not([aria-disabled="true"]),
  .button.-ghost[data-active="true"]:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--button-background-ghost-hover);
    opacity: 0.85;
  }

  .button.-danger {
    background-color: var(--color-danger);
    color: var(--color-ink-inverse);
    border-color: var(--color-danger);
  }
  .button.-danger:hover:not(:disabled):not([aria-disabled="true"]) {
    opacity: 0.9;
  }
  .button.-danger:active:not(:disabled):not([aria-disabled="true"]),
  .button.-danger[data-active="true"]:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--button-background-danger-active);
    border-color: var(--button-background-danger-active);
  }

  .button.-success {
    background-color: var(--color-success);
    color: var(--color-ink-inverse);
    border-color: var(--color-success);
  }
  .button.-success:hover:not(:disabled):not([aria-disabled="true"]) {
    opacity: 0.9;
  }
  .button.-success:active:not(:disabled):not([aria-disabled="true"]),
  .button.-success[data-active="true"]:not(:disabled):not([aria-disabled="true"]) {
    opacity: 0.8;
  }

  /* ----- Sizes ----- */

  .button.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    min-height: var(--size-control-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .button.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline: var(--space-inset-element-l);
    min-height: var(--size-control-l);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }
}


/* ===== ./src/elements/interactive/button-group/button-group.css ===== */
/*
 * Button-group — element (interactive)
 *
 * Joins multiple Buttons or Toggles into a connected horizontal row
 * with shared borders and squared inner corners. CSS-only — relies on
 * sibling selectors.
 *
 *   <div class="button-group" role="group" aria-label="Filter by status">
 *     <button class="button -secondary">All</button>
 *     <button class="button -secondary">Active</button>
 *     <button class="button -secondary">Archived</button>
 *   </div>
 *
 *   <div class="button-group">
 *     <button class="toggle" aria-pressed="false">B</button>
 *     <button class="toggle" aria-pressed="true">I</button>
 *     <button class="toggle" aria-pressed="false">U</button>
 *   </div>
 */

@layer malevich.components {
  .button-group {
    display: inline-flex;
    align-items: stretch;
    isolation: isolate;
  }

  /* Strip rounded corners between siblings. The first child keeps
   * inline-start radius; the last keeps inline-end. Middle children
   * lose all radius.
   */
  .button-group > .button,
  .button-group > .toggle {
    border-radius: 0;
  }

  .button-group > .button:first-child,
  .button-group > .toggle:first-child {
    border-start-start-radius: var(--radius-button);
    border-end-start-radius: var(--radius-button);
  }

  .button-group > .button:last-child,
  .button-group > .toggle:last-child {
    border-start-end-radius: var(--radius-button);
    border-end-end-radius: var(--radius-button);
  }

  /* Collapse the duplicate inner border between adjacent siblings. */
  .button-group > .button + .button,
  .button-group > .button + .toggle,
  .button-group > .toggle + .button,
  .button-group > .toggle + .toggle {
    margin-inline-start: calc(-1 * var(--border-width-hairline));
  }

  /* Focused / pressed / hovered child rises above its neighbors. */
  .button-group > .button:hover,
  .button-group > .button:focus-visible,
  .button-group > .toggle:hover,
  .button-group > .toggle:focus-visible,
  .button-group > .toggle[aria-pressed="true"] {
    z-index: 1;
  }

  /* Variants */

  .button-group.-vertical {
    flex-direction: column;
  }

  .button-group.-vertical > .button:first-child,
  .button-group.-vertical > .toggle:first-child {
    border-start-start-radius: var(--radius-button);
    border-start-end-radius: var(--radius-button);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
  }

  .button-group.-vertical > .button:last-child,
  .button-group.-vertical > .toggle:last-child {
    border-start-start-radius: 0;
    border-start-end-radius: 0;
    border-end-start-radius: var(--radius-button);
    border-end-end-radius: var(--radius-button);
  }

  .button-group.-vertical > .button + .button,
  .button-group.-vertical > .button + .toggle,
  .button-group.-vertical > .toggle + .button,
  .button-group.-vertical > .toggle + .toggle {
    margin-inline-start: 0;
    margin-block-start: calc(-1 * var(--border-width-hairline));
  }
}


/* ===== ./src/elements/interactive/tabs/tabs.css ===== */
/*
 * Tabs — block
 *
 * Pre-runtime markup (author):
 *   <div class="tabs">
 *     <nav class="tabs__list">
 *       <button class="tabs__tab" data-tab-target="panel-1">Overview</button>
 *       <button class="tabs__tab" data-tab-target="panel-2">Pricing</button>
 *     </nav>
 *     <section class="tabs__panel" id="panel-1">…</section>
 *     <section class="tabs__panel" id="panel-2" hidden>…</section>
 *   </div>
 *
 * After initTabs the list gains role="tablist", tabs gain role="tab"
 * + aria-selected + aria-controls + roving tabindex, panels gain
 * role="tabpanel" + aria-labelledby.
 */

@layer malevich.components {
  .tabs {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-blocks-s);
  }

  .tabs__list {
    display: inline-flex;
    align-items: stretch;
    gap: var(--space-gap-elements-s);
    border-bottom: var(--border-width-hairline) solid var(--tabs-rail-color);
  }

  .tabs__tab {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    background: transparent;
    cursor: pointer;
    user-select: none;

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    border: 0;
    border-bottom: var(--border-width-emphasis) solid transparent;
    margin-bottom: calc(-1 * var(--border-width-hairline));

    color: var(--color-ink-subtle);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    transition:
      color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      background-color var(--motion-fast) var(--motion-easing-default);
  }

  .tabs__tab:hover:not([disabled]):not([aria-selected="true"]) {
    color: var(--color-ink-strong);
  }

  .tabs__tab:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-emphasis);
  }

  .tabs__tab[aria-selected="true"] {
    color: var(--tabs-tab-text-active);
    border-bottom-color: var(--tabs-tab-border-active);
    background-color: var(--tabs-tab-background-active);
  }

  .tabs__tab[disabled] {
    color: var(--color-ink-subtle);
    opacity: 0.5;
    cursor: not-allowed;
  }

  .tabs__panel {
    display: block;
  }

  .tabs__panel[hidden] {
    display: none;
  }

  /* ----- Variant: pill ----- */

  .tabs.-pill .tabs__list {
    border-bottom: 0;
    gap: var(--space-gap-elements-s);
    padding: var(--space-inset-element-s);
    background-color: var(--color-surface-raised);
    border-radius: var(--radius-pill);
  }

  .tabs.-pill .tabs__tab {
    border: 0;
    margin-bottom: 0;
    border-radius: var(--radius-pill);
  }

  .tabs.-pill .tabs__tab[aria-selected="true"] {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);
  }
}


/* ===== ./src/elements/interactive/switch/switch.css ===== */
/*
 * Switch — element (interactive)
 *
 * On/off control built on a native <input type="checkbox">. The native
 * input is visually replaced (not hidden) by a track + thumb rendered
 * via CSS pseudo-elements on the surrounding label. Keyboard focus and
 * state stay on the real input for native accessibility.
 *
 *   <label class="switch">
 *     <input type="checkbox" class="switch__input" />
 *     <span class="switch__track"></span>
 *     <span class="switch__label">Enable notifications</span>
 *   </label>
 */

@layer malevich.components {
  .switch {
    --switch-track-w: calc(var(--size-control-m) * 1.6);
    --switch-track-h: var(--size-control-s);
    --switch-thumb: calc(var(--size-control-s) - var(--space-inset-element-s));

    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-m);
    cursor: pointer;
    user-select: none;

    color: var(--color-ink-strong);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  /* The native input is visually hidden but accessible. */
  .switch__input {
    position: absolute;
    inline-size: var(--border-width-hairline);
    block-size: var(--border-width-hairline);
    padding: 0;
    margin: calc(-1 * var(--border-width-hairline));
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .switch__track {
    position: relative;
    flex-shrink: 0;
    inline-size: var(--switch-track-w);
    block-size: var(--switch-track-h);

    background-color: var(--color-border-strong);
    border-radius: var(--radius-pill);

    transition: background-color var(--motion-fast) var(--motion-easing-default);
  }

  .switch__track::after {
    content: "";
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: var(--space-inset-element-s);
    transform: translateY(-50%);

    inline-size: var(--switch-thumb);
    block-size: var(--switch-thumb);

    background-color: var(--color-surface-canvas);
    border-radius: 50%;
    box-shadow: var(--shadow-raised);

    transition: inset-inline-start var(--motion-fast) var(--motion-easing-default);
  }

  /* Checked state */
  .switch__input:checked + .switch__track {
    background-color: var(--color-accent);
  }

  .switch__input:checked + .switch__track::after {
    inset-inline-start: calc(
      var(--switch-track-w) - var(--switch-thumb) - var(--space-inset-element-s)
    );
  }

  /* Focus */
  .switch__input:focus-visible + .switch__track {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  /* Disabled */
  .switch:has(.switch__input:disabled),
  .switch__input:disabled ~ .switch__label {
    cursor: not-allowed;
    opacity: 0.5;
  }

  .switch__label {
    flex: 1;
  }

  /* Variants */

  .switch.-success .switch__input:checked + .switch__track {
    background-color: var(--color-success);
  }

  .switch.-danger .switch__input:checked + .switch__track {
    background-color: var(--color-danger);
  }

  .switch.-s {
    --switch-track-w: var(--size-control-m);
    --switch-track-h: calc(var(--size-control-s) * 0.75);
    --switch-thumb: calc(var(--size-control-s) * 0.5);
  }

  @media (prefers-reduced-motion: reduce) {
    .switch__track,
    .switch__track::after {
      transition: none;
    }
  }
}


/* ===== ./src/elements/interactive/toggle/toggle.css ===== */
/*
 * Toggle — element (interactive)
 *
 * A button that retains a pressed state. Built on native <button> with
 * aria-pressed. The aria-pressed attribute is the source of truth; CSS
 * styles match against [aria-pressed="true"]. Authors flip the
 * attribute (typically via small inline JS).
 *
 *   <button type="button" class="toggle" aria-pressed="false">Bold</button>
 *   <button type="button" class="toggle" aria-pressed="true">Italic</button>
 */

@layer malevich.components {
  .toggle {
    /* Reset native button */
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    user-select: none;

    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-gap-elements-s);

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);
    min-block-size: var(--size-control-m);

    color: var(--color-ink-strong);
    background-color: transparent;
    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: var(--radius-button);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default);
  }

  .toggle:hover:not(:disabled):not([aria-disabled="true"]) {
    background-color: var(--color-surface-canvas);
  }

  .toggle:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  .toggle:disabled,
  .toggle[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.5;
  }

  /* Pressed state */
  .toggle[aria-pressed="true"] {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
  }

  .toggle[aria-pressed="true"]:hover:not(:disabled):not([aria-disabled="true"]) {
    opacity: 0.9;
  }

  /* Sizes */

  .toggle.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    min-block-size: var(--size-control-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .toggle.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline: var(--space-inset-element-l);
    min-block-size: var(--size-control-l);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  /* Variants */

  .toggle.-accent[aria-pressed="true"] {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
    border-color: var(--color-accent);
  }

  .toggle.-ghost {
    border-color: transparent;
  }

  .toggle.-ghost[aria-pressed="true"] {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);
    border-color: transparent;
  }
}


/* ===== ./src/elements/interactive/kbd/kbd.css ===== */
/*
 * Kbd — element (interactive)
 *
 * Inline keyboard key indicator. CSS-only — no JavaScript, no tweak
 * slots. Uses native <kbd> for semantics.
 *
 *   <kbd class="kbd">⌘</kbd>
 *   <kbd class="kbd">Enter</kbd>
 *   <kbd class="kbd -muted">Esc</kbd>
 *
 * Compound key combos chain <kbd> elements with a separator authored
 * by the consumer:
 *
 *   <kbd class="kbd">⌘</kbd>+<kbd class="kbd">K</kbd>
 */

@layer malevich.components {
  .kbd {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    min-inline-size: var(--size-control-s);
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);

    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: var(--radius-tag);

    box-shadow: var(--shadow-flat);

    font-family: var(--font-mono-m-family);
    font-size: var(--font-mono-m-size);
    font-weight: var(--font-mono-m-weight);
    line-height: var(--font-mono-m-line-height);
    letter-spacing: var(--font-mono-m-letter-spacing);

    white-space: nowrap;
    user-select: none;
  }

  .kbd.-muted {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-regular);
    border-color: var(--color-border-muted);
  }

  .kbd.-strong {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
  }
}



/* Elements — form */
/* ===== ./src/elements/form/input/input.css ===== */
/*
 * Input — element
 *
 * Pre-runtime and post-runtime markup:
 *   <input class="input" type="text">
 *
 * Input has no tweak slots — it is a leaf element. Variants signal
 * validation outcome; sizes mirror the Button control ramp.
 */

@layer malevich.components {
  .input {
    /* Reset native input chrome */
    appearance: none;
    -webkit-appearance: none;
    margin: 0;

    /* Layout — default size = medium */
    display: inline-flex;
    align-items: center;
    width: 100%;
    box-sizing: border-box;
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);
    min-height: var(--size-control-m);

    /* Typography */
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
    color: var(--color-ink-strong);

    /* Surface */
    background-color: var(--input-background);
    border: var(--border-width-hairline) solid var(--input-border);
    border-radius: var(--radius-field);

    /* Motion */
    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default),
      box-shadow var(--motion-fast) var(--motion-easing-default);
  }

  .input::placeholder {
    color: var(--input-text-placeholder);
    opacity: 1;
  }

  .input:hover:not(:disabled):not([readonly]) {
    border-color: var(--color-ink-strong);
  }

  .input:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
    border-color: var(--input-border-focus);
  }

  .input:disabled {
    cursor: not-allowed;
    background-color: var(--input-background-disabled);
    color: var(--color-ink-subtle);
  }

  .input[readonly] {
    background-color: var(--input-background-disabled);
  }

  /* ----- Variants ----- */

  .input.-error,
  .input[aria-invalid="true"] {
    background-color: var(--input-background-error);
    border-color: var(--input-border-error);
  }
  .input.-error:focus-visible,
  .input[aria-invalid="true"]:focus-visible {
    outline-color: var(--input-border-error);
    border-color: var(--input-border-error);
  }

  .input.-success {
    border-color: var(--color-success);
  }

  /* ----- Sizes ----- */

  .input.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    min-height: var(--size-control-s);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .input.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline: var(--space-inset-element-l);
    min-height: var(--size-control-l);
    font-family: var(--font-body-lead-family);
    font-size: var(--font-body-lead-size);
    font-weight: var(--font-body-lead-weight);
    line-height: var(--font-body-lead-line-height);
    letter-spacing: var(--font-body-lead-letter-spacing);
  }

  /* ----- Companion text ----- */

  .input__help,
  .input__error {
    display: block;
    margin-block-start: var(--space-gap-elements-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
    color: var(--color-ink-subtle);
  }

  .input__error {
    color: var(--color-danger);
  }
}


/* ===== ./src/elements/form/checkbox/checkbox.css ===== */
/*
 * Checkbox — element
 *
 * Restyles the native <input type="checkbox"> while preserving native
 * semantics, keyboard behavior, and indeterminate state. The check
 * glyph is drawn as an inline SVG background-image so it renders
 * reliably across browsers (Safari does not honor ::after on form
 * controls).
 *
 *   <label class="checkbox-field">
 *     <input type="checkbox" class="checkbox">
 *     <span>Accept terms</span>
 *   </label>
 */

@layer malevich.components {
  .checkbox {
    /* Reset native chrome */
    appearance: none;
    -webkit-appearance: none;
    margin: 0;

    /* Layout — default size mirrors size-control-s */
    flex-shrink: 0;
    display: inline-block;
    width: var(--size-control-s);
    height: var(--size-control-s);
    box-sizing: border-box;
    vertical-align: middle;
    cursor: pointer;

    /* Surface */
    background-color: var(--checkbox-background);
    background-repeat: no-repeat;
    background-position: center;
    background-size: 70% 70%;
    border: var(--border-width-hairline) solid var(--checkbox-border);
    border-radius: var(--radius-field);

    /* Motion */
    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      box-shadow var(--motion-fast) var(--motion-easing-default);
  }

  .checkbox:hover:not(:disabled) {
    border-color: var(--color-ink-strong);
  }

  .checkbox:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
  }

  .checkbox:checked {
    background-color: var(--checkbox-background-checked);
    border-color: var(--checkbox-border-checked);
    /* Inline SVG checkmark — color injected via currentColor */
    color: var(--checkbox-check-color);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'><polyline points='3 8.5 6.5 12 13 4.5'/></svg>");
  }

  .checkbox:indeterminate,
  .checkbox[data-indeterminate="true"] {
    background-color: var(--checkbox-background-checked);
    border-color: var(--checkbox-border-checked);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.5' stroke-linecap='round'><line x1='3.5' y1='8' x2='12.5' y2='8'/></svg>");
  }

  .checkbox:disabled {
    cursor: not-allowed;
    background-color: var(--input-background-disabled);
    border-color: var(--color-border-muted);
  }
  .checkbox:disabled:checked,
  .checkbox:disabled:indeterminate,
  .checkbox:disabled[data-indeterminate="true"] {
    background-color: var(--input-background-disabled);
    border-color: var(--color-border-muted);
    opacity: 0.7;
  }

  /* ----- Sizes ----- */

  .checkbox.-s {
    /* 60% of small control, rounded by browser */
    width: calc(var(--size-control-s) * 0.6);
    height: calc(var(--size-control-s) * 0.6);
  }
}


/* ===== ./src/elements/form/field-group/field-group.css ===== */
/*
 * Field-group — element (form)
 *
 * Canonical composite for a form field: Label + control + HelperText
 * + Error. State is driven entirely by data-state on the wrapper —
 * authors set data-state="error" before render; CSS handles visibility
 * (Error replaces HelperText; aria-invalid is matched). No runtime.
 *
 *   <div class="field-group">
 *     <label class="label" for="email">Email</label>
 *     <input class="input" type="email" id="email" />
 *     <p class="helper-text">We'll never share your email.</p>
 *   </div>
 *
 *   <div class="field-group" data-state="error">
 *     <label class="label" for="email">Email</label>
 *     <input class="input" type="email" id="email" aria-invalid="true" />
 *     <p class="helper-text">We'll never share your email.</p>
 *     <p class="error">Enter a valid email address.</p>
 *   </div>
 */

@layer malevich.components {
  .field-group {
    --field-label-min: calc(var(--size-control-xl) * 2);

    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  /* When error state is on, hide helper text (error replaces it). */
  .field-group[data-state="error"] .helper-text {
    display: none;
  }

  /* When error state is NOT on, hide any error element that may exist
   * in DOM (so authors can author both and toggle state via data-state).
   */
  .field-group:not([data-state="error"]) .error {
    display: none;
  }

  /* Disabled state — when the control inside is disabled, dim the
   * label and helper text. CSS :has() handles the propagation.
   */
  .field-group:has(:disabled) .label,
  .field-group:has(:disabled) .helper-text {
    opacity: 0.5;
  }

  /* Variants */

  .field-group.-horizontal {
    flex-direction: row;
    align-items: center;
    gap: var(--space-gap-elements-m);
  }

  .field-group.-horizontal .label {
    flex-shrink: 0;
    min-inline-size: var(--field-label-min);
  }

  .field-group.-horizontal .helper-text,
  .field-group.-horizontal .error {
    inline-size: 100%;
  }
}


/* ===== ./src/elements/form/label/label.css ===== */
/*
 * Label — element (form)
 *
 * Styled <label> for form context. Carries an optional required (*)
 * or optional indicator via data attributes. CSS-only.
 *
 *   <label class="label" for="email">Email</label>
 *   <label class="label" for="email" data-required="true">Email</label>
 *   <label class="label" for="phone" data-optional="true">Phone</label>
 */

@layer malevich.components {
  .label {
    display: inline-flex;
    align-items: baseline;
    gap: var(--space-gap-elements-s);

    color: var(--color-ink-strong);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: 600;
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .label[data-required="true"]::after {
    content: "*";
    color: var(--color-danger);
    font-weight: 700;
    user-select: none;
  }

  .label[data-optional="true"]::after {
    content: "(optional)";
    color: var(--color-ink-subtle);
    font-weight: 400;
    font-size: var(--font-caption-size);
    user-select: none;
  }
}


/* ===== ./src/elements/form/helper-text/helper-text.css ===== */
/*
 * HelperText — element (form)
 *
 * Supportive text below an input. CSS-only.
 *
 *   <p class="helper-text">We'll never share your email.</p>
 *   <p class="helper-text -muted">Format: +1 555 555 5555</p>
 */

@layer malevich.components {
  .helper-text {
    margin: 0;

    color: var(--color-ink-regular);

    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .helper-text.-muted {
    color: var(--color-ink-subtle);
  }
}


/* ===== ./src/elements/form/error/error.css ===== */
/*
 * Error — element (form)
 *
 * Field-level error message. Visibility is controlled by the parent
 * field-group's data-state. CSS-only.
 *
 *   <p class="error">Enter a valid email address.</p>
 */

@layer malevich.components {
  .error {
    margin: 0;
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);

    color: var(--color-danger);

    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: 600;
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  /* Decorative warning glyph */
  .error::before {
    content: "⚠";
    flex-shrink: 0;
    color: var(--color-danger);
    user-select: none;
  }
}


/* ===== ./src/elements/form/textarea/textarea.css ===== */
/*
 * Textarea — element (form)
 *
 * Multi-line text input. Mirrors Input's visual treatment but stays a
 * native <textarea> so resize, line wrap, and form integration work
 * out of the box. CSS-only.
 *
 *   <textarea class="textarea" rows="4"></textarea>
 *   <textarea class="textarea -error" rows="4"></textarea>
 *   <textarea class="textarea" rows="4" disabled></textarea>
 */

@layer malevich.components {
  .textarea {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;

    display: block;
    inline-size: 100%;
    box-sizing: border-box;
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);
    min-block-size: calc(var(--size-control-m) * 2);

    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
    color: var(--color-ink-strong);

    background-color: var(--color-surface-canvas);
    border: var(--border-width-hairline) solid var(--color-border-strong);
    border-radius: var(--radius-field);

    resize: vertical;

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default);
  }

  .textarea::placeholder {
    color: var(--color-ink-subtle);
    opacity: 1;
  }

  .textarea:hover:not(:disabled):not([readonly]) {
    border-color: var(--color-ink-strong);
  }

  .textarea:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
    border-color: var(--color-accent);
  }

  .textarea:disabled {
    cursor: not-allowed;
    opacity: 0.6;
    background-color: var(--color-surface-raised);
  }

  /* Error state — accepts both the explicit class and native aria-invalid */
  .textarea.-error,
  .textarea[aria-invalid="true"] {
    border-color: var(--color-danger);
  }

  .textarea.-error:focus-visible,
  .textarea[aria-invalid="true"]:focus-visible {
    outline-color: var(--color-danger);
    border-color: var(--color-danger);
  }

  /* Sizes */

  .textarea.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .textarea.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline: var(--space-inset-element-l);
    font-family: var(--font-body-lead-family);
    font-size: var(--font-body-lead-size);
    font-weight: var(--font-body-lead-weight);
    line-height: var(--font-body-lead-line-height);
    letter-spacing: var(--font-body-lead-letter-spacing);
  }

  /* No-resize variant */
  .textarea.-fixed {
    resize: none;
  }
}


/* ===== ./src/elements/form/form-divider/form-divider.css ===== */
/*
 * Form-divider — element (form)
 *
 * Divider with embedded text used between groups of form fields or
 * between auth provider sets ("or sign in with"). CSS-only.
 *
 * Per ADR-0013: this is distinct from the generic Divider. Form-divider
 * carries form-specific typography and spacing; generic Divider stays a
 * clean Foundation.
 *
 *   <div class="form-divider"><span>or</span></div>
 *   <div class="form-divider"><span>or sign in with</span></div>
 *   <div class="form-divider -strong"><span>Billing details</span></div>
 */

@layer malevich.components {
  .form-divider {
    display: flex;
    align-items: center;
    gap: var(--space-gap-elements-m);

    margin-block: var(--space-gap-elements-m);

    color: var(--color-ink-subtle);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
    text-transform: uppercase;
  }

  .form-divider::before,
  .form-divider::after {
    content: "";
    flex: 1;
    block-size: var(--border-width-hairline);
    background-color: var(--color-border-muted);
  }

  .form-divider > span {
    flex-shrink: 0;
    user-select: none;
  }

  /* Variants */

  .form-divider.-strong {
    color: var(--color-ink-strong);
    font-weight: 600;
  }

  .form-divider.-strong::before,
  .form-divider.-strong::after {
    background-color: var(--color-border-strong);
  }

  .form-divider.-start > span {
    order: -1;
  }
  .form-divider.-start::before {
    display: none;
  }

  .form-divider.-end > span {
    order: 1;
  }
  .form-divider.-end::after {
    display: none;
  }
}


/* ===== ./src/elements/form/form-button/form-button.css ===== */
/*
 * Form-button — element (form)
 *
 * Submit / reset / cancel button with form-aware states. Per ADR-0013:
 * distinct from generic Button because it carries states (submitting,
 * success, error) that generic Button does not.
 *
 * State is driven by data-state on the button itself. CSS handles
 * visual swap; consumers set data-state when transitioning. The
 * button shares --button-* tokens for visual consistency with
 * generic Button.
 *
 *   <button type="submit" class="form-button -primary">Save</button>
 *
 *   <button type="submit" class="form-button -primary" data-state="submitting" aria-busy="true">
 *     Save
 *     <span class="form-button__indicator" aria-hidden="true">
 *       <span class="spinner -s -inverse"></span>
 *     </span>
 *   </button>
 */

@layer malevich.components {
  .form-button {
    /* Inherit visual shape from Button by reusing the same selector
     * surface. We can't extend in CSS, so we duplicate the structural
     * rules and consume the same tokens.
     */
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    background: transparent;
    color: inherit;
    cursor: pointer;
    user-select: none;

    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-gap-elements-s);

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);
    min-block-size: var(--size-control-m);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    text-decoration: none;
    white-space: nowrap;

    border: var(--border-width-hairline) solid transparent;
    border-radius: var(--radius-button);

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default);
  }

  .form-button:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
  }

  /* The indicator slot holds the spinner / success-check / error-glyph.
   * Hidden by default; data-state reveals the matching child.
   */
  .form-button__indicator {
    display: none;
    align-items: center;
    justify-content: center;
  }

  .form-button[data-state="submitting"] .form-button__indicator,
  .form-button[data-state="success"] .form-button__indicator,
  .form-button[data-state="error"] .form-button__indicator {
    display: inline-flex;
  }

  /* Variants — mirror Button v1.0 names */

  .form-button.-primary {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
    border-color: var(--color-accent);
  }
  .form-button.-primary:hover:not(:disabled):not([aria-disabled="true"]):not([data-state]) {
    background-color: var(--color-accent-strong);
    border-color: var(--color-accent-strong);
  }

  .form-button.-secondary {
    background-color: transparent;
    color: var(--color-ink-strong);
    border-color: var(--color-border-strong);
  }
  .form-button.-secondary:hover:not(:disabled):not([aria-disabled="true"]):not([data-state]) {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
  }

  .form-button.-ghost {
    background-color: transparent;
    color: var(--color-ink-strong);
    border-color: transparent;
  }
  .form-button.-ghost:hover:not(:disabled):not([aria-disabled="true"]):not([data-state]) {
    background-color: var(--color-surface-canvas);
  }

  .form-button.-danger {
    background-color: var(--color-danger);
    color: var(--color-ink-inverse);
    border-color: var(--color-danger);
  }

  .form-button.-success {
    background-color: var(--color-success);
    color: var(--color-ink-inverse);
    border-color: var(--color-success);
  }

  /* Submitting — cursor wait, slightly dimmed */
  .form-button[data-state="submitting"] {
    cursor: progress;
    opacity: 0.85;
  }

  /* Success — flips to success color regardless of variant */
  .form-button[data-state="success"] {
    background-color: var(--color-success);
    color: var(--color-ink-inverse);
    border-color: var(--color-success);
  }

  /* Error — flips to danger color */
  .form-button[data-state="error"] {
    background-color: var(--color-danger);
    color: var(--color-ink-inverse);
    border-color: var(--color-danger);
  }

  /* Disabled */
  .form-button:disabled,
  .form-button[aria-disabled="true"] {
    cursor: not-allowed;
    opacity: 0.5;
  }

  /* Sizes */
  .form-button.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    min-block-size: var(--size-control-s);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .form-button.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline: var(--space-inset-element-l);
    min-block-size: var(--size-control-l);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }
}


/* ===== ./src/elements/form/select/select.css ===== */
/*
 * Select — element (form)
 *
 * Natively-styled <select>. Single-select only (v1.0). Visual surface
 * mirrors Input; chevron rendered via CSS mask. CSS-only.
 *
 *   <select class="select">
 *     <option>One</option>
 *     <option>Two</option>
 *   </select>
 */

@layer malevich.components {
  .select {
    appearance: none;
    -webkit-appearance: none;
    -moz-appearance: none;
    margin: 0;

    display: inline-flex;
    align-items: center;
    inline-size: 100%;
    box-sizing: border-box;
    padding-block: var(--space-inset-element-s);
    padding-inline-start: var(--space-inset-element-m);
    padding-inline-end: calc(var(--space-inset-element-m) * 2 + var(--size-control-s));
    min-block-size: var(--size-control-m);

    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
    color: var(--color-ink-strong);

    background-color: var(--color-surface-canvas);
    border: var(--border-width-hairline) solid var(--color-border-strong);
    border-radius: var(--radius-field);

    cursor: pointer;

    /* Chevron — CSS mask sized to the control */
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4 6 L8 10 L12 6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    background-repeat: no-repeat;
    background-position: right var(--space-inset-element-m) center;
    background-size: var(--space-inset-element-m);

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      color var(--motion-fast) var(--motion-easing-default);
  }

  .select:hover:not(:disabled) {
    border-color: var(--color-ink-strong);
  }

  .select:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-focus);
    border-color: var(--color-accent);
  }

  .select:disabled {
    cursor: not-allowed;
    opacity: 0.6;
    background-color: var(--color-surface-raised);
  }

  .select.-error,
  .select[aria-invalid="true"] {
    border-color: var(--color-danger);
  }

  .select.-error:focus-visible,
  .select[aria-invalid="true"]:focus-visible {
    outline-color: var(--color-danger);
    border-color: var(--color-danger);
  }

  /* Sizes */

  .select.-s {
    padding-block: var(--space-inset-element-s);
    padding-inline-start: var(--space-inset-element-s);
    min-block-size: var(--size-control-s);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .select.-l {
    padding-block: var(--space-inset-element-m);
    padding-inline-start: var(--space-inset-element-l);
    min-block-size: var(--size-control-l);
    font-family: var(--font-body-lead-family);
    font-size: var(--font-body-lead-size);
    font-weight: var(--font-body-lead-weight);
    line-height: var(--font-body-lead-line-height);
    letter-spacing: var(--font-body-lead-letter-spacing);
  }

  /* Native option styling is largely untouchable across browsers.
   * We do not attempt to style <option> elements — they fall back
   * to the OS dropdown.
   */
}


/* ===== ./src/elements/form/radio-group/radio-group.css ===== */
/*
 * Radio-group — element (form)
 *
 * Composite wrapper for a set of native <input type="radio">. The
 * radio inputs are visually hidden; CSS draws a custom radio indicator
 * on the surrounding label.
 *
 *   <fieldset class="radio-group">
 *     <legend class="radio-group__legend">Plan</legend>
 *     <label class="radio">
 *       <input type="radio" name="plan" class="radio__input" />
 *       <span class="radio__indicator"></span>
 *       <span class="radio__label">Free</span>
 *     </label>
 *     <label class="radio">
 *       <input type="radio" name="plan" class="radio__input" checked />
 *       <span class="radio__indicator"></span>
 *       <span class="radio__label">Pro</span>
 *     </label>
 *   </fieldset>
 */

@layer malevich.components {
  .radio-group {
    margin: 0;
    padding: 0;
    border: 0;

    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  .radio-group__legend {
    color: var(--color-ink-strong);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: 600;
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    margin-block-end: var(--space-gap-elements-s);
    padding: 0;
  }

  .radio-group.-horizontal {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-m);
  }

  /* Individual radio control — works standalone too */

  .radio {
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
    cursor: pointer;
    user-select: none;
    color: var(--color-ink-strong);

    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  .radio__input {
    position: absolute;
    inline-size: var(--border-width-hairline);
    block-size: var(--border-width-hairline);
    padding: 0;
    margin: calc(-1 * var(--border-width-hairline));
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  .radio__indicator {
    position: relative;
    flex-shrink: 0;
    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);

    background-color: var(--color-surface-canvas);
    border: var(--border-width-focus) solid var(--color-border-strong);
    border-radius: 50%;

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default);
  }

  .radio__indicator::after {
    content: "";
    position: absolute;
    inset: 0;
    margin: auto;
    inline-size: calc(var(--size-control-s) * 0.4);
    block-size: calc(var(--size-control-s) * 0.4);
    border-radius: 50%;
    background-color: var(--color-ink-inverse);
    transform: scale(0);
    transition: transform var(--motion-fast) var(--motion-easing-default);
  }

  .radio__input:checked ~ .radio__indicator {
    background-color: var(--color-accent);
    border-color: var(--color-accent);
  }

  .radio__input:checked ~ .radio__indicator::after {
    transform: scale(1);
  }

  .radio__input:focus-visible ~ .radio__indicator {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  .radio:has(.radio__input:disabled) {
    cursor: not-allowed;
    opacity: 0.5;
  }

  .radio__label {
    flex: 1;
  }
}


/* ===== ./src/elements/form/checkbox-group/checkbox-group.css ===== */
/*
 * Checkbox-group — element (form)
 *
 * Composite wrapper for a set of native <input type="checkbox">. Uses
 * the existing Checkbox component for individual items. The wrapper
 * just provides layout, legend, and a11y grouping.
 *
 *   <fieldset class="checkbox-group">
 *     <legend class="checkbox-group__legend">Notify me about</legend>
 *     <label class="checkbox">
 *       <input type="checkbox" class="checkbox__input" />
 *       <span class="checkbox__indicator"></span>
 *       <span class="checkbox__label">Comments</span>
 *     </label>
 *     <label class="checkbox">
 *       <input type="checkbox" class="checkbox__input" checked />
 *       <span class="checkbox__indicator"></span>
 *       <span class="checkbox__label">Mentions</span>
 *     </label>
 *   </fieldset>
 */

@layer malevich.components {
  .checkbox-group {
    margin: 0;
    padding: 0;
    border: 0;

    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  .checkbox-group__legend {
    color: var(--color-ink-strong);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: 600;
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    margin-block-end: var(--space-gap-elements-s);
    padding: 0;
  }

  .checkbox-group.-horizontal {
    flex-direction: row;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-m);
  }
}



/* Elements — display */
/* ===== ./src/elements/display/badge/badge.css ===== */
/*
 * Badge — element
 *
 * Inline status/category label. CSS-only — no JavaScript, no tweak slots.
 *
 *   <span class="badge">Default</span>
 *   <span class="badge -accent">Beta</span>
 *   <span class="badge -warning">Pending</span>
 */

@layer malevich.components {
  .badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border-radius: var(--radius-tag);

    font-family: var(--font-overline-family);
    font-size: var(--font-overline-size);
    font-weight: var(--font-overline-weight);
    line-height: var(--font-overline-line-height);
    letter-spacing: var(--font-overline-letter-spacing);

    text-transform: uppercase;
    white-space: nowrap;
    user-select: none;
  }

  /* ----- Variants ----- */

  .badge.-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
  }

  .badge.-danger {
    background-color: var(--color-danger);
    color: var(--color-ink-inverse);
  }

  /* Warning is bright — ink-strong text per brightness rule. */
  .badge.-warning {
    background-color: var(--color-warning);
    color: var(--color-ink-strong);
  }

  .badge.-success {
    background-color: var(--color-success);
    color: var(--color-ink-inverse);
  }

  .badge.-info {
    background-color: var(--color-info);
    color: var(--color-ink-inverse);
  }

  .badge.-muted {
    background-color: var(--color-border-muted);
    color: var(--color-ink-regular);
  }
}


/* ===== ./src/elements/display/alert/alert.css ===== */
/*
 * Alert — block
 *
 * Status message surface. Two style variants (rail default, -filled)
 * × four status variants (-info, -success, -warning, -danger).
 * CSS-only. The rail variant uses ADR-0003 Pattern 2 (currentColor)
 * for the left stripe.
 *
 *   <div role="alert" class="alert -warning">
 *     <span class="alert__icon" aria-hidden="true">⚠</span>
 *     <div>
 *       <p class="alert__title">Heads up</p>
 *       <p class="alert__body">Your trial expires in 3 days.</p>
 *     </div>
 *   </div>
 */

@layer malevich.components {
  .alert {
    position: relative;
    display: flex;
    align-items: flex-start;
    gap: var(--space-gap-elements-m);

    padding: var(--space-inset-block-s) var(--space-inset-element-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--color-border-muted);
    border-radius: var(--radius-card);
  }

  /* Rail (default style): left stripe inherits currentColor. The
     status variant sets color, the rail picks it up. */
  .alert::before {
    content: "";
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    width: var(--border-width-emphasis);
    background-color: currentColor;
    border-start-start-radius: inherit;
    border-end-start-radius: inherit;
  }

  /* ----- Subparts ----- */

  .alert__icon {
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: currentColor;
  }

  .alert__title {
    margin: 0;
    font-family: var(--font-heading-subsection-family);
    font-size: var(--font-heading-subsection-size);
    font-weight: var(--font-heading-subsection-weight);
    line-height: var(--font-heading-subsection-line-height);
    letter-spacing: var(--font-heading-subsection-letter-spacing);
    color: var(--color-ink-strong);
  }

  .alert__body {
    margin: 0;
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    color: var(--color-ink-regular);
  }

  /* ----- Status variants (rail default) ----- */

  .alert.-info    { color: var(--color-info); }
  .alert.-success { color: var(--color-success); }
  .alert.-warning { color: var(--color-warning); }
  .alert.-danger  { color: var(--color-danger); }

  /* ----- Filled variant ----- *
   * Background + text tokens encode the brightness rule. Each status
   * pairs a tier-3 background with its tier-3 text token; the rail
   * stripe collapses (same color as background). */

  .alert.-filled {
    border-color: transparent;
  }
  .alert.-filled::before {
    background-color: transparent;
  }
  .alert.-filled .alert__title,
  .alert.-filled .alert__body {
    color: inherit;
  }

  .alert.-filled.-info {
    background-color: var(--alert-background-info);
    color: var(--alert-text-info);
  }
  .alert.-filled.-success {
    background-color: var(--alert-background-success);
    color: var(--alert-text-success);
  }
  .alert.-filled.-warning {
    background-color: var(--alert-background-warning);
    color: var(--alert-text-warning);
  }
  .alert.-filled.-danger {
    background-color: var(--alert-background-danger);
    color: var(--alert-text-danger);
  }
}


/* ===== ./src/elements/display/code/code.css ===== */
/*
 * Code (inline) — element (display)
 *
 * Inline code styling. Uses native <code>. Copyable by default via
 * the copyable behavior modifier — opt out with data-copyable="false".
 *
 *   <code class="code">npm install malevich</code>
 *   <code class="code" data-copyable="false">no copy button</code>
 *   <code class="code -accent">highlighted</code>
 */

@layer malevich.components {
  .code {
    display: inline-flex;
    align-items: center;

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);

    border: var(--border-width-hairline) solid var(--color-border-muted);
    border-radius: var(--radius-tag);

    font-family: var(--font-mono-m-family);
    font-size: var(--font-mono-m-size);
    font-weight: var(--font-mono-m-weight);
    line-height: var(--font-mono-m-line-height);
    letter-spacing: var(--font-mono-m-letter-spacing);

    white-space: nowrap;
  }

  /* Copy button slot reservation. When data-copyable="true", the
   * runtime appends a button positioned by the shared copyable CSS.
   * The padding-inline-end below leaves room so long code text
   * doesn't slide under the button on hover.
   */
  .code[data-copyable="true"] {
    padding-inline-end: var(--space-inset-element-l);
  }

  .code.-accent {
    background-color: var(--color-accent-muted);
    color: var(--color-accent-strong);
    border-color: var(--color-accent-muted);
  }

  .code.-danger {
    background-color: var(--color-surface-raised);
    color: var(--color-danger);
    border-color: var(--color-danger);
  }

  .code.-muted {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-regular);
    border-color: var(--color-border-muted);
  }
}


/* ===== ./src/elements/display/tag/tag.css ===== */
/*
 * Tag — element (display)
 *
 * Inline metadata pill. Like Badge but optionally dismissible. The
 * dismiss button is an opt-in <button> inside the tag; tag dismiss
 * logic is the consumer's responsibility (remove the DOM node from a
 * click handler).
 *
 *   <span class="tag">Documentation</span>
 *   <span class="tag -accent">Featured</span>
 *
 *   <span class="tag">
 *     React
 *     <button type="button" class="tag__dismiss" aria-label="Remove React">×</button>
 *   </span>
 */

@layer malevich.components {
  .tag {
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);

    border: var(--border-width-hairline) solid var(--color-border-muted);
    border-radius: var(--radius-pill);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: 500;
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    white-space: nowrap;
    max-inline-size: 100%;
  }

  .tag__dismiss {
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 0;
    padding: 0;
    margin: 0;
    cursor: pointer;

    display: inline-flex;
    align-items: center;
    justify-content: center;

    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);
    margin-inline-end: calc(-1 * var(--space-inset-element-s));

    color: var(--color-ink-subtle);
    border-radius: 50%;
    font-family: inherit;
    font-size: inherit;
    line-height: 1;

    transition: color var(--motion-fast) var(--motion-easing-default),
                background-color var(--motion-fast) var(--motion-easing-default);
  }

  .tag__dismiss:hover {
    color: var(--color-ink-strong);
    background-color: var(--color-surface-canvas);
  }

  .tag__dismiss:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  /* Variants */

  .tag.-accent {
    background-color: var(--color-accent-muted);
    color: var(--color-accent-strong);
    border-color: var(--color-accent-muted);
  }

  .tag.-danger {
    background-color: var(--color-surface-raised);
    color: var(--color-danger);
    border-color: var(--color-danger);
  }

  .tag.-success {
    background-color: var(--color-surface-raised);
    color: var(--color-success);
    border-color: var(--color-success);
  }

  .tag.-muted {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-regular);
  }

  .tag.-s {
    padding-block: 0;
    padding-inline: var(--space-inset-element-s);
    font-size: var(--font-caption-size);
  }
}


/* ===== ./src/elements/display/avatar-group/avatar-group.css ===== */
/*
 * Avatar-group — element (display)
 *
 * Overlapping stack of avatars. Used to show participants, owners, or
 * any collection of people associated with a thing. CSS-only.
 *
 *   <div class="avatar-group">
 *     <span class="avatar">A</span>
 *     <span class="avatar">B</span>
 *     <span class="avatar">C</span>
 *     <span class="avatar -overflow">+5</span>
 *   </div>
 */

@layer malevich.components {
  .avatar-group {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.4);

    display: inline-flex;
    align-items: center;
    isolation: isolate;
  }

  .avatar-group > .avatar {
    border: var(--border-width-emphasis) solid var(--color-surface-canvas);
    position: relative;
    margin-inline-start: calc(-1 * var(--avatar-group-overlap));
  }

  .avatar-group > .avatar:first-child {
    margin-inline-start: 0;
  }

  /* Later siblings stack visually below the earlier ones — hover the
   * earlier ones to read them clearly. Z-index decreases along the
   * row so the first avatar sits on top.
   */
  .avatar-group > .avatar:nth-child(1) { z-index: 6; }
  .avatar-group > .avatar:nth-child(2) { z-index: 5; }
  .avatar-group > .avatar:nth-child(3) { z-index: 4; }
  .avatar-group > .avatar:nth-child(4) { z-index: 3; }
  .avatar-group > .avatar:nth-child(5) { z-index: 2; }
  .avatar-group > .avatar:nth-child(6) { z-index: 1; }

  /* Overflow indicator: e.g. "+5" appended after visible avatars */
  .avatar-group > .avatar.-overflow {
    background-color: var(--color-surface-raised);
    color: var(--color-ink-regular);
  }

  /* Variants */

  .avatar-group.-tight {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.6);
  }

  .avatar-group.-loose {
    --avatar-group-overlap: calc(var(--size-control-m) * 0.15);
  }

  /* When sitting on a non-canvas surface, expose the border tone via
   * a custom property the author can override. Defaults to canvas.
   */
  .avatar-group.-on-raised > .avatar {
    border-color: var(--color-surface-raised);
  }
}


/* ===== ./src/elements/display/tags-group/tags-group.css ===== */
/*
 * Tags-group — element (display)
 *
 * Horizontal/wrapping collection of Tags with runtime-driven overflow:
 * authors specify data-max-rows, the runtime measures wrapped layout
 * and hides tags beyond the row count, appending a "+N more" Tag at
 * the end.
 *
 *   <div class="tags-group" data-max-rows="2">
 *     <span class="tag">React</span>
 *     <span class="tag">TypeScript</span>
 *     ... many tags ...
 *   </div>
 *
 * Without data-max-rows the group simply wraps without trimming.
 */

@layer malevich.components {
  .tags-group {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-s);
  }

  /* While the runtime is measuring, keep contents in DOM but visually
   * accurate. Hidden overflow tags get a data-tags-hidden marker.
   */
  .tags-group [data-tags-hidden="true"] {
    display: none;
  }

  /* The +N overflow tag is appended by the runtime; consumers can also
   * write it manually for the static case.
   */
  .tags-group__overflow {
    /* Inherits .tag styles when also given the .tag class; this rule
     * is a no-op placeholder for authors who want extra targeting.
     */
  }
}



/* Blocks */
/* ===== ./src/blocks/card/card.css ===== */
/*
 * Card — block
 *
 * Grouping surface for related content. CSS-only — no runtime, no
 * tweak slots. Subparts are plain DOM elements with BEM element
 * classes.
 *
 *   <article class="card">
 *     <header class="card__header"><h3>Title</h3></header>
 *     <div class="card__body"><p>Body.</p></div>
 *     <footer class="card__footer">
 *       <button class="button -accent">Action</button>
 *     </footer>
 *   </article>
 */

@layer malevich.components {
  .card {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-m);

    padding: var(--card-padding);

    background-color: var(--card-background);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--card-border);
    border-radius: var(--radius-card);

    transition:
      background-color var(--motion-fast) var(--motion-easing-default),
      border-color var(--motion-fast) var(--motion-easing-default),
      box-shadow var(--motion-fast) var(--motion-easing-default);
  }

  /* ----- Subparts ----- */

  .card__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-gap-elements-s);
  }

  .card__body {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  .card__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-gap-elements-s);
  }

  /* ----- Variants ----- */

  .card.-feature {
    background-color: var(--card-background-feature);
  }
}


/* ===== ./src/blocks/accordion/accordion.css ===== */
/*
 * Accordion — block
 *
 * Built on native <details>/<summary> for keyboard, focus, and screen
 * reader support out of the box. CSS-only — no runtime, no JavaScript.
 *
 * Per ADR-0007 + answered design question: each <details> is
 * independent (no single-open coordination). If an author wants
 * single-open behavior, they add their own JS.
 *
 *   <section class="accordion">
 *     <details class="accordion__item">
 *       <summary class="accordion__summary">Section 1</summary>
 *       <div class="accordion__body">…</div>
 *     </details>
 *     <details class="accordion__item">
 *       <summary class="accordion__summary">Section 2</summary>
 *       <div class="accordion__body">…</div>
 *     </details>
 *   </section>
 */

@layer malevich.components {
  .accordion {
    display: flex;
    flex-direction: column;
    border: var(--border-width-hairline) solid var(--color-border-muted);
    border-radius: var(--radius-card);
    background-color: var(--color-surface-raised);
    overflow: hidden;
  }

  .accordion__item {
    border-block-end: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .accordion__item:last-child {
    border-block-end: 0;
  }

  .accordion__summary {
    list-style: none;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-block-m);
    padding-inline: var(--space-inset-block-m);

    color: var(--color-ink-strong);
    font-family: var(--font-heading-subsection-family);
    font-size: var(--font-heading-subsection-size);
    font-weight: var(--font-heading-subsection-weight);
    line-height: var(--font-heading-subsection-line-height);
    letter-spacing: var(--font-heading-subsection-letter-spacing);

    transition: background-color var(--motion-fast) var(--motion-easing-default);
  }

  /* Hide the native disclosure triangle across browsers */
  .accordion__summary::-webkit-details-marker {
    display: none;
  }

  .accordion__summary::marker {
    content: "";
  }

  .accordion__summary:hover {
    background-color: var(--color-surface-canvas);
  }

  .accordion__summary:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: calc(-1 * var(--border-width-focus));
  }

  /* Custom chevron indicator. Rotates when the parent <details> is open. */
  .accordion__summary::after {
    content: "";
    flex-shrink: 0;
    inline-size: var(--space-inset-element-m);
    block-size: var(--space-inset-element-m);

    background-color: currentColor;
    /* SVG-as-mask: chevron pointing down */
    mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4 6 L8 10 L12 6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    -webkit-mask-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'><path d='M4 6 L8 10 L12 6' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg>");
    mask-size: contain;
    -webkit-mask-size: contain;
    mask-repeat: no-repeat;
    -webkit-mask-repeat: no-repeat;
    mask-position: center;
    -webkit-mask-position: center;

    transition: transform var(--motion-fast) var(--motion-easing-default);
  }

  .accordion__item[open] > .accordion__summary::after {
    transform: rotate(180deg);
  }

  .accordion__body {
    padding-block-start: 0;
    padding-block-end: var(--space-inset-block-m);
    padding-inline: var(--space-inset-block-m);

    color: var(--color-ink-regular);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  /* Variants */
  .accordion.-flush {
    border: 0;
    border-radius: 0;
    background-color: transparent;
  }

  .accordion.-flush .accordion__item {
    border-block-end: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .accordion.-flush .accordion__item:last-child {
    border-block-end: 0;
  }

  @media (prefers-reduced-motion: reduce) {
    .accordion__summary,
    .accordion__summary::after {
      transition: none;
    }
  }
}


/* ===== ./src/blocks/breadcrumb/breadcrumb.css ===== */
/*
 * Breadcrumb — block
 *
 * Hierarchical navigation. Uses <nav> + <ol> for semantic correctness.
 * Separator is a chevron (›) rendered via CSS ::before on every item
 * except the first, marked aria-hidden by being a CSS pseudo-element.
 * CSS-only.
 *
 *   <nav class="breadcrumb" aria-label="Breadcrumb">
 *     <ol class="breadcrumb__list">
 *       <li class="breadcrumb__item"><a href="/" class="breadcrumb__link">Home</a></li>
 *       <li class="breadcrumb__item"><a href="/docs" class="breadcrumb__link">Docs</a></li>
 *       <li class="breadcrumb__item" aria-current="page">Components</li>
 *     </ol>
 *   </nav>
 */

@layer malevich.components {
  .breadcrumb {
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    color: var(--color-ink-subtle);
  }

  .breadcrumb__list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-gap-elements-s);
  }

  .breadcrumb__item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
  }

  /* Chevron separator. Rendered before every item except the first.
   * aria-hidden by virtue of being a pseudo-element (not in DOM).
   */
  .breadcrumb__item:not(:first-child)::before {
    content: "›";
    color: var(--color-ink-subtle);
    font-weight: 400;
    user-select: none;
  }

  .breadcrumb__link {
    color: var(--color-ink-regular);
    text-decoration: none;
    border-radius: var(--radius-tag);
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    transition: color var(--motion-fast) var(--motion-easing-default);
  }

  .breadcrumb__link:hover {
    color: var(--color-ink-strong);
    text-decoration: underline;
  }

  .breadcrumb__link:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  /* The current-page item (aria-current="page") gets stronger styling */
  .breadcrumb__item[aria-current="page"] {
    color: var(--color-ink-strong);
    font-weight: 600;
  }

  /* Variants */

  .breadcrumb.-strong {
    color: var(--color-ink-regular);
  }
  .breadcrumb.-strong .breadcrumb__link {
    color: var(--color-ink-strong);
  }
  .breadcrumb.-strong .breadcrumb__item[aria-current="page"] {
    color: var(--color-accent);
  }
}


/* ===== ./src/blocks/state/state.css ===== */
/*
 * State — block
 *
 * A self-contained block for empty / loading / error / success states.
 * Used inside cards, sections, or panels when content is unavailable
 * or operation feedback should fill the surface. CSS-only.
 *
 *   <section class="state" data-state="empty">
 *     <div class="state__icon">📭</div>
 *     <h3 class="state__title">No projects yet</h3>
 *     <p class="state__description">Create your first project to get started.</p>
 *     <div class="state__action">
 *       <button class="button -primary">New project</button>
 *     </div>
 *   </section>
 */

@layer malevich.components {
  .state {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-block-l);
    padding-inline: var(--space-inset-block-l);

    border-radius: var(--radius-card);
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);
  }

  .state__icon {
    inline-size: var(--size-control-xl);
    block-size: var(--size-control-xl);
    display: flex;
    align-items: center;
    justify-content: center;

    color: var(--color-ink-subtle);

    font-family: var(--font-display-statement-family);
    font-size: var(--font-display-statement-size);
    font-weight: var(--font-display-statement-weight);
  }

  .state__title {
    margin: 0;

    font-family: var(--font-heading-title-family);
    font-size: var(--font-heading-title-size);
    font-weight: var(--font-heading-title-weight);
    line-height: var(--font-heading-title-line-height);
    letter-spacing: var(--font-heading-title-letter-spacing);

    color: var(--color-ink-strong);
  }

  .state__description {
    margin: 0;
    max-inline-size: 48ch;

    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);

    color: var(--color-ink-regular);
  }

  .state__action {
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
    margin-block-start: var(--space-gap-elements-s);
  }

  /* Data-state hooks for icon color affordances. The icon's color
   * follows the data-state so authors can render a single icon and
   * have it tint correctly.
   */

  .state[data-state="empty"] .state__icon {
    color: var(--color-ink-subtle);
  }

  .state[data-state="loading"] .state__icon {
    color: var(--color-accent);
  }

  .state[data-state="error"] .state__icon {
    color: var(--color-danger);
  }

  .state[data-state="error"] .state__title {
    color: var(--color-danger);
  }

  .state[data-state="success"] .state__icon {
    color: var(--color-success);
  }

  .state[data-state="success"] .state__title {
    color: var(--color-success);
  }

  /* Variants */

  .state.-bordered {
    border: var(--border-width-hairline) solid var(--color-border-muted);
    background-color: var(--color-surface-raised);
  }

  .state.-compact {
    padding-block: var(--space-inset-block-m);
    padding-inline: var(--space-inset-block-m);
    gap: var(--space-gap-elements-s);
  }

  .state.-compact .state__title {
    font-family: var(--font-heading-section-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-heading-section-weight);
    line-height: var(--font-heading-section-line-height);
    letter-spacing: var(--font-heading-section-letter-spacing);
  }
}


/* ===== ./src/blocks/quote-block/quote-block.css ===== */
/*
 * Quote-block — block
 *
 * Pull-quote / blockquote with optional attribution. Native
 * <blockquote> for semantics. CSS-only.
 *
 *   <blockquote class="quote-block">
 *     <p class="quote-block__body">
 *       The standards committee should not have to think.
 *     </p>
 *     <footer class="quote-block__attribution">
 *       — <cite class="quote-block__cite">Alan Kay</cite>
 *     </footer>
 *   </blockquote>
 */

@layer malevich.components {
  .quote-block {
    margin: 0;
    padding-block: var(--space-inset-block-m);
    padding-inline-start: var(--space-inset-block-m);
    padding-inline-end: var(--space-inset-block-m);

    border-inline-start: var(--border-width-emphasis) solid var(--color-accent);
    background-color: transparent;
    color: var(--color-ink-strong);
  }

  .quote-block__body {
    margin: 0;
    font-family: var(--font-heading-section-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-heading-section-weight);
    line-height: var(--font-heading-section-line-height);
    letter-spacing: var(--font-heading-section-letter-spacing);
  }

  .quote-block__body + .quote-block__body {
    margin-block-start: var(--space-gap-elements-m);
  }

  .quote-block__attribution {
    margin-block-start: var(--space-gap-elements-m);

    color: var(--color-ink-regular);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);

    font-style: normal;
  }

  .quote-block__cite {
    font-style: normal;
    font-weight: 600;
    color: var(--color-ink-strong);
  }

  /* Variants */

  .quote-block.-card {
    border-inline-start: 0;
    background-color: var(--color-surface-raised);
    border-radius: var(--radius-card);
    padding-inline: var(--space-inset-block-l);
  }

  .quote-block.-pull {
    border-inline-start: 0;
    text-align: center;
    padding-block: var(--space-inset-block-l);
  }

  .quote-block.-pull .quote-block__body {
    font-family: var(--font-heading-title-family);
    font-size: var(--font-heading-title-size);
    font-weight: var(--font-heading-title-weight);
    line-height: var(--font-heading-title-line-height);
    letter-spacing: var(--font-heading-title-letter-spacing);
  }

  .quote-block.-muted {
    border-inline-start-color: var(--color-border-muted);
    color: var(--color-ink-regular);
  }
}


/* ===== ./src/blocks/carousel/carousel.css ===== */
/*
 * Carousel — block
 *
 * Minimal scope per the answered design question: scroll-snap track,
 * prev/next buttons, pagination dots. No autoplay, no loop, no fade
 * in v1.0.
 *
 *   <section class="carousel">
 *     <div class="carousel__viewport">
 *       <div class="carousel__track">
 *         <div class="carousel__slide">…</div>
 *         <div class="carousel__slide">…</div>
 *         <div class="carousel__slide">…</div>
 *       </div>
 *     </div>
 *     <div class="carousel__controls">
 *       <button class="carousel__prev" aria-label="Previous">‹</button>
 *       <ol class="carousel__dots" role="tablist" aria-label="Slide">
 *         <li><button class="carousel__dot" aria-selected="true" aria-label="Slide 1"></button></li>
 *         <li><button class="carousel__dot" aria-label="Slide 2"></button></li>
 *         <li><button class="carousel__dot" aria-label="Slide 3"></button></li>
 *       </ol>
 *       <button class="carousel__next" aria-label="Next">›</button>
 *     </div>
 *   </section>
 */

@layer malevich.components {
  .carousel {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-m);

    inline-size: 100%;
    box-sizing: border-box;
  }

  .carousel__viewport {
    overflow: hidden;
    inline-size: 100%;
  }

  .carousel__track {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(var(--carousel-slide-min), 1fr);
    gap: var(--space-gap-elements-m);

    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scroll-behavior: smooth;

    /* Hide scrollbar — carousel uses buttons / dots / native swipe.
     * Authors who want a visible scrollbar override locally.
     */
    scrollbar-width: none;
  }
  .carousel__track::-webkit-scrollbar {
    display: none;
  }

  .carousel__slide {
    scroll-snap-align: start;
    scroll-snap-stop: always;
    min-inline-size: 0;
  }

  /* Controls row */

  .carousel__controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-gap-elements-s);
  }

  .carousel__prev,
  .carousel__next {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    padding: 0;
    background: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: 50%;
    inline-size: var(--size-control-m);
    block-size: var(--size-control-m);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    flex-shrink: 0;

    transition: background-color var(--motion-fast) var(--motion-easing-default);
  }

  .carousel__prev:hover:not(:disabled),
  .carousel__next:hover:not(:disabled) {
    background-color: var(--color-surface-canvas);
  }

  .carousel__prev:focus-visible,
  .carousel__next:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  .carousel__prev:disabled,
  .carousel__next:disabled {
    cursor: not-allowed;
    opacity: 0.5;
  }

  .carousel__dots {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
  }

  .carousel__dot {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    padding: 0;
    background: var(--color-border-strong);
    border: 0;
    cursor: pointer;
    border-radius: 50%;
    inline-size: var(--space-inset-element-s);
    block-size: var(--space-inset-element-s);

    transition: background-color var(--motion-fast) var(--motion-easing-default);
  }

  .carousel__dot[aria-selected="true"] {
    background-color: var(--color-accent);
  }

  .carousel__dot:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  @media (prefers-reduced-motion: reduce) {
    .carousel__track {
      scroll-behavior: auto;
    }
  }
}


/* ===== ./src/blocks/code-block/code-block.css ===== */
/*
 * Code-block — block
 *
 * Multi-line code surface with optional syntax highlighting (via
 * registerHighlighter), language label, line numbers, and copy
 * button (via the copyable behavior modifier, default-on per the
 * v1.0 master diff §4.8).
 *
 * Per the answered design question:
 *   highlight(code, lang) → string HTML  (adapter pattern, like Icon)
 *
 *   <pre class="code-block" data-lang="ts" data-copyable="true">
 *     <code>const x = 1;</code>
 *   </pre>
 *
 *   <pre class="code-block" data-lang="bash" data-line-numbers="true">
 *     <code>pnpm install
 *     pnpm dev</code>
 *   </pre>
 */

@layer malevich.components {
  .code-block {
    --code-block-counter: 1;

    position: relative;
    display: block;
    margin: 0;

    padding-block: var(--space-inset-block-m);
    padding-inline: var(--space-inset-block-m);
    /* Reserve room for the copy button (per .malevich-copyable__button position) */
    padding-inline-end: calc(var(--space-inset-block-m) + var(--size-control-s));

    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);

    border: var(--border-width-hairline) solid var(--color-border-muted);
    border-radius: var(--radius-card);

    overflow-x: auto;
  }

  /* The <code> child gets the mono typography */
  .code-block > code,
  .code-block code {
    display: block;
    font-family: var(--font-mono-m-family);
    font-size: var(--font-mono-m-size);
    font-weight: var(--font-mono-m-weight);
    line-height: var(--font-mono-m-line-height);
    letter-spacing: var(--font-mono-m-letter-spacing);
    color: inherit;
    background: transparent;
    padding: 0;
    border: 0;
    white-space: pre;
  }

  /* ---- Language label ---- */
  .code-block[data-lang]::before {
    content: attr(data-lang);
    position: absolute;
    inset-block-start: var(--space-inset-element-s);
    inset-inline-start: var(--space-inset-element-s);

    color: var(--color-ink-subtle);
    font-family: var(--font-overline-family);
    font-size: var(--font-overline-size);
    font-weight: var(--font-overline-weight);
    line-height: var(--font-overline-line-height);
    letter-spacing: var(--font-overline-letter-spacing);
    text-transform: uppercase;
    user-select: none;
    pointer-events: none;
  }

  /* Push code body down to make room for the language label */
  .code-block[data-lang] {
    padding-block-start: calc(var(--space-inset-block-m) + var(--space-inset-element-m));
  }

  /* ---- Line numbers via CSS counter ----
   *
   * Authors break code into one <span class="code-block__line"> per
   * line OR rely on the runtime to split textContent. Without the
   * runtime, line-numbers fall back to a single counter on the
   * <code> element (the whole block reads as line 1).
   */

  .code-block[data-line-numbers="true"] > code,
  .code-block[data-line-numbers="true"] code {
    counter-reset: code-block-line;
  }

  .code-block[data-line-numbers="true"] .code-block__line {
    display: block;
    counter-increment: code-block-line;
    padding-inline-start: var(--space-inset-section-s);
    position: relative;
  }

  .code-block[data-line-numbers="true"] .code-block__line::before {
    content: counter(code-block-line);
    position: absolute;
    inset-inline-start: 0;
    color: var(--color-ink-subtle);
    user-select: none;
    text-align: end;
    min-inline-size: var(--space-inset-element-l);
    font-variant-numeric: tabular-nums;
  }

  /* ---- Variants ---- */

  .code-block.-flat {
    border: 0;
    background-color: var(--color-surface-raised);
  }

  .code-block.-on-inverse {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
    border-color: var(--color-ink-strong);
  }
}



/* Sections */
/* ===== ./src/sections/block-layout/block-layout.css ===== */
/*
 * Block-layout — section
 *
 * Single-column container with constrained measure. Per the answered
 * design question (container queries-first): no global @media; the
 * layout primitive sets a max-inline-size that the author picks via
 * data-size. Surrounding context (a centered Section, a sidebar
 * region) constrains naturally.
 *
 *   <section class="block-layout">
 *     <h1>Article title</h1>
 *     <p>…</p>
 *   </section>
 *
 *   <section class="block-layout" data-size="narrow">…</section>
 *   <section class="block-layout" data-size="wide">…</section>
 */

@layer malevich.components {
  .block-layout {
    inline-size: 100%;
    max-inline-size: var(--block-layout-measure);
    margin-inline: auto;

    padding-block: var(--space-inset-section-m);
    padding-inline: var(--space-inset-section-m);

    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-m);

    box-sizing: border-box;
  }

  .block-layout[data-size="narrow"] {
    max-inline-size: var(--block-layout-measure-narrow);
  }

  .block-layout[data-size="wide"] {
    max-inline-size: var(--block-layout-measure-wide);
  }

  .block-layout[data-size="full"] {
    max-inline-size: none;
  }

  /* Surface variants */
  .block-layout.-on-raised {
    background-color: var(--color-surface-raised);
  }
  .block-layout.-on-canvas {
    background-color: var(--color-surface-canvas);
  }
}


/* ===== ./src/sections/split-layout/split-layout.css ===== */
/*
 * Split-layout — section
 *
 * Two-panel layout that collapses to a single column when the
 * container width falls below the panel-min threshold. Container-
 * aware via grid auto-fit + minmax — no global @media queries.
 *
 *   <section class="split-layout">
 *     <div>Left panel</div>
 *     <div>Right panel</div>
 *   </section>
 *
 *   <section class="split-layout" data-ratio="1:2">
 *     <div>Narrow side</div>
 *     <div>Wide side</div>
 *   </section>
 */

@layer malevich.components {
  .split-layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--split-layout-panel-min), 1fr));
    gap: var(--space-gap-blocks-l);

    padding-block: var(--space-inset-section-m);
    padding-inline: var(--space-inset-section-m);

    inline-size: 100%;
    box-sizing: border-box;
  }

  /* Ratio variants — once both panels fit, the second token controls
   * the split. Below the panel-min threshold, auto-fit + minmax(1fr)
   * collapses; above it, the explicit ratio takes effect via the
   * declared columns.
   */

  .split-layout[data-ratio="1:1"] {
    grid-template-columns: repeat(auto-fit, minmax(var(--split-layout-panel-min), 1fr));
  }

  .split-layout[data-ratio="1:2"] {
    grid-template-columns: minmax(var(--split-layout-panel-min), 1fr)
                           minmax(var(--split-layout-panel-min), 2fr);
  }

  .split-layout[data-ratio="2:1"] {
    grid-template-columns: minmax(var(--split-layout-panel-min), 2fr)
                           minmax(var(--split-layout-panel-min), 1fr);
  }

  .split-layout[data-ratio="1:3"] {
    grid-template-columns: minmax(var(--split-layout-panel-min), 1fr)
                           minmax(var(--split-layout-panel-min), 3fr);
  }

  .split-layout[data-ratio="3:1"] {
    grid-template-columns: minmax(var(--split-layout-panel-min), 3fr)
                           minmax(var(--split-layout-panel-min), 1fr);
  }

  /* Alignment */
  .split-layout.-center {
    align-items: center;
  }

  .split-layout.-stretch {
    align-items: stretch;
  }

  .split-layout.-baseline {
    align-items: baseline;
  }
}


/* ===== ./src/sections/grid-layout/grid-layout.css ===== */
/*
 * Grid-layout — section
 *
 * N-column grid that adapts via auto-fit + minmax. Container-aware:
 * the cell-min token controls when columns merge as the container
 * shrinks. data-cols pins a maximum column count.
 *
 *   <section class="grid-layout">
 *     <div>Cell 1</div>
 *     <div>Cell 2</div>
 *     <div>Cell 3</div>
 *   </section>
 *
 *   <section class="grid-layout" data-cols="4">
 *     <!-- max 4 cols, auto-collapse below -->
 *   </section>
 */

@layer malevich.components {
  .grid-layout {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--grid-layout-cell-min), 1fr));
    gap: var(--space-gap-blocks-m);

    padding-block: var(--space-inset-section-m);
    padding-inline: var(--space-inset-section-m);

    inline-size: 100%;
    box-sizing: border-box;
  }

  /* data-cols pins a MAX column count by combining auto-fit with a
   * larger min via the standard "grid-line-trick": specifying a
   * second column-template-columns with explicit fr. We use the
   * simpler pattern: data-cols overrides the auto-fit with explicit
   * grid-template-columns above the cell-min, falls back below.
   */

  .grid-layout[data-cols="2"] {
    grid-template-columns: repeat(auto-fit, minmax(max(var(--grid-layout-cell-min), calc(50% - var(--space-gap-blocks-m))), 1fr));
  }

  .grid-layout[data-cols="3"] {
    grid-template-columns: repeat(auto-fit, minmax(max(var(--grid-layout-cell-min), calc(33.33% - var(--space-gap-blocks-m))), 1fr));
  }

  .grid-layout[data-cols="4"] {
    grid-template-columns: repeat(auto-fit, minmax(max(var(--grid-layout-cell-min), calc(25% - var(--space-gap-blocks-m))), 1fr));
  }

  .grid-layout[data-cols="6"] {
    grid-template-columns: repeat(auto-fit, minmax(max(var(--grid-layout-cell-min), calc(16.66% - var(--space-gap-blocks-m))), 1fr));
  }

  /* Gap variants */
  .grid-layout.-tight {
    gap: var(--space-gap-elements-m);
  }

  .grid-layout.-loose {
    gap: var(--space-gap-sections-s);
  }
}


/* ===== ./src/sections/stack-layout/stack-layout.css ===== */
/*
 * Stack-layout — section
 *
 * Vertical or horizontal stack with consistent gap. Simpler than
 * Split/Grid — no responsive collapse, just a flex container with
 * tokenized gap.
 *
 *   <section class="stack-layout">
 *     <div>One</div>
 *     <div>Two</div>
 *     <div>Three</div>
 *   </section>
 *
 *   <section class="stack-layout" data-direction="horizontal">…</section>
 *   <section class="stack-layout" data-gap="s">…</section>
 */

@layer malevich.components {
  .stack-layout {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-section-m);
    padding-inline: var(--space-inset-section-m);

    inline-size: 100%;
    box-sizing: border-box;
  }

  /* Direction */
  .stack-layout[data-direction="horizontal"] {
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
  }

  /* Gap variants — pick from semantic gap tokens */
  .stack-layout[data-gap="s"] {
    gap: var(--space-gap-elements-s);
  }
  .stack-layout[data-gap="m"] {
    gap: var(--space-gap-elements-m);
  }
  .stack-layout[data-gap="l"] {
    gap: var(--space-gap-blocks-m);
  }
  .stack-layout[data-gap="xl"] {
    gap: var(--space-gap-blocks-l);
  }

  /* Alignment along the cross-axis */
  .stack-layout.-start {
    align-items: flex-start;
  }
  .stack-layout.-center {
    align-items: center;
  }
  .stack-layout.-end {
    align-items: flex-end;
  }
  .stack-layout.-stretch {
    align-items: stretch;
  }

  /* Justify along the main-axis (horizontal direction only) */
  .stack-layout[data-direction="horizontal"].-between {
    justify-content: space-between;
  }
  .stack-layout[data-direction="horizontal"].-around {
    justify-content: space-around;
  }
  .stack-layout[data-direction="horizontal"].-evenly {
    justify-content: space-evenly;
  }
}


/* ===== ./src/sections/hero/hero.css ===== */
/*
 * Hero — section
 *
 * Above-the-fold page region for landing pages. Per v1-master-diff §2.1
 * with the answered design question (start with Hero + CTA in v1.0):
 * four authored patterns via data-pattern.
 *
 *   <section class="hero" data-pattern="standard">
 *     <div class="hero__eyebrow">v1.0 launch</div>
 *     <h1 class="hero__title">A semantic design system.</h1>
 *     <p class="hero__lede">For humans and AI agents.</p>
 *     <div class="hero__actions">
 *       <a href="#" class="button -primary">Get started</a>
 *       <a href="#" class="button -ghost">Read the manifesto</a>
 *     </div>
 *   </section>
 *
 * Patterns:
 *   standard  — eyebrow + title + lede + actions, left-aligned (default)
 *   centered  — same, center-aligned
 *   split     — content on one side, slot for visual on the other; the
 *               grid auto-collapses to a single column on narrow viewports
 *               via auto-fit + a hero-split-min tier-3 token.
 *   minimal   — title only, large display typography
 */

@layer malevich.components {
  .hero {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-section-l);
    padding-inline: var(--space-inset-section-m);

    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);

    inline-size: 100%;
    box-sizing: border-box;
  }

  .hero > * {
    max-inline-size: var(--hero-max-content);
  }

  .hero__eyebrow {
    color: var(--color-accent);
    font-family: var(--font-overline-family);
    font-size: var(--font-overline-size);
    font-weight: var(--font-overline-weight);
    line-height: var(--font-overline-line-height);
    letter-spacing: var(--font-overline-letter-spacing);
    text-transform: uppercase;
  }

  .hero__title {
    margin: 0;
    color: var(--color-ink-strong);

    /* Uses heading-hero typography. v0.2.0 will introduce a
     * dedicated display.hero fluid token (clamp); until then we
     * consume the heading-hero size which is the closest semantic.
     */
    font-family: var(--font-display-hero-family);
    font-size: var(--font-display-hero-size);
    font-weight: var(--font-display-hero-weight);
    line-height: var(--font-display-hero-line-height);
    letter-spacing: var(--font-display-hero-letter-spacing);
  }

  .hero__lede {
    margin: 0;
    color: var(--color-ink-regular);
    font-family: var(--font-body-lead-family);
    font-size: var(--font-body-lead-size);
    font-weight: var(--font-body-lead-weight);
    line-height: var(--font-body-lead-line-height);
    letter-spacing: var(--font-body-lead-letter-spacing);
  }

  .hero__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-gap-elements-s);
    margin-block-start: var(--space-gap-elements-s);
  }

  .hero__visual {
    inline-size: 100%;
  }

  /* Patterns */

  .hero[data-pattern="centered"] {
    align-items: center;
    text-align: center;
  }

  .hero[data-pattern="centered"] > * {
    margin-inline: auto;
  }

  .hero[data-pattern="centered"] .hero__actions {
    justify-content: center;
  }

  .hero[data-pattern="split"] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--hero-split-min), 1fr));
    gap: var(--space-gap-blocks-l);
    align-items: center;
  }

  .hero[data-pattern="split"] > * {
    max-inline-size: none;
  }

  .hero[data-pattern="minimal"] {
    align-items: flex-start;
    gap: var(--space-gap-elements-s);
  }

  /* On-surface variants */

  .hero.-on-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
  }
  .hero.-on-accent .hero__title,
  .hero.-on-accent .hero__lede,
  .hero.-on-accent .hero__eyebrow {
    color: var(--color-ink-inverse);
  }

  .hero.-on-inverse {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
  }
  .hero.-on-inverse .hero__title,
  .hero.-on-inverse .hero__lede {
    color: var(--color-ink-inverse);
  }
}


/* ===== ./src/sections/cta/cta.css ===== */
/*
 * CTA — section
 *
 * Hero-lite: title + lede + actions, designed for mid-page conversion
 * blocks ("Ready to start? Sign up.") rather than above-the-fold.
 *
 *   <section class="cta">
 *     <h2 class="cta__title">Ready to start?</h2>
 *     <p class="cta__lede">Free for personal use, no card required.</p>
 *     <div class="cta__actions">
 *       <a class="button -primary">Sign up</a>
 *       <a class="button -ghost">Talk to sales</a>
 *     </div>
 *   </section>
 */

@layer malevich.components {
  .cta {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-section-m);
    padding-inline: var(--space-inset-section-m);

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);

    border-radius: var(--radius-section);

    inline-size: 100%;
    box-sizing: border-box;
  }

  .cta > * {
    max-inline-size: var(--hero-max-content);
  }

  .cta__title {
    margin: 0;
    color: var(--color-ink-strong);
    font-family: var(--font-display-statement-family);
    font-size: var(--font-display-statement-size);
    font-weight: var(--font-display-statement-weight);
    line-height: var(--font-display-statement-line-height);
    letter-spacing: var(--font-display-statement-letter-spacing);
  }

  .cta__lede {
    margin: 0;
    color: var(--color-ink-regular);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: var(--font-body-regular-weight);
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  .cta__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: var(--space-gap-elements-s);
    margin-block-start: var(--space-gap-elements-s);
  }

  /* On-surface variants */

  .cta.-on-accent {
    background-color: var(--color-accent);
    color: var(--color-ink-inverse);
  }
  .cta.-on-accent .cta__title,
  .cta.-on-accent .cta__lede {
    color: var(--color-ink-inverse);
  }

  .cta.-on-inverse {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
  }
  .cta.-on-inverse .cta__title,
  .cta.-on-inverse .cta__lede {
    color: var(--color-ink-inverse);
  }

  .cta.-bordered {
    background-color: transparent;
    border: var(--border-width-hairline) solid var(--color-border-default);
  }

  /* Left-aligned variant */

  .cta.-start {
    align-items: flex-start;
    text-align: start;
  }

  .cta.-start .cta__actions {
    justify-content: flex-start;
  }
}


/* ===== ./src/sections/site-header/site-header.css ===== */
/*
 * Site-header — section
 *
 * Top-of-page chrome. Four patterns via data-pattern attribute:
 *
 *   standard   — Linear-style: logo left, nav center, actions right (default)
 *   inline     — Stripe-style: logo left, nav + actions right
 *   breadcrumb — Notion-style: logo left, breadcrumb (in __nav slot) grows,
 *                actions right
 *   centered   — Apple-style: logo centered, nav left of logo, actions right
 *
 * Sticky behavior is opt-in via data-sticky="true". Mobile collapse is
 * container-query driven: below the mobile breakpoint, nav + actions
 * hide and the mobile-trigger button appears.
 *
 *   <header class="site-header" data-pattern="standard" data-sticky="true">
 *     <a class="site-header__logo" href="/">Logo</a>
 *     <nav class="site-header__nav" aria-label="Primary">
 *       <a href="/docs">Docs</a>
 *     </nav>
 *     <div class="site-header__actions">
 *       <button class="button -primary -s">Get started</button>
 *     </div>
 *     <button class="site-header__mobile-trigger" type="button"
 *             aria-haspopup="dialog" aria-controls="mobile-menu"
 *             aria-expanded="false" aria-label="Open menu">☰</button>
 *   </header>
 */

@layer malevich.components {
  .site-header {
    container-type: inline-size;
    container-name: site-header;

    display: grid;
    align-items: center;
    gap: var(--space-gap-elements-m);

    padding-block: var(--space-inset-block-m);
    padding-inline: var(--space-inset-section-m);

    background-color: var(--color-surface-canvas);
    border-block-end: var(--border-width-hairline) solid var(--color-border-muted);

    inline-size: 100%;
    box-sizing: border-box;

    /* Default layout = standard pattern */
    grid-template-columns: auto 1fr auto auto;
    grid-template-areas: "logo nav actions mobile";
  }

  /* Sticky behavior modifier */
  .site-header[data-sticky="true"] {
    position: sticky;
    inset-block-start: 0;
    z-index: 100;
    backdrop-filter: blur(var(--site-header-sticky-blur));
  }

  /* ---- Grid areas (common to all patterns) ---- */

  .site-header__logo {
    grid-area: logo;
    display: inline-flex;
    align-items: center;
    color: var(--color-ink-strong);
    text-decoration: none;

    font-family: var(--font-display-title-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-display-title-weight);
    line-height: var(--font-heading-section-line-height);
    letter-spacing: var(--font-display-title-letter-spacing);
  }

  .site-header__nav {
    grid-area: nav;
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-m);
    min-inline-size: 0;
  }

  .site-header__nav a {
    color: var(--color-ink-regular);
    text-decoration: none;
    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-s);
    border-radius: var(--radius-button);
    white-space: nowrap;
    transition: color var(--motion-fast) var(--motion-easing-default),
                background-color var(--motion-fast) var(--motion-easing-default);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: 500;
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .site-header__nav a:hover {
    color: var(--color-ink-strong);
    background-color: var(--color-surface-raised);
  }

  .site-header__nav a[aria-current="page"] {
    color: var(--color-ink-strong);
    font-weight: 600;
  }

  .site-header__actions {
    grid-area: actions;
    display: inline-flex;
    align-items: center;
    gap: var(--space-gap-elements-s);
  }

  .site-header__mobile-trigger {
    grid-area: mobile;
    display: none;
    appearance: none;
    -webkit-appearance: none;
    background: transparent;
    border: 0;
    padding: var(--space-inset-element-s);
    margin: 0;
    cursor: pointer;
    color: var(--color-ink-strong);
    inline-size: var(--size-control-m);
    block-size: var(--size-control-m);
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-button);
  }

  .site-header__mobile-trigger:hover {
    background-color: var(--color-surface-raised);
  }

  /* ---- Pattern: standard (default, Linear-style) ----
   * logo | nav (center) | actions | mobile
   */
  .site-header[data-pattern="standard"],
  .site-header:not([data-pattern]) {
    grid-template-columns: auto 1fr auto auto;
    grid-template-areas: "logo nav actions mobile";
  }
  .site-header[data-pattern="standard"] .site-header__nav,
  .site-header:not([data-pattern]) .site-header__nav {
    justify-self: center;
  }

  /* ---- Pattern: inline (Stripe-style) ----
   * logo | spacer | nav | actions | mobile
   */
  .site-header[data-pattern="inline"] {
    grid-template-columns: auto 1fr auto auto auto;
    grid-template-areas: "logo . nav actions mobile";
  }
  .site-header[data-pattern="inline"] .site-header__nav {
    justify-self: end;
  }

  /* ---- Pattern: breadcrumb (Notion-style) ----
   * logo | breadcrumb (in __nav, grows from start) | actions | mobile
   * Authors place a <nav class="breadcrumb"> inside .site-header__nav.
   */
  .site-header[data-pattern="breadcrumb"] {
    grid-template-columns: auto 1fr auto auto;
    grid-template-areas: "logo nav actions mobile";
  }
  .site-header[data-pattern="breadcrumb"] .site-header__nav {
    justify-self: start;
    inline-size: 100%;
    overflow: hidden;
  }

  /* ---- Pattern: centered (Apple-style) ----
   * nav (left of logo) | logo (center) | actions (right) | mobile
   */
  .site-header[data-pattern="centered"] {
    grid-template-columns: 1fr auto 1fr auto;
    grid-template-areas: "nav logo actions mobile";
  }
  .site-header[data-pattern="centered"] .site-header__logo {
    justify-self: center;
  }
  .site-header[data-pattern="centered"] .site-header__nav {
    justify-self: start;
  }
  .site-header[data-pattern="centered"] .site-header__actions {
    justify-self: end;
  }

  /* ---- Container-aware mobile collapse ----
   * Below the mobile breakpoint every pattern reduces to:
   *   logo | spacer | mobile-trigger
   * Nav and actions are hidden; the consumer opens a Sheet from the
   * trigger.
   */
  @container site-header (max-width: 640px) {
    .site-header,
    .site-header[data-pattern] {
      grid-template-columns: auto 1fr auto;
      grid-template-areas: "logo . mobile";
    }
    .site-header__nav,
    .site-header__actions {
      display: none;
    }
    .site-header__mobile-trigger {
      display: inline-flex;
    }
  }
}


/* ===== ./src/sections/site-footer/site-footer.css ===== */
/*
 * Site-footer — section (minimal form)
 *
 * Single-row footer: logo + nav links + copyright. The expanded form
 * (multi-column with category groups) lives in Site-footer-extended.
 * Per the answered design question: two separate components.
 *
 *   <footer class="site-footer">
 *     <a class="site-footer__logo" href="/">Malevich</a>
 *     <nav class="site-footer__nav" aria-label="Footer">
 *       <a href="/manifesto">Manifesto</a>
 *       <a href="/license">License</a>
 *       <a href="/contact">Contact</a>
 *     </nav>
 *     <p class="site-footer__copyright">© 2026 Malevich.</p>
 *   </footer>
 */

@layer malevich.components {
  .site-footer {
    container-type: inline-size;
    container-name: site-footer;

    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-gap-elements-m);
    flex-wrap: wrap;

    padding-block: var(--space-inset-block-l);
    padding-inline: var(--space-inset-section-m);

    background-color: var(--color-surface-canvas);
    border-block-start: var(--border-width-hairline) solid var(--color-border-muted);
    color: var(--color-ink-regular);

    inline-size: 100%;
    box-sizing: border-box;
  }

  .site-footer__logo {
    display: inline-flex;
    align-items: center;
    color: var(--color-ink-strong);
    text-decoration: none;
    font-family: var(--font-display-title-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-display-title-weight);
    letter-spacing: var(--font-display-title-letter-spacing);
    flex-shrink: 0;
  }

  .site-footer__nav {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-m);
  }

  .site-footer__nav a {
    color: var(--color-ink-regular);
    text-decoration: none;
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    transition: color var(--motion-fast) var(--motion-easing-default);
  }

  .site-footer__nav a:hover {
    color: var(--color-ink-strong);
  }

  .site-footer__copyright {
    margin: 0;
    color: var(--color-ink-subtle);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
    flex-shrink: 0;
  }

  /* Variants */

  .site-footer.-on-inverse {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
  }
  .site-footer.-on-inverse .site-footer__logo,
  .site-footer.-on-inverse .site-footer__nav a {
    color: var(--color-ink-inverse);
  }
  .site-footer.-on-inverse .site-footer__nav a:hover {
    opacity: 0.85;
  }
  .site-footer.-on-inverse .site-footer__copyright {
    color: var(--color-ink-inverse);
    opacity: 0.6;
  }
}


/* ===== ./src/sections/site-footer-extended/site-footer-extended.css ===== */
/*
 * Site-footer-extended — section (expanded form)
 *
 * Multi-column footer: 3-5 category columns of links + a bottom row
 * with logo, copyright, and legal links. The minimal single-row form
 * lives in Site-footer.
 *
 *   <footer class="site-footer-extended">
 *     <div class="site-footer-extended__columns">
 *       <div class="site-footer-extended__column">
 *         <h3 class="site-footer-extended__column-title">Product</h3>
 *         <ul class="site-footer-extended__column-list">
 *           <li><a href="#">Components</a></li>
 *           <li><a href="#">Tokens</a></li>
 *           <li><a href="#">Themes</a></li>
 *         </ul>
 *       </div>
 *       <!-- more columns... -->
 *     </div>
 *     <div class="site-footer-extended__bottom">
 *       <a class="site-footer-extended__logo" href="/">Malevich</a>
 *       <p class="site-footer-extended__copyright">© 2026 Malevich.</p>
 *       <nav class="site-footer-extended__legal" aria-label="Legal">
 *         <a href="/privacy">Privacy</a>
 *         <a href="/terms">Terms</a>
 *       </nav>
 *     </div>
 *   </footer>
 */

@layer malevich.components {
  .site-footer-extended {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-blocks-l);

    padding-block: var(--space-inset-section-l);
    padding-inline: var(--space-inset-section-m);

    background-color: var(--color-surface-canvas);
    border-block-start: var(--border-width-hairline) solid var(--color-border-muted);
    color: var(--color-ink-regular);

    inline-size: 100%;
    box-sizing: border-box;
  }

  /* ---- Column grid ---- */

  .site-footer-extended__columns {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--site-footer-extended-column-min), 1fr));
    gap: var(--space-gap-blocks-l);
  }

  .site-footer-extended__column {
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  .site-footer-extended__column-title {
    margin: 0 0 var(--space-gap-elements-s);
    color: var(--color-ink-strong);
    font-family: var(--font-overline-family);
    font-size: var(--font-overline-size);
    font-weight: var(--font-overline-weight);
    line-height: var(--font-overline-line-height);
    letter-spacing: var(--font-overline-letter-spacing);
    text-transform: uppercase;
  }

  .site-footer-extended__column-list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--space-gap-elements-s);
  }

  .site-footer-extended__column-list a {
    color: var(--color-ink-regular);
    text-decoration: none;
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    transition: color var(--motion-fast) var(--motion-easing-default);
  }

  .site-footer-extended__column-list a:hover {
    color: var(--color-ink-strong);
  }

  /* ---- Bottom row ---- */

  .site-footer-extended__bottom {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-m);

    padding-block-start: var(--space-inset-block-m);
    border-block-start: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .site-footer-extended__logo {
    display: inline-flex;
    align-items: center;
    color: var(--color-ink-strong);
    text-decoration: none;
    font-family: var(--font-display-title-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-display-title-weight);
    letter-spacing: var(--font-display-title-letter-spacing);
    flex-shrink: 0;
  }

  .site-footer-extended__copyright {
    margin: 0;
    color: var(--color-ink-subtle);
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
  }

  .site-footer-extended__legal {
    display: inline-flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--space-gap-elements-m);
  }

  .site-footer-extended__legal a {
    color: var(--color-ink-subtle);
    text-decoration: none;
    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);
    transition: color var(--motion-fast) var(--motion-easing-default);
  }

  .site-footer-extended__legal a:hover {
    color: var(--color-ink-strong);
  }

  /* Variants */
  .site-footer-extended.-on-inverse {
    background-color: var(--color-ink-strong);
    color: var(--color-ink-inverse);
  }
  .site-footer-extended.-on-inverse .site-footer-extended__column-title,
  .site-footer-extended.-on-inverse .site-footer-extended__column-list a,
  .site-footer-extended.-on-inverse .site-footer-extended__logo {
    color: var(--color-ink-inverse);
  }
  .site-footer-extended.-on-inverse .site-footer-extended__copyright,
  .site-footer-extended.-on-inverse .site-footer-extended__legal a {
    color: var(--color-ink-inverse);
    opacity: 0.6;
  }
}



/* Overlays */
/* ===== ./src/overlays/dialog/dialog.css ===== */
/*
 * Dialog — overlay
 *
 * Built on the native <dialog> element. Authors call
 * dialog.showModal() to open (gets focus trap, backdrop, top-layer
 * rendering, Escape-to-close for free). initDialog adds focus
 * restoration and optional click-outside-to-close.
 *
 *   <dialog class="dialog">
 *     <header class="dialog__header">…</header>
 *     <div class="dialog__body">…</div>
 *     <footer class="dialog__footer">…</footer>
 *   </dialog>
 */

@layer malevich.components {
  .dialog {
    /* Reset native <dialog> defaults */
    margin: auto;
    padding: 0;

    background-color: var(--dialog-background);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--dialog-border);
    border-radius: var(--radius-dialog);

    max-width: var(--dialog-max-width);
    width: calc(100% - var(--space-inset-section-s) * 2);

    box-shadow: var(--shadow-overlay);

    /* Inner layout */
    display: flex;
    flex-direction: column;
  }

  .dialog::backdrop {
    background-color: var(--dialog-backdrop);
  }

  .dialog__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-gap-elements-m);
    padding: var(--space-inset-block-m);
    border-bottom: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .dialog__header > h1,
  .dialog__header > h2,
  .dialog__header > h3 {
    margin: 0;
  }

  .dialog__close {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    background: transparent;
    border: 0;
    color: var(--color-ink-subtle);
    cursor: pointer;
    padding: var(--space-inset-element-s);
    border-radius: var(--radius-button);
    line-height: 1;
  }

  .dialog__close:hover {
    color: var(--color-ink-strong);
    background-color: var(--color-surface-raised);
  }

  .dialog__close:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-emphasis);
  }

  .dialog__body {
    padding: var(--space-inset-block-l);
    overflow: auto;
  }

  .dialog__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-gap-elements-m);
    padding: var(--space-inset-block-m);
    border-top: var(--border-width-hairline) solid var(--color-border-muted);
  }

  /* ----- Variants ----- */

  .dialog.-large {
    max-width: var(--dialog-max-width-large);
  }
}


/* ===== ./src/overlays/tooltip/tooltip.css ===== */
/*
 * Tooltip — overlay
 *
 * Short, non-interactive contextual hint paired with a trigger via
 * aria-describedby. Positioning prefers CSS Anchor Positioning where
 * supported; falls back to inline top/left applied by initTooltip.
 *
 *   <button class="button" aria-describedby="t1">Save</button>
 *   <span class="tooltip" role="tooltip" id="t1" hidden>
 *     Saves your work to the cloud
 *   </span>
 */

@layer malevich.components {
  .tooltip {
    /* Take the tooltip out of normal flow; positioning provided by
       either inline top/left (JS fallback) or anchor positioning. */
    position: fixed;
    top: 0;
    left: 0;
    z-index: 1000;

    pointer-events: none;

    padding-block: var(--space-inset-element-s);
    padding-inline: var(--space-inset-element-m);

    background-color: var(--color-surface-overlay);
    color: var(--color-ink-inverse);
    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: var(--radius-tooltip);

    box-shadow: var(--shadow-overlay);

    font-family: var(--font-caption-family);
    font-size: var(--font-caption-size);
    font-weight: var(--font-caption-weight);
    line-height: var(--font-caption-line-height);
    letter-spacing: var(--font-caption-letter-spacing);

    opacity: 0;
    transition: opacity var(--motion-fast) var(--motion-easing-default);
  }

  .tooltip[data-malevich-visible="true"] {
    opacity: 1;
  }

  .tooltip[hidden] {
    display: none;
  }
}


/* ===== ./src/overlays/sheet/sheet.css ===== */
/*
 * Sheet — overlay
 *
 * 4-side slide-in panel built on native <dialog> (modal). Authors call
 * dialog.showModal() to open. Position is set via data-side; CSS
 * handles transform-in animation. Per answered design question: slide
 * from the relevant edge + fade backdrop; reduced-motion drops the
 * slide to fade-only.
 *
 *   <dialog class="sheet" data-side="right">
 *     <header class="sheet__header">…</header>
 *     <div class="sheet__body">…</div>
 *     <footer class="sheet__footer">…</footer>
 *   </dialog>
 */

@layer malevich.components {
  .sheet {
    --sheet-duration: var(--motion-base);

    margin: 0;
    padding: 0;

    background-color: var(--color-surface-raised);
    color: var(--color-ink-strong);
    border: 0;

    box-shadow: var(--shadow-overlay);

    display: flex;
    flex-direction: column;

    /* Default placement = right */
    position: fixed;
    inset-block-start: 0;
    inset-block-end: 0;
    inset-inline-end: 0;
    inline-size: var(--sheet-size);
    max-inline-size: 100vw;
    block-size: 100vh;
    max-block-size: 100vh;

    transform: translateX(100%);
    transition: transform var(--sheet-duration) var(--motion-easing-default);
  }

  .sheet[open] {
    transform: translateX(0);
  }

  .sheet::backdrop {
    background-color: var(--color-surface-overlay);
    opacity: 0;
    transition: opacity var(--sheet-duration) var(--motion-easing-default);
  }

  .sheet[open]::backdrop {
    opacity: 1;
  }

  /* Side placements */

  .sheet[data-side="right"] {
    inset-inline-start: auto;
    inset-inline-end: 0;
    transform: translateX(100%);
  }
  .sheet[data-side="right"][open] {
    transform: translateX(0);
  }

  .sheet[data-side="left"] {
    inset-inline-start: 0;
    inset-inline-end: auto;
    transform: translateX(-100%);
  }
  .sheet[data-side="left"][open] {
    transform: translateX(0);
  }

  .sheet[data-side="top"] {
    inset-block-start: 0;
    inset-block-end: auto;
    inset-inline-start: 0;
    inset-inline-end: 0;
    inline-size: auto;
    max-inline-size: 100vw;
    block-size: var(--sheet-size);
    transform: translateY(-100%);
  }
  .sheet[data-side="top"][open] {
    transform: translateY(0);
  }

  .sheet[data-side="bottom"] {
    inset-block-start: auto;
    inset-block-end: 0;
    inset-inline-start: 0;
    inset-inline-end: 0;
    inline-size: auto;
    max-inline-size: 100vw;
    block-size: var(--sheet-size);
    transform: translateY(100%);
  }
  .sheet[data-side="bottom"][open] {
    transform: translateY(0);
  }

  /* Layout slots */

  .sheet__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-gap-elements-m);
    padding: var(--space-inset-block-m);
    border-block-end: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .sheet__header > h1,
  .sheet__header > h2,
  .sheet__header > h3 {
    margin: 0;
    font-family: var(--font-heading-section-family);
    font-size: var(--font-heading-section-size);
    font-weight: var(--font-heading-section-weight);
    line-height: var(--font-heading-section-line-height);
  }

  .sheet__close {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    padding: var(--space-inset-element-s);
    background: transparent;
    color: var(--color-ink-regular);
    border: 0;
    cursor: pointer;
    border-radius: var(--radius-button);
    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .sheet__close:hover {
    background-color: var(--color-surface-canvas);
    color: var(--color-ink-strong);
  }

  .sheet__close:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  .sheet__body {
    flex: 1;
    overflow: auto;
    padding: var(--space-inset-block-m);
  }

  .sheet__footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-gap-elements-s);
    padding: var(--space-inset-block-m);
    border-block-start: var(--border-width-hairline) solid var(--color-border-muted);
  }

  /* Reduced motion drops the slide to a pure fade. */
  @media (prefers-reduced-motion: reduce) {
    .sheet,
    .sheet[data-side] {
      transform: none;
      opacity: 0;
      transition: opacity var(--sheet-duration) var(--motion-easing-default);
    }
    .sheet[open],
    .sheet[data-side][open] {
      transform: none;
      opacity: 1;
    }
  }
}


/* ===== ./src/overlays/popover/popover.css ===== */
/*
 * Popover — overlay
 *
 * Click-triggered floating panel anchored to a trigger element.
 * Non-modal: clicks outside dismiss it but interactions behind the
 * popover remain available. Per the answered design question:
 * reuses runtime/position.ts (no external Floating UI dependency).
 *
 *   <button type="button" class="button -secondary"
 *           aria-haspopup="dialog" aria-expanded="false"
 *           aria-controls="pop-1">More</button>
 *
 *   <div class="popover" id="pop-1" hidden role="dialog" aria-labelledby="pop-1-title">
 *     <header class="popover__header">
 *       <h3 id="pop-1-title" class="popover__title">Quick actions</h3>
 *     </header>
 *     <div class="popover__body">…</div>
 *   </div>
 */

@layer malevich.components {
  .popover {
    position: fixed;
    z-index: 1000;
    max-inline-size: var(--popover-max-width);

    background-color: var(--color-surface-float);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: var(--radius-tooltip);
    box-shadow: var(--shadow-float);

    /* Hidden by default — runtime toggles via [hidden] attribute. */
    opacity: 0;
    transform: translateY(calc(-1 * var(--space-inset-element-s)));
    transition:
      opacity var(--motion-fast) var(--motion-easing-default),
      transform var(--motion-fast) var(--motion-easing-default);
  }

  .popover[data-state="open"] {
    opacity: 1;
    transform: translateY(0);
  }

  .popover[hidden] {
    display: none;
  }

  .popover__header {
    padding: var(--space-inset-block-s) var(--space-inset-block-m);
    border-block-end: var(--border-width-hairline) solid var(--color-border-muted);
  }

  .popover__title {
    margin: 0;
    font-family: var(--font-heading-subsection-family);
    font-size: var(--font-heading-subsection-size);
    font-weight: var(--font-heading-subsection-weight);
    line-height: var(--font-heading-subsection-line-height);
    letter-spacing: var(--font-heading-subsection-letter-spacing);
    color: var(--color-ink-strong);
  }

  .popover__body {
    padding: var(--space-inset-block-m);

    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
    color: var(--color-ink-regular);
  }

  .popover__footer {
    padding: var(--space-inset-block-s) var(--space-inset-block-m);
    border-block-start: var(--border-width-hairline) solid var(--color-border-muted);
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-gap-elements-s);
  }

  @media (prefers-reduced-motion: reduce) {
    .popover {
      transform: none;
      transition: opacity var(--motion-fast) var(--motion-easing-default);
    }
    .popover[data-state="open"] {
      transform: none;
    }
  }
}


/* ===== ./src/overlays/toast/toast.css ===== */
/*
 * Toast + Notifications — overlays
 *
 * Sonner-style stack manager. A single Notifications container renders
 * at a corner; toasts append at the top and visually push older toasts
 * down with subtle scaling for depth. Auto-dismiss timer; hover pauses.
 *
 *   <ol class="notifications" data-position="bottom-right" aria-live="polite" aria-label="Notifications"></ol>
 *
 *   <li class="toast -success" data-state="enter">
 *     <span class="toast__icon" aria-hidden="true">✓</span>
 *     <div class="toast__content">
 *       <strong class="toast__title">Saved</strong>
 *       <p class="toast__description">Your changes were saved.</p>
 *     </div>
 *     <button class="toast__dismiss" aria-label="Dismiss">×</button>
 *   </li>
 *
 * The Notifications container is fixed-positioned; toasts are children
 * arranged in a column. Toast (standalone) can also be used outside
 * Notifications — it just won't get stack management.
 */

@layer malevich.components {
  /* ---- Notifications container ---- */

  .notifications {
    --notifications-gap: var(--space-gap-elements-s);
    --notifications-inset: var(--space-inset-block-m);

    list-style: none;
    margin: 0;
    padding: 0;

    position: fixed;
    z-index: 1100;

    display: flex;
    flex-direction: column-reverse;
    gap: var(--notifications-gap);

    inline-size: var(--notifications-width);
    max-inline-size: calc(100vw - var(--notifications-inset) * 2);
    pointer-events: none;
  }

  .notifications > .toast {
    pointer-events: auto;
  }

  .notifications[data-position="bottom-right"] {
    inset-block-end: var(--notifications-inset);
    inset-inline-end: var(--notifications-inset);
  }
  .notifications[data-position="bottom-left"] {
    inset-block-end: var(--notifications-inset);
    inset-inline-start: var(--notifications-inset);
  }
  .notifications[data-position="top-right"] {
    inset-block-start: var(--notifications-inset);
    inset-inline-end: var(--notifications-inset);
    flex-direction: column;
  }
  .notifications[data-position="top-left"] {
    inset-block-start: var(--notifications-inset);
    inset-inline-start: var(--notifications-inset);
    flex-direction: column;
  }

  /* ---- Toast ---- */

  .toast {
    display: flex;
    align-items: flex-start;
    gap: var(--space-gap-elements-s);

    padding: var(--space-inset-block-m);

    background-color: var(--color-surface-float);
    color: var(--color-ink-strong);
    border: var(--border-width-hairline) solid var(--color-border-default);
    border-radius: var(--radius-card);
    box-shadow: var(--shadow-float);

    transition:
      transform var(--motion-fast) var(--motion-easing-default),
      opacity var(--motion-fast) var(--motion-easing-default);
  }

  .toast[data-state="enter"] {
    transform: translateY(var(--space-inset-element-m));
    opacity: 0;
    animation: malevich-toast-in var(--motion-base) var(--motion-easing-default) forwards;
  }

  .toast[data-state="exit"] {
    transform: translateX(0);
    opacity: 1;
    animation: malevich-toast-out var(--motion-base) var(--motion-easing-default) forwards;
  }

  .toast__icon {
    flex-shrink: 0;
    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    color: var(--color-ink-regular);
  }

  .toast__content {
    flex: 1;
    min-inline-size: 0;
  }

  .toast__title {
    display: block;
    color: var(--color-ink-strong);
    font-family: var(--font-body-regular-family);
    font-size: var(--font-body-regular-size);
    font-weight: 600;
    line-height: var(--font-body-regular-line-height);
    letter-spacing: var(--font-body-regular-letter-spacing);
  }

  .toast__description {
    margin: 0;
    color: var(--color-ink-regular);
    font-family: var(--font-body-support-family);
    font-size: var(--font-body-support-size);
    font-weight: var(--font-body-support-weight);
    line-height: var(--font-body-support-line-height);
    letter-spacing: var(--font-body-support-letter-spacing);
  }

  .toast__title + .toast__description {
    margin-block-start: var(--space-gap-elements-s);
  }

  .toast__dismiss {
    appearance: none;
    -webkit-appearance: none;
    margin: 0;
    padding: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
    color: var(--color-ink-subtle);
    inline-size: var(--size-control-s);
    block-size: var(--size-control-s);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-button);
    flex-shrink: 0;
  }

  .toast__dismiss:hover {
    color: var(--color-ink-strong);
    background-color: var(--color-surface-canvas);
  }

  .toast__dismiss:focus-visible {
    outline: var(--border-width-focus) solid var(--color-accent);
    outline-offset: var(--border-width-hairline);
  }

  /* Status variants — color the left edge */

  .toast.-info {
    border-inline-start: var(--border-width-emphasis) solid var(--color-info);
  }
  .toast.-info .toast__icon { color: var(--color-info); }

  .toast.-success {
    border-inline-start: var(--border-width-emphasis) solid var(--color-success);
  }
  .toast.-success .toast__icon { color: var(--color-success); }

  .toast.-warning {
    border-inline-start: var(--border-width-emphasis) solid var(--color-warning);
  }
  .toast.-warning .toast__icon { color: var(--color-warning); }

  .toast.-danger {
    border-inline-start: var(--border-width-emphasis) solid var(--color-danger);
  }
  .toast.-danger .toast__icon { color: var(--color-danger); }

  @keyframes malevich-toast-in {
    to { transform: translateY(0); opacity: 1; }
  }

  @keyframes malevich-toast-out {
    to { transform: translateX(110%); opacity: 0; }
  }

  @media (prefers-reduced-motion: reduce) {
    .toast[data-state="enter"],
    .toast[data-state="exit"] {
      animation: none;
      opacity: 1;
      transform: none;
    }
  }
}


