/* system.css — Develop base + component layer (v2).
 *
 * Explicit @layer order: a consumer's own UNLAYERED rules always win over every
 * lib layer (opt-in, non-breaking); within lib, utilities > components > reset.
 * Tokens come from v2/tokens.css. Compact 12px base; one shared focus ring; one
 * global reduced-motion guard. Components reference SEMANTIC tokens only. */

@layer lib.reset, lib.components, lib.utilities;

@layer lib.reset {
  *, *::before, *::after { box-sizing: border-box; }

  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; tab-size: 4; }
  img, svg, video, canvas { max-width: 100%; height: auto; }
  svg { display: block; }
  /* An svg that declares its size via width/height ATTRIBUTES (the inline-icon
     pattern) must not be fluid-capped: inside a shrink-wrapped flex parent
     (e.g. an icon-only .btn) `max-width:100%` makes parent↔child sizing
     circular — Chrome resolves it to the attribute size, WebKit/iOS Safari
     collapses the icon to 0×0 (the "copy button vanished on mobile" bug).
     Explicit attributes mean the author already fixed the size; honor it. */
  svg[width][height] { max-width: none; }
  button, input, textarea, select { font: inherit; color: inherit; }
  :where(p, li, h1, h2, h3, h4, h5, h6) { overflow-wrap: break-word; }

  body {
    margin: 0;
    font-family: var(--font-sans);
    font-size: var(--text-body);
    line-height: var(--leading-body);
    background: var(--background);
    color: var(--foreground);
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
  }

  h1, h2, h3, h4, h5, h6 {
    margin: 0;
    font-weight: var(--weight-semibold);
    line-height: var(--leading-heading);
    letter-spacing: var(--tracking-tight);
    color: var(--foreground);
  }
  h1 { font-size: var(--text-display); }
  h2 { font-size: var(--text-subheading); }
  h3 { font-size: var(--text-heading); }
  h4 { font-size: var(--text-title); }
  h5 { font-size: var(--text-body); }
  h6 { font-size: var(--text-micro); }
  p { margin: 0; line-height: var(--leading-body); }
  /* Complete the margin/padding normalization so consumers never need their own
     `*{margin:0;padding:0}` reset (an UNLAYERED consumer reset would beat every
     lib component's padding — see top comment). :where() keeps specificity 0 so
     any product/component rule trivially overrides. */
  :where(ul, ol, menu) { margin: 0; padding: 0; }
  :where(figure, blockquote, dl, dd, fieldset) { margin: 0; }

  a { color: inherit; }

  /* Custom-element FOUC guards (components.js is deferred). */
  dev-site-header:not(:defined) { display: block; min-height: 48px; background: var(--background); border-bottom: 1px solid var(--border); }
  dev-site-footer:not(:defined) { display: block; min-height: 120px; background: var(--background); border-top: 1px solid var(--border); }
  /* Async custom elements with slotted application content stay hidden until
     upgrade; otherwise drawer bodies and option labels dump into normal page
     flow on a cold/slow components.js load. Important is intentional: the
     reset-layer guard must also beat the contextual drawer's utility-layer
     display rule before that element is defined. */
  dev-dialog:not(:defined),
  dev-drawer:not(:defined),
  dev-select:not(:defined) { display: none !important; }

  /* ONE global reduced-motion guard — neutralizes lib motion DURATION for users
     who ask for it (a11y). Leaves end-states intact so layout doesn't break. */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: 0.001ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.001ms !important;
    }
  }
}

