/*
 * letbe-ds — Component Styles
 * Framework-agnostic components using Letbe design tokens.
 * Uses --lb-* design tokens from tokens/theme.css.
 *
 * Import order: tokens/theme.css → components/components.css
 */

/* ═══════════════════════════════════════════════════════════
   GLOBAL [hidden] OVERRIDE
   ═══════════════════════════════════════════════════════════
   The browser's default rule is `[hidden] { display: none }` — but
   it's a single attribute selector (specificity 0,1,0) and ANY
   class-level `display: …` rule wins against it. So setting
   `el.hidden = true` on, say, a .lb-btn (display: inline-flex)
   has no visible effect.

   This single rule wins back against every single-class lb-* selector
   without resorting to !important: `[class*="lb-"][hidden]` has
   specificity 0,2,0 (two attribute selectors), beating .lb-foo's
   0,1,0. Any lb-* element with [hidden] always renders as none.

   Replaces six per-class overrides we'd accumulated as bugs surfaced.
   Future-proof: any new lb-* component automatically inherits the
   right behavior with no per-class boilerplate. ═══════════════════════════════════════════════════════════ */
[class*="lb-"][hidden] { display: none; }

/* ═══════════════════════════════════════════════════════════
   GLOBAL SCROLLBAR
   ═══════════════════════════════════════════════════════════
   Thin, theme-token driven. Uses --lb-fg-muted for the thumb so it
   automatically flips for dark mode. Track stays transparent — only
   the thumb is visible, and it darkens to --lb-fg-default on hover.

   WebKit/Blink (Chrome/Safari/Edge): full styling via ::-webkit-*
   Firefox: limited to scrollbar-width + scrollbar-color (no hover or
   radius support, but the thin tinted thumb still matches the theme).

   Touches every scrollable area in the gallery (modal body, sheet
   body, dropdown lists, datepicker selects, phone country picker,
   sidebar nav, theme editor body, multi-select pills, sticky tables,
   list components, command palette) plus any consumer app chrome.
   ═══════════════════════════════════════════════════════════ */
* {
  scrollbar-width: thin;
  /* Track transparent so the scrollbar only shows when content
     overflows — no permanent rail competing with body content.
     IMPORTANT: modern Chrome (like Firefox) gives these STANDARD
     properties precedence over the ::-webkit-scrollbar rules below,
     so this line IS the scrollbar on current browsers. Thumb tone:
     border-muted (2026-04) is invisible in dark mode, fg-muted is
     visually dominant in both — border-strong is the middle step
     (light neutral-400 / dark neutral-700): a slight "there's more
     content" indicator, never competing with content. Hover steps up
     to fg-muted. The ::-webkit-* block remains for older WebKit/Blink
     where it still wins. */
  scrollbar-color: var(--lb-border-strong) transparent;
}
*::-webkit-scrollbar           { width: var(--lb-size-2x); height: var(--lb-size-2x); }
*::-webkit-scrollbar-track     { background: transparent; }
*::-webkit-scrollbar-thumb     { background: var(--lb-border-strong); border-radius: var(--lb-radius-full); }
*::-webkit-scrollbar-thumb:hover { background: var(--lb-fg-muted); }
*::-webkit-scrollbar-corner    { background: transparent; }
/* Hide WebKit's scroll arrow buttons (Mac default off, Windows/Linux
   may render them — they fight the minimalist look). */
*::-webkit-scrollbar-button    { display: none; }

/* ═══════════════════════════════════════════════════════════
   GLOBAL ICON DEFAULTS
   Change --lb-stroke-icon to adjust all icon thickness.
   ═══════════════════════════════════════════════════════════ */

/* Default icon stroke = the brand Action stroke. One brand-driven
   thickness flows through buttons, fields, badges, banners, toasts,
   AND every icon — so adjusting the Action stroke knob in the theme
   editor keeps everything visually unified. Override the L1
   --lb-size-theme to retune all of it; override --lb-stroke-icon
   directly to retune icons only (Icon stroke knob does this). */
/* --lb-stroke-icon is emitted by build-tokens from semantic.stroke.stroke.icon
   in source-tokens.json. Theme.css renders it before this rule runs. */
svg[stroke-width] { stroke-width: var(--lb-stroke-icon); }

/* Icon slot — reserves 1em × 1em so [data-lb-icon] placeholders don't
   cause layout shift during async load. Parent's currentColor flows to
   the stroked SVG. Consumers can override size via inline style, CSS
   class, or nested sizing wrappers. */
[data-lb-icon] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1em;
  height: 1em;
  color: currentColor;
  flex-shrink: 0;
}
[data-lb-icon] svg { width: 100%; height: 100%; display: block; }

/* ═══════════════════════════════════════════════════════════
   LAYOUT PRIMITIVES
   Three single-purpose helpers for the spacing patterns we use most.
   Consumers tune via `--gap` (and `--min` on grid) so the same class
   covers tight toolbars and breathing-room hero sections.

     .lb-stack    vertical stack, gap between children
     .lb-cluster  horizontal row, gap between children, wraps
     .lb-grid     auto-fit grid, min column width drives the breakpoint

   Default gap = --lb-size-4x (16px). Override per instance by setting
   --gap on the element via inline style or a parent rule:
     <div class="lb-stack" style="--gap: var(--lb-size-2x);">
   ═══════════════════════════════════════════════════════════ */

.lb-stack {
  --gap: var(--lb-size-4x);
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

.lb-cluster {
  --gap: var(--lb-size-3x);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--gap);
}
/* Optional alignment modifiers for cluster — start (default), end,
   center, between. End is useful for action rows pinned right; between
   for header/actions split layouts. */
.lb-cluster--end     { justify-content: flex-end; }
.lb-cluster--center  { justify-content: center; }
.lb-cluster--between { justify-content: space-between; }
/* Cluster vertical alignment override (default is center for buttons +
   inline content; switch to start for top-aligned columns of mixed
   heights). */
.lb-cluster--top     { align-items: flex-start; }

.lb-grid {
  --gap: var(--lb-size-4x);
  --min: 16rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--min), 100%), 1fr));
  gap: var(--gap);
}

/* Masonry — Pinterest-style packed layout for items with variable
   heights. Built on CSS multi-column for universal browser support
   today (CSS grid-template-rows: masonry is still Firefox-only
   behind a flag as of 2026).
   READING ORDER CAVEAT: items flow column-by-column (A→D→G top-to-
   bottom in column 1, then B→E→H in column 2). Use for VISUAL content
   (cards with images, photo grids, mood boards) where strict left-to-
   right reading order doesn't matter. For ordered/scannable lists,
   use .lb-grid instead. */
.lb-masonry {
  --gap: var(--lb-size-4x);
  --min: 16rem;
  /* column-width acts like grid's `min` — browser fits as many columns
     of at least --min as it can. */
  column-width: var(--min);
  column-gap: var(--gap);
}
.lb-masonry > * {
  /* Vertical gap between items inside a column. Multi-column doesn't
     have a row-gap concept, so each child gets bottom margin instead.
     break-inside: avoid keeps items intact (no splitting across columns
     mid-element). */
  break-inside: avoid;
  margin-bottom: var(--gap);
  /* inline-size: 100% guarantees the item fills its column even if it
     contains an inline element that doesn't naturally stretch. */
  width: 100%;
}
/* Last item in each visual column shouldn't carry a trailing margin
   that pushes the next one down — multi-column figures this out
   automatically per column, this just trims the very last item. */
.lb-masonry > *:last-child { margin-bottom: 0; }

/* ═══════════════════════════════════════════════════════════
   SCROLL AREA
   ═══════════════════════════════════════════════════════════
   A documented primitive for "scrollable content block". Constrains
   height (or width for the --horizontal variant) and lets the global
   thin scrollbar styles take over. Use for consumer-app content like
   long descriptions, sidebar widgets, log views, code previews.

   The --fade modifier adds subtle scroll-shadow indicators at the
   start and end edges that appear/disappear based on scroll position
   — pure CSS via the background-attachment: local trick (no JS).

   Defaults: 16rem max-height, vertical scroll. Override via custom
   properties:
     <div class="lb-scroll-area" style="--max-height: 24rem;">…</div>
   ═══════════════════════════════════════════════════════════ */

.lb-scroll-area {
  --max-height: 16rem;
  --max-width: none;
  max-height: var(--max-height);
  max-width: var(--max-width);
  overflow-y: auto;
  /* Smooth scrolling — suppressed under prefers-reduced-motion below. */
  scroll-behavior: smooth;
}

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

/* Horizontal variant — flips overflow axis. Set --max-width to constrain. */
.lb-scroll-area--horizontal {
  --max-height: none;
  --max-width: 100%;
  overflow-y: visible;
  overflow-x: auto;
  white-space: nowrap;
}

/* Fade indicators — CSS-only "scroll shadows" using stacked background
   layers. The two `local`-attached layers scroll WITH the content
   (covering the scroll-shadow when at the edges); the two `scroll`-
   attached layers stay fixed (showing the shadow when content is
   scrolled away from the edge). Net effect: shadow at top appears
   only when content is scrolled down, shadow at bottom appears only
   when more content exists below.

   Token-driven: uses --lb-surface-bg-default for the cover gradient
   so it flips with theme; --lb-fg-default at low opacity for the
   shadow tint. Works in both light + dark mode without override. */
.lb-scroll-area--fade {
  background:
    /* Top cover — scrolls with content (hides shadow when at top) */
    linear-gradient(var(--lb-surface-bg-default) 30%, transparent) center top,
    /* Top shadow — fixed (shows when scrolled down) */
    linear-gradient(color-mix(in srgb, var(--lb-fg-default) 12%, transparent), transparent) center top,
    /* Bottom cover — scrolls with content */
    linear-gradient(transparent, var(--lb-surface-bg-default) 70%) center bottom,
    /* Bottom shadow — fixed */
    linear-gradient(transparent, color-mix(in srgb, var(--lb-fg-default) 12%, transparent)) center bottom;
  background-repeat: no-repeat;
  background-size: 100% 2.5rem, 100% 0.75rem, 100% 2.5rem, 100% 0.75rem;
  background-attachment: local, scroll, local, scroll;
}
.lb-scroll-area--horizontal.lb-scroll-area--fade {
  background:
    linear-gradient(to right, var(--lb-surface-bg-default) 30%, transparent) left center,
    linear-gradient(to right, color-mix(in srgb, var(--lb-fg-default) 12%, transparent), transparent) left center,
    linear-gradient(to left, var(--lb-surface-bg-default) 30%, transparent) right center,
    linear-gradient(to left, color-mix(in srgb, var(--lb-fg-default) 12%, transparent), transparent) right center;
  background-repeat: no-repeat;
  background-size: 2.5rem 100%, 0.75rem 100%, 2.5rem 100%, 0.75rem 100%;
  background-attachment: local, scroll, local, scroll;
}

/* ═══════════════════════════════════════════════════════════
   BUTTON
   Variants: primary | neutral | subtle | danger
   Sizes:    medium | small
   ═══════════════════════════════════════════════════════════ */

.lb-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--lb-size-2x);
  font-family: var(--lb-t-action-m-font-family);
  font-size: var(--lb-t-action-m-font-size);
  font-weight: var(--lb-t-action-m-font-weight);
  line-height: var(--lb-t-action-m-line-height);
  letter-spacing: var(--lb-t-action-m-letter-spacing);
  white-space: nowrap;
  text-decoration: none;
  border-radius: var(--lb-radius-full);
  border: var(--lb-border-width-action) solid transparent;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  appearance: none;
  -webkit-appearance: none;
}
.lb-btn:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-btn:disabled,
.lb-btn[aria-disabled="true"] {
  background-color: var(--lb-bg-disabled);
  border-color: var(--lb-border-disabled);
  color: var(--lb-fg-muted);
  cursor: not-allowed;
  pointer-events: none;
}
/* Fixed heights so buttons align with inputs (40px / 32px).
   Padding controls horizontal spacing; vertical centering is via flex. */
.lb-btn--medium { height: 2.5rem; padding: 0 var(--lb-size-4x); }
.lb-btn--small  { height: 2rem;   padding: 0 var(--lb-size-3x); font-size: var(--lb-t-action-s-font-size); line-height: var(--lb-t-action-s-line-height); letter-spacing: var(--lb-t-action-s-letter-spacing); }

/* Primary — filled action */
.lb-btn--primary { background-color: var(--lb-action-bg-primary-default); border-color: var(--lb-action-border-primary-default); color: var(--lb-action-fg-primary-default); }
.lb-btn--primary:hover:not(:disabled):not([aria-disabled="true"])   { background-color: var(--lb-action-bg-primary-hover);   border-color: var(--lb-action-border-primary-hover);   color: var(--lb-action-fg-primary-hover); }
.lb-btn--primary:active:not(:disabled):not([aria-disabled="true"])  { background-color: var(--lb-action-bg-primary-pressed); border-color: var(--lb-action-border-primary-pressed); color: var(--lb-action-fg-primary-pressed); }

/* Secondary — outlined action */
.lb-btn--secondary { background-color: var(--lb-action-bg-secondary-default); border-color: var(--lb-action-border-secondary-default); color: var(--lb-action-fg-secondary-default); }
.lb-btn--secondary:hover:not(:disabled):not([aria-disabled="true"])   { background-color: var(--lb-action-bg-secondary-hover);   color: var(--lb-action-fg-secondary-hover); }
.lb-btn--secondary:active:not(:disabled):not([aria-disabled="true"])  { background-color: var(--lb-action-bg-secondary-pressed); color: var(--lb-action-fg-secondary-pressed); }

/* Danger — destructive action (delete, revoke, force-logout) */
.lb-btn--danger { background-color: var(--lb-action-bg-danger-default); border-color: var(--lb-action-border-danger-default); color: var(--lb-action-fg-danger-default); }
.lb-btn--danger:hover:not(:disabled):not([aria-disabled="true"])   { background-color: var(--lb-action-bg-danger-hover);   border-color: var(--lb-action-border-danger-hover);   color: var(--lb-action-fg-danger-hover); }
.lb-btn--danger:active:not(:disabled):not([aria-disabled="true"])  { background-color: var(--lb-action-bg-danger-pressed); border-color: var(--lb-action-border-danger-pressed); color: var(--lb-action-fg-danger-pressed); }

/* Ghost — minimal action (replaces old neutral + subtle) */
.lb-btn--neutral,
.lb-btn--subtle,
.lb-btn--ghost { background-color: var(--lb-action-bg-ghost-default); border-color: transparent; color: var(--lb-action-fg-ghost-default); }
.lb-btn--neutral:hover:not(:disabled):not([aria-disabled="true"]),
.lb-btn--subtle:hover:not(:disabled):not([aria-disabled="true"]),
.lb-btn--ghost:hover:not(:disabled):not([aria-disabled="true"])   { background-color: var(--lb-action-bg-ghost-hover);   color: var(--lb-action-fg-ghost-hover); }
.lb-btn--neutral:active:not(:disabled):not([aria-disabled="true"]),
.lb-btn--subtle:active:not(:disabled):not([aria-disabled="true"]),
.lb-btn--ghost:active:not(:disabled):not([aria-disabled="true"])  { background-color: var(--lb-action-bg-ghost-pressed); color: var(--lb-action-fg-ghost-pressed); }

.lb-btn__icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: var(--lb-size-6x); height: var(--lb-size-6x); }
.lb-btn__icon svg { width: 100%; height: 100%; }
.lb-btn--small .lb-btn__icon { width: var(--lb-size-5x); height: var(--lb-size-5x); }

/* Trailing count slot — use the shared .lb-counter component with the
   --on-btn variant. See the Counter section below for the component and
   the per-button-variant colour-pair rules. */

/* ═══════════════════════════════════════════════════════════
   ICON BUTTON
   ═══════════════════════════════════════════════════════════ */

.lb-icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  border-radius: var(--lb-radius-full);
  border: var(--lb-border-width-action) solid transparent;
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  appearance: none;
  -webkit-appearance: none;
}
.lb-icon-btn:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-icon-btn:disabled, .lb-icon-btn[aria-disabled="true"] { background-color: var(--lb-bg-disabled); border-color: var(--lb-border-disabled); color: var(--lb-fg-muted); cursor: not-allowed; pointer-events: none; }
.lb-icon-btn--medium { width: 2.5rem; height: 2.5rem; }
.lb-icon-btn--small  { width: 2rem;   height: 2rem; }
/* Icon sizing — applies whether the consumer uses the .lb-icon-btn__icon
   wrapper or puts [data-lb-icon] directly inside .lb-icon-btn. Medium
   icons are 24px (1.5rem), small icons 16px (1rem). */
.lb-icon-btn__icon,
.lb-icon-btn > [data-lb-icon] { display: inline-flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; }
.lb-icon-btn__icon svg { width: 100%; height: 100%; }
.lb-icon-btn--small .lb-icon-btn__icon,
.lb-icon-btn--small > [data-lb-icon] { width: 1rem; height: 1rem; }

/* Primary */
.lb-icon-btn--primary { background-color: var(--lb-action-bg-primary-default); border-color: var(--lb-action-border-primary-default); color: var(--lb-action-fg-primary-default); }
.lb-icon-btn--primary:hover:not(:disabled):not([aria-disabled="true"])   { background-color: var(--lb-action-bg-primary-hover); border-color: var(--lb-action-border-primary-hover); color: var(--lb-action-fg-primary-hover); }

/* Danger */
.lb-icon-btn--danger { background-color: var(--lb-action-bg-danger-default); border-color: var(--lb-action-border-danger-default); color: var(--lb-action-fg-danger-default); }
.lb-icon-btn--danger:hover:not(:disabled):not([aria-disabled="true"]) { background-color: var(--lb-action-bg-danger-hover); border-color: var(--lb-action-border-danger-hover); color: var(--lb-action-fg-danger-hover); }

/* Secondary */
.lb-icon-btn--secondary { background-color: var(--lb-action-bg-secondary-default); border-color: var(--lb-action-border-secondary-default); color: var(--lb-action-fg-secondary-default); }
.lb-icon-btn--secondary:hover:not(:disabled):not([aria-disabled="true"]) { background-color: var(--lb-action-bg-secondary-hover); color: var(--lb-action-fg-secondary-hover); }

/* Ghost — replaces neutral and subtle */
.lb-icon-btn--neutral,
.lb-icon-btn--subtle,
.lb-icon-btn--ghost { background-color: var(--lb-action-bg-ghost-default); border-color: transparent; color: var(--lb-action-fg-ghost-default); }
.lb-icon-btn--neutral:hover:not(:disabled):not([aria-disabled="true"]),
.lb-icon-btn--subtle:hover:not(:disabled):not([aria-disabled="true"]),
.lb-icon-btn--ghost:hover:not(:disabled):not([aria-disabled="true"]) { background-color: var(--lb-action-bg-ghost-hover); color: var(--lb-action-fg-ghost-hover); }

/* ═══════════════════════════════════════════════════════════
   BUTTON GROUP
   ═══════════════════════════════════════════════════════════ */

.lb-btn-group { display: flex; gap: var(--lb-size-2x); }
.lb-btn-group--start   { justify-content: flex-start; }
.lb-btn-group--end     { justify-content: flex-end; }
.lb-btn-group--center  { justify-content: center; }
.lb-btn-group--justify > * { flex: 1; }
.lb-btn-group--stack   { flex-direction: column; }

/* ═══════════════════════════════════════════════════════════
   BADGE
   Variants: default | success | warning | danger | neutral
   Sizes:    medium | small
   ═══════════════════════════════════════════════════════════ */

.lb-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-label-s-font-family);
  font-weight: var(--lb-t-label-s-font-weight);
  /* Medium sizing is now the base — using --medium is optional */
  font-size: var(--lb-t-label-s-font-size);
  letter-spacing: var(--lb-t-label-s-letter-spacing);
  /* Vertical padding = 4px so a 16px icon clears the caps line on both sides */
  padding: var(--lb-size-1x) var(--lb-size-2x);
  border-radius: var(--lb-radius-badge);
  border: var(--lb-border-width-action) solid transparent;
  white-space: nowrap;
  line-height: 1;
}
/* --medium kept as a no-op alias for backward compat. Bare .lb-badge is already medium. */
.lb-badge--medium { /* intentionally empty */ }
.lb-badge--small  { font-size: var(--lb-t-caption-s-font-size); letter-spacing: var(--lb-t-caption-s-letter-spacing); padding: var(--lb-size-0-5x) var(--lb-size-1-5x); }

/* Status variants — L2 semantic direct (use status bg + border + fg together) */
/* Default badge is NEUTRAL (accent model 2026-08-03): a badge with no
   status carries no signal, so it carries no color. Same soft-pill recipe as the status
   variants, on the neutral ramp. */
.lb-badge--default  { background: var(--lb-bg-strong); color: var(--lb-fg-default); border-color: var(--lb-border-default); }
/* Status badges read as soft pills (tinted bg + matching fg + softer
   border). After the L2 status-intensity refactor, soft tints live at
   the -subtle suffix; mid-emphasis borders at -muted. The default
   (no-suffix) tokens are now the saturated variants — used for filled
   status bars, toast accents, etc. — but Badge keeps the soft look. */
.lb-badge--success  { background: var(--lb-bg-success-subtle); color: var(--lb-fg-success); border-color: var(--lb-border-success-muted); }
.lb-badge--warning  { background: var(--lb-bg-warning-subtle); color: var(--lb-fg-warning); border-color: var(--lb-border-warning-muted); }
.lb-badge--danger   { background: var(--lb-bg-danger-subtle);  color: var(--lb-fg-danger);  border-color: var(--lb-border-danger-muted); }
.lb-badge__dot { width: 0.4rem; height: 0.4rem; border-radius: 50%; background: currentColor; flex-shrink: 0; }
/* Live/realtime pulse: add --pulse to the dot for
   "42 live visitors" indicators. Ambient loop deliberately exceeds the
   500ms interaction-duration ceiling (it is status decoration, not a
   transition); disabled entirely under reduced motion. */
.lb-badge__dot--pulse { animation: lb-badge-pulse 2s var(--lb-ease-standard) infinite; }
@keyframes lb-badge-pulse {
  0% { box-shadow: 0 0 0 0 currentColor; opacity: 1; }
  70% { box-shadow: 0 0 0 0.4rem transparent; opacity: 1; }
  100% { box-shadow: 0 0 0 0 transparent; opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .lb-badge__dot--pulse { animation: none; }
}

/* Icon slot — 16px at medium, 12px at small. Inherits currentColor. */
.lb-badge__icon { display: inline-flex; align-items: center; justify-content: center; flex-shrink: 0; width: 1rem; height: 1rem; }
.lb-badge__icon svg { width: 100%; height: 100%; }
.lb-badge--small .lb-badge__icon { width: 0.75rem; height: 0.75rem; }

/* ═══════════════════════════════════════════════════════════
   COUNTER — numeric notification pill (the "bubble")
   Variants: default (accent, brand-themed) | --subtle | --on-btn
   Sizes:    medium (default, 5x) | --small (4x)
   ═══════════════════════════════════════════════════════════
   Recurring pattern previously copy-pasted as .lb-btn__count,
   .lb-tab__badge, .lb-tab__badge--past, and
   .lb-calendar__cell-booking-badge. Consolidated into a single
   .lb-counter component so all hosts (Tabs, Accordion, Calendar,
   Button) share the same shape, sizing, and contrast guarantees.

   Default colour pair routes through the primary-button tokens
   so the counter sits on a saturated brand bg with theme-stable
   light text — contrast holds in light AND dark themes, follows
   the user's chosen brand colour via the theme editor, and stays
   identical in shape regardless of host. */

.lb-counter {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  min-width: var(--lb-size-5x);
  height: var(--lb-size-5x);
  padding: 0 var(--lb-size-1-5x);
  border-radius: var(--lb-radius-full);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  line-height: 1;
  letter-spacing: 0;
  font-variant-numeric: tabular-nums;
  /* Default colour pair — accent-themed, contrast-safe in both
     themes. Borrows the primary-button colour pair so the bg is
     theme-stable saturated brand and the digit is theme-stable
     white (fg.inverse-strong). */
  background: var(--lb-action-bg-primary-default);
  color: var(--lb-action-fg-primary-default);
}
.lb-counter:empty { display: none; }

/* Small size — used in dense rows (calendar month cells, small
   buttons, compact tab strips). */
.lb-counter--small {
  min-width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  padding: 0 var(--lb-size-1x);
  font-family: var(--lb-t-caption-s-font-family);
  font-size: var(--lb-t-caption-s-font-size);
}

/* Subtle variant — quiet/dimmed counter for low-priority states
   (e.g. calendar past days, stale notifications, "+N more" chips). */
.lb-counter--subtle {
  background: var(--lb-bg-disabled);
  color: var(--lb-fg-disabled);
}

/* On-button variant — sits inside .lb-btn and inverts contrast
   against the host button's variant. Colour pair is set by the
   variant rules below; default L2 fallbacks here keep the
   counter looking right when used outside any variant scope
   (rare, but defensive). */
.lb-counter--on-btn {
  background: currentColor;
}

/* Per-button-variant colour mapping — bg = host's text colour,
   digit = host's bg colour. Matches the inverted-pill pattern the
   old .lb-btn__count had. */
.lb-btn--primary   .lb-counter--on-btn { background: var(--lb-action-fg-primary-default);   color: var(--lb-action-bg-primary-default); }
.lb-btn--danger    .lb-counter--on-btn { background: var(--lb-action-fg-danger-default);    color: var(--lb-action-bg-danger-default); }
.lb-btn--secondary .lb-counter--on-btn { background: var(--lb-action-fg-secondary-default); color: var(--lb-action-bg-secondary-default); }
.lb-btn--neutral   .lb-counter--on-btn,
.lb-btn--subtle    .lb-counter--on-btn,
.lb-btn--ghost     .lb-counter--on-btn { background: var(--lb-action-fg-ghost-default);     color: var(--lb-action-bg-ghost-default); }

/* When inside a small button, downsize automatically without
   needing a second --small modifier on the counter. */
.lb-btn--small .lb-counter--on-btn {
  min-width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  padding: 0 var(--lb-size-1x);
  font-family: var(--lb-t-caption-s-font-family);
  font-size: var(--lb-t-caption-s-font-size);
}

/* ═══════════════════════════════════════════════════════════
   FLAG — country flag with optional code label
   ═══════════════════════════════════════════════════════════
   Inline component for compact country representation in tables,
   bar lists, chart labels, breadcrumbs, attendee chips, etc. The
   flag image is sourced from /assets/flags/{iso}.svg (the same set
   the Phone input uses). Three sizes; circular by default to match
   Phone, with a `--rect` modifier for table rows where a rectangle
   reads more naturally. */
.lb-flag {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1-5x);
  vertical-align: middle;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
}
.lb-flag--small  { font-size: var(--lb-t-body-s-font-size); gap: var(--lb-size-1x); }
.lb-flag--large  { font-size: var(--lb-t-body-l-font-size); gap: var(--lb-size-2x); }

.lb-flag__img {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: 50%;
  object-fit: cover;
  flex-shrink: 0;
  /* Subtle border separates white flags (Japan, Israel, Switzerland)
     from white surfaces in light theme. */
  box-shadow: 0 0 0 1px var(--lb-border-muted) inset;
}
.lb-flag--small .lb-flag__img { width: 1rem;    height: 1rem; }
.lb-flag--large .lb-flag__img { width: 1.5rem;  height: 1.5rem; }

/* Rectangular variant — the natural aspect of a flag. Useful in
   table cells where consistency with non-circular thumbnails matters. */
.lb-flag--rect .lb-flag__img {
  border-radius: var(--lb-radius-2);
  width: 1.5rem;
  height: 1rem;
}
.lb-flag--rect.lb-flag--small .lb-flag__img { width: 1.25rem; height: var(--lb-size-3-5x); }
.lb-flag--rect.lb-flag--large .lb-flag__img { width: 2rem;    height: 1.5rem; }

.lb-flag__code {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--lb-fg-default);
}
.lb-flag__label {
  color: var(--lb-fg-default);
}

/* ═══════════════════════════════════════════════════════════
   AVATAR
   ═══════════════════════════════════════════════════════════ */

.lb-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  overflow: hidden;
  flex-shrink: 0;
  background: var(--lb-bg-bolder);
  color: var(--lb-fg-default);
  font-family: var(--lb-t-body-m-font-family);
  font-weight: var(--lb-font-weight-semibold);
  user-select: none;
}
.lb-avatar--large  { width: 3rem;   height: 3rem;   font-size: var(--lb-t-body-l-font-size); }
.lb-avatar--medium { width: 2.5rem; height: 2.5rem; font-size: var(--lb-t-body-m-font-size); }
.lb-avatar--small  { width: 2rem;   height: 2rem;   font-size: var(--lb-t-body-s-font-size); }
.lb-avatar__img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Avatar Group — stacked overlapping avatars with optional "+N" counter.
   Each child Avatar gets a surface-matching ring so overlaps read clearly.
   Overlap ratio ~25% of avatar width: tuned per size (sm 8px, md 10px, lg 12px).
   Size modifier on the group should mirror the child avatar size. */
.lb-avatar-group {
  display: inline-flex;
  align-items: center;
  isolation: isolate;  /* contain z-index stacking to this group */
}
.lb-avatar-group > .lb-avatar {
  border: var(--lb-border-width-medium) solid var(--lb-surface-border-cutout);
  box-sizing: content-box; /* border sits outside the avatar size */
}
/* Overlap — consecutive avatars pull left. First child keeps natural position. */
.lb-avatar-group > .lb-avatar + .lb-avatar         { margin-left: -0.625rem; /* design-intent: avatar overlap distance, medium default */ }
.lb-avatar-group--small  > .lb-avatar + .lb-avatar { margin-left: -0.5rem;   /* design-intent: avatar overlap distance, small */ }
.lb-avatar-group--medium > .lb-avatar + .lb-avatar { margin-left: -0.625rem; /* design-intent: avatar overlap distance, medium */ }
.lb-avatar-group--large  > .lb-avatar + .lb-avatar { margin-left: -0.75rem;  /* design-intent: avatar overlap distance, large */ }

/* Counter avatar — shows "+N more" as a subtle chip at the tail of the group */
.lb-avatar-group__count {
  background: var(--lb-bg-strong);
  color: var(--lb-fg-muted);
  font-weight: var(--lb-font-weight-medium);
  font-variant-numeric: tabular-nums;
}
/* Optional: reveal full group on hover (nice for dense team lists) */
.lb-avatar-group--hover-expand > .lb-avatar { transition: margin-left var(--lb-animation-dur-normal) var(--lb-animation-ease-ui); }
.lb-avatar-group--hover-expand:hover > .lb-avatar + .lb-avatar { margin-left: var(--lb-size-1x); }

/* ═══════════════════════════════════════════════════════════
   CHIP
   Single variant: outlined, toggleable with X to remove.
   Radius controlled by --lb-radius-full (follows theme).
   ═══════════════════════════════════════════════════════════ */

/* Chip = button visual pattern: unselected → secondary action, selected → primary action */
.lb-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1-5x);
  padding: var(--lb-size-1x) var(--lb-size-3x);
  border-radius: var(--lb-radius-full);
  border: var(--lb-border-width-action) solid var(--lb-action-border-secondary-default);
  background: var(--lb-action-bg-secondary-default);
  font-family: var(--lb-t-action-s-font-family);
  font-size: var(--lb-t-action-s-font-size);
  font-weight: var(--lb-t-action-s-font-weight);
  line-height: var(--lb-t-action-s-line-height);
  letter-spacing: var(--lb-t-action-s-letter-spacing);
  color: var(--lb-action-fg-secondary-default);
  white-space: nowrap;
  cursor: pointer;
  user-select: none;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-chip:hover { background: var(--lb-action-bg-secondary-hover); color: var(--lb-action-fg-secondary-hover); }
.lb-chip:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
/* Selected = quiet selection contract (2026-08-03; was full primary fill —
   sub-AA in light mode at chip text size, and primary fill is reserved for
   prominent actions). Full triplet, not bg-only, so the chip boundary stays
   legible on busy filter rails. Hover/active pinned to the same triplet:
   selection IS the state, and generic .lb-chip:hover would otherwise
   out-specify the modifier. */
.lb-chip--selected,
.lb-chip--selected:hover,
.lb-chip--selected:active { background: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); border-color: var(--lb-action-border-selected); }
/* Idiom split (2026-08-03): leading ✓ = selection (toggle/filter chips,
   added by initChips); trailing × = removal (Multi-Select field pills
   only). Padding compacts toward whichever indicator is present. */
.lb-chip:has(> .lb-chip__check) { padding-left: var(--lb-size-2x); }
.lb-chip:has(> .lb-chip__remove) { padding-right: var(--lb-size-2x); }
.lb-chip__check { display: inline-flex; align-items: center; line-height: 1; color: inherit; }
.lb-chip__check svg { width: 1rem; height: 1rem; }
.lb-chip--disabled { background-color: var(--lb-bg-disabled); border-color: var(--lb-border-disabled); color: var(--lb-fg-muted); cursor: not-allowed; pointer-events: none; }
.lb-chip__remove { background: none; border: none; padding: 0; cursor: pointer; color: inherit; display: inline-flex; align-items: center; line-height: 1; }
.lb-chip__remove:hover { opacity: 1; }
.lb-chip__remove:focus-visible { outline: var(--lb-border-width-medium) solid currentColor; outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-2); }
.lb-chip__remove svg { width: 1rem; height: 1rem; color: inherit; }

/* ═══════════════════════════════════════════════════════════
   DIVIDER
   ═══════════════════════════════════════════════════════════ */

.lb-divider { border: none; background: var(--lb-border-muted); flex-shrink: 0; }
.lb-divider--horizontal { display: block; width: 100%; height: var(--lb-border-width-thin); margin: 0; }
.lb-divider--vertical   { display: inline-block; width: var(--lb-border-width-thin); height: 1em; vertical-align: middle; }
/* Strong tone — opt-in when a divider needs to carry real weight (section break, legal fine print boundary, etc.) */
.lb-divider--strong { background: var(--lb-border-default); }

/* ═══════════════════════════════════════════════════════════
   LINK
   ═══════════════════════════════════════════════════════════ */

.lb-link {
  display: inline-flex;
  align-items: baseline;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-action-m-font-family);
  font-size: var(--lb-t-action-m-font-size);
  font-weight: var(--lb-t-action-m-font-weight);
  line-height: var(--lb-t-action-m-line-height);
  letter-spacing: var(--lb-t-action-m-letter-spacing);
  color: var(--lb-action-fg-link-default);
  text-decoration: underline;
  text-underline-offset: var(--lb-size-0-5x);
  cursor: pointer;
  transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-link:hover  { color: var(--lb-action-fg-link-hover); }
.lb-link:active { color: var(--lb-action-fg-link-pressed); }
.lb-link:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-2); }
.lb-link--small  { font-size: var(--lb-t-action-s-font-size); line-height: var(--lb-t-action-s-line-height); letter-spacing: var(--lb-t-action-s-letter-spacing); }
.lb-link--medium { font-size: var(--lb-t-action-m-font-size); line-height: var(--lb-t-action-m-line-height); letter-spacing: var(--lb-t-action-m-letter-spacing); }
.lb-link--large  { font-size: var(--lb-t-action-l-font-size); line-height: var(--lb-t-action-l-line-height); letter-spacing: var(--lb-t-action-l-letter-spacing); }
.lb-link--subtle { color: var(--lb-fg-muted); }
.lb-link--subtle:hover { color: var(--lb-fg-default); }

/* Optional icon slot — typically trailing (external-link, arrow-right,
   download). Sizes itself to the link's text via 1em so it scales with
   --small / --medium / --large. text-decoration: none on the icon
   keeps the underline clean (otherwise the icon's bounding box would
   carry the underline too). */
.lb-link__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1em;
  height: 1em;
  flex-shrink: 0;
  text-decoration: none;
  align-self: center;
}
.lb-link__icon svg { width: 100%; height: 100%; }

/* ═══════════════════════════════════════════════════════════
   SPINNER
   ═══════════════════════════════════════════════════════════ */

@keyframes lb-spin { to { transform: rotate(360deg); } }
.lb-spinner {
  display: inline-block;
  border-radius: 50%;
  border-style: solid;
  border-color: var(--lb-bg-bolder);
  border-top-color: var(--lb-bg-accent-value);
  animation: lb-spin 0.65s linear infinite;
  flex-shrink: 0;
}
.lb-spinner--small  { width: 1rem;   height: 1rem;   border-width: 0.125rem; }
.lb-spinner--medium { width: 1.5rem; height: 1.5rem; border-width: 0.1875rem; /* design-intent: ring thickness scaled to spinner diameter (medium) */ }
.lb-spinner--large  { width: 2.5rem; height: 2.5rem; border-width: 0.25rem;   /* design-intent: ring thickness scaled to spinner diameter (large) */ }

/* ── Visually hidden ─────────────────────────────────────────
   Screen-reader-only text: removed from layout, kept in the a11y tree.
   The one sanctioned way to give sr-only names/state to composed markup
   (calendar week-column header, stepper state text, …). */
.lb-visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}

/* Option-embedded checkbox visuals (List multi mode) are presentational —
   the option carries aria-selected; the input is disabled so it is not a
   second control, and this reset keeps it from LOOKING disabled. */
.lb-list__item .lb-checkbox--presentational:disabled { cursor: inherit; }
.lb-list__item .lb-checkbox--presentational:disabled ~ .lb-checkbox__glyph[data-lb-icon] { color: currentColor; }
/* Reduced motion: the ring keeps turning — a frozen spinner reads as a
   hung control — but slows well below the rate that provokes discomfort. */
@media (prefers-reduced-motion: reduce) {
  .lb-spinner { animation-duration: 2.4s; }
}

/* ═══════════════════════════════════════════════════════════
   PROGRESS
   ═══════════════════════════════════════════════════════════ */

.lb-progress-wrap { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-progress-label-row { display: flex; justify-content: space-between; align-items: baseline; }
.lb-progress-label { font-family: var(--lb-t-label-m-font-family); font-size: var(--lb-t-label-m-font-size); font-weight: var(--lb-t-label-m-font-weight); color: var(--lb-fg-default); }
.lb-progress-value { font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); }
/* Inline arrangement — value label + short thick mini track, for table
   cells / toolbars / footers. Same geometry as the chat budget bar's --compact. */
.lb-progress-inline { display: inline-flex; align-items: center; gap: var(--lb-size-1-5x); }
.lb-progress-inline .lb-progress-value { white-space: nowrap; font-variant-numeric: tabular-nums; }
.lb-progress-inline .lb-progress { width: 1.8rem; height: var(--lb-size-2x); flex: none; /* design-intent: mini track */ }
.lb-progress { appearance: none; -webkit-appearance: none; width: 100%; border: none; border-radius: 9999px; background: var(--lb-bg-bolder); overflow: hidden; }
.lb-progress--small  { height: 0.25rem; }
.lb-progress--medium { height: 0.5rem; }
.lb-progress--large  { height: 0.75rem; }
.lb-progress::-webkit-progress-bar { background: var(--lb-bg-bolder); border-radius: 9999px; }
.lb-progress::-webkit-progress-value { background: var(--lb-bg-accent-value); border-radius: 9999px; transition: width var(--lb-animation-dur-slow) var(--lb-animation-ease-ui); }
.lb-progress::-moz-progress-bar { background: var(--lb-bg-accent-value); border-radius: 9999px; }
.lb-progress--success::-webkit-progress-value { background: var(--lb-bg-success-value); }
.lb-progress--success::-moz-progress-bar       { background: var(--lb-bg-success-value); }
.lb-progress--warning::-webkit-progress-value { background: var(--lb-bg-warning-value); }
.lb-progress--warning::-moz-progress-bar       { background: var(--lb-bg-warning-value); }
.lb-progress--danger::-webkit-progress-value  { background: var(--lb-bg-danger-value); }
.lb-progress--danger::-moz-progress-bar        { background: var(--lb-bg-danger-value); }

/* ═══════════════════════════════════════════════════════════
   SKELETON
   ═══════════════════════════════════════════════════════════ */

.lb-skeleton { display: inline-block; background: var(--lb-bg-bolder); border-radius: var(--lb-radius-interactive); overflow: hidden; position: relative; }
.lb-skeleton::after { content: ''; position: absolute; inset: 0; background: linear-gradient(90deg, transparent 0%, var(--lb-bg-strong) 50%, transparent 100%); background-size: 200% 100%; animation: lb-skeleton-shimmer 1.4s ease-in-out infinite; }
@keyframes lb-skeleton-shimmer { 0% { background-position: 200% 0; } 100% { background-position: -200% 0; } }
.lb-skeleton--text { width: 100%; height: 1em; border-radius: var(--lb-radius-interactive); }
.lb-skeleton--circular { width: 2.5rem; height: 2.5rem; border-radius: 50%; }
.lb-skeleton--rectangular { width: 100%; height: 8rem; border-radius: var(--lb-radius-surface); }
.lb-skeleton-lines { display: flex; flex-direction: column; gap: var(--lb-size-2x); width: 100%; }
.lb-skeleton-lines .lb-skeleton--text { display: block; }

/* ═══════════════════════════════════════════════════════════
   CARD
   Variants: default | outlined | elevated
   ═══════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════
   CARD — surface container for grouped content
   Default: bordered, no elevation. Variants layer on top.
   Sizes:   --sm (16px) | default (24px) | --lg (32px)
   Variants: --elevated | --interactive | --stat
   Media:   .lb-card__media + --top (default) | --left | --background
   States:  --selected | --disabled
   Slots:   __header, __body, __footer, __section (divided subsection)
   ═══════════════════════════════════════════════════════════ */

.lb-card {
  --_card-pad: var(--lb-size-6x);  /* size-driven padding, overridden by --sm/--lg */
  font-family: var(--lb-t-body-m-font-family);
  background-color: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  border-radius: var(--lb-radius-surface);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  text-align: left;
}

/* Sizes — drive all __header/__body/__footer padding from one variable */
.lb-card--sm { --_card-pad: var(--lb-size-4x); }
.lb-card--lg { --_card-pad: var(--lb-size-8x); }

/* Padded shortcut — for cards holding a single block of content
   (chart, KPI, list) with no explicit __header/__body/__footer slots.
   Adds the same padding the slots would, on the wrapper itself. Pairs
   with the data viz suite where charts are dropped into a Card without
   the full slotted anatomy. Don't combine with __body/__header/__footer
   children (you'd get double padding). */
.lb-card--padded { padding: var(--_card-pad); }

/* Variants */
.lb-card--elevated { box-shadow: var(--lb-shadow-card); }
.lb-card--interactive {
  cursor: pointer;
  appearance: none;
  width: 100%;
  /* when rendered as <a>/<button>, strip native chrome */
  text-decoration: none;
  font: inherit;
  color: inherit;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
/* Hover and selected stay on the same surface bg + text color as the
   resting state — feedback comes from a thicker outline (via box-shadow
   spread, so layout doesn't shift by 1px) plus a drop shadow plus a
   subtle lift. Hover uses the neutral emphasis tone for the ring;
   Selected uses the accent tone (so consumers can still tell hover from
   selected at a glance). */
.lb-card--interactive:hover:not(.lb-card--disabled) {
  border-color: var(--lb-border-strong);
  box-shadow:
    0 0 0 1px var(--lb-border-strong),
    var(--lb-shadow-card);
  transform: translateY(-1px);
}
.lb-card--interactive:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
/* Honor reduced-motion preference — keep the bg/border/shadow hover
   feedback (those don't move), drop the lift transform animation that
   can trigger vestibular symptoms. */
@media (prefers-reduced-motion: reduce) {
  .lb-card--interactive { transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
  .lb-card--interactive:hover:not(.lb-card--disabled) { transform: none; }
}

/* ── Nav-icon slot ──
   Trailing chevron / arrow indicating "this card navigates somewhere".
   Sits at the right edge of the body; vertically centered against the
   title. Muted by default, full-color on hover, slides 2px right for
   delight. */
.lb-card__nav-icon {
  position: absolute;
  top: 50%;
  right: var(--_card-pad);
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  color: var(--lb-fg-muted);
  flex-shrink: 0;
  pointer-events: none;
  transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-card__nav-icon svg { width: 100%; height: 100%; }
.lb-card { position: relative; }
.lb-card:has(.lb-card__nav-icon) .lb-card__body,
.lb-card:has(.lb-card__nav-icon) .lb-card__header,
.lb-card:has(.lb-card__nav-icon) .lb-card__footer { padding-right: calc(var(--_card-pad) + var(--lb-size-6x)); }
.lb-card--interactive:hover:not(.lb-card--disabled) .lb-card__nav-icon {
  color: var(--lb-fg-default);
  transform: translateY(-50%) translateX(2px);
}
.lb-card--interactive:focus-visible .lb-card__nav-icon { color: var(--lb-fg-default); }
@media (prefers-reduced-motion: reduce) {
  .lb-card--interactive:hover:not(.lb-card--disabled) .lb-card__nav-icon {
    transform: translateY(-50%);
  }
}
/* Back-compat: --clickable keeps working (alias). New code should use --interactive. */
.lb-card--clickable { cursor: pointer; appearance: none; width: 100%; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-card--clickable:hover {
  border-color: var(--lb-border-strong);
  box-shadow:
    0 0 0 1px var(--lb-border-strong),
    var(--lb-shadow-card);
}
.lb-card--clickable:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }

/* States. Selected is signalled by a doubled accent-tone outline +
   drop shadow. Background and text color stay identical to resting so
   selected cards don't shift in tone — keeps visual noise low when
   many cards are stacked, and is the conventional treatment
   of "outline emphasis" over "fill emphasis". */
.lb-card--selected {
  border-color: var(--lb-border-accent);
  box-shadow:
    0 0 0 1px var(--lb-border-accent),
    var(--lb-shadow-card);
}
.lb-card--selected.lb-card--interactive:hover:not(.lb-card--disabled) {
  /* Selected + hovered stays in the selected (accent) tone — preserves
     "this one is chosen" while still lifting on hover. */
  border-color: var(--lb-border-accent);
  box-shadow:
    0 0 0 1px var(--lb-border-accent),
    var(--lb-shadow-card);
}
.lb-card--disabled {
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
}

/* ── Slots ── */

/* Header — row with title + optional trailing actions, divided from body */
.lb-card__header {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--lb-size-3x);
  padding: var(--_card-pad);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-card__header-title {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  min-width: 0;
  flex: 1;
}
.lb-card__header-actions {
  display: inline-flex;
  gap: var(--lb-size-1x);
  flex-shrink: 0;
}

/* Body — main content area */
.lb-card__body {
  padding: var(--_card-pad);
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}

/* Title + description — work inside either header or body */
.lb-card__title {
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-heading-s-font-size);
  font-weight: var(--lb-t-heading-s-font-weight);
  line-height: var(--lb-t-heading-s-line-height);
  letter-spacing: var(--lb-t-heading-s-letter-spacing);
  color: var(--lb-fg-default);
  margin: 0;
}
.lb-card__description {
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-t-body-m-font-weight);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-muted);
  margin: 0;
}

/* Section — internal divider-separated subsection (settings groups) */
.lb-card__section {
  padding: var(--_card-pad);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-card__section:first-child,
.lb-card__body + .lb-card__section,
.lb-card__header + .lb-card__section { /* header has its own bottom divider — avoid double lines */ }
/* The __header already adds a bottom divider, and __body doesn't — so the
   __section divider-top pairs correctly after __body. Remove top divider on
   the section that immediately follows the header (which has its own). */
.lb-card__header + .lb-card__section { border-top: none; }

/* Footer — actions row at the bottom, slimmer padding than body */
.lb-card__footer {
  padding: var(--lb-size-4x) var(--_card-pad);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  display: flex;
  gap: var(--lb-size-2x);
  align-items: center;
  justify-content: flex-end;
}
.lb-card__footer--start { justify-content: flex-start; }
.lb-card__footer--spread { justify-content: space-between; }
.lb-card--sm .lb-card__footer { padding: var(--lb-size-3x) var(--_card-pad); }

/* ── Media ── */

.lb-card__media {
  overflow: hidden;
  background: var(--lb-bg-strong);
}
.lb-card__media img,
.lb-card__media video {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Default: top-stacked. Explicit modifier for clarity. Top media carries
   a fixed aspect ratio (16:9 default) so it never collapses to 0 height
   and mirrors the Figma card/media box — override with a ratio modifier
   below. Ratio is inert for media-left (fixed column, stretch) and
   media-bg (absolute inset:0): those derive size from layout, not ratio. */
.lb-card__media--top { width: 100%; aspect-ratio: 16 / 9; }
/* Aspect-ratio presets — mirror the Figma card/media ratio variants. */
.lb-card__media--16x9 { aspect-ratio: 16 / 9; }
.lb-card__media--4x3  { aspect-ratio: 4 / 3; }
.lb-card__media--1x1  { aspect-ratio: 1 / 1; }
.lb-card__media--3x4  { aspect-ratio: 3 / 4; }
/* Left-stacked: horizontal layout, media takes a fixed column */
.lb-card--media-left {
  flex-direction: row;
  align-items: stretch;
}
.lb-card--media-left .lb-card__media {
  width: 33%;
  max-width: 14rem; /* design-intent: media-left card cover column cap */
  flex-shrink: 0;
}
.lb-card--media-left .lb-card__body,
.lb-card--media-left .lb-card__header,
.lb-card--media-left .lb-card__footer { flex: 1; min-width: 0; }
/* Full-bleed background: media covers the whole card; content overlays.
   Text uses fg.inverse-strong (theme-stable light) because the scrim is a
   hardcoded dark gradient that doesn't theme-flip. fg.inverse would
   theme-flip and produce dark text on the still-dark scrim in dark mode. */
.lb-card--media-bg {
  position: relative;
  color: var(--lb-fg-inverse-strong);
  isolation: isolate;
}
.lb-card--media-bg .lb-card__media {
  position: absolute;
  inset: 0;
  z-index: -1;
}
.lb-card--media-bg .lb-card__media::after {
  /* dark scrim so white text reads on any photo */
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.6), rgba(0, 0, 0, 0.15) 60%, transparent);
  pointer-events: none;
}
.lb-card--media-bg .lb-card__title { color: var(--lb-fg-inverse-strong); }
.lb-card--media-bg .lb-card__description { color: var(--lb-fg-inverse-strong); opacity: 0.85; }

/* Legacy __image class — backwards-compat alias */
.lb-card__image { width: 100%; overflow: hidden; }
.lb-card__image img { width: 100%; height: auto; display: block; }

/* ═══════════════════════════════════════════════════════════
   STAT CARD — specialised card for dashboard metric tiles
   Big number + small label + optional delta indicator.
   Structure: <div class="lb-card lb-card--stat"><span label><span value><span delta></div>
   ═══════════════════════════════════════════════════════════ */

.lb-card--stat {
  padding: var(--_card-pad);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
}
.lb-card__stat-label {
  font-family: var(--lb-t-label-s-font-family);
  font-size: var(--lb-t-label-s-font-size);
  font-weight: var(--lb-font-weight-medium);
  letter-spacing: var(--lb-t-label-s-letter-spacing);
  color: var(--lb-fg-muted);
  margin: 0;
  text-transform: uppercase;
}
.lb-card__stat-value {
  font-family: var(--lb-t-display-xs-font-family);
  font-size: var(--lb-t-display-xs-font-size);
  font-weight: var(--lb-font-weight-semibold);
  line-height: 1.1;
  color: var(--lb-fg-default);
  font-variant-numeric: tabular-nums;
  margin: 0;
}
.lb-card__stat-delta {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-card__stat-delta--up   { color: var(--lb-fg-success); }
.lb-card__stat-delta--down { color: var(--lb-fg-danger); }
.lb-card__stat-delta svg { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); }

/* ═══════════════════════════════════════════════════════════
   BANNER
   Variants: info | success | warning | danger
   Sizes:    l | m | s
   ═══════════════════════════════════════════════════════════ */

.lb-banner { display: flex; align-items: flex-start; gap: var(--lb-size-3x); border: var(--lb-border-width-action) solid transparent; font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); color: var(--lb-fg-default); }
/* Banner reads as soft tinted container — matches Toast. After the
   status-intensity refactor: -subtle bg + -muted border. */
.lb-banner--info    { background: var(--lb-bg-info-subtle);    border-color: var(--lb-border-info-muted); }
.lb-banner--success { background: var(--lb-bg-success-subtle); border-color: var(--lb-border-success-muted); }
.lb-banner--warning { background: var(--lb-bg-warning-subtle); border-color: var(--lb-border-warning-muted); }
.lb-banner--danger  { background: var(--lb-bg-danger-subtle);  border-color: var(--lb-border-danger-muted); }
/* Icon keeps the variant tint for visual recognition */
.lb-banner--info    .lb-banner__icon { color: var(--lb-fg-info); }
.lb-banner--success .lb-banner__icon { color: var(--lb-fg-success); }
.lb-banner--warning .lb-banner__icon { color: var(--lb-fg-warning); }
.lb-banner--danger  .lb-banner__icon { color: var(--lb-fg-danger); }
.lb-banner--m { padding: var(--lb-size-3x) var(--lb-size-4x); border-radius: var(--lb-radius-surface); }
.lb-banner--l { padding: var(--lb-size-4x) var(--lb-size-6x); border-radius: var(--lb-radius-surface); width: 100%; gap: var(--lb-size-4x); }
.lb-banner--s { display: inline-flex; align-items: center; padding: var(--lb-size-0-5x) var(--lb-size-2x); border-radius: var(--lb-radius-interactive); gap: var(--lb-size-1x); font-size: var(--lb-t-body-s-font-size); }
.lb-banner--s .lb-banner__icon { width: 1rem; height: 1rem; margin-top: 0; }
.lb-banner--s .lb-banner__title { font-size: var(--lb-t-body-s-font-size); }
.lb-banner__icon  { display: flex; align-items: center; flex-shrink: 0; margin-top: 0.1em; width: 1.25rem; height: 1.25rem; }
.lb-banner__icon svg { width: 100%; height: 100%; }
.lb-banner__body  { flex: 1; display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-banner__title { font-weight: var(--lb-font-weight-semibold); }

/* Actions slot — optional CTA(s) next to body (inline on --m / --s,
   stacked inside body on --l). Supports 1 or 2 buttons. */
.lb-banner__actions { display: flex; align-items: center; gap: var(--lb-size-2x); flex-shrink: 0; }
.lb-banner--l .lb-banner__body .lb-banner__actions { margin-top: var(--lb-size-2x); }

/* Close button — auto-right when it's the only trailing element.
   When .lb-banner__actions is present, actions take the right slot
   and close sits just after them. */
.lb-banner__close { background: none; border: none; cursor: pointer; padding: 0; color: inherit; display: flex; align-items: center; margin-left: auto; flex-shrink: 0; opacity: 0.7; }
.lb-banner__actions + .lb-banner__close { margin-left: 0; }
.lb-banner__body + .lb-banner__actions { margin-left: auto; }
.lb-banner__close:hover { opacity: 1; }
.lb-banner__close:focus-visible { outline: var(--lb-border-width-medium) solid currentColor; outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-2); }

/* Small banner: tighten the button size and gaps */
.lb-banner--s .lb-banner__actions { gap: var(--lb-size-1x); }

/* ═══════════════════════════════════════════════════════════
   BREADCRUMB
   ═══════════════════════════════════════════════════════════ */

.lb-breadcrumb { display: inline-flex; }
.lb-breadcrumb__list { display: flex; flex-wrap: wrap; align-items: center; gap: var(--lb-size-1x); list-style: none; margin: 0; padding: 0; font-family: var(--lb-t-action-s-font-family); font-size: var(--lb-t-action-s-font-size); letter-spacing: var(--lb-t-action-s-letter-spacing); }
.lb-breadcrumb__item { display: flex; align-items: center; gap: var(--lb-size-1x); }
.lb-breadcrumb__link { color: var(--lb-fg-muted); text-decoration: none; transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-breadcrumb__link--button { background: none; border: none; padding: 0; cursor: pointer; font-family: inherit; font-size: inherit; }
.lb-breadcrumb__link:hover { color: var(--lb-fg-default); text-decoration: underline; }
.lb-breadcrumb__link:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-interactive); }
.lb-breadcrumb__separator { color: var(--lb-fg-subtle); user-select: none; font-size: var(--lb-t-action-s-font-size); }
.lb-breadcrumb__current { color: var(--lb-fg-default); font-weight: var(--lb-font-weight-medium); }

/* ═══════════════════════════════════════════════════════════
   NAVIGATION
   ═══════════════════════════════════════════════════════════ */

/* Navigation — two variants share most styling, diverge on direction
   and active-state treatment. Horizontal nav uses an underline bar
   under active items; vertical nav uses a left bar. Both reads at a
   glance even when colors are dialled down. */
.lb-nav { font-family: var(--lb-t-action-m-font-family); display: flex; align-items: center; }
.lb-nav--horizontal { flex-direction: row; gap: var(--lb-size-2x); padding: var(--lb-size-3x) var(--lb-size-6x); background-color: var(--lb-surface-bg-default); border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default); }
.lb-nav--horizontal .lb-nav__list { flex-direction: row; gap: var(--lb-size-1x); flex: 1; }
.lb-nav--vertical { flex-direction: column; align-items: stretch; padding: var(--lb-size-4x); background-color: var(--lb-surface-bg-elevated); border-right: var(--lb-border-width-thin) solid var(--lb-surface-border-default); min-width: 14rem; }
.lb-nav--vertical .lb-nav__list { flex-direction: column; gap: var(--lb-size-0-5x); flex: 1; align-items: stretch; }

.lb-nav__brand { display: flex; align-items: center; gap: var(--lb-size-2x); flex-shrink: 0; margin-right: var(--lb-size-6x); font-weight: var(--lb-font-weight-semibold); font-size: var(--lb-t-action-m-font-size); color: var(--lb-fg-default); text-decoration: none; }
.lb-nav--vertical .lb-nav__brand { margin-right: 0; margin-bottom: var(--lb-size-6x); padding-bottom: var(--lb-size-4x); border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default); }
.lb-nav__brand-mark { width: 1.75rem; height: 1.75rem; /* design-intent: brand mark glyph slot (Tier B 28px cluster) */ border-radius: var(--lb-radius-interactive); flex-shrink: 0; display: block; }

.lb-nav__list { list-style: none; margin: 0; padding: 0; display: flex; align-items: center; }

.lb-nav__item {
  /* Pinned 40px height to match .lb-btn--medium — keeps app-shell
     headers and sidebars looking consistent with the rest of the
     button language, and packs more items into a fixed-height
     sidebar. Padding adjusts to keep the same internal feel. */
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-2x);
  height: 2.5rem;
  padding: 0 var(--lb-size-3x);
  border-radius: var(--lb-radius-interactive);
  border: none;
  background: var(--lb-action-bg-ghost-default);
  font-family: var(--lb-t-action-m-font-family);
  font-size: var(--lb-t-action-m-font-size);
  font-weight: var(--lb-t-action-m-font-weight);
  line-height: var(--lb-t-action-m-line-height);
  letter-spacing: var(--lb-t-action-m-letter-spacing);
  color: var(--lb-fg-default);
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-nav__item:hover:not(.lb-nav__item--disabled) { background-color: var(--lb-action-bg-ghost-hover); }
.lb-nav__item:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-nav__item--disabled { color: var(--lb-fg-disabled); cursor: not-allowed; pointer-events: none; }

/* Active state — same color treatment everywhere, with an extra
   directional bar (underline horizontal, left side bar vertical) so
   the current page reads at a glance even when scanning quickly. */
.lb-nav__item--active {
  color: var(--lb-action-fg-selected);
  background-color: var(--lb-action-bg-selected);
}
.lb-nav__item--active:hover { background-color: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); }
.lb-nav--horizontal .lb-nav__item--active::after {
  content: '';
  position: absolute;
  left: var(--lb-size-3x);
  right: var(--lb-size-3x);
  bottom: calc(-1 * var(--lb-size-3x) - var(--lb-border-width-thin));
  height: var(--lb-border-width-medium);
  background: var(--lb-action-border-selected);
}
.lb-nav--vertical .lb-nav__item--active::before {
  content: '';
  position: absolute;
  left: 0;
  top: var(--lb-size-1x);
  bottom: var(--lb-size-1x);
  width: var(--lb-border-width-medium);
  background: var(--lb-action-border-selected);
  border-radius: 0 var(--lb-radius-full) var(--lb-radius-full) 0;
}

.lb-nav--vertical .lb-nav__item { width: 100%; padding: 0 var(--lb-size-4x); }

.lb-nav__item-icon { display: inline-flex; align-items: center; justify-content: center; width: 1.25rem; height: 1.25rem; flex-shrink: 0; }
.lb-nav__item-icon svg { width: 100%; height: 100%; }

/* Trailing notification badge (counts, "new", etc). Sits to the right
   of the label, color-toned to the accent palette. */
.lb-nav__item-badge {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  margin-left: auto;
  padding: 0 var(--lb-size-1x);
  border-radius: var(--lb-radius-full);
  background: var(--lb-bg-accent);
  color: var(--lb-fg-inverse-strong);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  line-height: 1;
  flex-shrink: 0;
}
.lb-nav__item-badge:empty { display: none; }

/* Actions cluster — pinned right (horizontal) or pinned bottom (vertical). */
.lb-nav__actions { display: flex; align-items: center; gap: var(--lb-size-2x); margin-left: auto; flex-shrink: 0; }
.lb-nav--vertical .lb-nav__actions { margin-left: 0; margin-top: auto; padding-top: var(--lb-size-4x); border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default); }

/* Sectioned groups for vertical sidebars — small uppercase label above
   a cluster of related items. */
.lb-nav__group { display: flex; flex-direction: column; gap: var(--lb-size-0-5x); margin-bottom: var(--lb-size-3x); }
/* Group-label VOICE — one recipe for both nav + shell sidebars
   (consolidated 2026-07-31; ramp-minted as t-overline 2026-08-05 —
   the aa4f64c voice is now a named style). Spacing stays per-component
   below; uppercase stays here (DTCG typography carries no textCase). */
.lb-nav__group-label,
.lb-shell__group-label {
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  text-transform: uppercase;
}
.lb-nav__group-label {
  display: block;
  padding: var(--lb-size-3x) var(--lb-size-4x) var(--lb-size-2x);
}

/* Collapsed/icon-only sidebar variant — labels visually hidden, just
   glyphs. Labels stay CLIP-HIDDEN (not display:none) so every item and
   the brand keep their accessible names — same treatment as the
   app-shell rail. Badges and group labels are informational chrome and
   genuinely leave. */
.lb-nav--collapsed { min-width: auto; width: 4rem; padding: var(--lb-size-3x) var(--lb-size-1x); }
.lb-nav--collapsed .lb-nav__item { justify-content: center; padding: 0; }
.lb-nav--collapsed .lb-nav__item-label,
.lb-nav--collapsed .lb-nav__brand > span:not(.lb-nav__item-icon):not([data-lb-icon]),
.lb-nav--collapsed .lb-nav__brand-text {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  clip-path: inset(50%);
  overflow: hidden;
  white-space: nowrap;
}
.lb-nav--collapsed .lb-nav__item-badge,
.lb-nav--collapsed .lb-nav__group-label { display: none; }
.lb-nav--collapsed .lb-nav__brand { justify-content: center; }
.lb-nav--collapsed .lb-nav__item-icon { width: 1.5rem; height: 1.5rem; }

/* ═══════════════════════════════════════════════════════════
   INPUT
   ═══════════════════════════════════════════════════════════ */

.lb-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); }
.lb-label { font-family: var(--lb-t-label-m-font-family); font-size: var(--lb-t-label-m-font-size); font-weight: var(--lb-t-label-m-font-weight); line-height: var(--lb-t-label-m-line-height); letter-spacing: var(--lb-t-label-m-letter-spacing); color: var(--lb-field-fg-label); }
.lb-label--required::after { content: ' *'; color: var(--lb-fg-danger); }

/* Horizontal field layout — label on left, input (+ hint + error) on right.
   Uses grid: col 1 = label column (fixed), col 2 = everything else stacked.
   Collapses to vertical on narrow screens. */
.lb-field--horizontal {
  display: grid;
  grid-template-columns: 10rem 1fr;
  column-gap: var(--lb-size-4x);
  row-gap: var(--lb-size-1x);
  align-items: start;
}
.lb-field--horizontal > .lb-label {
  grid-column: 1;
  grid-row: 1;
  padding-top: var(--lb-size-2x); /* align baseline with input text */
}
.lb-field--horizontal > :not(.lb-label) { grid-column: 2; }
@media (max-width: 640px) {
  .lb-field--horizontal { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
  .lb-field--horizontal > .lb-label { padding-top: 0; }
}
.lb-input-wrap { position: relative; display: flex; align-items: center; }
.lb-input { width: 100%; font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-field-fg-default); background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); outline: none; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); appearance: none; -webkit-appearance: none; }
.lb-input--medium { height: 2.5rem; padding: 0 var(--lb-size-3x); }
.lb-input--small  { height: 2rem;   padding: 0 var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); }
.lb-input::placeholder { color: var(--lb-field-fg-placeholder); }
.lb-input::-webkit-search-cancel-button { -webkit-appearance: none; display: none; }
.lb-input::-webkit-search-decoration { -webkit-appearance: none; }
.lb-input:focus { border-color: var(--lb-field-border-focus); outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-input:disabled { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-input--error { border-color: var(--lb-field-border-error); }
.lb-input--error:focus { border-color: var(--lb-field-border-error); outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); outline-offset: var(--lb-size-0-5x); }
.lb-input--success { border-color: var(--lb-field-border-success); }
.lb-input--success:focus { border-color: var(--lb-field-border-success); outline: var(--lb-border-width-medium) solid var(--lb-field-border-success); outline-offset: var(--lb-size-0-5x); }
.lb-input--has-start { padding-left: 2.25rem; }
.lb-input--has-end   { padding-right: 2.25rem; }
/* Multiline variant — apply to <textarea class="lb-input lb-input--multiline">.
   Defeats the fixed height set by --small / --medium, restores textarea
   block-level padding, and pins resize to vertical only. Combine with
   --small for compact font-size in dense layouts.
   Width constraints follow common practice for free-form text fields:
   max-width 45rem (~720px) keeps lines at ~50–75 chars for readable prose. min-width
   18rem (~288px) is the comfortable typing threshold, but min() collapses
   it to 100% when the parent is narrower — no horizontal scroll on
   phones or inside narrow side panels. Override either with inline
   style="max-width: …" / "width: …" — inline always wins by specificity. */
.lb-input--multiline { height: auto; min-height: 5rem; padding: var(--lb-size-2x) var(--lb-size-3x); resize: vertical; min-width: min(18rem, 100%); max-width: 45rem; }
.lb-input--multiline:disabled { resize: none; }
.lb-input-wrap__icon { position: absolute; display: flex; align-items: center; justify-content: center; width: 1.25rem; height: 1.25rem; color: var(--lb-fg-muted); pointer-events: none; }
.lb-input-wrap__icon svg { width: 100%; height: 100%; }
.lb-input-wrap__icon--start { left: var(--lb-size-3x); }
.lb-input-wrap__icon--end   { right: var(--lb-size-3x); }

/* Interactive action button inside input (clearable X, password toggle) */
.lb-input-wrap__action { position: absolute; right: var(--lb-size-2x); display: flex; align-items: center; justify-content: center; width: 1.5rem; height: 1.5rem; padding: 0; background: none; border: none; border-radius: var(--lb-radius-interactive); color: var(--lb-fg-muted); cursor: pointer; transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); z-index: 1; }
.lb-input-wrap__action:hover { color: var(--lb-fg-default); background-color: var(--lb-bg-strong); }
.lb-input-wrap__action:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-input-wrap__action--hidden { display: none; }
.lb-input-wrap__action svg { width: 100%; height: 100%; }

.lb-field__hint    { font-family: var(--lb-t-body-xs-font-family); font-size: var(--lb-t-body-xs-font-size); line-height: var(--lb-t-body-xs-line-height); color: var(--lb-field-fg-hint); }
/* Validation hints: flex layout with a leading icon slot. The icon
   itself is a real <span data-lb-icon="…"> injected by lb.js's
   initFieldHintIcons() — that way it goes through the same icon
   library as everything else and the Icon stroke knob can retune it.
   (Earlier mask-image approach couldn't be retuned because mask layers
   are opaque silhouettes — host CSS variables can't reach inside.) */
.lb-field__error,
.lb-field__success {
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-body-xs-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  line-height: var(--lb-t-body-xs-line-height);
}
.lb-field__error   { color: var(--lb-field-fg-error); }
.lb-field__success { color: var(--lb-field-fg-success); }
.lb-field__error   > [data-lb-icon],
.lb-field__success > [data-lb-icon] { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); flex-shrink: 0; }

/* ═══════════════════════════════════════════════════════════
   FORM + FIELD GROUP
   .lb-form          — parent shell, consistent vertical rhythm
   .lb-form__actions — button row at bottom (submit/cancel)
   .lb-field-group   — <fieldset> grouping related fields under a legend
   Works with all existing form primitives (input, select, checkbox, radio,
   switch, datepicker, phone, dropdown, multi-select, textarea).
   ═══════════════════════════════════════════════════════════ */

.lb-form {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-6x); /* 24px between top-level fields / groups */
  font-family: var(--lb-t-body-m-font-family);
}
.lb-form--compact { gap: var(--lb-size-4x); }
.lb-form--loose   { gap: var(--lb-size-8x); }

.lb-form__actions {
  display: flex;
  gap: var(--lb-size-2x);
  padding-top: var(--lb-size-2x);
  justify-content: flex-end;
  flex-wrap: wrap;
}
.lb-form__actions--start  { justify-content: flex-start; }
.lb-form__actions--spread { justify-content: space-between; }

/* Field Group — <fieldset> with legend, resets native fieldset styling */
.lb-field-group {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-4x); /* 16px between fields inside a group */
  border: 0;
  padding: 0;
  margin: 0;
  min-width: 0;
}
.lb-field-group__legend {
  font-family: var(--lb-t-label-m-font-family);
  font-size: var(--lb-t-label-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  line-height: var(--lb-t-label-m-line-height);
  letter-spacing: var(--lb-t-label-m-letter-spacing);
  color: var(--lb-fg-default);
  padding: 0;
  margin: 0 0 var(--lb-size-1x);
}
.lb-field-group__description {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  color: var(--lb-fg-muted);
  margin: 0 0 var(--lb-size-2x);
}

/* Inline fields — a row of compact fields side-by-side (e.g. First name + Last name) */
.lb-field-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--lb-size-4x);
}

/* ═══════════════════════════════════════════════════════════
   TEXTAREA
   ═══════════════════════════════════════════════════════════ */

/* ═══════════════════════════════════════════════════════════
   NUMBER INPUT
   Field for numeric entry: stepper buttons, min/max clamping,
   prefix/suffix for units ($, %, kg). Buttons auto-disable at
   the min/max boundary. Dispatches `lb-number-change`.
   Sizes: --sm | --medium (default)
   ═══════════════════════════════════════════════════════════ */

.lb-number-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); }

.lb-number-wrap {
  display: inline-flex;
  align-items: stretch;
  width: 100%;
  background: var(--lb-field-bg-default);
  border: var(--lb-border-width-action) solid var(--lb-field-border-default);
  border-radius: var(--lb-radius-field);
  overflow: hidden;
  transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-number-wrap:focus-within {
  border-color: var(--lb-field-border-focus);
  outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-number-wrap--sm     { height: 2rem; }
.lb-number-wrap--medium { height: 2.5rem; }

/* Native input with all chrome stripped — wrap provides visual frame */
.lb-number {
  flex: 1;
  min-width: 3rem; /* design-intent: number-stepper input min readable width */
  border: none;
  outline: none;
  background: transparent;
  color: var(--lb-field-fg-default);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  text-align: center;
  font-variant-numeric: tabular-nums;
  padding: 0 var(--lb-size-2x);
  -moz-appearance: textfield;
  appearance: textfield;
}
.lb-number::-webkit-outer-spin-button,
.lb-number::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.lb-number::placeholder { color: var(--lb-field-fg-placeholder); }
.lb-number-wrap--sm .lb-number { font-size: var(--lb-t-body-s-font-size); }

/* Stepper buttons — ghost-style: use action-ghost L3 tokens so the icons
   read as full-confidence button glyphs (not placeholder/muted). */
.lb-number__step {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.25rem;
  flex-shrink: 0;
  border: none;
  background: transparent;
  color: var(--lb-action-fg-ghost-default);
  cursor: pointer;
  padding: 0;
  user-select: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-number-wrap--sm .lb-number__step { width: 1.75rem; /* design-intent: small stepper button width (Tier B 28px cluster) */ }
.lb-number__step:hover:not(:disabled) {
  background: var(--lb-action-bg-ghost-hover);
  color: var(--lb-action-fg-ghost-hover);
}
.lb-number__step:active:not(:disabled) { background: var(--lb-action-bg-ghost-pressed); }
.lb-number__step:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: calc(-1 * var(--lb-border-width-medium));
  z-index: 1;
}
.lb-number__step:disabled { color: var(--lb-fg-disabled); cursor: not-allowed; }
.lb-number__step svg { width: 1rem; height: 1rem; }

/* Separator strokes between stepper buttons and input cell — same width
   and tone as the outer frame so the field reads as one unified control. */
.lb-number__step--dec { border-right: var(--lb-border-width-action) solid var(--lb-field-border-default); }
.lb-number__step--inc { border-left:  var(--lb-border-width-action) solid var(--lb-field-border-default); }
/* Error state: inner separators pick up the error color to stay uniform */
.lb-number-wrap--error .lb-number__step--dec { border-right-color: var(--lb-field-border-error); }
.lb-number-wrap--error .lb-number__step--inc { border-left-color:  var(--lb-field-border-error); }
.lb-number-wrap--success .lb-number__step--dec { border-right-color: var(--lb-field-border-success); }
.lb-number-wrap--success .lb-number__step--inc { border-left-color:  var(--lb-field-border-success); }

/* Prefix / suffix for units ($, %, USD, kg) — sits between step button and input */
.lb-number__prefix,
.lb-number__suffix {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--lb-size-2x);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  user-select: none;
  flex-shrink: 0;
}
.lb-number__prefix { padding-left: var(--lb-size-3x); padding-right: 0; }
.lb-number__suffix { padding-right: var(--lb-size-3x); padding-left: 0; }
.lb-number__prefix + .lb-number { padding-left: var(--lb-size-1x); text-align: left; }
.lb-number:has(+ .lb-number__suffix) { padding-right: var(--lb-size-1x); text-align: left; }

/* State variants */
.lb-number-wrap--error { border-color: var(--lb-field-border-error); }
.lb-number-wrap--error:focus-within { border-color: var(--lb-field-border-error); outline-color: var(--lb-field-border-error); }
.lb-number-wrap--success { border-color: var(--lb-field-border-success); }
.lb-number-wrap--disabled,
.lb-number-wrap:has(.lb-number:disabled) {
  background: var(--lb-field-bg-disabled);
  border-color: var(--lb-field-border-disabled);
  cursor: not-allowed;
}
.lb-number-wrap--disabled .lb-number,
.lb-number:disabled { color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-number-wrap--disabled .lb-number__step,
.lb-number-wrap:has(.lb-number:disabled) .lb-number__step { color: var(--lb-fg-disabled); cursor: not-allowed; pointer-events: none; }
/* Inner separators match the disabled outer border tone */
.lb-number-wrap--disabled .lb-number__step--dec,
.lb-number-wrap:has(.lb-number:disabled) .lb-number__step--dec { border-right-color: var(--lb-field-border-disabled); }
.lb-number-wrap--disabled .lb-number__step--inc,
.lb-number-wrap:has(.lb-number:disabled) .lb-number__step--inc { border-left-color:  var(--lb-field-border-disabled); }

/* ═══════════════════════════════════════════════════════════
   FILE UPLOADER
   Drag-drop zone + click-to-browse + uploaded-files list.
   Composes: Button (browse), Progress (upload bar), List primitive
   (file list), Empty state (no files yet).
   ═══════════════════════════════════════════════════════════ */

.lb-uploader {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-3x);
  font-family: var(--lb-t-body-m-font-family);
}

/* Drop zone — dashed border target */
.lb-uploader__dropzone {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-8x) var(--lb-size-4x);
  border: var(--lb-border-width-action) dashed var(--lb-border-muted);
  border-radius: var(--lb-radius-surface);
  background: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-uploader__dropzone:hover:not(.lb-uploader__dropzone--disabled) {
  border-color: var(--lb-border-accent);
  background: var(--lb-bg-strong);
}
.lb-uploader__dropzone:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
/* Drag-active — user is hovering a file over the zone */
.lb-uploader__dropzone--drag-active {
  border-color: var(--lb-border-accent);
  background: var(--lb-bg-accent-muted);
  border-style: solid;
}
.lb-uploader__dropzone--disabled {
  opacity: 0.6;
  cursor: not-allowed;
  pointer-events: none;
}
.lb-uploader__dropzone--error {
  border-color: var(--lb-field-border-error);
  background: var(--lb-bg-danger-subtle);
}

.lb-uploader__icon {
  display: inline-flex;
  color: var(--lb-fg-muted);
  width: 3rem;
  height: 3rem;
}
.lb-uploader__icon svg { width: 100%; height: 100%; }
.lb-uploader__dropzone--drag-active .lb-uploader__icon,
.lb-uploader__dropzone--error .lb-uploader__icon {
  color: var(--lb-fg-accent);
}
.lb-uploader__dropzone--error .lb-uploader__icon { color: var(--lb-fg-danger); }

.lb-uploader__title {
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-body-l-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  margin: 0;
}
.lb-uploader__hint {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  margin: 0;
}

/* Hidden native file input — must stay in DOM for form submission */
.lb-uploader__input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: inherit;
  /* Don't receive pointer events — wrap handles clicks */
  pointer-events: none;
}

/* Compact variant — inline for settings rows, smaller padding */
.lb-uploader--compact .lb-uploader__dropzone {
  flex-direction: row;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-3x) var(--lb-size-4x);
  text-align: left;
}
.lb-uploader--compact .lb-uploader__icon { width: 1.5rem; height: 1.5rem; }
.lb-uploader--compact .lb-uploader__title { font-size: var(--lb-t-body-m-font-size); }
.lb-uploader--compact .lb-uploader__hint { font-size: var(--lb-t-caption-m-font-size); }
.lb-uploader--compact .lb-uploader__text { flex: 1; min-width: 0; }

/* File list — one row per file, with name, size, progress, remove */
.lb-uploader__files {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
}
.lb-uploader__files:empty { display: none; }

.lb-uploader__file {
  display: grid;
  grid-template-columns: auto 1fr auto auto;
  align-items: center;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  background: var(--lb-surface-bg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-surface);
  font-family: var(--lb-t-body-s-font-family);
}
.lb-uploader__file--error {
  border-color: var(--lb-field-border-error);
  background: var(--lb-bg-danger-subtle);
}
.lb-uploader__file--success { border-color: var(--lb-field-border-success); }

.lb-uploader__file-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;  /* design-intent: uploader file row icon slot (Tier B 28px cluster) */
  height: 1.75rem; /* design-intent: uploader file row icon slot (Tier B 28px cluster) */
  color: var(--lb-fg-muted);
  flex-shrink: 0;
}
.lb-uploader__file-icon svg { width: 1.25rem; height: 1.25rem; }

.lb-uploader__file-body {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  min-width: 0;
}
.lb-uploader__file-name {
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-default);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-uploader__file-meta {
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-uploader__file--error .lb-uploader__file-meta { color: var(--lb-fg-danger); }

/* Upload progress bar fills the `__progress` column — reuses .lb-progress */
.lb-uploader__progress { width: 8rem; /* design-intent: uploader progress column width */ }
.lb-uploader__file--done .lb-uploader__progress { display: none; }

/* Remove button — icon-only, tucked right */
.lb-uploader__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;  /* design-intent: uploader remove button (Tier B 28px cluster) */
  height: 1.75rem; /* design-intent: uploader remove button (Tier B 28px cluster) */
  padding: 0;
  border: none;
  background: transparent;
  color: var(--lb-fg-muted);
  border-radius: var(--lb-radius-full);
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-uploader__remove:hover { background: var(--lb-action-bg-ghost-hover); color: var(--lb-fg-default); }
.lb-uploader__remove:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-uploader__remove svg { width: 1rem; height: 1rem; }

/* ═══════════════════════════════════════════════════════════
   COMMAND PALETTE
   Global ⌘K/Ctrl+K launcher.
   Shell that anchors to top of viewport (not centered modal);
   composes the shared List primitive in --filterable mode for
   the actual command list. Keyboard nav, grouping, kbd hints.
   ═══════════════════════════════════════════════════════════ */

.lb-cmdk-backdrop {
  position: fixed;
  inset: 0;
  z-index: 7500;  /* above modals but below toasts */
  background: color-mix(in srgb, var(--lb-surface-bg-backdrop) 50%, transparent);
  display: flex;
  align-items: flex-start;     /* top-anchored, not centered */
  justify-content: center;
  padding-top: 12vh;           /* top-anchored, not vertically centred */
  padding-left: var(--lb-size-4x);
  padding-right: var(--lb-size-4x);
  animation: lb-cmdk-backdrop-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
/* [hidden] handled by global [class*="lb-"][hidden] rule near top of file */
@keyframes lb-cmdk-backdrop-in { from { opacity: 0; } to { opacity: 1; } }

.lb-cmdk {
  width: 100%;
  max-width: 40rem;           /* design-intent: cmdk dialog max — ~640px, fits long command labels */
  max-height: 70vh;           /* design-intent: cmdk dialog viewport cap */
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-modal);
  display: flex;
  flex-direction: column;
  overflow: hidden;            /* contains the inner scroll region */
  font-family: var(--lb-t-body-m-font-family);
  animation: lb-cmdk-in var(--lb-animation-dur-normal) cubic-bezier(0.16, 1, 0.3, 1);
}
@keyframes lb-cmdk-in {
  from { opacity: 0; transform: translateY(-8px) scale(0.98); } /* design-intent: cmdk drop-in offset */
  to   { opacity: 1; transform: translateY(0)    scale(1); }
}

/* Search row — hosts a real .lb-input-wrap + .lb-input (so the search
   field inherits DS styling, dark-mode support, focus states etc.)
   and the escape-hint kbd chip on the right. */
.lb-cmdk__search-wrap {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  flex-shrink: 0;
}
/* Our .lb-input brings its own border/radius — we don't need the double
   frame inside the palette, so the input has inline border:none above.
   But we keep the outer wrap focus ring intact by styling the wrap
   itself when focus is inside. */
.lb-cmdk__search-wrap:focus-within .lb-input-wrap { outline: none; }

/* Escape hint — small kbd chip on the right of the search row */
.lb-cmdk__escape-hint {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--lb-size-1-5x);
  height: 1.25rem;
  border-radius: var(--lb-radius-interactive);
  background: var(--lb-bg-strong);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  flex-shrink: 0;
  user-select: none;
}

/* Results region — scrollable, fills remaining height */
.lb-cmdk__results {
  overflow-y: auto;
  flex: 1;
  padding: var(--lb-size-1x) 0;
}

/* Group label — subtle section header between command groups */
/* t-overline — consolidated onto the one uppercase micro-label voice
   (2026-08-05, owner-decided; was label-s + semibold + wide). */
.lb-cmdk__group-label {
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  color: var(--lb-fg-muted);
  padding: var(--lb-size-2x) var(--lb-size-4x) var(--lb-size-1x);
  text-transform: uppercase;
}

/* Footer — tips/shortcuts strip */
.lb-cmdk__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-4x);
  padding: var(--lb-size-2x) var(--lb-size-4x);
  border-top: var(--lb-border-width-thin) solid var(--lb-border-muted);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  flex-shrink: 0;
}
.lb-cmdk__footer kbd {
  display: inline-flex;
  align-items: center;
  padding: 0 var(--lb-size-1-5x);
  min-height: 1.125rem;
  margin: 0 var(--lb-size-0-5x);
  border-radius: var(--lb-radius-interactive);
  background: var(--lb-bg-strong);
  /* t-code-s: keycaps read as mono (the item-17 kbd-mono wish). */
  font-family: var(--lb-t-code-s-font-family);
  font-size: var(--lb-t-code-s-font-size);
  color: var(--lb-fg-default);
}

/* Inside the results, reuse list primitive — scope a couple of
   command-palette-specific tweaks without fighting the base rules */
.lb-cmdk__results .lb-list { padding: 0; }
.lb-cmdk__results .lb-list__item {
  padding: var(--lb-size-2x) var(--lb-size-4x);
}

/* ═══════════════════════════════════════════════════════════
   SEGMENTED CONTROL
   Pill-style "either/or" selector — view modes, time ranges,
   sort orders, binary/ternary filters. Visually and semantically
   distinct from Tabs (which own content panels below).
   ARIA: <div role="radiogroup"> with role="radio" on each segment,
   or a group of <button aria-pressed> for toggle-style use.
   Sizes: --sm | --medium (default)
   Optional: --full-width (stretch to container)
   ═══════════════════════════════════════════════════════════ */

.lb-segmented {
  display: inline-flex;
  gap: var(--lb-size-0-5x);
  padding: var(--lb-size-0-5x);
  background: var(--lb-bg-strong);
  border-radius: var(--lb-radius-full);
  font-family: var(--lb-t-action-m-font-family);
  vertical-align: middle;
}
.lb-segmented--full-width { display: flex; width: 100%; }
.lb-segmented--full-width > .lb-segmented__item { flex: 1; }

.lb-segmented__item {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--lb-size-1x);
  height: 2rem;
  min-width: 0;
  padding: 0 var(--lb-size-3x);
  border: none;
  background: transparent;
  color: var(--lb-fg-muted);
  border-radius: var(--lb-radius-full);
  font-family: inherit;
  font-size: var(--lb-t-action-s-font-size);
  font-weight: var(--lb-t-action-s-font-weight);
  line-height: var(--lb-t-action-s-line-height);
  letter-spacing: var(--lb-t-action-s-letter-spacing);
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-segmented__item:hover:not([aria-checked="true"]):not([aria-pressed="true"]):not(:disabled) {
  color: var(--lb-fg-default);
}
.lb-segmented__item:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-segmented__item:disabled {
  color: var(--lb-fg-disabled);
  cursor: not-allowed;
}
/* Active — aria-checked for radiogroup, aria-pressed for button group */
.lb-segmented__item[aria-checked="true"],
.lb-segmented__item[aria-pressed="true"] {
  background: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  box-shadow: var(--lb-shadow-1);
}

/* Icon slot for segments */
.lb-segmented__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
}
.lb-segmented__icon svg { width: 100%; height: 100%; }

/* Sizes */
.lb-segmented--sm .lb-segmented__item { height: 1.5rem; padding: 0 var(--lb-size-2x); font-size: var(--lb-t-caption-m-font-size); }
.lb-segmented--sm .lb-segmented__icon { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); }
.lb-segmented--medium .lb-segmented__item { height: 2rem; }

/* ═══════════════════════════════════════════════════════════
   STEPPER
   Multi-step progress indicator — signup flows, checkout, wizards.
   Horizontal (default) or vertical (`--vertical`).
   States on each step: --complete, --active, default (upcoming).
   Pure declarative — consumer manages state.
   ═══════════════════════════════════════════════════════════ */

.lb-stepper {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  font-family: var(--lb-t-body-m-font-family);
  --lb-stepper-size: 2rem;           /* indicator diameter */
  --lb-stepper-connector: 2px;       /* design-intent: connector line thickness, variable per density */
}

/* Horizontal layout — equal-width columns, indicator + label stacked */
.lb-stepper,
.lb-stepper--horizontal {
  flex-direction: row;
  align-items: flex-start;
}
.lb-stepper--horizontal .lb-stepper__step {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  position: relative;
  min-width: 0;
}
/* Shared connector defaults — background + transition live here so state
   overrides (complete / error) only need to match this rule's specificity
   to win on source order. Per-orientation rules below only do positioning. */
.lb-stepper__step:not(:last-child)::after {
  content: '';
  position: absolute;
  background: var(--lb-border-muted);
  transition: background var(--lb-animation-dur-normal) var(--lb-animation-ease-ui);
}
/* Horizontal connector positioning — from center of current indicator to
   center of next step */
.lb-stepper--horizontal .lb-stepper__step:not(:last-child)::after {
  top: calc(var(--lb-stepper-size) / 2);
  left: calc(50% + (var(--lb-stepper-size) / 2) + var(--lb-size-1x));
  right: calc(-50% + (var(--lb-stepper-size) / 2) + var(--lb-size-1x));
  height: var(--lb-stepper-connector);
  transform: translateY(-50%);
}

/* Vertical layout — indicator + content side-by-side, connector vertical */
.lb-stepper--vertical {
  flex-direction: column;
  align-items: stretch;
}
.lb-stepper--vertical .lb-stepper__step {
  display: flex;
  flex-direction: row;
  align-items: flex-start;
  gap: var(--lb-size-3x);
  padding-bottom: var(--lb-size-6x);
  position: relative;
}
.lb-stepper--vertical .lb-stepper__step:last-child { padding-bottom: 0; }
.lb-stepper--vertical .lb-stepper__step:not(:last-child)::after {
  left: calc(var(--lb-stepper-size) / 2);
  top: calc(var(--lb-stepper-size) + var(--lb-size-1x));
  bottom: var(--lb-size-1x);
  width: var(--lb-stepper-connector);
  transform: translateX(-50%);
}

/* Indicator — circle with number or checkmark */
.lb-stepper__indicator {
  width: var(--lb-stepper-size);
  height: var(--lb-stepper-size);
  flex-shrink: 0;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--lb-bg-default);
  color: var(--lb-fg-muted);
  border: var(--lb-stepper-connector) solid var(--lb-border-muted);
  font-family: var(--lb-t-label-s-font-family);
  font-size: var(--lb-t-label-s-font-size);
  font-weight: var(--lb-font-weight-semibold);
  transition: background var(--lb-animation-dur-normal) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-normal) var(--lb-animation-ease-ui), color var(--lb-animation-dur-normal) var(--lb-animation-ease-ui);
  z-index: 1; /* keep indicator above the connector line */
  position: relative;
}
.lb-stepper__indicator svg { width: 1rem; height: 1rem; }

/* Content slot (vertical) — title + optional description stacked */
.lb-stepper__content {
  flex: 1;
  min-width: 0;
  padding-top: calc((var(--lb-stepper-size) - var(--lb-t-body-m-line-height)) / 2);
}
.lb-stepper__label {
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-muted);
  line-height: var(--lb-t-body-m-line-height);
  margin: 0;
  transition: color var(--lb-animation-dur-normal) var(--lb-animation-ease-ui);
}
.lb-stepper__description {
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  color: var(--lb-fg-muted);
  margin-top: var(--lb-size-1x);
}
/* Horizontal label sits below the indicator */
.lb-stepper--horizontal .lb-stepper__label {
  margin-top: var(--lb-size-2x);
  text-align: center;
  font-size: var(--lb-t-body-s-font-size);
}

/* ── States ── */
/* Active — the current step */
.lb-stepper__step--active .lb-stepper__indicator {
  background: var(--lb-action-bg-primary-default);
  border-color: var(--lb-action-border-primary-default);
  color: var(--lb-action-fg-primary-default);
}
.lb-stepper__step--active .lb-stepper__label { color: var(--lb-fg-default); font-weight: var(--lb-font-weight-semibold); }

/* Complete — connector + indicator fill with primary accent */
.lb-stepper__step--complete .lb-stepper__indicator {
  background: var(--lb-action-bg-primary-default);
  border-color: var(--lb-action-border-primary-default);
  color: var(--lb-action-fg-primary-default);
}
.lb-stepper__step--complete .lb-stepper__label { color: var(--lb-fg-default); }
/* Connector AFTER a complete step — traveled path */
.lb-stepper__step--complete:not(:last-child)::after { background: var(--lb-action-bg-primary-default); }

/* Connector INTO an error step takes the error color — the path was
   travelled but failed. Works for any step (complete/active/upcoming)
   that precedes an --error step. Higher specificity than the complete
   rule so it wins when both apply. */
.lb-stepper__step:not(:last-child):has(+ .lb-stepper__step--error)::after { background: var(--lb-action-bg-danger-default); }

/* Error — a step failed validation (optional state) */
.lb-stepper__step--error .lb-stepper__indicator {
  background: var(--lb-action-bg-danger-default);
  border-color: var(--lb-action-border-danger-default);
  color: var(--lb-action-fg-danger-default);
}
.lb-stepper__step--error .lb-stepper__label { color: var(--lb-fg-danger); font-weight: var(--lb-font-weight-semibold); }

/* ── Size variant — small (dense use in toolbars / inline contexts) ── */
.lb-stepper--sm { --lb-stepper-size: 1.5rem; --lb-stepper-connector: 2px; /* design-intent: small stepper connector thickness */ }
.lb-stepper--sm .lb-stepper__indicator { font-size: var(--lb-t-caption-m-font-size); }
.lb-stepper--sm .lb-stepper__indicator svg { width: 0.75rem; height: 0.75rem; }

/* ── Clickable variant — when a step is a <button> or has role=button ── */
.lb-stepper__step > button.lb-stepper__trigger {
  display: contents;
  background: none;
  border: none;
  padding: 0;
  font: inherit;
  color: inherit;
  cursor: pointer;
  text-align: inherit;
}
.lb-stepper__step > button.lb-stepper__trigger:focus-visible .lb-stepper__indicator {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-stepper__step > button.lb-stepper__trigger:hover:not(:disabled) .lb-stepper__indicator {
  box-shadow: 0 0 0 4px var(--lb-action-bg-ghost-hover);
}
.lb-stepper__step > button.lb-stepper__trigger:disabled { cursor: not-allowed; opacity: 0.6; }

/* Textarea is now an Input variant — see .lb-input--multiline above.
   The previous .lb-textarea / .lb-textarea-field rules were 95% duplicates
   of .lb-input + .lb-field. Pattern: <textarea class="lb-input lb-input--multiline"> */


/* ═══════════════════════════════════════════════════════════
   SELECT
   ═══════════════════════════════════════════════════════════ */

.lb-select-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); }
.lb-select-wrap { position: relative; display: flex; align-items: center; }
.lb-select { width: 100%; font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-field-fg-default); background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); outline: none; cursor: pointer; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); appearance: none; -webkit-appearance: none; padding-right: 2.25rem; }
.lb-select--medium { height: 2.5rem; padding-left: var(--lb-size-3x); }
.lb-select--small  { height: 2rem;   padding-left: var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); }
.lb-select:focus { border-color: var(--lb-field-border-focus); outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-select:disabled { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-select--error { border-color: var(--lb-field-border-error); }
.lb-select--error:focus { border-color: var(--lb-field-border-error); outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); outline-offset: var(--lb-size-0-5x); }
.lb-select-wrap__chevron { position: absolute; right: var(--lb-size-3x); pointer-events: none; color: var(--lb-fg-muted); display: flex; align-items: center; transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-select-wrap__chevron--open { transform: rotate(180deg); }
.lb-select-wrap__chevron svg { width: 1.25rem; height: 1.25rem; }

/* Custom select trigger (button-based) */
.lb-select__text { flex: 1; text-align: left; }
.lb-select__text--placeholder { color: var(--lb-field-fg-placeholder); }
button.lb-select { display: flex; align-items: center; gap: var(--lb-size-2x); text-align: left; }
.lb-dropdown-list__option--selected { font-weight: var(--lb-font-weight-semibold); color: var(--lb-fg-accent); }

/* ═══════════════════════════════════════════════════════════
   CHECKBOX
   ═══════════════════════════════════════════════════════════ */

.lb-checkbox-wrap { display: inline-flex; align-items: flex-start; gap: var(--lb-size-2x); cursor: pointer; }
.lb-checkbox-wrap--disabled { opacity: 0.5; cursor: not-allowed; }
.lb-checkbox { appearance: none; -webkit-appearance: none; width: 1.25rem; height: 1.25rem; flex-shrink: 0; margin-top: 0.1em; border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-interactive); background: var(--lb-field-bg-default); cursor: pointer; transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); position: relative; }
.lb-checkbox:checked, .lb-checkbox:indeterminate { background: var(--lb-action-bg-primary-default); border-color: var(--lb-action-border-primary-default); color: var(--lb-action-fg-primary-default); }
.lb-checkbox:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-checkbox:disabled { cursor: not-allowed; }

/* Checkbox glyph rendering — real SVGs via [data-lb-icon] so they pick
   up the global icon-stroke knob (mask-image earlier was opaque to host
   CSS variables). The frame wraps the input + two sibling glyph spans
   (check + minus) which JS injects in initCheckboxGlyphs(). Visibility
   is controlled by the sibling combinator on :checked / :indeterminate
   states; default is hidden. */
.lb-checkbox-frame {
  position: relative;
  display: inline-flex;
  flex-shrink: 0;
  line-height: 0;
}
/* Glyph slot inside the checkbox — overrides the global [data-lb-icon]
   rule (width:1em, inline-flex) by selector boost (.lb-checkbox-frame >
   [data-lb-icon] is 0,2,0 vs the global's 0,1,0). Without this, the
   glyph rendered at ~16px text-size in the top-left of the box and
   the absolute positioning never took effect. */
.lb-checkbox-frame > .lb-checkbox__glyph[data-lb-icon] {
  position: absolute;
  inset: 0;
  display: none;
  align-items: center;
  justify-content: center;
  width: auto;       /* clear the global 1em */
  height: auto;      /* clear the global 1em */
  pointer-events: none;
  /* Inherit checked-state color from the input via the sibling combinator
     below. The SVG stroke uses currentColor, so this paints the glyph. */
  color: var(--lb-action-fg-primary-default);
  /* Inset so the glyph doesn't crowd the rounded corners of the box. */
  padding: 12.5%;
}
.lb-checkbox-frame > .lb-checkbox__glyph[data-lb-icon] svg {
  width: 100%;
  height: 100%;
  /* Pin a fixed viewBox-unit stroke instead of the global brand-driven
     --lb-stroke-icon. At ~15px display the brand stroke reads as
     chunky; 2.5 viewBox units ≈ Lucide's intended weight when scaled
     down. */
  stroke-width: 2.5;
}
/* Visibility selectors match the same specificity bump (0,2,1) as the
   slot itself — without [data-lb-icon] here, the slot's `display: none`
   would win over the sibling-combinator `display: inline-flex` and the
   glyph would never appear. */
.lb-checkbox:checked       ~ .lb-checkbox__glyph--check[data-lb-icon]  { display: inline-flex; }
.lb-checkbox:indeterminate ~ .lb-checkbox__glyph--minus[data-lb-icon]  { display: inline-flex; }
/* If both states ever resolve true (rare browser race), prefer the
   indeterminate glyph by hiding check when minus is shown. */
.lb-checkbox:indeterminate ~ .lb-checkbox__glyph--check[data-lb-icon]  { display: none; }
/* Disabled + checked / indeterminate — match the muted box appearance
   so the glyph doesn't pop while the surrounding chrome dims. */
.lb-checkbox:disabled ~ .lb-checkbox__glyph[data-lb-icon] { color: var(--lb-fg-disabled); }

.lb-checkbox__label { font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-fg-default); user-select: none; }

/* ═══════════════════════════════════════════════════════════
   RADIO
   ═══════════════════════════════════════════════════════════ */

.lb-radio-wrap { display: inline-flex; align-items: flex-start; gap: var(--lb-size-2x); cursor: pointer; }
.lb-radio-wrap--disabled { opacity: 0.5; cursor: not-allowed; }
.lb-radio { appearance: none; -webkit-appearance: none; width: 1.25rem; height: 1.25rem; flex-shrink: 0; margin-top: 0.1em; border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: 50%; background: var(--lb-field-bg-default); cursor: pointer; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); position: relative; }
.lb-radio:checked { border-color: var(--lb-action-border-primary-default); border-width: 0.375rem; background: var(--lb-field-bg-default); }
.lb-radio:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-radio:disabled { cursor: not-allowed; }
.lb-radio__label { font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-fg-default); user-select: none; }
.lb-radio-group { display: flex; flex-direction: column; gap: var(--lb-size-2x); }
.lb-radio-group--horizontal { flex-direction: row; flex-wrap: wrap; gap: var(--lb-size-4x); }

/* ═══════════════════════════════════════════════════════════
   SWITCH
   ═══════════════════════════════════════════════════════════ */

.lb-switch-wrap { display: inline-flex; align-items: center; gap: var(--lb-size-2x); cursor: pointer; }
.lb-switch-wrap--disabled { opacity: 0.5; cursor: not-allowed; }
/* box-sizing: content-box pins the track's inner dimensions (36×20px)
   regardless of border width. The thumb's absolute top/left positions
   are measured from the padding-box, so as the Action stroke knob
   thickens the border, the thumb stays centered in the track instead
   of appearing pushed down/right (previous symptom with border-box). */
.lb-switch { appearance: none; -webkit-appearance: none; position: relative; box-sizing: content-box; width: 2.25rem; height: 1.25rem; flex-shrink: 0; border-radius: 9999px; background: var(--lb-bg-bolder); border: var(--lb-border-width-action) solid var(--lb-border-muted); cursor: pointer; transition: background var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
/* Thumb is vertically centered via top:50%/translateY(-50%) so it stays
   middle-aligned regardless of track height. Horizontal position:
   translateX(0) off-state (left edge + 2px padding), translateX(1rem)
   on-state (snaps to right edge). Both transforms compose. */
.lb-switch::after { content: ''; position: absolute; top: 50%; left: 0.125rem; width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); border-radius: 50%; background: var(--lb-fg-default); box-shadow: var(--lb-shadow-1); transform: translate(0, -50%); transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui), background var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-switch:checked { background: var(--lb-action-bg-primary-default); border-color: var(--lb-action-border-primary-default); }
.lb-switch:checked::after { transform: translate(1rem, -50%); background: var(--lb-action-fg-primary-default); }
.lb-switch:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-switch:disabled { cursor: not-allowed; }
.lb-switch__label { font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-fg-default); user-select: none; }

/* ═══════════════════════════════════════════════════════════
   ACCORDION
   ═══════════════════════════════════════════════════════════ */

/* No outer border/radius — accordions sit cleanly among other components.
   Each item owns a top and bottom divider. Extra bottom space on expanded
   items creates visual breathing room between content and the next row. */
.lb-accordion { font-family: var(--lb-t-action-l-font-family); }
/* Accordion item dividers use the Action stroke width — triggers are
   interactive, so the line follows the same thickness the editor sets
   for buttons/inputs. Routes through border.default (Track B / surface)
   for clear rhythm between items; was border.muted but the lines were
   barely visible. */
.lb-accordion__item { border-bottom: var(--lb-border-width-action) solid var(--lb-border-default); }
.lb-accordion__item:first-child { border-top: var(--lb-border-width-action) solid var(--lb-border-default); }

.lb-accordion__trigger {
  /* Closed accordion item height = 40px (matches button medium height).
     action-l line-height (~24px) + 8px top/bottom padding = 40px total.
     Gap is 12px (3x) — comfortable separation between icon and label
     without feeling disconnected. The right cluster (badges + chevron)
     sits in .lb-accordion__indicators which has its own tight 8px gap. */
  width: 100%;
  min-height: 2.5rem;
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-2x) 0;
  background: transparent;
  border: none;
  cursor: pointer;
  font-family: var(--lb-t-action-l-font-family);
  font-size: var(--lb-t-action-l-font-size);
  font-weight: var(--lb-t-action-l-font-weight);
  line-height: var(--lb-t-action-l-line-height);
  letter-spacing: var(--lb-t-action-l-letter-spacing);
  color: var(--lb-fg-default); /* neutral trigger — expanded state is signalled by the chevron only */
  text-align: left;
  transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-accordion__trigger:hover:not(:disabled) { color: var(--lb-fg-default); }
.lb-accordion__trigger:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-interactive); }
.lb-accordion__trigger:disabled { color: var(--lb-fg-disabled); cursor: not-allowed; }
.lb-accordion__trigger-label { flex: 1; }

/* Optional leading icon slot — sits before the label, inherits color
   from the trigger so disabled/hover states flow through. */
.lb-accordion__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  color: currentColor;
}
.lb-accordion__icon svg { width: 100%; height: 100%; }

/* Right-side cluster: optional badge + chevron, grouped with tighter gap */
.lb-accordion__indicators { display: inline-flex; align-items: center; gap: var(--lb-size-2x); flex-shrink: 0; }

.lb-accordion__chevron { display: inline-flex; flex-shrink: 0; color: var(--lb-fg-muted); transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-accordion__chevron--open { transform: rotate(180deg); }

.lb-accordion__panel { overflow: hidden; }
/* [hidden] handled by global rule near top of file */
/* Panel content: no side padding so text aligns with trigger label;
   generous bottom padding for breathing room when expanded. */
.lb-accordion__panel-inner { padding: 0 0 var(--lb-size-8x); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); line-height: var(--lb-t-body-m-line-height); color: var(--lb-fg-muted); }

/* ═══════════════════════════════════════════════════════════
   TABS
   ═══════════════════════════════════════════════════════════ */

.lb-tabs { display: flex; flex-direction: column; }
.lb-tab-list { display: flex; gap: 0; }
.lb-tab { display: inline-flex; align-items: center; gap: var(--lb-size-2x); background: none; border: none; border-bottom: var(--lb-border-width-medium) solid transparent; padding: var(--lb-size-2x) var(--lb-size-3x); font-family: var(--lb-t-action-m-font-family); font-size: var(--lb-t-action-m-font-size); font-weight: var(--lb-t-action-m-font-weight); line-height: var(--lb-t-action-m-line-height); letter-spacing: var(--lb-t-action-m-letter-spacing); color: var(--lb-fg-default); /* neutral idle — accent reserved for selected (d442ece rationale) */ cursor: pointer; white-space: nowrap; transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-tab:hover:not([aria-selected="true"]) { color: var(--lb-fg-default); }
.lb-tab[aria-selected="true"] { color: var(--lb-action-fg-selected); border-bottom-color: var(--lb-action-border-selected); }
.lb-tab:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); border-radius: var(--lb-radius-interactive) var(--lb-radius-interactive) 0 0; }
.lb-tab:disabled { opacity: 0.4; cursor: not-allowed; }

/* Icon slot — 24px, inherits tab color */
.lb-tab__icon { display: inline-flex; align-items: center; justify-content: center; width: var(--lb-size-6x); height: var(--lb-size-6x); flex-shrink: 0; color: inherit; }
.lb-tab__icon svg { width: 100%; height: 100%; }

/* Count badge: tabs use the shared .lb-counter component — see Counter
   section. Same color whether selected or not; the underline is the
   single indicator of which tab is active. */

/* Notification dot — same signal as badge but no number */
.lb-tab__dot { display: inline-block; width: var(--lb-size-1-5x); height: var(--lb-size-1-5x); border-radius: 50%; background: var(--lb-fg-accent); flex-shrink: 0; }

.lb-tab-panel { padding: var(--lb-size-4x) 0; }
.lb-tab-panel:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }

/* ═══════════════════════════════════════════════════════════
   MODAL
   ═══════════════════════════════════════════════════════════ */

.lb-modal-backdrop { position: fixed; inset: 0; background: color-mix(in srgb, var(--lb-surface-bg-backdrop) 50%, transparent); display: flex; align-items: center; justify-content: center; z-index: 10000; padding: var(--lb-size-4x); }
.lb-modal { background: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-modal); display: flex; flex-direction: column; width: 100%; max-height: calc(100vh - var(--lb-size-16x)); overflow: hidden; }
.lb-modal--small  { max-width: 24rem; /* design-intent: modal small max-width */ }
.lb-modal--medium { max-width: 36rem; /* design-intent: modal medium max-width */ }
.lb-modal--large  { max-width: 52rem; /* design-intent: modal large max-width */ }
.lb-modal__header { display: flex; align-items: center; justify-content: space-between; padding: var(--lb-size-4x) var(--lb-size-6x); border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); gap: var(--lb-size-3x); }
.lb-modal__header-title { display: flex; align-items: center; gap: var(--lb-size-2x); flex: 1; min-width: 0; }
.lb-modal__title { font-family: var(--lb-t-heading-m-font-family); font-size: var(--lb-t-heading-m-font-size); font-weight: var(--lb-t-heading-m-font-weight); line-height: var(--lb-t-heading-m-line-height); letter-spacing: var(--lb-t-heading-m-letter-spacing); color: var(--lb-fg-default); margin: 0; }
.lb-modal--alert .lb-modal__alert-icon { display: flex; align-items: center; flex-shrink: 0; color: var(--lb-fg-danger); }
.lb-modal--alert .lb-modal__title { color: var(--lb-fg-danger); }
.lb-modal__close { background: none; border: none; cursor: pointer; padding: var(--lb-size-1x); color: var(--lb-fg-muted); display: flex; align-items: center; border-radius: var(--lb-radius-interactive); flex-shrink: 0; }
.lb-modal__close:hover { color: var(--lb-fg-default); background: var(--lb-action-bg-ghost-hover); }
.lb-modal__close:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-modal__body { padding: var(--lb-size-6x); overflow-y: auto; flex: 1; color: var(--lb-fg-default); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); }
.lb-modal__footer { padding: var(--lb-size-4x) var(--lb-size-6x); border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); display: flex; justify-content: flex-end; gap: var(--lb-size-2x); font-family: var(--lb-t-body-m-font-family); }

/* ═══════════════════════════════════════════════════════════
   SHEET
   ═══════════════════════════════════════════════════════════ */

.lb-sheet-root { position: fixed; inset: 0; z-index: 200; display: flex; }
.lb-sheet-overlay { position: fixed; inset: 0; background: rgba(0, 0, 0, 0.4); animation: lb-sheet-overlay-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
@keyframes lb-sheet-overlay-in { from { opacity: 0; } to { opacity: 1; } }
.lb-sheet { position: fixed; background: var(--lb-surface-bg-overlay); display: flex; flex-direction: column; font-family: var(--lb-t-body-m-font-family); z-index: 201; overflow: hidden; }
.lb-sheet--right { top: 0; right: 0; bottom: 0; width: 400px; /* design-intent: side-sheet default width */ border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); animation: lb-sheet-right-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-sheet--left { top: 0; left: 0; bottom: 0; width: 400px; /* design-intent: side-sheet default width */ border-right: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); animation: lb-sheet-left-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-sheet--bottom { left: 0; right: 0; bottom: 0; height: 50vh; /* design-intent: bottom-sheet half-viewport drawer */ border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay) var(--lb-radius-overlay) 0 0; animation: lb-sheet-bottom-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-sheet--top { left: 0; right: 0; top: 0; height: 50vh; /* design-intent: top-sheet half-viewport drawer */ border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: 0 0 var(--lb-radius-overlay) var(--lb-radius-overlay); animation: lb-sheet-top-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
@keyframes lb-sheet-right-in  { from { transform: translateX(100%); } to { transform: translateX(0); } }
@keyframes lb-sheet-left-in   { from { transform: translateX(-100%); } to { transform: translateX(0); } }
@keyframes lb-sheet-bottom-in { from { transform: translateY(100%); } to { transform: translateY(0); } }
@keyframes lb-sheet-top-in    { from { transform: translateY(-100%); } to { transform: translateY(0); } }
.lb-sheet__header { display: flex; align-items: center; justify-content: space-between; padding: var(--lb-size-4x) var(--lb-size-4x) var(--lb-size-3x); border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); flex-shrink: 0; }
.lb-sheet__title { margin: 0; font-family: var(--lb-t-heading-s-font-family); font-size: var(--lb-t-heading-s-font-size); font-weight: var(--lb-t-heading-s-font-weight); line-height: var(--lb-t-heading-s-line-height); letter-spacing: var(--lb-t-heading-s-letter-spacing); color: var(--lb-fg-default); }
.lb-sheet__close { display: flex; align-items: center; justify-content: center; width: var(--lb-size-8x); height: var(--lb-size-8x); padding: 0; background: none; border: none; border-radius: var(--lb-radius-interactive); color: var(--lb-fg-muted); cursor: pointer; transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); margin-left: auto; }
.lb-sheet__close:hover { background: var(--lb-action-bg-ghost-hover); color: var(--lb-fg-default); }
.lb-sheet__close:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-sheet__body { flex: 1; overflow-y: auto; padding: var(--lb-size-4x); color: var(--lb-fg-muted); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); }

/* ═══════════════════════════════════════════════════════════
   DROPDOWN (Combobox)
   ═══════════════════════════════════════════════════════════ */

.lb-dropdown-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); }
.lb-dropdown-field__label { font-family: var(--lb-t-label-m-font-family); font-size: var(--lb-t-label-m-font-size); font-weight: var(--lb-t-label-m-font-weight); line-height: var(--lb-t-label-m-line-height); letter-spacing: var(--lb-t-label-m-letter-spacing); color: var(--lb-field-fg-label); }
.lb-dropdown-field__hint { font-family: var(--lb-t-body-xs-font-family); font-size: var(--lb-t-body-xs-font-size); line-height: var(--lb-t-body-xs-line-height); color: var(--lb-field-fg-hint); }
.lb-dropdown-field__hint--error,
.lb-dropdown-field__hint--success { display: flex; align-items: center; gap: var(--lb-size-1x); }
.lb-dropdown-field__hint--error   { color: var(--lb-field-fg-error); }
.lb-dropdown-field__hint--success { color: var(--lb-field-fg-success); }
.lb-dropdown-field__hint--error > [data-lb-icon],
.lb-dropdown-field__hint--success > [data-lb-icon] { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); flex-shrink: 0; }
.lb-dropdown-wrap { position: relative; display: flex; align-items: center; }
.lb-dropdown { width: 100%; font-family: var(--lb-t-body-m-font-family); color: var(--lb-field-fg-default); background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); outline: none; appearance: none; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); padding-right: 2rem; }
.lb-dropdown--small  { padding: var(--lb-size-1x) var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); line-height: var(--lb-t-body-s-line-height); }
.lb-dropdown--medium { padding: var(--lb-size-2x) var(--lb-size-3x); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); }
.lb-dropdown--large  { padding: var(--lb-size-3x) var(--lb-size-3x); font-size: var(--lb-t-body-l-font-size); line-height: var(--lb-t-body-l-line-height); }
.lb-dropdown::placeholder { color: var(--lb-field-fg-placeholder); }
.lb-dropdown:focus { border-color: var(--lb-field-border-focus); outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-dropdown--error { border-color: var(--lb-field-border-error); }
.lb-dropdown--error:focus { border-color: var(--lb-field-border-error); outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); outline-offset: var(--lb-size-0-5x); }
.lb-dropdown:disabled { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-dropdown-wrap__chevron { position: absolute; right: var(--lb-size-3x); color: var(--lb-fg-muted); pointer-events: none; display: flex; align-items: center; transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-dropdown-wrap__chevron--open { transform: rotate(180deg); }
/* × clear button — injected by LB.Dropdown when `clearable: true`.
   Sits between the input text and the chevron; hidden when input empty. */
.lb-dropdown-wrap__clear { position: absolute; right: calc(var(--lb-size-3x) + 1.25rem); display: flex; align-items: center; justify-content: center; width: 1.25rem; height: 1.25rem; padding: 0; border: none; background: transparent; border-radius: 999px; color: var(--lb-fg-muted); cursor: pointer; font-size: 1rem; line-height: 1; transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-dropdown-wrap__clear:hover { background: var(--lb-action-bg-ghost-hover); color: var(--lb-fg-default); }
.lb-dropdown--clearable { padding-right: calc(var(--lb-size-3x) + 2.75rem); }
.lb-dropdown-list { position: absolute; top: calc(100% + 4px); left: 0; right: 0; z-index: 100; list-style: none; margin: 0; padding: var(--lb-size-1x) 0; background: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-dropdown); max-height: 220px; overflow-y: auto; animation: lb-dropdown-list-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
@keyframes lb-dropdown-list-in { from { opacity: 0; transform: translateY(-4px); /* design-intent: dropdown drop-in offset */ } to { opacity: 1; transform: translateY(0); } }
.lb-dropdown-list__option { padding: var(--lb-size-2x) var(--lb-size-3x); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); color: var(--lb-fg-default); cursor: pointer; transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-dropdown-list__option--active { background: var(--lb-action-bg-ghost-hover); }
.lb-dropdown-list__option--disabled { color: var(--lb-fg-disabled); cursor: not-allowed; }

/* ═══════════════════════════════════════════════════════════
   MENU
   ═══════════════════════════════════════════════════════════ */

/* Menu = popup surface. Items are rendered with the shared .lb-list__*
   classes (item, separator, icon, label, hint, group-label) so they
   stay visually + keyboard-consistent with Dropdown, Multi-Select,
   Phone, Date Picker, Command Palette.

   Menu hover used to override the global with a milder tint, but the
   global is now strong enough that the override produced the same
   value — dropped to keep one source of truth. The danger override
   below remains because destructive actions still want the warmer
   tint instead of the neutral hover. */
.lb-menu .lb-list__item--danger:hover:not(.lb-list__item--disabled):not([aria-disabled="true"]) {
  background: var(--lb-bg-danger-subtle);
}

.lb-menu-wrapper { position: relative; display: inline-flex; }
.lb-menu__trigger { background: none; border: none; padding: 0; cursor: pointer; display: inline-flex; align-items: center; font-family: var(--lb-t-action-m-font-family); }
.lb-menu__trigger:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-4); }

/* Menu triggers ARE buttons (consumers use .lb-btn / .lb-icon-btn for
   the visual chassis), but a "this opens a menu" affordance shouldn't
   carry the same visual weight as a primary action button. Scoped
   overrides keep the visit calmer AND consistent across button
   variants (secondary, ghost, etc.):
     - Modest rounding (4px) so the hover fill reads as a chip
     - Same resting state regardless of variant — transparent bg +
       transparent border + default fg. The variant-specific bg and
       border at rest were what made hover transitions look different
       across the demos
     - Same hover bg (--lb-bg-bolder) — barely-there neutral tint
   Result: every menu trigger looks identical at rest and on hover,
   regardless of whether the consumer used --secondary or --ghost. */
.lb-menu__trigger.lb-btn,
.lb-menu__trigger.lb-icon-btn {
  border-radius: var(--lb-radius-4);
  background-color: transparent;
  border-color: transparent;
  color: var(--lb-fg-default);
}
.lb-menu__trigger.lb-btn:hover:not(:disabled),
.lb-menu__trigger.lb-icon-btn:hover:not(:disabled) {
  background-color: var(--lb-bg-bolder);
  border-color: transparent;
  color: var(--lb-fg-default);
}
/* Trailing chevron (the one that signals "this opens a menu") rotates
   180° while the menu is open. We set the transition on every chevron
   inside a menu trigger so the icon eases instead of snapping. */
.lb-menu__trigger [data-lb-icon="chevron-down"] {
  transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
}
.lb-menu__trigger[aria-expanded="true"] [data-lb-icon="chevron-down"] {
  transform: rotate(180deg);
}
.lb-menu { list-style: none; margin: 0; padding: var(--lb-size-1x) 0; background-color: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-dropdown); z-index: 1000; min-width: 12rem; }

/* Menu header — optional account/identity block at the top of a menu
   (avatar + name + email pattern, sign-out separator below). */
.lb-menu__header {
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-3x) var(--lb-size-4x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  margin-bottom: var(--lb-size-1x);
}
.lb-menu__header-text { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.lb-menu__header-name { font-weight: var(--lb-font-weight-semibold); color: var(--lb-fg-default); font-size: var(--lb-t-body-s-font-size); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.lb-menu__header-meta { font-size: var(--lb-t-caption-m-font-size); color: var(--lb-fg-muted); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Group label inside a menu — small uppercase header above a section. */
/* t-overline — consolidated onto the one uppercase micro-label voice
   (2026-08-05, owner-decided; was 11px + semibold + raw 0.05em). */
.lb-list__group-label {
  display: block;
  padding: var(--lb-size-2x) var(--lb-size-4x) var(--lb-size-1x);
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  color: var(--lb-fg-muted);
  text-transform: uppercase;
}

/* Checkbox + radio glyph slots for stateful menu items. The check is
   shown only when the item carries .lb-list__item--checked, otherwise
   the slot reserves space so labels stay aligned across mixed rows. */
.lb-list__check {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 1rem;
  height: 1rem;
  color: var(--lb-fg-accent);
  visibility: hidden;
}
.lb-list__check svg { width: 100%; height: 100%; }
.lb-list__item--checked .lb-list__check { visibility: visible; }

/* ═══════════════════════════════════════════════════════════
   POPOVER
   ═══════════════════════════════════════════════════════════ */

.lb-popover-host { position: relative; display: inline-flex; }
.lb-popover-trigger { display: inline-flex; cursor: pointer; }
.lb-popover { position: absolute; z-index: 100; min-width: 200px; max-width: 320px; background: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-dropdown); font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-default); animation: lb-popover-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
/* Fade-in only — don't animate transform. Position variants (--bottom, --top, etc.)
   set their own translate() for centering; animating transform here would override
   that centering during the 120ms animation, causing the popover to snap on open. */
@keyframes lb-popover-in { from { opacity: 0; } to { opacity: 1; } }
.lb-popover--bottom { top: calc(100% + 8px);    /* design-intent: popover gap from anchor */ left: 50%; transform: translateX(-50%); }
.lb-popover--top    { bottom: calc(100% + 8px); /* design-intent: popover gap from anchor */ left: 50%; transform: translateX(-50%); }
.lb-popover--right  { left: calc(100% + 8px);   /* design-intent: popover gap from anchor */ top: 50%; transform: translateY(-50%); }
.lb-popover--left   { right: calc(100% + 8px);  /* design-intent: popover gap from anchor */ top: 50%; transform: translateY(-50%); }
.lb-popover__header { padding: var(--lb-size-3x) var(--lb-size-3x) var(--lb-size-2x); font-weight: var(--lb-font-weight-medium); font-size: var(--lb-t-body-m-font-size); border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); }
.lb-popover__body { padding: var(--lb-size-3x); color: var(--lb-fg-muted); line-height: var(--lb-t-body-s-line-height); }

/* ═══════════════════════════════════════════════════════════
   TOOLTIP
   ═══════════════════════════════════════════════════════════ */

.lb-tooltip-wrap { position: relative; display: inline-flex; }

/* Tooltip surface — uses opacity + visibility for animation (display:none
   would cancel transitions). Small slide-in from the trigger gives the
   tooltip a directional feel; arrow caret renders via ::after. */
.lb-tooltip {
  position: absolute;
  z-index: 8000;
  padding: var(--lb-size-1x) var(--lb-size-2x);
  background: var(--lb-fg-default);
  color: var(--lb-fg-inverse);
  border-radius: var(--lb-radius-interactive);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-t-caption-m-font-weight);
  line-height: var(--lb-t-caption-m-line-height);
  pointer-events: none;
  box-shadow: var(--lb-shadow-tooltip);
  max-width: 15rem; /* design-intent: tooltip line-length cap */
  white-space: normal;
  text-align: center;
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), visibility 0s linear var(--lb-animation-dur-fast), transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-tooltip--open {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), visibility 0s, transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}

/* Reduced motion: tooltip appears/disappears instantly — no slide, no fade.
   (Placement transforms live on the --top/--bottom/... variants below and
   still apply; only the animation is suppressed.) */
@media (prefers-reduced-motion: reduce) {
  .lb-tooltip { transition: none; }
}

/* Small variant — tighter padding, useful for compact toolbars. */
.lb-tooltip--small {
  padding: var(--lb-size-0-5x) var(--lb-size-1-5x);
  font-size: var(--lb-font-size-2xs);
}

/* Arrow / caret — pure CSS triangle pointing at the trigger. Color
   matches the tooltip bg so it reads as one shape. The shape rotates
   based on position via CSS variables on the position modifier. */
.lb-tooltip::after {
  content: '';
  position: absolute;
  width: 0;
  height: 0;
  border-style: solid;
  border-color: transparent;
}

/* Top: tooltip above trigger, arrow points down */
.lb-tooltip--top {
  bottom: calc(100% + var(--lb-size-1-5x));
  left: 50%;
  transform: translateX(-50%) translateY(var(--lb-size-1x));
}
.lb-tooltip--top.lb-tooltip--open { transform: translateX(-50%) translateY(0); }
.lb-tooltip--top::after {
  top: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 6px 6px 0 6px; /* design-intent: triangle pseudo-border arrow */
  border-top-color: var(--lb-fg-default);
}

/* Bottom: tooltip below trigger, arrow points up */
.lb-tooltip--bottom {
  top: calc(100% + var(--lb-size-1-5x));
  left: 50%;
  transform: translateX(-50%) translateY(calc(-1 * var(--lb-size-1x)));
}
.lb-tooltip--bottom.lb-tooltip--open { transform: translateX(-50%) translateY(0); }
.lb-tooltip--bottom::after {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  border-width: 0 6px 6px 6px; /* design-intent: triangle pseudo-border arrow */
  border-bottom-color: var(--lb-fg-default);
}

/* Left: tooltip left of trigger, arrow points right */
.lb-tooltip--left {
  right: calc(100% + var(--lb-size-1-5x));
  top: 50%;
  transform: translateY(-50%) translateX(var(--lb-size-1x));
}
.lb-tooltip--left.lb-tooltip--open { transform: translateY(-50%) translateX(0); }
.lb-tooltip--left::after {
  left: 100%;
  top: 50%;
  transform: translateY(-50%);
  border-width: 6px 0 6px 6px; /* design-intent: triangle pseudo-border arrow */
  border-left-color: var(--lb-fg-default);
}

/* Right: tooltip right of trigger, arrow points left */
.lb-tooltip--right {
  left: calc(100% + var(--lb-size-1-5x));
  top: 50%;
  transform: translateY(-50%) translateX(calc(-1 * var(--lb-size-1x)));
}
.lb-tooltip--right.lb-tooltip--open { transform: translateY(-50%) translateX(0); }
.lb-tooltip--right::after {
  right: 100%;
  top: 50%;
  transform: translateY(-50%);
  border-width: 6px 6px 6px 0; /* design-intent: triangle pseudo-border arrow */
  border-right-color: var(--lb-fg-default);
}

/* Optional kbd-style shortcut shown inside a tooltip (e.g. "Save ⌘S"). */
.lb-tooltip__kbd {
  display: inline-block;
  margin-left: var(--lb-size-1x);
  padding: 0 var(--lb-size-1x);
  border-radius: var(--lb-radius-2);
  background: rgba(255, 255, 255, 0.15);
  font-family: var(--lb-t-code-s-font-family);
  font-size: var(--lb-t-code-s-font-size);
}

/* ═══════════════════════════════════════════════════════════
   SLIDER
   ═══════════════════════════════════════════════════════════ */

.lb-slider-field { display: flex; flex-direction: column; gap: var(--lb-size-2x); font-family: var(--lb-t-body-m-font-family); }
.lb-slider-field__header { display: flex; justify-content: space-between; align-items: center; }
.lb-slider-field__label { font-family: var(--lb-t-label-m-font-family); font-size: var(--lb-t-label-m-font-size); font-weight: var(--lb-t-label-m-font-weight); color: var(--lb-fg-default); }
.lb-slider-field__value { font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); font-variant-numeric: tabular-nums; }
.lb-slider-track-wrap { position: relative; display: flex; align-items: center; }
.lb-slider-track-wrap--medium { height: var(--lb-size-5x); }
.lb-slider-track-wrap--small  { height: var(--lb-size-4x); }
/* Slider track — thickness follows Action stroke (slider is interactive) */
.lb-slider-track { position: absolute; left: 0; right: 0; height: var(--lb-border-width-action); background: var(--lb-border-muted); border-radius: 9999px; overflow: hidden; pointer-events: none; }
.lb-slider-track__fill { height: 100%; background: var(--lb-bg-accent-value); border-radius: 9999px; transition: width 0ms; }
.lb-slider { -webkit-appearance: none; appearance: none; width: 100%; background: transparent; cursor: pointer; position: relative; margin: 0; padding: 0; }
/* Thumb: clean solid circle — no rings (owner call 2026-07-30: the thin
   outline read as noise). The 16px thumb pops off the hairline track by
   geometry alone; hit area stays the full input; focus keeps its ring. */
.lb-slider::-webkit-slider-thumb { -webkit-appearance: none; width: var(--lb-size-4x); height: var(--lb-size-4x); border-radius: 50%; background: var(--lb-bg-accent-value); border: none; cursor: pointer; transition: box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-slider::-moz-range-thumb { width: var(--lb-size-4x); height: var(--lb-size-4x); border-radius: 50%; background: var(--lb-bg-accent-value); border: none; cursor: pointer; transition: box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-slider::-webkit-slider-runnable-track { background: transparent; }
.lb-slider::-moz-range-track { background: transparent; }
.lb-slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 var(--lb-border-width-medium) var(--lb-border-focus); }
.lb-slider:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 var(--lb-border-width-medium) var(--lb-border-focus); }
.lb-slider:focus { outline: none; }
.lb-slider:disabled { cursor: not-allowed; }
.lb-slider:disabled::-webkit-slider-thumb { background: var(--lb-bg-disabled); border-color: var(--lb-border-disabled); box-shadow: none; }
.lb-slider:disabled::-moz-range-thumb { background: var(--lb-bg-disabled); border-color: var(--lb-border-disabled); box-shadow: none; }
.lb-slider:disabled ~ .lb-slider-track .lb-slider-track__fill { background: var(--lb-bg-disabled); }

/* ═══════════════════════════════════════════════════════════
   MEDIA PLAYER  (Slice 1 — audio core)
   Controls skin over a native <audio>/<video>. Colours use existing
   L2/L3 tokens only — no media-specific tokens (PLUGIN-HANDOFF 12).
   ═══════════════════════════════════════════════════════════ */

.lb-media { container-type: inline-size; display: flex; flex-direction: column; gap: var(--lb-size-3x); background: var(--lb-surface-bg-elevated); border: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated); border-radius: var(--lb-radius-overlay); padding: var(--lb-size-3x) var(--lb-size-4x); font-family: var(--lb-t-body-m-font-family); }
.lb-media--audio audio { display: none; } /* native chrome hidden; we drive it */

/* Optional now-playing block — cover art + title/artist. Opt-in: only
   rendered if the consumer includes the markup. */
.lb-media__now { display: flex; align-items: center; gap: var(--lb-size-4x); }
.lb-media__art { flex: none; width: 4rem; height: 4rem; border-radius: var(--lb-radius-interactive); object-fit: cover; background: var(--lb-bg-strong); }
.lb-media__meta { display: flex; flex-direction: column; gap: var(--lb-size-0-5x); min-width: 0; }
/* Right-aligned actions in the now-playing block (e.g. share + a menu of
   whole-playlist actions). meta keeps min-width:0 so the title can still
   truncate/marquee around the actions column. */
.lb-media__now-actions { display: flex; align-items: center; gap: var(--lb-size-1x); flex: none; margin-left: auto; }
.lb-media__now-actions .lb-menu-wrapper > ul.lb-menu { left: auto !important; right: 0 !important; }
.lb-media__title { display: block; max-width: 100%; overflow: hidden; }
.lb-media__title-text { font-family: var(--lb-t-label-l-font-family); font-size: var(--lb-t-label-l-font-size); font-weight: var(--lb-t-label-l-font-weight); color: var(--lb-fg-default); }

/* Reusable hover-reveal marquee — applied by LB.Media to the now-playing
   title AND every playlist row title (the player auto-wraps track titles,
   so consumers just write <span class="lb-media__track-title">Title</span>).
   Ellipsis-truncated at rest; on hover the inner slides left to reveal the
   overflow, then back on leave. JS (_measureMarquees) sets --lb-title-shift
   (negative px = overflow) + --lb-title-duration (a multiple of the 500ms
   token → longer titles scroll for longer = constant slow speed). Linear
   ease for steady motion. Triggers on hovering the title itself or its
   enclosing playlist row. */
.lb-media__marquee { overflow: hidden; }
.lb-media__marquee-text { display: block; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; transition: transform var(--lb-title-duration, var(--lb-duration-500)) var(--lb-ease-linear); }
/* Reveal (sliding out) and return (sliding back) BOTH keep the full text
   visible — overflow/text-overflow only revert to ellipsis once the text
   is home again (LB.Media removes --returning on transitionend), so the
   slide-back never shows a mid-animation ellipsis. JS drives these classes
   instead of :hover so the return can outlast the pointer leaving. */
.lb-media__marquee--revealing .lb-media__marquee-text,
.lb-media__marquee--returning .lb-media__marquee-text { overflow: visible; text-overflow: clip; }
.lb-media__marquee--revealing .lb-media__marquee-text { transform: translateX(var(--lb-title-shift, 0)); }
.lb-media__marquee--returning .lb-media__marquee-text { transform: translateX(0); }
@media (prefers-reduced-motion: reduce) { .lb-media__marquee-text { transition: none; } }
.lb-media__artist { font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); }

.lb-media__controls { display: flex; align-items: center; gap: var(--lb-size-2x); }

.lb-media__time { font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); font-variant-numeric: tabular-nums; min-width: var(--lb-size-12x); text-align: center; flex: none; }

/* Speed control — a small ghost pill showing the current rate ("1×"); the
   controller cycles the rate on click. Text, not an icon, so it sizes to
   fit "1.75×". */
.lb-media__speed { flex: none; display: inline-flex; align-items: center; justify-content: center; min-width: var(--lb-size-12x); height: var(--lb-size-8x); padding: 0 var(--lb-size-2x); border: none; border-radius: var(--lb-radius-interactive); background: var(--lb-action-bg-ghost-default); color: var(--lb-action-fg-ghost-default); font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); font-weight: var(--lb-t-label-m-font-weight); font-variant-numeric: tabular-nums; cursor: pointer; transition: background-color var(--lb-duration-100) var(--lb-ease-standard); }
.lb-media__speed:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-media__speed:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }

/* Minimal aesthetic for the audio / album / compact / card variants
   (NOT --video). Transparent at rest, faint ghost-hover on hover —
   mirrors the pattern the video variant already uses. Scoped to
   .lb-media so it doesn't affect any other .lb-icon-btn--ghost elsewhere
   in the DS. */
.lb-media:not(.lb-media--video) .lb-icon-btn--ghost,
.lb-media:not(.lb-media--video) .lb-media__speed { background-color: transparent; }
.lb-media:not(.lb-media--video) .lb-icon-btn--ghost:hover:not(:disabled):not([aria-disabled="true"]),
.lb-media:not(.lb-media--video) .lb-media__speed:hover { background-color: var(--lb-bg-bolder); }

/* Scrubber + volume share the same rail/fill structure. The native
   range input sits transparent on top for keyboard + drag; the visible
   rail/fill below is painted from the media events. */
.lb-media__scrubber { position: relative; flex: 1 1 auto; display: flex; align-items: center; height: var(--lb-size-5x); min-width: var(--lb-size-16x); }
.lb-media__volume   { position: relative; flex: none; width: var(--lb-size-24x); display: flex; align-items: center; height: var(--lb-size-5x); }

.lb-media__rail { position: absolute; left: 0; right: 0; height: var(--lb-border-width-action); background: var(--lb-border-muted); border-radius: var(--lb-radius-full); overflow: hidden; pointer-events: none; }
.lb-media__buffered { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: var(--lb-bg-bolder); border-radius: var(--lb-radius-full); }
.lb-media__fill { position: absolute; left: 0; top: 0; height: 100%; width: 0; background: var(--lb-bg-accent-value); border-radius: var(--lb-radius-full); }

/* Full-height, top-layer hit area: without an explicit height the range
   box collapses toward the thumb, so clicks on the bar's top/bottom miss
   the input and land on the pointer-events:none rail (= nothing happens,
   "can't slide"). height:100% + z-index makes the whole bar click+drag. */
.lb-media__range { -webkit-appearance: none; appearance: none; position: relative; z-index: 1; width: 100%; height: 100%; background: transparent; cursor: pointer; margin: 0; padding: 0; }
/* Thumb: clean solid circle — matches .lb-slider (rings removed 2026-07-30). */
.lb-media__range::-webkit-slider-thumb { -webkit-appearance: none; width: var(--lb-size-4x); height: var(--lb-size-4x); border-radius: var(--lb-radius-full); background: var(--lb-bg-accent-value); border: none; cursor: pointer; transition: box-shadow var(--lb-duration-100) var(--lb-ease-standard); }
.lb-media__range::-moz-range-thumb { width: var(--lb-size-4x); height: var(--lb-size-4x); border-radius: var(--lb-radius-full); background: var(--lb-bg-accent-value); border: none; cursor: pointer; transition: box-shadow var(--lb-duration-100) var(--lb-ease-standard); }
.lb-media__range::-webkit-slider-runnable-track { background: transparent; }
.lb-media__range::-moz-range-track { background: transparent; }
.lb-media__range:focus { outline: none; }
.lb-media__range:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 var(--lb-border-width-medium) var(--lb-border-focus); }
.lb-media__range:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 var(--lb-border-width-medium) var(--lb-border-focus); }

/* Narrow players (compact / mobile): the transport row can't fit inline,
   so the scrubber takes its own full-width line above the buttons + time
   labels. Container query → automatic for any player narrower than 320px,
   no demo-specific markup. */
@container (max-width: 320px) {
  .lb-media__controls { flex-wrap: wrap; }
  .lb-media__scrubber { order: -1; flex: 1 1 100%; }
}

/* Touch-target sizing — when the primary pointer is coarse (touch screens,
   not desktop or hybrid laptops), bump the player's medium icon-buttons
   from size-10x (40px) to size-12x (48px) so the transport controls clear
   the WCAG 2.1 AAA 44×44 touch target (we don't have a size-11x token, so
   12x is the closest available — never invent a new token). Scoped to
   .lb-media so the rest of the DS keeps the standard medium sizing. The
   icon glyph itself stays 1.5rem to avoid bloating the visual without
   reason — only the hit area grows. */
@media (pointer: coarse) {
  .lb-media .lb-icon-btn--medium { width: var(--lb-size-12x); height: var(--lb-size-12x); }
}

/* Card / now-playing layout — apply .lb-media--card. Large cover on top,
   centred title + artist, scrubber spanning a row, then current time
   (left) · play (centre) · total time (right). Same markup + controls as
   any player; only the arrangement changes (via order + flex). */
.lb-media--card { text-align: center; }
.lb-media--card .lb-media__now { flex-direction: column; align-items: center; text-align: center; gap: var(--lb-size-3x); }
.lb-media--card .lb-media__art { width: 100%; max-width: 220px; /* design-intent: media card art square cap */ height: auto; aspect-ratio: 1 / 1; }
/* Art ratio modifiers on the root — same ratio set as .lb-card__media--*
   (16:9 | 4:3 | 1:1 | 3:4). Square (default) and portrait keep the focal
   220px cap; landscape art reads as a banner/thumb and spans the card
   width, matching how card media behaves. */
.lb-media--card.lb-media--art-16x9 .lb-media__art { aspect-ratio: 16 / 9; max-width: 100%; }
.lb-media--card.lb-media--art-4x3 .lb-media__art { aspect-ratio: 4 / 3; max-width: 100%; }
.lb-media--card.lb-media--art-1x1 .lb-media__art { aspect-ratio: 1 / 1; }
.lb-media--card.lb-media--art-3x4 .lb-media__art { aspect-ratio: 3 / 4; }
.lb-media--card .lb-media__meta { align-items: center; max-width: 100%; }
/* Two-row controls in the card layout, wired via sub-row wrappers in the
   markup (.lb-media__progress-row and .lb-media__transport-row). Row 1:
   current · scrubber · duration inline. Row 2: prev · play · next,
   centred. Sub-rows are only used in --card so the inline player markup
   stays unchanged. */
.lb-media--card .lb-media__controls { flex-direction: column; row-gap: var(--lb-size-3x); align-items: stretch; }
.lb-media--card .lb-media__progress-row { display: flex; align-items: center; gap: var(--lb-size-2x); }
/* order:0 explicitly undoes the narrow-player container query (line ~2808)
   which sets scrubber order:-1 so the scrubber stacks above the times in
   single-row layouts. The card's progress-row IS the dedicated single
   row, so we want DOM order: [current time] [scrubber] [total time]. */
.lb-media--card .lb-media__progress-row .lb-media__scrubber { flex: 1 1 auto; order: 0; }
.lb-media--card .lb-media__progress-row .lb-media__time { flex: none; }
.lb-media--card .lb-media__transport-row { display: flex; align-items: center; justify-content: center; gap: var(--lb-size-2x); }
/* Top-right actions float in the card's corner; same .lb-media__now-actions
   class as the album, but here positioned absolute so it doesn't push the
   centred cover/meta around. The cluster lands ON the artwork at narrow
   card widths (always, on landscape art ratios), so it carries the system
   scrim-pill treatment — same recipe as --compact art-play and the video
   scrims: translucent bg-overlay pill, inverse-strong icons. */
.lb-media--card .lb-media__now-actions { position: absolute; top: var(--lb-size-2x); right: var(--lb-size-2x); margin: 0; z-index: 3; padding: var(--lb-size-0-5x); border-radius: var(--lb-radius-full); background: color-mix(in srgb, var(--lb-bg-overlay) 55%, transparent); }
.lb-media--card .lb-media__now-actions .lb-icon-btn { color: var(--lb-fg-inverse-strong); background: transparent; border-color: transparent; }
.lb-media--card .lb-media__now-actions .lb-icon-btn:hover { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 20%, transparent); }
.lb-media--card .lb-media__now-actions .lb-menu-wrapper > ul.lb-menu { left: auto !important; right: 0 !important; }

/* Compact layout — apply .lb-media--compact. Play button overlays the
   cover; the transport row is a single line: current · scrubber · total.
   The play button can live anywhere in the player (the controller finds
   it by data attribute), so here it sits inside the cover wrapper. */
.lb-media--compact .lb-media__art-wrap { position: relative; flex: none; line-height: 0; }
.lb-media--compact .lb-media__art-play { position: absolute; inset: 0; margin: auto; width: var(--lb-size-8x); height: var(--lb-size-8x); border: none; border-radius: var(--lb-radius-full); background: color-mix(in srgb, var(--lb-bg-overlay) 55%, transparent); color: var(--lb-fg-inverse-strong); }
.lb-media--compact .lb-media__art-play:hover { background: color-mix(in srgb, var(--lb-bg-overlay) 72%, transparent); }
.lb-media--compact .lb-media__art-play > [data-lb-icon] { width: var(--lb-size-5x); height: var(--lb-size-5x); }
/* single-line transport — override the narrow-width reflow so the times
   stay flanking the scrubber on one row */
.lb-media--compact .lb-media__controls { flex-wrap: nowrap; }
.lb-media--compact .lb-media__scrubber { order: 0; flex: 1 1 auto; }

/* Video layout — auto-applied when the player wraps a <video>. The video
   fills the frame; controls overlay the bottom over a scrim gradient and
   render light (inverse) so they read on any footage. Auto-hide while
   playing (LB.Media toggles --idle). */
.lb-media--video { position: relative; padding: 0; overflow: hidden; }
/* Stage = positioning context for the video + overlay controls. Wrapping
   video + top + controls in .lb-media__stage makes the absolute controls
   overlay JUST the video, even when other content (a playlist) sits below
   it inside the same .lb-media--video. Dark backdrop lives here (not on
   the outer .lb-media--video) so the playlist sits on the normal surface
   bg, matching the music player's playlist. */
.lb-media--video .lb-media__stage { position: relative; overflow: hidden; background: var(--lb-bg-overlay); }
.lb-media--video video { display: block; width: 100%; height: auto; }
.lb-media--video .lb-media__controls { position: absolute; left: 0; right: 0; bottom: 0; padding: var(--lb-size-6x) var(--lb-size-3x) var(--lb-size-3x); background: linear-gradient(to top, color-mix(in srgb, var(--lb-bg-overlay) 88%, transparent), transparent); transition: opacity var(--lb-duration-300) var(--lb-ease-standard); }
/* Top bar — mirrors the bottom scrim. Two slots: left (like/dislike) and
   right (speed, share, more). Children must explicitly opt into pointer
   events so the underlying video can still be clicked through the gaps. */
.lb-media--video .lb-media__top { position: absolute; left: 0; right: 0; top: 0; padding: var(--lb-size-3x) var(--lb-size-3x) var(--lb-size-6x); display: flex; justify-content: space-between; align-items: center; gap: var(--lb-size-2x); background: linear-gradient(to bottom, color-mix(in srgb, var(--lb-bg-overlay) 80%, transparent), transparent); transition: opacity var(--lb-duration-300) var(--lb-ease-standard); pointer-events: none; }
.lb-media--video .lb-media__top > * { pointer-events: auto; }
.lb-media__top-left, .lb-media__top-right { display: flex; align-items: center; gap: var(--lb-size-1x); }
/* Active reaction (like / dislike) — accent the icon. */
.lb-media--video [data-lb-media-like][aria-pressed="true"],
.lb-media--video [data-lb-media-dislike][aria-pressed="true"] { color: var(--lb-fg-accent); }
/* Active captions toggle */
.lb-media--video [data-lb-media-captions][aria-pressed="true"] { color: var(--lb-fg-accent); }
/* Half-width sound slider — more room for the video timeline. */
.lb-media--video .lb-media__volume { width: var(--lb-size-12x); }
/* Top-right menu anchors from the right (LB.Menu inline-sets left:0;
   !important is the cleanest scoped override) so the panel grows
   right-to-left and stays inside the player container. */
.lb-media__top-right .lb-menu-wrapper > ul.lb-menu { left: auto !important; right: 0 !important; }
/* Skip feedback badges shown while holding the left/right half. The
   badge fades in with the --rewinding / --ffwding class on the player
   and the accumulating "X0s" updates on each step. */
.lb-media__skip-fb { position: absolute; top: 50%; transform: translateY(-50%); display: flex; align-items: center; gap: var(--lb-size-1x); padding: var(--lb-size-2x) var(--lb-size-3x); border-radius: var(--lb-radius-full); background: color-mix(in srgb, var(--lb-bg-overlay) 75%, transparent); color: var(--lb-fg-inverse-strong); font-family: var(--lb-t-label-m-font-family); font-weight: var(--lb-t-label-m-font-weight); opacity: 0; pointer-events: none; transition: opacity var(--lb-duration-150) var(--lb-ease-standard); z-index: 2; }
.lb-media__skip-fb--left  { left:  var(--lb-size-4x); }
.lb-media__skip-fb--right { right: var(--lb-size-4x); }
.lb-media__skip-fb-icon { width: var(--lb-size-5x); height: var(--lb-size-5x); display: inline-flex; }
.lb-media__skip-fb-icon svg { width: 100%; height: 100%; }
.lb-media--rewinding .lb-media__skip-fb--left,
.lb-media--ffwding   .lb-media__skip-fb--right { opacity: 1; }
/* light controls over the scrim */
.lb-media--video .lb-icon-btn { color: var(--lb-fg-inverse-strong); background: transparent; border-color: transparent; }
.lb-media--video .lb-icon-btn:hover { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 20%, transparent); }
.lb-media--video .lb-media__time { color: var(--lb-fg-inverse-strong); }
.lb-media--video .lb-media__speed { color: var(--lb-fg-inverse-strong); background: color-mix(in srgb, var(--lb-fg-inverse-strong) 16%, transparent); }
.lb-media--video .lb-media__speed:hover { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 28%, transparent); }
.lb-media--video .lb-media__rail { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 30%, transparent); }
.lb-media--video .lb-media__buffered { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 45%, transparent); }
/* idle: hide controls + top bar + cursor during playback */
.lb-media--video.lb-media--idle { cursor: none; }
.lb-media--video.lb-media--idle .lb-media__controls,
.lb-media--video.lb-media--idle .lb-media__top { opacity: 0; pointer-events: none; }
/* Native subtitle cue styling — light text on a translucent dark pill
   so it reads on any footage. Uses existing tokens via color-mix. */
.lb-media--video video::cue { background: color-mix(in srgb, var(--lb-bg-overlay) 75%, transparent); color: var(--lb-fg-inverse-strong); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); }
/* fullscreen: scale the video to fill the viewport, preserving aspect
   ratio (letterbox when needed). Player covers viewport; video uses
   object-fit:contain. bg inherits --lb-bg-overlay from .lb-media--video. */
.lb-media--video.lb-media--fullscreen,
.lb-media--video:fullscreen { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; }
.lb-media--video.lb-media--fullscreen .lb-media__stage,
.lb-media--video:fullscreen .lb-media__stage { width: 100%; height: 100%; flex: 1; min-height: 0; }
.lb-media--video.lb-media--fullscreen video,
.lb-media--video:fullscreen video { width: 100%; height: 100%; max-width: none; max-height: none; object-fit: contain; }

/* Fullscreen playlist — a floating full-height rounded panel on the
   right with its own header (title + close), toggled by
   [data-lb-media-playlist-toggle] (button shown only in fullscreen).
   lb-media.js moves the playlist <ul> into the panel on fullscreen
   entry and back on exit. Always-light inverse-strong text (dark
   stage in both themes). */
.lb-media__playlist-toggle { display: none; }
.lb-media--fullscreen .lb-media__playlist-toggle,
.lb-media--video:fullscreen .lb-media__playlist-toggle { display: inline-flex; }
/* Any playlist still in the normal flow is hidden while fullscreen. */
.lb-media--video.lb-media--fullscreen > .lb-media__playlist,
.lb-media--video:fullscreen > .lb-media__playlist { display: none; }

.lb-media__playlist-panel {
  display: none;
  position: absolute;
  top: var(--lb-size-4x);
  right: var(--lb-size-4x);
  bottom: var(--lb-size-4x);
  width: min(24rem, 85vw); /* design-intent: fullscreen playlist panel */
  z-index: 6;
  flex-direction: column;
  overflow: hidden;
  border-radius: var(--lb-radius-overlay);
  border: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-fg-inverse-strong) 18%, transparent);
  background: color-mix(in srgb, var(--lb-bg-overlay) 92%, transparent);
  box-shadow: var(--lb-shadow-modal);
}
.lb-media--playlist-open .lb-media__playlist-panel { display: flex; }
.lb-media__playlist-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x) var(--lb-size-4x);
  border-bottom: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-fg-inverse-strong) 15%, transparent);
  color: var(--lb-fg-inverse-strong);
  font-family: var(--lb-t-label-m-font-family);
  font-size: var(--lb-t-label-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
}
.lb-media__playlist-panel .lb-media__playlist {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  margin: 0;
  padding: var(--lb-size-2x);
  border-top: none;
}
.lb-media__playlist-panel .lb-media__track { color: var(--lb-fg-inverse-strong); }
.lb-media__playlist-panel .lb-media__track:hover:not(.lb-media__track--active) { background: color-mix(in srgb, var(--lb-fg-inverse-strong) 15%, transparent); }

/* Playlist (optional variant) — a [data-lb-media-playlist] list of
   click-to-play tracks. Reuses ghost-hover + accent-muted tokens so it
   reads like the List/Menu primitives without forking them. */
.lb-media__playlist { list-style: none; margin: 0; padding: var(--lb-size-2x) 0 0; display: flex; flex-direction: column; gap: var(--lb-size-0-5x); border-top: var(--lb-border-width-thin) solid var(--lb-border-muted); }
.lb-media__track { display: flex; align-items: center; gap: var(--lb-size-3x); width: 100%; text-align: left; padding: var(--lb-size-2x) var(--lb-size-3x); border: none; background: transparent; border-radius: var(--lb-radius-interactive); color: var(--lb-fg-default); font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); line-height: var(--lb-t-body-m-line-height); cursor: pointer; transition: background-color var(--lb-duration-100) var(--lb-ease-standard), color var(--lb-duration-100) var(--lb-ease-standard), padding-left var(--lb-duration-100) var(--lb-ease-standard); }
/* Hover on the LI (not the button) so the row stays highlighted while the
   pointer moves onto the absolutely-positioned action buttons (share /
   favourite / more) sitting on top of the row. The :not(--active) guard
   keeps the active-row's accent background winning over hover. */
.lb-media__playlist > li:hover .lb-media__track:not(.lb-media__track--active) { background: var(--lb-bg-bolder); }
.lb-media__track:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-border-width-medium)); }
.lb-media__track--active { background: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); }
.lb-media__track-index { font-variant-numeric: tabular-nums; color: var(--lb-fg-muted); min-width: 1.5rem; text-align: center; }
.lb-media__track--active .lb-media__track-index { color: var(--lb-action-fg-selected); }
.lb-media__track-title { flex: 1 1 auto; min-width: 0; }
.lb-media__track-dur { font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); font-variant-numeric: tabular-nums; flex: none; transition: opacity var(--lb-duration-100) var(--lb-ease-standard); }

/* Per-row hover actions — opt-in: add a .lb-media__track-actions sibling
   to the track button inside the <li>. Quick action icon-btns + a
   .lb-menu-wrapper (data-lb-menu) for overflow ("…"). Duration fades out
   on row hover/focus and the actions fade in to take its place. */
.lb-media__playlist > li { position: relative; }
/* Pinned to the track-row height (var(--lb-size-10x) = 40px = the icon-btn
   medium token, which matches the track button's natural height). Stays
   on the row even when the <li> grows due to the expanded inline menu —
   if we anchored to the li's centre, the actions would migrate down into
   the panel area. */
.lb-media__track-actions { position: absolute; right: var(--lb-size-3x); top: 0; height: var(--lb-size-10x); display: flex; align-items: center; gap: var(--lb-size-0-5x); opacity: 0; pointer-events: none; transition: opacity var(--lb-duration-100) var(--lb-ease-standard); }
.lb-media__playlist > li:hover .lb-media__track-actions,
.lb-media__playlist > li:focus-within .lb-media__track-actions { opacity: 1; pointer-events: auto; }
/* Duration only fades when there are per-row actions to take its place
   (scoped via :has() so rows without actions — e.g. the compact demo
   playlist — keep their duration visible on hover). */
.lb-media__playlist > li:has(.lb-media__track-actions):hover .lb-media__track-dur,
.lb-media__playlist > li:has(.lb-media__track-actions):focus-within .lb-media__track-dur { opacity: 0; }
/* Lift the row whose menu is open above sibling rows (otherwise later
   rows' content paints above the open dropdown panel). */
.lb-media__playlist > li:focus-within { z-index: 5; }
.lb-media__track-actions .lb-menu { z-index: 10; }
/* Per-row menu opens right-anchored so it doesn't overflow the player. */
.lb-media__track-actions .lb-menu-wrapper > ul.lb-menu { left: auto !important; right: 0 !important; }
/* Optional scrollable playlist — opt-in via .lb-media__playlist--scroll.
   max-height = ~4.5 rows of 40px so longer lists show the scrollbar and
   the user sees there's more to scroll. */
.lb-media__playlist--scroll { max-height: 11.5rem; /* design-intent: media playlist scroll cap */ overflow-y: auto; }
/* Drag-to-reorder handle — injected by LB.Media on the left of each row
   when the playlist has data-lb-media-playlist-reorderable. Faint at rest,
   bright on row hover, grabs on hover. The whole row is draggable (so
   click-to-play still works) but a drag is only allowed when started from
   the handle. */
/* Larger hit area than the icon itself — easier to grab. The icon stays
   1rem; the surrounding pad makes a 2rem × 2rem clickable target on top
   of the row's left edge. */
/* Compact, edge-aligned grip — small icon hugging the left edge. At rest
   the grip is invisible AND pointer-events: none so clicks pass through
   to the row beneath. On row hover it fades in and becomes grabbable;
   the row's track simultaneously slides right (padding-left transition)
   to reveal the grip — no empty space at rest. */
/* Pinned to the track-row height (--lb-size-10x = 40px = the icon-btn
   medium token), same reason as .lb-media__track-actions: with
   height:100% the handle would stretch through the expanded inline
   menu and the icon would migrate down out of the row. */
.lb-media__track-drag { position: absolute; left: 0; top: 0; width: var(--lb-size-6x); height: var(--lb-size-10x); display: flex; align-items: center; justify-content: flex-start; padding-left: 0; color: var(--lb-fg-muted); cursor: grab; opacity: 0; pointer-events: none; transition: opacity var(--lb-duration-100) var(--lb-ease-standard); z-index: 2; touch-action: none; user-select: none; }
.lb-media__track-drag svg { width: var(--lb-size-4x); height: var(--lb-size-4x); }
.lb-media__playlist > li:hover .lb-media__track-drag,
.lb-media__playlist > li:focus-within .lb-media__track-drag { opacity: 0.7; pointer-events: auto; }
.lb-media__track-drag:hover { opacity: 1; }
.lb-media__track-drag:active { cursor: grabbing; }
/* While dragging — keep the row's hover background + a lifted shadow. */
.lb-media__playlist-li--dragging .lb-media__track { background: var(--lb-bg-bolder); box-shadow: var(--lb-shadow-dropdown); }
/* Hover-only grip column: at rest the row uses its normal padding (no
   empty space on the left). On hover/focus/dragging the row slides
   right to reveal the grip. Smooth via the padding-left transition on
   .lb-media__track. */
.lb-media__playlist[data-lb-media-playlist-reorderable] > li:hover > .lb-media__track,
.lb-media__playlist[data-lb-media-playlist-reorderable] > li:focus-within > .lb-media__track,
.lb-media__playlist[data-lb-media-playlist-reorderable] .lb-media__playlist-li--dragging > .lb-media__track { padding-left: var(--lb-size-5x); }

/* Inline (accordion) row-menu mode — opt-in via
   data-lb-media-playlist-actions-mode="inline" on the playlist. Instead
   of the 3-dots popping a dropdown that can overflow the player, the row
   expands a panel below the track button with the same menu items
   rendered inside using the shared .lb-list primitive. Animates
   max-height + opacity via existing duration/ease tokens. */
/* No padding on the panel itself — padding here would always render
   (content-box) and add height to every collapsed row, making the
   album playlist's rows visually taller than the compact / video
   playlists which don't inject a panel. The inset spacing lives on
   the inner panel-list as margin, which gets clipped by the panel's
   overflow:hidden when collapsed → row truly collapses to 0. */
.lb-media__track-panel { overflow: hidden; max-height: 0; opacity: 0; transition: max-height var(--lb-duration-300) var(--lb-ease-standard), opacity var(--lb-duration-200) var(--lb-ease-standard); }
.lb-media__playlist > li.lb-media__playlist-li--expanded > .lb-media__track-panel { max-height: 24rem; /* design-intent: media track panel expand cap */ opacity: 1; }
/* Outer panel uses padding (not content margin) to reveal the parent <li>
   bg-bolder card around the inner menu list — gives a clear "card within
   card" / nested-popout look. The inner list gets its own bg matching
   the player surface (--lb-surface-bg-elevated) so it reads as
   recessed; items show their normal .lb-list__item:hover (bg-bolder),
   which contrasts cleanly with the surface bg. The card boundary now
   does the work the border-top used to — divider removed. */
/* Inset spacing on the inner list via MARGIN (not parent padding) — when
   the panel is collapsed (max-height:0), this margin is clipped by
   overflow:hidden along with the rest. Asymmetric: small on top
   (size-2x = 8px) to stay close to the track row; moderate on sides +
   bottom (size-4x = 16px) for the nested card-within-card feel. */
/* Qualified with .lb-list so this beats the base .lb-list rule (which
   defines margin:0 + padding:size-2x 0 later in the file and otherwise
   wins on equal specificity + source order). */
.lb-media__track-panel-list.lb-list { margin: var(--lb-size-2x) var(--lb-size-4x) var(--lb-size-4x); list-style: none; padding: var(--lb-size-2x); display: flex; flex-direction: column; gap: var(--lb-size-0-5x); background: var(--lb-surface-bg-elevated); border-radius: var(--lb-radius-interactive); }
/* Expanded row reads as one continuous "card" wrapping the track button
   + the panel: bg on the <li> so the panel inherits it visually, plus a
   border-radius so the whole thing has a single rounded shape. Track
   button gets the same bg so it merges seamlessly (active state still
   wins via the existing --active rule). Actions stay visible + duration
   fades, matching the hover behaviour. */
.lb-media__playlist > li.lb-media__playlist-li--expanded { background: var(--lb-bg-bolder); border-radius: var(--lb-radius-interactive); }
.lb-media__playlist > li.lb-media__playlist-li--expanded > .lb-media__track:not(.lb-media__track--active) { background: var(--lb-bg-bolder); }
/* When the EXPANDED row is the currently-playing one, the outer card
   picks up the same --lb-action-bg-selected as the active track so the
   row + card stay visually consistent (instead of an accent track on a
   bg-bolder card). Inner panel-list keeps its surface bg regardless. */
.lb-media__playlist > li.lb-media__playlist-li--expanded:has(> .lb-media__track--active) { background: var(--lb-action-bg-selected); }
.lb-media__playlist > li.lb-media__playlist-li--expanded .lb-media__track-actions { opacity: 1; pointer-events: auto; }
.lb-media__playlist > li.lb-media__playlist-li--expanded .lb-media__track-dur { opacity: 0; }
@media (prefers-reduced-motion: reduce) { .lb-media__track-panel { transition: none; } }
/* Unify the three action buttons (share / favourite / overflow trigger)
   so the LB.Menu trigger's default styling doesn't make it look different
   from its siblings. */
.lb-media__track-actions .lb-icon-btn,
.lb-media__track-actions .lb-menu__trigger.lb-icon-btn { background: transparent; border-color: transparent; color: var(--lb-fg-muted); }
.lb-media__track-actions .lb-icon-btn:hover,
.lb-media__track-actions .lb-menu__trigger.lb-icon-btn:hover { background: var(--lb-action-bg-ghost-hover); color: var(--lb-fg-default); }
.lb-media__track--active .lb-media__track-dur { color: var(--lb-fg-accent-muted); }

/* ═══════════════════════════════════════════════════════════
   TIMELINE
   ═══════════════════════════════════════════════════════════ */

/* Standalone primitive: a horizontal trim/playhead/ruler/zoom surface.
   Emits lb-timeline-change {inSec, outSec, playheadSec}. Composes with
   Media Player but doesn't require one — useful for any "set in/out
   over a duration" UI. Engine-pluggable per HARD principle: letbe-ds
   ships the chrome, waveform / frame-accurate scrub engines (WaveSurfer
   / Peaks / hls.js) attach via callbacks set by the consumer. */

/* Shell — card-like surface so the lane reads as a contained editor
   widget, not a runaway bar. Uses size-3x padding to match Card --sm. */
.lb-timeline {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x);
  background: var(--lb-surface-bg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-surface);
  font-family: var(--lb-t-body-m-font-family);
  color: var(--lb-fg-default);
}

/* Readout row — In / Out / Duration triad. Each value tabular-nums
   so the column doesn't shift when digits change while dragging. */
.lb-timeline__readout {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--lb-size-4x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
}
.lb-timeline__readout-item { display: inline-flex; align-items: baseline; gap: var(--lb-size-1x); }
.lb-timeline__readout-label { color: var(--lb-fg-muted); }
.lb-timeline__readout-value { color: var(--lb-fg-default); font-variant-numeric: tabular-nums; font-weight: var(--lb-t-label-m-font-weight); }

/* Header row — readout (in / out / duration) sits LEFT, zoom slider
   sits RIGHT on the same line. flex-wrap lets the slider drop to its
   own line at narrow widths instead of squeezing the readout.
   margin-left:auto on the slider pushes it to the right edge whether
   or not flex-wrap kicks in. */
.lb-timeline__header {
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  flex-wrap: wrap;
}
/* The zoom slider is a SECONDARY affordance, laid out as one inline
   row: [Label] [Track] [Value]. CSS Grid + `display: contents` on
   the slider field's header un-nests label + value so all three
   pieces participate directly in the field's grid. margin-left:auto
   pushes the whole control to the right of the readout when there's
   room; flex-wrap on the parent drops it to its own line at narrow
   widths instead of squeezing the readout. */
.lb-timeline__zoom {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: auto;
  align-items: center;
  gap: var(--lb-size-2x);
  margin-left: auto;
  flex: 0 1 220px;
}
.lb-timeline__zoom .lb-slider-field__header { display: contents; }
/* Pin every grid item to row 1 explicitly. `display: contents` on
   the header would otherwise let the grid auto-place track-wrap on
   the next row because label + value land first in source order
   and the auto-placement skips occupied positions even when an
   explicit grid-column is set. */
.lb-timeline__zoom .lb-slider-field__label     { grid-column: 1; grid-row: 1; }
.lb-timeline__zoom .lb-slider-track-wrap       { grid-column: 2; grid-row: 1; margin: 0; }
.lb-timeline__zoom .lb-slider-field__value     { grid-column: 3; grid-row: 1; }
.lb-timeline__zoom .lb-slider-field__label,
.lb-timeline__zoom .lb-slider-field__value { font-size: var(--lb-t-caption-m-font-size); }

/* Viewport — fixed-width visible area that horizontally scrolls when
   the scroller (which scales with zoom) exceeds it. overflow-y is
   hidden so a stray vertical scrollbar doesn't appear. The native
   scrollbar inherits the design system's thin-scrollbar treatment. */
.lb-timeline__viewport {
  overflow-x: auto;
  overflow-y: hidden;
  /* Hairline border-top so the viewport reads as a contained surface
     when the ruler + lane scroll inside it. */
}
.lb-timeline__scroller {
  position: relative;
  /* width is set inline by JS to (zoom * 100%) — at zoom=1 the
     scroller exactly fits the viewport and there is no scrollbar. */
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  min-width: 100%;
}

/* Ruler — fixed-height row of major/minor ticks with labels above.
   The ticks paint inside the same .lb-timeline__track horizontal
   coordinate system as the lane below, so visually they align.
   Height = size-6x (24px) gives room for labels above tick lines
   without crowding. */
.lb-timeline__ruler {
  position: relative;
  height: var(--lb-size-6x);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  line-height: 1;
  user-select: none;
}
.lb-timeline__tick {
  position: absolute;
  top: 0;
  width: var(--lb-border-width-thin);
  background: var(--lb-border-muted);
}
.lb-timeline__tick--major { height: 100%; background: var(--lb-border-strong); }
.lb-timeline__tick--minor { height: 50%; bottom: 0; top: auto; }
.lb-timeline__tick-label {
  position: absolute;
  top: 0;
  transform: translateX(var(--lb-size-1x));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
  pointer-events: none;
}
/* Right-anchored variant — used by the labels near the end of the
   ruler (pct > 95%) so the text hangs LEFT of the tick line instead
   of overflowing the scroller's right edge. Without this, the final
   label forces a horizontal scrollbar even at zoom=1 where nothing
   should scroll. */
.lb-timeline__tick-label--right {
  transform: translateX(calc(-100% - var(--lb-size-1x)));
}

/* Lane — the main horizontal track holding the trim selection +
   playhead. Height = size-10x (40px) so the trim handles have a
   comfortable hit area without dominating the row. The lane bg is
   the "out of selection" muted fill; the selection paints inside via
   --in/--out percentage variables set by the JS. */
.lb-timeline__lane {
  position: relative;
  height: var(--lb-size-10x);
  background: var(--lb-bg-bolder);
  border-radius: var(--lb-radius-interactive);
  overflow: hidden;
  --in: 0%;
  --out: 100%;
  --playhead: 0%;
}

/* Selection fill — the picked in/out window. Uses bg-accent-muted so
   it reads as "this is what's selected" without screaming. */
.lb-timeline__selection {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--in);
  right: calc(100% - var(--out));
  background: var(--lb-bg-accent-muted);
}

/* Handles — visible bar is size-1x wide; ::before gives a wider
   invisible hit area (size-4x = 16px) so the bar is always easy to
   grab without bloating the visual. touch-action:none stops the
   browser from scrolling/zooming when the user drags on touch.
   Cursor uses ew-resize so the affordance reads at-a-glance.
   color: inherit on the bar so the dragging-state outline picks up
   the same accent token. */
.lb-timeline__handle {
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--lb-size-1x);
  background: var(--lb-bg-accent-value);
  cursor: ew-resize;
  touch-action: none;
  z-index: 1;
}
.lb-timeline__handle::before {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: var(--lb-size-4x);
  transform: translateX(-50%);
  /* Invisible hit area — pointer events land here so the visible bar
     stays slim. */
}
.lb-timeline__handle--in  { left: var(--in);  transform: translateX(-50%); }
.lb-timeline__handle--out { left: var(--out); transform: translateX(-50%); }
/* Hover + focus reveal the handle is interactive without changing
   layout: outline + slight scale. Focus uses border-focus token so
   keyboard users get the same a11y treatment as everywhere else. */
.lb-timeline__handle:hover,
.lb-timeline__handle--dragging {
  background: var(--lb-bg-accent-strong);
  box-shadow: 0 0 0 var(--lb-border-width-action) var(--lb-bg-accent);
}
.lb-timeline__handle:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
/* While dragging any handle, dim the cursor over the entire lane so
   the user gets a "you're in a drag" hint even if they slide off the
   handle bar (pointer capture keeps the drag wired to the handle). */
.lb-timeline__lane:has(.lb-timeline__handle--dragging) { cursor: ew-resize; }

/* Playhead — the current scrub position. The element itself is the
   thin vertical line (border-width-action ≈ 2px) with a triangular
   marker above via ::before. ::after extends an invisible 16px hit
   area centred on the line so the playhead is grabbable without
   making the visible decoration thicker. Sits above handles in z so
   click-on-overlap grabs the playhead — matches the video editor
   convention where playhead is the primary drag target. */
.lb-timeline__playhead {
  position: absolute;
  top: 0;
  bottom: 0;
  width: var(--lb-border-width-action);
  left: var(--playhead);
  transform: translateX(-50%);
  background: var(--lb-fg-default);
  cursor: ew-resize;
  touch-action: none;
  z-index: 2;
}
.lb-timeline__playhead::before {
  content: '';
  position: absolute;
  top: 0;
  left: 50%;
  transform: translate(-50%, -25%);
  width: var(--lb-size-2x);
  height: var(--lb-size-2x);
  background: var(--lb-fg-default);
  clip-path: polygon(0 0, 100% 0, 50% 100%);
  pointer-events: none;
}
.lb-timeline__playhead::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: var(--lb-size-4x);
  transform: translateX(-50%);
}
.lb-timeline__playhead:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-timeline__playhead--dragging,
.lb-timeline__playhead:hover { background: var(--lb-fg-accent); }
.lb-timeline__playhead--dragging::before,
.lb-timeline__playhead:hover::before { background: var(--lb-fg-accent); }

/* Lane gains "scrub" cursor on hover when no handle is being dragged
   so the user knows clicking the empty lane jumps the playhead. */
.lb-timeline__lane { cursor: ew-resize; }

/* Empty state — when no duration is set yet. Border-dashed reads as
   "ready to receive media" rather than broken. */
.lb-timeline--empty .lb-timeline__lane {
  background: transparent;
  border: var(--lb-border-width-action) dashed var(--lb-border-muted);
}
.lb-timeline--empty .lb-timeline__selection,
.lb-timeline--empty .lb-timeline__handle,
.lb-timeline--empty .lb-timeline__playhead { display: none; }

/* ═══════════════════════════════════════════════════════════
   PAGINATION
   ═══════════════════════════════════════════════════════════ */

.lb-pagination { font-family: var(--lb-t-action-m-font-family); display: flex; align-items: center; gap: var(--lb-size-1x); }
.lb-pagination__btn { display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; padding: 0 var(--lb-size-2x); border-radius: var(--lb-radius-interactive); border: var(--lb-border-width-action) solid transparent; background: var(--lb-action-bg-ghost-default); font-family: var(--lb-t-action-m-font-family); font-size: var(--lb-t-action-m-font-size); font-weight: var(--lb-t-action-m-font-weight); line-height: var(--lb-t-action-m-line-height); letter-spacing: var(--lb-t-action-m-letter-spacing); color: var(--lb-action-fg-ghost-default); cursor: pointer; transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-pagination__btn:hover:not(:disabled):not(.lb-pagination__btn--active) { background-color: var(--lb-action-bg-ghost-hover); }
.lb-pagination__btn:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-pagination__btn:disabled { color: var(--lb-fg-disabled); cursor: not-allowed; }
.lb-pagination__btn--active { background-color: var(--lb-action-bg-primary-default); border-color: var(--lb-action-border-primary-default); color: var(--lb-action-fg-primary-default); }
.lb-pagination__btn--active:hover { background-color: var(--lb-action-bg-primary-hover); border-color: var(--lb-action-border-primary-hover); color: var(--lb-action-fg-primary-hover); }
.lb-pagination__ellipsis { min-width: 2rem; height: 2rem; display: inline-flex; align-items: center; justify-content: center; font-family: var(--lb-t-action-m-font-family); font-size: var(--lb-t-action-m-font-size); color: var(--lb-fg-muted); user-select: none; }

/* ═══════════════════════════════════════════════════════════
   DATEPICKER
   ═══════════════════════════════════════════════════════════ */

.lb-datepicker-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); position: relative; }
.lb-datepicker-field__label { font-family: var(--lb-t-label-m-font-family); font-size: var(--lb-t-label-m-font-size); font-weight: var(--lb-t-label-m-font-weight); line-height: var(--lb-t-label-m-line-height); letter-spacing: var(--lb-t-label-m-letter-spacing); color: var(--lb-field-fg-label); }
.lb-datepicker-field__hint { font-family: var(--lb-t-body-xs-font-family); font-size: var(--lb-t-body-xs-font-size); line-height: var(--lb-t-body-xs-line-height); color: var(--lb-field-fg-hint); }
.lb-datepicker-field__hint--error,
.lb-datepicker-field__hint--success { display: flex; align-items: center; gap: var(--lb-size-1x); }
.lb-datepicker-field__hint--error   { color: var(--lb-field-fg-error); }
.lb-datepicker-field__hint--success { color: var(--lb-field-fg-success); }
.lb-datepicker-field__hint--error > [data-lb-icon],
.lb-datepicker-field__hint--success > [data-lb-icon] { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); flex-shrink: 0; }
.lb-datepicker--inline { display: inline-flex; flex-direction: column; gap: var(--lb-size-2x); font-family: var(--lb-t-body-m-font-family); width: fit-content; }
.lb-datepicker-trigger { display: flex; align-items: center; gap: var(--lb-size-2x); width: 100%; background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); color: var(--lb-field-fg-default); cursor: pointer; font-family: var(--lb-t-body-m-font-family); text-align: left; transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
/* Fixed heights match inputs/buttons. Large = 48px (desktop-only, still AA touch target). */
.lb-datepicker-trigger--small  { height: 2rem;   padding: 0 var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); }
.lb-datepicker-trigger--medium { height: 2.5rem; padding: 0 var(--lb-size-3x); font-size: var(--lb-t-body-m-font-size); }
.lb-datepicker-trigger--large  { height: 3rem;   padding: 0 var(--lb-size-3x); font-size: var(--lb-t-body-l-font-size); }
.lb-datepicker-trigger:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); border-color: var(--lb-field-border-focus); }
.lb-datepicker-trigger--error { border-color: var(--lb-field-border-error); }
.lb-datepicker-trigger--error:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); outline-offset: var(--lb-size-0-5x); }
.lb-datepicker-trigger:disabled { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-datepicker-trigger__icon    { display: flex; align-items: center; color: var(--lb-fg-muted); flex-shrink: 0; width: 1.25rem; height: 1.25rem; }
.lb-datepicker-trigger__icon svg { width: 100%; height: 100%; }
.lb-datepicker-trigger__text    { flex: 1; }
.lb-datepicker-trigger--placeholder .lb-datepicker-trigger__text { color: var(--lb-field-fg-placeholder); }

/* Heading variant — for cases where the date IS the section heading
   (e.g. Calendar headline). Reads as a heading at rest, with a
   trailing chevron-down hinting at click. Pure ghost-button hover
   so it sits inside section headers without competing visually.
   Reuses ghost L3 + heading-s typography composite — no new tokens. */
.lb-datepicker-trigger--heading {
  height: auto;
  padding: var(--lb-size-1x) var(--lb-size-2x);
  background: transparent;
  border: var(--lb-border-width-thin) solid transparent;
  border-radius: var(--lb-radius-field);
  color: var(--lb-fg-default);
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-heading-s-font-size);
  font-weight: var(--lb-t-heading-s-font-weight);
  line-height: var(--lb-t-heading-s-line-height);
  letter-spacing: var(--lb-t-heading-s-letter-spacing);
}
.lb-datepicker-trigger--heading:hover:not(:disabled) {
  background: var(--lb-action-bg-ghost-hover);
}
.lb-datepicker-trigger--heading:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
  border-color: transparent;
}
.lb-datepicker-trigger--heading.lb-datepicker-trigger--placeholder .lb-datepicker-trigger__text {
  color: var(--lb-fg-default);
}
.lb-datepicker-trigger__chevron { display: flex; align-items: center; color: var(--lb-fg-muted); flex-shrink: 0; margin-left: auto; width: 1.25rem; height: 1.25rem; transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-datepicker-trigger__chevron--open { transform: rotate(180deg); }
.lb-datepicker-trigger__chevron svg { width: 100%; height: 100%; }
.lb-datepicker-popover { position: absolute; top: calc(100% + 4px); /* design-intent: popover gap from anchor */ left: 0; z-index: 100; background: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-dropdown); animation: lb-datepicker-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); padding: var(--lb-size-4x); }
@keyframes lb-datepicker-in { from { opacity: 0; transform: translateY(-4px); /* design-intent: datepicker drop-in offset */ } to { opacity: 1; transform: translateY(0); } }
.lb-datepicker--inline .lb-datepicker__grid-root { background: var(--lb-surface-bg-default); border: var(--lb-border-width-thin) solid var(--lb-surface-border-default); border-radius: var(--lb-radius-overlay); padding: var(--lb-size-4x); }
/* width: 280px is the *content* area (7 × 40px day cells). content-box
   sizing means the inline variant's 16px padding wraps around that
   content rather than eating into it — keeps horizontal breathing
   equal to the top/bottom padding so the day grid doesn't kiss the
   inline border. */
.lb-datepicker__grid-root { display: flex; flex-direction: column; gap: var(--lb-size-4x); user-select: none; font-family: var(--lb-t-body-m-font-family); width: 280px; /* design-intent: datepicker grid content width (7 × 40px day cells) */ box-sizing: content-box; }
/* align-self: center stops the table from stretching to the flex
   container's cross-axis width — table hugs its 7 columns. Cells
   are 40px (36px day + 2px padding each side) so adjacent days have
   4px horizontal AND vertical breathing space — keeps each date
   readable inside a selected range. */
.lb-datepicker__table { table-layout: fixed; border-collapse: collapse; align-self: center; }
.lb-datepicker__header { display: flex; align-items: center; justify-content: space-between; gap: var(--lb-size-2x); }
.lb-datepicker__selects { display: flex; gap: var(--lb-size-3x); flex: 1; min-width: 0; }

/* Time-mode layout — reuses .lb-datepicker__select-wrap mini-select
   chrome (rendered by _renderTime()). When the grid-root contains a
   time-row it drops the 320px day-grid width and shrinks to fit. The
   inline/popover surface still owns the outer padding, so the row
   itself stays paddingless. */
.lb-datepicker__grid-root:has(.lb-datepicker__time-row) {
  width: auto;
  gap: 0;
}
.lb-datepicker--inline .lb-datepicker__grid-root:has(.lb-datepicker__time-row) {
  padding: var(--lb-size-2x) var(--lb-size-3x);
}
.lb-datepicker-popover:has(.lb-datepicker__time-row) {
  padding: var(--lb-size-2x) var(--lb-size-3x);
}
.lb-datepicker__time-row {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--lb-size-1-5x);
}
.lb-datepicker__time-row .lb-datepicker__select-wrap {
  flex: 0 0 auto;
  min-width: 3.5rem; /* design-intent: time-row select column min */
}
.lb-datepicker__time-colon {
  font-family: var(--lb-font-family-3);
  font-size: var(--lb-t-body-l-font-size);
  color: var(--lb-fg-muted);
  user-select: none;
  line-height: 1;
}
.lb-datepicker__select-wrap { position: relative; flex: 1; min-width: 0; }
.lb-datepicker__select { display: flex; align-items: center; justify-content: space-between; gap: var(--lb-size-1x); width: 100%; font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); color: var(--lb-field-fg-default); background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); padding: var(--lb-size-1x) var(--lb-size-1-5x); cursor: pointer; white-space: nowrap; overflow: hidden; }
.lb-datepicker__select:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-datepicker__select-text { overflow: hidden; text-overflow: ellipsis; }
.lb-datepicker__select-chevron { display: flex; align-items: center; color: var(--lb-fg-muted); flex-shrink: 0; transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-datepicker__select-chevron--open { transform: rotate(180deg); }
.lb-datepicker__select-list { position: absolute; top: calc(100% + 2px); /* design-intent: select-list gap from anchor */ left: 0; right: 0; z-index: 300; list-style: none; margin: 0; padding: var(--lb-size-1x) 0; background: var(--lb-surface-bg-overlay); border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay); border-radius: var(--lb-radius-overlay); box-shadow: var(--lb-shadow-dropdown); max-height: 200px; /* design-intent: datepicker select-list scroll cap */ overflow-y: auto; animation: lb-dropdown-list-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
/* [hidden] handled by global rule near top of file */
.lb-datepicker__select-option { padding: var(--lb-size-1x) var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-default); cursor: pointer; transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-datepicker__select-option:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-datepicker__select-option--selected { font-weight: var(--lb-font-weight-semibold); color: var(--lb-fg-accent); }
.lb-datepicker__nav-btn { display: inline-flex; align-items: center; justify-content: center; width: 2rem; height: 2rem; border-radius: 50%; border: none; background: none; color: var(--lb-fg-default); cursor: pointer; flex-shrink: 0; padding: var(--lb-size-2x); transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-datepicker__nav-btn:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-datepicker__nav-btn:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-datepicker__weekday { font-family: var(--lb-t-body-xs-font-family); font-size: var(--lb-t-body-xs-font-size); font-weight: var(--lb-t-body-xs-font-weight); color: var(--lb-fg-muted); text-align: center; padding-bottom: var(--lb-size-2x); width: var(--lb-size-10x); }
.lb-datepicker__cell { padding: var(--lb-size-0-5x); text-align: center; }
.lb-datepicker__day { display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 36px; border-radius: var(--lb-radius-field); border: none; background: none; font-family: var(--lb-t-body-m-font-family); font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-t-body-m-font-weight); color: var(--lb-fg-default); cursor: pointer; transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); line-height: 1; }
.lb-datepicker__day:hover:not(.lb-datepicker__day--disabled):not(.lb-datepicker__day--selected) { background: var(--lb-action-bg-ghost-hover); }
.lb-datepicker__day:active:not(.lb-datepicker__day--disabled) { background: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); }
.lb-datepicker__day:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
/* Today indicator border — each day is a clickable target; the ring
   around today tracks Action stroke along with button/input borders. */
.lb-datepicker__day--today { border: var(--lb-border-width-action) solid var(--lb-action-border-secondary-default); color: var(--lb-fg-accent); font-weight: var(--lb-font-weight-semibold); }
.lb-datepicker__day--selected { background: var(--lb-action-bg-primary-default); color: var(--lb-action-fg-primary-default); font-weight: var(--lb-font-weight-semibold); border-color: var(--lb-action-border-primary-default); }
.lb-datepicker__day--selected:hover { background: var(--lb-action-bg-primary-hover); color: var(--lb-action-fg-primary-hover); }
.lb-datepicker__day--in-range { background: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); border-radius: var(--lb-radius-field); }
.lb-datepicker__day--out-of-month { color: var(--lb-fg-disabled); cursor: default; pointer-events: none; }
.lb-datepicker__day--disabled { color: var(--lb-fg-disabled); cursor: not-allowed; pointer-events: none; }

/* ═══════════════════════════════════════════════════════════
   DATEPICKER — WEEK MODE
   ═══════════════════════════════════════════════════════════
   Same grid layout as single/range modes, but selection is by
   whole week. The whole row highlights on hover via :has(), and
   each day in the selected week carries the --in-week modifier
   so the persistent highlight reads as a continuous bar. */

/* Hover — entire row tints when any day in it is hovered. Applies to
   every day uniformly; week mode uses --in-week (not --selected) for
   the persistent fill so the row hover and selection are independent
   states that don't fight each other. */
.lb-datepicker__row--week-pick:hover .lb-datepicker__day:not(.lb-datepicker__day--out-of-month):not(.lb-datepicker__day--disabled):not(.lb-datepicker__day--in-week) {
  background: var(--lb-action-bg-ghost-hover);
}
/* Selected week — fill the row with the accent + inverted text. All
   7 days get --in-week, including the day the user clicked, so the
   look is uniform across the row. */
.lb-datepicker__day--in-week {
  background: var(--lb-action-bg-primary-default);
  color: var(--lb-action-fg-primary-default);
  font-weight: var(--lb-font-weight-semibold);
}
/* Hover stepup on selected week — match the single-day selected:hover
   intensity so the row visibly responds to mouse-over. */
.lb-datepicker__row--week-pick:hover .lb-datepicker__day--in-week {
  background: var(--lb-action-bg-primary-hover);
  color: var(--lb-action-fg-primary-hover);
}
.lb-datepicker__day--in-week.lb-datepicker__day--out-of-month {
  /* Days that fall outside the focal month but are part of the
     selected week (rare — happens at month boundaries) — still
     highlight, just with disabled-toned text. */
  color: var(--lb-action-fg-primary-default);
  opacity: 0.7;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   DATEPICKER — MONTH MODE
   ═══════════════════════════════════════════════════════════
   4 rows × 3 columns of month cells. Year nav in header.
   No table — uses CSS grid for the cell layout. */

.lb-datepicker__header--month-mode {
  /* Year sits centred between prev/next chevrons. Same flex pattern
     as the day grid header, just without the month/year selects. */
}
/* Year select in the month-mode header. Replaces the static label so
   users can jump directly to a specific year (range goes back to
   1920). The wrapper takes flex: 1 so it occupies the space between
   the prev/next chevrons; the inner trigger is overridden to hug its
   content (the canonical mini-select would otherwise stretch full-
   width via the .lb-datepicker__select-wrap flex: 1 + .lb-datepicker__
   select width:100% pair). Trigger ends up centred and compact. */
.lb-datepicker__year-select {
  flex: 1;
  display: flex;
  justify-content: center;
}
.lb-datepicker__year-select.lb-datepicker__select-wrap {
  flex: 1;            /* override the canonical flex:1 on the wrap */
}
.lb-datepicker__year-select .lb-datepicker__select {
  width: auto;        /* hug content instead of filling the wrapper */
  min-width: 0;
  /* Slightly larger typography fits the heading-level role this select
     plays in the month-mode header. Same action-l composite the
     previous static label used. */
  font-family: var(--lb-t-action-l-font-family);
  font-size: var(--lb-t-action-l-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-default);
  /* Quieter chrome — the year is the heading, not a form field. Drop
     the field-style border/bg so it reads as part of the header. */
  background: transparent;
  border-color: transparent;
  padding: var(--lb-size-1x) var(--lb-size-2x);
}
.lb-datepicker__year-select .lb-datepicker__select:hover {
  background: var(--lb-action-bg-ghost-hover);
}
.lb-datepicker__year-select .lb-datepicker__select:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
  border-color: transparent;
}
.lb-datepicker__months {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--lb-size-1x);
  width: 280px; /* design-intent: months grid content width (matches day grid) */
  align-self: center;
  box-sizing: content-box;
}
.lb-datepicker__month-cell {
  appearance: none;
  height: 3.5rem;
  padding: 0 var(--lb-size-2x);
  background: transparent;
  border: var(--lb-border-width-thin) solid transparent;
  border-radius: var(--lb-radius-field);
  cursor: pointer;
  font-family: var(--lb-t-action-m-font-family);
  font-size: var(--lb-t-action-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-datepicker__month-cell:hover:not(.lb-datepicker__month-cell--disabled):not(.lb-datepicker__month-cell--selected) {
  background: var(--lb-action-bg-ghost-hover);
}
.lb-datepicker__month-cell:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-datepicker__month-cell--today {
  /* Today's month — same accent underline pattern as Calendar's
     today-cell-num, scoped to this control. */
  border-color: var(--lb-border-accent);
  color: var(--lb-fg-accent);
}
.lb-datepicker__month-cell--selected {
  background: var(--lb-action-bg-primary-default);
  color: var(--lb-action-fg-primary-default);
  font-weight: var(--lb-font-weight-semibold);
  border-color: var(--lb-action-border-primary-default);
}
.lb-datepicker__month-cell--selected:hover {
  background: var(--lb-action-bg-primary-hover);
  color: var(--lb-action-fg-primary-hover);
}
.lb-datepicker__month-cell--disabled {
  color: var(--lb-fg-disabled);
  cursor: not-allowed;
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════
   TOAST
   ═══════════════════════════════════════════════════════════ */

@keyframes lb-toast-in { from { opacity: 0; transform: translateX(calc(100% + var(--lb-size-4x))); } to { opacity: 1; transform: translateX(0); } }
/* Toasts sit above every transient surface: modal backdrop (10000),
   theme editor (9999), command palette backdrop (7500), and any popover
   layer (≤ 10000). Picked 10100 to leave clean headroom above the
   highest existing layer without dipping into 2^15+ paranoia values. */
.lb-toast-region { position: fixed; bottom: var(--lb-size-4x); right: var(--lb-size-4x); display: flex; flex-direction: column; gap: var(--lb-size-2x); z-index: 10100; pointer-events: none; max-width: 22rem; width: 100%; }
.lb-toast { display: flex; align-items: flex-start; gap: var(--lb-size-3x); padding: var(--lb-size-3x) var(--lb-size-4x); border-radius: var(--lb-radius-surface); border: var(--lb-border-width-action) solid transparent; box-shadow: var(--lb-shadow-modal); font-family: var(--lb-t-body-s-font-family); font-size: var(--lb-t-body-s-font-size); line-height: var(--lb-t-body-s-line-height); pointer-events: all; color: var(--lb-fg-default); animation: lb-toast-in var(--lb-animation-dur-gentle) cubic-bezier(0.16, 1, 0.3, 1); }
/* Toast reads as soft tinted container, same as Banner. */
.lb-toast--info    { background: var(--lb-bg-info-subtle);    border-color: var(--lb-border-info-muted); }
.lb-toast--success { background: var(--lb-bg-success-subtle); border-color: var(--lb-border-success-muted); }
.lb-toast--warning { background: var(--lb-bg-warning-subtle); border-color: var(--lb-border-warning-muted); }
.lb-toast--danger  { background: var(--lb-bg-danger-subtle);  border-color: var(--lb-border-danger-muted); }
.lb-toast__icon   { display: flex; flex-shrink: 0; align-items: center; width: 1.5rem; height: 1.5rem; margin-top: 0; }
.lb-toast__icon svg { width: 100%; height: 100%; }
/* Icon keeps the variant tint */
.lb-toast--info    .lb-toast__icon { color: var(--lb-fg-info); }
.lb-toast--success .lb-toast__icon { color: var(--lb-fg-success); }
.lb-toast--warning .lb-toast__icon { color: var(--lb-fg-warning); }
.lb-toast--danger  .lb-toast__icon { color: var(--lb-fg-danger); }
.lb-toast__body   { flex: 1; color: var(--lb-fg-default); }
.lb-toast__title  { font-weight: var(--lb-font-weight-semibold); display: block; margin-bottom: 0.1em; }
.lb-toast__close  { background: none; border: none; padding: 0; cursor: pointer; color: var(--lb-fg-muted); display: flex; flex-shrink: 0; }
.lb-toast__close:hover { color: var(--lb-fg-default); }
.lb-toast__close:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-2); }

/* ── Neutral toast — the actionable/undo flavor ──────────────
   A neutral event ("Moved to Archive", "3 items deleted") is not a
   status, and under the accent doctrine colour must carry information —
   so this variant drops status colour and uses the plain elevated surface
   instead. It follows the theme exactly like the status variants do:
   neutral and status toasts share one region and are frequently on screen
   together, so an inverted (dark-on-light) pill would read as a different
   component rather than a sibling. Slightly translucent with a backdrop
   blur so it reads as floating app chrome rather than a flat card — the
   blur is progressive enhancement, without support it is simply opaque.
   No icon slot: an icon here would imply a status. */
.lb-toast--neutral {
  background: color-mix(in srgb, var(--lb-surface-bg-elevated) 94%, transparent);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border-color: var(--lb-surface-border-elevated);
  border-radius: var(--lb-radius-overlay);
  align-items: center;
}

/* ── Toast action — exactly one, never a filled button ───────
   Styled from currentColor so one rule works on every variant: a quiet
   chip on the toast's own ink. Deliberately not .lb-btn — a filled or
   accented button in a transient surface pulls more attention than the
   message it belongs to. */
.lb-toast__action {
  flex-shrink: 0;
  align-self: center;
  padding: var(--lb-size-1x) var(--lb-size-3x);
  background: color-mix(in srgb, currentColor 16%, transparent);
  border: var(--lb-border-width-thin) solid color-mix(in srgb, currentColor 42%, transparent);
  border-radius: var(--lb-radius-full);
  color: inherit;
  font-family: var(--lb-t-action-s-font-family);
  font-size: var(--lb-t-action-s-font-size);
  font-weight: var(--lb-font-weight-semibold);
  line-height: var(--lb-t-action-s-line-height);
  cursor: pointer;
  white-space: nowrap;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-toast__action:hover { background: color-mix(in srgb, currentColor 28%, transparent); border-color: color-mix(in srgb, currentColor 60%, transparent); }
.lb-toast__action:focus-visible {
  outline: var(--lb-border-width-medium) solid currentColor;
  outline-offset: var(--lb-size-0-5x);
}

/* Reduced motion: the toast still appears, it just doesn't slide in. */
@media (prefers-reduced-motion: reduce) {
  .lb-toast { animation: none; }
}

/* ═══════════════════════════════════════════════════════════
   PHONE INPUT
   ═══════════════════════════════════════════════════════════ */

.lb-phone { display: flex; align-items: center; width: 100%; font-family: var(--lb-t-body-m-font-family); background: var(--lb-field-bg-default); border: var(--lb-border-width-action) solid var(--lb-field-border-default); border-radius: var(--lb-radius-field); transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); position: relative; }
.lb-phone:focus-within { border-color: var(--lb-field-border-focus); outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-phone--error { border-color: var(--lb-field-border-error); }
.lb-phone--error .lb-phone__divider { background: var(--lb-field-border-error); }
.lb-phone--error:focus-within { border-color: var(--lb-field-border-error); outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); outline-offset: var(--lb-size-0-5x); }
.lb-phone--disabled { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); cursor: not-allowed; pointer-events: none; }
.lb-phone--disabled .lb-phone__trigger,
.lb-phone--disabled .lb-phone__input { color: var(--lb-field-fg-disabled); }
.lb-phone--disabled .lb-phone__code { color: var(--lb-field-fg-disabled); }
.lb-phone--disabled .lb-phone__chevron { color: var(--lb-fg-disabled); }
.lb-phone--disabled .lb-phone__divider { background: var(--lb-field-border-disabled); }
.lb-phone--disabled .lb-phone__flag { opacity: 0.4; }

/* Country selector trigger */
.lb-phone__trigger { display: flex; align-items: center; gap: var(--lb-size-1-5x); padding: 0 var(--lb-size-3x); height: 2.5rem; background: none; border: none; cursor: pointer; color: var(--lb-field-fg-default); font-family: inherit; font-size: var(--lb-t-body-m-font-size); white-space: nowrap; flex-shrink: 0; border-radius: var(--lb-radius-field) 0 0 var(--lb-radius-field); transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-phone__trigger:hover { background-color: var(--lb-action-bg-ghost-hover); }
.lb-phone__trigger:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); border-radius: var(--lb-radius-field) 0 0 var(--lb-radius-field); z-index: 1; }

/* Flag image */
.lb-phone__flag { width: 1.25rem; height: 1.25rem; border-radius: 50%; object-fit: cover; flex-shrink: 0; }

/* Dial code text */
.lb-phone__code { font-size: var(--lb-t-body-m-font-size); color: var(--lb-field-fg-default); }

/* Chevron */
.lb-phone__chevron { display: flex; align-items: center; color: var(--lb-fg-muted); transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui); }
.lb-phone__chevron--open { transform: rotate(180deg); }
.lb-phone__chevron svg { width: 1rem; height: 1rem; }

/* Divider between trigger and input */
/* Divider between phone country picker + number input — follows Action
   stroke since it sits between two interactive segments. */
.lb-phone__divider { width: var(--lb-border-width-action); align-self: stretch; background: var(--lb-field-border-default); flex-shrink: 0; }

/* Number input */
.lb-phone__input { flex: 1; height: 2.5rem; padding: 0 var(--lb-size-3x); border: none; outline: none; background: transparent; font-family: inherit; font-size: var(--lb-t-body-m-font-size); color: var(--lb-field-fg-default); min-width: 0; border-radius: 0 var(--lb-radius-field) var(--lb-radius-field) 0; }
.lb-phone__input::placeholder { color: var(--lb-field-fg-placeholder); }

/* ── Country dropdown ──
   The dropdown is a .lb-list.lb-list--filterable instance, so the search
   input, scrollable items, no-results placeholder, hover/selected states,
   keyboard nav, and ARIA all come from the List component. Phone only
   adds positioning + max-height + the entrance animation here. */
.lb-phone__dropdown {
  position: absolute;
  top: calc(100% + 4px); /* design-intent: dropdown gap from anchor */
  left: 0;
  right: 0;
  z-index: 200;
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-dropdown);
  max-height: 280px; /* design-intent: phone country menu scroll cap */
  animation: lb-phone-dropdown-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
@keyframes lb-phone-dropdown-in { from { opacity: 0; transform: translateY(-4px); /* design-intent: dropdown drop-in offset */ } to { opacity: 1; transform: translateY(0); } }
/* [hidden] handled by global rule near top of file */

/* ═══════════════════════════════════════════════════════════
   TABLE
   Data-dense tabular layout. Semantic <table> markup with
   slot-based cells — drop any letbe-ds component inside.
   Sizes:     --sm | (default) | --lg
   Modifiers: --striped --sticky --hoverable --bordered
   Cell:      --start (default) --center --end --select --actions
   Row:       --selected (sets on <tr>), :hover
   ═══════════════════════════════════════════════════════════ */

.lb-table-wrap {
  width: 100%;
  overflow-x: auto;
  border-radius: var(--lb-radius-surface);
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-surface-bg-default);
}
/* Sticky-header — the previous attempt put <thead> inside a scrollable
   <div class="lb-table-wrap__body"> with position: sticky. That works
   visually (thead pins) but the scrollbar still belongs to the scroll
   container and runs the FULL height including alongside the thead.
   Browser invariant — can't be decoupled.

   True fix: split the <thead> into its own table OUTSIDE the scroll
   container. Two tables — one for the header (no scroll), one for
   the body (vertically scrollable). Column widths sync via
   `table-layout: fixed` on .lb-table--sticky so both tables
   distribute columns identically by default.

   Markup:
     <div class="lb-table-wrap lb-table-wrap--sticky">
       <div class="lb-table-wrap__header">
         <table class="lb-table lb-table--sticky">
           <thead>…</thead>
         </table>
       </div>
       <div class="lb-table-wrap__body">
         <table class="lb-table lb-table--sticky">
           <tbody>…</tbody>
         </table>
       </div>
     </div>

   For unequal column widths, consumers add a matching <colgroup> in
   both tables (rare — most data tables work fine with the default
   even distribution from table-layout:fixed). */
.lb-table-wrap--sticky {
  display: flex;
  flex-direction: column;
  max-height: 26rem;
}
.lb-table-wrap__header {
  flex-shrink: 0;
  /* No overflow here — the header doesn't scroll. */
}
.lb-table-wrap__body {
  flex: 1;
  overflow-y: auto;
  /* Scrollbar lives ONLY along this body region, never past the thead. */
}
/* table-layout: fixed makes both tables distribute columns identically
   by default, so consumers don't need a colgroup just to align them. */
/* Row expansion: [data-lb-table-expand] button toggles the adjacent
   .lb-table__detail-row (LB.Table wires it; chevron rotates via the
   global aria-expanded rule). Recessed band distinguishes detail
   content from data rows. NOT compatible with --striped (nth-child
   stripes count detail rows). */
.lb-table__detail-row > .lb-table__cell { background: var(--lb-bg-strong); }
.lb-table__detail-row[hidden] { display: none; }

/* Column resize (opt-in data-lb-table-resize on the table, or on the
   sticky wrap to sync both split tables). Fixed layout makes <col>
   widths authoritative; the handle is an invisible hit zone on the
   header-cell edge whose line appears on hover/focus/drag (industry
   norm), with keyboard + double-click-reset alternatives wired in JS. */
.lb-table--fixed { table-layout: fixed; }
/* Under fixed layout the 1px hug-column trick collapses to a literal
   1px track (fixed layout takes header widths as authoritative) — give
   the select/actions columns real widths there. Applies to --sticky
   too, which is also fixed layout. */
.lb-table--fixed .lb-table__cell--select,
.lb-table--sticky .lb-table__cell--select { width: var(--lb-size-12x); }
.lb-table--fixed .lb-table__cell--actions,
.lb-table--sticky .lb-table__cell--actions { width: var(--lb-size-16x); }
/* Pinned first column (opt-in .lb-table--pin-first; in the sticky split,
   put it on BOTH tables). Sticky-left inside the scrolling wrap; base
   background is opaque so scrolled content never bleeds through, and the
   row-state rules (hover/selected/zebra — all `tr… > .lb-table__cell`,
   higher specificity) override it so pinned cells track their row.
   The hairline divider marks the pin boundary. */
.lb-table--pin-first th:first-child,
.lb-table--pin-first td:first-child { position: sticky; left: 0; z-index: 1; background: var(--lb-surface-bg-default); border-right: var(--lb-border-width-thin) solid var(--lb-border-muted); }
.lb-table--pin-first thead th:first-child { z-index: 2; }
.lb-table__cell--resizable { position: relative; }
.lb-table__resize { position: absolute; top: 0; right: calc(-1 * var(--lb-size-1x)); width: var(--lb-size-2x); height: 100%; cursor: col-resize; z-index: 2; touch-action: none; }
.lb-table__resize::after { content: ''; position: absolute; top: 0; bottom: 0; left: 50%; width: var(--lb-border-width-medium); transform: translateX(-50%); background: transparent; }
.lb-table__resize:hover::after,
.lb-table__resize--active::after { background: var(--lb-border-strong); }
.lb-table__resize:focus-visible { outline: none; }
.lb-table__resize:focus-visible::after { background: var(--lb-border-focus); }
.lb-table--sticky { table-layout: fixed; }
.lb-table--sticky thead { background: var(--lb-bg-strong); }

.lb-table {
  width: 100%;
  border-collapse: separate; /* keeps sticky thead from losing border */
  border-spacing: 0;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-default);
}

/* Cell base — applied to <th> and <td> */
.lb-table__cell {
  text-align: start;
  vertical-align: middle;
  padding: var(--lb-size-3x) var(--lb-size-4x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-surface-bg-default);
}

/* Header cells — neutral band (accent model 2026-08-03; was brand-
   tinted). Enterprise tables keep neutral headers so accent stays free
   to mean selection. Bottom border uses the softer row-divider tone —
   the bg band already separates header from body. */
.lb-table thead .lb-table__cell {
  font-family: var(--lb-t-label-s-font-family);
  font-size: var(--lb-t-label-s-font-size);
  font-weight: var(--lb-font-weight-semibold);
  letter-spacing: var(--lb-t-label-s-letter-spacing);
  color: var(--lb-fg-default);
  background: var(--lb-bg-strong);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  white-space: nowrap;
}

/* Last row — trim divider for a clean bottom edge */
.lb-table tbody tr:last-child > .lb-table__cell { border-bottom: 0; }

/* Sizes */
.lb-table--sm .lb-table__cell { padding: var(--lb-size-2x) var(--lb-size-3x); font-size: var(--lb-t-body-s-font-size); line-height: var(--lb-t-body-s-line-height); }
.lb-table--lg .lb-table__cell { padding: var(--lb-size-4x) var(--lb-size-5x); }

/* Alignment modifiers */
.lb-table__cell--start   { text-align: start; }
.lb-table__cell--center  { text-align: center; }
.lb-table__cell--end     { text-align: end; font-variant-numeric: tabular-nums; }

/* Narrow columns — selection + row actions */
.lb-table__cell--select  { width: 1px; /* design-intent: hug-content column (1px + nowrap shrinks to content) */ white-space: nowrap; padding-right: var(--lb-size-1x); text-align: center; }
.lb-table__cell--actions { width: 1px; /* design-intent: hug-content column (1px + nowrap shrinks to content) */ white-space: nowrap; text-align: end; }

/* Center checkbox vertically in its cell */
.lb-table__cell--select .lb-checkbox-wrap { justify-content: center; align-items: center; margin: 0; }
.lb-table__cell--select .lb-checkbox { margin-top: 0; }

/* Row states */
.lb-table--hoverable tbody tr:hover > .lb-table__cell { background: var(--lb-bg-strong); }
.lb-table tbody tr.lb-table__row--selected > .lb-table__cell { background: var(--lb-action-bg-selected); }
.lb-table--hoverable tbody tr.lb-table__row--selected:hover > .lb-table__cell { background: var(--lb-action-bg-selected); }

/* Zebra striping (opt-in) */
.lb-table--striped tbody tr:nth-child(even) > .lb-table__cell { background: var(--lb-bg-strong); }
.lb-table--striped tbody tr.lb-table__row--selected > .lb-table__cell { background: var(--lb-action-bg-selected); }
.lb-table--striped.lb-table--hoverable tbody tr:hover > .lb-table__cell { background: var(--lb-bg-bolder); }

/* Sticky header */
.lb-table--sticky thead .lb-table__cell { position: sticky; top: 0; z-index: 1; }

/* Sort button */
.lb-table__sort {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: 0;
  margin: 0;
  background: transparent;
  border: 0;
  font: inherit;
  color: inherit;
  letter-spacing: inherit;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
}
.lb-table__sort:hover { color: var(--lb-fg-default); }
.lb-table__sort:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); border-radius: var(--lb-radius-interactive); }
/* Sort indicator. The icon itself is swapped by JS based on aria-sort
   state (chevrons-up-down → chevron-up → chevron-down), so the CSS
   only needs to handle opacity + color — no rotation transform. */
.lb-table__sort-indicator[data-lb-icon] {
  display: inline-flex;
  width: 1rem;
  height: 1rem;
  color: currentColor;
  opacity: 0.45;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-table__sort:hover .lb-table__sort-indicator[data-lb-icon] { opacity: 0.8; }
.lb-table__cell[aria-sort="ascending"]  .lb-table__sort-indicator[data-lb-icon],
.lb-table__cell[aria-sort="descending"] .lb-table__sort-indicator[data-lb-icon] {
  opacity: 1;
  color: var(--lb-fg-default);
}

/* Cell content helpers — compose inside cells */
.lb-table__stack   { display: flex; flex-direction: column; gap: var(--lb-size-0-5x); min-width: 0; }
.lb-table__inline  { display: inline-flex; align-items: center; gap: var(--lb-size-2x); min-width: 0; }
.lb-table__caption { font-size: var(--lb-t-caption-m-font-size); line-height: var(--lb-t-caption-m-line-height); color: var(--lb-fg-muted); }
.lb-table__truncate { display: block; max-width: 100%; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }

/* Empty state row — resets table cell chrome so the shared .lb-empty-state
   component can render cleanly inside a full-width row via colspan. */
.lb-table__row--empty > .lb-table__cell {
  padding: var(--lb-size-8x) var(--lb-size-4x);
  text-align: center;
  border-bottom: 0;
  background: transparent;
}

/* Loading — suppress row hover while aria-busy */
.lb-table tbody[aria-busy="true"] tr:hover > .lb-table__cell { background: var(--lb-surface-bg-default); }

/* Keyboard focus outline on a row (inset so it doesn't clip) */
.lb-table tbody tr:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: calc(-1 * var(--lb-border-width-medium));
}

/* Visually hidden utility for accessible labels (shared) */
.lb-visually-hidden {
  position: absolute;
  width: 1px; height: 1px;   /* design-intent: a11y visually-hidden idiom */
  padding: 0; margin: -1px;  /* design-intent: a11y visually-hidden idiom */
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Selection toolbar — optional slot above the table, appears when rows selected */
.lb-table-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  background: var(--lb-bg-accent-muted);
  border: var(--lb-border-width-thin) solid var(--lb-border-accent);
  border-radius: var(--lb-radius-surface);
  color: var(--lb-fg-default);
  font-size: var(--lb-t-body-s-font-size);
  margin-top: var(--lb-size-2x);
}
.lb-table-toolbar__count { font-weight: var(--lb-font-weight-medium); }
.lb-table-toolbar__actions { display: flex; gap: var(--lb-size-2x); }

/* ═══════════════════════════════════════════════════════════
   EMPTY STATE
   Reusable "no data yet" pattern — list views, search results,
   filtered results, inbox zero, 404. Compose with an icon or an
   illustration, a title, optional description, and optional actions.
   Sizes: --sm | (default md) | --lg  (for full-page empty states)
   ═══════════════════════════════════════════════════════════ */

.lb-empty-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-8x) var(--lb-size-4x);
  text-align: center;
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-m-font-family);
  max-width: 32rem; /* design-intent: empty-state text column cap */
  margin: 0 auto;
}

/* Icon / illustration slot */
.lb-empty-state__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--lb-fg-subtle);
  opacity: 0.6;
  width: 3rem;  /* 48px default */
  height: 3rem;
  margin-bottom: var(--lb-size-2x);
}
.lb-empty-state__icon svg { width: 100%; height: 100%; }

/* Title — prominent, full-color text */
.lb-empty-state__title {
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-heading-s-font-size);
  font-weight: var(--lb-t-heading-s-font-weight);
  line-height: var(--lb-t-heading-s-line-height);
  letter-spacing: var(--lb-t-heading-s-letter-spacing);
  color: var(--lb-fg-default);
  margin: 0;
}
/* Description — muted supporting text */
.lb-empty-state__description {
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-muted);
  margin: 0;
}
/* Actions — button row */
.lb-empty-state__actions {
  display: flex;
  gap: var(--lb-size-2x);
  margin-top: var(--lb-size-3x);
  flex-wrap: wrap;
  justify-content: center;
}

/* Small — for inline empty states (inside cards, tables, widgets) */
.lb-empty-state--sm { padding: var(--lb-size-6x) var(--lb-size-4x); gap: var(--lb-size-1x); }
.lb-empty-state--sm .lb-empty-state__icon { width: 2rem; height: 2rem; margin-bottom: var(--lb-size-1x); }
.lb-empty-state--sm .lb-empty-state__title { font-size: var(--lb-t-body-m-font-size); font-weight: var(--lb-font-weight-medium); line-height: var(--lb-t-body-m-line-height); letter-spacing: 0; font-family: var(--lb-t-body-m-font-family); }
.lb-empty-state--sm .lb-empty-state__description { font-size: var(--lb-t-body-s-font-size); line-height: var(--lb-t-body-s-line-height); }
.lb-empty-state--sm .lb-empty-state__actions { margin-top: var(--lb-size-2x); }

/* Large — full-page empty states, 404s, onboarding blanks */
.lb-empty-state--lg { padding: var(--lb-size-16x) var(--lb-size-6x); gap: var(--lb-size-3x); }
.lb-empty-state--lg .lb-empty-state__icon { width: 4rem; height: 4rem; margin-bottom: var(--lb-size-3x); }
.lb-empty-state--lg .lb-empty-state__title { font-size: var(--lb-t-heading-m-font-size); line-height: var(--lb-t-heading-m-line-height); }
.lb-empty-state--lg .lb-empty-state__description { font-size: var(--lb-t-body-l-font-size); line-height: var(--lb-t-body-l-line-height); }

/* Danger — empty state that's actually an error state (failed to load,
   permission denied, network problem). Tints the icon to fg-danger and
   gives it full opacity so it reads as risky vs the muted neutral
   tone of a regular empty state. Title + description stay default
   so the headline doesn't shout — the icon carries the signal. */
.lb-empty-state--danger .lb-empty-state__icon {
  color: var(--lb-fg-danger);
  opacity: 1;
}

/* Empty-value placeholder — single-cell missing value marker. Use INSIDE a
   cell/field where the data loaded successfully but this particular value
   is null. Muted + non-selectable so it reads as a visual signal, not
   content. Uses --lb-fg-muted (neutral-600) — lighter than --fg-subtle,
   so the em-dash recedes behind real data. Standard glyph is em-dash (—);
   author-controlled content. Pair with aria-label="No data" for screen
   readers if desired. */
.lb-empty-value {
  color: var(--lb-fg-muted);
  user-select: none;
  font-variant-numeric: tabular-nums;
}

/* ═══════════════════════════════════════════════════════════
   MULTI-SELECT
   Form field with inline chip pills + popup listbox.
   Uses .lb-list--multi-select internally for the option list.
   Sizes: --small | --medium (default)
   Opt-ins on the field: data-lb-filterable (search in popup),
   data-lb-sort-selected (float selected items to top on open).
   ═══════════════════════════════════════════════════════════ */

.lb-multi-select-field { display: flex; flex-direction: column; gap: var(--lb-size-1x); font-family: var(--lb-t-body-m-font-family); }
.lb-multi-select-wrap { position: relative; display: flex; align-items: stretch; }

.lb-multi-select {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--lb-size-1x);
  width: 100%;
  padding: var(--lb-size-1x) var(--lb-size-3x);
  min-height: 2.5rem;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-field-fg-default);
  background: var(--lb-field-bg-default);
  border: var(--lb-border-width-action) solid var(--lb-field-border-default);
  border-radius: var(--lb-radius-field);
  outline: none;
  cursor: text;
  transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  text-align: left;
}
.lb-multi-select--small  { min-height: 2rem;   padding: var(--lb-size-0-5x) var(--lb-size-2x); font-size: var(--lb-t-body-s-font-size); }
.lb-multi-select--medium { min-height: 2.5rem; padding: var(--lb-size-1x)   var(--lb-size-3x); }
.lb-multi-select:focus-visible { border-color: var(--lb-field-border-focus); outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-multi-select[aria-disabled="true"] { background: var(--lb-field-bg-disabled); border-color: var(--lb-field-border-disabled); color: var(--lb-field-fg-disabled); cursor: not-allowed; }
.lb-multi-select--error { border-color: var(--lb-field-border-error); }
.lb-multi-select--error:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-field-border-error); }

.lb-multi-select__pills {
  display: inline-flex;
  flex-wrap: wrap;
  gap: var(--lb-size-1x);
  flex: 1;
  min-width: 0;
}
/* [hidden] handled by global rule near top of file */
/* Pills rendered inside are regular chips (.lb-chip.lb-chip--selected)
   — reuses the Chip component's quiet-selected variant so theme + dark
   mode work for free. */
.lb-multi-select__placeholder {
  color: var(--lb-field-fg-placeholder);
  flex: 1;
  user-select: none;
}
.lb-multi-select-wrap__chevron {
  display: flex;
  align-items: center;
  color: var(--lb-fg-muted);
  flex-shrink: 0;
  width: 1.25rem;
  height: 1.25rem;
  transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
  pointer-events: none;
}
.lb-multi-select-wrap__chevron--open { transform: rotate(180deg); }
.lb-multi-select-wrap__chevron svg { width: 100%; height: 100%; }

/* Popup — reuse lb-dropdown-list surface on top of lb-list primitive */

/* ═══════════════════════════════════════════════════════════
   LIST — shared primitive for option lists
   Used internally by Select, Dropdown (combobox), MultiSelect,
   Menu, Phone country picker, Datepicker month/year, etc.
   Variants:  --with-icons | --multi-select | --filterable
   Item:      --active (keyboard), --selected, --disabled, --danger
   Slots:     __icon __label __subtext __stack __hint __check
   ═══════════════════════════════════════════════════════════ */

.lb-list {
  list-style: none;
  margin: 0;
  /* 8px vertical gap so items don't reach the rounded corners of a
     wrapping surface (popover, dropdown). Consumers should still apply
     overflow: hidden on their container for guaranteed clipping. */
  padding: var(--lb-size-2x) 0;
  font-family: var(--lb-t-body-m-font-family);
  color: var(--lb-fg-default);
}

/* Filterable layout: search pinned at top, scrollable items below */
.lb-list--filterable {
  display: flex;
  flex-direction: column;
  padding: 0;
}
.lb-list--filterable .lb-list__search-wrap {
  padding: var(--lb-size-2x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  flex-shrink: 0;
}
/* When the consumer provides a plain <input class="lb-list__search">
   (legacy shape), give it the same visual treatment as .lb-input so
   it doesn't look smaller/uncompoundable with the rest of the DS. */
.lb-list--filterable input.lb-list__search:not(.lb-input) {
  width: 100%;
  height: 2.5rem;
  padding: 0 var(--lb-size-3x);
  border: var(--lb-border-width-action) solid var(--lb-field-border-default);
  border-radius: var(--lb-radius-field);
  outline: none;
  background: var(--lb-field-bg-default);
  font-family: inherit;
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
  transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-list--filterable input.lb-list__search:not(.lb-input):focus {
  border-color: var(--lb-field-border-focus);
}
.lb-list--filterable input.lb-list__search::placeholder { color: var(--lb-field-fg-placeholder); }
/* When the consumer wraps the input in .lb-input-wrap + uses .lb-input
   directly (new, preferred shape), don't re-apply any of the above —
   the Input component already owns its visuals. */
.lb-list--filterable .lb-list__items {
  list-style: none;
  margin: 0;
  padding: var(--lb-size-1x) 0;
  overflow-y: auto;
  flex: 1;
}

/* Item — use <li>, <button>, or <a> */
/* [hidden] handled by global rule near top of file */
.lb-list__item {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-default);
  cursor: pointer;
  user-select: none;
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  /* strip button/link browser styling when the item IS a button/a */
  background: none;
  border: none;
  width: 100%;
  text-align: left;
  text-decoration: none;
  font-family: inherit;
}
.lb-list__item:hover:not(.lb-list__item--disabled):not([aria-disabled="true"]) {
  background: var(--lb-bg-bolder);
}
.lb-list__item--active {
  background: var(--lb-bg-bolder);
}
.lb-list__item:focus-visible {
  outline: none;
  background: var(--lb-bg-bolder);
}
.lb-list__item--selected {
  color: var(--lb-action-fg-selected);
  font-weight: var(--lb-font-weight-semibold);
}
.lb-list__item--selected .lb-list__check { visibility: visible; }
.lb-list__item--danger { color: var(--lb-fg-danger); }
.lb-list__item--danger:hover:not(.lb-list__item--disabled):not([aria-disabled="true"]) { background: var(--lb-bg-danger-subtle); }
.lb-list__item--disabled,
.lb-list__item[aria-disabled="true"] {
  color: var(--lb-fg-disabled);
  cursor: not-allowed;
  pointer-events: none;
}
/* Section header inside a grouped LB.Dropdown listbox. Style overrides the
   normal disabled muted-look — headers should read as structural labels
   rather than greyed-out options. The top border doubles as a section
   divider; the :first-child suppression keeps the very first section
   from carrying a divider above it. */
.lb-list__item--header {
  background: var(--lb-bg-strong);
  color: var(--lb-fg-muted);
  font-size: var(--lb-font-size-2xs);
  font-weight: var(--lb-font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em; /* design-intent: uppercase list group header tracking */
  padding-top: var(--lb-size-2x);
  padding-bottom: var(--lb-size-1x);
  margin-top: var(--lb-size-1x);
  border-top: var(--lb-border-width-thin) solid var(--lb-border-default);
  cursor: default;
}
.lb-list__item--header:first-child {
  margin-top: 0;
  border-top: 0;
}
.lb-list__item--header:hover { background: var(--lb-bg-strong); }
/* Footer row inside a grouped LB.Dropdown listbox — used for hint text
   like "+ 1800 more — type to filter". Same not-navigable behaviour as
   headers but centred and italic. */
.lb-list__item--footer {
  color: var(--lb-fg-muted);
  font-size: var(--lb-font-size-2xs);
  font-style: italic;
  justify-content: center;
  cursor: default;
}
.lb-list__item--footer:hover { background: transparent; }

/* Slots */
.lb-list__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.25rem;
  height: 1.25rem;
  flex-shrink: 0;
  color: currentColor;
}
.lb-list__icon svg { width: 100%; height: 100%; }
/* Support img as direct .lb-list__icon (e.g. Phone country flag) or wrapped inside */
.lb-list__icon img { width: 100%; height: 100%; object-fit: cover; border-radius: inherit; }
img.lb-list__icon { object-fit: cover; }
.lb-list__icon--round { border-radius: 50%; }
img.lb-list__icon--round { object-fit: cover; }

.lb-list__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Stacked label + subtext block — when cell needs two lines */
.lb-list__stack {
  display: flex;
  flex-direction: column;
  gap: 0;
  flex: 1;
  min-width: 0;
}
.lb-list__subtext {
  font-size: var(--lb-t-caption-m-font-size);
  line-height: var(--lb-t-caption-m-line-height);
  color: var(--lb-fg-muted);
  font-weight: var(--lb-font-weight-regular);
}
.lb-list__item--selected .lb-list__subtext { color: inherit; opacity: 0.8; }

/* Trailing text — kbd shortcut, country dial code, badge count, etc. */
.lb-list__hint {
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-s-font-size);
  flex-shrink: 0;
  font-weight: var(--lb-font-weight-regular);
}

/* Trailing check (single-select confirmation) */
.lb-list__check {
  display: inline-flex;
  width: 1rem;
  height: 1rem;
  color: var(--lb-fg-accent);
  visibility: hidden;
  flex-shrink: 0;
}
.lb-list__check svg { width: 100%; height: 100%; }

/* Multi-select: checkbox rendered inline as leading slot (the <input> sits in the gap slot) */
.lb-list--multi-select .lb-list__item { gap: var(--lb-size-2x); }
.lb-list--multi-select .lb-list__item .lb-checkbox { margin-top: 0; pointer-events: none; /* label handles clicks */ }

/* Separator — static (author-placed) or auto (injected by sort-selected mode) */
.lb-list__separator {
  display: block;
  height: var(--lb-border-width-thin);
  background: var(--lb-border-muted);
  margin: var(--lb-size-1x) var(--lb-size-3x);
  list-style: none;
  border: none;
  padding: 0;
}

/* Empty / no-results state — shown when a filter returns zero matches.
   Handles plain <li> fallback AND nested .lb-empty-state composition
   (Command Palette uses the latter for a more substantial message). */
.lb-list__no-results {
  padding: var(--lb-size-3x);
  text-align: center;
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-s-font-size);
  list-style: none;
}
.lb-list__no-results .lb-empty-state { padding: var(--lb-size-6x) var(--lb-size-4x); }

/* ───────── Rating ─────────
   Inline radiogroup of icon items (star by default; heart, thumbs-up
   also bundled). Whole-step values. Filled state swaps between paired
   icon variants (star ↔ star-filled) — JS retoggles data-lb-icon and
   re-runs LB.initIcons. Hover preview lights up to the cursor;
   mouseleave restores the committed value. */
.lb-rating {
  --size: 1.25rem;
  --gap: var(--lb-size-1x);
  display: inline-flex;
  align-items: center;
  gap: var(--gap);
  vertical-align: middle;
}
.lb-rating--small  { --size: 1rem; }
.lb-rating--medium { --size: 1.25rem; }
.lb-rating--large  { --size: 1.75rem; /* design-intent: rating star size large (Tier B 28px cluster) */ }

.lb-rating__item {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--size);
  height: var(--size);
  margin: 0;
  cursor: pointer;
  color: var(--lb-fg-muted);
  transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
/* Filled stars are a VALUE display but read as decoration in violet —
   neutral solid vs muted empty keeps the value legible (accent model
   2026-08-03). */
.lb-rating__item--filled { color: var(--lb-fg-default); }

.lb-rating--readonly .lb-rating__item,
.lb-rating--disabled .lb-rating__item { cursor: default; }
.lb-rating--disabled { opacity: var(--lb-opacity-60); }

.lb-rating:not(.lb-rating--readonly):not(.lb-rating--disabled) .lb-rating__item:hover {
  transform: scale(1.1);
}
.lb-rating__input {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  opacity: 0;
  cursor: inherit;
  margin: 0;
}
.lb-rating__input:focus-visible ~ .lb-rating__icon {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
  border-radius: var(--lb-radius-field);
}
.lb-rating__icon {
  width: 100%;
  height: 100%;
  display: inline-flex;
  pointer-events: none;
}
.lb-rating__icon svg {
  width: 100%;
  height: 100%;
}
.lb-rating__value-text {
  margin-left: var(--lb-size-2x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
@media (prefers-reduced-motion: reduce) {
  .lb-rating__item { transition: none; }
  .lb-rating:not(.lb-rating--readonly):not(.lb-rating--disabled) .lb-rating__item:hover { transform: none; }
}

/* ───────── Resizable / Splitter ─────────
   Flex container of panels with auto-injected drag handles between
   them. Each panel keeps its size in --lb-resizable-size (%); the
   handle drags the boundary between two adjacent panels. Visible
   1px line sits centered in a wider hit area so the cursor doesn't
   need pixel-perfect aim. Vertical variant flips axis. */
.lb-resizable {
  display: flex;
  width: 100%;
  height: 100%;
  min-height: 0;
  min-width: 0;
}
.lb-resizable--horizontal { flex-direction: row; }
.lb-resizable--vertical   { flex-direction: column; }
.lb-resizable__panel {
  flex: 1 1 var(--lb-resizable-size, 0%);
  min-width: 0;
  min-height: 0;
  overflow: auto;
  position: relative;
}
.lb-resizable__handle {
  flex: 0 0 var(--lb-resizable-handle-size, 0.5rem);
  position: relative;
  background: transparent;
  border: none;
  padding: 0;
  z-index: 1;
}
/* The visible 1px line sits centered in the wider hit area. Uses
   border.default (the "everyday separator" tier) — border.muted is
   one shade above page bg in dark theme (neutral.900 on neutral.950)
   and effectively invisible at 1px. The handle is a primary affordance,
   not a passive divider — it has to be findable. */
.lb-resizable__handle::before {
  content: '';
  position: absolute;
  background: var(--lb-border-default);
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  pointer-events: none;
}
.lb-resizable--horizontal .lb-resizable__handle {
  cursor: col-resize;
  align-self: stretch;
}
.lb-resizable--horizontal .lb-resizable__handle::before {
  top: 0;
  bottom: 0;
  left: 50%;
  width: var(--lb-border-width-thin);
  transform: translateX(-50%);
}
.lb-resizable--vertical .lb-resizable__handle {
  cursor: row-resize;
}
.lb-resizable--vertical .lb-resizable__handle::before {
  left: 0;
  right: 0;
  top: 50%;
  height: var(--lb-border-width-thin);
  transform: translateY(-50%);
}
.lb-resizable__handle:hover::before,
.lb-resizable__handle--dragging::before {
  background: var(--lb-fg-accent);
}
.lb-resizable__handle:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
  border-radius: var(--lb-radius-field);
}
.lb-resizable__handle:focus-visible::before {
  background: var(--lb-fg-accent);
}
/* While dragging, suppress text selection across the entire container
   so the cursor stays as a resize cursor instead of becoming a caret. */
.lb-resizable--dragging,
.lb-resizable--dragging * {
  user-select: none;
  cursor: inherit !important;
}

/* ───────── Tree ─────────
   Hierarchical list: <ul data-lb-tree> with <li data-lb-node>
   children, optionally containing nested <ul>s. JS wraps each node's
   row in a focusable container with chevron + optional icon + label.
   Selection is single by default; expanded state is tracked via
   aria-expanded on each treeitem. */
.lb-tree {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
}
.lb-tree__node { list-style: none; }
.lb-tree__row {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-1x) var(--lb-size-2x);
  border-radius: var(--lb-radius-field);
  cursor: pointer;
  user-select: none;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
/* Soft hover/selected for dense lists. Hover uses neutral subtle bg
   (--lb-bg-strong via the ghost token); selected uses the muted accent
   tint (violet-100 / violet-900) with accent-tone text — clear "this
   is selected" without the saturated fill that fights body content. */
.lb-tree__row:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-tree__row--selected {
  background: var(--lb-action-bg-selected);
  color: var(--lb-action-fg-selected);
}
.lb-tree__row--selected:hover { background: var(--lb-action-bg-selected); }
.lb-tree__row:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-tree__chevron {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  color: var(--lb-fg-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-tree__chevron svg { width: 100%; height: 100%; }
/* Spacer keeps leaf rows aligned with parent rows. */
.lb-tree__chevron--leaf { visibility: hidden; pointer-events: none; }
.lb-tree__icon {
  width: 1rem;
  height: 1rem;
  flex-shrink: 0;
  color: var(--lb-fg-muted);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.lb-tree__icon svg { width: 100%; height: 100%; }
.lb-tree__row--selected .lb-tree__chevron,
.lb-tree__row--selected .lb-tree__icon { color: inherit; }
.lb-tree__label {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-tree__children {
  list-style: none;
  /* Indent each level — chevron 1rem + icon 1rem + 2 gaps × 0.5rem. */
  padding-left: var(--lb-size-5x);
  margin: 0;
}
.lb-tree__children[hidden] { display: none; }

/* ───────── Stat ─────────
   Single KPI primitive: label, big number, optional delta chip.
   Pure HTML/CSS — drop a Sparkline alongside it for a metric card,
   or stack several inside a Grid for a KPI strip. The
   Stat owns no surface; place inside Card or any container. */
.lb-stat {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-body-m-font-family);
}
/* Optional leading icon. Default is icon-free: icons earn their
   place only as scan anchors in LARGE mixed-metric grids.
   Opt-in via markup, aria-hidden (label text carries meaning), always
   fg-muted — the delta badge stays the only semantically-colored glyph.
   Consistency rule: all tiles in a grid get one, or none. */
.lb-stat__icon { display: inline-flex; flex-shrink: 0; width: var(--lb-size-4x); height: var(--lb-size-4x); color: var(--lb-fg-muted); }
.lb-stat__icon svg { width: 100%; height: 100%; }
.lb-stat__label:has(.lb-stat__icon) { display: flex; align-items: center; gap: var(--lb-size-1x); }

.lb-stat__label {
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  color: var(--lb-fg-muted);
  text-transform: uppercase;
}
.lb-stat__value {
  font-family: var(--lb-t-display-s-font-family);
  font-size: var(--lb-t-display-s-font-size);
  font-weight: var(--lb-t-display-s-font-weight);
  line-height: var(--lb-t-display-s-line-height);
  color: var(--lb-fg-default);
  font-variant-numeric: tabular-nums;
}
.lb-stat__sub {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  flex-wrap: wrap;
}
/* Delta is now expressed as a real Badge (small variant). The
   `.lb-stat__delta` class is kept as a no-op alias for any existing
   markup using it — paint comes from the Badge classes. Drop a Badge
   directly in `.lb-stat__sub` for new code. */
.lb-stat__delta { font-variant-numeric: tabular-nums; }
.lb-stat__caption {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}
/* Compact variant for dense KPI strips / sidebars. */
.lb-stat--compact .lb-stat__value {
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-heading-s-font-size);
  font-weight: var(--lb-t-heading-s-font-weight);
  line-height: var(--lb-t-heading-s-line-height);
}
/* Side-by-side layout — value + sparkline / icon. */
.lb-stat--row {
  flex-direction: row;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-4x);
}

/* ───────── Sparkline ─────────
   Inline mini chart — line, area, or bar. Fills its host's width and
   height (default sized via tokens). Color picks from --lb-data-1
   by default; override per-instance via inline `style="--color: ..."`
   or `data-lb-color`. */
.lb-sparkline {
  display: block;
  width: 100%;
  height: 2.5rem;
  vertical-align: middle;
  --color: var(--lb-data-1);
}
.lb-sparkline > svg {
  width: 100%;
  height: 100%;
  display: block;
  /* Let the end-of-series dot extend past the SVG box at the right edge
     without being clipped — same approach used by Bar Chart and Line
     Chart for axis labels and overflow markers. */
  overflow: visible;
}
.lb-sparkline__line { fill: none; stroke: var(--color); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; }
.lb-sparkline__area { fill: var(--color); fill-opacity: 0.15; stroke: none; }
.lb-sparkline__bar  { fill: var(--color); }
/* Optional end-of-series dot, for the metric-card pattern. */
.lb-sparkline__dot  { fill: var(--color); r: calc(var(--lb-size-2x) / 2); }

/* ───────── Bar List ─────────
   Ranked horizontal bars: top countries, top sources, top pages.
   Bar fill scales as % of the row's container width (the largest
   value is set to 100%; everything else is proportional to it). The
   value label sits flush right; the bar itself is the row's bg layer
   beneath the label. Layout is pure CSS; a small initialiser sets
   --bar-width per row from data-lb-value, or the consumer sets it
   inline instead. */
.lb-bar-list {
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1-5x);
  --color: var(--lb-data-1);
}
.lb-bar-list__row {
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  min-height: 1.75rem; /* design-intent: bar-list row density (Tier B 28px cluster) */
  padding: var(--lb-size-1x) var(--lb-size-2x);
  border-radius: var(--lb-radius-field);
}
/* The bar fills the label column only — the value column on the right
   is left clean so the number can never be overlapped or hidden behind
   the tinted bar. The bar's percentage scales relative to the label's
   own width (which is the row width minus value + gap), keeping the
   ratios visually correct without any JS measurement. */
.lb-bar-list__label {
  position: relative;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  color: var(--lb-fg-default);
  padding: var(--lb-size-1x) var(--lb-size-2x);
  margin: calc(-1 * var(--lb-size-1x)) calc(-1 * var(--lb-size-2x));
  border-radius: var(--lb-radius-field);
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
}
.lb-bar-list__label::before {
  content: '';
  position: absolute;
  inset: 0;
  width: var(--bar-width, 0%);
  background: var(--color);
  opacity: 0.18;
  border-radius: inherit;
  transition: width var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
  pointer-events: none;
}
.lb-bar-list__label > * {
  position: relative;
  z-index: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}
.lb-bar-list__value {
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
  flex-shrink: 0;
}
/* Hover state for clickable lists — soft ghost background on the row,
   slightly stronger bar tint to emphasise the hovered item. */
/* Linked labels (the documented pattern: wrap the label text in an <a>)
   inherit the row's color — the row is the affordance, not link-blue. */
.lb-bar-list__label a { color: inherit; }

.lb-bar-list--interactive .lb-bar-list__row {
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-bar-list--interactive .lb-bar-list__row:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-bar-list--interactive .lb-bar-list__row:hover .lb-bar-list__label::before { opacity: 0.26; }

/* ───────── Donut ─────────
   Proportions chart. SVG viewBox is 0 0 100 100 with the donut
   centered at 50,50. Each segment is a stroke arc on a same-radius
   circle, separated by a 1-unit dasharray gap. Rotation is applied
   per-circle via a transform so the sum starts at top (12 o'clock).
   --thickness controls the donut hole; set to 50 for a pie. */
.lb-donut {
  position: relative;
  display: inline-block;
  width: 12rem;  /* design-intent: donut chart default canvas */
  height: 12rem; /* design-intent: donut chart default canvas */
  vertical-align: middle;
  --thickness: 14;
}
.lb-donut svg { width: 100%; height: 100%; display: block; }
.lb-donut__track { fill: none; stroke: var(--lb-bg-strong); }
.lb-donut__seg   { fill: none; transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-donut:hover .lb-donut__seg { opacity: 0.85; }
.lb-donut__seg:hover { opacity: 1 !important; }
/* Center slot — stack value + label inside the donut hole. */
.lb-donut__center {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  pointer-events: none;
  font-family: var(--lb-t-body-m-font-family);
}
.lb-donut__center-value {
  font-family: var(--lb-t-heading-m-font-family);
  font-size: var(--lb-t-heading-m-font-size);
  font-weight: var(--lb-t-heading-m-font-weight);
  color: var(--lb-fg-default);
  font-variant-numeric: tabular-nums;
  line-height: 1.1;
}
.lb-donut__center-label {
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  color: var(--lb-fg-muted);
  text-transform: uppercase;
  margin-top: var(--lb-size-1x);
}
/* Legend — paired with the donut. Reuses Bar List token for color
   chips, but ships its own component to keep semantics clear. */
.lb-donut-legend {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-donut-legend__item {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
}
.lb-donut-legend__swatch {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--lb-radius-2);
  flex-shrink: 0;
}
.lb-donut-legend__label {
  flex: 1;
  color: var(--lb-fg-default);
}
.lb-donut-legend__value {
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
}

/* ───────── Bar Chart ─────────
   SVG with explicit pixel-based viewBox (computed at render time)
   so axis labels stay readable at any container width. The chart
   wrapper carries a default height; consumer can override via
   inline style or width via CSS. Tooltip is a small absolute div
   that follows the cursor over the chart area. */
.lb-bar-chart {
  position: relative;
  width: 100%;
  display: block;
  font-family: var(--lb-t-body-m-font-family);
  --bar-chart-height: 18rem;
}
.lb-bar-chart > svg {
  width: 100%;
  height: var(--bar-chart-height);
  display: block;
  overflow: visible;
}
/* When a legend is rendered above the SVG, give it a small bottom
   margin and the SVG height stays the same — total widget grows to
   accommodate the legend. */
.lb-bar-chart > .lb-bar-chart__legend + svg { /* no special rule needed; spacing handled via legend margin-bottom */ }
.lb-bar-chart__bar {
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  cursor: default;
}
.lb-bar-chart__bar:hover { opacity: 0.85; }
.lb-bar-chart__grid line {
  stroke: var(--lb-border-muted);
  stroke-dasharray: 2 3;
  stroke-width: 1;
}
.lb-bar-chart__axis-label {
  font-size: var(--lb-t-body-xs-font-size);
  font-family: var(--lb-t-body-xs-font-family);
  fill: var(--lb-fg-muted);
}
.lb-bar-chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-3x);
  margin-bottom: var(--lb-size-3x);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}
.lb-bar-chart__legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
}
.lb-bar-chart__legend-swatch {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--lb-radius-2);
}
/* Tooltip — shared shape for all charts. */
.lb-chart-tooltip {
  position: absolute;
  background: var(--lb-surface-bg-overlay);
  color: var(--lb-fg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-dropdown);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  font-size: var(--lb-t-body-s-font-size);
  pointer-events: none;
  z-index: 100;
  min-width: 8rem; /* design-intent: line-chart tooltip min */
  transform: translate(-50%, calc(-100% - 8px)); /* design-intent: lift tooltip above point + arrow gap */
  white-space: nowrap;
  display: none;
}
.lb-chart-tooltip[data-visible="true"] { display: block; }
.lb-chart-tooltip__title {
  font-weight: var(--lb-font-weight-semibold);
  margin-bottom: var(--lb-size-1x);
  color: var(--lb-fg-default);
}
.lb-chart-tooltip__row {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  font-variant-numeric: tabular-nums;
}
.lb-chart-tooltip__swatch {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: var(--lb-radius-2);
  flex-shrink: 0;
}
.lb-chart-tooltip__label { flex: 1; color: var(--lb-fg-muted); }
.lb-chart-tooltip__value { color: var(--lb-fg-default); font-weight: var(--lb-font-weight-semibold); }

/* ───────── Line / Area Chart ─────────
   Same pixel-based viewBox as Bar Chart so labels stay readable.
   Lines are drawn as paths with stroke-linecap=round; area variant
   adds a baseline-closed path beneath at low opacity. Per-point dot
   markers act as hover targets driving the shared chart tooltip. */
.lb-line-chart {
  position: relative;
  width: 100%;
  display: block;
  font-family: var(--lb-t-body-m-font-family);
  --line-chart-height: 18rem;
}
.lb-line-chart > svg {
  width: 100%;
  height: var(--line-chart-height);
  display: block;
  overflow: visible;
}
.lb-line-chart__line {
  fill: none;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}
/* Comparison overlay — series[i].dashed: the de-emphasized
   "previous period" idiom (dash carries the meaning; pair with a
   muted series color for the full treatment). */
.lb-line-chart__line--dashed {
  stroke-dasharray: 5 4; /* design-intent: comparison-series dash rhythm */
}
.lb-line-chart__area { stroke: none; opacity: 0.16; }
.lb-line-chart__dot {
  /* Visible data point — 8px diameter (--lb-size-2x). */
  r: calc(var(--lb-size-2x) / 2);
  pointer-events: none;
  transition: r var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-line-chart__hit {
  /* Transparent hover/click target — 24px diameter (--lb-size-6x).
     Sized for WCAG 2.5.8 AA target size minimum. */
  r: calc(var(--lb-size-6x) / 2);
  fill: transparent;
  cursor: default;
}
.lb-line-chart__hit:hover + .lb-line-chart__dot { r: calc(var(--lb-size-2x) / 2 + 1px); /* design-intent: hover bump radius */ }
.lb-line-chart__grid line {
  stroke: var(--lb-border-muted);
  stroke-dasharray: 2 3;
  stroke-width: 1;
}
.lb-line-chart__axis-label {
  font-size: var(--lb-t-body-xs-font-size);
  font-family: var(--lb-t-body-xs-font-family);
  fill: var(--lb-fg-muted);
}
.lb-line-chart__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-3x);
  margin-bottom: var(--lb-size-3x);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}
.lb-line-chart__legend-item {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
}
.lb-line-chart__legend-swatch {
  width: 0.625rem;
  height: 0.625rem;
  border-radius: var(--lb-radius-2);
}

/* ───────── Color Picker ─────────
   Hand-rolled saturation×value surface, hue slider, optional alpha
   slider. Reuses the existing Popover + Input components for the
   trigger-swatch dropdown and hex field. */
.lb-color-picker--popover { display: inline-block; }

/* Trigger swatch button — used in popover variant. Same height/border
   tokens as a small Input so it lines up in form rows. */
.lb-color-picker__trigger {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-1x) var(--lb-size-2x) var(--lb-size-1x) var(--lb-size-1x);
  height: 2rem;
  background: var(--lb-field-bg-default);
  border: var(--lb-border-width-action) solid var(--lb-field-border-default);
  border-radius: var(--lb-radius-field);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-field-fg-default);
  cursor: pointer;
}
.lb-color-picker__trigger:hover { border-color: var(--lb-field-border-hover); }
.lb-color-picker__trigger:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-field-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-color-picker__trigger-swatch {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--lb-radius-field);
  flex-shrink: 0;
  /* Tiny inset border so white/very-light swatches separate from the
     trigger background. */
  box-shadow: 0 0 0 1px var(--lb-border-muted) inset;
  /* Checkerboard under the color so semi-transparent values read
     correctly even on the trigger. */
  background-image:
    linear-gradient(45deg, var(--lb-bg-strong) 25%, transparent 25%),
    linear-gradient(-45deg, var(--lb-bg-strong) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--lb-bg-strong) 75%),
    linear-gradient(-45deg, transparent 75%, var(--lb-bg-strong) 75%);
  background-size: var(--lb-size-2x) var(--lb-size-2x);
  background-position: 0 0,
    0 var(--lb-size-1x),
    var(--lb-size-1x) calc(-1 * var(--lb-size-1x)),
    calc(-1 * var(--lb-size-1x)) 0;
}
.lb-color-picker__trigger-label {
  font-variant-numeric: tabular-nums;
  text-transform: uppercase;
}

/* Popover content — sized for the picker surface. Used for both the
   inline popover variant and the floating (body-attached) variant. */
.lb-color-picker__popover {
  padding: var(--lb-size-3x);
  width: 18rem;     /* design-intent: color-picker popover canvas */
  max-width: 18rem; /* design-intent: color-picker popover canvas */
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-dropdown);
  box-sizing: border-box;
}
/* Floating variant — re-parented to <body> on open and positioned via
   inline top/left from the JS. fixed positioning escapes any scrolling
   or overflow:hidden ancestor (accordion, sheet, modal body). z-index
   chosen above the theme editor (9999), modal (7000), toast (7500),
   so the picker is always reachable when triggered from inside any
   overlay surface. */
.lb-color-picker__popover--floating {
  position: fixed;
  z-index: 10000;
  animation: lb-popover-in var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}

/* Inline body — used directly in inline mode and inside the popover. */
.lb-color-picker__body {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-3x);
  font-family: var(--lb-t-body-s-font-family);
}

/* Saturation × Value surface */
.lb-color-picker__surface {
  position: relative;
  width: 100%;
  aspect-ratio: 8 / 5;
  border-radius: var(--lb-radius-field);
  cursor: crosshair;
  user-select: none;
  touch-action: none;
}
.lb-color-picker__surface:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-color-picker__cursor {
  position: absolute;
  width: var(--lb-size-3x);
  height: var(--lb-size-3x);
  border-radius: var(--lb-radius-full);
  border: var(--lb-border-width-action) solid var(--lb-fg-inverse-strong);
  /* design-intent: theme-STABLE dark contrast ring over the arbitrary hue
     field — sanctioned direct-L1 exception (fg-inverse-strong is the
     stable-LIGHT mirror; no stable-dark L2 role exists, single consumer). */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--lb-neutral-950) 40%, transparent);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Hue + alpha sliders share the same shape — full-width track, round
   thumb on top. */
.lb-color-picker__sliders {
  display: flex;
  align-items: stretch;
  gap: var(--lb-size-2x);
}
.lb-color-picker__rgb-stack {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  flex: 1;
}
.lb-color-picker__hue,
.lb-color-picker__alpha {
  position: relative;
  width: 100%;
  height: var(--lb-size-3x);
  border-radius: var(--lb-radius-full);
  cursor: pointer;
  user-select: none;
  touch-action: none;
}
/* The hue rail IS the color spectrum, not a theme decision — its six
   stops are mathematical positions on the HSL colour wheel (0/60/120/
   180/240/300/360 degrees). Using design-system tokens here would
   reduce the rainbow to a ramp of brand colours, defeating the picker's
   purpose. Documented exception to the "no hardcoded values" rule. */
.lb-color-picker__hue {
  background: linear-gradient(to right,
    #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%,
    #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}
/* Alpha slider — checkerboard background so transparency reads, with
   a gradient from clear → opaque current color overlaid via mask.
   The fallback color is fg-default so the alpha rail still reads
   before JS sets --alpha-color. */
.lb-color-picker__alpha {
  background-image:
    linear-gradient(to right, transparent, var(--alpha-color, var(--lb-fg-default))),
    linear-gradient(45deg, var(--lb-bg-strong) 25%, transparent 25%),
    linear-gradient(-45deg, var(--lb-bg-strong) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, var(--lb-bg-strong) 75%),
    linear-gradient(-45deg, transparent 75%, var(--lb-bg-strong) 75%);
  background-size: 100% 100%,
    var(--lb-size-2x) var(--lb-size-2x),
    var(--lb-size-2x) var(--lb-size-2x),
    var(--lb-size-2x) var(--lb-size-2x),
    var(--lb-size-2x) var(--lb-size-2x);
  background-position: 0 0, 0 0,
    0 var(--lb-size-1x),
    var(--lb-size-1x) calc(-1 * var(--lb-size-1x)),
    calc(-1 * var(--lb-size-1x)) 0;
}
.lb-color-picker__hue-thumb,
.lb-color-picker__alpha-thumb {
  position: absolute;
  top: 50%;
  width: var(--lb-size-3x);
  height: var(--lb-size-3x);
  border-radius: var(--lb-radius-full);
  border: var(--lb-border-width-action) solid var(--lb-fg-inverse-strong);
  /* design-intent: theme-STABLE dark contrast ring over the arbitrary hue
     field — sanctioned direct-L1 exception (fg-inverse-strong is the
     stable-LIGHT mirror; no stable-dark L2 role exists, single consumer). */
  box-shadow: 0 0 0 1px color-mix(in srgb, var(--lb-neutral-950) 40%, transparent);
  transform: translate(-50%, -50%);
  pointer-events: none;
}
.lb-color-picker__hue:focus-visible,
.lb-color-picker__alpha:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-1x);
}

.lb-color-picker__eyedropper {
  flex-shrink: 0;
  width: 2rem;
  height: 2rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: none;
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-field);
  color: var(--lb-fg-muted);
  cursor: pointer;
  padding: 0;
}
.lb-color-picker__eyedropper:hover { color: var(--lb-fg-default); border-color: var(--lb-field-border-hover); }
.lb-color-picker__eyedropper:focus-visible { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }
.lb-color-picker__eyedropper [data-lb-icon] { width: 1rem; height: 1rem; display: inline-flex; }
.lb-color-picker__eyedropper [data-lb-icon] svg { width: 100%; height: 100%; }

/* Output row — vertical stack: format toggle on top, the matching
   input row below. The toggle is a tight 3-up segmented control. */
.lb-color-picker__output {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}
.lb-color-picker__format {
  display: inline-flex;
  align-self: flex-start;
  background: var(--lb-bg-strong);
  border-radius: var(--lb-radius-field);
  padding: var(--lb-size-0-5x);
  gap: var(--lb-size-0-5x);
}
.lb-color-picker__format-btn {
  appearance: none;
  background: none;
  border: none;
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  font-family: var(--lb-t-label-s-font-family);
  font-size: var(--lb-t-label-s-font-size);
  font-weight: var(--lb-t-label-s-font-weight);
  color: var(--lb-fg-muted);
  border-radius: calc(var(--lb-radius-field) - 2px); /* design-intent: nest format button inside field radius */
  cursor: pointer;
  letter-spacing: 0.04em; /* design-intent: uppercase format button tracking */
  line-height: 1.4;
}
.lb-color-picker__format-btn:hover { color: var(--lb-fg-default); }
.lb-color-picker__format-btn:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-color-picker__format-btn--active {
  background: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  box-shadow: var(--lb-shadow-1);
}

.lb-color-picker__inputs { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-color-picker__hex-wrap { flex: 1; }
.lb-color-picker__hex {
  font-family: var(--lb-font-family-3);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}
.lb-color-picker__num-row {
  display: grid;
  grid-template-columns: repeat(var(--lb-color-picker-cols, 3), 1fr);
  gap: var(--lb-size-1x);
}
.lb-color-picker__num-row:has(input[data-cmp="a"]) {
  --lb-color-picker-cols: 4;
}
.lb-color-picker__num {
  font-family: var(--lb-font-family-3);
  text-align: center;
  /* Hide spinner controls — they crowd the small fields. Users can
     drag the surface or sliders for fine-grained control; the number
     fields are for direct-input + paste. */
  appearance: textfield;
  -moz-appearance: textfield;
}
.lb-color-picker__num::-webkit-outer-spin-button,
.lb-color-picker__num::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
.lb-color-picker__input-labels {
  display: grid;
  grid-template-columns: repeat(var(--lb-color-picker-cols, 3), 1fr);
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-caption-s-font-family);
  font-size: var(--lb-t-caption-s-font-size);
  color: var(--lb-fg-muted);
  text-align: center;
  letter-spacing: 0.05em; /* design-intent: uppercase color-picker input label tracking */
}
.lb-color-picker__num-row:has(input[data-cmp="a"]) ~ .lb-color-picker__input-labels { --lb-color-picker-cols: 4; }
.lb-color-picker__inputs:has(input[data-cmp="a"]) .lb-color-picker__input-labels {
  --lb-color-picker-cols: 4;
}

/* Preset row */
.lb-color-picker__presets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-1x);
}
.lb-color-picker__preset {
  width: 1.25rem;
  height: 1.25rem;
  border-radius: var(--lb-radius-field);
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  cursor: pointer;
  padding: 0;
}
.lb-color-picker__preset:hover {
  border-color: var(--lb-border-strong);
  transform: scale(1.08);
}
.lb-color-picker__preset:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-color-picker__preset--active {
  border-color: var(--lb-border-accent);
  box-shadow: 0 0 0 2px var(--lb-bg-default), 0 0 0 4px var(--lb-border-accent);
}
@media (prefers-reduced-motion: reduce) {
  .lb-color-picker__preset:hover { transform: none; }
}

/* ───────── Code Block ─────────
   <pre data-lb-code-block> wraps a <code> child. Optional header strip
   carries language label / filename and a copy button. Optional line
   numbers via data-lb-numbers. The JS class adds an opt-in regex
   highlighter for js/ts/json/css/html/bash; consumers can also pre-
   highlight by hand and skip the highlighter. */
.lb-code-block {
  position: relative;
  display: block;
  /* surface-bg-elevated (bg.strong tint): a "subtle" surface variant was
     referenced here but never existed — phantom var resolved transparent.
     Elevated is the one tinted surface step; if a recessed surface ever
     diverges from it, mint then (no 1:1 aliases). Figma binds the same. */
  background: var(--lb-surface-bg-elevated);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-overlay);
  overflow: hidden;
  margin: 0;
  font-family: var(--lb-t-code-m-font-family);
  font-size: var(--lb-t-code-m-font-size);
  line-height: var(--lb-t-code-m-line-height);
  color: var(--lb-fg-default);
  /* Reset the UA <pre> default of `white-space: pre`. Otherwise the
     layout whitespace between the (absolute) copy button and the
     <code> child renders as a visible blank line ABOVE the code.
     The <code> child sets its own `white-space: pre` for its
     content. */
  white-space: normal;
}
/* Header strip — only renders when JS injects it (lang / filename
   present, or copy enabled). Sits above the code. */
.lb-code-block__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-1-5x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  background: var(--lb-bg-default);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  color: var(--lb-fg-muted);
}
/* Right side of the header strip — groups the language pill and the
   action row. Inline-flex so they sit side-by-side with a gap. */
.lb-code-block__header-right {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-2x);
}

.lb-code-block__title {
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  font-family: var(--lb-font-family-3);
}
.lb-code-block__lang {
  text-transform: uppercase;
  letter-spacing: 0.05em; /* design-intent: uppercase code language label tracking */
  font-size: var(--lb-t-caption-s-font-size);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-s-font-family);
}
/* Action row — Slice 6 expansion. Replaces the previous single Copy
   button with a row of action buttons (Copy / Save / Open / Apply).
   The `.lb-code-block__action` class carries the shared icon-button
   styling; per-action classes (.lb-code-block__copy etc.) stay for
   backwards-compatible CSS overrides. */
.lb-code-block__actions {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-0-5x);
}
.lb-code-block__action {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  background: none;
  border: var(--lb-border-width-thin) solid transparent;
  padding: var(--lb-size-0-5x) var(--lb-size-1-5x);
  border-radius: var(--lb-radius-field);
  color: var(--lb-fg-muted);
  cursor: pointer;
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-code-block__action:hover {
  color: var(--lb-fg-default);
  background: var(--lb-action-bg-ghost-hover);
}
.lb-code-block__action:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-code-block__action-icon { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); display: inline-flex; }
.lb-code-block__action-icon svg { width: 100%; height: 100%; }
.lb-code-block__copy--copied { color: var(--lb-fg-success); }

/* Apply gets primary treatment — it's the dev-surface "do the thing"
   affordance; visually elevated above the secondary actions. */
.lb-code-block__action--primary {
  color: var(--lb-action-fg-primary-default);
  background: var(--lb-action-bg-primary-default);
}
.lb-code-block__action--primary:hover {
  color: var(--lb-action-fg-primary-default);
  background: var(--lb-action-bg-primary-hover);
}

/* Legacy class still styled identically for any consumer that relied
   on `.lb-code-block__copy` directly. New code uses `.lb-code-block
   __action.lb-code-block__copy` — both selectors resolve to the same
   look. */
.lb-code-block__copy {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  background: none;
  border: var(--lb-border-width-thin) solid transparent;
  padding: var(--lb-size-0-5x) var(--lb-size-1-5x);
  border-radius: var(--lb-radius-field);
  color: var(--lb-fg-muted);
  cursor: pointer;
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  transition: color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-code-block__copy:hover {
  color: var(--lb-fg-default);
  background: var(--lb-action-bg-ghost-hover);
}
.lb-code-block__copy:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-code-block__copy [data-lb-icon] { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); display: inline-flex; }
.lb-code-block__copy [data-lb-icon] svg { width: 100%; height: 100%; }

/* The code itself — overflows horizontally for long lines, never
   wraps (consumers can opt into wrap with white-space: pre-wrap). */
.lb-code-block > code {
  display: block;
  padding: var(--lb-size-3x) var(--lb-size-4x);
  overflow-x: auto;
  white-space: pre;
  /* Fix tab width to 2 spaces — readable for most languages. */
  tab-size: 2;
  -moz-tab-size: 2;
  font-family: inherit;
  font-size: inherit;
  line-height: inherit;
  color: inherit;
  background: none;
  /* Remove default <code> chrome from inline fallback. */
  border: 0;
}
/* Floating actions — used when there's no header strip. Anchored top-
   right over the code surface. Per Slice 6 / forum-win #8 these are
   now ALWAYS-VISIBLE (not hover-gated) so users discover Save / Open
   / Apply without having to know they exist. Background card so the
   buttons stay legible against highlighted code. */
.lb-code-block:not(:has(.lb-code-block__header)) .lb-code-block__actions {
  position: absolute;
  top: var(--lb-size-2x);
  right: var(--lb-size-2x);
  padding: var(--lb-size-0-5x);
  background: var(--lb-bg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-field);
  z-index: 1;
}

/* Line numbers — opt-in via data-lb-numbers. JS wraps each line in
   a span; the gutter number is rendered by a CSS counter::before
   that sits inline at the start of each line. Inline-block instead
   of absolute so the number column never overlaps the code text and
   the spacing is determined by the natural text flow. The gutter
   scrolls with horizontal overflow — acceptable trade-off for the
   simpler model and for short snippets it's invisible. */
.lb-code-block--numbers > code { counter-reset: lb-line; }
.lb-code-block--numbers .lb-code-block__line { display: block; }
.lb-code-block--numbers .lb-code-block__line::before {
  counter-increment: lb-line;
  content: counter(lb-line);
  display: inline-block;
  /* size-6x fits 2-digit numbers at code-m mono (library-session find:
     size-5x left 14px for ~17px of digits). 100+ line snippets: widen
     at the consumer. */
  width: var(--lb-size-6x);
  margin-right: var(--lb-size-2x);
  padding-right: var(--lb-size-1-5x);
  text-align: right;
  color: var(--lb-fg-muted);
  user-select: none;
  font-variant-numeric: tabular-nums;
  border-right: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}

/* Syntax token classes — set by the JS highlighter. Colors flow from
   the L2 code.* palette so dark mode flips cleanly. Mapping:
     code.1 = keyword (violet)
     code.2 = number / function (blue)
     code.3 = string (green)
     code.4 = attribute (yellow)
     code.5 = tag (red)
     code.6..8 reserved (neutral / orange / cyan) for future syntax roles.
   comment + punctuation reuse fg-muted directly — they're not chromatic
   identity, just dimmed neutral copy. */
.lb-tok-keyword     { color: var(--lb-code-1); font-weight: var(--lb-font-weight-medium); }
.lb-tok-string      { color: var(--lb-code-3); }
.lb-tok-number      { color: var(--lb-code-2); }
.lb-tok-comment     { color: var(--lb-fg-muted); font-style: italic; }
.lb-tok-punctuation { color: var(--lb-fg-muted); }
.lb-tok-tag         { color: var(--lb-code-5); }
.lb-tok-attr        { color: var(--lb-code-4); }
.lb-tok-fn          { color: var(--lb-code-2); }

/* Inline .lb-code — the prose-friendly counterpart to the block.
   Gives a single back-ticked phrase the system's mono font + a soft
   tinted box without affecting line height. */
.lb-code {
  font-family: var(--lb-t-code-m-font-family);
  font-size: var(--lb-t-code-m-font-size);
  background: var(--lb-bg-strong);
  color: var(--lb-fg-default);
  padding: 0.1em var(--lb-size-1x);
  border-radius: var(--lb-radius-field);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}

/* ═══════════════════════════════════════════════════════════
   CALENDAR — Month / Week / List views, browse + book intents
   ═══════════════════════════════════════════════════════════
   Sits in the data-viz family, separate from Datepicker (which is
   the input control). Three views, two intents, full ISO week-num
   support, past-day dimming for clear "what's happened vs ahead".
   All values route through DS tokens; no hardcoded colours/sizes.
   ═══════════════════════════════════════════════════════════ */

.lb-calendar {
  display: block;
  width: 100%;
  background: var(--lb-surface-bg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-overlay);
  overflow: hidden;
  /* Bind to body's role family so calendar chrome follows the role map. */
  font-family: var(--lb-typography-family-body);
  color: var(--lb-fg-default);
}

/* Header — title + view toggle + nav. Same pattern as Bar Chart's
   chrome row so the data-viz family reads consistently. */
.lb-calendar__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-3x) var(--lb-size-4x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  flex-wrap: wrap;
}
.lb-calendar__title-group {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  min-width: 0;
}
/* Title host — the wrapper that mounts a DatePicker (heading variant).
   position: relative so the DatePicker's popover anchors correctly.
   The DatePicker itself owns all visible styling; this host is just
   the positioning context. */
.lb-calendar__title-picker {
  position: relative;
  display: inline-flex;
}
/* Week-number badge in the header — small subtle pill. Visible only
   in week + list views; month uses the per-row weeknum column. */
.lb-calendar__week-badge {
  display: inline-flex;
  align-items: center;
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  background: var(--lb-bg-strong);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-badge);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  letter-spacing: 0.04em; /* design-intent: numeric line counter tracking */
  font-variant-numeric: tabular-nums;
}
.lb-calendar__controls {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-3x);
  flex-wrap: wrap;
}
.lb-calendar__nav {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
}

/* ── Month view ─────────────────────────────────────────── */

.lb-calendar__month {
  display: block;
}

/* Weekday row (Mon Tue Wed …) — sticky header above the week rows.
   When weekNumbers is on, an empty spacer column sits to the left to
   align with the per-row W## column below. */
.lb-calendar__weekday-row {
  display: grid;
  grid-template-columns: var(--lb-cal-grid-cols);
  background: var(--lb-bg-strong);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-calendar:not(.lb-calendar--no-weeknum) .lb-calendar__month {
  --lb-cal-grid-cols: var(--lb-size-8x) repeat(7, minmax(0, 1fr));
}
.lb-calendar.lb-calendar--no-weeknum .lb-calendar__month {
  --lb-cal-grid-cols: repeat(7, minmax(0, 1fr));
}
/* Default: weeknum column ON. Width 32px (size-8x) gives comfortable
   room for "W52" without crowding; the smaller caption-s typography
   on the W## label keeps the badge reading subtly. minmax(0, 1fr) on
   the day columns prevents content (long event titles) from forcing
   a column wider than its 1fr share — without the 0 floor, 1fr's
   implicit min-content floor lets a wide pill expand its column. */
.lb-calendar__weekday {
  padding: var(--lb-size-2x) var(--lb-size-2x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-muted);
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.06em; /* design-intent: uppercase weekday column header tracking */
}
.lb-calendar__weekcol-spacer {
  /* Empty cell above the W## column. Same dimensions as
     .lb-calendar__weeknum for column alignment. */
}

/* Week rows. Each row is a grid with the same template as the
   weekday row above so columns line up. */
.lb-calendar__row {
  display: grid;
  grid-template-columns: var(--lb-cal-grid-cols);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-calendar__row:last-child { border-bottom: none; }

/* W## indicator — sits in its own thin column, centre-aligned text,
   muted colour. Decorative; not interactive. ISO 8601 week numbers. */
.lb-calendar__weeknum {
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding-top: var(--lb-size-2x);
  background: var(--lb-bg-strong);
  border-right: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  font-family: var(--lb-t-caption-s-font-family);
  font-size: var(--lb-t-caption-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

/* Day cells — fixed minimum height so empty days don't squish; events
   stack vertically inside. No outer borders between cells (the row
   border-bottom does horizontal separation; column gridlines are
   intentional left border on each cell). */
.lb-calendar__cell {
  min-height: var(--lb-size-20x);
  padding: var(--lb-size-1-5x);
  border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  background: var(--lb-surface-bg-default);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  cursor: pointer;
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-calendar__cell:first-child { border-left: none; }
.lb-calendar__cell:hover { background: var(--lb-bg-strong); }
.lb-calendar__cell-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-shrink: 0;
}
.lb-calendar__cell-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: var(--lb-size-5x);
  height: var(--lb-size-5x);
  padding: 0 var(--lb-size-1x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  font-variant-numeric: tabular-nums;
}
.lb-calendar__cell-events {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  min-height: 0;
}

/* Out-of-month days — number stays visible (so users can click
   forward into next month) but the cell content reads dimmer. */
.lb-calendar--month .lb-calendar__cell--out .lb-calendar__cell-num {
  color: var(--lb-fg-disabled);
}
.lb-calendar--month .lb-calendar__cell--out .lb-calendar__event {
  opacity: 0.5;
}

/* Today — underline on the date number. Clear "you are here" cue
   without a heavy bg fill that competes with events. */
.lb-calendar__cell--today .lb-calendar__cell-num {
  color: var(--lb-fg-accent);
  border-bottom: var(--lb-border-width-medium) solid var(--lb-border-accent);
  border-radius: 0;
}

/* Past days — the cell content (events area) reads dimmer AND the
   cell carries a soft tinted bg so completed days are clearly distinct
   from upcoming. Same `bg-subtle 50%` mix Week-view past columns use,
   so all three views read consistently. The cell-head stays full
   opacity so the date is always legible. */
.lb-calendar__cell--past {
  background: color-mix(in srgb, var(--lb-bg-strong) 50%, var(--lb-surface-bg-default));
}
.lb-calendar__cell--past .lb-calendar__cell-events {
  opacity: 0.5;
}

/* Event pills inside a month cell. Each gets its category colour via
   a CSS custom property the JS sets inline (--lb-cal-event-color =
   var(--lb-data-N)). Hover lifts subtly. */
.lb-calendar__event {
  appearance: none;
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-0-5x) var(--lb-size-1x);
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 18%, transparent);
  border: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 40%, transparent);
  border-radius: var(--lb-radius-badge);
  cursor: pointer;
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-default);
  text-align: left;
  width: 100%;
  min-width: 0;
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-calendar__event:hover {
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 28%, transparent);
}
.lb-calendar__event:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-calendar__event-dot {
  display: inline-block;
  width: var(--lb-size-1x);
  height: var(--lb-size-1x);
  border-radius: var(--lb-radius-full);
  background: var(--lb-cal-event-color, var(--lb-data-1));
  flex-shrink: 0;
}
.lb-calendar__event-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  min-width: 0;
}

/* "+N more" overflow indicator — links to a Popover (Commit 3) but
   for now fires the date-click event so consumers can wire it. */
.lb-calendar__more {
  appearance: none;
  background: none;
  border: none;
  padding: 0 var(--lb-size-1x);
  margin-top: var(--lb-size-0-5x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  cursor: pointer;
  text-align: left;
}
.lb-calendar__more:hover { color: var(--lb-fg-accent); }

/* ── Calendar — Week view ────────────────────────────────────
   Post-feedback rewrite. Sticky header + all-day strip; everything
   below scrolls internally. Slot-based grid: each slot row is 2.5rem
   tall regardless of slot duration, so a 30-min meeting block reads
   as 40px (one row), 1-hour as 80px (two rows). Hour-mark slots get
   stronger separators so the hourly rhythm stays visible.
   Default scroll position lands at scrollHour (08:00 by default).
   See _renderWeek + _wire in lb.js. */

.lb-calendar__week {
  display: flex;
  flex-direction: column;
  /* Each slot is a fixed-height row. 2.5rem = 40px; 30-min slot
     fits one row, 1-hour fits two. Tweakable per-instance via the
     custom property if needed. */
  --lb-cal-slot-height: 2.5rem;
  --lb-cal-rail-width: var(--lb-size-12x);
  /* Whole-component height target. Sticky header eats some of this;
     the scrollable grid takes the rest. */
  max-height: 36rem; /* design-intent: calendar component target height */
}
.lb-calendar__week-header,
.lb-calendar__week-allday-row,
.lb-calendar__week-grid {
  display: grid;
  grid-template-columns: var(--lb-cal-rail-width) repeat(7, minmax(0, 1fr));
}
/* Sticky chrome — header (day labels) + all-day strip never scroll. */
.lb-calendar__week-header,
.lb-calendar__week-allday-row {
  position: sticky;
  top: 0;
  z-index: 3;
  background: var(--lb-surface-bg-default);
}
.lb-calendar__week-header {
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-calendar__week-corner {
  background: var(--lb-bg-strong);
}
.lb-calendar__week-day-head {
  padding: var(--lb-size-2x) var(--lb-size-2x);
  background: var(--lb-bg-strong);
  border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--lb-size-0-5x);
}
.lb-calendar__week-day-name {
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em; /* design-intent: uppercase week-number column tracking */
}
.lb-calendar__week-day-num {
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  font-variant-numeric: tabular-nums;
}
.lb-calendar__week-day-head--today .lb-calendar__week-day-num {
  color: var(--lb-fg-accent);
  border-bottom: var(--lb-border-width-medium) solid var(--lb-border-accent);
}
.lb-calendar__week-day-head--past .lb-calendar__week-day-name {
  opacity: 0.6;
}

/* All-day strip — visible only when at least one all-day or multi-day
   event exists in the focal week. Hidden completely otherwise so the
   header sits directly above the time grid (cleaner than a thin empty
   strip with a clipped label). The modifier is set in JS based on
   allDayBars.length. */
.lb-calendar__week-allday-row {
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  min-height: var(--lb-size-8x);
  padding: var(--lb-size-1x) 0;
  align-items: center;
}
.lb-calendar__week--no-allday .lb-calendar__week-allday-row {
  display: none;
}
.lb-calendar__week-allday-label {
  padding: 0 var(--lb-size-2x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  text-align: right;
}
.lb-calendar__week-allday {
  appearance: none;
  margin: 0 var(--lb-size-0-5x);
  padding: var(--lb-size-0-5x) var(--lb-size-1-5x);
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 22%, transparent);
  border: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 50%, transparent);
  border-radius: var(--lb-radius-badge);
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-default);
  text-align: left;
  min-width: 0;
}
.lb-calendar__week-allday:hover {
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 32%, transparent);
}
.lb-calendar__week-allday:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}

/* Internal scroll container — owns the only scrollbar. Header +
   all-day strip remain visible while the user scrolls hours. */
.lb-calendar__week-scroll {
  flex: 1;
  overflow-y: auto;
  overflow-x: hidden;
}

/* Slot grid — rows are slots (slot-min minutes each); each row is a
   fixed pixel height so events render legibly regardless of total
   range. Hour rail spans `slotsPerHour` rows per label. */
.lb-calendar__week-grid {
  position: relative;
  /* Total grid height = slot count × slot height. */
  height: calc(var(--lb-cal-slots) * var(--lb-cal-slot-height));
}
.lb-calendar__week-hour-rail {
  display: grid;
  grid-template-rows: repeat(var(--lb-cal-slots), var(--lb-cal-slot-height));
  background: var(--lb-bg-strong);
}
.lb-calendar__week-hour-label {
  /* Span set inline (style="grid-row: span N") so the label aligns
     with hour boundaries even when slotDuration < 60. */
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  text-align: right;
  font-variant-numeric: tabular-nums;
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-calendar__week-col {
  position: relative;
  display: grid;
  grid-template-rows: repeat(var(--lb-cal-slots), var(--lb-cal-slot-height));
  border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  background: var(--lb-surface-bg-default);
}
.lb-calendar__week-col--past { background: color-mix(in srgb, var(--lb-bg-strong) 50%, var(--lb-surface-bg-default)); }
.lb-calendar__week-col--today { background: color-mix(in srgb, var(--lb-bg-accent-muted) 30%, var(--lb-surface-bg-default)); }

/* Slot cells — sub-hour slots get a hairline border, hour-mark slots
   get the stronger surface-border so the hourly rhythm reads cleanly
   even when slotDuration = 15 or 30. */
.lb-calendar__week-cell {
  border-bottom: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-surface-border-default) 50%, transparent);
  cursor: pointer;
}
.lb-calendar__week-cell--hour {
  border-bottom-color: var(--lb-surface-border-default);
}
.lb-calendar__week-cell:hover { background: var(--lb-bg-strong); }

/* Past-hours overlay inside today's column. Mirrors the past-day
   dimming pattern at the hour level — natural extension of "this is
   the past" cue. Sits between cells (z=0) and events (z=1) so
   events stay readable even if they sit behind the wash. */
.lb-calendar__week-col-past-overlay {
  position: absolute;
  inset: 0 0 auto 0;
  background: color-mix(in srgb, var(--lb-bg-strong) 60%, transparent);
  z-index: 0;
  pointer-events: none;
}

/* Event block */
.lb-calendar__week-event {
  position: absolute;
  appearance: none;
  padding: var(--lb-size-0-5x) var(--lb-size-1x);
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 28%, transparent);
  border: var(--lb-border-width-thin) solid color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 60%, transparent);
  border-left: var(--lb-border-width-medium) solid var(--lb-cal-event-color, var(--lb-data-1));
  border-radius: var(--lb-radius-field);
  cursor: pointer;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-default);
  text-align: left;
  overflow: hidden;
  z-index: 1;
}
.lb-calendar__week-event:hover {
  background: color-mix(in srgb, var(--lb-cal-event-color, var(--lb-data-1)) 38%, transparent);
}
.lb-calendar__week-event:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: 0;
}
.lb-calendar__week-event--past { opacity: 0.55; }
.lb-calendar__week-event--live {
  /* Live "in progress now" gets a brighter accent border so the user
     can pick the active event out of the day quickly. */
  box-shadow: 0 0 0 var(--lb-border-width-thin) var(--lb-border-focus);
}
.lb-calendar__week-event-time {
  font-weight: var(--lb-font-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
}
.lb-calendar__week-event-title {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Current-time line — restricted to today's column. Carries a small
   "NOW" label at the left edge so it reads as a time indicator at a
   glance, not a stray ornament. The line itself is 2px (medium
   border-width) so it pops against the cell hairlines. */
.lb-calendar__week-now {
  position: absolute;
  left: 0;
  right: 0;
  height: 0;
  border-top: var(--lb-border-width-medium) solid var(--lb-border-danger);
  z-index: 2;
  pointer-events: none;
}
.lb-calendar__week-now-label {
  position: absolute;
  left: 0;
  top: 50%;
  transform: translate(calc(-100% - var(--lb-size-1x)), -50%);
  padding: 0 var(--lb-size-1x);
  background: var(--lb-bg-danger);
  color: var(--lb-fg-inverse-strong);
  border-radius: var(--lb-radius-badge);
  font-family: var(--lb-t-caption-s-font-family);
  font-size: var(--lb-t-caption-s-font-size);
  font-weight: var(--lb-font-weight-bold);
  letter-spacing: 0.08em; /* design-intent: uppercase today-badge tracking (widest, for emphasis) */
  line-height: var(--lb-size-3x);
}

/* Density-overflow popover (Month "+N more"). Floats from <body>;
   anchored via inline left/top set in JS. Z above page, below modal. */
.lb-calendar__more-pop {
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-3);
  padding: var(--lb-size-2x);
  min-width: 16rem; /* design-intent: "+N more" popover min width */
  max-width: 22rem; /* design-intent: "+N more" popover max width */
  z-index: 1000;
}
.lb-calendar__more-pop-head {
  padding: var(--lb-size-1x) var(--lb-size-2x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-default);
}
.lb-calendar__more-pop-list {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  margin-top: var(--lb-size-1x);
}
.lb-calendar__more-pop-row {
  appearance: none;
  display: grid;
  grid-template-columns: var(--lb-size-2x) 4rem 1fr;
  gap: var(--lb-size-2x);
  align-items: center;
  padding: var(--lb-size-1x) var(--lb-size-2x);
  background: none;
  border: none;
  border-radius: var(--lb-radius-field);
  cursor: pointer;
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-default);
  text-align: left;
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-calendar__more-pop-row:hover { background: var(--lb-bg-strong); }
.lb-calendar__more-pop-time {
  font-family: var(--lb-font-family-3);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-calendar__more-pop-title { min-width: 0; }

/* ── Calendar — List / Agenda view ──────────────────────────────
   Built on LB.Accordion (multi-open). Each day is one accordion item;
   today + 2 days ahead start expanded by default, past days always
   start collapsed. Each trigger carries a .lb-counter for the day's
   event count — past days use .lb-counter--subtle so completed days
   read as gone.
   The day-row presentation inside each panel keeps its existing
   .lb-calendar__list-row styling. */

.lb-calendar__list {
  display: flex;
  flex-direction: column;
}
/* Reset the gallery accordion's container padding so day items run
   edge-to-edge (no inset rhythm — the day separators carry the visual
   structure). The Accordion component's own __item border-bottom
   handles separation between items. */
.lb-calendar__list-trigger {
  /* Inherit the canonical accordion trigger treatment (transparent
     bg, ghost interaction tokens). Inset padding so day rows align
     with the gallery edge inset. */
  padding-left: var(--lb-size-4x);
  padding-right: var(--lb-size-4x);
}
/* Today gets the soft accent tint to keep the "you are here" cue
   loud without overwhelming the row. */
.lb-calendar__list-trigger--today {
  background: var(--lb-bg-accent-muted);
}
/* Past days reuse bg-subtle to read as "completed" — same surface
   tone used elsewhere for non-active states. The body of those days
   still expands on demand. */
.lb-calendar__list-trigger--past {
  background: var(--lb-bg-strong);
}
.lb-calendar__list-trigger--past .lb-calendar__list-dow,
.lb-calendar__list-trigger--past .lb-calendar__list-date {
  opacity: 0.6;
}
/* Trigger label cluster — day-of-week + date side-by-side, takes
   `flex: 1` from the existing .lb-accordion__trigger-label rule via
   composition. */
.lb-calendar__list-trigger-label {
  flex: 1;
  display: inline-flex;
  align-items: baseline;
  gap: var(--lb-size-2x);
  min-width: 0;
}
.lb-calendar__list-dow {
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-default);
}
.lb-calendar__list-date {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}
.lb-calendar__list-today {
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  background: var(--lb-bg-accent);
  color: var(--lb-action-fg-primary-default);
  border-radius: var(--lb-radius-badge);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  text-transform: uppercase;
  letter-spacing: 0.06em; /* design-intent: uppercase month-cell badge tracking */
  flex-shrink: 0;
}
/* Past day badge: uses .lb-counter--subtle (see Counter component for
   the disabled-token treatment that makes completed days read as
   "activity gone" rather than "current attention"). */

/* Panel inner — strip the gallery's default bottom padding for a
   tighter rhythm between trigger and rows; rows manage their own
   spacing. */
.lb-calendar__list-panel-inner {
  padding-bottom: 0;
}
.lb-calendar__list-row {
  appearance: none;
  display: grid;
  grid-template-columns: 8rem auto 1fr auto;
  gap: var(--lb-size-3x);
  align-items: center;
  padding: var(--lb-size-2x) var(--lb-size-4x);
  background: var(--lb-surface-bg-default);
  border: none;
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  cursor: pointer;
  text-align: left;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
  width: 100%;
}
.lb-calendar__list-row:first-child { border-top: none; }
.lb-calendar__list-row:hover { background: var(--lb-bg-strong); }
.lb-calendar__list-row:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: calc(-1 * var(--lb-border-width-medium));
}
.lb-calendar__list-row--past { opacity: 0.5; }
.lb-calendar__list-time {
  font-family: var(--lb-font-family-3);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-calendar__list-dot {
  display: inline-block;
  width: var(--lb-size-1-5x);
  height: var(--lb-size-1-5x);
  background: var(--lb-cal-event-color, var(--lb-data-1));
  border-radius: var(--lb-radius-full);
  flex-shrink: 0;
}
.lb-calendar__list-title { min-width: 0; }
.lb-calendar__list-location {
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}
.lb-calendar__list-empty {
  padding: var(--lb-size-2x) var(--lb-size-4x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  font-style: italic;
}
.lb-calendar__list-empty--past { opacity: 0.5; }

/* ── Calendar — Booking intent ──────────────────────────────────
   When `intent="book"`, the time grid hosts slot blocks instead of
   (or alongside) events. Visual treatment differs from events:
   slots invite ACTION, events display info.
   - Available: tinted accent block, hover lifts, pointer cursor
   - Blocked:   greyed neutral block, no hover, not-allowed cursor
   - Selected:  solid accent fill (the slot the user just picked)
   - Past:      reduced opacity + disabled (today only — past days
                hide their slots entirely via the parent column's
                `--past` modifier)
   Slots sit at z-index 0 so events still visually win on overlap. */

.lb-calendar__week-slot {
  position: absolute;
  left: var(--lb-size-1x);
  right: var(--lb-size-1x);
  appearance: none;
  border: var(--lb-border-width-thin) solid var(--lb-action-border-secondary-default);
  border-left: var(--lb-border-width-medium) solid var(--lb-action-border-primary-default);
  background: color-mix(in srgb, var(--lb-action-bg-primary-default) 12%, var(--lb-surface-bg-default));
  color: var(--lb-fg-default);
  border-radius: var(--lb-radius-field);
  padding: var(--lb-size-0-5x) var(--lb-size-1x);
  font-family: var(--lb-t-caption-m-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  text-align: left;
  cursor: pointer;
  z-index: 0;
  display: flex;
  align-items: flex-start;
  transition: background var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui), box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-calendar__week-slot:hover {
  background: color-mix(in srgb, var(--lb-action-bg-primary-default) 22%, var(--lb-surface-bg-default));
  box-shadow: var(--lb-shadow-1);
}
.lb-calendar__week-slot:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: 0;
  z-index: 1;
}
.lb-calendar__week-slot-time {
  font-weight: var(--lb-font-weight-semibold);
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
}

/* Blocked — full / unavailable. Reads as "this slot exists but you
   can't pick it" rather than "this slot doesn't exist". */
.lb-calendar__week-slot--blocked {
  background: var(--lb-bg-disabled);
  border-color: var(--lb-border-disabled);
  border-left-color: var(--lb-border-disabled);
  color: var(--lb-fg-disabled);
  cursor: not-allowed;
}
.lb-calendar__week-slot--blocked:hover {
  background: var(--lb-bg-disabled);
  box-shadow: none;
}
.lb-calendar__week-slot--blocked .lb-calendar__week-slot-time {
  color: var(--lb-fg-disabled);
}

/* Selected — locked-in. Solid accent fill so the user can see at a
   glance which slot they picked, even if scrolled away. */
.lb-calendar__week-slot--selected,
.lb-calendar__week-slot--selected:hover {
  background: var(--lb-action-bg-primary-default);
  border-color: var(--lb-action-border-primary-default);
  border-left-color: var(--lb-action-border-primary-default);
  color: var(--lb-action-fg-primary-default);
  box-shadow: var(--lb-shadow-2);
}
.lb-calendar__week-slot--selected .lb-calendar__week-slot-time {
  color: var(--lb-action-fg-primary-default);
}

/* Past — slots within today that have already happened. Greyed but
   still visible so the user has reference for "what was free
   earlier today" — non-clickable via the disabled attribute. */
.lb-calendar__week-slot--past,
.lb-calendar__week-slot[disabled] {
  opacity: 0.5;
  cursor: not-allowed;
}
.lb-calendar__week-slot[disabled]:hover {
  background: color-mix(in srgb, var(--lb-action-bg-primary-default) 12%, var(--lb-surface-bg-default));
  box-shadow: none;
}

/* Month-view booking indicator — uses the shared .lb-counter--small
   component for the pill shape, colour, and auto-hide behaviour.
   Scoped rule below adds the left margin that separates it from the
   date number in the cell head. */
.lb-calendar__cell-head .lb-counter { margin-left: var(--lb-size-1x); }

/* ═══════════════════════════════════════════════════════════
   CHAT — BUBBLE
   ═══════════════════════════════════════════════════════════ */

/* Message primitive for chat threads. Three role variants:
   user (right-aligned tinted card body), assistant (flat,
   full-width body, no card), system (centred muted caption).
   Four states via data-state: done | streaming | error | edited.
   Slots: avatar | content (header + body + footer). Footer
   action row is hover/focus-revealed. */

.lb-bubble {
  display: grid;
  grid-template-columns: auto 1fr;
  grid-template-areas: "avatar content";
  gap: var(--lb-size-3x);
  padding: var(--lb-size-3x) 0;
  align-items: start;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-default);
}
.lb-bubble__avatar { grid-area: avatar; align-self: start; flex: none; }
.lb-bubble__content {
  grid-area: content;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  min-width: 0;
}
.lb-bubble__header {
  display: flex;
  align-items: baseline;
  gap: var(--lb-size-2x);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-bubble__sender {
  color: var(--lb-fg-default);
  font-weight: var(--lb-t-label-m-font-weight);
}
.lb-bubble__timestamp { color: var(--lb-fg-muted); }
.lb-bubble__body { color: var(--lb-fg-default); }
.lb-bubble__body > p:first-child { margin-top: 0; }
.lb-bubble__body > p:last-child { margin-bottom: 0; }
.lb-bubble__footer {
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
  margin-top: var(--lb-size-1x);
  opacity: 0;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-bubble:hover .lb-bubble__footer,
.lb-bubble:focus-within .lb-bubble__footer { opacity: 1; }

/* User variant — right-aligned tinted card. Avatar flips to the right
   via reversed grid-template-areas. Body is a contained card so the
   user message visually separates from assistant flow. Max-width on
   the body caps long inputs from spanning full width. */
.lb-bubble--user {
  grid-template-columns: 1fr auto;
  grid-template-areas: "content avatar";
}
.lb-bubble--user .lb-bubble__content { align-items: flex-end; }
.lb-bubble--user .lb-bubble__header { flex-direction: row-reverse; }
.lb-bubble--user .lb-bubble__body {
  background: var(--lb-bg-strong);
  border-radius: var(--lb-radius-surface);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  max-width: 75%;
  text-align: left;
}
.lb-bubble--user .lb-bubble__footer { justify-content: flex-end; }

/* Assistant variant — uses base styles. Flat text, full content
   width, no card. Footer aligns left under the body. */

/* System variant — centred caption, no avatar, no header, no footer.
   Used for status messages: "Chat title updated", "Connection lost",
   "Memory updated", etc. */
.lb-bubble--system {
  grid-template-columns: 1fr;
  grid-template-areas: "content";
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  color: var(--lb-fg-muted);
  text-align: center;
  padding: var(--lb-size-2x) 0;
}
.lb-bubble--system .lb-bubble__avatar,
.lb-bubble--system .lb-bubble__header,
.lb-bubble--system .lb-bubble__footer { display: none; }
.lb-bubble--system .lb-bubble__content { align-items: center; }

/* State: streaming — blinking caret at end of body. Uses an inline-
   block ::after that rides at the end of the last text node. Reduced-
   motion users get a static dim caret instead of blink. */
.lb-bubble[data-state="streaming"] .lb-bubble__body::after {
  content: '';
  display: inline-block;
  width: 0.4em;
  height: 1em;
  background: var(--lb-fg-default);
  vertical-align: -0.15em;
  margin-left: 2px;
  animation: lb-bubble-caret 1s steps(2) infinite;
}
@keyframes lb-bubble-caret { 50% { opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .lb-bubble[data-state="streaming"] .lb-bubble__body::after {
    animation: none;
    opacity: 0.6;
  }
}

/* State: error — danger-tinted border on body. Padded so the border
   sits cleanly around the message content. User-variant errors get
   a subtle background tint so the card shape stays consistent. */
.lb-bubble[data-state="error"] .lb-bubble__body {
  border: var(--lb-border-width-thin) solid var(--lb-border-danger);
  border-radius: var(--lb-radius-surface);
  padding: var(--lb-size-2x) var(--lb-size-3x);
}
.lb-bubble--user[data-state="error"] .lb-bubble__body {
  background: var(--lb-bg-danger-subtle);
}

/* State: edited — appends "(edited)" after the timestamp. Subtle by
   design: the edit is disclosed, not advertised. */
.lb-bubble[data-state="edited"] .lb-bubble__timestamp::after {
  content: ' (edited)';
  color: var(--lb-fg-subtle);
}

/* ═══════════════════════════════════════════════════════════
   CHAT — THREAD
   ═══════════════════════════════════════════════════════════ */

/* Host for chat bubbles. Scrolls. Auto-stick at bottom when content
   grows IF the user was at bottom. Jump-to-bottom pill appears
   bottom-right when scrolled away. Container is relatively positioned
   so the absolute-positioned pill anchors to it. */

.lb-thread {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-3x) var(--lb-size-4x);
  overflow-y: auto;
  scrollbar-gutter: stable;
}

.lb-thread__jump-pill {
  position: absolute;
  right: var(--lb-size-4x);
  bottom: var(--lb-size-3x);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-8x);
  height: var(--lb-size-8x);
  padding: 0;
  border: var(--lb-border-width-thin) solid var(--lb-border-strong);
  border-radius: var(--lb-radius-full);
  background: var(--lb-surface-bg-overlay);
  color: var(--lb-fg-default);
  box-shadow: var(--lb-shadow-dropdown);
  cursor: pointer;
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition: opacity var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui),
              transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
}
.lb-thread__jump-pill:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-thread__jump-pill:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
}
.lb-thread__jump-pill [data-lb-icon],
.lb-thread__jump-pill svg {
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
}
.lb-thread--has-jump .lb-thread__jump-pill {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}

/* ═══════════════════════════════════════════════════════════
   CHAT — COMPOSER
   ═══════════════════════════════════════════════════════════ */

/* Input dock. Slice 2 minimum: rounded card containing a single
   row with an autogrowing textarea on the left and a send/stop
   button on the right. Slice 4 adds the attachment row above,
   tool chips, model picker, mic. The card's outer container is
   the focus host — focus-within highlights the whole card. */

.lb-composer {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  background: var(--lb-surface-bg-elevated);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  /* Overlay radius (not card): the composer is a standalone SURFACE
     hovering the canvas — the 2026 AI-composer look — not an inline
     form field, so it doesn't need to align with input corners. */
  border-radius: var(--lb-radius-overlay);
  transition: border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              box-shadow var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-composer:focus-within {
  border-color: var(--lb-border-focus);
  box-shadow: 0 0 0 var(--lb-border-width-thin) var(--lb-border-focus);
}

.lb-composer__row {
  display: flex;
  align-items: flex-end;
  gap: var(--lb-size-2x);
}

/* Textarea: no border or background, fills width, autogrows up
   to ~10 lines (height capped in JS at 240px). Resize handle off
   since we manage height programmatically. */
.lb-composer__input,
[data-lb-composer-input] {
  flex: 1;
  min-height: var(--lb-size-8x);
  max-height: 240px;
  padding: var(--lb-size-1x) 0;
  border: none;
  background: transparent;
  outline: none;
  resize: none;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-default);
  overflow-y: auto;
}
.lb-composer__input::placeholder,
[data-lb-composer-input]::placeholder {
  color: var(--lb-fg-muted);
}

.lb-composer__actions {
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
  flex: none;
}

/* Send / stop buttons — sized consistently with the icon-btn rhythm
   on the rest of the system. The two share the same physical slot;
   only one is visible at a time based on composer state. */
[data-lb-composer-send],
[data-lb-composer-stop] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-8x);
  height: var(--lb-size-8x);
  padding: 0;
  border: none;
  border-radius: var(--lb-radius-full);
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
[data-lb-composer-send] {
  background: var(--lb-action-bg-primary-default);
  color: var(--lb-action-fg-primary-default);
}
[data-lb-composer-send]:hover:not(:disabled) {
  background: var(--lb-action-bg-primary-hover);
}
[data-lb-composer-send]:disabled {
  background: var(--lb-action-bg-primary-disabled);
  color: var(--lb-action-fg-primary-disabled);
  cursor: not-allowed;
}
[data-lb-composer-stop] {
  background: var(--lb-action-bg-secondary-default);
  color: var(--lb-action-fg-secondary-default);
  border: var(--lb-border-width-action) solid var(--lb-action-border-secondary-default);
}
[data-lb-composer-stop]:hover {
  background: var(--lb-action-bg-secondary-hover);
}
[data-lb-composer-send] [data-lb-icon],
[data-lb-composer-stop] [data-lb-icon],
[data-lb-composer-send] svg,
[data-lb-composer-stop] svg {
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
}

/* ═══════════════════════════════════════════════════════════
   CHAT — BRANCHING + INLINE EDIT
   ═══════════════════════════════════════════════════════════ */

.lb-bubble__branch-nav {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-0-5x);
  margin-right: var(--lb-size-2x);
  padding-right: var(--lb-size-2x);
  border-right: var(--lb-border-width-thin) solid var(--lb-border-muted);
  opacity: 1;
}
.lb-bubble__branch-count {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
  min-width: var(--lb-size-8x);
  text-align: center;
}

.lb-bubble--branch-hidden { display: none; }

.lb-bubble__edit {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  background: var(--lb-surface-bg-elevated);
  border: var(--lb-border-width-thin) solid var(--lb-border-focus);
  border-radius: var(--lb-radius-surface);
  padding: var(--lb-size-2x) var(--lb-size-3x);
}
.lb-bubble__edit-input {
  width: 100%;
  min-height: var(--lb-size-10x);
  max-height: 320px;
  border: none;
  background: transparent;
  outline: none;
  resize: none;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  line-height: var(--lb-t-body-m-line-height);
  color: var(--lb-fg-default);
}
.lb-bubble__edit-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--lb-size-1x);
}
.lb-bubble--editing .lb-bubble__footer { opacity: 0.3; pointer-events: none; }

/* ═══════════════════════════════════════════════════════════
   CHAT — COMPOSER WORKBENCH (Slice 4)
   ═══════════════════════════════════════════════════════════ */

/* Composer's three-section layout when workbench markup is present:
   - top    chip row (removable context items: attached files, etc.)
   - middle textarea row with attach button + actions
   - bottom tool toggle chips + model picker
   The container reuses the existing .lb-composer card styling; these
   rules add the extra slots. */

/* Dragover state — highlight the whole card when a file is dragged
   anywhere onto the composer. */
.lb-composer--dragover {
  border-color: var(--lb-border-accent);
  /* muted, not subtle: a transient highlight needs visible presence —
     post-GAP-12 subtle is a near-invisible wash */
  background: var(--lb-bg-accent-muted);
}

/* Chips row (above the textarea) */
.lb-composer__chips {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-1x);
  padding-bottom: var(--lb-size-1x);
}
.lb-composer__chips--empty { display: none; }

.lb-composer-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  background: var(--lb-bg-strong);
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  border-radius: var(--lb-radius-full);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-default);
  max-width: 100%;
}
.lb-composer-chip__icon {
  display: inline-flex;
  width: var(--lb-size-3-5x);
  height: var(--lb-size-3-5x);
  color: var(--lb-fg-muted);
}
.lb-composer-chip__label {
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 200px;
}
.lb-composer-chip__remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-3-5x);
  height: var(--lb-size-3-5x);
  padding: 0;
  border: none;
  background: transparent;
  color: var(--lb-fg-muted);
  cursor: pointer;
  border-radius: var(--lb-radius-full);
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-composer-chip__remove:hover {
  background: var(--lb-bg-bolder);
  color: var(--lb-fg-default);
}
.lb-composer-chip__remove [data-lb-icon],
.lb-composer-chip__remove svg { width: var(--lb-size-3x); height: var(--lb-size-3x); }

/* Attach button (leading +) */
[data-lb-composer-attach] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-8x);
  height: var(--lb-size-8x);
  padding: 0;
  border: none;
  border-radius: var(--lb-radius-full);
  background: transparent;
  color: var(--lb-fg-muted);
  cursor: pointer;
  flex: none;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
[data-lb-composer-attach]:hover {
  background: var(--lb-action-bg-ghost-hover);
  color: var(--lb-fg-default);
}
[data-lb-composer-attach] [data-lb-icon],
[data-lb-composer-attach] svg { width: var(--lb-size-5x); height: var(--lb-size-5x); }

/* Mic button — same look as attach, sits in actions row */
[data-lb-composer-mic] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-8x);
  height: var(--lb-size-8x);
  padding: 0;
  border: none;
  border-radius: var(--lb-radius-full);
  background: transparent;
  color: var(--lb-fg-muted);
  cursor: pointer;
  flex: none;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
[data-lb-composer-mic]:hover {
  background: var(--lb-action-bg-ghost-hover);
  color: var(--lb-fg-default);
}
[data-lb-composer-mic] [data-lb-icon],
[data-lb-composer-mic] svg { width: var(--lb-size-5x); height: var(--lb-size-5x); }

/* Footer row: tools left, model picker right */
.lb-composer__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-2x);
}
/* Right cluster of the footer: model selector + send/stop. The input
   row above holds ONLY the textarea (full width) — all actions live in
   this bottom bar (owner call 2026-07-30). */
.lb-composer__end {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  flex-shrink: 0;
  padding-top: var(--lb-size-1x);
  flex-wrap: wrap;
}
.lb-composer__tools {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-1x);
}
.lb-composer__model { flex: none; position: relative; }

/* Tool toggle chips */
.lb-composer-tool {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  background: transparent;
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  border-radius: var(--lb-radius-full);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              border-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-composer-tool:hover {
  border-color: var(--lb-border-strong);
  color: var(--lb-fg-default);
}
.lb-composer-tool--active {
  background: var(--lb-action-bg-selected);
  border-color: var(--lb-action-border-selected);
  color: var(--lb-action-fg-selected);
}
.lb-composer-tool__icon {
  display: inline-flex;
  width: var(--lb-size-3-5x);
  height: var(--lb-size-3-5x);
}

/* Model picker */
.lb-composer-model {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-0-5x) var(--lb-size-2x);
  background: transparent;
  border: none;
  border-radius: var(--lb-radius-interactive);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-composer-model:hover {
  background: var(--lb-action-bg-ghost-hover);
  color: var(--lb-fg-default);
}
.lb-composer-model__chevron { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); }
.lb-composer-model__menu {
  position: absolute;
  right: 0;
  bottom: 100%;
  margin-bottom: var(--lb-size-1x);
  min-width: 200px;
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-dropdown);
  padding: var(--lb-size-1x) 0;
  z-index: 100;
}
.lb-composer-model__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--lb-size-1x) var(--lb-size-3x);
  background: transparent;
  border: none;
  color: var(--lb-fg-default);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  cursor: pointer;
}
.lb-composer-model__item:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-composer-model__item--active { color: var(--lb-fg-accent); font-weight: var(--lb-t-label-m-font-weight); }

/* Slash command palette — appears anchored to the bottom of the
   composer card, opens above the input. Auto-removes when slash
   condition exits or input blurs. */
.lb-composer { position: relative; }
.lb-composer-slash {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  margin-bottom: var(--lb-size-1x);
  background: var(--lb-surface-bg-overlay);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-overlay);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-dropdown);
  padding: var(--lb-size-1x) 0;
  max-height: 280px;
  overflow-y: auto;
  z-index: 100;
}
.lb-composer-slash__empty {
  padding: var(--lb-size-2x) var(--lb-size-3x);
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-composer-slash__item {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-1x) var(--lb-size-3x);
  cursor: pointer;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
}
.lb-composer-slash__item:hover,
.lb-composer-slash__item--active { background: var(--lb-action-bg-ghost-hover); }
.lb-composer-slash__icon { width: var(--lb-size-4x); height: var(--lb-size-4x); color: var(--lb-fg-muted); }
.lb-composer-slash__id {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-accent);
  min-width: 60px;
}
.lb-composer-slash__label { flex: 1; }
.lb-composer-slash__hint { color: var(--lb-fg-muted); font-size: var(--lb-t-caption-m-font-size); }

/* ═══════════════════════════════════════════════════════════
   CHAT — TOOL CALL CARD (Slice 5)
   ═══════════════════════════════════════════════════════════ */

/* Collapsible card showing one tool invocation. Header is a clickable
   button (one-line: icon + tool name + verb + status + chevron). Body
   has Formatted / Raw I/O tabs and an optional confirm gate for risky
   ops. Toggles via data-expanded; collapsed body is display:none. */

.lb-tool-call {
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  border-radius: var(--lb-radius-surface);
  background: var(--lb-surface-bg-default);
  margin: var(--lb-size-1x) 0;
  overflow: hidden;
}
.lb-tool-call[data-status="error"] {
  border-color: var(--lb-border-danger);
  background: var(--lb-bg-danger-subtle);
}
.lb-tool-call[data-status="awaiting-confirm"] {
  border-color: var(--lb-border-warning);
  background: var(--lb-bg-warning-subtle);
}

.lb-tool-call__head {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  width: 100%;
  padding: var(--lb-size-2x) var(--lb-size-3x);
  background: transparent;
  border: none;
  cursor: pointer;
  text-align: left;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-tool-call__head:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-tool-call__head:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: calc(-1 * var(--lb-border-width-medium));
}

.lb-tool-call__icon {
  display: inline-flex;
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  color: var(--lb-fg-muted);
  flex: none;
}

.lb-tool-call__summary {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  flex: 1;
  min-width: 0;
}
.lb-tool-call__name {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-tool-call__verb {
  color: var(--lb-fg-default);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Status pill now uses .lb-badge — see lb-chat.js TOOL_STATUS_BADGE
   for the variant + icon mapping. The badge primitive supplies its
   own colour/border/spacing tokens; we only need to make sure it
   doesn't get squeezed by the flexible summary slot. */
[data-lb-tool-call-status] { flex: none; }

.lb-tool-call__chevron {
  display: inline-flex;
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  color: var(--lb-fg-muted);
  flex: none;
  transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-tool-call[data-expanded="true"] .lb-tool-call__chevron { transform: rotate(180deg); }

/* Body — collapsed by default. data-expanded="true" reveals it. */
.lb-tool-call__body { display: none; border-top: var(--lb-border-width-thin) solid var(--lb-border-muted); }
.lb-tool-call[data-expanded="true"] .lb-tool-call__body { display: block; }

.lb-tool-call__tabs {
  display: flex;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-1x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
}
.lb-tool-call__tab {
  padding: var(--lb-size-1x) var(--lb-size-2x);
  background: transparent;
  border: none;
  border-radius: var(--lb-radius-interactive);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-body-s-font-size);
  cursor: pointer;
  transition: background-color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui),
              color var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-tool-call__tab:hover { color: var(--lb-fg-default); }
.lb-tool-call__tab--active {
  background: var(--lb-bg-strong);
  color: var(--lb-fg-default);
}

.lb-tool-call__formatted,
.lb-tool-call__raw {
  padding: var(--lb-size-3x);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
  color: var(--lb-fg-default);
}

.lb-tool-call__section { margin-bottom: var(--lb-size-3x); }
.lb-tool-call__section:last-child { margin-bottom: 0; }
.lb-tool-call__section-label {
  font-family: var(--lb-t-body-s-font-family);
  font-size: var(--lb-t-caption-m-font-size);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--lb-fg-muted);
  margin-bottom: var(--lb-size-1x);
}
.lb-tool-call__section-body { color: var(--lb-fg-default); }

.lb-tool-call__raw-block {
  background: var(--lb-bg-bolder);
  border: var(--lb-border-width-thin) solid var(--lb-border-muted);
  border-radius: var(--lb-radius-interactive);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  margin: 0;
  font-family: var(--lb-t-code-m-font-family, 'Roboto Mono', monospace);
  font-size: var(--lb-t-body-s-font-size);
  line-height: 1.55;
  color: var(--lb-fg-default);
  overflow-x: auto;
  white-space: pre;
}

/* Confirm gate — for risky tools (shell, file write, etc.). Shown
   above the tabs so user sees it first. */
.lb-tool-call__confirm {
  padding: var(--lb-size-3x);
  background: var(--lb-bg-warning-subtle);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-warning);
}
.lb-tool-call__confirm-msg {
  margin: 0 0 var(--lb-size-2x);
  color: var(--lb-fg-warning);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-m-font-size);
}
.lb-tool-call__confirm-actions {
  display: flex;
  gap: var(--lb-size-1x);
  justify-content: flex-end;
}

/* ─── CONVERSATION LIST (sidebar) ─── */
/* Slim sidebar for chat history. Sections by date bucket, optional
   search box, pinned bucket, color-tag stripe, kebab popover. */
.lb-conv-list {
  display: flex;
  flex-direction: column;
  min-height: 0;
  background: var(--lb-bg-default);
  border-right: var(--lb-border-width-thin) solid var(--lb-border-muted);
  font-family: var(--lb-t-body-m-font-family);
}
.lb-conv-list__search {
  padding: var(--lb-size-2x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  flex: 0 0 auto;
}
/* Stretch the consumed .lb-input-wrap to fill the search row — the input
   primitive's own sizing rules drive everything else. */
.lb-conv-list__search > .lb-input-wrap { width: 100%; }
.lb-conv-list__search .lb-input { width: 100%; }

.lb-conv-list__items {
  list-style: none;
  margin: 0;
  padding: var(--lb-size-1x) 0;
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
}
.lb-conv-list__group-header {
  padding: var(--lb-size-3x) var(--lb-size-3x) var(--lb-size-1x);
  margin-top: var(--lb-size-2x);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  line-height: var(--lb-t-body-xs-line-height);
  font-weight: var(--lb-font-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-top: var(--lb-border-width-thin) solid var(--lb-border-muted);
}
/* First header doesn't need a top divider — the search row's bottom
   border above it already provides the separation. */
.lb-conv-list__items > .lb-conv-list__group-header:first-child {
  border-top: 0;
  margin-top: 0;
}
.lb-conv-list__empty {
  padding: var(--lb-size-4x) var(--lb-size-3x);
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-s-font-size);
  text-align: center;
}

/* ── Single conversation row ── */
.lb-conv {
  position: relative;
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  margin: 0 var(--lb-size-1x);
  padding: var(--lb-size-2x) var(--lb-size-2x);
  border-radius: var(--lb-radius-interactive);
  cursor: pointer;
  color: var(--lb-fg-default);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
}
.lb-conv:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-conv:focus-visible {
  outline: var(--lb-border-width-action) solid var(--lb-border-default);
  outline-offset: -2px;
}
.lb-conv--active { background: var(--lb-action-bg-selected); }
.lb-conv--active:hover { background: var(--lb-action-bg-selected); }

/* Color-tag stripe: 3px ribbon on the leading edge, only when --lb-conv-tag is set. */
.lb-conv--tagged::before {
  content: '';
  position: absolute;
  left: 0;
  top: 4px;
  bottom: 4px;
  width: 3px;
  border-radius: 0 var(--lb-radius-2) var(--lb-radius-2) 0;
  background: var(--lb-conv-tag, transparent);
}

.lb-conv__pin {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-3-5x);
  height: var(--lb-size-3-5x);
  color: var(--lb-fg-muted);
}
.lb-conv__pin svg { width: 100%; height: 100%; }

.lb-conv__title {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* The title is the row's real <button> (aria-current marks the open
     conversation) — reset chrome so it reads as row text. */
  background: none;
  border: 0;
  margin: 0;
  padding: 0;
  font: inherit;
  color: inherit;
  text-align: left;
  cursor: pointer;
}
.lb-conv__title:focus-visible {
  outline: var(--lb-border-width-medium) solid var(--lb-border-focus);
  outline-offset: var(--lb-size-0-5x);
  border-radius: var(--lb-radius-interactive);
}
.lb-conv__unread {
  flex: 0 0 auto;
  min-width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  padding: 0 var(--lb-size-1x);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: var(--lb-action-bg-primary-default);
  color: var(--lb-action-fg-primary-default);
  border-radius: var(--lb-radius-9999);
  font-size: var(--lb-t-body-xs-font-size);
  font-weight: var(--lb-font-weight-medium);
  line-height: 1;
}
.lb-conv__kebab {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-5x);
  height: var(--lb-size-5x);
  padding: 0;
  background: transparent;
  border: 0;
  border-radius: var(--lb-radius-interactive);
  color: var(--lb-fg-muted);
  cursor: pointer;
  opacity: 0;
  transition: opacity 0.12s ease;
}
.lb-conv:hover .lb-conv__kebab,
.lb-conv:focus-within .lb-conv__kebab,
.lb-conv--active .lb-conv__kebab,
.lb-conv .lb-conv__kebab[aria-expanded="true"] { opacity: 1; }
.lb-conv__kebab:hover { background: var(--lb-action-bg-ghost-hover); color: var(--lb-fg-default); }
.lb-conv__kebab:focus-visible {
  opacity: 1;
  outline: var(--lb-border-width-action) solid var(--lb-border-default);
  outline-offset: -2px;
}
.lb-conv__kebab svg { width: 16px; height: 16px; }

/* Kebab popover surface — positioning only. The .lb-menu primitive
   already supplies background, border, radius, shadow, item styling.
   This helper class exists just to mark the surface for any future
   ConvList-specific tweaks (none right now). */
.lb-conv-list__kebab-surface { /* inherits .lb-menu */ }

/* ─── CONTEXT BUDGET BAR ─── */
/* Compact horizontal bar showing context-window pressure. Used by
   ChatWorkspace header; reusable wherever pressure visualisation is
   needed. Tone shifts at 70% / 85% via data-tone. */
.lb-context-budget-bar {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-2x);
  min-width: 9rem;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  line-height: var(--lb-t-body-xs-line-height);
  color: var(--lb-fg-muted);
}
/* --compact: mini footer/toolbar variant — no reserved min-width, the
   track fixed at a small sliver; label keeps natural size. */
.lb-context-budget-bar--compact { min-width: 0; gap: var(--lb-size-1-5x); }
.lb-context-budget-bar--compact .lb-context-budget-bar__track { flex: 0 0 auto; width: 1.8rem; min-width: 0; height: var(--lb-size-2x); /* design-intent: mini track — short but THICKER (8px vs the default 4px) so it stays legible */ }
.lb-context-budget-bar__label {
  flex: 0 0 auto;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.lb-context-budget-bar__track {
  flex: 1 1 auto;
  position: relative;
  height: var(--lb-size-1x);
  background: var(--lb-bg-bolder);
  border-radius: var(--lb-radius-9999);
  overflow: hidden;
  min-width: 4rem;
}
.lb-context-budget-bar__fill {
  position: absolute;
  inset: 0 auto 0 0;
  width: 0;
  background: var(--lb-fg-muted);
  border-radius: inherit;
  transition: width 0.18s ease, background 0.18s ease;
}
.lb-context-budget-bar[data-tone="warning"] { color: var(--lb-fg-warning); }
.lb-context-budget-bar[data-tone="warning"] .lb-context-budget-bar__fill { background: var(--lb-fg-warning); }
.lb-context-budget-bar[data-tone="danger"]  { color: var(--lb-fg-danger); }
.lb-context-budget-bar[data-tone="danger"]  .lb-context-budget-bar__fill { background: var(--lb-fg-danger); }

/* ─── CHAT WORKSPACE SHELL ─── */
/* Opt-in dashboard. Composes sidebar (ConvList), main (Thread +
   Composer), optional right rail (Artifact panel / Settings panel).
   Body row is a plain flex with FIXED-PIXEL sidebar + rail and a
   flexing main. Two custom drag handles adjust the two CSS vars
   --lb-sidebar-width and --lb-rail-width independently — so closing
   the rail does NOT reflow the sidebar. */
.lb-chat-workspace {
  --lb-sidebar-width: 18rem;
  --lb-rail-width: 28rem;
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  min-height: 0;
  background: var(--lb-bg-default);
  color: var(--lb-fg-default);
  font-family: var(--lb-t-body-m-font-family);
  position: relative;
  overflow: hidden;
}
.lb-chat-workspace__body {
  flex: 1 1 auto;
  display: flex;
  align-items: stretch;
  min-height: 0;
  min-width: 0;
}
/* Sidebar handle + rail handle reuse the LB.Resizable visual surface
   (.lb-resizable__handle gives them background + transition +
   pointer-events:none on the ::before line). The positioning of the
   line is normally provided by .lb-resizable--horizontal — which
   doesn't apply here since our body isn't a Resizable container — so
   we redeclare the horizontal positioning explicitly. */
.lb-chat-workspace__sidebar-handle,
.lb-chat-workspace__rail-handle {
  flex: 0 0 var(--lb-resizable-handle-size, 0.5rem);
  position: relative;
  cursor: col-resize;
  align-self: stretch;
  z-index: 1;
}
.lb-chat-workspace__sidebar-handle::before,
.lb-chat-workspace__rail-handle::before {
  top: 0;
  bottom: 0;
  left: 50%;
  width: var(--lb-border-width-thin);
  transform: translateX(-50%);
}
.lb-chat-workspace__sidebar-handle:hover::before,
.lb-chat-workspace__rail-handle:hover::before,
.lb-chat-workspace__sidebar-handle--dragging::before,
.lb-chat-workspace__rail-handle--dragging::before {
  background: var(--lb-border-emphasis, var(--lb-border-default));
  width: var(--lb-border-width-action);
}
/* Hide the rail handle when the rail is collapsed. */
.lb-chat-workspace__body:has(.lb-chat-workspace__rail[hidden]) .lb-chat-workspace__rail-handle { display: none; }
/* When sidebar is collapsed (hamburger), hide its handle too. */
.lb-chat-workspace[data-sidebar-collapsed="true"] .lb-chat-workspace__sidebar,
.lb-chat-workspace[data-sidebar-collapsed="true"] .lb-chat-workspace__sidebar-handle {
  display: none;
}
/* While a handle is being dragged, prevent text selection across
   the whole workspace so the cursor doesn't flicker. */
.lb-chat-workspace--dragging,
.lb-chat-workspace--dragging * { user-select: none; cursor: col-resize !important; }

/* ── Header ── */
.lb-chat-workspace__header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  padding: var(--lb-size-2x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-bg-default);
  min-height: var(--lb-size-12x);
  box-sizing: border-box;
}
/* Hamburger consumes .lb-icon-btn + .lb-btn--ghost — no per-button
   styling here. This selector exists only so JS can find it. */
.lb-chat-workspace__hamburger { flex: 0 0 auto; }

.lb-chat-workspace__title {
  flex: 0 1 auto;
  min-width: 0;
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.lb-chat-workspace__mode { flex: 0 0 auto; }
.lb-chat-workspace__actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
  margin-left: auto;
}
/* Budget bar now lives at the foot of main (under the composer
   frame). Full width, slim top border so it reads as part of the
   chat surface chrome rather than a separate dock. */
.lb-chat-workspace__main > .lb-chat-workspace__budget {
  flex: 0 0 auto;
  padding: var(--lb-size-1-5x) var(--lb-size-4x);
  border-top: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-bg-default);
}
.lb-chat-workspace__main > .lb-chat-workspace__budget > .lb-context-budget-bar {
  display: flex;
  width: 100%;
  max-width: var(--lb-chat-thread-width, 768px);
  margin: 0 auto;
}

/* ── Sidebar ── */
/* Fixed-pixel width driven by --lb-sidebar-width (the workspace's
   own custom property). User-adjustable via the sidebar handle.
   The 1px visual divider is drawn by .lb-resizable__handle::before
   from the handle that sits to its right. */
.lb-chat-workspace__sidebar {
  flex: 0 0 var(--lb-sidebar-width, 18rem);
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--lb-bg-default);
  position: relative;
  overflow: hidden;
}
.lb-chat-workspace__sidebar-body {
  flex: 1 1 auto;
  min-height: 0;
  overflow: hidden;
  display: flex;
  flex-direction: column;
}
.lb-chat-workspace__sidebar-body > [data-lb-conv-list] {
  flex: 1 1 auto;
  min-height: 0;
}

/* Layout switcher in the sidebar — sits above the search row in the
   ConvList so workspace mode changes are high-discoverability. The
   bottom border butts up against the ConvList's own search-row top
   padding, so the two rows feel like a single chrome strip. */
.lb-chat-workspace__layout-bar {
  flex: 0 0 auto;
  padding: var(--lb-size-2x) var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-bg-default);
}
.lb-chat-workspace__layout-bar[hidden] { display: none; }

/* Settings gear in the header — uses .lb-icon-btn styling for the
   button shape; this selector exists only as a hook for JS lookup. */
.lb-chat-workspace__settings-btn { flex: 0 0 auto; }
/* Sidebar close button — visible only in the mobile drawer breakpoint
   (see the @media block below). All visual styling comes from
   .lb-icon-btn + .lb-btn--ghost. */
.lb-chat-workspace__sidebar-close {
  display: none;
  position: absolute;
  top: var(--lb-size-2x);
  right: var(--lb-size-2x);
  z-index: 2;
}

/* ── Main ── */
.lb-chat-workspace__main {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  position: relative;
  overflow: hidden;
}
.lb-chat-workspace__thread-frame {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0 var(--lb-size-4x);
  overflow: hidden;
}
.lb-chat-workspace__thread-frame > [data-lb-thread] {
  flex: 1 1 auto;
  min-height: 0;
  width: 100%;
  max-width: var(--lb-chat-thread-width, 768px);
}
.lb-chat-workspace__composer-frame {
  flex: 0 0 auto;
  display: flex;
  justify-content: center;
  padding: var(--lb-size-3x) var(--lb-size-4x) var(--lb-size-4x);
  border-top: var(--lb-border-width-thin) solid var(--lb-border-muted);
  background: var(--lb-bg-default);
}
.lb-chat-workspace__composer-frame > [data-lb-composer] {
  width: 100%;
  max-width: var(--lb-chat-thread-width, 768px);
}

/* ── Rail ── */
/* Fixed-pixel width driven by --lb-rail-width. User-adjustable via
   the rail handle. [hidden] fully collapses it (display:none) so
   the body flex row reflows — main fills the freed space and the
   sidebar stays at its current pixel width. */
.lb-chat-workspace__rail {
  flex: 0 0 var(--lb-rail-width, 28rem);
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  background: var(--lb-bg-default);
  overflow: hidden;
}
.lb-chat-workspace__rail[hidden] { display: none; }

/* ── Scrim ── */
.lb-chat-workspace__scrim {
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--lb-bg-overlay) 40%, transparent);
  z-index: 4;
  display: none;
}

/* ── Mobile breakpoint ── */
@media (max-width: 720px) {
  /* Sidebar leaves the resizable flow and floats above main as a drawer.
     The Resizable handle inside __panels is hidden — there is nothing
     to resize when one panel is overlaid. */
  .lb-chat-workspace__sidebar {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    width: 80vw;
    max-width: 20rem;
    z-index: 5;
    transform: translateX(-100%);
    transition: transform 0.18s ease;
    box-shadow: var(--lb-shadow-dropdown);
    flex: 0 0 auto;
  }
  .lb-chat-workspace__panels > .lb-resizable__handle { display: none; }
  .lb-chat-workspace[data-mobile-drawer="open"] .lb-chat-workspace__sidebar {
    transform: translateX(0);
  }
  .lb-chat-workspace__sidebar-close { display: inline-flex; }
  .lb-chat-workspace[data-mobile-drawer="open"] .lb-chat-workspace__scrim { display: block; }
  /* Rail collapses out on mobile — consumer is expected to open it as a
     full-screen sheet via their own pattern (Slice 9 lands the sheet UI). */
  .lb-chat-workspace__rail { display: none; }
  /* Sidebar-collapsed has no desktop meaning on mobile — drawer is the model. */
  .lb-chat-workspace[data-sidebar-collapsed="true"] .lb-chat-workspace__sidebar { display: flex; }
  .lb-chat-workspace__thread-frame { padding: 0 var(--lb-size-3x); }
  .lb-chat-workspace__composer-frame { padding: var(--lb-size-2x) var(--lb-size-3x) var(--lb-size-3x); }
}

/* ─── ARTIFACT PANEL ─── */
/* Right-rail panel for code / preview artifacts. All buttons come from .lb-icon-btn, the
   tabs from .lb-tabs, the selects from .lb-select-field, the code
   view from .lb-code-block — this file only adds the panel layout. */
.lb-artifact {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--lb-bg-default);
}
.lb-artifact[hidden] { display: none; }

/* ── Header (title row + toolbar) ── */
.lb-artifact__header {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
}
.lb-artifact__title-row {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x) var(--lb-size-3x) var(--lb-size-2x);
}
.lb-artifact__title-group {
  flex: 1 1 auto;
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  min-width: 0;
}
.lb-artifact__icon {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  color: var(--lb-fg-muted);
}
.lb-artifact__icon svg { width: 100%; height: 100%; }
.lb-artifact__title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-artifact__close { flex: 0 0 auto; }

/* Toolbar: tabs on the left, selects + actions on the right. Wraps
   gracefully when the rail is narrow. */
.lb-artifact__toolbar {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: 0 var(--lb-size-3x);
  flex-wrap: wrap;
}
/* The Tabs primitive owns .lb-tabs styling. We just trim its panel
   padding because the panel content has its own scroll region and
   our header already provides vertical breathing room. */
.lb-artifact__tabs { flex: 0 0 auto; }
.lb-artifact__switcher,
.lb-artifact__versions {
  flex: 0 1 auto;
  min-width: 0;
}
.lb-artifact__switcher[hidden],
.lb-artifact__versions[hidden] { display: none; }
.lb-artifact__actions {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--lb-size-0-5x);
  margin-left: auto;
}

/* ── Body (tab panels) ── */
.lb-artifact__body {
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.lb-artifact__panel {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  padding: var(--lb-size-3x);
}
.lb-artifact__panel[hidden] { display: none; }
.lb-artifact__panel--code { padding: var(--lb-size-3x); }
.lb-artifact__panel--code > .lb-code-block { margin: 0; }

.lb-artifact__preview-slot {
  min-height: 0;
}

.lb-artifact__empty {
  padding: var(--lb-size-6x) var(--lb-size-4x);
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  text-align: center;
}


/* ─── COMPOSER — POPOVER VARIANT ─── */
/* Compact composer for the popover-anchored pattern (Timeline
   selection, text-selection on a canvas surface, etc.). Same internal
   structure as the standalone composer — same chips/row/footer slots,
   same LB.Composer engine — just tighter and stripped of the card
   chrome (the surrounding .lb-popover supplies background, border,
   shadow). Footer hidden when no tools/models are configured. */
.lb-composer-popover-surface {
  /* Override the .lb-popover defaults: composer needs more horizontal
     room than the generic popover allows. */
  min-width: 22rem;
  max-width: 32rem;
  padding: var(--lb-size-2x);
}
.lb-composer-popover-surface .lb-composer--popover {
  /* Strip the card chrome — surface already has it. */
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
  gap: var(--lb-size-1x);
}
.lb-composer-popover-surface .lb-composer--popover:focus-within {
  box-shadow: none;
}
.lb-composer-popover-surface .lb-composer--popover [data-lb-composer-input] {
  min-height: var(--lb-size-6x);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
}
.lb-composer-popover-surface .lb-composer--popover .lb-composer__footer {
  padding-top: var(--lb-size-1x);
  border-top: var(--lb-border-width-thin) solid var(--lb-border-muted);
}

/* Layout C — Timeline composition. The timeline takes the main
   column; the composer is summoned imperatively via
   LB.openComposerPopover anchored to the user's selection rect. */
.lb-chat-workspace__timeline-frame {
  flex: 1 1 auto;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-4x);
  padding: var(--lb-size-4x);
  min-height: 0;
  overflow: auto;
}
.lb-chat-workspace__timeline-hint {
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  text-align: center;
  padding: var(--lb-size-2x) var(--lb-size-4x);
  background: var(--lb-bg-bolder);
  border-radius: var(--lb-radius-interactive);
}

/* ─── SETTINGS PANEL (workspace-level) ─── */
/* Opens in the rail — same slot as the Artifact panel, but only one
   tenant lives there at a time. Layout: scrollable column of sections
   (Appearance, Keyboard shortcuts, About by default; consumers add
   more via ws.addSettingsSection({id,label,icon,render})). */
.lb-settings-panel {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
  background: var(--lb-bg-default);
}
.lb-settings-panel__header {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
}
.lb-settings-panel__title {
  flex: 1 1 auto;
  margin: 0;
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-m-font-size);
  font-weight: var(--lb-font-weight-medium);
  color: var(--lb-fg-default);
}
.lb-settings-panel__close { flex: 0 0 auto; }
.lb-settings-panel__body {
  flex: 1 1 auto;
  min-height: 0;
  overflow-y: auto;
  padding: var(--lb-size-2x) 0;
}

.lb-settings-section {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-border-muted);
}
.lb-settings-section:last-child { border-bottom: 0; }
.lb-settings-section__head {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
}
.lb-settings-section__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--lb-size-4x);
  height: var(--lb-size-4x);
  color: var(--lb-fg-muted);
}
.lb-settings-section__icon svg { width: 100%; height: 100%; }
.lb-settings-section__title {
  margin: 0;
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-s-font-size);
  font-weight: var(--lb-font-weight-medium);
  letter-spacing: 0.02em;
  text-transform: uppercase;
  color: var(--lb-fg-muted);
}
.lb-settings-section__body {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-3x);
}

.lb-settings-row {
  display: flex;
  align-items: flex-start;
  gap: var(--lb-size-3x);
  justify-content: space-between;
  flex-wrap: wrap;
}
.lb-settings-row__copy {
  flex: 1 1 12rem;
  min-width: 0;
}
.lb-settings-row__label {
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-default);
  font-weight: var(--lb-font-weight-medium);
  margin-bottom: var(--lb-size-0-5x);
}
.lb-settings-row__hint {
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  line-height: var(--lb-t-body-xs-line-height);
}
.lb-settings-row__control {
  flex: 0 0 auto;
}

/* Read-only keyboard map. Definition list with two columns —
   description on the left, combo on the right. */
.lb-settings-kbd-list {
  display: grid;
  grid-template-columns: 1fr auto;
  column-gap: var(--lb-size-4x);
  row-gap: var(--lb-size-1-5x);
  margin: 0;
  padding: 0;
  font-family: var(--lb-t-body-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-settings-kbd-list dt {
  color: var(--lb-fg-default);
}
.lb-settings-kbd-list dd {
  margin: 0;
  font-family: var(--lb-t-code-m-font-family, 'Roboto Mono', monospace);
  font-variant-numeric: tabular-nums;
  color: var(--lb-fg-muted);
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════
   HEADER — site / app navigation header (LB.Header)
   Three base compositions via modifiers: contained bar (default),
   mega-menu (--mega items), floating pill (--floating). Reuses .lb-btn
   for CTAs. a11y: mega = disclosure (button+aria-expanded), drawer =
   modal dialog + focus trap. All colours/space/radius from tokens.
   NOTE: a sticky header (--sticky) MUST be a direct child of the scroll
   root — never nested in a min-height:100vh wrapper (it stops sticking).
   ═══════════════════════════════════════════════════════════ */

/* Scroll-lock helper — set on <html> while a modal drawer is open. */
.lb-scroll-locked { overflow: hidden; }

.lb-header {
  position: relative;
  z-index: 900;
  width: 100%;
  background: var(--lb-surface-bg-default);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  font-family: var(--lb-t-action-m-font-family);
}
.lb-header--sticky { position: sticky; top: 0; }

/* Skip-to-content — visually hidden until focused (WCAG bypass block).
   Uses clip-based hiding (not transform) so the box never peeks out of a
   transparent/non-clipping ancestor such as the floating-pill header. */
.lb-header__skip {
  position: absolute;
  left: var(--lb-size-2x);
  top: var(--lb-size-2x);
  z-index: 1;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  background: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  border: var(--lb-border-width-thin) solid var(--lb-border-default);
  border-radius: var(--lb-radius-interactive);
}
.lb-header__skip:focus-visible {
  width: auto;
  height: auto;
  padding: var(--lb-size-1-5x) var(--lb-size-3x);
  overflow: visible;
  clip: auto;
  clip-path: none;
  outline: var(--lb-border-width-action) solid var(--lb-border-focus);
}

/* Inner container — brand | nav | actions | toggle. */
.lb-header__inner {
  display: flex;
  align-items: center;
  gap: var(--lb-size-4x);
  max-width: var(--lb-header-max, 75rem);
  margin: 0 auto;
  padding: var(--lb-size-3x) var(--lb-size-6x);
  transition: padding var(--lb-animation-dur-normal) var(--lb-animation-ease-ui);
}

.lb-header__brand {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  flex-shrink: 0;
  font-family: var(--lb-t-label-l-font-family);
  font-weight: var(--lb-font-weight-semibold);
  font-size: var(--lb-t-action-m-font-size);
  color: var(--lb-fg-default);
  text-decoration: none;
}
.lb-header__logo { display: flex; align-items: center; height: var(--lb-size-8x); }
.lb-header__logo svg, .lb-header__logo img { height: 100%; width: auto; display: block; }

/* Nav links row. */
.lb-header__nav {
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
}
.lb-header__item { position: static; }
.lb-header__link {
  display: inline-flex;
  align-items: center;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-1-5x) var(--lb-size-3x);
  border-radius: var(--lb-radius-interactive);
  color: var(--lb-fg-default); /* neutral idle — accent reserved for active (16-system convention) */
  font-size: var(--lb-t-action-m-font-size);
  font-family: inherit;
  text-decoration: none;
  background: none;
  border: none;
  cursor: pointer;
  white-space: nowrap;
}
.lb-header__link:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-header__link:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); }
.lb-header__link--active { color: var(--lb-action-fg-selected); }
.lb-header__link [data-lb-icon] { width: var(--lb-size-4x); height: var(--lb-size-4x); display: inline-flex; transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-header__item--open .lb-header__link [data-lb-icon] { transform: rotate(180deg); }

/* Actions cluster — CTAs (reuse .lb-btn) pushed to the end. */
/* Actions sit at the far right: brand + nav cluster left, actions pushed
   right by the single auto margin. (One auto margin only — two facing
   autos would split the gap and center them.) */
.lb-header__actions {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  margin-left: auto;
  flex-shrink: 0;
}

/* Hamburger — consumes .lb-icon-btn (use with --ghost --medium); this
   class only adds header behavior: hidden on desktop, pushed to the far
   right, shown at the mobile breakpoint (media rule below). Inside the
   drawer head (close button) it is always shown. */
.lb-header__toggle { display: none; margin-left: auto; }
.lb-header__drawer-head .lb-header__toggle { display: inline-flex; }

/* ── Mega-menu panel — full-width categorized dropdown ── */
.lb-header__mega {
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  background: var(--lb-surface-bg-elevated);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated);
  box-shadow: var(--lb-shadow-dropdown);
  z-index: 10;
}
.lb-header__mega[hidden] { display: none; }
.lb-header__mega-inner {
  max-width: var(--lb-header-max, 75rem);
  margin: 0 auto;
  padding: var(--lb-size-6x);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
  gap: var(--lb-size-6x);
}
.lb-header__mega-col { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-header__mega-label {
  color: var(--lb-fg-muted);
  font-family: var(--lb-t-label-l-font-family);
  font-size: var(--lb-t-body-xs-font-size);
  font-weight: var(--lb-font-weight-medium);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: var(--lb-size-1x);
}
.lb-header__mega-link {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  padding: var(--lb-size-2x);
  border-radius: var(--lb-radius-interactive);
  color: var(--lb-fg-default);
  text-decoration: none;
  font-size: var(--lb-t-body-s-font-size);
}
.lb-header__mega-link:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-header__mega-link:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); }
.lb-header__mega-link small { color: var(--lb-fg-muted); font-size: var(--lb-t-body-xs-font-size); }

/* ── Floating pill composition ── */
.lb-header--floating {
  position: sticky;
  top: var(--lb-size-4x);
  /* Horizontal inset so the pill visibly floats off the container edges
     even when the container is narrower than --lb-header-max. Matches the
     common content gutter (size-6x) so the pill edges align with page text. */
  padding-inline: var(--lb-size-6x);
  border: none;
  background: transparent;
  z-index: 900;
}
.lb-header--floating .lb-header__inner {
  max-width: var(--lb-header-max, 64rem);
  margin: 0 auto;
  padding: var(--lb-size-2x) var(--lb-size-3x);
  background: var(--lb-surface-bg-default);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated);
  border-radius: var(--lb-radius-full);
  box-shadow: var(--lb-shadow-card);
}
/* Pill mega panel tucks under the pill, rounded. */
.lb-header--floating .lb-header__mega {
  left: 50%;
  right: auto;
  transform: translateX(-50%);
  width: min(var(--lb-header-max, 64rem), calc(100vw - var(--lb-size-8x)));
  top: calc(100% + var(--lb-size-2x));
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated);
  border-radius: var(--lb-radius-overlay);
  overflow: hidden;
}

/* ── Transparent-over-hero → solid on scroll ── */
.lb-header--transparent {
  background: transparent;
  border-bottom-color: transparent;
}
.lb-header--transparent.lb-header--scrolled {
  background: var(--lb-surface-bg-default);
  border-bottom-color: var(--lb-surface-border-default);
}
/* Opt-in translucency (glass): ONLY safe with the scrim; research flagged
   contrast failures over variable backgrounds, so this is opt-in, not
   default, and still resolves to solid on scroll. */
.lb-header--glass.lb-header--scrolled .lb-header__inner,
.lb-header--floating.lb-header--glass .lb-header__inner {
  background: color-mix(in srgb, var(--lb-surface-bg-default) 82%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}

/* ── Shrink on scroll ── */
.lb-header--shrink.lb-header--scrolled .lb-header__inner {
  padding-top: var(--lb-size-1-5x);
  padding-bottom: var(--lb-size-1-5x);
}

/* ── Mobile drawer (modal) + scrim ── */
.lb-header__scrim {
  position: fixed;
  inset: 0;
  background: color-mix(in srgb, var(--lb-bg-overlay) 45%, transparent);
  z-index: 1000;
}
.lb-header__scrim[hidden] { display: none; }
.lb-header__drawer {
  position: fixed;
  top: 0;
  right: 0;
  bottom: 0;
  width: min(88vw, 22rem);
  z-index: 1001;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-1x);
  padding: var(--lb-size-4x);
  background: var(--lb-surface-bg-default);
  border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  box-shadow: var(--lb-shadow-modal);
  overflow-y: auto;
  animation: lb-header-drawer-in var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
}
.lb-header__drawer[hidden] { display: none; }
@keyframes lb-header-drawer-in { from { transform: translateX(100%); } to { transform: translateX(0); } }
.lb-header__drawer-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: var(--lb-size-3x);
}
.lb-header__drawer .lb-header__link { width: 100%; justify-content: flex-start; }
.lb-header__drawer-actions {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
  margin-top: var(--lb-size-4x);
  padding-top: var(--lb-size-4x);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-header__drawer-actions .lb-btn { width: 100%; }

/* ── Responsive: collapse nav → hamburger at ≤768px ── */
@media (max-width: 768px) {
  .lb-header__nav,
  .lb-header__inner > .lb-header__actions { display: none; }
  .lb-header__toggle { display: inline-flex; }
  .lb-header__inner { padding-left: var(--lb-size-4x); padding-right: var(--lb-size-4x); }
  .lb-header--floating { top: var(--lb-size-2x); padding-inline: var(--lb-size-3x); }
}
@media (min-width: 769px) {
  .lb-header__drawer, .lb-header__scrim { display: none !important; }
}

/* Reduced motion: no drawer slide / padding animation. */
@media (prefers-reduced-motion: reduce) {
  .lb-header__inner,
  .lb-header__skip { transition: none; }
  .lb-header__drawer { animation: none; }
}

/* ═══════════════════════════════════════════════════════════
   FOOTER — Stage 2 of the app-shell/templates program.
   Two flavors + one decorative variant (2026-07 footer research):
     - marketing (default): brand zone + link columns + optional
       social row + optional newsletter + legal row
     - --app: thin single-row footer for app shells
     - __giant: oversized decorative brand wordmark
   No JS: mobile collapse is pure-CSS stacking (accordion columns
   rejected — unverified benefit, real a11y cost) and the
   newsletter form's submit engine belongs to the consumer.
   a11y (verified, W3C/MDN): render as THE single body-scoped
   <footer>, OUTSIDE <main> — nested in main/section/article it
   silently loses the contentinfo landmark. Each link column is a
   <nav aria-labelledby> pointing at its real heading; never
   aria-label="Footer" (announces "contentinfo footer"). Icon-only
   social links carry aria-label names.
   ═══════════════════════════════════════════════════════════ */

.lb-footer {
  background: var(--lb-surface-bg-default);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  color: var(--lb-fg-default);
  font-family: var(--lb-t-action-m-font-family);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-footer__inner {
  max-width: var(--lb-footer-max, 75rem);
  margin: 0 auto;
  padding: var(--lb-size-12x) var(--lb-size-6x) var(--lb-size-6x);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-10x);
}

/* ── Top zone: brand column + link columns (+ optional inline newsletter) ── */
.lb-footer__top {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-10x) var(--lb-size-8x);
}
.lb-footer__brandcol {
  flex: 1 1 14rem;
  max-width: 20rem; /* design-intent: keeps tagline measure readable */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--lb-size-4x);
}
.lb-footer__brand {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  font-family: var(--lb-t-label-l-font-family);
  font-weight: var(--lb-font-weight-semibold);
  font-size: var(--lb-t-action-m-font-size);
  color: var(--lb-fg-default);
  text-decoration: none;
}
.lb-footer__logo { display: flex; align-items: center; height: var(--lb-size-8x); }
.lb-footer__logo svg, .lb-footer__logo img { height: 100%; width: auto; display: block; }
.lb-footer__tagline {
  margin: 0;
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
}
/* Social row — links consume .lb-icon-btn (--ghost --small); this is just the row. */
.lb-footer__social { display: flex; align-items: center; gap: var(--lb-size-1x); }

/* Link columns — each is <nav aria-labelledby> with a real heading. */
.lb-footer__cols {
  flex: 2 1 28rem;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: var(--lb-size-8x);
}
.lb-footer__col { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-footer__col-title {
  margin: 0 0 var(--lb-size-2x);
  font-family: var(--lb-t-label-m-font-family);
  font-size: var(--lb-t-label-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-default);
}
.lb-footer__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}
.lb-footer__link {
  color: var(--lb-fg-muted);
  text-decoration: none;
  font-size: inherit;
  border-radius: var(--lb-radius-interactive);
  width: fit-content;
}
.lb-footer__link:hover { color: var(--lb-fg-default); text-decoration: underline; text-underline-offset: var(--lb-size-1x); }
.lb-footer__link:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); }

/* ── Newsletter zone (optional) — consumes .lb-field/.lb-input-wrap/.lb-btn.
   Placement inline: put it inside __top (flexes beside the columns).
   Placement below: add --row and place it as its own zone before __legal. ── */
.lb-footer__newsletter {
  flex: 1 1 16rem;
  max-width: 24rem; /* design-intent: form measure */
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}
.lb-footer__newsletter-title {
  margin: 0;
  font-family: var(--lb-t-label-m-font-family);
  font-size: var(--lb-t-label-m-font-size);
  font-weight: var(--lb-font-weight-semibold);
  color: var(--lb-fg-default);
}
.lb-footer__newsletter-desc { margin: 0; color: var(--lb-fg-muted); }
.lb-footer__newsletter-form { display: flex; gap: var(--lb-size-2x); }
.lb-footer__newsletter-form .lb-input-wrap { flex: 1 1 auto; }
.lb-footer__newsletter--row {
  max-width: none;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-4x) var(--lb-size-8x);
  padding: var(--lb-size-6x);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  border-radius: var(--lb-radius-overlay);
}
.lb-footer__newsletter--row .lb-footer__newsletter-form { flex: 1 1 20rem; max-width: 28rem; }

/* ── Legal / utility row — copyright, legal links, optional status badge. ── */
.lb-footer__legal {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--lb-size-3x) var(--lb-size-4x);
  padding-top: var(--lb-size-6x);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-xs-font-size);
}
/* Single auto margin pushes the links/status cluster right. */
.lb-footer__legal-links {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--lb-size-4x);
  margin-left: auto;
}

/* ── App flavor: one thin row (put __legal directly in __inner). ── */
.lb-footer--app .lb-footer__inner { padding: var(--lb-size-4x) var(--lb-size-6x); gap: 0; }
.lb-footer--app .lb-footer__legal { padding-top: 0; border-top: none; }

/* ── Giant decorative brand wordmark (optional, aria-hidden in markup). ── */
.lb-footer__giant {
  font-family: var(--lb-t-display-xl-font-family);
  font-weight: var(--lb-t-display-xl-font-weight);
  font-size: clamp(3.5rem, 13vw, 11rem); /* design-intent: fills the row width */
  line-height: 1;
  letter-spacing: -0.03em;
  text-align: center;
  color: color-mix(in srgb, var(--lb-fg-default) 8%, transparent);
  user-select: none;
  pointer-events: none;
  margin: 0;
  margin-bottom: calc(-1 * var(--lb-size-4x)); /* tucks toward the legal rule */
}

/* ── Responsive: stack (verified pattern; no accordion). ── */
@media (max-width: 768px) {
  .lb-footer__inner { padding: var(--lb-size-8x) var(--lb-size-4x) var(--lb-size-4x); gap: var(--lb-size-8x); }
  .lb-footer__cols { gap: var(--lb-size-6x); }
  .lb-footer__newsletter--row { padding: var(--lb-size-4x); }
  .lb-footer__legal-links { margin-left: 0; }
}

/* ═══════════════════════════════════════════════════════════
   AUTH TEMPLATES — Stage 3 of the app-shell/templates program.
   Composed SCREENS, not primitives: login / signup / forgot /
   reset / verify (OTP | link-sent) / MFA, each in two layouts
   (centered-card default · --split with a brand-panel slot).
   This block is scaffolding ONLY — fields, buttons, checkboxes,
   cards, links all come from existing primitives. No JS. The
   auth ENGINE is the consumer's (screens/skin only).
   Verified-2026 notes baked in: visible labels always (never
   placeholder-only); autocomplete attrs are WCAG 1.3.5 —
   username/current-password/new-password/one-time-code, plus
   "username webauthn" on the login identifier for passkey
   autofill (FIDO primary pattern; a passkey BUTTON is an
   optional secondary slot). OTP entry is a SINGLE input —
   multi-box breaks SMS autofill and screen readers.
   ═══════════════════════════════════════════════════════════ */

/* Page shell — centers the card in whatever region hosts it. */
.lb-auth {
  display: grid;
  place-items: center;
  min-height: 100%;
  padding: var(--lb-size-10x) var(--lb-size-6x);
  background: var(--lb-bg-default);
}
.lb-auth__card {
  width: 100%;
  max-width: 26rem; /* design-intent: form measure */
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-6x);
}

/* ── Split layout: brand panel + form side. Panel is a slot. ── */
.lb-auth--split {
  grid-template-columns: 1fr 1fr;
  place-items: stretch;
  padding: 0;
}
/* Neutral brand panel (accent model 2026-08-03; was violet-washed).
   The calm panel IS the brand moment now — logo/illustration inside
   carries any color. */
.lb-auth__panel {
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
  padding: var(--lb-size-10x);
  background: var(--lb-bg-strong);
  color: var(--lb-fg-default);
}
.lb-auth__main {
  display: grid;
  place-items: center;
  padding: var(--lb-size-10x) var(--lb-size-6x);
}

/* ── Head: logo + title + subtitle. ── */
.lb-auth__head {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--lb-size-2x);
  text-align: center;
}
.lb-auth__logo { display: flex; align-items: center; justify-content: center; height: var(--lb-size-10x); color: var(--lb-fg-default); }
.lb-auth__logo svg, .lb-auth__logo img { height: 100%; width: auto; display: block; }
.lb-auth__title {
  margin: 0;
  font-family: var(--lb-t-heading-m-font-family);
  font-size: var(--lb-t-heading-m-font-size);
  font-weight: var(--lb-t-heading-m-font-weight);
  line-height: var(--lb-t-heading-m-line-height);
  color: var(--lb-fg-default);
}
.lb-auth__subtitle {
  margin: 0;
  font-size: var(--lb-t-body-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  color: var(--lb-fg-muted);
}

/* ── Social row — .lb-btn--secondary + brand icons. Column default
   (icon+label); --row for compact side-by-side. Position (leading
   vs trailing) is just markup order around the divider. ── */
.lb-auth__social { display: flex; flex-direction: column; gap: var(--lb-size-2x); }
.lb-auth__social .lb-btn { width: 100%; }
/* Form action buttons span the card (submit, passkey). */
.lb-auth__card .lb-form .lb-btn { width: 100%; }
.lb-auth__social--row { flex-direction: row; }
.lb-auth__social--row .lb-btn { flex: 1 1 0; }

/* ── "or" divider. ── */
.lb-auth__divider {
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  color: var(--lb-fg-muted);
  font-size: var(--lb-t-body-xs-font-size);
}
.lb-auth__divider::before,
.lb-auth__divider::after {
  content: "";
  flex: 1;
  height: var(--lb-border-width-thin);
  background: var(--lb-surface-border-default);
}

/* ── Between-fields row: remember-me left, forgot link right. ── */
.lb-auth__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--lb-size-3x);
  flex-wrap: wrap;
}

/* ── OTP code field: ONE input, styled big + spaced. ── */
.lb-auth__code .lb-input {
  text-align: center;
  font-family: var(--lb-t-code-l-font-family);
  font-size: var(--lb-t-code-l-font-size);
  letter-spacing: var(--lb-t-code-l-letter-spacing);
}

/* ── Bottom meta line: "No account? Sign up" etc. ── */
.lb-auth__meta {
  margin: 0;
  text-align: center;
  font-size: var(--lb-t-body-s-font-size);
  color: var(--lb-fg-muted);
}

/* ── Responsive: split collapses to the form side only. ── */
@media (max-width: 768px) {
  .lb-auth--split { grid-template-columns: 1fr; }
  .lb-auth__panel { display: none; }
  .lb-auth__main { padding: var(--lb-size-8x) var(--lb-size-4x); }
}

/* ═══════════════════════════════════════════════════════════
   APP SHELL — Stage 4 of the app-shell/templates program.
   The "inverted L": full-height sidebar
   + content column whose header lives INSIDE the column (a nested
   header never gets the banner landmark — W3C-intentional, same
   scoping rule as footer/contentinfo).
   Variant axes (2026-07 research): collapse mode (expanded ·
   icon-rail · offcanvas) × side (left · --right) × style
   (standard · --floating · --inset) × right rail (slot on/off).
   Widths per verified convention: 16rem expanded / 3rem rail /
   18rem mobile drawer — component-local custom props (same idiom
   as --lb-header-max; promote to tokens only if layout widths
   should ever theme).
   a11y spec (verified): sidebar nav = <nav aria-label> (NOT
   aside/complementary); content column = <main tabindex="-1">;
   skip link first-focusable → #main; toggle = button +
   aria-expanded + aria-controls (APG disclosure); rail keeps
   labels in-DOM (visually hidden) so accessible names survive;
   frame height 100dvh (100vh overflows under mobile toolbars);
   reduced-motion kills the collapse transition.
   JS (lb-shell.js): collapse toggle + localStorage persistence +
   ctrl/cmd+B + mobile drawer (modal, reuses header-drawer spec)
   or bottom-bar mode + opt-in drag-resize (consumes the
   .lb-resizable__handle skin + separator semantics).
   ═══════════════════════════════════════════════════════════ */

.lb-shell {
  --lb-shell-sidebar-w: 16rem;      /* design-intent: verified 256px convention */
  --lb-shell-rail-w: 3rem;          /* design-intent: verified 48px rail */
  --lb-shell-drawer-w: 18rem;       /* design-intent: verified 288px mobile drawer */
  --lb-shell-panel-w: 18rem;        /* design-intent: right inspector rail */
  display: flex;
  height: 100dvh;
  overflow: hidden;
  background: var(--lb-bg-default);
  color: var(--lb-fg-default);
  font-family: var(--lb-t-body-m-font-family);
}

/* Skip link — same clip-hidden pattern as the header's. */
.lb-shell__skip {
  position: absolute;
  left: var(--lb-size-2x);
  top: var(--lb-size-2x);
  z-index: 30;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  background: var(--lb-surface-bg-default);
  color: var(--lb-fg-default);
  border: var(--lb-border-width-thin) solid var(--lb-border-default);
  border-radius: var(--lb-radius-interactive);
}
.lb-shell__skip:focus-visible {
  width: auto;
  height: auto;
  padding: var(--lb-size-1-5x) var(--lb-size-3x);
  overflow: visible;
  clip: auto;
  clip-path: none;
  outline: var(--lb-border-width-action) solid var(--lb-border-focus);
}

/* ── Sidebar — three zones: head / scrollable nav / foot. ── */
.lb-shell__sidebar {
  position: relative;
  display: flex;
  flex-direction: column;
  flex-shrink: 0;
  width: var(--lb-shell-sidebar-w);
  background: var(--lb-surface-bg-default);
  border-right: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  transition: width var(--lb-animation-dur-normal) var(--lb-animation-ease-ui),
              margin var(--lb-animation-dur-normal) var(--lb-animation-ease-ui);
  overflow: hidden;
}
.lb-shell__sidebar-head {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-3x);
  min-height: var(--lb-size-12x);
}
.lb-shell__brand {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  font-family: var(--lb-t-heading-xs-font-family);
  font-weight: var(--lb-t-heading-xs-font-weight);
  font-size: var(--lb-t-heading-xs-font-size);
  color: var(--lb-fg-default);
  text-decoration: none;
  white-space: nowrap;
}
.lb-shell__logo { display: flex; align-items: center; flex-shrink: 0; width: var(--lb-size-8x); height: var(--lb-size-8x); }
.lb-shell__logo svg { width: 100%; height: 100%; }

/* Nav zone — the independent scroll region. Focusable children make it
   keyboard-reachable already; no tabindex needed (Chrome 130 rule). */
.lb-shell__nav {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--lb-size-2x);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-4x);
}
.lb-shell__group { display: flex; flex-direction: column; gap: var(--lb-size-0-5x); }
.lb-shell__group-label {
  padding: var(--lb-size-1x) var(--lb-size-2x);
  white-space: nowrap;
}
.lb-shell__item {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  width: 100%;
  padding: var(--lb-size-1-5x) var(--lb-size-2x);
  border: none;
  border-radius: var(--lb-radius-interactive);
  background: none;
  color: var(--lb-fg-default); /* neutral idle — accent reserved for active */
  font-family: inherit;
  font-size: var(--lb-t-action-s-font-size);
  text-decoration: none;
  text-align: left;
  cursor: pointer;
  white-space: nowrap;
}
.lb-shell__item:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-shell__item:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); }
.lb-shell__item--active { background: var(--lb-action-bg-selected); color: var(--lb-action-fg-selected); }
.lb-shell__item-icon { display: inline-flex; flex-shrink: 0; width: var(--lb-size-5x); height: var(--lb-size-5x); color: var(--lb-fg-muted); /* icons one step muted */ }
.lb-shell__item--active .lb-shell__item-icon, .lb-shell__item:hover .lb-shell__item-icon { color: inherit; }
.lb-shell__item-icon svg { width: 100%; height: 100%; }
.lb-shell__item-label { flex: 1; overflow: hidden; text-overflow: ellipsis; }
.lb-shell__item-chevron { display: inline-flex; flex-shrink: 0; width: var(--lb-size-4x); height: var(--lb-size-4x); transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-shell__item[aria-expanded="true"] .lb-shell__item-chevron { transform: rotate(90deg); }
/* One level of nesting (verified convention). */
.lb-shell__sub {
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-0-5x);
  padding-left: calc(var(--lb-size-5x) + var(--lb-size-2x)); /* icon width + gap — subs align under labels */
}
.lb-shell__sub[hidden] { display: none; }

.lb-shell__sidebar-foot {
  padding: var(--lb-size-2x);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
/* User item — .lb-avatar sits as a direct flex child (its own 2rem box,
   never squeezed into the 20px __item-icon slot). */
.lb-shell__item--user { padding-top: var(--lb-size-1x); padding-bottom: var(--lb-size-1x); }
.lb-shell__item--user .lb-avatar { flex-shrink: 0; }

/* ── Collapse: icon-rail mode (labels stay in DOM, clipped). ── */
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar { width: var(--lb-shell-rail-w); }
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__group-label,
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__item-label,
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__item-chevron,
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__brand-name {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__item { justify-content: center; padding-left: 0; padding-right: 0; }
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sub { display: none; }
.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar-head { justify-content: center; padding-left: 0; padding-right: 0; }

/* Rail-content hooks: mark sidebar content [data-lb-shell-expanded-only]
   to remove it on the icon rail (e.g. a conversation list), and provide a
   [data-lb-shell-rail-only] group of icon shortcuts shown ONLY on the
   rail. */
.lb-shell [data-lb-shell-rail-only] { display: none; }
.lb-shell--collapsed[data-lb-shell-collapse="icon"] [data-lb-shell-rail-only] { display: flex; }
.lb-shell--collapsed[data-lb-shell-collapse="icon"] [data-lb-shell-expanded-only] { display: none; }

/* ── Collapse: offcanvas mode (fully hidden). ── */
.lb-shell--collapsed[data-lb-shell-collapse="offcanvas"] .lb-shell__sidebar { width: 0; border-right-width: 0; }

/* ── Hover-peek rail (opt-in --peek):
   a collapsed icon rail expands as a temporary OVERLAY on
   hover or keyboard focus; content never shifts. Pure CSS: layout
   width stays the rail — the expanded box eats over the content via
   negative margin. Keyboard parity via :focus-within (peek content is
   reachable without a pointer). Small open delay avoids drive-by
   triggers; closing is instant. Scoped to the standard style —
   floating/inset sidebar margins would fight the negative-margin
   trick — and to desktop (mobile uses the drawer). ── */
@media (min-width: 769px) {
  .lb-shell--peek:not(.lb-shell--floating):not(.lb-shell--inset).lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) {
    width: var(--lb-shell-sidebar-w);
    margin-right: calc(var(--lb-shell-rail-w) - var(--lb-shell-sidebar-w));
    z-index: 15;
    box-shadow: var(--lb-shadow-dropdown);
    transition-delay: var(--lb-animation-dur-fast);
  }
  .lb-shell--peek.lb-shell--right:not(.lb-shell--floating):not(.lb-shell--inset).lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) {
    margin-right: 0;
    margin-left: calc(var(--lb-shell-rail-w) - var(--lb-shell-sidebar-w));
  }
  /* While peeking, reverse the rail's clip-hiding so labels/groups/subs
     come back (mirrors the collapse rules above). */
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__item-label,
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__item-chevron,
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__brand-name,
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__group-label {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    overflow: visible;
    clip: auto;
    clip-path: none;
  }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__group-label {
    padding: var(--lb-size-1x) var(--lb-size-2x);
  }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__item {
    justify-content: flex-start;
    padding: var(--lb-size-1-5x) var(--lb-size-2x);
  }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__sub:not([hidden]) {
    display: flex;
  }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) .lb-shell__sidebar-head {
    justify-content: flex-start;
    padding: var(--lb-size-3x);
  }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) [data-lb-shell-expanded-only] { display: revert; }
  .lb-shell--peek.lb-shell--collapsed[data-lb-shell-collapse="icon"] .lb-shell__sidebar:where(:hover, :focus-within) [data-lb-shell-rail-only] { display: none; }
}

/* ── Side: right. ── */
.lb-shell--right { flex-direction: row-reverse; }
.lb-shell--right .lb-shell__sidebar { border-right: none; border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default); }

/* ── Style: floating — sidebar as a detached card. ── */
.lb-shell--floating { background: var(--lb-bg-strong); }
.lb-shell--floating .lb-shell__sidebar {
  margin: var(--lb-size-2x);
  height: calc(100% - 2 * var(--lb-size-2x));
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-card);
}
.lb-shell--floating.lb-shell--collapsed[data-lb-shell-collapse="offcanvas"] .lb-shell__sidebar { margin: 0; border-width: 0; }

/* ── Style: inset — content column as the elevated card. ── */
.lb-shell--inset { background: var(--lb-bg-strong); }
.lb-shell--inset .lb-shell__sidebar { background: transparent; border-right: none; }
.lb-shell--inset .lb-shell__main {
  margin: var(--lb-size-2x);
  margin-left: 0;
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-elevated);
  border-radius: var(--lb-radius-overlay);
  box-shadow: var(--lb-shadow-card);
  background: var(--lb-surface-bg-default);
  overflow: hidden;
}
.lb-shell--inset.lb-shell--right .lb-shell__main { margin-left: var(--lb-size-2x); margin-right: 0; }

/* ── Content column: topbar + scrollable content (+ page header). ── */
.lb-shell__main {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
}
.lb-shell__topbar {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-2x) var(--lb-size-4x);
  min-height: var(--lb-size-12x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  flex-shrink: 0;
}
.lb-shell__topbar-actions { display: flex; align-items: center; gap: var(--lb-size-2x); margin-left: auto; }
.lb-shell__content {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--lb-size-6x);
}
.lb-shell__content:focus { outline: none; } /* skip-link target; visible focus not needed on the region itself */
.lb-shell__content--narrow > * { max-width: 72rem; margin-left: auto; margin-right: auto; } /* design-intent: readable dashboard measure */
.lb-shell__page-head {
  display: flex;
  align-items: center;
  gap: var(--lb-size-3x);
  flex-wrap: wrap;
  margin-bottom: var(--lb-size-6x);
}
.lb-shell__page-title {
  margin: 0;
  font-family: var(--lb-t-heading-m-font-family);
  font-size: var(--lb-t-heading-m-font-size);
  font-weight: var(--lb-t-heading-m-font-weight);
  line-height: var(--lb-t-heading-m-line-height);
}
.lb-shell__page-actions { display: flex; align-items: center; gap: var(--lb-size-2x); margin-left: auto; }

/* ── Right rail (inspector) — optional slot. ── */
.lb-shell__panel {
  width: var(--lb-shell-panel-w);
  flex-shrink: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--lb-size-4x);
  background: var(--lb-surface-bg-default);
  border-left: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}

/* ── Drag-resize handle (opt-in) — consumes the .lb-resizable__handle
   skin; lb-shell.js adds separator semantics + clamped drag. ── */
.lb-shell__resize {
  position: absolute;
  top: 0;
  right: calc(-1 * var(--lb-size-1x) / 2);
  width: var(--lb-size-1x);
  height: 100%;
  cursor: col-resize;
  z-index: 10;
}
.lb-shell--right .lb-shell__resize { right: auto; left: calc(-1 * var(--lb-size-1x) / 2); }
.lb-shell__resize:hover, .lb-shell__resize:focus-visible { background: var(--lb-border-focus); opacity: 0.5; }
.lb-shell__resize:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: 0; opacity: 1; }
.lb-shell--collapsed .lb-shell__resize { display: none; }

/* ── Mobile: sidebar becomes a modal drawer OR a bottom bar. ── */
.lb-shell__scrim {
  position: absolute;
  inset: 0;
  z-index: 20;
  background: color-mix(in srgb, var(--lb-bg-overlay) 45%, transparent);
}
.lb-shell__scrim[hidden] { display: none; }
.lb-shell__bottombar { display: none; }

@media (max-width: 768px) {
  .lb-shell:not(.lb-shell--mobile-bar) .lb-shell__sidebar {
    position: absolute;
    top: 0; bottom: 0; left: 0;
    z-index: 21;
    width: var(--lb-shell-drawer-w) !important; /* drawer ignores rail/resize widths */
    margin: 0;
    height: 100%;
    border-radius: 0;
    box-shadow: var(--lb-shadow-modal);
    transform: translateX(-100%);
    transition: transform var(--lb-animation-dur-gentle) var(--lb-animation-ease-ui);
  }
  .lb-shell--right:not(.lb-shell--mobile-bar) .lb-shell__sidebar { left: auto; right: 0; transform: translateX(100%); }
  .lb-shell--drawer-open .lb-shell__sidebar { transform: translateX(0) !important; }
  .lb-shell:not(.lb-shell--mobile-bar) .lb-shell__resize { display: none; }
  .lb-shell--inset .lb-shell__main { margin: 0; border: none; border-radius: 0; box-shadow: none; }

  /* Bottom-bar mode: sidebar hidden entirely; bar shows. */
  .lb-shell--mobile-bar .lb-shell__sidebar, 
  .lb-shell--mobile-bar .lb-shell__scrim { display: none; }
  .lb-shell--mobile-bar { flex-direction: column; }
  .lb-shell--mobile-bar .lb-shell__bottombar {
    display: flex;
    align-items: stretch;
    justify-content: space-around;
    gap: var(--lb-size-1x);
    padding: var(--lb-size-1x) var(--lb-size-2x);
    padding-bottom: calc(var(--lb-size-1x) + env(safe-area-inset-bottom, 0px));
    border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
    background: var(--lb-surface-bg-default);
    flex-shrink: 0;
  }
  .lb-shell__bottombar-item {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--lb-size-0-5x);
    flex: 1;
    padding: var(--lb-size-1x);
    border-radius: var(--lb-radius-interactive);
    color: var(--lb-fg-muted); /* muted idle — mobile tab-bar convention */
    font-size: var(--lb-t-caption-s-font-size);
    text-decoration: none;
  }
  .lb-shell__bottombar-item:hover { background: var(--lb-action-bg-ghost-hover); }
  .lb-shell__bottombar-item:focus-visible { outline: var(--lb-border-width-action) solid var(--lb-border-focus); outline-offset: calc(-1 * var(--lb-size-0-5x)); }
  .lb-shell__bottombar-item--active { color: var(--lb-fg-accent); }
  .lb-shell__bottombar-item [data-lb-icon] { width: var(--lb-size-5x); height: var(--lb-size-5x); display: inline-flex; }
}
@media (min-width: 769px) {
  .lb-shell__scrim { display: none !important; }
}

/* Reduced motion: no width/slide animation. */
@media (prefers-reduced-motion: reduce) {
  .lb-shell__sidebar, .lb-shell__item-chevron { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   COMPOSER DOCK — module S1 of the workspace-modules program.
   Mounts the existing .lb-composer (which brings its own card
   visuals, chips/attach/mic/send slots and LB.Composer behavior)
   at the bottom of a workspace canvas.
   DOCKED (default): position sticky at the container bottom, so
   the dock stays in flow and reserves space — content scrolls
   under the solid band while moving, and the last message still
   ends above the dock rather than behind it. Content width caps
   at --lb-dock-max (48rem) to match --lb-chat-thread-width.
   Safe-area aware.
   --floating (opt-in, canvas contexts like media galleries):
   overlays the content instead of reserving space — requires a
   positioned ancestor (the host sets position: relative).
   PARAMETER TRAY: consume .lb-popover-host + .lb-popover--top on
   any toggle inside the composer footer (LB.Popover provides
   aria-haspopup/expanded/controls, Esc, outside-click — no dock
   JS at all). a11y: tab order follows DOM order — the docked
   variant is the last child of the scroll container, after the
   thread.
   Mobile note (documented): on-screen keyboards collapse the
   visual viewport and browsers scroll the focused input into
   view; the sticky dock rides this natively — do not fight it.
   ═══════════════════════════════════════════════════════════ */

.lb-dock {
  position: sticky;
  bottom: 0;
  z-index: 50;
  padding: var(--lb-size-3x) var(--lb-size-4x);
  padding-bottom: calc(var(--lb-size-3x) + env(safe-area-inset-bottom, 0px));
  background: var(--lb-bg-default);
}
.lb-dock__inner {
  position: relative;
  max-width: var(--lb-dock-max, 48rem); /* design-intent: matches --lb-chat-thread-width */
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}
/* Optional suggestion-chip row above the composer (keyboard-reachable
   .lb-chip buttons — they precede the input in DOM order). */
.lb-dock__suggestions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--lb-size-2x);
  justify-content: center;
}
/* Optional compact notice above the composer — consumes .lb-banner--s
   (the "system info" line: model updates, limits…). */
.lb-dock__notice { display: flex; justify-content: center; }

/* Optional hint line under the composer (shortcuts, disclaimers). */
.lb-dock__hint {
  margin: 0;
  text-align: center;
  font-size: var(--lb-t-body-xs-font-size);
  color: var(--lb-fg-muted);
}

/* ── Floating variant — overlays a canvas. ── */
.lb-dock--floating {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  background: transparent;
  pointer-events: none;
}
.lb-dock--floating .lb-dock__inner { pointer-events: auto; }
.lb-dock--floating .lb-composer { box-shadow: var(--lb-shadow-modal); }

/* ── Parameter tray — a .lb-popover--top consumed inside the composer
   footer; this modifier just sizes/aligns it for tray content. ── */
.lb-popover--tray {
  min-width: 18rem; /* design-intent: fits segmented option rows */
  left: auto;
  right: 0;
  transform: none;
  padding: var(--lb-size-3x);
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-3x);
}
.lb-dock__tray-row { display: flex; flex-direction: column; gap: var(--lb-size-1x); }
.lb-dock__tray-label {
  font-family: var(--lb-t-label-s-font-family);
  font-size: var(--lb-t-label-s-font-size);
  font-weight: var(--lb-t-label-s-font-weight);
  color: var(--lb-fg-muted);
}

@media (prefers-reduced-motion: reduce) {
  .lb-dock .lb-composer { transition: none; }
}

/* Disclosure chevron rotation — companion to the menu-indicator
   affordance policy: any expanded disclosure button flips its
   chevron-down so open state is visible on the trigger itself. */
button[aria-expanded] [data-lb-icon="chevron-down"] {
  display: inline-flex;
  transition: transform var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
button[aria-expanded="true"] [data-lb-icon="chevron-down"] { transform: rotate(180deg); }
@media (prefers-reduced-motion: reduce) {
  button[aria-expanded] [data-lb-icon="chevron-down"] { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   TOOLBAR ROW — module S3a of the workspace-modules program.
   The canvas-top row: search · filter (count badge) · sort ·
   view switcher · pagination, and the BULK-SELECTION bar that
   replaces it while a selection is active (the toolbar is the
   canonical mount point for bulk actions). Pure CSS —
   all controls are existing atoms; LB.Selection toggles
   .lb-toolbar--selecting.
   ═══════════════════════════════════════════════════════════ */
/* Applied-filter chips row — sits between the toolbar and the data it
   filters; each applied filter renders as a removable pill. Chips
   inside keep the removal idiom (× removes; initChips skips them). */
.lb-filter-bar { display: flex; flex-wrap: wrap; align-items: center; gap: var(--lb-size-1x); margin-bottom: var(--lb-size-3x); }
.lb-filter-bar__label { font-size: var(--lb-t-body-s-font-size); color: var(--lb-fg-muted); margin-right: var(--lb-size-1x); }
.lb-filter-bar[hidden] { display: none; }

.lb-toolbar {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  min-height: var(--lb-size-12x);
}
.lb-toolbar__default,
.lb-toolbar__bulk {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  flex: 1;
  flex-wrap: wrap;
}
.lb-toolbar__bulk { display: none; }
.lb-toolbar--selecting .lb-toolbar__default { display: none; }
.lb-toolbar--selecting .lb-toolbar__bulk { display: flex; }
.lb-toolbar__search { flex: 1 1 12rem; max-width: 22rem; /* design-intent: search measure */ }
.lb-toolbar__spacer { margin-left: auto; }
.lb-toolbar__count {
  font-family: var(--lb-t-heading-xs-font-family);
  font-size: var(--lb-t-heading-xs-font-size);
  font-weight: var(--lb-t-heading-xs-font-weight);
  line-height: var(--lb-t-heading-xs-line-height);
  color: var(--lb-fg-default);
  white-space: nowrap;
}

/* ═══════════════════════════════════════════════════════════
   MEDIA CARD + SELECTION — modules S3b/S3c.
   Grid (default) and --row list variants. Media area consumes
   the .lb-card__media aspect presets. Overlay slots: selection
   check (top-left), hover quick-action cluster (top-right),
   duration/status badge (bottom-right), caption row below.
   Selection spec (verified): check target 24px visual (AA floor)
   inside a 32px padded hit area — clear of the action cluster so
   the WCAG 2.5.8 spacing rule holds; hover/focus reveals the
   check, the FIRST selection escalates checks onto every card
   (progressive disclosure — LB.Selection adds
   .lb-selection--active to the container); selected state =
   accent ring + scrim + persistent check; long-press enters
   selection on touch. Selection persists after bulk actions
   until deliberately cleared (Esc or deselect-all).
   ═══════════════════════════════════════════════════════════ */
.lb-media-card {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-2x);
}
.lb-media-card__media {
  position: relative;
  overflow: hidden;
  width: 100%;
  border-radius: var(--lb-radius-surface);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  background: var(--lb-bg-strong);
}
.lb-media-card__media img, .lb-media-card__media video {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}
/* Selected: accent ring + scrim, check stays on. */
.lb-media-card--selected .lb-media-card__media {
  outline: var(--lb-border-width-medium) solid var(--lb-border-accent);
  outline-offset: var(--lb-size-0-5x);
}
.lb-media-card--selected .lb-media-card__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background: color-mix(in srgb, var(--lb-bg-accent-muted) 35%, transparent);
  pointer-events: none;
}

/* Check — 24px control in a padded 32px hit area, top-left. */
.lb-media-card__check {
  position: absolute;
  top: var(--lb-size-1x);
  left: var(--lb-size-1x);
  z-index: 2;
  padding: var(--lb-size-1x);
  display: inline-flex;
  border-radius: var(--lb-radius-interactive);
  opacity: 0;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-media-card__check .lb-checkbox { width: var(--lb-size-6x); height: var(--lb-size-6x); }
.lb-media-card:hover .lb-media-card__check,
.lb-media-card:focus-within .lb-media-card__check,
.lb-selection--active .lb-media-card__check,
.lb-media-card--selected .lb-media-card__check { opacity: 1; }

/* Hover quick-action cluster — top-right, solid surface for contrast,
   kept clear of the check (2.5.8 spacing). */
.lb-media-card__actions {
  position: absolute;
  top: var(--lb-size-2x);
  right: var(--lb-size-2x);
  z-index: 2;
  display: flex;
  gap: var(--lb-size-1x);
  opacity: 0;
  transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui);
}
.lb-media-card:hover .lb-media-card__actions,
.lb-media-card:focus-within .lb-media-card__actions { opacity: 1; }
.lb-media-card__actions .lb-icon-btn { background: var(--lb-surface-bg-overlay); box-shadow: var(--lb-shadow-card); }

/* Duration / status badge — bottom-right over media. */
.lb-media-card__duration {
  position: absolute;
  bottom: var(--lb-size-2x);
  right: var(--lb-size-2x);
  z-index: 1;
  padding: 0 var(--lb-size-1-5x);
  border-radius: var(--lb-radius-2);
  background: color-mix(in srgb, var(--lb-bg-overlay) 70%, transparent);
  color: var(--lb-fg-inverse-strong); /* always light — the scrim is dark in BOTH modes */
  font-size: var(--lb-t-caption-s-font-size);
  line-height: var(--lb-t-body-s-line-height);
  font-variant-numeric: tabular-nums;
}

/* Caption row — title/meta left, kebab right. */
.lb-media-card__caption {
  display: flex;
  align-items: flex-start;
  gap: var(--lb-size-2x);
}
.lb-media-card__text { flex: 1; min-width: 0; }
.lb-media-card__title {
  margin: 0;
  font-family: var(--lb-t-heading-xs-font-family);
  font-size: var(--lb-t-heading-xs-font-size);
  font-weight: var(--lb-t-heading-xs-font-weight);
  line-height: var(--lb-t-heading-xs-line-height);
  color: var(--lb-fg-default);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-media-card__meta {
  margin: 0;
  font-size: var(--lb-t-body-xs-font-size);
  color: var(--lb-fg-muted);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* List variant — horizontal row. Check sits inline at the row start
   (not over the thumb); row itself carries hover/selected background. */
.lb-media-card--row {
  flex-direction: row;
  align-items: center;
  padding: var(--lb-size-2x);
  border-radius: var(--lb-radius-interactive);
}
.lb-media-card--row:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-media-card--row .lb-media-card__media { width: 8rem; /* design-intent: list thumb */ flex-shrink: 0; }
.lb-media-card--row .lb-media-card__caption { flex: 1; min-width: 0; }
.lb-media-card--row .lb-media-card__check {
  position: static;
  order: -1;
  align-self: center;
  opacity: 1; /* list view = manage mode: checks always visible */
}
.lb-media-card--row.lb-media-card--selected { background: var(--lb-action-bg-selected); }
.lb-media-card--row.lb-media-card--selected .lb-media-card__media { outline: none; }
.lb-media-card--row.lb-media-card--selected .lb-media-card__media::after { content: none; }

@media (prefers-reduced-motion: reduce) {
  .lb-media-card__check, .lb-media-card__actions { transition: none; }
}

/* ═══════════════════════════════════════════════════════════
   INSPECTOR PANEL — module S4 of the workspace-modules program.
   The right-rail detail/settings CONTENT pattern (song detail,
   object properties, issue detail, agent settings).
   Pure CSS anatomy — mounts inside the shell's in-flow
   aside.lb-shell__panel (nonmodal complementary landmark — the
   verified default for reference/compare + copy-paste tasks) or
   inside .lb-sheet--right for the transient overlay mode. When
   opened dynamically: move focus INTO the panel programmatically
   and return it to the launcher on close.
   Rows carry copy-to-clipboard affordances — the documented
   rationale for nonmodal detail surfaces.
   ═══════════════════════════════════════════════════════════ */
.lb-inspector {
  display: flex;
  flex-direction: column;
  height: 100%;
  min-height: 0;
}
.lb-inspector__head {
  display: flex;
  align-items: flex-start;
  gap: var(--lb-size-2x);
  padding-bottom: var(--lb-size-3x);
  border-bottom: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-inspector__titles { flex: 1; min-width: 0; }
.lb-inspector__label {
  margin: 0;
  font-family: var(--lb-t-overline-font-family);
  font-size: var(--lb-t-overline-font-size);
  font-weight: var(--lb-t-overline-font-weight);
  line-height: var(--lb-t-overline-line-height);
  letter-spacing: var(--lb-t-overline-letter-spacing);
  text-transform: uppercase;
  color: var(--lb-fg-muted);
}
.lb-inspector__title {
  margin: 0;
  font-family: var(--lb-t-heading-s-font-family);
  font-size: var(--lb-t-heading-s-font-size);
  font-weight: var(--lb-t-heading-s-font-weight);
  line-height: var(--lb-t-heading-s-line-height);
  color: var(--lb-fg-default);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.lb-inspector__body {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  display: flex;
  flex-direction: column;
  gap: var(--lb-size-5x);
  padding: var(--lb-size-4x) 0;
}
.lb-inspector__hero {
  overflow: hidden;
  border-radius: var(--lb-radius-surface);
  border: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-inspector__hero img { width: 100%; display: block; }
.lb-inspector__section { display: flex; flex-direction: column; gap: var(--lb-size-2x); }
.lb-inspector__section-title {
  margin: 0;
  font-family: var(--lb-t-heading-xs-font-family);
  font-size: var(--lb-t-heading-xs-font-size);
  font-weight: var(--lb-t-heading-xs-font-weight);
  line-height: var(--lb-t-heading-xs-line-height);
  color: var(--lb-fg-default);
}
/* Key/value row with the copy affordance. */
.lb-inspector__row {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  font-size: var(--lb-t-body-s-font-size);
}
.lb-inspector__row-label { color: var(--lb-fg-muted); flex-shrink: 0; }
.lb-inspector__row-value { flex: 1; min-width: 0; text-align: right; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--lb-fg-default); }
/* Sticky footer actions (flex-pinned; body scrolls above it). */
.lb-inspector__foot {
  display: flex;
  gap: var(--lb-size-2x);
  padding-top: var(--lb-size-3x);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
}
.lb-inspector__foot .lb-btn { flex: 1; }

/* ── Choice row — radio-with-description (settings-panel form
   pattern, S6): consumes .lb-radio; adds title + description. ── */
.lb-choice {
  display: flex;
  align-items: flex-start;
  gap: var(--lb-size-2x);
  padding: var(--lb-size-2x);
  border-radius: var(--lb-radius-interactive);
  cursor: pointer;
}
.lb-choice:hover { background: var(--lb-action-bg-ghost-hover); }
.lb-choice .lb-radio { margin-top: var(--lb-size-0-5x); flex-shrink: 0; }
.lb-choice__text { flex: 1; min-width: 0; }
.lb-choice__title {
  display: block;
  font-family: var(--lb-t-heading-xs-font-family);
  font-size: var(--lb-t-heading-xs-font-size);
  font-weight: var(--lb-t-heading-xs-font-weight);
  line-height: var(--lb-t-heading-xs-line-height);
  color: var(--lb-fg-default);
}
.lb-choice__desc {
  display: block;
  font-size: var(--lb-t-body-xs-font-size);
  line-height: var(--lb-t-body-s-line-height);
  color: var(--lb-fg-muted);
}

/* ═══════════════════════════════════════════════════════════
   PLAYBAR — module S5: persistent bottom now-playing/status dock
   (a transport bar that survives navigation). Layout + skin ONLY: transport
   wiring belongs to the consumer's engine (LB.Media or their
   own) per the pluggable-engines principle. Mounts as the last
   child of the shell (below __main) or any app frame.
   ═══════════════════════════════════════════════════════════ */
.lb-playbar {
  display: flex;
  align-items: center;
  gap: var(--lb-size-4x);
  padding: var(--lb-size-2x) var(--lb-size-4x);
  padding-bottom: calc(var(--lb-size-2x) + env(safe-area-inset-bottom, 0px));
  background: var(--lb-surface-bg-default);
  border-top: var(--lb-border-width-thin) solid var(--lb-surface-border-default);
  flex-shrink: 0;
}
.lb-playbar__now {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  flex: 1 1 12rem;
  min-width: 0;
}
.lb-playbar__thumb {
  width: var(--lb-size-10x);
  height: var(--lb-size-10x);
  border-radius: var(--lb-radius-2);
  overflow: hidden;
  flex-shrink: 0;
  background: var(--lb-bg-strong);
}
.lb-playbar__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lb-playbar__titles { min-width: 0; }
.lb-playbar__title {
  margin: 0;
  font-family: var(--lb-t-heading-xs-font-family);
  font-size: var(--lb-t-heading-xs-font-size);
  font-weight: var(--lb-t-heading-xs-font-weight);
  line-height: var(--lb-t-heading-xs-line-height);
  color: var(--lb-fg-default);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-playbar__artist {
  margin: 0;
  font-size: var(--lb-t-body-xs-font-size);
  color: var(--lb-fg-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.lb-playbar__transport {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--lb-size-1x);
  flex: 2 1 20rem;
  min-width: 0;
}
.lb-playbar__buttons { display: flex; align-items: center; gap: var(--lb-size-1x); }
/* Toggle buttons (shuffle/repeat): pressed = accent. */
.lb-playbar .lb-icon-btn[aria-pressed="true"] {
  color: var(--lb-fg-accent);
  background: var(--lb-bg-accent-muted);
}
.lb-playbar__scrub {
  display: flex;
  align-items: center;
  gap: var(--lb-size-2x);
  width: 100%;
  font-size: var(--lb-t-caption-s-font-size);
  color: var(--lb-fg-muted);
  font-variant-numeric: tabular-nums;
}
.lb-playbar__scrub .lb-slider-track-wrap { flex: 1; }
.lb-playbar__utils {
  display: flex;
  align-items: center;
  gap: var(--lb-size-1x);
  flex: 1 1 8rem;
  justify-content: flex-end;
}
@media (max-width: 768px) {
  .lb-playbar__utils { display: none; }
  .lb-playbar__transport { flex-basis: auto; }
}

/* ═══════════════════════════════════════════════════════════
   KANBAN BOARD — Stage-5 item #2 (board/column/card vocabulary).
   The projection model: columns are values of a field, the DS owns
   zero data. Cards are .lb-card--sm compositions with a fixed slot
   layout (title → labels → footer) so scanning survives density
   (NN/g). Menu-move (LB.Board kebab) is the canonical WCAG 2.5.7
   path; pointer drag is progressive enhancement on top. */

.lb-board { display: flex; align-items: flex-start; gap: var(--lb-size-3x); overflow-x: auto; padding-bottom: var(--lb-size-2x); }
.lb-board__column { flex: 0 0 17rem; /* design-intent: column width */ display: flex; flex-direction: column; background: var(--lb-bg-strong); border-radius: var(--lb-radius-surface); max-height: 100%; min-width: 0; }
.lb-board__column-header { display: flex; align-items: center; gap: var(--lb-size-2x); padding: var(--lb-size-3x) var(--lb-size-3x) var(--lb-size-2x); }
.lb-board__column-title { font-family: var(--lb-t-heading-2xs-font-family); font-size: var(--lb-t-heading-2xs-font-size); font-weight: var(--lb-t-heading-2xs-font-weight); line-height: var(--lb-t-heading-2xs-line-height); letter-spacing: var(--lb-t-heading-2xs-letter-spacing); color: var(--lb-fg-default); }
.lb-board__column-header .lb-menu-wrapper { margin-left: auto; }
.lb-board__column-header .lb-menu-wrapper > ul.lb-menu,
.lb-board__card .lb-menu-wrapper > ul.lb-menu { left: auto !important; right: 0 !important; }
.lb-board__column-body { display: flex; flex-direction: column; gap: var(--lb-size-2x); padding: var(--lb-size-1x) var(--lb-size-3x); overflow-y: auto; min-height: var(--lb-size-16x); flex: 1; }
.lb-board__column-footer { padding: var(--lb-size-2x) var(--lb-size-3x) var(--lb-size-3x); }
.lb-board__column-footer .lb-btn { width: 100%; justify-content: flex-start; }

/* Card recipe — fixed slots: body = title row (+ hover/focus-reveal
   kebab, media-card precedent) then labels; people + time live in the
   Card component's CANONICAL .lb-card__footer (--spread), whose
   built-in hairline gives the footer its own zone (owner-decided
   2026-08-04 over a flat, divider-free footer). */
.lb-board__card .lb-card__body { display: block; }
.lb-board__card-row { display: flex; align-items: flex-start; gap: var(--lb-size-2x); }
.lb-board__card-title { flex: 1; font-size: var(--lb-t-body-s-font-size); line-height: var(--lb-t-body-s-line-height); font-weight: var(--lb-font-weight-medium); color: var(--lb-fg-default); }
.lb-board__card-kebab { opacity: 0; transition: opacity var(--lb-animation-dur-fast) var(--lb-animation-ease-ui); }
.lb-board__card:hover .lb-board__card-kebab,
.lb-board__card:focus-within .lb-board__card-kebab { opacity: 1; }
.lb-board__card-meta { display: flex; flex-wrap: wrap; gap: var(--lb-size-1x); margin-top: var(--lb-size-2x); }
.lb-board__card-due { font-size: var(--lb-t-caption-s-font-size); color: var(--lb-fg-muted); white-space: nowrap; }
/* Board cards run the footer more compact than the --sm default
   (12px → 8px vertical) — dense columns want the tighter rhythm. */
.lb-board__card .lb-card__footer { padding-top: var(--lb-size-2x); padding-bottom: var(--lb-size-2x); }
@media (prefers-reduced-motion: reduce) {
  .lb-board__card-kebab { transition: none; }
}

/* Drag state + empty-column coexistence. The live card is the drop
   preview (house pattern from the playlist reorder); an empty-state
   inside a column body yields whenever real cards are present. */
.lb-board__card { cursor: grab; }
.lb-board__card--dragging { opacity: 0.9; box-shadow: var(--lb-shadow-modal); cursor: grabbing; }
.lb-board__column-body:has([data-lb-board-card]) > .lb-empty-state { display: none; }
.lb-board__card--grabbed { outline: var(--lb-border-width-medium) solid var(--lb-border-focus); outline-offset: var(--lb-size-0-5x); box-shadow: var(--lb-shadow-modal); }

/* Card-content vocabulary. Due-date states are the card's primary
   signal: overdue=danger, due-soon=warning, done=success — and never
   leave red on a completed card, which reads as an unresolved error.
   ID is plain muted mono. Stats are quiet icon+count pairs, not
   bordered pills. */
.lb-board__card-due--overdue { color: var(--lb-fg-danger); }
.lb-board__card-due--soon { color: var(--lb-fg-warning); }
.lb-board__card-due--done { color: var(--lb-fg-success); }
.lb-board__card-id { font-family: var(--lb-t-code-s-font-family); font-size: var(--lb-t-code-s-font-size); font-weight: var(--lb-t-code-s-font-weight); line-height: var(--lb-t-code-s-line-height); color: var(--lb-fg-muted); }
.lb-board__card-stats { display: inline-flex; align-items: center; gap: var(--lb-size-2x); color: var(--lb-fg-muted); font-size: var(--lb-t-caption-s-font-size); }
.lb-board__card-stat { display: inline-flex; align-items: center; gap: var(--lb-size-0-5x); }
.lb-board__card-stat [data-lb-icon] { width: var(--lb-size-3-5x); height: var(--lb-size-3-5x); }