@layer lib.components {
  /* ---- Buttons ---- */
  /* Default button = NEUTRAL OUTLINE (reference-console discipline: hue is
     reserved for the primary CTA + selected states; every other button stays
     quiet so a screen full of actions doesn't read as a wall of color). */
  .btn {
    box-sizing: border-box;
    display: inline-flex; align-items: center; justify-content: center; gap: var(--sp-2);
    min-height: var(--c-btn-h); padding: 0 var(--c-btn-px);
    border: 1px solid var(--btn-outline-border); border-radius: var(--c-btn-radius);
    background: var(--btn-outline-bg); color: var(--btn-outline-fg);
    box-shadow: var(--elevation-1);
    font-family: inherit; font-size: var(--text-caption); font-weight: var(--weight-medium);
    line-height: 1.2; letter-spacing: var(--tracking-normal); white-space: nowrap;
    text-decoration: none; cursor: pointer;
    transition: transform 100ms var(--ease-out),
                box-shadow 120ms var(--ease-out),
                background-color 120ms var(--ease-smooth),
                border-color 120ms var(--ease-smooth),
                filter 120ms var(--ease-smooth);
  }
  .btn:not(:disabled):hover { background: var(--btn-outline-bg-hover); border-color: var(--btn-outline-border-hover); }
  /* Press = 1px sink (the reference press affordance), not a scale. */
  .btn:not(:disabled):active { transform: translateY(1px); box-shadow: none; }
  .btn:focus-visible { outline: 2px solid transparent; outline-offset: 2px; box-shadow: var(--focus-ring); }
  .btn:disabled, .btn[aria-disabled="true"] { opacity: var(--state-disabled-opacity); cursor: not-allowed; }
  .btn[aria-busy="true"] { cursor: progress; color: transparent; position: relative; }
  .btn[aria-busy="true"]::after {
    content: ""; position: absolute; inset: 0; margin: auto;
    width: 1em; height: 1em; border-radius: 50%;
    border: 2px solid currentColor; border-right-color: transparent;
    color: var(--btn-outline-fg); animation: lib-spin 0.7s linear infinite;
  }
  /* Primary CTA — SAME white outline family as the default button (operator
     2026-07-12: no filled/colored primary), distinguished by a heavier ink
     border + semibold label. Hierarchy comes from border weight + type, not
     fill. The only remaining filled button is .btn-danger-solid (terminal
     destructive). */
  .btn-primary { background: var(--btn-outline-bg); color: var(--foreground); border: 1px solid color-mix(in oklab, var(--foreground) 55%, var(--border)); font-weight: var(--weight-semibold); box-shadow: var(--elevation-1); }
  /* Solid accent CTA — the skin's voice color (paper: amber). For the one
     decisive action on a surface (send, save-to-asset). */
  .btn-accent { background: var(--p-accent); color: var(--p-gray-0); border: 1px solid transparent; font-weight: var(--weight-semibold); }
  .btn-accent:hover:not(:disabled) { background: var(--p-accent-deep); color: var(--p-gray-0); }
  /* Accent-outlined secondary action (save-as-asset, view). */
  .btn-outline-accent { background: transparent; color: var(--p-accent); border: 1px solid color-mix(in oklab, var(--p-accent) 45%, var(--surface-raised)); }
  .btn-outline-accent:hover:not(:disabled) { background: color-mix(in oklab, var(--p-accent) 14%, var(--surface-raised)); color: var(--p-accent-deep); }
  .btn-primary:not(:disabled):hover { background: var(--btn-outline-bg-hover); border-color: color-mix(in oklab, var(--foreground) 75%, var(--border)); }
  .btn-primary:not(:disabled):active { transform: translateY(1px); box-shadow: none; }
  .btn-primary[aria-busy="true"]::after { color: var(--foreground); }
  /* Secondary — neutral FILLED (quiet sibling of the outline default). */
  .btn-secondary { background: var(--secondary); color: var(--secondary-foreground); border: 1px solid var(--border); box-shadow: none; }
  .btn-secondary:not(:disabled):hover { background: var(--muted); border-color: var(--border-strong); }
  /* Ghost — the QUIET, neutral button (cancel / toolbar / icon). Neutral fg so
     it does NOT carry the brand-blue accent; only the solid/selected states do. */
  .btn-ghost { background: transparent; border-color: transparent; box-shadow: none; color: var(--secondary-foreground); }
  .btn-ghost:not(:disabled):hover { background: var(--state-hover); border-color: transparent; box-shadow: none; color: var(--foreground); }
  .btn-ghost:not(:disabled):active { background: var(--state-pressed); transform: none; box-shadow: none; }
  /* Danger — SOFT destructive (tinted fill, no shouting border); the solid
     variant below stays for the truly terminal action. */
  .btn-danger { background: var(--danger-bg); color: var(--danger); border-color: transparent; box-shadow: none; }
  .btn-danger:not(:disabled):hover { background: color-mix(in oklab, var(--danger) 20%, var(--surface)); border-color: transparent; }
  .btn-danger:focus-visible, .btn-danger-solid:focus-visible { box-shadow: var(--focus-ring-danger); }
  .btn-danger-solid { background: var(--danger); color: var(--danger-foreground); border: 1px solid transparent; box-shadow: var(--shadow-card); }
  .btn-danger-solid:not(:disabled):hover { background: var(--danger); filter: brightness(0.95); }
  .btn-danger-solid:not(:disabled):active { filter: brightness(0.9); }
  .btn[aria-pressed="true"], .btn.is-selected { background: var(--btn-tonal-selected-bg); border-color: var(--btn-tonal-border-hover); color: var(--btn-tonal-fg); box-shadow: none; }
  .btn-primary[aria-pressed="true"], .btn-primary.is-selected { background: var(--state-selected); }
  .btn-sm { min-height: var(--control-h-sm); padding: 0 0.625rem; font-size: var(--text-micro); }
  .btn-lg { min-height: var(--control-h-lg); padding: 0 var(--sp-4); font-size: var(--text-body); }
  .btn-icon { padding: 0; width: var(--c-btn-h); aspect-ratio: 1; }
  .btn-icon.btn-sm { width: var(--control-h-sm); }
  .btn-icon.btn-lg { width: var(--control-h-lg); }
  .btn-icon:not(:disabled):hover { transform: none; box-shadow: none; }

  /* ---- Inputs ---- */
  .input, .textarea, select.input {
    box-sizing: border-box; width: 100%; padding: 0 var(--sp-3);
    font-family: inherit; font-size: var(--text-body); line-height: var(--leading-body);
    color: var(--foreground); background: var(--c-input-bg);
    border: 1px solid var(--c-input-border); border-radius: var(--radius);
    outline: none; caret-color: var(--ui-accent);   /* branded text cursor — a subtle refined detail */
    transition: border-color var(--duration-fast) var(--ease-smooth), box-shadow var(--duration-fast) var(--ease-smooth);
  }
  .input, select.input { min-height: var(--c-input-h); }
  .input-number { width: 4rem; min-width: 4rem; }
  .textarea { padding: var(--sp-2) var(--sp-3); resize: vertical; }
  .input:hover, .textarea:hover, select.input:hover { border-color: var(--border-strong); }
  /* Focus with the BRAND accent — the field a user is typing in reads as intentional, and
     ties the form to the same accent the buttons use (resting state stays neutral). */
  .input:focus-visible, .textarea:focus-visible, select.input:focus-visible,
  .input:focus, .textarea:focus, select.input:focus { border-color: var(--ui-accent); box-shadow: var(--focus-ring-brand); }
  .input::placeholder, .textarea::placeholder { color: var(--placeholder); }
  .input:disabled, .textarea:disabled, select.input:disabled { opacity: var(--state-disabled-opacity); cursor: not-allowed; background: var(--muted); }
  .input-invalid, .input[aria-invalid="true"], .textarea[aria-invalid="true"] { border-color: var(--danger); }
  .input-invalid:focus, .input[aria-invalid="true"]:focus { box-shadow: var(--focus-ring-danger); }
  .input-sm { min-height: 1.75rem; font-size: var(--text-caption); }
  .input-lg { min-height: 2.5rem; }
  select.input {
    appearance: none; cursor: pointer; padding-right: var(--sp-8);
    background-image: var(--c-select-caret);
    background-repeat: no-repeat; background-position: right var(--sp-3) center;
  }

  /* ---- Form field scaffold ---- */
  .form-field { display: grid; gap: var(--sp-1); }
  /* Horizontal field: label on the left (fixed column so inputs align across a
     stack), control on the right. Pair with .form-label. Override the label
     column width per-form with --field-label-w. */
  .form-field-row { display: grid; grid-template-columns: var(--field-label-w, 5rem) 1fr; align-items: start; gap: var(--sp-2); }
  /* The label is a box the height of ONE input, top-aligned in the grid, so it lines up with the
     control even when the control column carries a help line beneath the input (align-items:center
     used to sink the label to the middle of input+help — the row-misalignment bug). */
  .form-field-row > .form-label { white-space: nowrap; text-align: end; min-block-size: var(--c-input-h); display: inline-flex; align-items: center; justify-content: flex-end; }
  .form-label { font-size: var(--text-caption); font-weight: var(--weight-medium); color: var(--foreground); }
  .form-label .required { color: var(--danger); margin-left: 2px; }
  .form-help { font-size: var(--text-micro); color: var(--muted-foreground); }
  .form-error { font-size: var(--text-micro); color: var(--danger); }

  /* ---- Checkbox / radio (native, tinted) ---- */
  .checkbox, .radio { width: 1rem; height: 1rem; accent-color: var(--primary); cursor: pointer; }
  .checkbox:focus-visible, .radio:focus-visible { outline: none; box-shadow: var(--focus-ring); }

  /* ---- Tags / badges ---- */
  .tag {
    display: inline-flex; align-items: center; gap: var(--sp-1);
    padding-block: 0.1875rem; padding-inline: var(--sp-2);
    font-size: var(--text-micro); font-weight: var(--weight-medium); line-height: 1.4;
    border-radius: var(--c-tag-radius); background: var(--secondary); color: var(--secondary-foreground); white-space: nowrap;
  }
  /* Soft intent tints communicate category through background + inset border;
     text stays on the guaranteed readable foreground token. Saturated intent
     ink on a 10–14% tint fell below normal-text contrast, especially warning. */
  .tag-success { background: var(--success-bg); color: var(--foreground); box-shadow: inset 0 0 0 1px var(--success-border); }
  .tag-warning { background: var(--warning-bg); color: var(--foreground); box-shadow: inset 0 0 0 1px var(--warning-border); }
  .tag-danger  { background: var(--danger-bg);  color: var(--foreground); box-shadow: inset 0 0 0 1px var(--danger-border); }
  .tag-info    { background: var(--info-bg);    color: var(--foreground); box-shadow: inset 0 0 0 1px var(--info-border); }
  .tag-brand   { background: var(--brand-soft); color: var(--foreground); box-shadow: inset 0 0 0 1px var(--brand-soft-hover); }
  .tag-solid   { background: var(--primary); color: var(--primary-foreground); }
  /* High-contrast filled semantic tags (saturated bg + readable foreground) —
     for a coloured LABEL that must stay legible where the soft .tag-* (light bg
     + saturated text) reads too faintly. */
  .tag-solid-info    { background: var(--info);    color: var(--info-foreground); }
  .tag-solid-warning { background: var(--warning); color: var(--warning-foreground); }
  .tag-solid-success { background: var(--success); color: var(--success-foreground); }
  .tag-solid-danger  { background: var(--danger);  color: var(--danger-foreground); }

  /* ---- Cards ---- */
  .card { border: 1px solid var(--border); border-radius: var(--c-card-radius); background: var(--card); color: var(--card-foreground); box-shadow: var(--c-card-shadow); transition: border-color var(--duration-normal) var(--ease-out), box-shadow var(--duration-normal) var(--ease-out), translate var(--duration-normal) var(--ease-out); }
  .card-pad { padding: var(--c-card-pad); }
  .card-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-block-end: 1px solid var(--border); background: var(--surface-sunken); }
  .card-body { padding: var(--sp-4); }
  /* Interactive cards lift 1px on hover (translate, not transform — composes
     with any consumer transform) with a soft mid shadow; the old overlay-grade
     float shadow read as heavy next to the reference consoles. */
  .card-hover:hover { border-color: var(--border-strong); box-shadow: var(--elevation-2); translate: 0 -1px; }
  .card-active { border-color: var(--ring); box-shadow: 0 0 0 2px color-mix(in oklab, var(--ring) 22%, transparent); }
  /* Whole-card actions: use with .card + layout utilities. This keeps channel
     landing pages semantic and keyboard accessible without private reset CSS. */
  .action-card { appearance: none; inline-size: 100%; box-sizing: border-box; text-align: start; cursor: pointer; font: inherit; }
  .action-card:focus-visible { outline: none; box-shadow: var(--focus-ring); border-color: var(--ring); }
  .action-card:disabled { cursor: not-allowed; opacity: var(--state-disabled-opacity); }
  /* Small, reusable onboarding flow. Content and actions remain channel-owned;
     lib owns only the responsive visual relationship. */
  .workflow-steps { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: var(--sp-3); }
  .workflow-step { display: flex; align-items: flex-start; gap: var(--sp-3); min-inline-size: 0; padding: var(--sp-3); border: 0; border-radius: var(--radius); background: var(--surface-sunken); color: var(--foreground); }
  .workflow-step-index { display: inline-grid; place-items: center; flex: 0 0 1.75rem; inline-size: 1.75rem; block-size: 1.75rem; border-radius: var(--radius-full); background: var(--primary); color: var(--primary-foreground); font-size: var(--text-micro); font-weight: var(--weight-bold); }
  /* Leading-edge colour accent — a 3px semantic bar on a card's start edge to
     category-code it (e.g. one card per vendor). Generic + reusable. */
  .card-accent-info    { border-inline-start: 3px solid var(--info); }
  .card-accent-warning { border-inline-start: 3px solid var(--warning); }
  .card-accent-success { border-inline-start: 3px solid var(--success); }
  .card-accent-danger  { border-inline-start: 3px solid var(--danger); }
  .card-accent-brand   { border-inline-start: 3px solid var(--brand); }

  /* ---- Alert ---- */
  .alert { display: flex; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--radius); border: 1px solid var(--border); background: var(--surface-sunken); color: var(--foreground); font-size: var(--text-caption); }
  .alert-success { background: var(--success-bg); border-color: var(--success-border); }
  .alert-warning { background: var(--warning-bg); border-color: var(--warning-border); }
  .alert-danger  { background: var(--danger-bg);  border-color: var(--danger-border); }
  .alert-info    { background: var(--info-bg);    border-color: var(--info-border); }

  /* ---- Progress ---- */
  .progress { height: 6px; border-radius: var(--radius-full); background: var(--muted); overflow: hidden; }
  .progress-bar { height: 100%; border-radius: inherit; background: var(--brand-gradient); transition: width var(--duration-slow) var(--ease-out); }
  .progress-indeterminate .progress-bar { width: 40%; animation: lib-indeterminate 1.1s var(--ease-smooth) infinite; }

  /* ---- Spinner ---- */
  .spinner { display: inline-block; width: var(--icon-md); height: var(--icon-md); border: 2px solid var(--border); border-right-color: var(--foreground); border-radius: 50%; animation: lib-spin 0.7s linear infinite; }

  /* ---- Skeleton ---- */
  .skeleton { background: linear-gradient(90deg, var(--muted) 25%, var(--surface-sunken) 50%, var(--muted) 75%); background-size: 200% 100%; border-radius: var(--radius-sm); animation: lib-shimmer 1.3s linear infinite; }

  /* ---- Empty state ---- */
  .empty-state { display: grid; justify-items: center; gap: var(--sp-2); padding: var(--sp-8) var(--sp-4); text-align: center; color: var(--muted-foreground); }
  .empty-state-icon { font-size: var(--text-display); opacity: 0.7; }
  .empty-state-title { font-size: var(--text-title); font-weight: var(--weight-semibold); color: var(--foreground); }

  /* ---- Misc primitives ---- */
  .divider { border: none; border-top: 1px solid var(--border); margin: var(--sp-3) 0; }
  .kbd { font-family: var(--font-mono); font-size: var(--text-micro); padding: 1px var(--sp-1); border: 1px solid var(--border); border-bottom-width: 2px; border-radius: var(--radius-sm); background: var(--surface-raised); color: var(--foreground); }
  .code { font-family: var(--font-mono); font-size: 0.95em; padding: 1px var(--sp-1); border-radius: var(--radius-sm); background: var(--surface-sunken); color: var(--foreground); }
  .avatar { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: var(--radius-full); background: var(--secondary); color: var(--secondary-foreground); font-size: var(--text-caption); font-weight: var(--weight-semibold); overflow: hidden; }
  .avatar img { width: 100%; height: 100%; object-fit: cover; }

  /* ---- Overlay (for non-dev-dialog modals) ---- */
  .overlay { position: fixed; inset: 0; display: flex; align-items: center; justify-content: center; background: oklch(0.2 0 0 / 0.4); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); z-index: var(--z-modal); animation: lib-fade-in var(--duration-normal) var(--ease-out); }
  .modal-card { background: var(--surface-overlay); color: var(--card-foreground); border: 1px solid var(--border); border-radius: var(--radius-xl); box-shadow: var(--elevation-4); max-width: min(560px, 92vw); max-height: 86vh; overflow: auto; animation: lib-scale-in var(--duration-normal) var(--ease-out); }
  /* Wide variant for content-heavy modals (a form + a data table); pair with .modal-card. */
  .modal-card.modal-lg { max-width: min(900px, 94vw); width: 100%; }

  /* ---- Scrollbar (opt-in) ---- */
  .scroll-thin { scrollbar-width: thin; scrollbar-color: var(--border) transparent; }
  .scroll-thin::-webkit-scrollbar { width: 6px; height: 6px; }
  .scroll-thin::-webkit-scrollbar-track { background: transparent; }
  .scroll-thin::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--radius-full); }
  .scroll-thin::-webkit-scrollbar-thumb:hover { background: var(--border-strong); }
}

@layer lib.utilities {
  .stack { display: flex; flex-direction: column; gap: var(--stack-gap, var(--sp-4)); }
  .cluster { display: flex; flex-wrap: wrap; align-items: center; gap: var(--cluster-gap, var(--sp-2)); }
  .container, .center { margin-inline: auto; max-width: var(--container-max, 72rem); padding-inline: var(--container-pad, var(--sp-6)); }
  .text-balance { text-wrap: balance; }

  /* ---- Finite layout / spacing utilities (token-driven, RTL-safe logical
     properties, NO JIT — this is what makes "link + use" cover app screens). ---- */
  .flex { display: flex; } .inline-flex { display: inline-flex; }
  .grid { display: grid; gap: var(--grid-gap, var(--sp-4)); }
  .block { display: block; } .inline-block { display: inline-block; }
  .hidden { display: none !important; }
  .flex-col { flex-direction: column; } .flex-row { flex-direction: row; }
  .flex-wrap { flex-wrap: wrap; } .flex-nowrap { flex-wrap: nowrap; }
  .items-start { align-items: flex-start; } .items-center { align-items: center; }
  .items-end { align-items: flex-end; } .items-stretch { align-items: stretch; }
  .self-start { align-self: flex-start; } .self-end { align-self: flex-end; } .self-center { align-self: center; }
  .justify-start { justify-content: flex-start; } .justify-center { justify-content: center; }
  .justify-end { justify-content: flex-end; } .justify-between { justify-content: space-between; }
  .flex-1 { flex: 1 1 0%; min-width: 0; } .flex-auto { flex: 1 1 auto; }
  .shrink-0 { flex-shrink: 0; } .grow { flex-grow: 1; }
  .grid-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .grid-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .grid-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
  .grid-auto { grid-template-columns: repeat(auto-fill, minmax(var(--grid-min, 16rem), 1fr)); }
  .grid-rail { grid-template-columns: minmax(13rem, 17rem) minmax(0, 1fr); }
  /* Mirrored rail: content first, metadata/actions rail at the end (viewers). */
  .grid-rail-end { grid-template-columns: minmax(0, 1fr) minmax(13rem, 17rem); }
  /* Two-pane editing workspace. Desktop keeps a stable rail and a fill-height
     editor; phones stack full-width, independently usable panes inside the
     surrounding dialog/page scroller. */
  .workspace-split { display: grid; grid-template-columns: minmax(13rem, 17rem) minmax(0, 1fr); gap: var(--sp-4); block-size: 65dvh; min-block-size: 30rem; }
  .workspace-split > * { min-inline-size: 0; }
  /* Main document + contextual end Inspector. Pair the surrounding page or
     dialog with .cq so the split responds to its usable width, not only the
     viewport. The rail stays visible while both panes own their scrolling. */
  .workspace-split.workspace-split-end { grid-template-columns: minmax(0, 1fr) minmax(22rem, 26rem); align-items: start; block-size: calc(100dvh - 11rem); min-block-size: 38rem; }
  .workspace-split.workspace-split-end > * { min-block-size: 0; block-size: 100%; }
  .workspace-split.workspace-split-end > :last-child { position: sticky; inset-block-start: var(--sp-4); }
  /* Fill variant: inside a fixed app-shell main (flex column) the split grows to
     the exact remaining height instead of guessing with 100dvh math, so a
     bottom-anchored composer really touches the viewport edge. */
  .workspace-split.workspace-split-fill { flex: 1 1 0%; block-size: auto; min-block-size: 0; align-items: stretch; }
  .workspace-split.workspace-split-fill > :last-child { position: static; }
  /* Opt-in contextual end rail. A dev-drawer is the second workspace column on
     desktop, then becomes its normal modal drawer below 48rem. The trigger and
     in-panel close button are real buttons; consumers only wire open()/close(). */
  .workspace-context-toggle, .workspace-context-close { display: none; }
  .workspace-split.workspace-split-end > dev-drawer.workspace-context-drawer {
    position: relative; inset: auto; z-index: auto; display: block;
    min-inline-size: 0; min-block-size: 0; block-size: 100%;
  }
  /* AI-assisted long-form workspace: light outline, one continuous document,
     and a persistent end rail. Each column owns its vertical scrolling and the
     shell never creates a page-level horizontal scrollbar. */
  .document-workspace-shell { display: flex; flex-direction: column; min-inline-size: 0; min-block-size: 38rem; block-size: calc(100dvh - 7rem); overflow: hidden; background: var(--background); }
  .document-workspace-shell[data-fullscreen] { block-size: 100dvh; min-block-size: 0; }
  .document-workspace-topbar { flex: none; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); min-inline-size: 0; padding: var(--sp-2) var(--sp-3); border-block-end: 1px solid var(--border); background: var(--background); }
  .document-workspace-topbar-start,.document-workspace-topbar-actions,.document-workspace-title { min-inline-size: 0; }
  .document-workspace-body { flex: 1 1 auto; display: grid; grid-template-columns: minmax(11rem,14rem) minmax(38rem,1fr) minmax(24rem,28rem); min-inline-size: 0; min-block-size: 0; overflow: hidden; }
  .document-workspace-body > * { min-inline-size: 0; min-block-size: 0; }
  .document-workspace-outline,.document-workspace-main { overflow: auto; overscroll-behavior: contain; }
  .document-workspace-outline { border-inline-end: 1px solid var(--border); background: var(--surface-sunken); }
  .document-workspace-main { background: var(--surface-sunken); }
  .document-workspace-rail { display: flex; flex-direction: column; overflow: hidden; border-inline-start: 1px solid var(--border); background: var(--card); overscroll-behavior: contain; }
  .document-workspace-body > dev-drawer.workspace-context-drawer { min-inline-size: 0; min-block-size: 0; block-size: 100%; }
  .document-workspace-body > dev-drawer.workspace-context-drawer .document-workspace-rail { block-size: 100%; }
  .document-workspace-rail-scroll { flex: 1 1 auto; min-block-size: 0; overflow: auto; }
  .document-workspace-rail-head { flex: none; padding: var(--sp-3); border-block-end: 1px solid var(--border); background: linear-gradient(180deg,color-mix(in oklab,var(--brand-soft) 58%,var(--card)),var(--card)); }
  .document-workspace-agent-mark { display: inline-grid; place-items: center; inline-size: var(--control-h); block-size: var(--control-h); flex: none; border: 1px solid color-mix(in oklab,var(--brand) 40%,var(--border)); border-radius: var(--radius-md); background: var(--brand-gradient); color: var(--brand-gradient-fg); box-shadow: var(--elevation-1); }
  .document-workspace-context-card { padding: var(--sp-2); border: 1px solid color-mix(in oklab,var(--brand) 24%,var(--border)); border-radius: var(--radius-md); background: color-mix(in oklab,var(--brand-soft) 60%,var(--background)); }
  .document-workspace-context-summary { display: -webkit-box; overflow: hidden; -webkit-box-orient: vertical; -webkit-line-clamp: 3; }
  .document-workspace-context-actions { display: flex; flex-wrap: wrap; gap: var(--sp-1); }
  .document-workspace-action-chip { --action-tone:var(--brand);--action-bg:var(--brand-soft);display:inline-flex;align-items:center;gap:var(--sp-1);min-block-size:var(--control-h-sm);padding-inline:var(--sp-2);border:1px solid color-mix(in oklab,var(--action-tone) 34%,var(--border));border-radius:var(--radius-full);background:color-mix(in oklab,var(--action-bg) 72%,var(--card));color:color-mix(in oklab,var(--action-tone) 72%,var(--foreground));font:inherit;font-size:var(--text-micro);font-weight:var(--weight-semibold);cursor:pointer;transition:background var(--duration-fast) var(--ease-standard),border-color var(--duration-fast) var(--ease-standard),transform var(--duration-fast) var(--ease-standard)}
  .document-workspace-action-chip:hover,.document-workspace-action-chip[aria-pressed="true"]{background:var(--action-bg);border-color:color-mix(in oklab,var(--action-tone) 62%,var(--border))}
  .document-workspace-action-chip:active{transform:translateY(1px)}
  .document-workspace-action-chip:focus-visible{outline:2px solid transparent;box-shadow:var(--focus-ring)}
  .document-workspace-action-chip[data-tone="image"],.document-workspace-action-chip[data-tone="reference"]{--action-tone:var(--success);--action-bg:var(--success-bg)}
  .document-workspace-action-chip[data-tone="video"]{--action-tone:var(--info);--action-bg:var(--info-bg)}
  .document-workspace-action-chip[data-tone="audio"],.document-workspace-action-chip[data-tone="settings"]{--action-tone:var(--warning);--action-bg:var(--warning-bg)}
  .document-workspace-action-chip[data-tone="history"]{--action-tone:var(--muted-foreground);--action-bg:var(--muted)}
  .document-workspace-reference-strip { flex: none; padding: var(--sp-2) var(--sp-3); border-block-end: 1px solid var(--border); background: var(--background); }
  .document-workspace-reference-list { display: flex; gap: var(--sp-2); max-inline-size: 100%; overflow-x: auto; padding-block-end: var(--sp-1); overscroll-behavior-inline: contain; scrollbar-width: thin; }
  .document-workspace-reference-item { --reference-tone:var(--info);position:relative;display:grid;grid-template-rows:calc(var(--sp-8) + var(--sp-2)) auto auto;inline-size:calc(var(--sp-12) + var(--sp-4));min-inline-size:calc(var(--sp-12) + var(--sp-4));padding:0;overflow:hidden;border:1px solid color-mix(in oklab,var(--reference-tone) 42%,var(--border));border-radius:var(--radius-md);background:var(--card);color:var(--foreground);font:inherit;text-align:start;box-shadow:var(--elevation-1)}
  .document-workspace-reference-item[data-tone="scene"]{--reference-tone:var(--success)}
  .document-workspace-reference-item[data-tone="prop"]{--reference-tone:var(--warning)}
  .document-workspace-reference-item[data-tone="style"]{--reference-tone:var(--brand)}
  .document-workspace-reference-item[data-tone="result"],.document-workspace-reference-item[data-tone="video"]{--reference-tone:var(--brand)}
  .document-workspace-reference-item>img,.document-workspace-reference-item>video{inline-size:100%;block-size:100%;min-block-size:0;object-fit:cover;background:var(--surface-sunken)}
  .document-workspace-reference-kind{display:flex;align-items:center;gap:var(--sp-1);padding:var(--sp-0_5) var(--sp-1);border-block-start:var(--sp-0_5) solid var(--reference-tone);background:color-mix(in oklab,var(--reference-tone) 10%,var(--card));color:var(--reference-tone);font-size:var(--text-micro);font-weight:var(--weight-semibold)}
  .document-workspace-reference-label{padding:var(--sp-1);font-size:var(--text-micro);font-weight:var(--weight-medium)}
  .document-workspace-reference-lock { position:absolute;inset-block-start:var(--sp-1);inset-inline-end:var(--sp-1);display:grid;place-items:center;inline-size:var(--control-h-sm);block-size:var(--control-h-sm);padding:0;border:1px solid color-mix(in oklab,var(--card) 65%,transparent);border-radius:var(--radius-full);background:color-mix(in oklab,var(--foreground) 72%,transparent);color:var(--background);cursor:pointer }
  .document-workspace-reference-lock[aria-pressed="true"]{background:var(--brand);color:var(--brand-gradient-fg)}
  .document-workspace-reference-play { position:absolute;inset-block-start:calc(var(--sp-4) - var(--sp-1));inset-inline-start:50%;display:grid;place-items:center;transform:translateX(-50%);color:var(--brand-gradient-fg);filter:drop-shadow(0 1px 2px color-mix(in oklab,var(--foreground) 70%,transparent));pointer-events:none }
  .document-workspace-result-peek { overflow:hidden;border:1px solid var(--border);border-radius:var(--radius-md);background:var(--surface-sunken) }
  .document-workspace-result-card { flex:0 1 22rem;min-block-size:12rem;overflow:auto;padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--border);background:var(--surface-sunken);overscroll-behavior:contain }
  .document-workspace-tool-panel { flex:0 1 45%;min-block-size:10rem;display:flex;flex-direction:column;overflow:hidden;border-block-end:1px solid var(--border);background:var(--surface-sunken) }
  .document-workspace-tool-head { flex:none;padding:var(--sp-2) var(--sp-3);border-block-end:1px solid var(--border);background:var(--card) }
  .document-workspace-tool-scroll { flex:1 1 auto;min-block-size:0;overflow:auto }
  .document-workspace-thread { flex:1 1 auto;min-block-size:0;display:flex;flex-direction:column;overflow:hidden;background:var(--card) }
  .document-workspace-thread-scroll { flex:1 1 auto;min-block-size:0;overflow:auto;overscroll-behavior:contain;scrollbar-width:thin }
  .document-workspace-composer { flex: none; padding: var(--sp-3); border-block-start: 1px solid color-mix(in oklab,var(--brand) 24%,var(--border)); background: var(--card); box-shadow:var(--elevation-2); }
  .document-workspace-composer-input { resize:none;background:var(--background);border-color:color-mix(in oklab,var(--brand) 24%,var(--border)) }
  .document-workspace-composer-input:focus { border-color:var(--brand);box-shadow:var(--focus-ring) }
  .document-workspace-send,.document-workspace-preview-action { border-color:transparent;background:var(--brand-gradient);color:var(--brand-gradient-fg);box-shadow:var(--elevation-1) }
  .document-workspace-send:hover:not(:disabled),.document-workspace-preview-action:hover:not(:disabled){filter:saturate(1.08) brightness(1.02)}
  .document-workspace-outline-item { --outline-tone:var(--info);border-inline-start:var(--sp-0_5) solid transparent }
  .document-workspace-outline-item[data-tone="success"]{--outline-tone:var(--success)}
  .document-workspace-outline-item[data-tone="warning"]{--outline-tone:var(--warning)}
  .document-workspace-outline-item[data-tone="accent"]{--outline-tone:var(--brand)}
  .document-workspace-outline-item:hover{border-inline-start-color:color-mix(in oklab,var(--outline-tone) 48%,transparent);background:color-mix(in oklab,var(--outline-tone) 7%,var(--surface-sunken))}
  .document-workspace-outline-item.is-active{border-inline-start-color:var(--outline-tone);background:color-mix(in oklab,var(--outline-tone) 13%,var(--surface-sunken));color:var(--foreground)}
  .document-workspace-outline-toggle,.document-workspace-agent-dock { display: none; }
  .w-full { width: 100%; } .h-full { height: 100%; } .min-w-0 { min-width: 0; } .min-h-0 { min-height: 0; }
  .max-w-prose { max-width: 65ch; } .max-w-field { max-width: 24rem; } .max-w-full { max-width: 100%; } .max-inline-none { max-inline-size: none; }
  .relative { position: relative; } .sticky { position: sticky; }
  .overflow-auto { overflow: auto; } .overflow-hidden { overflow: hidden; }
  .border-0 { border: 0; }
  .text-pre-wrap { white-space: pre-wrap; overflow-wrap: anywhere; }
  .page-pad { padding: var(--sp-5) var(--sp-7) var(--sp-8); }
  .fieldset-reset { min-inline-size: 0; margin: 0; padding: 0; border: 0; }
  .text-center { text-align: center; } .text-end { text-align: end; }
  /* padding (logical: px=inline, py=block, ps/pe=inline start/end) */
  .p-0{padding:0} .p-1{padding:var(--sp-1)} .p-2{padding:var(--sp-2)} .p-3{padding:var(--sp-3)} .p-4{padding:var(--sp-4)} .p-6{padding:var(--sp-6)} .p-8{padding:var(--sp-8)}
  .px-0{padding-inline:0} .px-1{padding-inline:var(--sp-1)} .px-2{padding-inline:var(--sp-2)} .px-3{padding-inline:var(--sp-3)} .px-4{padding-inline:var(--sp-4)} .px-6{padding-inline:var(--sp-6)} .px-8{padding-inline:var(--sp-8)}
  .py-0{padding-block:0} .py-1{padding-block:var(--sp-1)} .py-2{padding-block:var(--sp-2)} .py-3{padding-block:var(--sp-3)} .py-4{padding-block:var(--sp-4)} .py-6{padding-block:var(--sp-6)} .py-8{padding-block:var(--sp-8)}
  /* Edge-specific padding is intentionally reset-only. Keep the public surface
     small; non-zero edge spacing should use a semantic role or a nested stack. */
  .pt-0{padding-block-start:0} .pb-0{padding-block-end:0}
  /* margin */
  .m-0{margin:0} .mx-auto{margin-inline:auto}
  .mt-0{margin-block-start:0} .mt-1{margin-block-start:var(--sp-1)} .mt-2{margin-block-start:var(--sp-2)} .mt-3{margin-block-start:var(--sp-3)} .mt-4{margin-block-start:var(--sp-4)} .mt-6{margin-block-start:var(--sp-6)} .mt-8{margin-block-start:var(--sp-8)} .mt-auto{margin-block-start:auto} .ms-auto{margin-inline-start:auto}
  .mb-0{margin-block-end:0} .mb-1{margin-block-end:var(--sp-1)} .mb-2{margin-block-end:var(--sp-2)} .mb-3{margin-block-end:var(--sp-3)} .mb-4{margin-block-end:var(--sp-4)} .mb-6{margin-block-end:var(--sp-6)} .mb-8{margin-block-end:var(--sp-8)}
  /* gap */
  .gap-0{gap:0} .gap-1{gap:var(--sp-1)} .gap-2{gap:var(--sp-2)} .gap-3{gap:var(--sp-3)} .gap-4{gap:var(--sp-4)} .gap-6{gap:var(--sp-6)} .gap-8{gap:var(--sp-8)}
  .gap-x-2{column-gap:var(--sp-2)} .gap-x-4{column-gap:var(--sp-4)} .gap-y-2{row-gap:var(--sp-2)} .gap-y-4{row-gap:var(--sp-4)}
  .truncate { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .line-clamp-2 { display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; }
  .text-left { text-align: left; } .text-center { text-align: center; } .text-right { text-align: right; }
  .sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
  .sr-only-focusable:focus, .sr-only-focusable:focus-within { position: static; width: auto; height: auto; margin: 0; overflow: visible; clip: auto; white-space: normal; }
  .mono { font-family: var(--font-mono); }
  .dim { color: var(--muted-foreground); }
  /* Type-role utilities — bind text to the role scale (so channels never write
     a raw px size). SELF-CONTAINED: each role carries its canonical font-weight
     too, so it renders identically on ANY element (span / div / h*) and never
     depends on heading defaults — which a host CSS reset (e.g. Tailwind
     preflight) would otherwise strip. Heading-rank roles default to semibold;
     text roles to normal. Override weight only when truly needed via an inline
     style — a "title that isn't bold" usually means the wrong role. */
  .text-display { font-size: var(--text-display); font-weight: var(--weight-semibold); line-height: var(--leading-heading); letter-spacing: var(--tracking-tight); }
  .text-heading { font-size: var(--text-heading); font-weight: var(--weight-semibold); line-height: var(--leading-heading); }
  .text-title { font-size: var(--text-title); font-weight: var(--weight-semibold); line-height: var(--leading-heading); }
  .text-body { font-size: var(--text-body); font-weight: var(--weight-normal); line-height: var(--leading-body); }
  .text-caption { font-size: var(--text-caption); font-weight: var(--weight-normal); line-height: var(--leading-body); }
  .text-micro { font-size: var(--text-micro); font-weight: var(--weight-normal); line-height: var(--leading-body); }
  /* Marketing poster scale — fluid hero/section type beyond --text-display (22). */
  .text-poster-sm { font-size: var(--text-poster-sm); font-weight: var(--weight-bold); line-height: 1.1; letter-spacing: var(--tracking-tight); }
  .text-poster-md { font-size: var(--text-poster-md); font-weight: var(--weight-bold); line-height: 1.05; letter-spacing: var(--tracking-tight); }
  .text-poster-lg { font-size: var(--text-poster-lg); font-weight: var(--weight-bold); line-height: 1.02; letter-spacing: var(--tracking-tight); }
  .brand-gradient-text { background-image: var(--brand-gradient); -webkit-background-clip: text; background-clip: text; color: transparent; }
  .animate-spin { animation: lib-spin 0.9s linear infinite; }
  /* Slow "living gradient" sweep — pair with .brand-gradient-text on a headline. */
  .animate-shine { background-size: 200% auto; animation: lib-shine 5.5s ease-in-out infinite; }
  /* Keep page transitions opacity-only. A transformed page becomes the
     containing block for fixed-position dropdowns/dialogs, which offsets
     floating panels by the app sidebar and can push them off-screen. */
  .page-enter { animation: lib-fade-in 0.24s var(--ease-out); }
  /* Element-level entrance (chat bubbles, media cards). Element scope only —
     never on a page/panel container (transform would trap fixed children,
     see .page-enter note above). `both` keeps the pre-animation frame hidden. */
  .fade-up { animation: lib-fade-up var(--duration-slow) var(--ease-out) both; }
  .stagger-1 { animation-delay: 0.05s; } .stagger-2 { animation-delay: 0.1s; }
  .stagger-3 { animation-delay: 0.15s; } .stagger-4 { animation-delay: 0.2s; }
  /* Responsive overrides must stay in the same cascade layer as the desktop
     utility. A lower-priority component layer cannot override utilities even
     when its media query matches. */
  @media (max-width: 48rem) {
    .grid-rail, .grid-rail-end { grid-template-columns: minmax(0, 1fr); }
    /* Settings and other dense section navigation can opt into a compact,
       horizontally scrollable rail. Keeping the rail in normal flow avoids
       a full-height sidebar overlapping the stacked content on phones. */
    .grid-rail.grid-rail-nav > .sidebar {
      flex-direction: row;
      block-size: calc(var(--control-h) + var(--sp-4));
      min-block-size: calc(var(--control-h) + var(--sp-4));
      inline-size: 100%;
      max-inline-size: 100%;
      overflow-x: auto;
      overflow-y: hidden;
      padding-block: var(--sp-2);
      border-inline-end: 0;
      border-block-end: 1px solid var(--border);
      overscroll-behavior-inline: contain;
      scroll-snap-type: x proximity;
      scroll-padding-inline: var(--sp-2);
      -webkit-overflow-scrolling: touch;
    }
    .grid-rail.grid-rail-nav > .sidebar > .sidebar-label { display: none; }
    .grid-rail.grid-rail-nav > .sidebar > .sidebar-item {
      flex: 0 0 auto;
      inline-size: auto;
      white-space: nowrap;
      scroll-snap-align: start;
      scroll-margin-inline: var(--sp-2);
    }
    .grid-rail.grid-rail-nav > .sidebar > .sidebar-item.is-active,
    .grid-rail.grid-rail-nav > .sidebar > .sidebar-item[aria-current="page"] { scroll-snap-align: center; }
    .grid-rail.grid-rail-nav > .sidebar > .sidebar-item::before {
      inset-inline: var(--sp-2);
      inset-block-start: auto;
      inset-block-end: 0;
      inline-size: auto;
      block-size: 2px;
      border-radius: var(--radius-full);
    }
    .workspace-split { grid-template-columns: minmax(0, 1fr); block-size: auto; min-block-size: 0; }
    .workspace-split > * { min-block-size: 30rem; }
    .workspace-split.workspace-split-end { grid-template-columns: minmax(0, 1fr); block-size: auto; min-block-size: 0; }
    .workspace-split.workspace-split-end > * { min-block-size: 30rem; block-size: auto; }
    .workspace-split.workspace-split-end > :last-child:not(.workspace-context-drawer) { position: static; }
    .workspace-split.workspace-split-fill { flex: 0 0 auto; }
    .workspace-split.workspace-split-end > dev-drawer.workspace-context-drawer[data-context-modal] {
      position: fixed; inset: 0; z-index: var(--z-modal); display: none;
      min-block-size: 0; block-size: auto;
    }
    .workspace-split.workspace-split-end > dev-drawer.workspace-context-drawer[data-context-modal][open] { display: block; }
    /* These controls exist only in the phone drawer flow, so their touch
       target must not depend on pointer-capability detection. Width emulation,
       hybrid devices and mobile browsers can all report a fine pointer. */
    .workspace-context-toggle, .workspace-context-close {
      display: inline-flex;
      min-block-size: var(--sp-11);
    }
    .page-pad { padding-inline: var(--sp-3); }
    .workflow-steps { grid-template-columns: minmax(0, 1fr); }
  }
  @container (max-width: 56rem) {
    .workspace-split.workspace-split-fill { flex: 0 0 auto; }
    .workspace-split.workspace-split-end { grid-template-columns: minmax(0, 1fr); block-size: auto; min-block-size: 0; }
    .workspace-split.workspace-split-end > * { min-block-size: 30rem; block-size: auto; }
    .workspace-split.workspace-split-end > :last-child:not(.workspace-context-drawer) { position: static; }
    .workspace-split.workspace-split-end > dev-drawer.workspace-context-drawer[data-context-modal] {
      position: fixed; inset: 0; z-index: var(--z-modal); display: none;
      min-block-size: 0; block-size: auto;
    }
    .workspace-split.workspace-split-end > dev-drawer.workspace-context-drawer[data-context-modal][open] { display: block; }
    .workspace-context-toggle, .workspace-context-close {
      display: inline-flex;
      min-block-size: var(--sp-11);
    }
    .document-workspace-shell { block-size: calc(100dvh - 4rem); min-block-size: 0; }
    .document-workspace-topbar { padding-inline: var(--sp-2); }
    .document-workspace-body { display: block; overflow: hidden; }
    .document-workspace-main { block-size: 100%; padding-block-end: calc(var(--sp-11) + var(--sp-4)); }
    .document-workspace-body > dev-drawer.workspace-context-drawer[data-context-modal] {
      position: fixed; inset: 0; z-index: var(--z-modal); display: none;
      min-block-size: 0; block-size: auto;
    }
    .document-workspace-body > dev-drawer.workspace-context-drawer[data-context-modal][open] { display: block; }
    .document-workspace-agent-dock {
      position: fixed; z-index: var(--z-sticky); inset-inline: var(--sp-3); inset-block-end: var(--sp-3);
      display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2);
      min-block-size: var(--sp-11); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border);
      border-radius: var(--radius-full); background: var(--card); color: var(--card-foreground,var(--foreground));
      box-shadow: var(--elevation-3);
    }
  }

  @media (max-width: 80rem) {
    .document-workspace-body { grid-template-columns: minmax(38rem,1fr) minmax(22rem,24rem); }
    .document-workspace-outline { display: none; }
    .document-workspace-outline-toggle { display: inline-flex; }
  }

  @media (max-width: 56rem) {
    .document-workspace-shell { block-size: calc(100dvh - 4rem); min-block-size: 0; }
    .document-workspace-topbar { padding-inline: var(--sp-2); }
    .document-workspace-body { display: block; overflow: hidden; }
    .document-workspace-main { block-size: 100%; padding-block-end: calc(var(--sp-11) + var(--sp-4)); }
    .document-workspace-agent-dock { position: fixed; z-index: var(--z-sticky); inset-inline: var(--sp-3); inset-block-end: var(--sp-3); display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); min-block-size: var(--sp-11); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); border-radius: var(--radius-full); background: var(--card); color: var(--card-foreground,var(--foreground)); box-shadow: var(--elevation-3); }
  }

  @media (max-width: 30rem) {
    .document-workspace-topbar { flex-wrap: wrap; gap: var(--sp-1); }
    .document-workspace-topbar-start,.document-workspace-topbar-actions { inline-size: 100%; }
    .document-workspace-topbar-start { flex: 1 1 100%; }
    .document-workspace-topbar-actions { justify-content: flex-end; }
    .document-workspace-subtitle { display: none; }
  }
}

/* Keyframes (outside @layer — not subject to the cascade). */
@keyframes lib-spin { to { transform: rotate(360deg); } }
@keyframes lib-fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes lib-scale-in { from { opacity: 0; transform: scale(0.97); } to { opacity: 1; transform: scale(1); } }
@keyframes lib-fade-up { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: none; } }
@keyframes lib-shimmer { to { background-position: -200% 0; } }
@keyframes lib-indeterminate { 0% { margin-left: -40%; } 100% { margin-left: 100%; } }
@keyframes lib-marquee { from { transform: translateX(0); } to { transform: translateX(-50%); } }
@keyframes lib-shine { 0% { background-position: 0% center; } 50% { background-position: 120% center; } 100% { background-position: 0% center; } }
@media (prefers-reduced-motion: reduce) { .animate-shine { animation: none; } }

/* ---- Forced-colors / Windows High Contrast Mode. box-shadow (our focus ring)
   is stripped here, so restore real borders + a system-colored focus outline,
   and keep functional fills painted. Top-level (not layered) so it wins. ---- */
@media (forced-colors: active) {
  .btn, .input, .textarea, select.input, .tag, .card, .alert, .modal-card,
  .kbd, .code, .avatar { border: 1px solid ButtonText; }
  .btn-ghost { border-color: transparent; }
  :focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
  .progress-bar, .skeleton, .spinner { forced-color-adjust: none; }
}

/* ---- Scrim robustness: opaque fallback where backdrop-filter is unsupported,
   and respect prefers-reduced-transparency. ---- */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .overlay { background: rgba(20, 20, 22, 0.62); }
}
@media (prefers-reduced-transparency: reduce) {
  .overlay { background: var(--background); -webkit-backdrop-filter: none; backdrop-filter: none; }
}

/* ===== vP5 — structural components (pure CSS; same @layer merges) ===== */
@layer lib.components {
  /* Tabs (visual; consumer wires roving-tabindex / panels) */
  .tabs { display: flex; gap: var(--sp-1); border-block-end: 1px solid var(--border); }
  .tabs.tabs-scroll { overflow-x: auto; scrollbar-width: thin; overscroll-behavior-inline: contain; scroll-snap-type: x proximity; scroll-padding-inline: var(--sp-2); -webkit-overflow-scrolling: touch; }
  .tabs.tabs-scroll > .tab { flex: 0 0 auto; scroll-snap-align: start; scroll-margin-inline: var(--sp-2); }
  .tab { appearance: none; background: none; border: none; cursor: pointer; padding: var(--sp-2) var(--sp-3); font: inherit; font-size: var(--text-caption); color: var(--muted-foreground); border-block-end: 2px solid transparent; margin-block-end: -1px; }
  .tabs.tabs-compact > .tab { padding-inline: var(--sp-2); }
  .tab:hover { color: var(--foreground); background: var(--state-hover); border-start-start-radius: var(--radius-sm); border-start-end-radius: var(--radius-sm); }
  .tab[aria-selected="true"], .tab.is-active { color: var(--foreground); border-block-end-color: var(--ui-accent); font-weight: var(--weight-semibold); }
  .tabs.tabs-scroll > .tab[aria-selected="true"], .tabs.tabs-scroll > .tab.is-active { scroll-snap-align: center; }
  .tab:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }

  /* Table */
  .table { width: 100%; border-collapse: collapse; font-size: var(--text-caption); font-variant-numeric: tabular-nums; }
  .table th, .table td { padding: var(--sp-2) var(--sp-3); text-align: start; border-block-end: 1px solid var(--border); }
  .table thead th { font-size: var(--text-micro); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wide); white-space: nowrap; color: var(--muted-foreground); background: var(--surface-sunken); border-block-end-color: var(--border-strong); }
  .table tbody tr:hover { background: var(--state-hover); }
  .table-zebra tbody tr:nth-child(even) { background: color-mix(in oklab, var(--foreground) 3%, transparent); }
  .table tr[aria-selected="true"], .table tr.is-selected { background: var(--state-selected); }
  .table-sticky thead th { position: sticky; inset-block-start: 0; z-index: 1; }
  /* Dense operational tables with many columns should preserve readable cells
     and let .table-wrap provide horizontal scrolling instead of crushing every
     column into a few characters. */
  .table-wide { min-inline-size: 72rem; }
  /* Wrap a wide .table in this so it scrolls horizontally on a narrow screen
     instead of overflowing the viewport (clipping the 操作/copy buttons on the
     right). The wrapper carries the scroll; the table keeps its desktop layout. */
  .table-wrap { inline-size: 100%; max-inline-size: 100%; overflow-x: auto; scrollbar-width: thin; -webkit-overflow-scrolling: touch; overscroll-behavior-inline: contain; }

  /* Input group + addons */
  .input-group { display: flex; align-items: stretch; }
  .input-group > .input, .input-group > .input-addon { border-radius: 0; }
  .input-group > :first-child { border-start-start-radius: var(--radius); border-end-start-radius: var(--radius); }
  .input-group > :last-child { border-start-end-radius: var(--radius); border-end-end-radius: var(--radius); }
  .input-group > :not(:first-child) { margin-inline-start: -1px; }
  .input-addon { display: inline-flex; align-items: center; padding: 0 var(--sp-3); white-space: nowrap; background: var(--secondary); border: 1px solid var(--border); color: var(--muted-foreground); font-size: var(--text-caption); }

  /* Button group (segmented) */
  .button-group { display: inline-flex; }
  .button-group > .btn { border-radius: 0; }
  .button-group > .btn:first-child { border-start-start-radius: var(--radius); border-end-start-radius: var(--radius); }
  .button-group > .btn:last-child { border-start-end-radius: var(--radius); border-end-end-radius: var(--radius); }
  .button-group > .btn:not(:first-child) { margin-inline-start: -1px; }

  /* Breadcrumb */
  .breadcrumb { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-2); margin: 0; padding: 0; list-style: none; font-size: var(--text-caption); color: var(--muted-foreground); }
  .breadcrumb li { display: flex; align-items: center; gap: var(--sp-2); }
  .breadcrumb li:not(:last-child)::after { content: "/"; color: var(--border-strong); }
  .breadcrumb a { color: var(--muted-foreground); text-decoration: none; }
  .breadcrumb a:hover { color: var(--foreground); }
  .breadcrumb [aria-current="page"] { color: var(--foreground); font-weight: var(--weight-medium); }

  /* Pagination */
  .pagination { display: flex; align-items: center; gap: var(--sp-1); margin: 0; padding: 0; list-style: none; }
  .pagination .page { display: inline-flex; align-items: center; justify-content: center; min-width: var(--control-h); height: var(--control-h); padding: 0 var(--sp-2); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-raised); color: var(--foreground); font-size: var(--text-caption); text-decoration: none; cursor: pointer; }
  .pagination .page:hover { border-color: var(--border-strong); background: color-mix(in oklab, var(--foreground) 5%, var(--surface-raised)); }
  .pagination .page:active { background: color-mix(in oklab, var(--foreground) 9%, var(--surface-raised)); }
  .pagination .page[aria-current="page"] { background: var(--primary); color: var(--primary-foreground); border-color: transparent; }

  /* List */
  .list { display: flex; flex-direction: column; overflow: hidden; background: var(--card); border: 1px solid var(--border); border-radius: var(--radius-lg); }
  .list-header { padding: var(--sp-2) var(--sp-3); font-size: var(--text-micro); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--muted-foreground); background: var(--surface-sunken); border-block-end: 1px solid var(--border); }
  .list-item { display: flex; align-items: center; gap: var(--sp-3); padding: var(--sp-3); border-block-end: 1px solid var(--border); }
  .list-item:last-child { border-block-end: none; }
  .list-item:hover { background: var(--state-hover); }
  .list-item.list-item-bordered { border: 1px solid var(--border); border-radius: var(--radius); }

  /* Banner (page-level vs inline .alert) */
  .banner { display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-4); font-size: var(--text-caption); color: var(--foreground); background: var(--surface-sunken); border-block-end: 1px solid var(--border); }
  .banner-success { background: var(--success-bg); }
  .banner-warning { background: var(--warning-bg); }
  .banner-danger { background: var(--danger-bg); }
  .banner-info { background: var(--info-bg); }

  /* Accordion (native <details>) */
  .accordion { overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-lg); }
  .accordion > details { border-block-end: 1px solid var(--border); }
  .accordion > details:last-child { border-block-end: none; }
  .accordion summary { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-3); font-weight: var(--weight-medium); cursor: pointer; list-style: none; }
  .accordion summary:hover { background: var(--state-hover); }
  .accordion summary:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
  .accordion summary::-webkit-details-marker { display: none; }
  .accordion summary::after { content: "▸"; color: var(--muted-foreground); transition: transform var(--duration-fast) var(--ease-smooth); }
  .accordion details[open] > summary::after { transform: rotate(90deg); }
  .accordion-body { padding: 0 var(--sp-3) var(--sp-3); font-size: var(--text-caption); color: var(--muted-foreground); }

  /* Single advanced disclosure. Channels often need one optional filter or
     expert-settings block without constructing a full accordion wrapper. */
  .advanced-filter { overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius-lg); background: var(--surface-raised); }
  .advanced-filter > summary { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-3); font-weight: var(--weight-medium); cursor: pointer; list-style: none; }
  .advanced-filter > summary:hover { background: var(--state-hover); }
  .advanced-filter > summary:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); border-radius: var(--radius-sm); }
  .advanced-filter > summary::-webkit-details-marker { display: none; }
  .advanced-filter > summary::after { content: "▸"; color: var(--muted-foreground); transition: transform var(--duration-fast) var(--ease-smooth); }
  .advanced-filter[open] > summary { border-block-end: 1px solid var(--border); }
  .advanced-filter[open] > summary::after { transform: rotate(90deg); }
}

/* ===== vP6 — component breadth: batch 1 (separator / label / skeleton-text /
   stat-card / segmented). Pure CSS, same @layer merges. ===== */
@layer lib.components {
  /* Separator (explicit h/v line; .divider stays the margin'd <hr>) */
  .separator { flex: none; border: none; background: var(--border); }
  .separator:not(.separator-vertical) { block-size: 1px; inline-size: 100%; }
  .separator-vertical { inline-size: 1px; align-self: stretch; min-block-size: 1em; }
  /* Dashed variant — soft boundary for collapsible detail regions (e.g. a
     composer's advanced-params fold). Draws with a dashed border, not bg. */
  .separator-dashed:not(.separator-vertical) { block-size: 0; background: transparent; border-block-start: 1px dashed var(--border); }
  .separator-dashed.separator-vertical { inline-size: 0; background: transparent; border-inline-start: 1px dashed var(--border); }

  /* Fit-content input/select — for bare inline controls in a toolbar row where
     the default width:100% would blow the flex line. select.input-fit matches
     select.input's specificity so the width:100% base loses. */
  .input-fit, select.input-fit { width: auto; min-width: 0; }

  /* Standalone label (complements grid-context .form-label) */
  .label { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--text-caption); font-weight: var(--weight-medium); color: var(--foreground); }
  .label .required { color: var(--danger); }
  .label-muted { color: var(--muted-foreground); font-weight: var(--weight-normal); }

  /* Skeleton text line (paragraph placeholders; last line is shorter) */
  .skeleton-text { display: block; block-size: 0.7em; margin-block: 0.35em; border-radius: var(--radius-sm); background: linear-gradient(90deg, var(--muted) 25%, var(--surface-sunken) 50%, var(--muted) 75%); background-size: 200% 100%; animation: lib-shimmer 1.3s linear infinite; }
  .skeleton-text:last-child { inline-size: 70%; }

  /* NOTE: .stat-card intentionally NOT defined here — the clipboard channel
     already uses that class name for its own boxes. It will return once that
     channel adopts lib's version (see docs/lib-design-system-progress.md). */

  /* Segmented control (visual radio / mode switch). Works with aria-pressed
     buttons OR <label><input type=radio>…</label> via :has(). */
  .segmented { display: inline-flex; gap: 2px; padding: 2px; background: var(--surface-sunken); border: 1px solid var(--border); border-radius: var(--radius); }
  .segmented > button, .segmented > label { appearance: none; border: none; background: none; cursor: pointer; font: inherit; font-size: var(--text-caption); color: var(--muted-foreground); padding: 0 var(--sp-3); min-block-size: calc(var(--control-h) - 6px); display: inline-flex; align-items: center; justify-content: center; border-radius: calc(var(--radius) - 2px); white-space: nowrap; transition: background-color 120ms var(--ease-smooth), color 120ms var(--ease-smooth); }
  .segmented > button:hover, .segmented > label:hover { color: var(--foreground); }
  .segmented > button[aria-pressed="true"], .segmented > [aria-selected="true"], .segmented > .is-active, .segmented > label:has(input:checked) { background: var(--surface-raised); color: var(--foreground); box-shadow: var(--shadow-card); font-weight: var(--weight-medium); }
  .segmented > label > input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
  .segmented > button:focus-visible, .segmented > label:focus-within { outline: 2px solid transparent; box-shadow: var(--focus-ring); }
  .segmented > button:disabled, .segmented > label:has(input:disabled) { opacity: var(--state-disabled-opacity); cursor: not-allowed; }

  /* Menu / dropdown surface — styles the slotted content of <dev-menu>, and
     stands alone for pure-CSS menus. */
  .menu { display: flex; flex-direction: column; min-inline-size: 11rem; padding: var(--sp-1); background: var(--popover); color: var(--popover-foreground); border: 1px solid var(--border); border-radius: var(--radius); box-shadow: var(--elevation-3); }
  .menu-item { display: flex; align-items: center; gap: var(--sp-2); inline-size: 100%; box-sizing: border-box; padding: var(--sp-1) var(--sp-2); border: none; background: none; border-radius: var(--radius-sm); font: inherit; font-size: var(--text-caption); color: var(--foreground); text-align: start; cursor: pointer; }
  .menu-item:hover, .menu-item:focus-visible, .menu-item.is-active { background: var(--state-hover); outline: none; }
  .menu-item:disabled, .menu-item[aria-disabled="true"] { opacity: var(--state-disabled-opacity); pointer-events: none; }
  .menu-item-danger { color: var(--danger); }
  .menu-item-danger:hover, .menu-item-danger:focus-visible { background: var(--danger-bg); }
  .menu-item .menu-shortcut { margin-inline-start: auto; padding-inline-start: var(--sp-4); color: var(--muted-foreground); font-size: var(--text-micro); }
  .menu-sep { block-size: 1px; background: var(--border); margin: var(--sp-1) calc(-1 * var(--sp-1)); }
  .menu-label { padding: var(--sp-1) var(--sp-2); font-size: var(--text-micro); font-weight: var(--weight-semibold); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--muted-foreground); }
  /* Anchored popover variant: pair with .menu inside a position:relative anchor
     (e.g. a composer's @-mention layer). Fixed compact width, capped height,
     floats above the anchor; interior scrolling belongs to a .scroll-area child. */
  .menu-float { position: absolute; inset-block-end: 100%; inset-inline-start: 0; z-index: 60; inline-size: min(26.25rem, 100%); max-block-size: 25rem; margin-block-end: var(--sp-2); border-radius: var(--radius-lg); overflow: hidden; }

  /* ---- batch 3: scroll-area (drawer/lightbox are web components).
     NOTE: .dropzone intentionally NOT defined — xsvg already uses that class
     name; it returns once that channel adopts lib's version. ---- */
  .scroll-area { overflow: auto; max-block-size: var(--scroll-max, 16rem); scrollbar-width: thin; scrollbar-color: var(--border) transparent; overscroll-behavior: contain; }
  .scroll-area::-webkit-scrollbar { width: 8px; height: 8px; }
  .scroll-area::-webkit-scrollbar-track { background: transparent; }
  .scroll-area::-webkit-scrollbar-thumb { background: var(--border); border-radius: var(--radius-full); border: 2px solid transparent; background-clip: content-box; }
  .scroll-area::-webkit-scrollbar-thumb:hover { background: var(--border-strong); background-clip: content-box; }

  /* ---- batch 4: slider / stepper / chip (combobox + collapsible are WCs) ---- */
  .slider { -webkit-appearance: none; appearance: none; inline-size: 100%; max-inline-size: 18rem; block-size: 1.25rem; background: transparent; cursor: pointer; }
  .slider::-webkit-slider-runnable-track { block-size: 4px; border-radius: var(--radius-full); background: var(--muted); }
  .slider::-moz-range-track { block-size: 4px; border-radius: var(--radius-full); background: var(--muted); }
  .slider::-moz-range-progress { block-size: 4px; border-radius: var(--radius-full); background: var(--primary); }
  .slider::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; inline-size: 14px; block-size: 14px; margin-block-start: -5px; border-radius: 50%; background: var(--background); border: 2px solid var(--primary); box-shadow: var(--shadow-card); transition: box-shadow 120ms var(--ease-smooth); }
  .slider::-moz-range-thumb { inline-size: 14px; block-size: 14px; border: 2px solid var(--primary); border-radius: 50%; background: var(--background); box-shadow: var(--shadow-card); }
  .slider:focus-visible { outline: none; }
  .slider:focus-visible::-webkit-slider-thumb { box-shadow: var(--focus-ring); }
  .slider:focus-visible::-moz-range-thumb { box-shadow: var(--focus-ring); }
  .slider:disabled { opacity: var(--state-disabled-opacity); cursor: not-allowed; }

  .stepper { display: inline-flex; align-items: stretch; border: 1px solid var(--c-input-border); border-radius: var(--radius); overflow: hidden; background: var(--c-input-bg); }
  .stepper > button { appearance: none; border: none; background: var(--secondary); color: var(--foreground); inline-size: var(--control-h); cursor: pointer; font: inherit; font-size: var(--text-body); display: inline-flex; align-items: center; justify-content: center; }
  .stepper > button:hover { background: var(--state-hover); }
  .stepper > button:disabled { opacity: var(--state-disabled-opacity); cursor: not-allowed; }
  .stepper > input { inline-size: 3rem; border: none; text-align: center; background: transparent; color: inherit; font: inherit; font-size: var(--text-body); -moz-appearance: textfield; appearance: textfield; outline: none; }
  .stepper > input::-webkit-outer-spin-button, .stepper > input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
  .stepper:focus-within { border-color: var(--ring); box-shadow: var(--focus-ring); }

  .chip { display: inline-flex; align-items: center; gap: var(--sp-1); padding-block: 0.1875rem; padding-inline: var(--sp-2); font-size: var(--text-micro); border: 1px solid var(--border); border-radius: var(--radius-full); background: var(--secondary); color: var(--foreground); white-space: nowrap; }
  .chip-clickable { cursor: pointer; transition: background-color 120ms var(--ease-smooth), border-color 120ms var(--ease-smooth); }
  .chip-clickable:hover { border-color: var(--border-strong); background: var(--state-hover); }
  .chip.is-selected { background: var(--primary); color: var(--primary-foreground); border-color: transparent; }
  /* Tinted semantic chips — coloured bg + matching border, but KEEP .chip's
     readable --foreground text (unlike the soft .tag-*, whose saturated text can
     read faintly). For many small coloured chips that must each stay legible. */
  .chip-info    { background: var(--info-bg);    border-color: var(--info-border);    }
  .chip-warning { background: var(--warning-bg); border-color: var(--warning-border); }
  .chip-success { background: var(--success-bg); border-color: var(--success-border); }
  .chip-danger  { background: var(--danger-bg);  border-color: var(--danger-border);  }
  .chip-brand   { background: var(--brand-soft); border-color: var(--brand-soft-hover); }
  .chip-remove { display: inline-flex; align-items: center; justify-content: center; inline-size: 1rem; block-size: 1rem; margin-inline-end: -3px; padding: 0; border: none; border-radius: 50%; background: none; color: inherit; cursor: pointer; font-size: 0.9em; line-height: 1; opacity: 0.65; }
  .chip-remove:hover { opacity: 1; background: color-mix(in oklab, currentColor 18%, transparent); }

  /* ---- batch 5: sidebar / carousel / command-item (tabs + command are WCs) ---- */
  /* Items in a section are tight (2px); each .sidebar-label opens a new section —
     the first hugs the top, the rest get a hairline rule + breathing room so the
     groups (e.g. Console vs Admin) are unmistakably separate. Items carry a
     leading icon slot (any inline svg) that follows the row colour. */
  /* min-block-size:100% so the rail (and its border-inline-end divider) fills a
     stretched parent all the way down instead of stopping at content height —
     null-effect when the parent has no definite height, so it never over-stretches
     a non-app-shell usage. */
  .sidebar { display: flex; flex-direction: column; min-block-size: 100%; gap: 2px; inline-size: var(--sidebar-w, 15rem); padding: var(--sp-3) var(--sp-2); background: var(--sidebar, var(--surface-sunken)); color: var(--sidebar-foreground, var(--foreground)); border-inline-end: 1px solid var(--border); }
  .sidebar-label { padding: var(--sp-1) var(--sp-2); font-size: var(--text-micro); font-weight: var(--weight-bold); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--muted-foreground); }
  .sidebar-label:first-child { margin-block-start: 0; }
  .sidebar-label:not(:first-child) { margin-block-start: var(--sp-3); padding-block-start: var(--sp-4); border-block-start: 1px solid var(--border); }
  /* Item text uses --text-menu (13px / medium) — the platform-wide left-nav
     standard shared with the AI对话 and AI短剧 sidebars. */
  .sidebar-item { position: relative; display: flex; align-items: center; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: none; background: none; border-radius: var(--radius); font: inherit; font-size: var(--text-menu, 0.8125rem); font-weight: var(--weight-medium); color: inherit; text-decoration: none; text-align: start; cursor: pointer; transition: background-color var(--duration-fast) var(--ease-smooth), color var(--duration-fast) var(--ease-smooth); }
  .sidebar-item > svg { inline-size: 1rem; block-size: 1rem; flex-shrink: 0; opacity: 0.8; transition: opacity var(--duration-fast) var(--ease-smooth), color var(--duration-fast) var(--ease-smooth); }
  .sidebar-item:hover { background: var(--state-hover); color: var(--foreground); }
  .sidebar-item:hover > svg { opacity: 0.95; }
  /* Row-hover-revealed inline action (delete/rename on list rows): invisible
     until the row is hovered or the control is keyboard-focused; always
     faintly visible on touch devices where hover cannot reveal it. */
  .row-action { opacity: 0; transition: opacity var(--duration-fast) var(--ease-smooth); }
  :hover > .row-action, .row-action:focus-visible { opacity: 1; }
  @media (hover: none) { .row-action { opacity: 0.55; } }
  .sidebar-item:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); }
  /* Active item: a neutral grey wash (NOT brand-tinted) + a blue accent bar on
     the leading edge — a calm, on-any-brand "selected" signal that doesn't fight
     a white-label palette. */
  .sidebar-item.is-active, .sidebar-item[aria-current="page"] { background: var(--state-pressed); color: var(--foreground); font-weight: var(--weight-semibold); }
  .sidebar-item.is-active > svg, .sidebar-item[aria-current="page"] > svg { opacity: 1; color: var(--foreground); }
  .sidebar-item.is-active:hover, .sidebar-item[aria-current="page"]:hover { background: var(--state-pressed); color: var(--foreground); }
  .sidebar-item.is-active::before, .sidebar-item[aria-current="page"]::before { content: ""; position: absolute; inset-block: 0.3rem; inset-inline-start: 0; inline-size: 3px; border-radius: 0 var(--radius-sm) var(--radius-sm) 0; background: var(--info); }
  .sidebar-item > .tag, .sidebar-item > .chip { margin-inline-start: auto; }

  /* ---- canonical app-shell — the ONE full-page layout every product emits ----
     Gives the lib .sidebar a definite full height so its border-inline-end divider
     runs edge-to-edge to the bottom, without each product re-inventing min-h-screen /
     grid / items-start glue. Document-scroll preserving (NO internal scroll, NO pinned
     footer): the shell is min 100dvh and GROWS with tall content. Structure:
       .app-shell > [header] + .app-shell-body( .sidebar + .app-main ) + [footer / mobile-nav]
     Short page → the body-row fills the viewport (rail reaches the bottom); tall page →
     it grows to content height (rail reaches the content's bottom) and the page scrolls
     normally. 100dvh is mobile-URL-bar correct; logical props keep it writing-mode safe. */
  .app-shell { display: flex; flex-direction: column; min-block-size: 100dvh; }
  /* The row fills the height left under the header (flex:1) but never shrinks below its
     content — so the rail reaches the bottom on short AND tall pages. */
  .app-shell-body { display: flex; flex: 1; }
  .app-shell-body > .sidebar, .app-shell-body > .app-sidebar { align-self: stretch; }
  /* Content pane: fills the row inline; min-inline-size:0 lets long content shrink
     instead of overflowing. Padding is opt-in via --app-main-pad (default 0 so
     full-bleed pages and padded consoles both compose without per-product overrides). */
  .app-main { flex: 1; min-inline-size: 0; padding: var(--app-main-pad, 0); }

  /* Opt-in fixed-viewport console/editor shell. The header stays in flow while
     the body consumes the remaining viewport and only the main pane scrolls.
     Products select the behavior; they do not reimplement height/overflow CSS. */
  .app-shell.app-shell-fixed { block-size: 100dvh; min-block-size: 0; overflow: hidden; }
  .app-shell.app-shell-fixed > .app-shell-body { min-block-size: 0; overflow: hidden; }
  .app-shell.app-shell-fixed > .app-shell-body > .app-main { display: flex; flex-direction: column; min-block-size: 0; overflow: auto; }

  /* ---- responsive app-shell — phone sidebar drawer (< the header's 768px PC
     breakpoint) ----------------------------------------------------------------
     Desktop: .sidebar is the in-flow rail. Phone: it becomes an off-canvas drawer
     toggled by a product-rendered hidden checkbox (.app-nav-toggle-input) — pure
     CSS via :has(), NO JS, and picking a nav item (which re-renders the shell)
     closes it. Products emit, as children of .app-shell-body: the hidden checkbox,
     .sidebar, <main.app-main> (whose first child is a label.app-nav-toggle
     hamburger), then a label.app-nav-backdrop. All the off-canvas chrome is hidden
     on desktop, so adding the markup is inert above the breakpoint. */
  .app-nav-toggle-input { position: absolute; inline-size: 1px; block-size: 1px; margin: -1px; opacity: 0; pointer-events: none; }
  .app-nav-toggle { display: none; align-self: flex-start; align-items: center; justify-content: center; gap: var(--sp-2); block-size: 2.25rem; min-inline-size: 2.25rem; padding: 0 var(--sp-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-raised); color: var(--foreground); font: inherit; font-size: var(--text-caption); font-weight: var(--weight-medium); cursor: pointer; user-select: none; }
  .app-nav-toggle:hover { background: var(--state-hover); }
  .app-nav-toggle > svg { inline-size: 1.1rem; block-size: 1.1rem; flex: none; }
  .app-nav-backdrop { display: none; }
  @media (max-width: 48rem) {
    /* Strictly OPT-IN: the off-canvas behavior only engages when the page emits
       the .app-nav-toggle-input checkbox (+ a .app-nav-toggle hamburger). A shell
       without the toggle keeps its in-flow sidebar unchanged, so this is safe for
       every channel that hasn't adopted the drawer yet. */
    .app-shell-body:has(> .app-nav-toggle-input) > .sidebar,
    .app-shell-body:has(> .app-nav-toggle-input) > .app-sidebar {
      position: fixed; inset-block: 0; inset-inline-start: 0; z-index: 60;
      inline-size: min(17rem, 82vw); max-inline-size: 82vw;
      transform: translateX(-100%);
      transition: transform var(--duration-medium, 0.22s) var(--ease-smooth, ease);
      box-shadow: var(--shadow-float, 0 10px 30px rgba(0, 0, 0, 0.22));
      overflow-y: auto;
    }
    .app-shell-body:has(> .app-nav-toggle-input:checked) > .sidebar,
    .app-shell-body:has(> .app-nav-toggle-input:checked) > .app-sidebar { transform: translateX(0); }
    .app-shell-body:has(> .app-nav-toggle-input) .app-nav-backdrop { display: block; position: fixed; inset: 0; z-index: 55; border: 0; background: rgba(0, 0, 0, 0.45); opacity: 0; pointer-events: none; transition: opacity var(--duration-medium, 0.22s) var(--ease-smooth, ease); }
    .app-shell-body:has(> .app-nav-toggle-input:checked) .app-nav-backdrop { opacity: 1; pointer-events: auto; }
    /* The hamburger is phone-only, so it always receives the shared 44px touch
       floor even when desktop devtools emulate width without a coarse pointer. */
    .app-nav-toggle { display: inline-flex; min-block-size: var(--sp-11); }
  }

  .carousel { display: flex; gap: var(--sp-3); overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: thin; padding-block-end: var(--sp-2); overscroll-behavior-inline: contain; }
  .carousel > * { scroll-snap-align: start; flex: 0 0 auto; }
  .carousel-marquee { overflow: hidden; }
  .carousel-marquee > .carousel-track { display: flex; gap: var(--sp-3); inline-size: max-content; animation: lib-marquee 24s linear infinite; }
  .carousel-marquee:hover > .carousel-track { animation-play-state: paused; }

  .cmd-item { display: flex; align-items: center; gap: var(--sp-2); inline-size: 100%; box-sizing: border-box; padding: var(--sp-2) var(--sp-3); border: none; background: none; border-radius: var(--radius-sm); font: inherit; font-size: var(--text-caption); color: var(--foreground); text-align: start; cursor: pointer; }
  .cmd-item:hover, .cmd-item.active { background: var(--state-hover); }
  .cmd-item .menu-shortcut { margin-inline-start: auto; }

  /* ---- batch 6: tree + diff (rich-textarea/calendar/image-annotate are WCs) ---- */
  .tree, .tree-group { list-style: none; margin: 0; padding: 0; }
  .tree { font-size: var(--text-caption); }
  .tree-group { padding-inline-start: var(--sp-4); }
  [role="treeitem"][aria-expanded="false"] > .tree-group { display: none; }
  .tree-item { display: flex; align-items: center; gap: var(--sp-1); padding: var(--sp-1) var(--sp-2); border-radius: var(--radius-sm); color: var(--foreground); cursor: pointer; }
  .tree-item:hover { background: var(--state-hover); }
  .tree-item:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); }
  [role="treeitem"][aria-selected="true"] > .tree-item { background: var(--accent); color: var(--accent-foreground, var(--foreground)); font-weight: var(--weight-medium); }
  .tree-twisty { display: inline-flex; inline-size: 1rem; justify-content: center; flex: none; color: var(--muted-foreground); transition: transform 150ms var(--ease-smooth); }
  [role="treeitem"][aria-expanded="false"] > .tree-item .tree-twisty { transform: rotate(-90deg); }
  [role="treeitem"]:not([aria-expanded]) > .tree-item .tree-twisty { visibility: hidden; }

  .diff { display: grid; grid-template-columns: 1fr 1fr; gap: 1px; background: var(--border); border: 1px solid var(--border); border-radius: var(--radius); overflow: hidden; font-family: var(--font-mono); font-size: var(--text-caption); line-height: 1.55; }
  .diff-pane { background: var(--card); overflow: auto; max-block-size: 22rem; }
  .diff-pane-head { padding: var(--sp-1) var(--sp-3); font-family: var(--font-sans); font-size: var(--text-micro); font-weight: var(--weight-semibold); color: var(--muted-foreground); background: var(--surface-sunken); border-block-end: 1px solid var(--border); position: sticky; inset-block-start: 0; }
  .diff-line { display: block; padding-inline: var(--sp-3); white-space: pre-wrap; word-break: break-word; }
  .diff-add { background: var(--success-bg); }
  .diff-del { background: var(--danger-bg); }
  .diff-empty { background: color-mix(in oklab, var(--muted) 60%, transparent); min-block-size: 1.55em; }

  /* ---- vP7: channel-migration gaps (collision-safe names) ---- */
  /* Metric tile — generic key/value stat (replaces channels' bespoke
     .stat-card/.metrics/.buy-stats; the bare .stat-card name stays withheld). */
  .metric { display: grid; gap: var(--sp-1); padding: var(--c-card-pad); border: 1px solid var(--border); border-radius: var(--c-card-radius); background: var(--card); min-inline-size: 0; }
  .metric-label { font-size: var(--text-micro); font-weight: var(--weight-medium); text-transform: uppercase; letter-spacing: var(--tracking-wide); color: var(--muted-foreground); }
  .metric-value { font-size: var(--text-title); font-weight: var(--weight-semibold); line-height: 1.1; color: var(--foreground); font-variant-numeric: tabular-nums; }
  .metric-delta { display: inline-flex; align-items: center; gap: 2px; font-size: var(--text-micro); color: var(--muted-foreground); }
  .metric-delta.is-up { color: var(--success); }
  .metric-delta.is-down { color: var(--danger); }
  /* Dashboard-grade KPI variant — the number carries the tile. */
  .metric-lg .metric-value { font-size: var(--text-display); }
  /* horizontal key:value pill variant (e.g. timing rows) */
  .metric-row { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-2); padding: var(--sp-2) var(--sp-3); border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-sunken); min-inline-size: 0; }
  .metric-row .metric-value { font-size: var(--text-body); text-align: end; }

  /* Dark-glass badge for labeling content OVER media (theme-independent,
     legible on any image — token .tag/.chip are invisible over photos). */
  .media-badge { display: inline-flex; align-items: center; gap: var(--sp-1); min-block-size: 1.5rem; padding: 0.3125rem 0.625rem; border-radius: var(--radius-full); border: 1px solid rgba(255,255,255,0.18); background: rgba(0,0,0,0.6); color: #fff; font-size: var(--text-micro); line-height: 1; letter-spacing: 0.02em; -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px); }

  /* Generic media-library composition. Consumers provide only media and data;
     lib owns the preview ratio, selection state, card spacing, and actions. */
  .media-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(var(--media-card-min, 14rem), 1fr)); gap: var(--sp-4); align-items: start; }
  .media-card { position: relative; min-inline-size: 0; overflow: hidden; padding: 0; border: 1px solid var(--border); border-radius: var(--radius-lg); appearance: none; background: var(--card); color: var(--card-foreground); box-shadow: var(--shadow-card); font: inherit; text-align: inherit; }
  button.media-card { cursor: pointer; }
  .media-card[aria-selected="true"], .media-card.is-selected { border-color: var(--ring); box-shadow: var(--focus-ring); }
  .media-preview { position: relative; display: grid; place-items: center; aspect-ratio: var(--media-aspect, 16 / 10); overflow: hidden; background: var(--surface-sunken); border-block-end: 1px solid var(--border); }
  .media-preview.media-preview-video { --media-aspect: 16 / 9; }
  .media-preview.media-preview-portrait { --media-aspect: 3 / 4; }
  .media-preview > img, .media-preview > video { inline-size: 100%; block-size: 100%; object-fit: cover; }
  .media-preview.media-preview-contain > img, .media-preview.media-preview-contain > video { object-fit: contain; }
  .media-preview > audio { inline-size: calc(100% - (2 * var(--sp-3))); max-inline-size: 100%; }
  .media-preview-placeholder { display: grid; place-items: center; inline-size: 100%; block-size: 100%; color: var(--muted-foreground); font-size: var(--text-title); }
  .media-preview > .media-badge { position: absolute; inset-block-start: var(--sp-2); inset-inline-end: var(--sp-2); }
  /* Anything wired to the singleton <dev-lightbox> (declarative data-lightbox attr
     or a channel click handler) advertises the full-view affordance. */
  [data-lightbox] { cursor: zoom-in; }
  .media-player { inline-size: 100%; max-block-size: var(--media-player-max, 24rem); border-radius: var(--radius); background: var(--surface-sunken); }
  .media-card-select { position: absolute; inset-block-start: var(--sp-2); inset-inline-start: var(--sp-2); z-index: 1; display: inline-flex; padding: var(--sp-1); border-radius: var(--radius-sm); background: color-mix(in oklab, var(--card) 86%, transparent); -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
  .media-card-body { display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); }
  .media-card-title { min-inline-size: 0; overflow: hidden; color: var(--foreground); font-size: var(--text-body); font-weight: var(--weight-semibold); text-overflow: ellipsis; white-space: nowrap; }
  .media-card-meta { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); color: var(--muted-foreground); font-size: var(--text-micro); }
  .media-card-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--sp-1); padding-block-start: var(--sp-1); border-block-start: 1px solid var(--border); }
  /* Compact thumbnail for horizontal asset rows (asset rails, mention lists).
     Size/aspect are tokens: override --media-thumb-w / --media-aspect per list. */
  .media-thumb { position: relative; flex: none; inline-size: var(--media-thumb-w, 3.75rem); aspect-ratio: var(--media-aspect, 3 / 4); display: grid; place-items: center; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-sunken); color: var(--muted-foreground); font-size: var(--text-micro); }
  .media-thumb > img, .media-thumb > video { inline-size: 100%; block-size: 100%; object-fit: cover; }
  .media-thumb-duration { position: absolute; inset-block-end: var(--sp-1); inset-inline-end: var(--sp-1); padding: 0 var(--sp-1); border-radius: var(--radius-sm); background: color-mix(in oklab, var(--foreground) 75%, transparent); color: var(--background); font-size: var(--text-micro); }

  /* Compact media editor slot used wherever one immutable image/video input
     owns upload, generate, edit, and history actions. This is deliberately a
     generic role: channels provide the media and commands, lib owns layout,
     overlay contrast, and narrow-container sizing. */
  .media-slot { display: flex; flex-direction: column; gap: var(--sp-2); inline-size: min(100%, var(--media-slot-width, 12.5rem)); flex: none; }
  .media-slot-preview { position: relative; display: grid; place-items: center; inline-size: 100%; overflow: hidden; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-sunken); }
  .media-slot-preview > img, .media-slot-preview > video { inline-size: 100%; block-size: 100%; object-fit: cover; }
  .media-overlay-action { position: absolute; inset-block-start: var(--sp-1); inset-inline-start: var(--sp-1); z-index: 1; display: inline-flex; align-items: center; justify-content: center; inline-size: var(--control-h-sm); block-size: var(--control-h-sm); padding: 0; border: 0; border-radius: var(--radius-sm); background: rgba(0,0,0,0.55); color: #fff; cursor: pointer; }
  .media-overlay-action:hover { background: rgba(0,0,0,0.76); }
  .media-overlay-action:focus-visible { outline: 2px solid transparent; box-shadow: 0 0 0 2px #fff; }
  .media-progress-overlay { position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--sp-2); background: rgba(0,0,0,0.55); color: #fff; }
  .media-progress-overlay > .spinner { border-color: rgba(255,255,255,0.35); border-right-color: #fff; }
  .media-preview-action { position: absolute; inset: 0; display: grid; place-items: center; inline-size: 100%; block-size: 100%; padding: 0; border: 0; background: rgba(0,0,0,0.22); color: #fff; cursor: pointer; transition: background var(--duration-fast) var(--ease-standard); }
  .media-preview-action:hover { background: rgba(0,0,0,0.45); }
  .media-preview-action:focus-visible { outline: 2px solid transparent; box-shadow: inset 0 0 0 3px #fff; }

  /* Fill-height card — same surface as .card but stretches in a flex/grid row
     (dev-card's shadow body is content-height and cannot). */
  .card-stretch { display: flex; flex-direction: column; min-block-size: 0; background: var(--card); color: var(--card-foreground, var(--foreground)); border: 1px solid var(--border); border-radius: var(--c-card-radius); box-shadow: var(--c-card-shadow); overflow: hidden; }
  .card.card-selected { background: var(--state-selected); }

  /* Conversation messages are generic content roles. Compose with .card and
     the type/spacing utilities; the channel supplies only message content. */
  .chat-message { inline-size: min(82%, 42rem); }
  .chat-message-user { align-self: flex-end; background: var(--state-selected); }
  .chat-message-assistant { align-self: flex-start; }

  /* Conversation workbench bubbles — accent-tonal user speech with a keyed
     corner, a square AI mark, and entity reference chips. Skin decides the
     hues (paper: amber speech / teal references). */
  .chat-bubble-user { max-inline-size: 78%; align-self: flex-end; background: color-mix(in oklab, var(--p-accent) 16%, var(--surface-raised)); border: 1px solid color-mix(in oklab, var(--p-accent) 34%, var(--surface-raised)); color: color-mix(in oklab, var(--p-accent) 28%, var(--foreground)); padding: var(--sp-3) var(--sp-4); border-radius: var(--radius-xl) var(--radius-xl) calc(var(--radius) - 6px) var(--radius-xl); line-height: 1.8; white-space: pre-wrap; font-size: var(--text-body); }
  .chat-avatar-mark { display: inline-flex; align-items: center; justify-content: center; inline-size: 1.75rem; block-size: 1.75rem; flex: 0 0 1.75rem; border-radius: var(--radius-sm); background: linear-gradient(135deg, var(--p-gray-7), var(--p-gray-5)); border: 1px solid var(--border-strong); color: var(--p-accent); font-size: var(--text-micro); font-weight: var(--weight-bold); }
  .chip-ref { background: color-mix(in oklab, var(--chart-2) 13%, var(--surface-raised)); border-color: color-mix(in oklab, var(--chart-2) 36%, var(--surface-raised)); color: color-mix(in oklab, var(--chart-2) 72%, var(--foreground)); }
  .chip-ref:hover { background: color-mix(in oklab, var(--chart-2) 22%, var(--surface-raised)); }
  /* Conversation typing indicator — three pulsing accent dots. */
  .typing-dots { display: inline-flex; align-items: center; gap: 5px; padding-block: var(--sp-2); }
  .typing-dots > span { inline-size: 7px; block-size: 7px; border-radius: var(--radius-full); background: var(--p-accent); animation: lib-dot-pulse 1.2s infinite; }
  .typing-dots > span:nth-child(2) { animation-delay: 0.2s; }
  .typing-dots > span:nth-child(3) { animation-delay: 0.4s; }
  @keyframes lib-dot-pulse { 0%, 80%, 100% { opacity: 0.25; transform: scale(0.85); } 40% { opacity: 1; transform: none; } }
  /* Chat body copy breathes looser than tool-grade text. */
  .leading-chat { line-height: 1.8; }
  /* Identity swatches — small colored initial squares for list identity. */
  .swatch { display: inline-flex; align-items: center; justify-content: center; inline-size: 1.625rem; block-size: 1.625rem; flex: 0 0 1.625rem; border-radius: var(--radius-sm); color: var(--primary-foreground); font-size: var(--text-micro); font-weight: var(--weight-bold); }
  .swatch-1 { background: var(--chart-1); } .swatch-2 { background: var(--chart-2); } .swatch-3 { background: var(--chart-3); } .swatch-4 { background: var(--chart-4); } .swatch-5 { background: var(--chart-5); }

  /* Structured editable document: one framed surface with selectable blocks
     and seam-free shared editors. Product channels provide only content. */
  .document-surface { margin: 0 var(--sp-3) var(--sp-3); overflow: auto; border: 1px solid var(--border); border-radius: var(--radius); background: var(--surface-raised); }
  .document-block { position: relative; overflow: hidden; border-block-end: 1px solid var(--border); background: var(--surface-raised); transition: background var(--duration-fast) var(--ease-standard), box-shadow var(--duration-fast) var(--ease-standard); }
  .document-block:last-child { border-block-end: 0; }
  .document-block.is-selected { background: color-mix(in srgb, var(--brand) 6%, var(--surface-raised)); box-shadow: inset var(--sp-1) 0 0 var(--brand); }
  .document-block:focus-visible { outline: 2px solid transparent; box-shadow: var(--focus-ring); }
  .editor-seamless { inline-size: 100%; margin: 0; }
  .editor-seamless::part(box) { border-inline: 0; border-radius: 0; background: transparent; }

  /* <dev-captcha> — light-DOM host for the vendored ALTCHA widget. ALTCHA
     injects its stylesheet into document.head, which cannot cross a shadow
     boundary, so the widget MUST live in light DOM; these rules map the
     design tokens onto ALTCHA's theming variables (light/dark follow the
     host palette automatically). min-block-size reserves the widget's
     resting height so the form doesn't jump when the lazy vendor bundle
     arrives. */
  dev-captcha { display: block; min-block-size: 52px; }
  dev-captcha altcha-widget {
    --altcha-color-base: var(--card);
    --altcha-color-base-content: var(--card-foreground, var(--foreground));
    --altcha-color-neutral: var(--muted-foreground);
    --altcha-color-neutral-content: var(--card);
    --altcha-color-primary: var(--primary);
    --altcha-color-primary-content: var(--primary-foreground);
    --altcha-color-error: var(--danger);
    --altcha-color-success: var(--success);
    --altcha-border-color: var(--border);
    --altcha-border-radius: var(--radius);
    --altcha-input-background-color: var(--background);
    --altcha-input-color: var(--foreground);
    --altcha-max-width: 100%;
  }
}

/* Coarse-pointer target floor. Compact desktop controls keep their 26–40px
   visual rhythm; touch input gets the platform 44px spacing step without any
   product breakpoint or one-off override. */
@layer lib.components {
  @media (pointer: coarse) {
    :is(
      .btn, .input, .textarea, select.input, .tab, .sidebar-item,
      .menu-item, .cmd-item, .pagination .page, .segmented > button,
      .segmented > label, .stepper > button, .chip-clickable,
      .app-nav-toggle, .workspace-context-toggle, .workspace-context-close,
      .action-card, .media-overlay-action
    ) { min-block-size: var(--sp-11); }
    .btn-icon, .pagination .page, .media-overlay-action { min-inline-size: var(--sp-11); }
  }
}

/* ===== vP4 — container-query responsive (no JIT, no viewport breakpoints).
   Opt in with .cq on a wrapper; descendants use md-/lg-prefixed classes that
   react to the wrapper's width, not the viewport. ===== */
.cq { container-type: inline-size; }
@container (min-width: 30rem) {
  .md-cols-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .md-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .md-row { flex-direction: row; }
  .md-flex { display: flex; }
  .md-hidden { display: none; }
  .md-block { display: block; }
}
@container (min-width: 48rem) {
  .lg-cols-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .lg-cols-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
}
