/* GENERATED — DO NOT EDIT.
 * Theme custom properties (:root, [data-theme]) come from
 *   resources/bao/tokens/tokens.bao
 * Rule bodies, composition, layering, and manifest-derived utilities come from
 *   resources/bao/styles.bao
 * HIG stamps derive from
 *   resources/bao/design-canon.json
 * Generated source APIs implement the declared style.emission plan.
 * Edit canonical sources, then run `bun run compile:bao:all`.
 */

@layer base {
  :root {
    --font-sans: -apple-system, BlinkMacSystemFont, 'SF Pro', system-ui, 'Segoe UI', sans-serif;
    --font-brand: -apple-system, BlinkMacSystemFont, 'SF Pro', system-ui, 'Segoe UI', sans-serif;
    --font-mono: ui-monospace, 'SF Mono', SFMono-Regular, Menlo, Monaco, Consolas, monospace;
    --font-weight-normal: 400;
    --font-weight-medium: 500;
    --font-weight-semibold: 600;
    --font-weight-bold: 700;
    --text-2xs: 0.6875rem;
    --text-xs: 0.75rem;
    --text-sm: 0.875rem;
    --text-base: 1rem;
    --text-lg: 1.125rem;
    --text-xl: 1.25rem;
    --text-2xl: 1.5rem;
    --text-3xl: 1.875rem;
    --text-4xl: 2.25rem;
    --leading-tight: 1.25;
    --leading-snug: 1.375;
    --leading-normal: 1.5;
    --leading-relaxed: 1.625;
    --tracking-tighter: -0.026em;
    --tracking-tight: -0.02em;
    --tracking-normal: 0em;
    --tracking-wide: 0.025em;
    --tracking-wider: 0.05em;
    --tracking-otp: 0.35em;
    --tracking-control: -0.01em;
    --tracking-display: 0.01em;
    --tracking-eyebrow: 0.04em;
    --accent-hover: #11436E;
    --accent-primary: #16548A;
    --accent-primary-content: #ffffff;
    --accent-secondary: #B04C1B;
    --accent-secondary-content: #ffffff;
    --accent-secondary-hover: #893B15;
    --annotation-accent: #0369a1;
    --annotation-canvas-bg: #f0f1f3;
    --annotation-grid: #71717a;
    --annotation-grid-major: #71717a;
    --annotation-grid-minor: #dfe1e5;
    --annotation-on-surface: #18181b;
    --annotation-paper-white: #ffffff;
    --annotation-pin: #0369a1;
    --annotation-redact-fill: #000000;
    --annotation-slide-edge: #ffffff;
    --annotation-stroke: #b91c1c;
    --annotation-stroke-ai-pending: #b45309;
    --annotation-stroke-measurement: #0369a1;
    --annotation-stroke-rejected: #7f1d1d;
    --annotation-stroke-selected: #1766A8;
    --annotation-surface: #ffffff;
    --bg-app: #f2f2f7;
    --bg-panel: #ffffff;
    --bg-surface: #eeeef0;
    --bg-surface-hover: #e5e5ea;
    --black: #000000;
    --border-base: #d1d1d6;
    --border-control: #73737a;
    --focus-ring-color: #1766A8;
    --glass-button-highlight: rgba(255, 255, 255, 0.36);
    --glass-button-tint-opacity: 0.96;
    --glass-control-border: rgba(60, 60, 67, 0.18);
    --glass-control-fill: rgba(255, 255, 255, 1);
    --glass-edge-fade: rgba(0, 0, 0, 0.06);
    --glass-fill-bg: rgba(255, 255, 255, 1);
    --glass-fill-border: rgba(60, 60, 67, 0.14);
    --glass-highlight-clear: rgba(255, 255, 255, 0);
    --glass-highlight-soft: rgba(255, 255, 255, 0.12);
    --glass-highlight-strong: rgba(255, 255, 255, 0.72);
    --glass-illumination-soft: rgba(255, 255, 255, 0.08);
    --glass-illumination-strong: rgba(255, 255, 255, 0.16);
    --glass-mask-source: #ffffff;
    --glass-noise-blend: overlay;
    --glass-noise-size: 128px;
    --glass-noise-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.03'/%3E%3C/svg%3E");
    --glass-scrim: rgba(0, 0, 0, 0.35);
    --glass-scrollbar-thumb: color-mix(in oklab, var(--color-base-content) 40%, transparent);
    --glass-scrollbar-track: transparent;
    --glass-shadow-soft: rgba(0, 0, 0, 0.09);
    --glass-shadow-strong: rgba(0, 0, 0, 0.14);
    --glass-specular-radius-max: 6px;
    --heatmap-background: #f0f1f3;
    --heatmap-coverage: #0369a1;
    --heatmap-series-1: #0369a1;
    --heatmap-series-2: #a84d08;
    --heatmap-series-3: #6d28d9;
    --heatmap-series-4: #065f46;
    --heatmap-series-5: #be123c;
    --heatmap-series-6: #854d0e;
    --lg-pointer-angle: 135deg;
    --liquid-blur-clear: 10px;
    --liquid-blur-mobile: 10px;
    --liquid-blur-nav: 32px;
    --liquid-blur-none: 0px;
    --liquid-blur-regular: 20px;
    --liquid-blur-small: 14px;
    --liquid-blur-tablet: 18px;
    --liquid-border-clear: rgba(60, 60, 67, 0.36);
    --liquid-border-contrast: rgba(24, 24, 27, 0.65);
    --liquid-border-regular: rgba(60, 60, 67, 0.32);
    --liquid-fill-blocking: 0.90;
    --liquid-fill-clear: 0.22;
    --liquid-fill-control: 0.18;
    --liquid-fill-persistent: 0.80;
    --liquid-fill-persistent-coarse: 0.86;
    --liquid-fill-tinted: 0.84;
    --liquid-fill-transient: 0.88;
    --liquid-lens-blur: 1;
    --liquid-lens-frequency: 0.012 0.012;
    --liquid-lens-octaves: 2;
    --liquid-lens-scale: -28;
    --liquid-lens-seed: 7;
    --liquid-saturate-clear: 1.4;
    --liquid-saturate-mobile: 1.5;
    --liquid-saturate-regular: 1.5;
    --liquid-saturate-strong: 1.9;
    --liquid-saturate-tablet: 1.5;
    --overlay-backdrop: rgba(0, 0, 0, 0.35);
    --overlay-btn-secondary-bg: rgba(255, 255, 255, 0.12);
    --overlay-btn-secondary-border: rgba(255, 255, 255, 0.25);
    --overlay-grid-line: rgba(255, 255, 255, 0.3);
    --overlay-label-bg: rgba(0, 0, 0, 0.75);
    --overlay-shade: rgba(0, 0, 0, 0.5);
    --overlay-text-dim: rgba(255, 255, 255, 0.7);
    --overlay-text-muted: rgba(255, 255, 255, 0.85);
    --overlay-text-primary: #ffffff;
    --overlay-toolbar-bg: rgba(0, 0, 0, 0.82);
    --overlay-toolbar-border: rgba(255, 255, 255, 0.1);
    --status-error: #b91c1c;
    --status-error-content: #ffffff;
    --status-info: #0369a1;
    --status-info-content: #ffffff;
    --status-success: #065f46;
    --status-success-content: #ffffff;
    --status-warning: #a84d08;
    --status-warning-content: #ffffff;
    --text-primary: #18181b;
    --text-secondary: #52525b;
    --text-tertiary: #606068;
    --white: #ffffff;
    --space-2xs: 0.125rem;
    --space-xs: 0.1875rem;
    --space-page: 1rem;
    --space-section: 0.75rem;
    --space-inline: 0.5rem;
    --space-micro: 0.25rem;
    --space-lg: 1.25rem;
    --space-xl: 1.5rem;
    --space-2xl: 2rem;
    --space-3xl: 3rem;
    --space-empty: 3rem;
    --radius-control: 0.75rem;
    --radius-panel: 1.25rem;
    --radius-xs: 0.25rem;
    --radius-sm: 0.5rem;
    --radius-md: 0.75rem;
    --radius-lg: 1rem;
    --radius-xl: 1.25rem;
    --radius-2xl: 1.5rem;
    --radius-full: 9999px;
    --radius-none: 0;
    --touch-target-min: max(2.75rem, 44px);
    --checkbox-mark-size: 1.5rem;
    --control-mini: max(2.75rem, 44px);
    --control-small: max(2.75rem, 44px);
    --control-regular: 2.75rem;
    --control-large: 3.25rem;
    --control-xlarge: 4rem;
    --sidebar-row-small: max(2.75rem, 44px);
    --sidebar-row-medium: max(2.75rem, 44px);
    --sidebar-row-large: 2.75rem;
    --pane-divider: 1px;
    --inspector-pane-min: 14rem;
    --inspector-pane-max: 32rem;
    --breakpoint-sm: 640px;
    --breakpoint-md: 768px;
    --breakpoint-lg: 1024px;
    --breakpoint-xl: 1280px;
    --breakpoint-2xl: 1536px;
    --duration-instant: 0ms;
    --duration-fast: 120ms;
    --duration-normal: 300ms;
    --duration-slow: 400ms;
    --duration-press: 80ms;
    --duration-focus-pulse: 1.5s;
    --duration-skeleton: 1.8s;
    --duration-progress: 2s;
    --duration-reduced-motion-calm: 150ms;
    --easing-standard: cubic-bezier(0.22, 1, 0.36, 1);
    --easing-entrance: cubic-bezier(0.05, 0.7, 0.1, 1);
    --easing-exit: cubic-bezier(0.3, 0, 0.8, 0.15);
    --reduced-motion-min-duration: 120ms;
    --entrance-offset: 0.375rem;
    --stagger-step: 30ms;
    --view-transition-new-delay: 80ms;
    --duration-pulse: 800ms;
    --duration-pulse-alpha: 1000ms;
    --pulse-alpha-floor: 0.55;
    --pulse-scale-peak: 1.05;
    --opacity-disabled: 0.5;
    --opacity-muted: 0.55;
    --opacity-soft: 0.65;
    --opacity-medium: 0.75;
    --opacity-strong: 0.85;
    --opacity-near: 0.9;
    --opacity-chrome: 0.92;
    --hover-scale: 1.02;
    --focus-ring-width: 2px;
    --focus-ring-offset: 2px;
    --focus-ring-offset-snug: 1px;
    --focus-ring-offset-tight: -2px;
    --focus-panel-ring-alpha: 40%;
    --density-compact-row-height: 2rem;
    --density-compact-font-size: 0.8125rem;
    --density-default-row-height: 2.25rem;
    --density-default-font-size: 0.875rem;
    --density-comfortable-row-height: 2.5rem;
    --density-comfortable-font-size: 0.9375rem;
    --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.04);
    --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.08), 0 2px 4px -2px rgb(0 0 0 / 0.08);
    --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.08), 0 4px 6px -4px rgb(0 0 0 / 0.08);
    --shadow-glass-elevated: 0 8px 28px -6px var(--glass-shadow-strong), 0 2px 8px -3px var(--glass-shadow-soft);
    --shadow-glass-floating: 0 16px 40px -12px var(--glass-shadow-strong), 0 4px 12px -4px var(--glass-shadow-soft);
    --shadow-glass-clear: 0 1px 0 0 var(--liquid-border-clear) inset, 0 4px 16px -6px var(--glass-shadow-soft);
    --shadow-glass-inner: 0 1px 0 0 color-mix(in oklab, var(--glass-highlight-strong) 60%, transparent) inset, 0 -1px 0 0 color-mix(in oklab, var(--glass-shadow-soft) 30%, transparent) inset;
    --shadow-overlay-toolbar: 0 -4px 12px -2px rgb(0 0 0 / 0.20);
    --z-base: 0;
    --z-local: 1;
    --z-raised: 2;
    --z-raised-high: 3;
    --z-tabs-sticky: 5;
    --z-canvas-base: 1;
    --z-canvas-empty: 20;
    --z-canvas-overlay: 30;
    --z-canvas-interaction: 31;
    --z-content-overlay: 10;
    --z-table-header: 10;
    --z-table-action: 20;
    --z-shell-drawer: 1125;
    --z-shell-drawer-overlay: 1300;
    --z-shell-topbar: 1250;
    --z-dropdown: 1250;
    --z-sticky: 1100;
    --z-overlay: 1200;
    --z-modal: 1300;
    --z-toast: 1400;
    --z-tooltip: 1400;
    --page-standard: 80rem;
    --page-wide: 96rem;
    --page-full: 100%;
    --page-conversation: 48rem;
    --description: 65ch;
    --overlay-panel: 20rem;
    --auth: 28rem;
    --form: 44rem;
    --grid-track-min: 18rem;
    --grid-panel-quarter-min: 12rem;
    --grid-panel-third-min: 16rem;
    --grid-panel-half-min: 24rem;
    --grid-panel-span-min: 38rem;
    --grid-form-min: 16rem;
    --grid-choice-min: 14rem;
    --grid-context-min: 10rem;
    --dock-primary-basis: 32rem;
    --dock-side-basis: 15rem;
    --dock-side-wide-basis: 18rem;
    --selection-column-width: 2.5rem;
    --editor-canvas-basis: 32rem;
    --editor-canvas-overlays-basis: var(--sidebar-expanded);
    --editor-3d-basis: 28rem;
    --editor-inspector-basis: 24rem;
    --editor-tool-rail-basis: 12rem;
    --editor-palette-basis: 14rem;
    --media-primary-basis: 24rem;
    --media-inspector-basis: 20rem;
    --training-workspace-basis: 26rem;
    --training-context-basis: 18rem;
    --chat-empty-action-basis: 9.5rem;
    --skeleton-panel-min-height: 7rem;
    --skeleton-media-min-height: 12rem;
    --chat-panel-width: 28rem;
    --sheet-panel-width: 20rem;
    --sheet-panel-max-width: 85vw;
    --sheet-panel-max-height: min(72dvh, 32rem);
    --command-palette-max-width: 48rem;
    --keyboard-shortcuts-max-width: 36rem;
    --settings-dialog-max-width: 56rem;
    --palette-max-height: 16rem;
    --scroll-edge-fade: 1.5rem;
    --scroll-edge-mask: linear-gradient(to bottom, transparent, black var(--scroll-edge-fade));
    --modal-max-height: min(92dvh, 92vh);
    --modal-default-max-width: 32rem;
    --modal-tablet-max-width: 40rem;
    --modal-scroll-max-height: min(70dvh, 70vh);
    --modal-body-max-height: min(58dvh, 58vh);
    --editor-root-min-height: calc(100dvh - 8rem);
    --editor-canvas-height: clamp(26rem, 58vh, 44rem);
    --canvas-region-min-height: clamp(18rem, 42vh, 30rem);
    --panel-scroll-max-height: min(70dvh, 70vh);
    --panel-body-min-height: 15rem;
    --rail-composer-min-height: 15rem;
    --composer-min-height: 5rem;
    --composer-max-height: 20rem;
    --attachment-preview-size: 5rem;
    --scroll-pt-shell: 3.5rem;
    --scroll-pt-main: 3rem;
    --scroll-mt-section: 6rem;
    --shell-drawer-width: 20rem;
    --shell-drawer-max-viewport: 88vw;
    --brand-mark-size: 2.5rem;
    --icon-gutter: 2rem;
    --page-gutter-inline: min(clamp(1rem, 2vw, 1.5rem), 5vw);
    --page-gutter-block: clamp(0.75rem, 1.5vw, 1.25rem);
    --page-gutter-inline-compact: min(clamp(0.75rem, 3vw, 1rem), 5vw);
    --page-section-gap: clamp(0.75rem, 1.5vw, 1.5rem);
    --scroll-edge-width: 2.5rem;
    --scroll-edge-cue-width: 0.875rem;
    --scroll-edge-cue-opacity: 14%;
    --scroll-edge-cue-opacity-contrast: 55%;
    --toolbar-search-max-width: 7rem;
    --toolbar-spacer-min-width: 0.5rem;
    --table-row-actions-max-inline: 16rem;
    --table-identifier-column-width: 8rem;
    --table-timestamp-column-width: 10rem;
    --table-prose-min-inline: 14rem;
    --toolbar-label-reveal-max-width: 12rem;
    --toolbar-action-pad-inline: 0.625rem;
    --toast-max-inline-size: 20rem;
    --dock-label-max-width: 4.5rem;
    --space-compact: 0.375rem;
    --tracking-label: 0.01em;
    --annotation-stroke-width-base: 2;
    --annotation-stroke-width-hairline: 1;
    --annotation-stroke-width-volume: 6;
    --annotation-sphere-radius-px: 12;
    --annotation-volume-proxy-size-px: 32;
    --annotation-pen-scale-min: 0.55;
    --annotation-pen-scale-range: 1.45;
    --annotation-grid-spacing-px: 50;
    --annotation-point-radius-px: 4;
    --annotation-label-font-size-px: 18;
    --tooltip-max-width: 20rem;
    --tooltip-viewport-inset: 0.75rem;
    --table-column-min: 4rem;
    --table-column-max: 32rem;
    --sidebar-expanded: 16rem;
    --sidebar-collapsed: 4rem;
    --session-rail-expanded: 18rem;
    --session-rail-collapsed: 3rem;
    --session-rail-min: 12rem;
    --session-rail-max: 32rem;
    --session-rail-main-min: 36rem;
    --session-rail-resize-step: 1rem;
    --session-rail-resize-step-large: 4rem;
  }

  [data-theme="capture-dx-dark"] {
    --accent-hover: #65c4eb;
    --accent-primary: #41B6E6;
    --accent-primary-content: #0c1017;
    --accent-secondary: #F56E28;
    --accent-secondary-content: #18181b;
    --accent-secondary-hover: #FF8040;
    --annotation-accent: #41B6E6;
    --annotation-canvas-bg: #1e2633;
    --annotation-grid: #71717a;
    --annotation-grid-major: #71717a;
    --annotation-grid-minor: #273242;
    --annotation-on-surface: #f4f4f5;
    --annotation-paper-white: #ffffff;
    --annotation-pin: #41B6E6;
    --annotation-redact-fill: #000000;
    --annotation-slide-edge: #151b24;
    --annotation-stroke: #dc2626;
    --annotation-stroke-ai-pending: #d97706;
    --annotation-stroke-measurement: #41B6E6;
    --annotation-stroke-rejected: #f87171;
    --annotation-stroke-selected: #1E73BE;
    --annotation-surface: #151b24;
    --bg-app: #101012;
    --bg-panel: #1c1c1e;
    --bg-surface: #2c2c2e;
    --bg-surface-hover: #3a3a3c;
    --black: #000000;
    --border-base: #48484a;
    --border-control: #9b9da1;
    --focus-ring-color: #41B6E6;
    --glass-button-highlight: rgba(255, 255, 255, 0.22);
    --glass-button-tint-opacity: 0.88;
    --glass-control-border: rgba(255, 255, 255, 0.18);
    --glass-control-fill: rgba(28, 28, 30, 1);
    --glass-edge-fade: rgba(0, 0, 0, 0.22);
    --glass-fill-bg: rgba(28, 28, 30, 1);
    --glass-fill-border: rgba(255, 255, 255, 0.12);
    --glass-highlight-clear: rgba(255, 255, 255, 0);
    --glass-highlight-soft: rgba(255, 255, 255, 0.06);
    --glass-highlight-strong: rgba(255, 255, 255, 0.36);
    --glass-illumination-soft: rgba(255, 255, 255, 0.05);
    --glass-illumination-strong: rgba(255, 255, 255, 0.14);
    --glass-mask-source: #ffffff;
    --glass-noise-blend: overlay;
    --glass-noise-size: 128px;
    --glass-noise-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.02'/%3E%3C/svg%3E");
    --glass-scrim: rgba(0, 0, 0, 0.35);
    --glass-scrollbar-thumb: color-mix(in oklab, var(--color-base-content) 40%, transparent);
    --glass-scrollbar-track: transparent;
    --glass-shadow-soft: rgba(0, 0, 0, 0.18);
    --glass-shadow-strong: rgba(0, 0, 0, 0.40);
    --glass-specular-radius-max: 6px;
    --heatmap-background: #1e2633;
    --heatmap-coverage: #41B6E6;
    --heatmap-series-1: #41B6E6;
    --heatmap-series-2: #e58212;
    --heatmap-series-3: #a78bfa;
    --heatmap-series-4: #25ac83;
    --heatmap-series-5: #fb7185;
    --heatmap-series-6: #facc15;
    --lg-pointer-angle: 135deg;
    --liquid-blur-clear: 10px;
    --liquid-blur-mobile: 10px;
    --liquid-blur-nav: 32px;
    --liquid-blur-none: 0px;
    --liquid-blur-regular: 20px;
    --liquid-blur-small: 14px;
    --liquid-blur-tablet: 18px;
    --liquid-border-clear: rgba(255, 255, 255, 0.30);
    --liquid-border-contrast: rgba(244, 244, 245, 0.55);
    --liquid-border-regular: rgba(255, 255, 255, 0.26);
    --liquid-fill-blocking: 0.94;
    --liquid-fill-clear: 0.26;
    --liquid-fill-control: 0.22;
    --liquid-fill-persistent: 0.82;
    --liquid-fill-persistent-coarse: 0.90;
    --liquid-fill-tinted: 0.88;
    --liquid-fill-transient: 0.92;
    --liquid-lens-blur: 1;
    --liquid-lens-frequency: 0.012 0.012;
    --liquid-lens-octaves: 2;
    --liquid-lens-scale: -28;
    --liquid-lens-seed: 7;
    --liquid-saturate-clear: 1.4;
    --liquid-saturate-mobile: 1.5;
    --liquid-saturate-regular: 1.5;
    --liquid-saturate-strong: 1.9;
    --liquid-saturate-tablet: 1.5;
    --overlay-backdrop: rgba(0, 0, 0, 0.35);
    --overlay-btn-secondary-bg: rgba(255, 255, 255, 0.12);
    --overlay-btn-secondary-border: rgba(255, 255, 255, 0.25);
    --overlay-grid-line: rgba(255, 255, 255, 0.3);
    --overlay-label-bg: rgba(0, 0, 0, 0.75);
    --overlay-shade: rgba(0, 0, 0, 0.5);
    --overlay-text-dim: rgba(255, 255, 255, 0.7);
    --overlay-text-muted: rgba(255, 255, 255, 0.85);
    --overlay-text-primary: #ffffff;
    --overlay-toolbar-bg: rgba(0, 0, 0, 0.82);
    --overlay-toolbar-border: rgba(255, 255, 255, 0.1);
    --status-error: #f87171;
    --status-error-content: #0c1017;
    --status-info: #41B6E6;
    --status-info-content: #0c1017;
    --status-success: #25ac83;
    --status-success-content: #0c1017;
    --status-warning: #e58212;
    --status-warning-content: #18181b;
    --text-primary: #f4f4f5;
    --text-secondary: #b6b6bd;
    --text-tertiary: #a4a5b0;
    --white: #ffffff;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme]) {
    --accent-hover: #65c4eb;
    --accent-primary: #41B6E6;
    --accent-primary-content: #0c1017;
    --accent-secondary: #F56E28;
    --accent-secondary-content: #18181b;
    --accent-secondary-hover: #FF8040;
    --annotation-accent: #41B6E6;
    --annotation-canvas-bg: #1e2633;
    --annotation-grid: #71717a;
    --annotation-grid-major: #71717a;
    --annotation-grid-minor: #273242;
    --annotation-on-surface: #f4f4f5;
    --annotation-paper-white: #ffffff;
    --annotation-pin: #41B6E6;
    --annotation-redact-fill: #000000;
    --annotation-slide-edge: #151b24;
    --annotation-stroke: #dc2626;
    --annotation-stroke-ai-pending: #d97706;
    --annotation-stroke-measurement: #41B6E6;
    --annotation-stroke-rejected: #f87171;
    --annotation-stroke-selected: #1E73BE;
    --annotation-surface: #151b24;
    --bg-app: #101012;
    --bg-panel: #1c1c1e;
    --bg-surface: #2c2c2e;
    --bg-surface-hover: #3a3a3c;
    --black: #000000;
    --border-base: #48484a;
    --border-control: #9b9da1;
    --focus-ring-color: #41B6E6;
    --glass-button-highlight: rgba(255, 255, 255, 0.22);
    --glass-button-tint-opacity: 0.88;
    --glass-control-border: rgba(255, 255, 255, 0.18);
    --glass-control-fill: rgba(28, 28, 30, 1);
    --glass-edge-fade: rgba(0, 0, 0, 0.22);
    --glass-fill-bg: rgba(28, 28, 30, 1);
    --glass-fill-border: rgba(255, 255, 255, 0.12);
    --glass-highlight-clear: rgba(255, 255, 255, 0);
    --glass-highlight-soft: rgba(255, 255, 255, 0.06);
    --glass-highlight-strong: rgba(255, 255, 255, 0.36);
    --glass-illumination-soft: rgba(255, 255, 255, 0.05);
    --glass-illumination-strong: rgba(255, 255, 255, 0.14);
    --glass-mask-source: #ffffff;
    --glass-noise-blend: overlay;
    --glass-noise-size: 128px;
    --glass-noise-texture: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='128' height='128'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.02'/%3E%3C/svg%3E");
    --glass-scrim: rgba(0, 0, 0, 0.35);
    --glass-scrollbar-thumb: color-mix(in oklab, var(--color-base-content) 40%, transparent);
    --glass-scrollbar-track: transparent;
    --glass-shadow-soft: rgba(0, 0, 0, 0.18);
    --glass-shadow-strong: rgba(0, 0, 0, 0.40);
    --glass-specular-radius-max: 6px;
    --heatmap-background: #1e2633;
    --heatmap-coverage: #41B6E6;
    --heatmap-series-1: #41B6E6;
    --heatmap-series-2: #e58212;
    --heatmap-series-3: #a78bfa;
    --heatmap-series-4: #25ac83;
    --heatmap-series-5: #fb7185;
    --heatmap-series-6: #facc15;
    --lg-pointer-angle: 135deg;
    --liquid-blur-clear: 10px;
    --liquid-blur-mobile: 10px;
    --liquid-blur-nav: 32px;
    --liquid-blur-none: 0px;
    --liquid-blur-regular: 20px;
    --liquid-blur-small: 14px;
    --liquid-blur-tablet: 18px;
    --liquid-border-clear: rgba(255, 255, 255, 0.30);
    --liquid-border-contrast: rgba(244, 244, 245, 0.55);
    --liquid-border-regular: rgba(255, 255, 255, 0.26);
    --liquid-fill-blocking: 0.94;
    --liquid-fill-clear: 0.26;
    --liquid-fill-control: 0.22;
    --liquid-fill-persistent: 0.82;
    --liquid-fill-persistent-coarse: 0.90;
    --liquid-fill-tinted: 0.88;
    --liquid-fill-transient: 0.92;
    --liquid-lens-blur: 1;
    --liquid-lens-frequency: 0.012 0.012;
    --liquid-lens-octaves: 2;
    --liquid-lens-scale: -28;
    --liquid-lens-seed: 7;
    --liquid-saturate-clear: 1.4;
    --liquid-saturate-mobile: 1.5;
    --liquid-saturate-regular: 1.5;
    --liquid-saturate-strong: 1.9;
    --liquid-saturate-tablet: 1.5;
    --overlay-backdrop: rgba(0, 0, 0, 0.35);
    --overlay-btn-secondary-bg: rgba(255, 255, 255, 0.12);
    --overlay-btn-secondary-border: rgba(255, 255, 255, 0.25);
    --overlay-grid-line: rgba(255, 255, 255, 0.3);
    --overlay-label-bg: rgba(0, 0, 0, 0.75);
    --overlay-shade: rgba(0, 0, 0, 0.5);
    --overlay-text-dim: rgba(255, 255, 255, 0.7);
    --overlay-text-muted: rgba(255, 255, 255, 0.85);
    --overlay-text-primary: #ffffff;
    --overlay-toolbar-bg: rgba(0, 0, 0, 0.82);
    --overlay-toolbar-border: rgba(255, 255, 255, 0.1);
    --status-error: #f87171;
    --status-error-content: #0c1017;
    --status-info: #41B6E6;
    --status-info-content: #0c1017;
    --status-success: #25ac83;
    --status-success-content: #0c1017;
    --status-warning: #e58212;
    --status-warning-content: #18181b;
    --text-primary: #f4f4f5;
    --text-secondary: #b6b6bd;
    --text-tertiary: #a4a5b0;
    --white: #ffffff;
    }
  }
}


@layer base {
  /* One presentation owner keeps native scrollbars visible on every scrollport. */
  :root {
    scrollbar-color: var(--glass-scrollbar-thumb) var(--glass-scrollbar-track);
  }
  * {
    scrollbar-width: thin;
  }
  /* Reserve classic scrollbar width only on declared vertical scroll owners.
   * Bounded overflow-hidden frames and horizontal-only tracks keep their full
   * content width. An explicitly vertical document root follows this same rule. */
  :where(.overflow-y-auto, .overflow-y-scroll, .bao-scroll-edge-y, .bao-panel-scroll):not(.overflow-hidden):not(.overflow-y-hidden) {
    scrollbar-gutter: stable;
  }
}

@layer utilities {
  /* Measured overflow is the sole edge-cue owner. Masks leave the host
   * material intact; opaque local covers painted rectangles over glass even
   * when nothing overflowed. Native scrollbars remain visible in every mode.
   * Increased-contrast and forced-colors modes use the native scrollbar. */
  @media (forced-colors: none) and (prefers-contrast: no-preference) {
    .bao-scroll-edge-x:dir(ltr)[data-overflow-start="true"]:not([data-overflow-end="true"]),
    .bao-scroll-edge-x:dir(rtl)[data-overflow-end="true"]:not([data-overflow-start="true"]) {
      mask-image: linear-gradient(to right, transparent, black var(--scroll-edge-cue-width));
    }
    .bao-scroll-edge-x:dir(ltr)[data-overflow-end="true"]:not([data-overflow-start="true"]),
    .bao-scroll-edge-x:dir(rtl)[data-overflow-start="true"]:not([data-overflow-end="true"]) {
      mask-image: linear-gradient(to left, transparent, black var(--scroll-edge-cue-width));
    }
    .bao-scroll-edge-x[data-overflow-start="true"][data-overflow-end="true"] {
      mask-image: linear-gradient(to right, transparent, black var(--scroll-edge-cue-width), black calc(100% - var(--scroll-edge-cue-width)), transparent);
    }
    /*
     * Vertical twin for block scrollports (menu sheets, popover panels). The
     * same observer stamps data-overflow-start/end from scrollTop against
     * scrollHeight, and the mask fades only the edge that still hides rows.
     * Mask-only on purpose: these hosts paint Liquid Glass through the
     * background shorthand, so the inline utility's background-image cue
     * would be reset by the material rule and never show.
     */
    .bao-scroll-edge-y[data-overflow-start="true"]:not([data-overflow-end="true"]) {
      mask-image: linear-gradient(to bottom, transparent, black var(--scroll-edge-cue-width));
    }
    .bao-scroll-edge-y[data-overflow-end="true"]:not([data-overflow-start="true"]) {
      mask-image: linear-gradient(to top, transparent, black var(--scroll-edge-cue-width));
    }
    .bao-scroll-edge-y[data-overflow-start="true"][data-overflow-end="true"] {
      mask-image: linear-gradient(to bottom, transparent, black var(--scroll-edge-cue-width), black calc(100% - var(--scroll-edge-cue-width)), transparent);
    }
  }
  /* daisyUI 5 .carousel sets scrollbar-width: none. Hide is banned; utilities restore the shared thin scrollbar. */
  .carousel {
    scrollbar-width: thin;
  }
  .carousel::-webkit-scrollbar {
    display: block;
    width: 6px;
    height: 6px;
  }
}


@layer utilities {
  /* Stacking context for sticky filter chrome — named SSOT, not raw Tailwind-only. */
  .isolation-isolate { isolation: isolate; }

  /*
   * Sticky filter host: creates a stacking context so dropdowns/menus from the
   * bar paint above scrolling table bodies without z-index wars.
   */
  .bao-filter-bar-sticky:not([data-filter-sheet-open="true"]) {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky, 10);
    isolation: isolate;
  }

  /*
   * Dense queue row action cluster (annotation-review / clinical queues).
   *
   * The cluster wraps, but a wrapping box still measures its max-content until
   * something caps it — and this one sits in a `white-space: nowrap` pinned
   * cell, so its natural width became the column's. Measured 2026-08-22 at
   * 1440x900: /medical-ai-review carries three actions and its Actions column
   * came to 371px, taking the table to 1233px inside a 1042px scrollport. The
   * fitter had already given up both expendable columns, so its only move left
   * was to release the shelf, and the third action then sat off the right edge
   * with no scrollbar under it.
   *
   * Two labelled actions on a line is the cap: `--table-row-actions-max-inline`
   * is the width of two soft buttons and their gap, so a two-action queue keeps
   * its single row and a third action takes a second line inside the cell
   * instead of taking width from the columns beside it. Every action stays
   * painted, which is the contract this cluster exists to keep.
   */
  .bao-queue-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-micro);
    justify-content: flex-end;
    min-width: 0;
    max-inline-size: var(--table-row-actions-max-inline, 16rem);
  }

  /* Typography / text colors */
  .text-base-content { color: var(--text-primary); }
  .text-base-content\/70 { color: color-mix(in oklab, var(--text-primary) 70%, var(--text-secondary)); }
  .text-base-content\/60 { color: var(--text-secondary); }
  .text-base-content\/40 { color: var(--text-tertiary); }
  .text-accent-primary { color: var(--accent-primary); }
  .text-accent-hover { color: var(--accent-hover); }
  .text-accent-secondary { color: var(--accent-secondary); }
  .text-accent-secondary-hover { color: var(--accent-secondary-hover); }
  .text-status-success { color: var(--status-success); }
  .text-status-success-content { color: var(--status-success-content); }
  .text-status-error { color: var(--status-error); }
  .text-status-error-content { color: var(--status-error-content); }
  .text-status-warning { color: var(--status-warning); }
  .text-status-warning-content { color: var(--status-warning-content); }
  .text-status-info { color: var(--status-info); }
  .text-status-info-content { color: var(--status-info-content); }
  .text-accent-primary-content { color: var(--accent-primary-content); }
  .text-accent-secondary-content { color: var(--accent-secondary-content); }

  /* Background colors */
  .bg-base-100 { background-color: var(--bg-panel); }
  .bg-base-200 { background-color: var(--bg-surface); }
  .bg-base-300 { background-color: var(--bg-surface-hover); }
  .bg-accent-primary { background-color: var(--accent-primary); }
  .bg-accent-hover { background-color: var(--accent-hover); }
  .bg-accent-secondary { background-color: var(--accent-secondary); }
  .bg-accent-secondary-hover { background-color: var(--accent-secondary-hover); }
  .bg-status-success { background-color: var(--status-success); }
  .bg-status-error { background-color: var(--status-error); }
  .bg-status-warning { background-color: var(--status-warning); }
  .bg-status-info { background-color: var(--status-info); }
  .bg-border-base { background-color: var(--border-base); }
  .bg-accent-primary\/5 { background-color: color-mix(in oklab, var(--accent-primary) 5%, transparent); }
  .bg-status-error\/10 { background-color: color-mix(in oklab, var(--status-error) 10%, transparent); }
  .bg-status-info\/10 { background-color: color-mix(in oklab, var(--status-info) 10%, transparent); }
  .bg-status-warning\/10 { background-color: color-mix(in oklab, var(--status-warning) 10%, transparent); }
.bg-status-error\/20 { background-color: color-mix(in oklab, var(--status-error) 20%, transparent); }
  .bg-status-success\/20 { background-color: color-mix(in oklab, var(--status-success) 20%, transparent); }
  .bg-status-warning\/20 { background-color: color-mix(in oklab, var(--status-warning) 20%, transparent); }
  .ring-status-error\/30 { --tw-ring-color: var(--status-error); }
  @supports (color: color-mix(in lab, red, red)) {
    .ring-status-error\/30 { --tw-ring-color: color-mix(in oklab, var(--status-error) 30%, transparent); }
  }
  .ring-status-warning\/30 { --tw-ring-color: var(--status-warning); }
  @supports (color: color-mix(in lab, red, red)) {
    .ring-status-warning\/30 { --tw-ring-color: color-mix(in oklab, var(--status-warning) 30%, transparent); }
  }
  .bg-base-100\/95 { background-color: color-mix(in oklab, var(--bg-panel) 95%, transparent); }
  .bg-base-100\/90 { background-color: color-mix(in oklab, var(--bg-panel) 90%, transparent); }
  .bg-base-100\/80 { background-color: color-mix(in oklab, var(--bg-panel) 80%, transparent); }
  .border-status-error { border-color: var(--status-error); }
  .border-status-success { border-color: var(--status-success); }
  .border-status-warning { border-color: var(--status-warning); }
  .border-status-info { border-color: var(--status-info); }
  .border-status-error\/30 { border-color: color-mix(in oklab, var(--status-error) 30%, transparent); }
  .border-status-error\/40 { border-color: color-mix(in oklab, var(--status-error) 40%, transparent); }
  .border-status-warning\/40 { border-color: color-mix(in oklab, var(--status-warning) 40%, transparent); }
  .border-status-info\/40 { border-color: color-mix(in oklab, var(--status-info) 40%, transparent); }

  /* Overlay surfaces (canvas chrome, sheets, dialogs) */
  .bg-overlay-backdrop { background-color: var(--overlay-backdrop); }
  .bg-overlay-shade { background-color: var(--overlay-shade); }
  .bg-overlay-toolbar-bg { background-color: var(--overlay-toolbar-bg); }
  .border-overlay-toolbar-border { border-color: var(--liquid-border-regular); }
  .bg-overlay-toolbar-border { background-color: var(--overlay-toolbar-border); }
  .text-overlay-text-primary { color: var(--overlay-text-primary); }
  .text-overlay-text-muted { color: var(--overlay-text-muted); }
  .text-overlay-text-dim { color: var(--overlay-text-dim); }
  .bg-overlay-label-bg { background-color: var(--overlay-label-bg); }

  /* Border colors */
  .border-base-300 { border-color: var(--border-base); }
  .border-accent-primary { border-color: var(--accent-primary); }

  /* Radius */
  .rounded-radius-control { border-radius: var(--radius-control); }
  .rounded-radius-panel { border-radius: var(--radius-panel); }
  .rounded-md { border-radius: var(--radius-control); }
  .rounded-xl { border-radius: var(--radius-panel); }
  .rounded-full { border-radius: var(--radius-full); }

  /* Shadows */
  .shadow-sm { box-shadow: var(--shadow-sm); }
  .shadow-md { box-shadow: var(--shadow-md); }
  .shadow-lg { box-shadow: var(--shadow-lg); }
  .shadow-shadow-overlay-toolbar { box-shadow: var(--shadow-overlay-toolbar); }

/* Spacing */
  .p-space-page { padding: var(--space-page); }
  .p-space-section { padding: var(--space-section); }
  .p-space-inline { padding: var(--space-inline); }
  .p-space-micro { padding: var(--space-micro); }
  .p-space-empty { padding: var(--space-empty); }
  /* Skip-link focus chrome — tokenized padding, not raw focus:p-3. */
  .focus\:p-space-section:focus { padding: var(--space-section); }
  .pt-0 { padding-top: 0; }
  .gap-space-page { gap: var(--space-page); }
  .gap-space-section { gap: var(--space-section); }
  .gap-space-inline { gap: var(--space-inline); }
  .gap-space-micro { gap: var(--space-micro); }

  /* 2xs hairline scale — mirrors the micro set so *-space-2xs utilities
     always resolve (class-resolution gate; tokens.bao space-2xs). */
  .gap-space-2xs { gap: var(--space-2xs); }
  .gap-x-space-2xs { column-gap: var(--space-2xs); }
  .gap-y-space-2xs { row-gap: var(--space-2xs); }
  .p-space-2xs { padding: var(--space-2xs); }
  .px-space-2xs { padding-inline: var(--space-2xs); }
  .py-space-2xs { padding-block: var(--space-2xs); }
  .pt-space-2xs { padding-top: var(--space-2xs); }
  .pb-space-2xs { padding-bottom: var(--space-2xs); }
  .ps-space-2xs { padding-inline-start: var(--space-2xs); }
  .pe-space-2xs { padding-inline-end: var(--space-2xs); }
  .mt-space-2xs { margin-top: var(--space-2xs); }
  .mb-space-2xs { margin-bottom: var(--space-2xs); }
  .space-y-space-2xs > * + * { margin-top: var(--space-2xs); }
  .gap-x-space-micro { column-gap: var(--space-micro); }
  .gap-x-space-inline { column-gap: var(--space-inline); }
  .gap-x-space-section { column-gap: var(--space-section); }
  .gap-y-space-micro { row-gap: var(--space-micro); }
  .gap-y-space-inline { row-gap: var(--space-inline); }
  .gap-y-space-section { row-gap: var(--space-section); }
  .px-space-page { padding-inline: var(--space-page); }
  .px-space-section { padding-inline: var(--space-section); }
  .px-space-inline { padding-inline: var(--space-inline); }
  .px-space-micro { padding-inline: var(--space-micro); }
  .px-page-gutter-inline { padding-inline: var(--page-gutter-inline); }
  .px-page-gutter-inline-compact { padding-inline: var(--page-gutter-inline-compact); }
  .bao-content-inset-section { padding-inline: min(var(--space-section), 5%); }
  .bao-content-inset-inline { padding-inline: min(var(--space-inline), 5%); }
  .bao-content-inset-micro { padding-inline: min(var(--space-micro), 5%); }
  .py-space-page { padding-block: var(--space-page); }
  .py-space-section { padding-block: var(--space-section); }
  .py-space-inline { padding-block: var(--space-inline); }
  .py-space-micro { padding-block: var(--space-micro); }
  .py-space-empty { padding-block: var(--space-empty); }
  .pe-space-inline { padding-inline-end: var(--space-inline); }
  .pe-space-section { padding-inline-end: var(--space-section); }
  .pe-space-micro { padding-inline-end: var(--space-micro); }
  /* Logical padding-inline-start family, mirroring the pe- set above so
     *-space-* utilities always resolve (class-resolution gate). */
  .ps-space-page { padding-inline-start: var(--space-page); }
  .ps-space-section { padding-inline-start: var(--space-section); }
  .ps-space-inline { padding-inline-start: var(--space-inline); }
  .ps-space-micro { padding-inline-start: var(--space-micro); }
  .me-space-inline { margin-inline-end: var(--space-inline); }
  .me-space-micro { margin-inline-end: var(--space-micro); }
  .ms-space-page { margin-inline-start: var(--space-page); }
  .ms-space-section { margin-inline-start: var(--space-section); }
  .ms-space-inline { margin-inline-start: var(--space-inline); }
  .start-space-inline { inset-inline-start: var(--space-inline); }
  .start-space-section { inset-inline-start: var(--space-section); }
  .start-space-micro { inset-inline-start: var(--space-micro); }
  .end-space-inline { inset-inline-end: var(--space-inline); }
  .end-space-section { inset-inline-end: var(--space-section); }
  .end-space-micro { inset-inline-end: var(--space-micro); }
  .ps-icon-gutter { padding-inline-start: var(--icon-gutter); }
  .pe-icon-gutter { padding-inline-end: var(--icon-gutter); }
  .scroll-pt-shell { scroll-padding-top: var(--scroll-pt-shell); }
  .scroll-pt-main { scroll-padding-top: var(--scroll-pt-main); }
  .scroll-mt-section { scroll-margin-top: var(--scroll-mt-section); }
  .m-space-inline { margin: var(--space-inline); }
  .mx-space-micro { margin-inline: var(--space-micro); }
  .mx-space-inline { margin-inline: var(--space-inline); }
  .mx-space-section { margin-inline: var(--space-section); }
  .my-space-micro { margin-block: var(--space-micro); }
  .my-space-inline { margin-block: var(--space-inline); }
  .mt-space-page { margin-top: var(--space-page); }
  .mt-space-section { margin-top: var(--space-section); }
  .mt-space-inline { margin-top: var(--space-inline); }
  .mt-space-micro { margin-top: var(--space-micro); }
  .mb-space-page { margin-bottom: var(--space-page); }
  .mb-space-section { margin-bottom: var(--space-section); }
  .mb-space-inline { margin-bottom: var(--space-inline); }
  .mb-space-micro { margin-bottom: var(--space-micro); }
  .pt-space-page { padding-top: var(--space-page); }
  .pt-space-section { padding-top: var(--space-section); }
  .pt-space-inline { padding-top: var(--space-inline); }
  .pt-space-micro { padding-top: var(--space-micro); }
  .pb-space-page { padding-bottom: var(--space-page); }
  .pb-space-section { padding-bottom: var(--space-section); }
  .pb-space-inline { padding-bottom: var(--space-inline); }
  .pb-space-micro { padding-bottom: var(--space-micro); }
  .inset-x-space-section { inset-inline: var(--space-section); }
  .inset-x-space-inline { inset-inline: var(--space-inline); }
  .top-space-section { top: var(--space-section); }
  .top-space-inline { top: var(--space-inline); }
  .top-space-micro { top: var(--space-micro); }
  /* Physical right family, mirroring top-/bottom- — used beside physical
     top-full anchors (enterprise-editor view-adjust panel). */
  .right-space-page { right: var(--space-page); }
  .right-space-section { right: var(--space-section); }
  .right-space-inline { right: var(--space-inline); }
  .right-space-micro { right: var(--space-micro); }
  .bottom-space-section { bottom: var(--space-section); }
  .bottom-space-inline { bottom: var(--space-inline); }
  .bottom-space-micro { bottom: var(--space-micro); }
  .inset-x-space-micro { inset-inline: var(--space-micro); }
  /* Full-inset family — scanner reticle overlays inset the capture page
     gutter (Scan.bao reticle: absolute inset-space-page). */
  .inset-space-page { inset: var(--space-page); }
  .inset-space-section { inset: var(--space-section); }
  .inset-space-inline { inset: var(--space-inline); }
  .inset-space-micro { inset: var(--space-micro); }
  .max-h-panel-body { max-height: var(--panel-body-min-height); }
  .space-y-space-section > * + * { margin-top: var(--space-section); }
  .space-y-space-page > * + * { margin-top: var(--space-page); }
  .space-y-space-inline > * + * { margin-top: var(--space-inline); }
  .space-y-space-micro > * + * { margin-top: var(--space-micro); }
  /*
   * Negative inline margin — lets a sticky dock bleed to the edges of a
   * gutter-padded parent (login submit dock) so its border and background span
   * the full surface instead of floating inset. Tailwind cannot generate this
   * from an arbitrary custom property, so the token owns it.
   */
  .-mx-space-inline { margin-inline: calc(var(--space-inline) * -1); }

  /*
   * Negative block margin — lets an inline row target grow to the HIG 44pt
   * touch floor (min-h-11) and pay the growth back so its list row keeps its
   * height. Tailwind cannot generate this from a custom property, so the
   * token owns it.
   */
  .-my-space-section { margin-block: calc(var(--space-section) * -1); }



  /* Layout */
  /* Parent marker for descendant state variants (toolbar/tooltips). */

  /* Structural utilities (.flex, .hidden, .grid, .items-…, .justify-…, .w-full)
     are intentionally NOT re-declared here. Tailwind is their single owner:
     a flat copy in this later-loaded sheet lands after Tailwind's
     breakpoint-gated variants in the same utilities layer and silently beats
     them (e.g. a re-declared .flex-wrap killed max-sm:flex-nowrap; .hidden
     killed hidden sm:flex). Only token-valued classes belong in this file. */
  .w-sidebar-expanded { width: var(--sidebar-expanded); }
  .size-brand-mark {
    width: var(--brand-mark-size);
    height: var(--brand-mark-size);
  }
  .min-w-control { min-width: var(--density-compact-row-height); }
  /* Fluid shell tracks — CSS vars from tokens.bao (no invented rem).
     max-width clamps to the viewport so end-anchored dropdowns never
     paint past the right edge on phone-width shells. */
  .bao-width-menu-lg {
    /* Preferred tracks are independent of the anchor area; popovers own viewport caps. */
    width: var(--dock-side-wide-basis);
    max-width: min(100%, var(--dock-side-wide-basis));
  }
  .bao-width-menu-md {
    width: var(--grid-choice-min);
    max-width: min(100%, var(--grid-choice-min));
  }
   .bao-width-avatar { width: var(--icon-gutter); }
   .bao-width-sheet {
     width: min(100%, var(--sheet-panel-width));
     max-width: min(100%, var(--sheet-panel-max-width));
   }
   .bao-width-rail-collapsed { width: var(--session-rail-collapsed); }
   .bao-width-selection-col { width: var(--selection-column-width); }
   .bao-max-w-search { max-width: min(100%, var(--dock-primary-basis)); }
   .bao-max-w-command { --modal-box-track: var(--command-palette-max-width); max-width: min(100%, var(--command-palette-max-width)); }
   .bao-max-w-shortcuts { --modal-box-track: var(--keyboard-shortcuts-max-width); max-width: min(100%, var(--keyboard-shortcuts-max-width)); }
   .bao-max-w-settings { --modal-box-track: var(--settings-dialog-max-width); max-width: min(100%, var(--settings-dialog-max-width)); }
   /* Topbar chips size via flex tracks in shell responsive CSS — no hard 10rem cap. */
   .bao-max-w-context-chip { max-width: 100%; min-width: 0; }
   /* Topbar actions: cap width on narrow so brand/title keep room; scroll overflow. */
   .bao-max-w-topbar-actions { max-width: 50%; }
   .bao-max-w-voice-status { max-width: min(10rem, 60vw); }
   @media (min-width: 40rem) {
     .bao-max-w-voice-status { max-width: min(16rem, 60vw); }
   }
   /* Toolbar search + flex spacer — tokens.bao layoutSize (no max-w-28 / min-w-2). */
   .bao-max-w-toolbar-search { max-width: min(100%, var(--toolbar-search-max-width)); }
   .bao-min-w-toolbar-spacer { min-width: var(--toolbar-spacer-min-width); }
   @media (min-width: 40rem) {
     .bao-max-w-topbar-actions { max-width: none; }
   }
   /* Sticky topbar clears notch / status bar on phones and tablets.
      Keep padding-top explicit (never padding-block) so safe-area wins. */
   .navbar.z-shell-topbar {
      padding-top: max(var(--safe-area-inset-top, var(--space-micro, 0.25rem)), env(safe-area-inset-top, 0px));
      padding-bottom: var(--space-micro, 0.25rem);
      padding-inline-start: max(var(--safe-area-inset-left, var(--space-inline)), env(safe-area-inset-left, 0px));
      padding-inline-end: max(var(--safe-area-inset-right, var(--space-inline)), env(safe-area-inset-right, 0px));
   }
   @media (min-width: 40rem) {
     .navbar.z-shell-topbar {
       padding-inline-start: max(var(--space-section), env(safe-area-inset-left, 0px));
       padding-inline-end: max(var(--space-section), env(safe-area-inset-right, 0px));
     }
   }
   .bao-max-h-palette { max-height: var(--palette-max-height); }
   .bao-field-basis { flex-basis: min(100%, var(--grid-context-min)); }
   .bao-control-h { height: var(--density-compact-row-height); }
   .min-w-56 { min-width: min(100%, var(--grid-choice-min)); }
   .h-space-page { height: var(--space-page); }
   .h-space-section { height: var(--space-section); }
   .h-space-inline { height: var(--space-inline); }
   .h-space-micro { height: var(--space-micro); }
   .bao-min-h-panel-body { min-height: var(--panel-body-min-height); }
   .bao-min-h-rail-composer { min-height: var(--rail-composer-min-height); }
   .bao-max-h-modal { max-height: var(--modal-max-height); }
   .bao-max-h-modal-scroll { max-height: var(--modal-scroll-max-height); }
   .bao-max-h-modal-body { max-height: var(--modal-body-max-height); }
   .bao-max-h-composer { max-height: var(--composer-max-height); }
   .bao-min-h-panel-scroll { min-height: var(--panel-scroll-max-height); }
   .max-w-3xl { max-width: var(--command-palette-max-width); }
   .max-w-4xl { max-width: var(--settings-dialog-max-width); }
   .max-w-6xl { max-width: var(--page-wide); }
   .max-w-56 { max-width: var(--grid-choice-min); }
   .max-w-chip { max-width: var(--max-w-chip, 14rem); }
   .max-w-dropdown { max-width: min(100vw - 2rem, var(--max-w-dropdown, 20rem)); }
   .max-w-page { max-width: var(--page-standard); }
  .z-canvas-base { z-index: var(--z-canvas-base); }
  .z-canvas-empty { z-index: var(--z-canvas-empty, 20); }
  .z-canvas-overlay { z-index: var(--z-canvas-overlay); }
  .z-content-overlay { z-index: var(--z-content-overlay); }
  .z-table-header { z-index: var(--z-table-header); }
  .z-table-action { z-index: var(--z-table-action); }
  .z-shell-drawer { z-index: var(--z-shell-drawer); }
  .z-shell-drawer-overlay { z-index: var(--z-shell-drawer-overlay); }
  .z-shell-topbar { z-index: var(--z-shell-topbar); }
  .z-dropdown { z-index: var(--z-dropdown); }
  .z-sticky { z-index: var(--z-sticky); }
  .z-overlay { z-index: var(--z-overlay); }
  .z-modal { z-index: var(--z-modal); }

  /* Locale chrome hooks (locale-chrome-trigger / locale-switcher-form).
     Marker hides the summary disclosure glyph; list-style here and the
     WebKit pseudo below are the cross-engine pair (Tailwind's list-none
     covers only the standard property). */
  .bao-details-marker-hidden { list-style: none; }
  .bao-details-marker-hidden::-webkit-details-marker { display: none; }
  /* The switch form lives in a dropdown panel: a flex/grid child that must
     yield so long locale labels overflow the select (which carries its own
     min-w-0 max-w-full) instead of widening the panel past its host. */
  .bao-locale-switcher { min-width: 0; max-width: 100%; }
  .z-toast { z-index: var(--z-toast); }

  /* The native skip link enters document flow on focus. Chrome-aligned token
     margins preserve its shared focus-ring paint room and both safe-area
     sources; the unfocused link retains its above-viewport waiting state. */
  .bao-skip-link {
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0;
    transform: translateY(-100%);
    display: inline-flex;
    flex-shrink: 0;
    align-self: flex-start;
    max-inline-size: 100%;
    align-items: center;
    justify-content: center;
    white-space: normal;
    overflow-wrap: anywhere;
    padding-inline: var(--space-section);
    font-size: var(--text-sm);
    background: var(--color-primary);
    color: var(--color-primary-content);
  }
  .bao-skip-link:focus {
    position: relative;
    transform: translateY(0);
    z-index: var(--z-tooltip);
    margin-block-start: calc(var(--space-micro) + max(var(--safe-area-inset-top, 0px), env(safe-area-inset-top, 0px)));
    margin-block-end: var(--space-micro);
    margin-inline: max(var(--space-inline), var(--safe-area-inset-left, 0px), env(safe-area-inset-left, 0px))
      max(var(--space-inline), var(--safe-area-inset-right, 0px), env(safe-area-inset-right, 0px));
  }

  /* Grid base utilities (.grid/.grid-cols-*) live in Tailwind only — see the
     structural-utilities note above; re-declaring them here beats Tailwind's
     responsive grid-cols variants. */
  /* Responsive variants (sm:/md:/lg:/xl:) are intentionally NOT defined here —
     hand-written flat copies have no @media gate and apply at every width,
     overriding Tailwind's correctly breakpoint-gated utilities. Tailwind
     generates these from the scanned templates; leave them to it. */



/*
 * Inspector disclosure — one visible disclosure control in every workbench
 * band (Apple sidebars: a pane collapses to its labelled control, it is never
 * removed). Utilities layer so the attribute rule still beats the nested
 * daisyUI .btn display inside the same layer tree; the rail-docked variant
 * below is the ONE display:none owner (see the cascade test).
 */
[data-inspector-toggle] {
  display: inline-flex;
}

/*
 * The physical session rail owns disclosure for its live Inspector: when the
 * editor chrome docks the inspector into the rail, duplicate stage controls
 * retire. One rule covers descendants and the portalled 3D stage handle.
 */
[data-editor-chrome][data-inspector-dock="rail"] [data-inspector-toggle]:not([hidden]):not(.hidden),
body:has([data-editor-chrome][data-inspector-dock="rail"]) [data-inspector-toggle]:not([hidden]):not(.hidden) {
  display: none;
}


.bao-capture-device-grid {
  display: grid;
  width: 100%;
  min-width: 0;
  align-items: stretch;
  gap: var(--space-inline);
  /* Phone: single column so empty-hint fieldsets never sit beside short peers. */
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 40rem) {
  .bao-capture-device-grid {
    /* auto-fill (not fit) avoids 0px phantom tracks beside 3 short fieldsets. */
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 14rem), 1fr));
  }
}
  /*
   * Fluid KPI stat strip — auto-fit tracks, never hardcoded counts: a phone
   * width yields 2-up, wide hosts 4-up, purely from available inline size
   * (§8.6 canonical transformation; replaces stats-vertical stacking that
   * spent ~140px of viewport per number on compact shells).
   */
  .bao-grid-stats {
    display: grid;
    min-width: 0;
    width: 100%;
    align-items: stretch;
    gap: var(--space-inline, 0.5rem);
    grid-template-columns: repeat(auto-fit, minmax(min(9rem, 100%), 1fr));
  }
  /* Solid metric host — content plane; never glass (pairs with .bao-stat-card). */
  .bao-stat-card {
    background-color: var(--color-base-100, var(--bg-panel));
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /* Page content track — never let max-w-full win over enterprise max-w-page-*. */
  .bao-page-track {
    width: 100%;
    min-width: 0;
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--page-section-gap, var(--space-section));
    /*
     * §8.6 canonical transformation — page track is the container query host
     * (enterprise-page @container class). Nested grids reflow off rendered
     * track width, not viewport, so split panels and embedded widgets collapse
     * correctly without per-page media forks.
     */
    container-type: inline-size;
  }
  /*
   * Page-track container column transforms — one owner for collection/form/
   * detail grids inside the content column (never duplicate in page partials).
   */
  @container (max-width: 36rem) {.bao-page-track .bao-context-grid-reactive,
.bao-page-track .bao-grid-reactive-collection {
      grid-template-columns: minmax(0, 1fr);
    }
    /*
     * KPI stat strips keep auto-fit (Cached|Loaded 2-up on phone). Forcing
     * single-column here burned a full viewport row per number (models pipeline).
     * .bao-grid-stats base owns minmax(min(9rem, 100%), 1fr) fluid tracks.
     */
  }
  .bao-page-track.max-w-page-standard {
    max-width: var(--page-standard, 80rem);
  }
  .bao-page-track.max-w-page-wide {
    max-width: var(--page-wide, 96rem);
  }
  .bao-page-track.max-w-page-full {
    max-width: none;
  }

/* The stat group already owns its inset; cells must not add a second gutter. */
.bao-grid-stats > .stat {
  padding-inline: 0;
}

/* Content-sized groups share one sizing policy across grid and panel projections. */
.bao-grid-content {
  --bao-panel-grid-align: start;
  --bao-panel-height: auto;
  --bao-panel-min-height: 0;
}

  .bao-state-glyph-sm { width: var(--space-xl); height: var(--space-xl); }
  .bao-state-glyph-md { width: var(--space-3xl); height: var(--space-3xl); }
  .bao-state-glyph-lg { width: var(--control-xlarge); height: var(--control-xlarge); }


  /*
   * Page-header primary CTAs (New Case, etc.): HIG 44px min height.
   * daisyUI .btn-sm sets a fixed height (~32px); override height+max-height
   * so min-height actually expands the control for touch.
   */
  [data-page-header-actions] > .btn.btn-primary,
  [data-page-header-actions] > a.btn.btn-primary,
  [data-page-header-actions] > .btn.btn-primary.btn-sm,
  [data-page-header-actions] > a.btn.btn-primary.btn-sm,
  [data-primitive="PageHeader"] [data-page-header-actions] > .btn.btn-primary,
  [data-primitive="PageHeader"] [data-page-header-actions] > a.btn.btn-primary {
    /* daisyUI 5 sizes buttons via --size; raise it so btn-sm is still 44px. */
    --size: var(--touch-target-min, 2.75rem);
    min-height: var(--touch-target-min, 2.75rem);
    height: var(--touch-target-min, 2.75rem);
    max-height: none;
    min-width: 0;
  }

  /*
   * Dual-title ban — SOLE owner of shell-title visibility.
   * Demote the shell title only when a content H1 is the visible name. The
   * verdict is NOT re-derived here: pages-renderers-header.ts stamps
   * data-page-header-mode on the PageHeader, app-shell JS mirrors it onto
   * <body> for WebView 101 (no :has()), and the :has() branch reads the same
   * stamp so first paint matches post-hydration. The old structural probe
   * (PageHeader > div:not(.sr-only) h1) matched the crumbs wrapper that the
   * demoted layout emits ahead of the sr-only title block, so every page
   * resolved to content mode and BOTH titles ended up clipped.
   *
   * display:none, not the sr-only clip: a demoted shell title is a duplicate
   * of the visible H1, so it must leave the accessibility tree with the
   * pixels. #shell-page-title carries no aria-hidden, so clipping it here
   * would double-announce the page name on content-mode surfaces.
   */
  body[data-page-header-mode="content"] [data-shell-page-title],
  body:has([data-primitive="PageHeader"][data-page-header-mode="content"]) [data-shell-page-title] {
    display: none;
  }


  /*
   * Happydumpling shell law: [data-shell-scroll="main"] is a flex host. Standard pages scroll
   * on main; immersive pages (media/conversation) do not — the thread/canvas does.
   * Content column uses max-width + centered track for non-immersive pages.
   */
  [data-shell-scroll="main"] {
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
    flex: 1 1 0%;
    width: 100%;
    max-width: 100%;
    /* Inline-size containment keeps nested min-content tables from inflating scrollWidth. */
    contain: inline-size;
    overflow-y: auto;
    overscroll-behavior-x: none;
    /* Sticky topbar must not obscure focused controls (WCAG 2.4.11). */
    scroll-padding-top: var(--scroll-pt-main, var(--chrome-min-height, 3.5rem));
    /* Block-end scroll clearance is owned by tokens-layout-dock. */
  }
  /* Direct children only — a universal descendant min-width reset lets any
     flex child collapse and paint over siblings (phone toolbar pile-ups). */
  [data-shell-scroll="main"] > * {
    box-sizing: border-box;
    min-width: 0;
  }
  /* Scroll hosts own wide content; do not inflate [data-shell-scroll="main"].scrollWidth. */
  [data-shell-scroll="main"] .bao-data-panel,
  [data-shell-scroll="main"] .overflow-x-auto,
  [data-shell-scroll="main"] .bao-panel-scroll {
    max-width: 100%;
  }
  [data-shell-scroll="main"] pre,
  [data-shell-scroll="main"] code {
    max-width: 100%;
    overflow-x: auto;
  }
  [data-shell-scroll="main"] > [data-page]:not([data-page-type="media"]):not([data-page-type="conversation"]) {
    width: 100%;
    min-width: 0;
    max-width: 100%;
  }
  [data-shell-scroll="main"]:not(:has([data-page-type="media"])):not(:has([data-page-type="conversation"])) {
    overflow-x: clip;
    overflow-y: auto;
    scroll-behavior: smooth;
    /* Happydumpling fluid gutters: clamp tracks, not flat 12px.
     * padding-block-end is owned by dock clearance SSOT (tokens-layout-dock)
     * so this higher-specificity rule cannot wipe mobile dock room. */
    padding-block-start: var(--page-gutter-block);
    /* Notched phones / home indicator — keep content out of unsafe insets. */
    padding-inline-start: max(var(--page-gutter-inline), env(safe-area-inset-left, 0px));
    padding-inline-end: max(var(--page-gutter-inline), env(safe-area-inset-right, 0px));
  }
  /* Mobile: compact inline gutter under tight viewports. */
  @media (max-width: 48rem) {
    [data-shell-scroll="main"]:not(:has([data-page-type="media"])):not(:has([data-page-type="conversation"])) {
      padding-inline-start: max(var(--page-gutter-inline-compact), env(safe-area-inset-left, 0px));
      padding-inline-end: max(var(--page-gutter-inline-compact), env(safe-area-inset-right, 0px));
    }
  }
  /* Reduced motion: the ID+:has() selector above (1,x,x) out-specificities the
     universal a11y clamp, so main-scroll snapping gets its own override —
     mirrors the .bao-shell-sidebar pattern in tokens-glass-shell-webview-surfaces. */
  @media (prefers-reduced-motion: reduce) {
    [data-shell-scroll="main"]:not(:has([data-page-type="media"])):not(:has([data-page-type="conversation"])) {
      scroll-behavior: auto;
    }
  }

  /*
   * Page chrome density (Apple HIG / Hick's law): phone keeps ≤1 labeled primary
   * CTA; secondary chrome is icon+tooltip only. Prefer progressive disclosure
   * over packing 6+ labeled controls in one row.
   */
  @media (max-width: 48rem) {
    /*
     * Scroll-edge fade: clipped actions stay discoverable (design.pdf §9.5),
     * but ONLY over genuinely clipped content — the shell runtime
     * (app-shell-glass.ts bindActionStripOverflowState) stamps
     * data-overflow-start/end from live scroll metrics. An unconditional
     * mask fades the primary CTA even when everything fits, which reads
     * as a half-disabled control.
     */
    [data-page-header-actions][data-overflow-end="true"] {
      mask-image: linear-gradient(to right, var(--black) calc(100% - 1.25rem), transparent);
      -webkit-mask-image: linear-gradient(to right, var(--black) calc(100% - 1.25rem), transparent);
    }
    [data-page-header-actions][data-overflow-start="true"] {
      mask-image: linear-gradient(to left, var(--black) calc(100% - 1.25rem), transparent);
      -webkit-mask-image: linear-gradient(to left, var(--black) calc(100% - 1.25rem), transparent);
    }
    [data-page-header-actions][data-overflow-start="true"][data-overflow-end="true"] {
      mask-image: linear-gradient(to right, transparent, var(--black) 1.25rem, var(--black) calc(100% - 1.25rem), transparent);
      -webkit-mask-image: linear-gradient(to right, transparent, var(--black) 1.25rem, var(--black) calc(100% - 1.25rem), transparent);
    }
    /* Contrast modes: replace the fade with the native scrollbar (design.pdf §9.3).
       :is() with the attribute variants keeps this override above the
       overflow-scoped masks in specificity. */
    @media (prefers-contrast: more), (forced-colors: active) {
      :is([data-page-header-actions], [data-page-header-actions][data-overflow-start="true"], [data-page-header-actions][data-overflow-end="true"]) {
        mask-image: none;
        -webkit-mask-image: none;
      }
    }
    /*
     * Phone density: icon-only densify for ghost/outline square chrome only.
     * Primary + soft clinical secondaries (finish / generate report) keep labels
     * (design.pdf: essentials must not depend on hover).
     */
    [data-page-header-actions] .btn:not(.btn-primary):not(.btn-soft) > span:not(.sr-only):not([class*="loading"]):not(.badge) {
      display: none;
    }
    [data-page-header-actions] .btn {
      flex: 0 0 auto;
      flex-direction: row;
      align-items: center;
    }
    /* Dashboard customize trays: long panel titles → icon density / truncate. */
    [data-dashboard-visibility-tray] .btn:not(.btn-primary),
    [data-dashboard-uniform-size-tray] .btn:not(.btn-primary) {
      max-width: 10rem;
    }
    [data-dashboard-visibility-tray] .btn:not(.btn-primary) {
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    [data-primitive="PageHeader"] {
      gap: var(--space-inline, 0.5rem);
    }
    /* Page header actions: never overshoot viewport (models Customize etc.). */
    [data-page-header-actions],
    [data-primitive="PageHeader"] [data-page-header-actions] {
      overflow-x: auto;
      -webkit-overflow-scrolling: touch;
      gap: var(--space-micro, 0.25rem);
      max-width: 100%;
      min-width: 0;
      justify-content: flex-start;
      flex-wrap: wrap;
    }
    [data-page-header-actions] > .btn,
    [data-page-header-actions] > a.btn {
      max-width: 100%;
      min-width: 0;
      flex: 0 1 auto;
      /* HIG 44px primary CTAs (New Case, etc.) — btn-sm alone is 32px. */
      min-height: var(--touch-target-min, 2.75rem);
      height: auto;
    }
    [data-page-header-actions] > .btn:not(.btn-primary):not(.btn-soft),
    [data-page-header-actions] > a.btn:not(.btn-primary):not(.btn-soft) {
      width: var(--touch-target-min, 2.75rem);
      min-width: var(--touch-target-min, 2.75rem);
      max-width: var(--touch-target-min, 2.75rem);
      padding-inline: 0;
      justify-content: center;
    }
    [data-page-header-actions] > .btn.btn-soft,
    [data-page-header-actions] > a.btn.btn-soft {
      width: auto;
      max-width: none;
      min-width: var(--touch-target-min, 2.75rem);
      padding-inline: 0.5rem;
      justify-content: center;
      gap: var(--space-micro, 0.25rem);
    }
    /*
     * Keyboard cheatsheet: keep HTML hidden sm:inline-flex — do not force
     * display:none here (that wiped the control on every phone width and
     * could win over sm: for residual viewports). Phone uses user menu.
     */
    /* Tooltips as block captions under icons — kill on touch. */
    .bao-shell-topbar .tooltip::before,
    .bao-shell-topbar .tooltip::after,
    [data-page-header-actions] .tooltip::before,
    [data-page-header-actions] .tooltip::after {
      display: none;
    }
  }



  /* Immersive pages: :has for modern engines + data-main-page-type for WebView 101. */
  /* Overflow is owned by tokens-glass-shell-webview-surfaces.
   * Dock clearance is owned by tokens-layout-dock. */
  [data-shell-scroll="main"][data-main-page-type="media"],
  [data-shell-scroll="main"][data-main-page-type="conversation"],
  [data-shell-scroll="main"]:has([data-page-type="media"]),
  [data-shell-scroll="main"]:has([data-page-type="conversation"]) {
    height: 100%;
    padding-inline: 0;
    padding-block-start: 0;
  }
  /* Standard pages: consistent content column padding via main; avoid double chrome.
   * block-end is dock SSOT — never use padding-block shorthand here. */
  [data-shell-scroll="main"]:has([data-page-type="home"]),
  [data-shell-scroll="main"]:has([data-page-type="collection"]) {
    padding-block-start: var(--page-gutter-block);
  }
  [data-page-type="media"],
  [data-page-type="conversation"] {
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    flex-direction: column;
  }
  [data-shell-scroll="main"] > [data-page][data-page-type="media"],
  [data-shell-scroll="main"] > [data-page][data-page-type="conversation"] {
    min-height: 0;
    flex: 1 1 auto;
  }
  [data-page-type="media"] > [data-state-content]:not(.bao-media-session-root),
  .bao-media-page-root:not(.bao-media-session-root) {
    display: flex;
    min-height: 0;
    flex: 1 1 0%;
    flex-direction: column;
    gap: var(--space-inline);
    overflow: hidden;
  }
  /* Capture chrome: command strip shrinks, workbench owns remaining height. */
  [data-page-type="media"] [data-session-mode-panel] {
    display: flex;
    min-height: 0;
    flex: 1 1 0%;
    flex-direction: column;
    gap: var(--space-inline);
  }
  [data-page-type="media"] [data-capture-context-strip],
  [data-page-type="media"] [data-capture-command-chrome],
  [data-page-type="media"] [data-session-mode-tabs] {
    flex: 0 0 auto;
  }
  .bao-media-workbench,
  [data-page-type="media"] [data-capture-workbench] {
    display: flex;
    flex-wrap: wrap;
    min-width: 0;
    flex: 1 1 auto;
    align-items: stretch;
    gap: var(--space-section);
  }

  /*
   * Model readiness / missing-context gates — dense sticky Alert under session
   * chrome (daisyUI alert SSOT; data-model-readiness-gate owns density).
   */
  [data-page="capture"] [data-model-readiness-gate]:not([hidden]),
  [data-page="capture"] [data-capture-missing-context]:not([hidden]) {
    position: sticky;
    top: 0;
    z-index: var(--z-sticky, 1100);
    margin-block: 0;
  }
  [data-page="capture"] [data-model-readiness-gate][data-state="success"] {
    display: none;
  }
  [data-page="capture"] [data-model-readiness-gate] {
    max-width: 100%;
    overflow: hidden;
  }
  [data-page="capture"] [data-model-readiness-gate] [data-model-readiness-message],
  [data-page="capture"] [data-model-readiness-gate] [data-model-readiness-hint] {
    overflow-wrap: anywhere;
    word-break: break-word;
  }
  /* Narrow gate: full-width action row (container query, not viewport). */
  @container (max-width: 28rem) {
    [data-model-readiness-gate] [data-model-readiness-actions] {
      flex: 1 1 100%;
      justify-content: stretch;
      margin-inline-start: 0;
    }
    [data-model-readiness-gate] [data-model-readiness-actions] .btn {
      flex: 1 1 auto;
      justify-content: center;
    }
  }
/* Readiness state paint has one owner; runtime writes only the page-state contract. */
[data-model-readiness-gate][data-state="loading"] {
  border-color: color-mix(in oklab, var(--status-info) 40%, transparent);
  background-color: color-mix(in oklab, var(--status-info) 10%, transparent);
}
[data-model-readiness-gate][data-state="denied"],
[data-model-readiness-gate][data-state="error"] {
  border-color: color-mix(in oklab, var(--status-error) 40%, transparent);
  background-color: color-mix(in oklab, var(--status-error) 10%, transparent);
}
[data-model-readiness-gate][data-state="success"] {
  border-color: color-mix(in oklab, var(--status-warning) 40%, transparent);
  background-color: color-mix(in oklab, var(--status-warning) 10%, transparent);
}
[data-model-readiness-gate][data-state="loading"] [data-model-readiness-loaded-count] {
  color: var(--status-info);
}
[data-model-readiness-gate][data-state="denied"] [data-model-readiness-loaded-count],
[data-model-readiness-gate][data-state="error"] [data-model-readiness-loaded-count] {
  color: var(--status-error);
}
[data-model-readiness-gate][data-state="success"] [data-model-readiness-loaded-count] {
  color: var(--status-warning);
}


  /*
   * Media page header is sr-only (shell title owns naming). Keep a compact
   * escape hatch if a page still emits a visible header.
   */
  [data-page-type="media"] > [data-state-content] > [data-primitive="PageHeader"]:not(.sr-only) {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-micro);
    padding-block-end: var(--space-micro);
    /* Width alone inherited preflight currentColor — a full-brightness
       hairline. Divide with the same subtle token mix panels use. */
    border-block-end: 1px solid
      var(--liquid-border-regular);
  }
  [data-page-type="media"] > [data-state-content] > [data-primitive="PageHeader"]:not(.sr-only) h1 {
    font-size: var(--text-sm, 0.875rem);
    line-height: 1.25;
  }
  [data-page-type="media"] > [data-state-content] > [data-primitive="PageHeader"]:not(.sr-only) p {
    display: none;
  }
  /* Session mode tabs sit under shell chrome as primary media navigation.
     Segmented sizing SSOT: tokens-glass-shell-capture.ts. */
  [data-page-type="media"] [data-session-mode-tabs] {
    margin-block-end: 0;
  }/*
   * The phone dock for these header actions is NOT declared here. This module
   * emits inside @layer utilities,
and the canonical
   * .bao-page-header width:100% is unlayered — an unlayered declaration
   * beats a layered one regardless of specificity,
so a width set here is
   * silently discarded (measured: inline-size stayed 359px). It lives in
   * tokens-glass-shell-capture-status.ts,
which emits unlayered.
   */
  /*
   * Media full-bleed belongs to the camera/canvas STAGE only. Structured
   * chrome (page header,
journey band,
control strips) keeps the page
   * gutter — content must never shear against the viewport edge (§8.2/§9.5).
   */
  [data-page-type="media"] > [data-state-content] > [data-primitive="PageHeader"]:not(.sr-only) {
    padding-inline: var(--page-gutter-inline, var(--space-section, 0.75rem));
  }/*
   * Fine pointer: icon-first with tip/hover reveal. Coarse pointer: visible
   * compact labels — hover must not own essential media actions (design.pdf §6).
   *
   * Both branches now honour data-toolbar-density. They did not: the coarse
   * branch below gated on [data-toolbar-density="labeled"] while this one
   * clipped the editor dock unconditionally,
so the same file answered the
   * same question two ways and a dock asking for labels got them on touch and
   * lost them on a mouse.
   *
   * The clip is FINAL for the dock, not rest-only: part-1/part-2's generic
   * hover reveal (max-width/opacity + width:auto on .btn-square) is the
   * contract for STANDALONE square chrome. Inside the joined dock strip it
   * cannot work — measured 2026-09-01 at 1440x900: unclipping on hover made
   * the joined row clip every revealed label to one glyph and squash the key
   * chip, because .join members share the strip's fixed width. The dock's
   * hover surface is therefore the tooltip (data-tip carries "Ruler (M)"),
   * and aria-pressed context is carried by the button's pressed style.
   */
  @media (hover: hover) and (pointer: fine) {[data-editor-toolbar]:not([data-toolbar-density="labeled"]) [data-hig-key-hint] {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }
  }
  /* Media-session navigation and commands use the shared Workbench tracks. */
[data-page-type="media"] .bao-editor-workbench,
[data-page="capture"] .bao-editor-workbench {
    min-height: 0;
    flex: 1 1 0%;
    overflow-x: hidden;
    overflow-y: hidden;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
  }[data-page-type="media"] [data-editor-canvas-overlays],
[data-page="capture"] [data-editor-canvas-overlays] {
    max-height: 100%;
  }
/*
 * Phone capture bar (Apple Camera): the mode picker is its own centred row,
 * the shutter row puts gallery at the start, the shutter in the middle and
 * More at the end. Measured 2026-08-23 at 390x844: one flex row of picker +
 * gallery + shutter + More was 352px in a 330px bar and More painted past
 * the card edge.
 */
/*
 * Capture bar grammar at every width (Apple Camera): the shutter sits on the
 * bar's centre line, the mode picker and gallery lead, More trails — measured
 * 2026-08-23 at 1440x900 the shutter floated wherever the flex row left it.
 */
[data-page="capture"] [data-capture-preview-actions] {
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  grid-template-areas: "leading shutter more";
}
[data-page="capture"] [data-capture-preview-actions] > [data-capture-leading] {
  grid-area: leading;
  justify-self: start;
}
[data-page="capture"] [data-capture-preview-actions] > form {
  grid-area: shutter;
  justify-self: center;
}
[data-page="capture"] [data-capture-preview-actions] > [data-capture-action-bar] {
  grid-area: more;
  justify-self: end;
}
@media (max-width: 40rem) {
  [data-page="capture"] [data-capture-preview-actions] {
    grid-template-areas:
      "mode mode mode"
      "gallery shutter more";
    row-gap: var(--space-inline, 0.5rem);
  }
  /* The leading group dissolves so the picker takes its own row. */
  [data-page="capture"] [data-capture-preview-actions] > [data-capture-leading] {
    display: contents;
  }
  [data-page="capture"] [data-capture-preview-actions] [data-capture-media-mode-switch] {
    grid-area: mode;
    justify-self: center;
  }
  [data-page="capture"] [data-capture-preview-actions] [data-capture-gallery-root] {
    grid-area: gallery;
    justify-self: start;
  }
}
/*
 * The depth status line is a live region for a depth session; a device that
 * simply has no depth capture keeps the sentence for assistive tech and the
 * disabled "3D depth" segment carries it visually (its tip). A permanent
 * caption on every capture bar was noise, not status.
 */
[data-page="capture"] [data-capture-depth-status][data-state="empty"] {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}


  /* Context chips are interactive buttons — reset native button chrome. */
  button.bao-context-card {
    appearance: none;
    cursor: pointer;
    text-align: start;
    font: inherit;
    color: inherit;
  }
  /* On full Chat page, hide the rail mini-composer (same surface — no dual chat). */
  body:has([data-page="chat"]) #session-rail-live [data-session-section="ai"],
  body:has([data-page="chat"]) #chat-assistant-rail-live,
  body:has([data-page="chat"]) [data-chat-assistant-rail] {
    display: none;
  }
  /* Media tabs never steal vertical space with trailing margin. */
  [data-page-type="media"] [data-session-mode-tabs] {
    margin-bottom: 0;
  }

  .bao-composer-shell {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: 0;
    border: 1px solid var(--color-base-300);
    border-radius: var(--radius-field);
    background: var(--color-base-100);
  }
  [data-page-type="conversation"] > [data-state-content],
  .bao-conversation-shell {
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 0;
    height: 100%;
  }
  [data-shell-scroll="main"]:has([data-page-type="conversation"]) > [data-page] > [data-state-content]:not([hidden]) {
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    flex-direction: column;
  }
  .bao-conversation-messages {
    position: relative;
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    flex-direction: column;
    overflow: hidden;
  }
  /* The empty invitation remains adjacent to its editor; centered when viewport allows, scrolling as one flow when enlarged. */
  .bao-conversation-shell:has([data-chat-empty]:not([hidden])) {
    overflow-y: auto;
  }
  .bao-conversation-shell:has([data-chat-empty]:not([hidden])) > .bao-conversation-messages {
    flex: 0 0 auto;
    overflow: visible;
  }
  .bao-conversation-thread {
    min-height: 0;
    flex: 1 1 auto;
  }
  .bao-conversation-messages:has([data-chat-empty]:not([hidden])) .bao-conversation-thread {
    display: none;
  }
  .bao-conversation-footer {
    min-width: 0;
    flex: 0 0 auto;
    padding-bottom: max(var(--space-inline), env(safe-area-inset-bottom, 0px));
  }
  footer.bao-conversation-dock,
  .bao-conversation-footer.bao-conversation-dock,
  .bao-composer-dock-safe {
    background: transparent;
    border: 0;
    box-shadow: none;
  }
  .bao-conversation-shell:has([data-chat-empty]:not([hidden])) > .bao-conversation-footer {
    position: static;
  }
  .bao-composer-dock-fade {
    background: linear-gradient(
      to top,
      color-mix(in oklab, var(--color-base-100) 40%, transparent),
      transparent
    );
  }
  .bao-conversation-gutter {
    padding-inline-start: max(var(--page-gutter-inline-compact), env(safe-area-inset-left, 0px));
    padding-inline-end: max(var(--page-gutter-inline-compact), env(safe-area-inset-right, 0px));
  }
  @media (min-width: 48rem) {
    .bao-conversation-gutter {
      padding-inline-start: max(var(--page-gutter-inline), env(safe-area-inset-left, 0px));
      padding-inline-end: max(var(--page-gutter-inline), env(safe-area-inset-right, 0px));
    }
  }
  .bao-conversation-context-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    justify-content: space-between;
    border-block-end: 1px solid var(--liquid-border-regular);
  }
  .bao-conversation-context-bar > [data-model-field] {
    min-width: 0;
    flex: 1 1 var(--grid-choice-min);
    margin: 0;
  }
  .bao-conversation-context-bar > [data-chat-context] {
    min-width: 0;
    max-width: 100%;
    flex: 0 0 auto;
    align-self: flex-start;
  }
  /* Clinical context refreshes independently of model choice and editable draft. */
  .bao-chat-context-grid {
    display: flex;
    flex-wrap: wrap;
    box-sizing: border-box;
    align-items: center;
    min-width: 0;
    gap: var(--space-micro);
  }
  [data-chat-context],
  [data-chat-context].htmx-added,
  [data-chat-context] .htmx-added,
  [data-chat-context] .bao-context-card,
  [data-capture-context-strip],
  [data-capture-context-strip].htmx-added,
  [data-capture-context-strip] .htmx-added {
    animation: none;
    transform: none;
  }
  [data-chat-insert-tools] {
    min-width: 0;
    flex: 1 1 auto;
  }
  [data-chat-empty] fieldset {
    display: grid;
    grid-template-columns: var(--bao-grid-track-12-fluid);
    gap: var(--space-micro);
  }
  [data-chat-empty] fieldset > .btn {
    width: 100%;
    height: 100%;
    min-width: 0;
    max-width: 100%;
  }
  .bao-conversation-empty[hidden],
  [data-chat-empty][hidden] {
    display: none;
  }
  /* The routed conversation owns one composer; its assistant rail remains a navigation entry point. */
  body:has([data-page="chat"]) #session-rail [data-session-section="ai"],
  body:has([data-page="chat"]) #session-rail-sheet [data-session-section="ai"] {
    display: none;
  }
  /* Form/detail pages share the canonical content gutter and section rhythm. */
  [data-shell-scroll="main"]:has([data-page-type="form"]),
  [data-shell-scroll="main"]:has([data-page-type="detail"]),
  [data-shell-scroll="main"]:has([data-page-type="ops"]) {
    padding-block-start: var(--page-gutter-block);
    padding-inline: var(--page-gutter-inline);
  }
  @media (max-width: 48rem) {
    [data-shell-scroll="main"]:has([data-page-type="form"]),
    [data-shell-scroll="main"]:has([data-page-type="detail"]),
    [data-shell-scroll="main"]:has([data-page-type="ops"]) {
      padding-inline-start: max(var(--page-gutter-inline-compact), env(safe-area-inset-left, 0px));
      padding-inline-end: max(var(--page-gutter-inline-compact), env(safe-area-inset-right, 0px));
    }
  }
  @media (max-width: 40rem) {
    [data-primitive="PageHeader"] {
      align-items: stretch;
    }
    [data-primitive="PageHeader"] .card-actions {
      width: 100%;
      justify-content: flex-start;
    }
  }
  [data-page-type="form"] > [data-state-content],
  [data-page-type="detail"] > [data-state-content],
  [data-page-type="ops"] > [data-state-content] {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: var(--page-section-gap);
  }
  [data-page-type="collection"] [data-case-list],
  [data-page-type="collection"] [data-table-host],
  [data-page="cases"] [data-cases-workbench],
  .bao-table-host {
    min-width: 0;
  }

  @media (prefers-contrast: more) {
    .bao-composer-shell {
      border-width: var(--focus-ring-width);
      border-color: var(--color-base-content);
    }
  }
  @media (forced-colors: active) {
    .bao-composer-shell {
      color: CanvasText;
      background: Canvas;
      border-color: ButtonText;
    }
  }


  [data-page-type="collection"],
  [data-page-type="detail"] {
    display: flex;
    min-width: 0;
    flex: 1 1 auto;
    flex-direction: column;
    gap: var(--space-section);
  }
  [data-page-type="collection"] > [data-state-content],
  [data-page-type="detail"] > [data-state-content] {
    flex: 1 1 auto;
  }
  /* Collection pages: last interactive row clears fixed mobile dock. */
  @media (max-width: 47.99rem) {
    [data-page-type="collection"] > [data-state-content] {
      padding-block-end: calc(var(--touch-target-min, 2.75rem) + var(--space-section, 0.75rem));
    }
  }

  @media (max-width: 47.99rem) {
    [data-page-type="collection"] .overflow-y-auto,
    [data-page-type="collection"] [data-scroll-region],
    [data-page-type="collection"] .bao-panel-scroll {
      scroll-padding-bottom: calc(var(--touch-target-min, 2.75rem) + var(--space-section, 0.75rem));
      padding-block-end: calc(var(--touch-target-min, 2.75rem) + var(--space-section, 0.75rem));
    }
  }


  [data-page-type="media"] [data-capture-device-toolbar],
  [data-page-type="media"] [data-capture-command-chrome] .bao-capture-device-grid {
    gap: var(--space-micro);
    align-items: stretch;
  }
  @media (min-width: 40rem) {
    [data-page-type="media"] [data-capture-command-chrome] .bao-capture-device-grid {
      grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    }
  }


  /*
   * Background only. Layout (display/flex-direction/align/justify/gap) and —
   * critically — VISIBILITY belong to tokens-layout-capture-preview.ts, which
   * hides this placeholder while [data-capture-case-ready="false"] so the
   * case-required overlay can own the plane. Re-declaring display:flex here
   * gave that one question a second owner and defeated the conditional hide:
   * on /capture at 375px the camera-empty and case-required overlays painted
   * on top of each other ("Live Preview" over "Active case", colliding CTAs).
   * That file's own comment already said not to force display here.
   */
  .bao-preview-region > [data-camera-preview-placeholder] {
    background:
      radial-gradient(circle at 50% 40%, color-mix(in oklab, var(--color-base-content) 4%, transparent), transparent 55%);
  }
  [data-page-type="form"] [data-settings-panel] {
    max-width: none;
    width: 100%;
    min-width: 0;
  }


  @media (max-width: 47.99rem) {
    [data-page-type="collection"] {
      padding-block-end: calc(var(--touch-target-min, 2.75rem) + var(--space-section, 0.75rem));
    }
  }

  @media (max-width: 47.99rem) {
    [data-page-type="collection"] input,
    [data-page-type="collection"] .btn,
    [data-page-type="collection"] button {
      scroll-margin-block-end: calc(var(--touch-target-min, 2.75rem));
    }
  }


  /* Physical end-spacer so last controls can scroll fully above fixed dock. */
  @media (max-width: 47.99rem) {
    [data-page-type="collection"] > [data-state-content]::after {
      content: "";
      display: block;
      flex: 0 0 auto;
      width: 100%;
      height: calc(var(--dock-height, 4rem) + var(--dock-safe-area-offset, 0px) + var(--touch-target-min, 2.75rem));
      min-height: calc(var(--dock-height, 4rem) + var(--touch-target-min, 2.75rem));
      pointer-events: none;
    }
  }
/* Native page controls retain their touch geometry independently of fluid panel tracks. */
  @media (max-width: 42rem) {
[data-page-type="collection"] .card-body,
[data-page-type="collection"] form,
[data-page-type="form"] .card-body,
[data-page-type="form"] form,
[data-page-type="ops"] .card-body,
[data-page-type="ops"] form,
[data-page-type="detail"] .card-body,
[data-page-type="detail"] form {
      min-width: 0;
      width: 100%;
    }[data-page-type="collection"] .input,
[data-page-type="collection"] .select,
[data-page-type="collection"] .btn:not(.btn-square),
[data-page-type="form"] .input,
[data-page-type="form"] .select,
[data-page-type="form"] .btn:not(.btn-square),
[data-page-type="ops"] .input,
[data-page-type="ops"] .select,
[data-page-type="ops"] .btn:not(.btn-square),
[data-page-type="detail"] .input,
[data-page-type="detail"] .select,
[data-page-type="detail"] .btn:not(.btn-square) {
      min-height: var(--touch-target-min, 2.75rem);
    }
    /* Primary form submit full-width;secondary icon chrome stays square. */
    [data-page-type="collection"] form .btn.btn-primary,
[data-page-type="form"] form .btn.btn-primary,
[data-page-type="ops"] form .btn.btn-primary,
[data-page-type="detail"] form .btn.btn-primary {
      width: 100%;
      justify-content: center;
    }[data-page-type="collection"] form .btn.btn-square,
[data-page-type="form"] form .btn.btn-square,
[data-page-type="detail"] form .btn.btn-square {
      width: var(--touch-target-min, 2.75rem);
      max-width: var(--touch-target-min, 2.75rem);
    }/* Card bodies: no horizontal scroll from long mono paths / table shells.
     * Use :is() so we never emit bare bao-data-panel multi-selectors that
     * the solid-content-plane gate mistakes for glass co-tagging. */
    [data-page-type="collection"] :is(.card, .bao-data-panel):not(.bao-table-scroll-x),
[data-page-type="detail"] :is(.card, .bao-data-panel):not(.bao-table-scroll-x) {
      overflow-x: clip;
      max-width: 100%;
    }/* Form fieldsets: full-bleed rows on phone (settings + licensing). */
    [data-page-type="form"] .bao-settings-group.fieldset,
[data-page-type="collection"] .bao-settings-group.fieldset,
[data-page-type="form"] fieldset.bao-settings-group,
[data-page-type="collection"] fieldset.bao-settings-group {
      width: 100%;
      max-width: none;
    }
  }/* Dashboard embeds one dense case list inside one widget surface. Rows are
     separators,
never a second card layer. */
  [data-page-type="home"] [data-case-list] tbody {
    gap: 0;
  }
  [data-page-type="home"] [data-case-list] tbody > tr {
    border: 0;
    border-block-end: 1px solid var(--border-base);
    border-radius: 0;
    background: transparent;
    box-shadow: none;
    padding: var(--space-inline) 0;
  }
  [data-page-type="home"] [data-case-list] tbody > tr:last-child {
    border-block-end: 0;
  }

  /* Page header densify — phone-first title stack (happydumpling topbar rhythm). */
  [data-primitive="PageHeader"] {
    gap: var(--space-inline);
  }
  [data-primitive="PageHeader"] h1 {
    font-size: var(--text-xl, 1.25rem);
    line-height: 1.2;
  }
  [data-primitive="PageHeader"] p {
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.35;
    color: var(--text-secondary);
  }
  /*
   * Page type answered the viewport and then stopped: the title held
   * --text-xl from 48rem to 4K and the lead paragraph held --text-xs at every
   * width above phone, so a 27" display rendered the page title at the same
   * 20px as a tablet and its supporting copy at 12px. These steps are keyed to
   * the CONTAINER, not the viewport, so a header inside a narrow inspector
   * pane keeps the compact size while the same primitive on a wide page grows
   * — the rest of this layout is already container-driven, and type was the
   * one axis still asking the window how big it was.
   *
   * Every step lands on the canonical tokens.bao ramp (xs -> sm, xl -> 2xl),
   * so computed-token-audit still grades each rendered size against a declared
   * stop instead of a free-floating fluid value.
   */
  @container (min-width: 48rem) {
    [data-primitive="PageHeader"] p {
      font-size: var(--text-sm, 0.875rem);
    }
  }
  @container (min-width: 64rem) {
    [data-primitive="PageHeader"] h1 {
      font-size: var(--text-2xl, 1.5rem);
    }
  }
  @media (max-width: 40rem) {
    [data-primitive="PageHeader"] [data-page-header-actions] {
      gap: var(--space-micro);
    }
    [data-primitive="PageHeader"] [data-page-header-actions] .btn {
      /* WCAG/HIG: never shrink header CTAs below 44px on phone. */
      min-height: var(--touch-target-min, 2.75rem);
      height: auto;
      min-width: var(--touch-target-min, 2.75rem);
      padding-inline: var(--space-inline);
      font-size: var(--text-sm);
    }
  }

  /*
   * Operational solid tiles — dense data surfaces (content plane).
   * Page-type SSoT: collection + home DashboardWidget / bao-data-panel.
   * Glass is chrome-only;:not(.bao-surface-glass-*) is a hard ban so a
   * mis-tagged glass class never inherits content-tile paint.
   */
  [data-page-type="collection"] .bao-data-panel:not(.bao-surface-glass-regular):not(.bao-surface-glass-clear),
[data-page-type="home"] [data-dashboard-widget].bao-data-panel:not(.bao-surface-glass-regular):not(.bao-surface-glass-clear),
[data-page-type="home"] .card.bao-data-panel:not(.bao-surface-glass-regular):not(.bao-surface-glass-clear) {
    border: 1px solid var(--liquid-border-regular);
    border-radius: var(--radius-panel);
    background: var(--bg-panel);
    box-shadow:
      0 1px 0 color-mix(in oklab, var(--bg-panel) 65%, transparent) inset,
      0 1px 2px color-mix(in oklab, var(--text-primary) 6%, transparent);
  }




  .bao-case-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-inline);
    max-block-size: var(--palette-max-height);
    overflow-y: auto;
    overscroll-behavior-block: contain;
    margin: 0;
    padding: 0;
    list-style: none;
  }
  /*
   * Closed <details> must not paint the list. Author `display:flex` on
   * .bao-case-list outranks the UA closed-content hide in Chromium, so the
   * list kept real boxes (and PE:auto cards) while the host stayed summary-
   * height only — case cards stacked over specimen select/add (capture@tablet
   * reachability). Explicit :not([open]) hide + [open] re-show is the fix.
   */
  details[data-case-picker-disclosure]:not([open]) > .bao-case-list,
  details[data-case-picker-disclosure]:not([open]) > :not(summary) {
    display: none;
  }
  details[data-case-picker-disclosure] > summary {
    /* The disclosure trigger must own its tappable area above the open list:
       the list once painted over the summary's bottom strip (z-raised) and
       stole its HIG 44pt edge — measured on /specimens. One step above the
       list's own token so the trigger always out-ranks it. */
    position: relative;
    z-index: calc(var(--z-raised, 2) + 1);
    pointer-events: auto;
  }
  details[data-case-picker-disclosure][open] > .bao-case-list {
    display: flex;
    flex-direction: column;
  }
  /*
   * Specimen create disclosure: author flex on the form host left the submit
   * ("Add specimen") with a real box while closed — visual gate stamped it
   * then timed out on click (/specimens dual-walk).
   */
  details[data-specimen-create-disclosure]:not([open]) > :not(summary),
  details[data-specimen-create-disclosure]:not([open]) ~ [data-specimen-create-form-panel] {
    display: none;
  }
  .bao-case-card {
    /* visible: auto+intrinsic collapsed layout while cards painted full size (reachability). */
    content-visibility: auto;
    contain-intrinsic-size: auto 5rem;
    position: relative;
    z-index: var(--z-local, 1);
    isolation: isolate;
    scroll-margin-block-end: calc(var(--dock-height, 4rem) + var(--touch-target-min, 2.75rem));
    display: flex;
    flex-direction: column;
    gap: var(--space-micro);
    margin: 0;
    padding: var(--space-section);
    /*
     * The border belongs to the template, not to this class. All three
     * `.bao-case-card` hosts — case-picker, case-option and
     * case-empty-option — compose their own `border border-base-300/70
     * border-s-4 …` utilities, and a shorthand here reset all four widths
     * from a stylesheet that loads after Tailwind's, in the same layer and at
     * the same specificity. Measured on /specimens: the picker's 4px
     * selection accent and the case list's 4px `border-s-primary/40` edge
     * both rendered at 1px, so a selected case was a hairline like every
     * other card. Only the radius stays, because no host states one.
     */
    border-radius: var(--radius-field, 0.75rem);
    background: var(--bg-panel);
    box-shadow: 0 1px 2px color-mix(in oklab, var(--text-primary) 5%, transparent);
    overflow: hidden;
    min-width: 0;
  }

  @media (max-width: 47.99rem) {
    .bao-case-list-host {
      padding: var(--space-micro);
    }
    .bao-case-list {
      gap: var(--space-micro);
    }
    .bao-case-card {
      padding-block: var(--space-micro);
      padding-inline: var(--space-inline);
      gap: var(--space-micro);
    }
  }
  .bao-case-card {
    transition:
      border-color var(--duration-fast) var(--easing-standard),
      box-shadow var(--duration-fast) var(--easing-standard),
      transform var(--duration-fast) var(--easing-standard);
  }
  @media (hover: hover) and (pointer: fine) {
    .bao-case-card:hover {
      border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
      box-shadow: var(--shadow-sm);
      transform: translateY(-1px);
    }
  }
  .bao-case-card:active {
    transform: scale(0.99);
  }
  .bao-case-card:focus-within {
    border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
  }
  @media (prefers-reduced-motion: reduce) {
    .bao-case-card {
      transition: none;
    }
    .bao-case-card:hover,
    .bao-case-card:active {
      transform: none;
    }
  }
  [data-case-option][data-selected="true"] .bao-case-card,
  [data-case-option][aria-selected="true"] .bao-case-card {
    border-color: color-mix(in oklab, var(--color-success) 50%, var(--border-base));
    border-inline-start-color: var(--color-success);
    background: color-mix(in oklab, var(--color-success) 10%, var(--bg-panel));
  }
  .bao-case-card-selected-icon {
    display: none;
  }
  [data-case-option][data-selected="true"] .bao-case-card-selected-icon,
  [data-case-option][aria-selected="true"] .bao-case-card-selected-icon {
    display: inline-block;
  }
  .bao-case-meta {
    color: var(--text-secondary);
    opacity: 1;
  }
  /* Case detail preview fact rows — one owner for the label/value pair chain. */
  .bao-case-fact-row {
    display: flex;
    min-width: 0;
    align-items: baseline;
    gap: var(--space-micro);
    font-size: var(--text-xs, 0.75rem);
  }
  /* Sentence case labels (Apple HIG) — uppercase burned vertical rhythm. */
  .bao-case-fact-label {
    flex: 0 0 auto;
    font-weight: 600;
    text-transform: none;
    letter-spacing: normal;
    color: color-mix(in oklab, var(--color-base-content) 72%, var(--color-base-100));
  }
  /*
   * Capture strip cards only — never bare .bao-context-card.
   * Chat/shell chips share that class for borders but stay row flex;
   * forcing column here fought horizontal rail CSS and reflow-thrashed
   * (WebView 101 chip vibration) on every HTMX remount.
   */
  [data-capture-context],
  [data-capture-context-strip] > .bao-context-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-micro);
    min-height: 3.25rem;
    padding: var(--space-inline) var(--space-section);
    border: 1px solid var(--liquid-border-regular);
    border-inline-start: 3px solid var(--color-primary);
    border-radius: var(--radius-field, 0.75rem);
    background: var(--bg-panel);
    text-align: start;
    box-shadow: 0 1px 2px color-mix(in oklab, var(--text-primary) 4%, transparent);
  }
  #case-list-section,
  [data-case-list] {
    min-height: 8rem;
    width: 100%;
    visibility: visible;
    opacity: 1;
  }

  /*
   * Active clinical case in the worklist — shell context match (Apple list
   * selection). Primary edge + soft fill; never a second chrome plate.
   */
  [data-case-row-primary][data-case-active="true"],
  tr[data-case-row-primary][data-case-active="true"] {
    border-inline-start: 3px solid var(--color-primary);
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  @media (hover: hover) and (pointer: fine) {
    [data-case-row-primary][data-case-active="true"]:hover {
      background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
    }
  }

  /* Fluid collection grid — auto-fit density */
  .bao-grid-reactive-collection {
    display: grid;
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(100%, var(--grid-track-min, 18rem)), 1fr)
    );
    gap: var(--space-inline);
    align-items: stretch;
    width: 100%;
    min-width: 0;
  }

  /* Empty panels — compact dashed host, never sparse white voids */
  .bao-empty-panel {
    min-height: 4.5rem;
    padding: var(--space-section);
  }

  /* The shell owns the ambient field; content panels own their opaque fill. */

  /*
   * Collection densify: workbench owns chrome; avoid stacked section-group voids.
   */
  [data-page-type="collection"] [data-section-group] {
    gap: var(--space-inline);
  }

  /* Filter bar fields: controls align on one baseline (labels are sr-only). */


  /* New Case dialog steps: dense on phone; box height tracks visual viewport. */
  @media (max-width: 40rem) {
    [data-case-create-dialog] .modal-box,
    [data-case-create-dialog] .bao-modal-box-shell {
      max-height: min(92dvh, var(--vv-height, 100%));
    }
    [data-case-create-dialog] .bao-modal-body-scroll {
      max-height: min(
        var(--modal-body-max-height),
        calc(var(--vv-height, 100dvh) * 0.5)
      );
    }
  }

  /*
   * Dashboard recent-cases embed: widget owns card chrome. Strip nested
   * DataSection padding and flatten phone row "mini-cards" so we never get
   * card-in-card nesting (Hick/Apple density).
   */
  @media (max-width: 47.99rem) {
    [data-dashboard-widget] [data-case-list] tbody tr {
      border-radius: 0;
      border-inline: 0;
      border-block-start: 0;
      border-block-end: 1px solid var(--liquid-border-regular);
      background: transparent;
      box-shadow: none;
      padding-inline: 0;
      padding-block: var(--space-micro);
    }
  }

/* Specimens is one operational list plane; rows use separators rather than nested plates. */
[data-page="specimens"] [data-primitive="DataTable"] tr.bao-table-responsive-row[data-specimen-id] {
  border-radius: 0;
  border-inline-width: 0;
  border-block-start-width: 0;
  border-block-end-width: var(--border);
  border-style: solid;
  border-color: var(--border-base);
  background-color: transparent;
  box-shadow: none;
  padding-inline: 0;
}

[data-page="specimens"] [data-primitive="DataTable"] .bao-table-responsive-body > * + * {
  margin-block-start: 0;
}

[data-page="specimens"] [data-primitive="DataTable"] [data-specimen-actions] > [data-dropdown-trigger] {
  inline-size: var(--touch-target-min);
  min-inline-size: var(--touch-target-min);
  min-block-size: var(--touch-target-min);
  justify-content: center;
}

  /* Tablet master-detail composition. The page is the query container so the workbench can react to its usable content width. */
  [data-page="cases"] {
    container-type: inline-size;
    container-name: cases-page;
  }
  [data-case-detail-pane] {
    display: none;
  }
  @media (min-width: 48rem) and (max-width: 63.99rem) {
    @container cases-page (min-width: 40rem) {
      [data-cases-workbench]:has(> [data-case-detail-pane]:not([data-state="empty"])) {
        display: grid;
        grid-template-columns: minmax(18rem, 1fr) minmax(0, min(24rem, 40%));
        gap: var(--space-inline);
        align-items: start;
      }
      [data-cases-workbench]:has(> [data-case-detail-pane]:not([data-state="empty"])) > [data-case-filters] {
        grid-column: 1 / -1;
      }
    }
    [data-case-detail-pane]:not([data-state="empty"]) {
      display: flex;
      flex-direction: column;
      gap: var(--space-inline);
      min-width: 0;
      padding: var(--space-inline);
      border-block-start: 1px solid var(--liquid-border-regular);
      outline: none;
    }
    @container cases-page (min-width: 40rem) {
      [data-case-detail-pane]:not([data-state="empty"]) {
        border-block-start: none;
        border-inline-start: 1px solid var(--liquid-border-regular);
      }
    }
    [data-case-detail-pane]:focus-visible {
      outline: var(--focus-ring-width) solid var(--color-primary);
      outline-offset: var(--focus-ring-offset-tight);
    }
  }
  .bao-case-detail-pane-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-inline);
  }
  .bao-case-detail-pane-title {
    margin: 0;
    font-size: var(--text-sm, 0.875rem);
    font-weight: 600;
    color: var(--text-primary);
  }
  .bao-case-detail-pane-description {
    margin: 0;
    font-size: var(--text-xs, 0.75rem);
    color: var(--text-secondary);
  }
  .bao-case-detail-pane-body {
    min-height: 8rem;
    min-width: 0;
  }
  .bao-case-detail-pane-error {
    padding: var(--space-inline);
    border-radius: var(--radius-field, 0.75rem);
    border: 1px solid color-mix(in oklab, var(--color-error) 40%, var(--border-base));
    color: var(--color-error);
    font-size: var(--text-xs, 0.75rem);
  }
  .bao-case-detail-pane-error-copy {
    margin: 0;
  }
  .bao-case-detail-facts {
    display: flex;
    flex-direction: column;
    gap: var(--space-micro);
    margin: 0;
  }
  .bao-case-detail-facts dd {
    margin: 0;
    min-width: 0;
  }
  .bao-case-detail-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-micro);
    margin-block-start: var(--space-inline);
    margin-inline: 0;
    padding: 0;
    border: 0;
    min-inline-size: 0;
  }
/*
   * Global page density SSOT — every pageType inherits Apple-tight chrome:
   * form cards,
tables,
and section stacks share the same spacing scale.
   * No per-page bespoke overrides.
   */
  [data-page] .bao-page-track {
    gap: var(--space-section);
  }[data-page-type="collection"] .bao-page-track,
[data-page-type="form"] .bao-page-track,
[data-page-type="detail"] .bao-page-track {
    gap: var(--space-inline);
  }
  [data-page] [data-primitive="DataSection"] {
    min-width: 0;
  }
  [data-page] .bao-data-panel {
    min-width: 0;
    max-width: 100%;
  }/* Overflow containment: no panel may paint outside the page track */
  [data-page] .bao-page-track,
[data-page] [data-state-content] {
    min-width: 0;
    max-width: 100%;
  }
  /* Secondary soft chrome: ban invisible zero-height ghosts from layout thrash */
  [data-page] .btn.btn-soft.btn-square {
    flex: 0 0 auto;
  }/* Phone: bound supporting copy and retain command touch targets. */
  @media (max-width: 40rem) {
    [data-page] [data-primitive="PageHeader"] p {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow: hidden;
    }
    [data-page] [data-page-header-actions] > .btn {
      flex: 1 1 auto;
      min-height: var(--touch-target-min, 2.75rem);
    }
  }


  .bao-workbench {
    box-sizing: border-box;
    width: 100%;
    max-width: 100%;
    min-width: 0;
    min-height: 0;
    overflow-x: clip;
  }

  /* Session-panel visibility pair, owned here with the visible rules below:
     the hidden guard must outrank the annotate panel display:flex
     (tokens-layout-skeleton-surfaces) or a hidden panel paints. The
     tab-panel selector shares the rule because the session renderer stamps
     data-tab-panel and data-session-panel on the same element
     (pages-renderers-session-modes). */
  [data-page="capture"] [data-session-panel][hidden],
  [data-page="capture"] [data-tab-panel][hidden] { display: none; }

  /* A single media-session owner defines every ancestor before forwarding tracks. */
  .bao-media-session-root,
  .bao-media-session-acquire,
  .bao-media-session-panel:not([hidden]) {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    min-block-size: 0;
    column-gap: var(--space-inline);
  }
  @supports not (display: grid) {
    .bao-media-session-root,
    .bao-media-session-acquire,
    .bao-media-session-panel:not([hidden]) {
      row-gap: var(--space-inline);
    }
  }
  .bao-media-session-panel,
  .bao-media-session-acquire {
    flex: 1 1 0%;
  }
  .bao-media-session-acquire {
    overflow: hidden;
  }
  .bao-toolbar-command {
    flex: 0 0 auto;
    inline-size: var(--touch-target-min);
    min-inline-size: var(--touch-target-min);
    min-block-size: var(--touch-target-min);
    padding-inline: 0;
  }
  .bao-media-session-root > [data-primitive="Toolbar"] {
    flex-wrap: wrap;
    align-self: start;
    max-inline-size: 100%;
    position: relative;
    z-index: var(--z-raised);
  }
  /* Explicit grids keep navigation in flow when subgrid is unavailable; subgrid places
     modes beside commands over the shared canvas without a separate row. */
  @supports (display: grid) {
    .bao-media-session-root {
      display: grid;
      grid-template-columns: [modes-start commands-start] minmax(0, 1fr) [inline-end];
      grid-template-rows: [navigation-start] auto [source-start] auto [commands-start] auto [viewport-start] minmax(0, 1fr) [status-start] auto [block-end customizer-size-start] auto [customizer-visibility-start] auto [customizer-feedback-start] auto [layout-end];
      row-gap: 0;
      container-type: inline-size;
      container-name: editor-surface;
    }
    .bao-media-session-panel:not([hidden]),
    .bao-media-session-acquire,
    .bao-media-session-panel[data-session-panel="annotate"] [data-editor-chrome] {
      display: grid;
      grid-column: modes-start / inline-end;
      grid-row: source-start / layout-end;
      grid-template-columns: [modes-start commands-start] minmax(0, 1fr) [inline-end];
      grid-template-rows: [source-start] auto [commands-start] auto [viewport-start] minmax(0, 1fr) [status-start] auto [block-end customizer-size-start] auto [customizer-visibility-start] auto [customizer-feedback-start] auto [layout-end];
      row-gap: 0;
    }
    .bao-media-session-root > [data-primitive="Toolbar"] {
      grid-column: modes-start / inline-end;
      grid-row: navigation-start / source-start;
    }
    .bao-media-session-acquire > [data-capture-command-chrome] {
      grid-column: commands-start / inline-end;
      grid-row: commands-start / viewport-start;
      justify-self: start;
      align-self: start;
      z-index: var(--z-raised);
    }
    .bao-media-session-acquire > .bao-media-workbench {
      grid-column: modes-start / inline-end;
      grid-row: commands-start / status-start;
    }
    .bao-media-session-acquire > [data-model-readiness-gate] {
      grid-column: modes-start / inline-end;
      grid-row: status-start / block-end;
    }
    .bao-media-session-panel [data-dashboard-customizer-render="inline"] > [data-dashboard-uniform-size-tray] {
      grid-column: modes-start / inline-end;
      grid-row: customizer-size-start / customizer-visibility-start;
    }
    .bao-media-session-panel [data-dashboard-customizer-render="inline"] > [data-dashboard-visibility-tray] {
      grid-column: modes-start / inline-end;
      grid-row: customizer-visibility-start / customizer-feedback-start;
    }
    .bao-media-session-panel [data-dashboard-customizer-render="inline"] > [data-layout-persistence-status] {
      grid-column: modes-start / inline-end;
      grid-row: customizer-feedback-start / layout-end;
    }
  }
  @supports (grid-template-columns: subgrid) {
    .bao-media-session-root {
      grid-template-columns: [modes-start] max-content [commands-start] minmax(0, 1fr) [inline-end];
      grid-template-rows: [source-start] auto [commands-start] auto [viewport-start] minmax(0, 1fr) [status-start] auto [block-end customizer-size-start] auto [customizer-visibility-start] auto [customizer-feedback-start] auto [layout-end];
    }
    .bao-media-session-root > [data-primitive="Toolbar"] {
      grid-column: modes-start / commands-start;
      grid-row: commands-start / viewport-start;
      margin: var(--space-micro);
    }
    .bao-media-session-panel [data-capture-command-chrome],
    .bao-media-session-panel [data-editor-stage-toolbar] {
      margin: var(--space-micro);
      max-inline-size: calc(100% - var(--space-micro) * 2);
    }
    .bao-media-session-panel:not([hidden]),
    .bao-media-session-acquire {
      grid-template-columns: subgrid;
      grid-template-rows: subgrid;
    }
  }
  @container (min-width: 56rem) {
    .bao-toolbar-command {
      inline-size: auto;
      padding-inline: var(--toolbar-action-pad-inline);
    }
  }
  /* Conversation dock SSOT: tokens-layout-page-shells-conversation.ts owns
     all .bao-conversation-dock rules (solid form surface per design.pdf §5.5).
     Skeleton module must not duplicate — DRY single owner. */
  @media (prefers-reduced-motion: reduce) {
.bao-motion-transition-colors {
      transition-property: none; transition-duration: var(--duration-instant);
      animation: none;
    }
  }
  /* Conversation message stream — scroll region host. */
  .bao-conversation-stream {
    scrollbar-gutter: stable;
    scroll-padding-block: var(--space-section);
  }
  /* Conversation page header band. */
  .bao-conversation-header {
    min-height: var(--chrome-min-height, max(2.75rem, 44px));
  }
  .bao-skeleton-header {
    min-height: var(--density-comfortable-row-height);
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-field);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-toolbar {
    min-height: var(--density-default-row-height);
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-field);
    background-color: var(--bg-surface-hover);
  }
  /* Floating glass toolbar — geometry-faithful surface for capture/editor top chrome. */
  .bao-skeleton-toolbar-floating {
    min-height: var(--density-comfortable-row-height);
    width: 100%;
    border-radius: var(--radius-field);
    border: 1px solid color-mix(in oklab, var(--liquid-border-clear) 50%, transparent);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-inspector {
    min-height: var(--skeleton-media-min-height);
    width: 100%;
    max-width: 100%;
    border: 1px solid var(--border-base);
    border-radius: var(--radius-box);
    background-color: var(--bg-surface);
  }
  /* Workbench side panel — captures card card-border geometry + card-body padding. */
  .bao-skeleton-side-panel {
    min-height: var(--skeleton-panel-min-height, 7rem);
    width: 100%;
    border-radius: var(--radius-box);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  .bao-skeleton-side-panel-card {
    min-height: var(--skeleton-panel-min-height, 7rem);
    width: 100%;
    border-radius: var(--radius-box);
    border: 1px solid var(--border-base);
    background-color: var(--bg-panel);
    box-shadow: 0 1px 2px color-mix(in oklab, var(--color-base-content) 6%, transparent);
  }
  /* Workbench preview region — matches camera preview box geometry. */
  .bao-skeleton-preview-region {
    aspect-ratio: 16 / 9;
    min-height: var(--skeleton-media-min-height, 12rem);
    width: 100%;
    max-width: 100%;
    border-radius: var(--radius-box);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  /* Workbench preview empty placeholder — matches centered icon+copy stack. */
  .bao-skeleton-preview-empty {
    min-height: var(--skeleton-media-min-height, 12rem);
    width: 100%;
    border-radius: var(--radius-box);
    border: 1px dashed var(--liquid-border-regular);
    background-color: var(--bg-surface);
  }
  /* Workbench canvas region — matches annotation editor canvas column. */
  .bao-skeleton-canvas-region {
    min-height: var(--canvas-region-min-height, clamp(18rem, 42vh, 30rem));
    width: 100%;
    border-radius: var(--radius-box);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  /* Panel card header — matches card-title band above card-body. */
  .bao-skeleton-panel-header {
    min-height: var(--density-comfortable-row-height);
    width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-message {
    width: min(75%, var(--page-standard));
  }
  .bao-skeleton-message,
  .bao-skeleton-message-reply {
    min-height: var(--density-comfortable-row-height);
    border-radius: var(--radius-box);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-message-reply {
    margin-inline-start: auto;
    width: min(60%, var(--page-standard));
  }
  /* Assistant chat bubble — mirrors chat-bubble border + radius at chat-start row. */
  .bao-skeleton-message-assistant {
    min-height: var(--density-comfortable-row-height);
    width: min(75%, var(--page-conversation, 48rem));
    border-radius: var(--radius-box);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  /* User chat bubble — mirrors chat-bubble-primary at chat-end row. */
  .bao-skeleton-message-user {
    min-height: var(--density-comfortable-row-height);
    width: min(60%, var(--page-conversation, 48rem));
    border-radius: var(--radius-box);
    background-color: var(--bg-surface-hover);
  }
  /* Conversation context strip — sticky chip band above thread. */
  .bao-skeleton-conversation-context-strip {
    min-height: 3rem;
    width: 100%;
    flex: 0 0 auto;

    max-width: var(--page-wide, 96rem);
    margin-inline: auto;
    border-radius: var(--radius-field);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface-hover);
  }
  /* Glass-docked composer — same footprint as final composer footer. */
  .bao-skeleton-conversation-composer-docked {
    min-height: 8rem;
    width: 100%;
    flex: 0 0 auto;
    max-width: var(--page-wide, 96rem);
    margin-inline: auto;
    border-radius: var(--radius-box);
    border: 1px solid var(--liquid-border-regular);
    background-color: var(--bg-surface-hover);
  }

/* Task areas bind to their existing semantic roots; the permanent request receiver supplies the container. */
.bao-task-queue,
.bao-task-board {
  align-items: start;
  grid-template-columns: minmax(0, 1fr);
}
.bao-task-queue {
  grid-template-areas: "main" "rail" "inspector";
}
.bao-task-board {
  grid-template-areas: "main" "inspector" "rail";
}
.bao-task-main { grid-area: main; }
.bao-task-rail {
  grid-area: rail;
  grid-template-columns: minmax(0, 1fr);
}
.bao-task-inspector { grid-area: inspector; }
.bao-task-board-canvas {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-choice-min)), 1fr));
}
.bao-task-board-canvas > * { min-inline-size: 0; }
.bao-task-board > .bao-task-rail {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-panel-third-min)), 1fr));
}

/* Engines without container queries retain the complete single-column flow above. */
@supports (container-type: inline-size) {
  .bao-task-page { container: task-workbench / inline-size; }

  @container task-workbench (min-width: 52rem) {
    .bao-task-queue {
      grid-template-columns: minmax(0, 1.6fr) minmax(var(--grid-track-min), 1fr);
      grid-template-areas: "main inspector" "rail rail";
    }
    .bao-task-queue > .bao-task-rail {
      grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-panel-third-min)), 1fr));
    }
  }

  @container task-workbench (min-width: 76rem) {
    .bao-task-queue {
      grid-template-columns: minmax(var(--grid-choice-min), 0.8fr) minmax(var(--grid-panel-half-min), 1.8fr) minmax(var(--grid-track-min), 1fr);
      grid-template-areas: "rail main inspector";
    }
    .bao-task-queue > .bao-task-rail { grid-template-columns: minmax(0, 1fr); }
  }
}

.bao-ai-analysis-workbench {
  container-type: inline-size;
  container-name: ai-analysis-workbench;
}

.bao-ai-analysis-primary,
.bao-ai-analysis-inspector {
  min-inline-size: 0;
  max-inline-size: 100%;
}

.bao-ai-analysis-inspector {
  display: grid;
  grid-template-areas: "inputs" "status";
  gap: var(--space-section);
  container-type: inline-size;
  container-name: ai-analysis-inspector;
}

.bao-ai-analysis-inspector > form {
  grid-area: inputs;
  max-width: none;
  max-inline-size: 100%;
  min-inline-size: 0;
}

.bao-ai-analysis-inspector > [role="status"] {
  grid-area: status;
}

@container ai-analysis-workbench (max-width: 32rem) {
  .bao-ai-analysis-primary {
    border-block-start: var(--border) solid var(--color-base-300);
    padding-block-start: var(--space-section);
  }
  .bao-ai-analysis-workbench [data-viz-dimension-switcher].join {
    max-inline-size: 100%;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
  }
}

.bao-inline-target {
  display: inline-flex;
  min-width: 0;
  align-items: center;
}

.bao-size-attachment-preview {
  inline-size: var(--attachment-preview-size);
  block-size: var(--attachment-preview-size);
  flex: 0 0 var(--attachment-preview-size);
}

@media (max-width: 47.99rem), (pointer: coarse) {
  .bao-inline-target {
    min-block-size: var(--touch-target-min, 2.75rem);
  }
}

/* Floating canvas toolbars anchor to logical corners of their positioning host. */
.bao-toolbar-canvas-block-start,
.bao-toolbar-canvas-block-end {
  position: absolute;
  inset-inline-end: var(--space-inline);
  max-inline-size: calc(100% - var(--space-inline) * 2);
}
.bao-toolbar-canvas-block-start {
  inset-block-start: var(--space-inline);
}
.bao-toolbar-canvas-block-end {
  inset-block-end: var(--space-inline);
}

  .bao-media-workbench-primary {
    display: flex;
    min-width: 0;
    min-height: 0;
    flex: 999 1 var(--media-primary-basis);
    flex-direction: column;
    gap: var(--space-inline);
  }
  .bao-media-workbench-secondary {
    display: grid;
    grid-auto-rows: max-content;
    align-content: start;
    align-self: start;
    min-width: 0;
    min-height: 0;
    max-height: 100%;
    /* Cap inspector rail so it never starves the media stage on ultrawide. */
    flex: 0 1 var(--media-inspector-basis);
    max-width: min(24rem, 100%);
    gap: var(--space-inline);
    overflow-y: visible;
  }
  .bao-preview-context-panel {
    min-width: 0;
    width: 100%;
  }

  .bao-form-adaptive {
    display: grid;
    min-width: 0;
    gap: var(--space-section);
  }
  .bao-form-grid-two {
    display: grid;
    min-width: 0;
    gap: var(--space-section);
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(100%, var(--grid-form-min, 16rem)), 1fr)
    );
  }
  .bao-choice-grid {
    display: grid;
    min-width: 0;
    gap: var(--space-inline);
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(100%, var(--grid-choice-min, 14rem)), 1fr)
    );
  }
  /*
   * Collection choice densify: compact padding + single column on phone.
   * Security/permission radiogroups (API keys scopes) KEEP helper copy —
   * title-only chips hide least-privilege meaning (enterprise anti-pattern).
   * Non-security choice grids may densify titles only via data-choice-density.
   */
  @media (max-width: 47.99rem) {
    .bao-choice-grid {
      gap: var(--space-micro);
    }.bao-choice-grid > .label,
.bao-choice-grid > .bao-choice-option {
      padding: var(--space-inline, 0.5rem);
      min-height: var(--touch-target-min, 2.75rem);
      /* HIG Dynamic Type: the inner layout span is display:grid with
         auto-sized tracks, so at root font 400% with WCAG text spacing the
         checkbox column, title, and helper caption each demand their
         natural width and the option outgrows the viewport (api-keys scope
         options measured right edge 1445px on a 1440px viewport). A fluid
         track and wrap-capable captions keep the text inside the option
         instead of pushing past the edge. */
    }
    .bao-choice-grid > .label > span.grid,
    .bao-choice-grid > .bao-choice-option > span.grid {
      grid-template-columns: minmax(0, 1fr);
      min-width: 0;
      max-width: 100%;
    }
    .bao-choice-grid > .label > span.grid > span,
    .bao-choice-grid > .bao-choice-option > span.grid > span {
      min-width: 0;
      overflow-wrap: anywhere;
    }/* Optional dense chips: opt-in only (never default for permission scopes). */
    .bao-choice-grid[data-choice-density="title-only"] > .label > span.grid > span:last-child,
.bao-choice-grid[data-choice-density="title-only"] > .label > span > span.text-xs,
.bao-choice-grid[data-choice-density="title-only"] > .bao-choice-option > span.grid > span:last-child,
.bao-choice-grid[data-choice-density="title-only"] > .bao-choice-option > span > span.text-xs {
      display: none;
    }  }/* Collection dual panels (licensing,
ops): full-width stack under tablet. */
  .bao-context-grid-reactive {
    display: grid;
    min-width: 0;
    align-items: stretch;
    gap: var(--space-micro);
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(100%, var(--grid-context-min, 10rem)), 1fr)
    );
  }
  .bao-page-chrome[data-chat-context] {
    display: flex;
    flex-wrap: wrap;
    min-width: 0;
    gap: var(--space-micro);
  }
  .bao-tabs-scroll {
    display: flex;
    flex-direction: row;
    align-items: stretch;
    width: 100%;
    min-width: 0;
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-inline: contain;
    scroll-snap-type: x proximity;
    scroll-padding-inline: var(--space-inline);
    /*
     * No mask here. The clipped-content affordance has ONE owner —
     * .bao-scroll-edge-x (tokens-utilities-scroll-edge), which every compiled
     * .bao-tabs-scroll host also carries. Its shared observer marks only
     * genuinely clipped edges; nothing is drawn when there is no overflow.
     *
     * The mask that used to live here was unconditional, so a strip with
     * nothing to scroll still faded its trailing 1.25rem — measured on
     * /capture at 375px: scrollWidth === clientWidth === 357 and the tab strip
     * was still dimmed at the right edge. Two affordances on one element, one
     * of them lying about scrollability.
     */
  }
  /* Scroll rails preserve complete destination labels instead of compressing them. */
  .bao-tabs-scroll > .tab {
    flex: 0 0 auto;
    min-width: max-content;
    max-width: none;
    scroll-snap-align: start;
  }
  .bao-dock-reactive { display: flex; flex-wrap: wrap; }
  .bao-dock-reactive-primary { flex: 999 1 var(--dock-primary-basis); min-width: 0; }
  /*
   * Cap by the smaller of the rail width and the container. A bare 24rem
   * cap (max-w-sm) is a rem length, so it grew with the root font: at 125%
   * Dynamic Type the Capture device controls measured 406px inside a 390px
   * phone viewport with no scroller to reveal them (Apple HIG Dynamic Type;
   * WCAG 2.2 1.4.4). min(..., 100%) is the pattern .bao-media-workbench-secondary
   * already uses for the same reason.
   */
  .bao-dock-reactive-side { flex: 1 1 var(--dock-side-basis); min-width: 0; max-width: min(24rem, 100%); }
  .bao-dock-reactive-side-wide { flex: 1 1 var(--dock-side-wide-basis); min-width: 0; }
/* Mobile dock CSS emits UNLAYERED from tokens.ts (tokens-layout-dock) —
   never nest it inside @layer utilities or WebView 101 drops the hide. */
  /* Dynamic Type reflow contracts (HIG / WCAG 1.4.4) — the clusters the
     audit measured past the viewport at 400% root font with WCAG text
     spacing, with the touch-target floor scaling with root text:
     - Button labels are owned by the button reflow rule in
       tokens-glass-shell-controls; tabs carry the same nowrap floor, so
       release them here.
     - A fieldset defaults to min-inline-size:min-content; floor it, or an
       enlarged text pushes the whole cluster past its track.
     - Auto-width ancestors defeat a child's percentage max-width
       (percentage against an indefinite resolved width is inert), so the
       sticky identity hosts and cluster forms declare their own bound for
       the pills and rows inside to clip or wrap against.
     - The sticky badge pills wrap instead of forcing the sticky host wider
       than the viewport. Wrap is preferred over a scroller here — a
       scroller on the sticky host re-clips dropdown panels the editor
       rules explicitly unclip for open menus. */
  .tab:not([hidden]):not(.hidden) {
    white-space: normal;
  }
  /* Native control groups share the shrink floor, including join and grid layouts. */
  fieldset {
    min-inline-size: 0;
  }
  [data-editor-chrome] dl.flex.min-w-0:not([data-editor-persistence-status]),
  dl.m-0.flex:not([data-editor-persistence-status]),
  form.mt-space-inline.border-t {
    width: 100%;
    max-width: 100%;
  }
  [data-editor-chrome] dl.flex.min-w-0 > div.bao-context-badge,
  dl.bao-ai-provenance-sticky > div.flex.min-w-0 {
    min-width: 0;
    max-width: 100%;
    flex-wrap: wrap;
  }
  [data-editor-chrome] dl.flex.min-w-0 > div.bao-context-badge > * {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
  }
  dl.bao-ai-provenance-sticky dd,
  dl.bao-ai-provenance-sticky dt {
    min-width: 0;
    max-width: 100%;
  }
  dl.bao-ai-provenance-sticky dd > span {
    min-width: 0;
    max-width: 100%;
  }
  fieldset.flex.flex-col > label.flex > div.flex.w-full {
    flex-wrap: wrap;
    min-width: 0;
  }
  /* Sticky badge term/value pills: dt/dd carry an inherited or declared
     nowrap as a chrome convention; at an enlarged root font the pill runs
     past the viewport (measured /editor Custody dt at right 450px on a
     390px viewport). Break the pill terms while keeping the badge bounds. */
  [data-shell-scroll="main"] dl.flex.min-w-0 > div.bao-context-badge > dt,
  [data-shell-scroll="main"] dl.flex.min-w-0 > div.bao-context-badge > dd {
    white-space: normal;
    overflow-wrap: anywhere;
  }

  /* Native composition separates intrinsic field tracks from the full-width footer. */
  .bao-form-composition {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "content" "actions";
    align-items: start;
    gap: var(--space-section);
    min-inline-size: 0;
  }
  .bao-form-composition-body { grid-area: content; }
  .bao-form-catalog {
    min-inline-size: 0;
    margin: 0;
    padding: 0;
    border: 0;
  }
  .bao-form-catalog > legend {
    max-inline-size: 100%;
    margin-block-end: var(--space-section);
    padding: 0;
  }
  .bao-form-footer { grid-area: actions; }

  /* Content-sized tracks wrap from the canonical minimum and retain at most two panels. */
  .bao-grid-reactive-panels {
    display: grid;
    min-inline-size: 0;
    inline-size: 100%;
    align-items: var(--bao-panel-grid-align, stretch);
    gap: var(--space-section);
    grid-auto-rows: auto;
    container-type: inline-size;
    overflow-x: clip;
    max-inline-size: 100%;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, max(var(--grid-panel-half-min), calc((100% - var(--space-section)) / 2))), 1fr));
  }
  [data-dashboard-panel-size="half"],
  [data-dashboard-panel-size="full"] {
    min-inline-size: 0;
    max-inline-size: 100%;
    height: var(--bao-panel-height, 100%);
    box-sizing: border-box;
  }
  .bao-grid-reactive-panels > [data-dashboard-panel-size="full"],
  .bao-grid-reactive-panels > * > [data-dashboard-panel-size="full"] {
    min-height: var(--bao-panel-min-height, var(--bao-dashboard-panel-full-min-height, 8rem));
    grid-column: 1 / -1;
  }
  .bao-grid-reactive-panels > [data-dashboard-panel-size="half"],
  .bao-grid-reactive-panels > * > [data-dashboard-panel-size="half"] {
    min-height: var(--bao-panel-min-height, var(--bao-dashboard-panel-min-height, 11rem));
  }
  /*
   * Nested widget shells (section-group wraps cells): fill equal-height tracks.
   * Direct children and one-level nested cards share the same stretch SSOT.
   */
  .bao-grid-reactive-panels > [data-dashboard-widget]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]),
  .bao-grid-reactive-panels > [data-primitive="DashboardWidget"]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]),
  .bao-grid-reactive-panels > .card:not([hidden]):not([data-dashboard-panel-visibility="hidden"]),
  .bao-grid-reactive-panels > * > [data-dashboard-widget]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]),
  .bao-grid-reactive-panels > * > [data-primitive="DashboardWidget"]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]),
  .bao-grid-reactive-panels > * > .card:not([hidden]):not([data-dashboard-panel-visibility="hidden"]) {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    width: 100%;
    height: var(--bao-panel-height, 100%);
    min-height: var(--bao-panel-min-height, var(--bao-dashboard-panel-min-height, 11rem));
    min-width: 0;
  }
  /* Ordinary card bodies retain their own content geometry. */
  .bao-grid-reactive-panels > .card > .card-body,
  .bao-grid-reactive-panels > * > .card > .card-body {
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    min-width: 0;
    /* Surface content: clip width only; vertical overflow belongs to the page
       or to a table-bearing widget below (HIG scroll-views: no nested
       same-axis scroll views — measured on /reports: every widget card-body
       was its own vertical scroller, a 10-18px scroll trap over the page). */
    overflow-x: clip;
    overflow-y: visible;
  }
  /* Only the value body scrolls; its sibling heading and controls remain reachable. */
  .bao-grid-reactive-panels [data-widget-value] {
    overflow-x: clip;
  }
  /* Ordinary content follows the page scroll instead of creating a nested scrollport. */
  .bao-grid-reactive-panels [data-widget-value]:not(:has(:is([data-case-list], [data-primitive="DataTable"], [data-saved-reports], [data-report-templates], [data-column-list]))) {
    overflow-y: visible;
  }
  /* Table rows retain a bounded body scrollport without scrolling the widget chrome. */
  .bao-grid-reactive-panels [data-widget-value]:has(:is([data-case-list], [data-primitive="DataTable"], [data-saved-reports], [data-report-templates], [data-column-list])) {
    overflow-y: auto;
  }
  /* Path / mono / secondary copy never blows the card width (design.pdf type). */
  .bao-grid-reactive-panels .bao-dashboard-widget-secondary,
  .bao-grid-reactive-panels .bao-dashboard-widget-meta,
  .bao-grid-reactive-panels [data-widget-secondary],
  .bao-grid-reactive-panels [data-widget-meta] {
    min-width: 0;
    max-width: 100%;
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* Content headings wrap fully, including a single word wider than an enlarged card. */
  .bao-grid-reactive-panels .card-title {
    min-inline-size: 0;
    max-inline-size: 100%;
    flex-wrap: wrap;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .bao-grid-reactive-panels .bao-dashboard-widget-label,
  .bao-grid-reactive-panels [data-widget-title] {
    min-width: 0;
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  /* Dense list rows inside dashboard panels (template library, saved reports). */
  .bao-list-row-dense {
    min-height: var(--bao-list-row-min-height, 3.25rem);
  }
  [data-report-templates] .list-row,
  [data-saved-reports] .list-row {
    min-height: var(--bao-list-row-min-height, 3.25rem);
    align-items: center;
  }

  /* Subgrid: children that need cross-sibling column alignment (status rows,
     export action rows, label/value meta grids) opt in via .bao-subgrid.
     The parent grid's column track is inherited; @supports guards older engines. */
  @supports (grid-template-columns: subgrid) {
    .bao-subgrid {
      grid-column: 1 / -1;
      display: grid;
      grid-template-columns: subgrid;
      align-items: center;
      gap: var(--space-inline);
    }
    .bao-subgrid-rows {
      grid-template-rows: subgrid;
    }
  }

  /*
   * Editor key-hint chips (`.bao-toolbar-action .kbd` + `[data-hig-key-hint]`)
   * belong to the toolbar-reveal contract in tokens-glass-chrome-body-part-1
   * + part-2, not to a fixed 2xl always-on regime. The historical gate here
   * targeted the daisyUI `.kbd` class and never matched the chip our
   * editor-toolbar renderer emits, which is exactly why the chip was visible
   * at every width. The reveal/hide contract now lives with the label.
   */

  /* Download cards contain file paths and action controls; direct-touch flow is one card per row. */
  @media (max-width: 42rem), (hover: none) and (pointer: coarse) {
    [data-predefined-models-section] [data-model-download-card] {
      grid-column: 1 / -1;
    }
  }

  /* Choice grid base SSOT: tokens-layout-framework.ts. Checked state only here. */
  .bao-choice-grid > .bao-choice-option:has(> input:checked) {
    border-color: var(--color-primary);
    box-shadow: 0 0 0 1px var(--liquid-border-regular);
  }


  .bao-collection-action-row {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: var(--space-inline);
    padding-block: var(--space-inline);
    min-inline-size: 0;
  }
  .bao-collection-identity {
    display: flex;
    flex-direction: column;
    gap: var(--space-micro);
    flex: 1 1 var(--grid-choice-min);
    min-inline-size: 0;
  }
  .bao-collection-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-micro);
    flex: 0 0 auto;
    min-inline-size: 0;
    max-inline-size: 100%;
  }
  .bao-collection-title-actions {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    gap: var(--space-inline);
    min-inline-size: 0;
    max-inline-size: 100%;
  }
  .bao-collection-title-actions > form {
    justify-self: end;
  }
  /* Descriptor lists read as one caption line; the separator is decorative (empty alt text). */
  .bao-collection-metadata {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-micro);
    margin: 0;
    padding: 0;
    list-style: none;
    min-inline-size: 0;
  }
  .bao-collection-metadata > li + li::before {
    content: "·" / "";
    margin-inline-end: var(--space-micro);
    color: var(--text-tertiary);
  }


  /* Layout visibility is independent of native permission/loading concealment. */
  [data-dashboard-widget][data-dashboard-panel-visibility="hidden"] {
    display: none;
  }


  /* Nested tables inside dashboard cards: no second framed host (SSOT single card). */
  [data-dashboard-widget] [data-case-list] > .bao-data-panel,
  [data-dashboard-widget] [data-primitive="DataTable"].bao-data-panel,
  [data-dashboard-widget] .overflow-x-auto.bao-data-panel {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  /* Nested framed cards under any widget host — unframe (never dual chrome). */
  [data-dashboard-widget] .card.card-border.bao-data-panel,
  [data-dashboard-widget] [data-primitive="Card"].bao-data-panel {
    border-width: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  /* Dashboard panel body slot — dense KPI geometry. */
  .bao-dashboard-panel-value {
    display: flex;
    min-height: 0;
    flex: 1 1 auto;
    flex-direction: column;
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
  }

  .bao-dashboard-widget-detail-grid {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-panel-quarter-min)), 1fr));
  }

  /* One reading column keeps the value, subtitle and supporting state together. */
  .bao-dashboard-widget-fragment {
    display: flex;
    min-width: 0;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-micro);
    text-align: start;
  }
  .bao-dashboard-widget-copy {
    min-inline-size: 0;
    overflow-wrap: anywhere;
  }
  /* Narrow widgets retain full-width copy and natural text reflow. */
  @media (max-width: 39.99rem) {
    [data-page="dashboard"] .bao-dashboard-widget-status,
    [data-page-type="home"] .bao-dashboard-widget-status,
    [data-page="dashboard"] .bao-dashboard-widget-secondary,
    [data-page-type="home"] .bao-dashboard-widget-secondary {
      white-space: normal;
      overflow: visible;
      text-overflow: unset;
      max-width: 100%;
      overflow-wrap: anywhere;
    }
  }
  .bao-dashboard-widget-value {
    display: block;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
    min-inline-size: 0;
    max-inline-size: 100%;
    font-size: var(--text-xl, 1.25rem);
    font-weight: 700;
    line-height: 1.15;
    letter-spacing: var(--tracking-tight, -0.025em);
    font-variant-numeric: tabular-nums;
    color: var(--text-primary);
  }
  .bao-dashboard-widget-value:empty {
    display: none;
  }
  .bao-dashboard-widget-label {
    display: block;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
    min-inline-size: 0;
    max-inline-size: 100%;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 500;
    color: var(--text-tertiary);
  }
  .bao-dashboard-widget-label:empty {
    display: none;
  }
  .bao-dashboard-widget-secondary {
    display: block;
    max-width: 100%;
    overflow: visible;
    text-overflow: clip;
    white-space: normal;
    overflow-wrap: anywhere;
    min-inline-size: 0;
    max-inline-size: 100%;
    font-size: var(--text-xs, 0.75rem);
    color: var(--text-tertiary);
  }
  /* Paths / mono detail lines never blow out the KPI tile width. */
  .bao-dashboard-widget-secondary[data-path],
  .bao-dashboard-widget-secondary.font-mono,
  [data-dashboard-widget] .bao-dashboard-widget-secondary {
    min-width: 0;
    max-width: 100%;
    overflow: visible;
    white-space: normal;
    overflow-wrap: anywhere;
  }

  .bao-dashboard-widget-secondary:empty {
    display: none;
  }
  @media (max-width: 40rem) {
    .bao-dashboard-widget-value {
      font-size: var(--text-lg, 1.125rem);
    }
    [data-dashboard-widget] {
      min-width: 0;
    }
  }
  .bao-dashboard-widget-meta {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: center;
    gap: var(--space-inline);
    min-inline-size: 0;
    margin-block-start: var(--space-inline);
  }
  .bao-dashboard-widget-meta-content {
    grid-column: 1;
    grid-row: 1;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-inline);
    min-inline-size: 0;
  }
  .bao-dashboard-widget-trend::before {
    content: "\2192";
    font-variant-numeric: tabular-nums;
  }
  .bao-dashboard-widget-trend[data-trend-value="up"] {
    color: var(--status-success);
  }
  .bao-dashboard-widget-trend[data-trend-value="up"]::before {
    content: "\2191";
  }
  .bao-dashboard-widget-trend[data-trend-value="down"] {
    color: var(--status-error);
  }
  .bao-dashboard-widget-trend[data-trend-value="down"]::before {
    content: "\2193";
  }
  .bao-dashboard-widget-trend:empty {
    display: none;
  }
  .bao-dashboard-widget-status {
    display: inline-flex;
    flex: 0 0 auto;
    align-items: center;
    gap: var(--space-micro);
    white-space: normal;
    min-inline-size: 0;
    max-inline-size: 100%;
    overflow-wrap: anywhere;
    font-size: var(--text-xs, 0.75rem);
    font-weight: 500;
    color: var(--text-tertiary);
  }
  .bao-dashboard-widget-detail {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    display: block;
    min-inline-size: 0;
    max-inline-size: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
  }
  .bao-dashboard-widget-detail[open] {
    grid-column: 1 / -1;
    justify-self: stretch;
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    align-items: start;
    column-gap: var(--space-inline);
  }
  .bao-dashboard-widget-detail[open] > summary {
    grid-column: 2;
    grid-row: 1;
    justify-self: end;
    align-self: start;
  }
  .bao-dashboard-widget-detail[open]::details-content {
    grid-column: 1 / -1;
    grid-row: 2;
    min-inline-size: 0;
  }
  .bao-dashboard-widget-detail[open] > p {
    min-inline-size: 0;
    max-inline-size: 100%;
  }
  /* Only metric readings own containment; list menus keep their normal escape geometry. */
  .bao-dashboard-panel-value:has(> .bao-dashboard-widget-fragment) {
    container-type: inline-size;
    container-name: bao-widget-value;
  }
  @container bao-widget-value (max-width: 12rem) {
    .bao-dashboard-widget-status > [data-status-indicator] {
      flex-wrap: wrap;
    }
  }
  .bao-dashboard-widget-detail:has(> p:empty) {
    display: none;
  }
  /* Flat trends add no second reading on compact viewports. */
  @media (max-width: 40rem) {
    .bao-dashboard-widget-trend:empty,
    .bao-dashboard-widget-trend:not([data-trend-value]),
    .bao-dashboard-widget-trend[data-trend-value=""],
    .bao-dashboard-widget-trend[data-trend-value="flat"],
    .bao-dashboard-widget-trend[data-trend-value="none"] {
      display: none;
    }
  }
  /* Empty KPI: drop long detail so tiles do not balloon equal-row white voids */
  [data-dashboard-widget-fragment][data-state="empty"] + .bao-dashboard-widget-detail {
    display: none;
  }
 

  /*
   * HTMX indicators never reserve layout space — in either state.
   *
   * `position: absolute` used to sit on the idle selector alone, so the
   * moment a request opened, every indicator on every page dropped back to
   * static and pushed whatever followed it down for the length of the
   * fetch. Measured at 1280x800 on /settings?tab=capture-devices: the panel
   * host travelled y=159 to y=183 and back across one request, two layout
   * shifts of 0.198 apiece and a route CLS of 0.4214 against the 0.1 budget
   * this codebase sets for skeleton geometry.
   *
   * Absolute with no offsets keeps the spinner at its static position, so
   * it paints exactly where it always did and displaces nothing. The
   * comment above this rule always claimed indicators reserve no space;
   * now both states honour it.
   */
  .htmx-indicator {
    position: absolute;
  }
  .htmx-indicator:not(:is(.htmx-request, [data-shell-loading])) {
    display: none;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
  }
  .htmx-indicator:is(.htmx-request, [data-shell-loading]) {
    display: inline-block;
  }

  [data-page="dashboard"] [data-dashboard-widget]:not([data-widget="recent-cases"]),
  [data-page-type="collection"] [data-dashboard-widget] {
    overflow: hidden;
  }


  [data-dashboard-widget][data-widget-density="compact"] [data-case-journey-host],
  [data-dashboard-widget][data-widget-density="compact"] [data-case-journey] {
    min-height: 0;
  }






  /* Nested fragment hosts stay unframed — DashboardWidget owns the only chrome. */
  [data-page="dashboard"] [data-dashboard-widget] [data-dashboard-widget-fragment],
  [data-page-type="collection"] [data-dashboard-widget] [data-dashboard-widget-fragment] {
    min-width: 0;
  }

  /* Idle HTMX indicators must not reserve layout on home/collection. */
  [data-page="dashboard"] .htmx-indicator:not(:is(.htmx-request, [data-shell-loading])),
  [data-page-type="home"] .htmx-indicator:not(:is(.htmx-request, [data-shell-loading])),
  [data-page-type="collection"] .htmx-indicator:not(:is(.htmx-request, [data-shell-loading])) {
    display: none;
    width: 0;
    height: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
    position: absolute;
  }

  /*
   * Layout customizer exclusivity (Apple edit mode):
   * daisyUI .card-actions is @layer — unlayered SSOT with compound
   * class+attr selectors wins via cascade. Only show size/move/
   * visibility chrome while data-dashboard-editing=true.
   */
  [data-dashboard-panel-controls][hidden],
  [data-dashboard-visibility-tray][hidden],
  [data-dashboard-uniform-size-tray][hidden],
  [data-dashboard-layout-root][data-dashboard-editing="false"] [data-dashboard-panel-controls],
  [data-dashboard-layout-root][data-dashboard-editing="false"] [data-dashboard-visibility-tray],
  [data-dashboard-layout-root][data-dashboard-editing="false"] [data-dashboard-uniform-size-tray] {
    display: none;
    visibility: hidden;
    pointer-events: none;
    width: 0;
    height: 0;
    min-height: 0;
    margin: 0;
    padding: 0;
    overflow: hidden;
    border: 0;
    gap: 0;
  }

  [data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-panel-controls]:not([hidden]),
  [data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-visibility-tray]:not([hidden]),
  [data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-uniform-size-tray]:not([hidden]) {
    display: flex;
    visibility: visible;
    pointer-events: auto;
    width: auto;
    height: auto;
    min-height: 0;
  }

  /* Uniform size tray labels → icon-first density on phone when editing. */
  @media (max-width: 47.99rem) {
    [data-dashboard-uniform-size-tray] > .btn {
      min-width: var(--touch-target-min, 2.75rem);
      max-width: var(--touch-target-min, 2.75rem);
      padding-inline: 0;
      justify-content: center;
    }
  }

  /*
   * Popover customizer (renderAs: "popover"):
   * Source shell under the layout root is display:contents / none until edit.
   * JS reparents trays into [data-dashboard-customizer-dropdown] next to the
   * header customize button — that host must size and show content itself.
   */
  [data-dashboard-customizer-popover] {
    display: contents;
  }
  [data-dashboard-layout-root][data-dashboard-customizer-render="popover"][data-dashboard-editing="false"] [data-dashboard-customizer-popover] {
    display: none;
  }
  [data-dashboard-layout-root][data-dashboard-customizer-render="popover"][data-dashboard-editing="true"] [data-dashboard-customizer-content] {
    display: flex;
    flex-direction: column;
    visibility: visible;
  }
  /*
   * Runtime host + open-tray geometry live UNLAYERED in
   * tokens-layout-customizer-host.ts — inside @layer utilities they lose to
   * unlayered daisyUI dropdown structure and the tray ships 0x0.
   */
  [data-dashboard-customizer-dropdown] [data-dashboard-uniform-size-tray]:not([hidden]),
  [data-dashboard-customizer-dropdown] [data-dashboard-visibility-tray]:not([hidden]),
  [data-dashboard-layout-root][data-dashboard-customizer-render="popover"] [data-dashboard-uniform-size-tray]:not([hidden]),
  [data-dashboard-layout-root][data-dashboard-customizer-render="popover"] [data-dashboard-visibility-tray]:not([hidden]) {
    display: flex;
    flex-wrap: wrap;
    visibility: visible;
    width: 100%;
    max-width: none;
    min-height: var(--touch-target-min, 2.75rem);
    margin-block: 0;
    gap: var(--space-micro, 0.25rem);
  }
  [data-dashboard-customizer-dropdown] [data-dashboard-customizer-section],
  [data-dashboard-customizer-content] [data-dashboard-customizer-section] {
    display: flex;
    flex-direction: column;
    gap: var(--space-micro, 0.25rem);
    width: 100%;
    min-width: 0;
  }

  /*
   * Phone home densify — widget helper/body copy is secondary to the KPI.
   * Two-line clamp keeps the card grid scannable (Apple widget density);
   * full copy remains in aria when truncated by overflow.
   */
  @media (max-width: 47.99rem) {
    /* Clamp descriptions only; shared table values retain their own flex layout. */
    [data-page="dashboard"] [data-dashboard-widget] [data-widget-description] {
      display: -webkit-box;
      -webkit-box-orient: vertical;
      -webkit-line-clamp: 2;
      overflow: hidden;
      text-overflow: ellipsis;
    }
    [data-page="dashboard"] [data-dashboard-widget] .bao-dashboard-panel-value {
      font-size: var(--text-lg, 1.125rem);
      line-height: 1.2;
    }
    /*
     * Drag-handle chrome clutter: fine-pointer grab affordance is desktop-only.
     * Phone / coarse pointers reorder via customize move buttons (HIG 2.5.7).
     */
  }

/* Widget titles remain readable at compact widths. */
[data-dashboard-widget] .card-title > .truncate {
  white-space: normal;
  overflow: visible;
  text-overflow: clip;
}


/* Recent-case table scroll bounds belong to the widget, not the conversation shell. */
  [data-page="dashboard"] [data-dashboard-widget][data-widget="recent-cases"] .bao-panel-scroll,
  [data-page="dashboard"] [data-dashboard-widget][data-widget-id="recent-cases"] .bao-data-panel,
  [data-page="dashboard"] [data-dashboard-widget][data-widget-id="recent-cases"] .bao-panel-scroll {
    max-height: min(22rem, 42vh);
  }

[data-report-pdf-preview] {
  min-inline-size: 0;
  min-block-size: 0;
}

.bao-report-pdf-frame[data-report-pdf-frame] {
  display: block;
  flex: 1 1 auto;
  inline-size: 100%;
  block-size: min(34rem, calc(var(--vv-height, 100dvh) * 0.55));
  min-inline-size: 0;
  min-block-size: 0;
  max-block-size: 100%;
  border: 1px solid var(--border-base);
  border-radius: var(--radius-field);
  background: var(--color-base-100);
}

@media (max-width: 47.99rem) {
  .bao-report-pdf-frame[data-report-pdf-frame] {
    block-size: min(18rem, calc(var(--vv-height, 100dvh) * 0.34));
  }
}

@media (forced-colors: active) {
  .bao-report-pdf-frame[data-report-pdf-frame] {
    border-color: ButtonText;
    background: Canvas;
  }
}


  /* Page-level skeleton shells — geometry matches final success layout
     (CLS < 0.1). Pair daisyUI skeleton class on children for motion. */
  .bao-page-skeleton {
    box-sizing: border-box;
    width: 100%; min-width: 0; max-width: 100%;
    overflow-x: clip;
  }
  .bao-page-skeleton-default {
    display: flex;
    flex-direction: column;
    gap: var(--space-inline);
    padding-block: var(--space-page);
  }
  .bao-page-skeleton-grid {
    display: grid;
    align-items: stretch;
    grid-auto-rows: auto;
    gap: var(--space-section);
    padding-block: var(--space-page);
    container-type: inline-size;
    grid-template-columns: repeat(
      auto-fit,
      minmax(min(100%, var(--grid-track-min, 18rem)), 1fr)
    );
  }
  /* Detail / auth skeleton: centered single column matching AuthShell card
     geometry so the skeleton-to-content swap stays CLS-safe (CLS < 0.1). */
  .bao-page-skeleton-detail {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 0;
    flex: 1 1 auto;
    gap: var(--space-section);
    padding-block: var(--space-empty);
    padding-inline: var(--space-page);
  }
  .bao-page-skeleton-detail > .bao-skeleton-panel {
    width: 100%;
    max-width: var(--auth, 28rem);
  }
  .bao-page-skeleton-table {
    display: flex;
    flex-direction: column;
    gap: var(--space-inline);
    padding-block: var(--space-page);
  }
  .bao-page-skeleton-media {
    display: grid;
    min-width: 0;
    gap: var(--space-section);
    padding-block: var(--space-page);
    container-type: inline-size;
    grid-template-columns: minmax(0, 1fr);
  }
  @container (min-width: 40rem) {
    .bao-page-skeleton-media {
      grid-template-columns: minmax(0, 2fr) minmax(0, 1fr);
    }
  }
  .bao-page-skeleton-media-side {
    display: flex;
    flex-direction: column;
    gap: var(--space-inline);
    min-width: 0; max-width: 100%;
  }
  /* Conversation skeleton matches context strip + thread + composer geometry. */
  .bao-page-skeleton-conversation {
    display: flex;
    flex-direction: column;
    gap: var(--space-section);
    min-height: 0;
    flex: 1 1 auto;
    padding-block: var(--space-page);
  }
  .bao-skeleton-conversation-chip {
    height: 3rem;
    width: 100%;
    min-width: 0;
    border-radius: var(--radius-field, 0.75rem);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-conversation-thread {
    flex: 1 1 auto;
    min-height: min(28rem, 50vh);
    width: 100%;
    border-radius: var(--radius-box, 1rem);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  .bao-skeleton-conversation-composer {
    height: 8rem;
    width: 100%;
    flex: 0 0 auto;
    max-width: var(--page-wide, 96rem);
    margin-inline: auto;
    border-radius: var(--radius-box, 1rem);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface-hover);
  }

  /* Skeleton blocks — solid surfaces for data (no glass on dense chrome). */
  .bao-skeleton-line {
    height: var(--bao-skeleton-line-height);
    width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-line-short {
    height: var(--bao-skeleton-line-height);
    width: var(--bao-skeleton-line-short);
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-line-medium {
    height: var(--bao-skeleton-line-height);
    width: var(--bao-skeleton-line-medium);
    max-width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-line-long {
    height: var(--bao-skeleton-line-height);
    width: var(--bao-skeleton-line-long);
    max-width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-line-title {
    height: var(--bao-skeleton-line-height);
    width: var(--bao-skeleton-line-title);
    max-width: 100%;
    border-radius: var(--radius-box, 1rem);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-line-subtitle {
    height: var(--bao-skeleton-line-height);
    width: var(--bao-skeleton-line-subtitle);
    max-width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-value {
    height: var(--bao-skeleton-row-height-dense);
    width: var(--bao-skeleton-table-col-wide);
    max-width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-value-hero {
    height: var(--bao-skeleton-row-height);
    width: var(--bao-skeleton-line-title);
    max-width: 100%;
    border-radius: var(--radius-box, 1rem);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-block {
    height: var(--bao-skeleton-card-image-height);
    width: 100%;
    border-radius: var(--radius-box, 1rem);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-mark {
    width: var(--bao-skeleton-avatar-size);
    height: var(--bao-skeleton-avatar-size);
    max-width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-list-dot {
    width: var(--space-inline);
    height: var(--space-inline);
    max-width: 100%;
    margin-top: var(--space-micro);
    border-radius: var(--radius-full);
    flex: 0 0 auto;
    background-color: var(--bg-surface-hover);
  }
  /* Card shells clip their own overflow; dropdown/popover surfaces stay unclipped. */
  .card.bao-data-panel,
  .bao-card-clip {
    min-width: 0;
    max-width: 100%;
    overflow: clip;
  }
  .bao-skeleton-panel {
    box-sizing: border-box; display: flex;
    flex-direction: column;
    gap: var(--space-inline);
    min-height: var(--skeleton-panel-min-height, 7rem);
    width: 100%; min-width: 0; max-width: 100%;
    overflow-x: clip;
    padding: var(--space-page);
    border-radius: var(--radius-box, 1rem);
    border: 1px solid var(--border-base);
    background-color: var(--bg-panel);
    box-shadow: 0 1px 2px color-mix(in oklab, var(--color-base-content) 6%, transparent);
  }
  .bao-skeleton-panel-body {
    height: 3.5rem;
    width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-home-full {
    min-height: 12rem;
    width: 100%;
    border-radius: var(--radius-box, 1rem);
  }
  .bao-skeleton-media {
    box-sizing: border-box; aspect-ratio: 16 / 9;
    width: 100%; max-width: 100%;
    min-height: var(--skeleton-media-min-height, 12rem);
    overflow-x: clip;
    border-radius: var(--radius-box, 1rem);
    border: 1px solid var(--border-base);
    background-color: var(--bg-surface);
  }
  .bao-skeleton-table-header {
    height: var(--density-default-row-height, 2.25rem);
    width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }
  .bao-skeleton-table-row {
    height: var(--density-default-row-height, 2.25rem);
    width: 100%;
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface);
    border: 1px solid var(--border-base);
  }
  /* Pathologist journey step skeleton — matches .bao-pathologist-journey step
     label + circle geometry (tokens-glass-journey-workflow). */
  .bao-pathologist-journey .bao-skeleton-journey-step,
  .bao-skeleton-journey-step {
    display: inline-block;
    height: var(--text-2xs, 0.6875rem);
    width: 4.5rem;
    max-width: 100%;
    min-height: var(--touch-target-min, 2.75rem);
    border-radius: var(--radius-sm);
    background-color: var(--bg-surface-hover);
  }



  /* Named layout surfaces — replace arbitrary Tailwind brackets in .bao tokens. */
  .bao-editor-root {
    min-width: 0;
    max-width: 100%;
    overflow-x: clip;
  }
/* Catalog bounds and wrapping are owned by tokens-layout-editor-toolbar-disclosure. Rail axes are owned by tokens-layout-editor-toolbar-container-presentation. */

  [data-editor-tool-rail] > .btn {
    flex: 0 0 auto;
  }
  /*
   * Context status strip — bounded. Badges wrap or ellipsize; they do not pan.
   */
  [data-editor-context-bar] {
    min-width: 0;
    max-width: 100%;
  }
  [data-editor-chrome] > .flex:has(> [data-editor-context-bar]) {
    min-width: 0;
    max-width: 100%;
  }
  /*
   * Context badge value pill — single-line ellipsis at every viewport so
   * long image UUIDs ('30c35c36-bd5e-...-52ee0') never balloon the strip
   * past the editor column. The dock-densify-b phone rule covers ≤47.99rem;
   * this global rule extends the cap to tablet/desktop so Custody never
   * gets pushed off the right edge of the rail.
   */
  [data-editor-context] strong,
  [data-editor-context-bar] .bao-context-badge strong,
  [data-capture-context] strong {
    display: block;
    min-width: 0;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
  }
  [data-editor-context],
  [data-editor-context-bar] .bao-context-badge,
  [data-capture-context] {
    min-width: 0;
    max-width: 100%;
  }

  /*
   * Filmstrip tiles are the capture navigation under the stage. The current
   * capture carries the primary ring; the tile itself is the touch target,
   * so the ring never shrinks the hit area.
   */
  [data-editor-filmstrip-list] a[aria-current="true"] {
    border-color: var(--color-primary);
    background: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  [data-editor-filmstrip-list] a:hover,
  [data-editor-filmstrip-list] a:focus-visible {
    border-color: var(--border-base, var(--color-base-300));
  }

@media (max-width: 47.99rem) {
  /*
   * Model provenance belongs to the AI panel on a phone. The strip measured
   * three rows at 390px with "Provider: litert · Model: MedGemma 1.5 4B
   * Vision" on the last, over a 200px canvas.
   */
  [data-editor-status-bar] [data-editor-status="ai-provider"],
  [data-editor-status-bar] [data-editor-status="ai-model"] {
    display: none;
  }
  /*
   * Status strip density (Apple HUD): keep zoom + review + AI provenance;
   * hide cursor/input/layer chrome that floods the bottom overlay on phone.
   */
  [data-editor-status-bar] [data-editor-status="cursor"],
  [data-editor-status-bar] [data-editor-status="input"],
  [data-editor-status-bar] [data-editor-status="layer"] {
    display: none;
  }
  /*
   * Dimension switcher collapses to its glyphs with the rest of the stage
   * toolbar, so leading and trailing share one row.
   */
  [data-editor-stage-toolbar] [data-viz-dimension-switcher] button > span:not(.sr-only) {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  [data-ai-overlay-item] [data-ai-overlay-coords],
  [data-ai-overlay-item] [data-ai-overlay-space],
  [data-ai-overlay-item] [data-ai-overlay-geometry-projection-row],
  [data-ai-overlay-item] [data-ai-overlay-source-row],
  [data-ai-overlay-item] [data-ai-overlay-created-row] {
    display: none;
  }
  .bao-ai-provenance-sticky {
    grid-template-columns: minmax(0, 1fr);
  }
}

  /* The media and its direct layers stay inside the canvas host at every text size. */
  [data-editor-stage] canvas,
  .bao-editor-canvas canvas,
  .bao-editor-canvas > * {
    max-width: 100%;
  }
  /* Annotate session panel shares the same bounded flex chain as capture stage.
   * Panel + chrome clip; workbench owns overflow-y scroll (never nest hidden). */
  [data-session-panel="annotate"] {
    display: flex;
    flex-direction: column;
    min-height: 0;
    max-height: 100%;
    flex: 1 1 0%;
    overflow: hidden;
  }
  [data-session-panel="annotate"] .bao-editor-workbench {
    min-height: 0;
    max-height: 100%;
    flex: 1 1 0%;
    overflow-x: hidden;
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    touch-action: pan-y;
  }
  .bao-editor-canvas[data-state="empty"] [data-editor-viewport-controls="2d"],
  .bao-editor-canvas[data-state="error"] [data-editor-viewport-controls="2d"] {
    display: none;
  }
  /*
   * Empty / error: Fabric stage paints an opaque white box over the empty
   * CTA (z-canvas-base under fabric). Park fabric below and inert until an
   * image loads; empty panel owns the full stage with solid fill + CTAs.
   */
  .bao-editor-canvas[data-state="empty"] .bao-fabric-stage,
  .bao-editor-canvas[data-state="error"] .bao-fabric-stage {
    opacity: 0;
    pointer-events: none;
    z-index: var(--z-canvas-base, 1);
  }
  .bao-editor-canvas[data-state="empty"] [data-editor-canvas-empty],
  .bao-editor-canvas[data-state="error"] [data-editor-canvas-empty] {
    display: flex;
    z-index: var(--z-canvas-empty, 20);
    pointer-events: auto;
  }
  /* No clinical image: present one acquisition decision, not an inert tool wall. */
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-toolbar] [data-tool],
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-ai-review-form] button[type="submit"],
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-ai-review-form] select,
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-ai-review-form] input:not([type="hidden"]) {
    pointer-events: none;
  }
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-document-status] [data-editor-context-bar],
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-toolbar],
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-canvas-overlays]:not([data-inspector-expanded="true"]),
  [data-editor-chrome]:not([data-annotation-ready="true"]) .bao-editor-save-bar,
  /*
   * The 3D stage may paint when the operator has explicitly asked for it, even
   * with nothing loaded — it owns an empty state ("No specimen in 3D") that is
   * the whole point of showing it. Without this exemption the dimension toggle
   * was a dead control: measured on /editor at 1440x900 with an empty canvas,
   * clicking "Switch to 3D" flipped data-editor-view-mode to "3d" and
   * aria-pressed to "true" while the 3D column stayed display:none and the 2D
   * column stayed visible. Nothing on screen changed, and assistive tech was
   * told the 3D view was active when it was not.
   */
  [data-editor-chrome]:not([data-annotation-ready="true"]):not([data-editor-view-mode="3d"]) [data-editor-3d-viewport] {
    display: none;
  }
  /* Dual guard: the canvas island is authoritative when its state is empty. */
  [data-editor-chrome]:has(.bao-editor-canvas[data-state="empty"]) [data-editor-toolbar],
  [data-editor-chrome]:has(.bao-editor-canvas[data-state="empty"]) [data-editor-canvas-overlays]:not([data-inspector-expanded="true"]),
  [data-editor-chrome]:not([data-editor-view-mode="3d"]):has(.bao-editor-canvas[data-state="empty"]) [data-editor-3d-viewport],
  [data-editor-chrome]:has(.bao-editor-canvas[data-state="empty"]) .bao-editor-save-bar {
    display: none;
  }
  /*
   * Empty / not-ready stage: no readouts. Zoom, save and review state
   * describe an image that is not there, and a provider/model pair names a
   * model that has not run — measured on every audited band, the empty stage
   * header read "Provider: litert · Model: MedGemma 1.5 4B Vision" over a
   * placeholder. The AI panel in the inspector is where a model is chosen;
   * the strip returns with the image.
   */
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-status-bar],
  [data-editor-chrome]:has(.bao-editor-canvas[data-state="empty"]) [data-editor-status-bar] {
    display: none;
  }
  /* AI finding selection is owned by tokens-glass-shell-overlays. */
  [data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-canvas-region] {
    width: 100%;
    min-width: 100%;
    flex-basis: 100%;
  }
  /*
   * Immersion idle-hide: fade chrome that OVERLAYS the specimen after
   * inactivity (JS sets data-editor-chrome-idle). Status strip STAYS painted —
   * zoom / AI provenance chips are diagnostic HUD, not chrome thrash (Apple
   * media player keeps the scrubber readable; design.pdf §5.4).
   *
   * The stage header IS the document toolbar now (Save, Export, 2D/3D, the
   * inspector tabs' toggle), so it auto-hides only in immersive maximize —
   * HIG toolbars never vanish from a normal window. Measured 2026-08-23 in
   * the Claude Browser pane at 1440x900: an untouched window showed the stage
   * with no toolbar at all after the idle timer fired.
   */
  [data-editor-chrome][data-canvas-maximized="true"][data-editor-chrome-idle="true"] [data-editor-stage-header],
  body[data-canvas-maximized="true"] [data-editor-chrome][data-editor-chrome-idle="true"] [data-editor-stage-header],
  body[data-canvas-maximized="true"] [data-editor-chrome][data-editor-chrome-idle="true"] [data-editor-toolbar] {
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-normal) var(--easing-standard, ease);
  }
  /*
   * Immersive maximize: mirror island state on editor chrome (WebViews without
   * :has). Hide inspector sheet; floating toolbar + stage/status keep glass SSOT.
   */
  [data-editor-chrome][data-canvas-maximized="true"] [data-editor-canvas-overlays],
  [data-editor-chrome][data-canvas-maximized="true"] [data-editor-filmstrip-disclosure] {
    display: none;
  }
  /* WebView-safe mirror of the maximized canvas state. The filmstrip is stage
     navigation, not stage: measured maximized at 1440x900 it kept painting at
     y=142 over the specimen. */
  body[data-canvas-maximized="true"] [data-editor-canvas-overlays],
  body[data-canvas-maximized="true"] [data-editor-filmstrip-disclosure] {
    display: none;
  }

  /*
   * Maximized: the palette is absolutely positioned inside the stage, and the
   * stage is what goes full-screen, so the palette rides with it and needs no
   * fixed-strip mirror.
   */
  /*
   * Selected tool affordance (design.pdf §2.11): active tool gets filled-weight
   * icon stroke beyond the glass ring — stroke-only SVGs only; no path fill.
   */
  [data-editor-toolbar] [data-tool][aria-pressed="true"] svg {
    stroke-width: 2.2;
  }
  [data-editor-toolbar] [data-tool][aria-pressed="true"] svg [fill="none"] {
    fill: none;
  }
  @media (prefers-reduced-motion: reduce) {
    [data-editor-chrome][data-editor-chrome-idle="true"] [data-editor-toolbar],
    [data-editor-chrome][data-editor-chrome-idle="true"] [data-editor-stage-header] {
      transition: none;
    }
  }
  [data-editor-requires-image][aria-disabled="true"] {
    pointer-events: none;
  }
  /*
   * 2D/3D dimension radios are sr-only (focusable) instead of display:none
   * (AE-06): the visible focus ring lands on the hosting label so keyboard
   * operation of the radiogroup stays perceivable.
   */
  [data-viz-dimension-switcher] label:has(input[type="radio"]:focus-visible) {
    outline: var(--focus-ring-width) solid var(--color-primary, var(--accent-primary, currentColor));
    outline-offset: var(--focus-ring-offset);
  }
  /* Phone density: drop AI/spatial panel marketing blurbs; keep controls. */
  @media (max-width: 40rem) {
    [data-editor-ai-review] > p,
    [data-editor-spatial] > p,
    [data-editor-overlays] > p {
      display: none;
    }
    /* Model select already lists options; search is desktop densify only. */
    [data-editor-ai-model-search] {
      display: none;
    }
  }
  /* Disabled Finish/Generate must never look primary-ready (daisy softens). */
  [data-page-header-actions] .btn:disabled,
  [data-page-header-actions] .btn[aria-disabled="true"],
  [data-page-header-actions] .btn.btn-disabled {
    opacity: var(--opacity-muted, 0.55);
    pointer-events: none;
  }


.bao-editor-filmstrip [data-editor-filmstrip-list] {
  display: flex;
  flex-wrap: nowrap;
  overflow-x: auto;
  scroll-snap-type: x proximity;
}


/* The capture rail is intrinsic chrome; it never claims leftover stage height. */
[data-editor-stage] > [data-editor-filmstrip-disclosure],
[data-editor-stage] > [data-editor-filmstrip-disclosure] > [data-editor-filmstrip] {
  min-block-size: 0;
  block-size: fit-content;
  max-block-size: max-content;
  flex: 0 0 auto;
}

/* Thumbnails align their snap edge to the rail's inline start, and the rail
   reserves the same scroll buffer every other interactive surface uses so
   focus rings are never clipped by the strip's padding box. */
.bao-editor-filmstrip-item {
  scroll-snap-align: start;
}

.bao-editor-filmstrip [data-editor-filmstrip-list] {
  scroll-padding-inline-start: var(--space-micro, 0.25rem);
}

  .bao-editor-workbench > [data-editor-canvas-overlays] {
    min-width: 0;
    max-width: 100%;
    height: 100%;
    max-height: 100%;
    flex: 0 1 var(--editor-canvas-overlays-basis);
  }
  .bao-editor-workbench > [data-editor-canvas-overlays]:not([data-inspector-expanded="true"]) {
    display: none;
  }
  /*
   * Small browser viewports keep the workbench vertically scrollable. Column
   * priority is defined separately by the workbench container so a rail-narrowed
   * desktop follows the same stage-first contract.
   */
  @media (max-width: 64rem) {.bao-editor-workbench,
[data-session-panel="annotate"] .bao-editor-workbench {
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
    }
  }
  .bao-editor-spatial-form {
    margin-top: var(--space-section);
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-form-min)), 1fr));
    align-items: end;
    gap: var(--space-inline);
  }
  /*
   * Review-state FSM picker (design.pdf §6 selected-vs-rest): soft buttons at
   * rest; the CURRENT state owns the persistent primary fill; legal targets
   * stay quiet; illegal transitions disable without vanishing.
   */
  [data-editor-review-transitions] [data-review-transition] {
    justify-content: flex-start;
    text-align: start;
  }
  [data-editor-review-transitions] [data-review-transition][aria-pressed="true"] {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: var(--accent-primary-content);
    box-shadow: inset 0 0 0 1px color-mix(in oklab, var(--accent-primary-content) 35%, transparent);
  }
  /* Selected toolbar and stage controls own solid accent fill to resolve layered paint contrast. */
  [data-viz-dimension-switcher] button[aria-pressed="true"],
  [data-editor-tool-rail] [data-tool][aria-pressed="true"],
  .bao-toolbar-action[aria-pressed="true"] {
    background: var(--accent-primary);
    border-color: var(--accent-primary);
    color: var(--accent-primary-content);
    opacity: 1;
  }[data-editor-review-transitions] [data-review-transition]:disabled,
[data-editor-review-transitions] [data-review-transition][aria-disabled="true"] {
    opacity: var(--opacity-disabled, 0.5);
    box-shadow: none;
  }
  /* The inspector body owns scrolling; transition choices stay in its content flow. */
  [data-editor-review-transitions] fieldset {
    display: flex;
    flex-direction: column;
    flex-wrap: nowrap;
    gap: var(--space-micro, 0.25rem);
    width: 100%;
  }
  [data-editor-review-transitions] fieldset [data-review-transition] {
    width: 100%;
    min-width: 0;
  }
  /* Submit spans its own row so the label never clips in the narrow inspector
     rail; coordinate fields (x/y and optional z) reflow across the row above. */
  .bao-editor-spatial-form > button {
    grid-column: 1 / -1;
  }/* The AI review dock reuses the spatial form shell but carries full-width
     controls (mode,
model,
search) rather than coordinate cells: stack them. */
  .bao-editor-spatial-form[data-editor-ai-review-form] {
    grid-template-columns: minmax(0, 1fr);
  }
  .bao-panel-scroll {
    min-width: 0;
    width: 100%;
    max-height: var(--panel-scroll-max-height);
    overflow-x: auto;
    overflow-y: auto;
  }
  [data-sidebar-rail][data-sidebar-expanded="true"] {
    padding-block: var(--space-section);
    padding-inline: min(var(--space-section), 5%);
  }/*
   * ID + class beats Tailwind overflow-x-hidden on .bao-shell-sidebar so tip +
   * focus rings escape the icon rail (daisyUI is-drawer-close pattern).
   */
  .bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"],
[data-sidebar-rail][data-sidebar-expanded="false"] {
    padding: var(--space-micro);
    overflow-x: visible;
  }/* Icon-only rail: center targets,
keep ≥44px hit area on touch. */
  [data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item {
    justify-content: center;
    min-height: var(--touch-target-min, 2.75rem);
    min-width: var(--touch-target-min, 2.75rem);
    padding-inline: 0;
  }
  /*
   * Focus ring inset — outline-offset:2 clips under overflow-y:auto parents.
   * daisyUI 5 tips open on :hover / :has(:focus-visible) child only;the tip
   * class lives on the focused <a>,
so keyboard must force tip opacity here.
   */
  [data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-primary, var(--accent-primary, currentColor));
    outline-offset: var(--focus-ring-offset-tight);
    z-index: var(--z-raised, 2);
    position: relative;
  }[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip:focus-visible[data-tip]::before,
[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip:focus-visible::after {
    opacity: 100%;
    --tt-pos: 0rem;
  }[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.menu-active,
[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item[aria-current="page"] {
    box-shadow: none;
    background: color-mix(in oklab, var(--accent-primary) 18%, var(--bg-panel));
  }
  /* Icon rail: hide group titles + expanded labels;tooltips carry names. */
  [data-sidebar-rail][data-sidebar-expanded="false"] .menu-title,
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] .menu-title {
    display: none;
  }[data-sidebar-rail][data-sidebar-expanded="false"] [data-sidebar-expanded-only],
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] [data-sidebar-expanded-only] {
    display: none;
  }[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip::before,
[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip::after,
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip::before,
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item.tooltip::after {
    display: block;
  }
  @media (min-width: 80rem) {.bao-shell-sidebar .bao-nav-item.menu-active,
.bao-shell-sidebar .bao-nav-item[aria-current="page"] {
      background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
      box-shadow: inset 0 0 0 1px var(--liquid-border-regular);
      font-weight: 600;
    }
    /*
     * Permanent-rail band: smooth label/icon rescale when collapse toggles.
     * Expanded labels fade/max-width;collapsed icons recenter with a subtle
     * scale cue (design.pdf §8.6 — dock yields to rail at 80rem).
     */
    .bao-shell-sidebar .bao-nav-item [data-sidebar-expanded-only],
.bao-shell-sidebar .menu-title {
      transition-property: opacity, max-width, margin-inline-start;
      transition-duration: var(--duration-normal);
      transition-timing-function: var(--easing-standard);
    }.bao-shell-sidebar .bao-nav-item svg,
.bao-shell-sidebar .bao-nav-item [aria-hidden="true"] svg {
      transition: transform var(--duration-fast) var(--easing-standard);
      transform-origin: center;
    }[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item svg,
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item svg {
      transform: scale(1.08);
    }
  }
  @media (min-width: 80rem) and (prefers-reduced-motion: reduce) {.bao-shell-sidebar .bao-nav-item [data-sidebar-expanded-only],
.bao-shell-sidebar .menu-title,
.bao-shell-sidebar .bao-nav-item svg {
      transition: none;
    }[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item svg,
.bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] .bao-nav-item svg {
      transform: none;
    }
  }
  /* Phone: header-anchored customizer becomes a pinned bottom sheet
     (source popover is display:contents; runtime host is
     [data-dashboard-customizer-dropdown] next to the edit toggle). */
  @media (max-width: 47.99rem) {
    [data-dashboard-customizer-dropdown].dropdown-open {
      position: fixed;
      inset-inline: 0;
      inset-block-end: calc(var(--dock-height, 4rem) + var(--dock-safe-area-offset, 0px) + env(safe-area-inset-bottom, 0px));
      inset-block-start: auto;
      display: block;
      z-index: var(--z-shell-topbar, 30);
    }[data-dashboard-customizer-dropdown].dropdown-open > [data-dashboard-customizer-content],
[data-dashboard-customizer-popover] .dropdown-content,
[data-dashboard-customizer-content] {
      position: static;
      min-width: 0;
      border-radius: var(--radius-box, 1rem) var(--radius-box, 1rem) 0 0;
      border-block-end: none;
      overflow-y: auto;
      -webkit-overflow-scrolling: touch;
      overscroll-behavior-y: contain;
    }
  }
/* Native paint controls share a fluid field grid at every inspector width. */
.bao-editor-paint-fields {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-context-min)), 1fr));
  gap: var(--space-inline);
  min-inline-size: 0;
}
/*
 * Editor height ownership and empty-stage floor. Column bands live in
 * tokens-layout-editor-workbench-grid (named `editor-surface`).
 * Query the workbench, not an unnamed container and not the viewport:
 * a pinned session rail can leave a desktop window with a tablet-width grid.
 */
/*
 * The empty stage fills its column at every band. A 48vh cap used to leave
 * the placeholder floating over an ~850px void on a 768x1024 tablet and a
 * 174px void on a phone; the grid row (`minmax(0, 1fr)`) already bounds the
 * column, so the cap only ever subtracted from the stage.
 */




  /* Stage column geometry and dimension visibility are owned by tokens-layout-editor-stage-structure. */
  /*
   * Dimension-scoped tool rails: the 2D rail floats over the stage and stayed
   * visible (and enabled) in 3D view, where its drawing tools are inert — the
   * phone visual gate measured Rectangle/Ellipse/Freehand clicks with zero
   * effect. Hide the off-dimension rail so gated controls are never presented
   * as live. 3D tools only exist while the 3D pose owns the stage.
   */
  [data-editor-chrome][data-editor-view-mode="3d"] [data-editor-tool-rail][data-editor-tool-dimension="2d"] {
    display: none;
  }
  [data-editor-chrome]:not([data-editor-view-mode="3d"]) [data-editor-tool-rail][data-editor-tool-dimension="3d"] {
    display: none;
  }
  /*
   * Desktop dual-pane only: when the inspector is actually live (annotation-ready
   * + side-by-side >64rem),
provider/model chips leave the status strip to avoid
   * dual chrome. Idle empty stage keeps chips so model provenance stays visible
   * while the AI review form is zero-geometry (pointer-events/hidden until ready).
   * Phone + tablet stack the inspector (≤64rem) — always keep chips in the HUD.
   */
  @media (min-width: 64.01rem) {[data-page-type="media"] [data-editor-chrome][data-annotation-ready="true"] [data-editor-status="ai-provider"],
[data-page-type="media"] [data-editor-chrome][data-annotation-ready="true"] [data-editor-status="ai-model"] {
      display: none;
    }
  }

  /* The WebGL canvas fills the region; OrbitControls owns its gestures. */
  .bao-editor-3d-viewport > canvas {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    display: block;
    touch-action: none;
    cursor: grab;
  }
  .bao-editor-3d-viewport > canvas:active {
    cursor: grabbing;
  }
  /* Keyboard focus ring on the runtime canvas (tabindex 0 via focus-contract). */
  .bao-editor-3d-viewport > canvas:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-primary, var(--accent-primary, currentColor));
    outline-offset: var(--focus-ring-offset-tight);
  }/* State machine: exactly one state block visible at a time. */
  .bao-editor-3d-viewport [data-editor-3d-loading],
.bao-editor-3d-viewport [data-editor-3d-empty],
.bao-editor-3d-viewport [data-editor-3d-error] {
    display: none;
  }.bao-editor-3d-viewport[data-state="loading"] [data-editor-3d-loading],
.bao-editor-3d-viewport[data-state="empty"] [data-editor-3d-empty],
.bao-editor-3d-viewport[data-state="error"] [data-editor-3d-error] {
    display: flex;
    z-index: var(--z-canvas-empty, 20);
    pointer-events: auto;
  }/* Media controls only make sense on a live scene. */
  .bao-editor-3d-viewport[data-state="loading"] [data-editor-3d-controls],
.bao-editor-3d-viewport[data-state="empty"] [data-editor-3d-controls],
.bao-editor-3d-viewport[data-state="error"] [data-editor-3d-controls] {
    display: none;
  }
  /* Collapse toggle exists only for the compact sheet transformation. */
  [data-editor-3d-toggle] {
    display: none;
  }
  /*
   * Compact sheet: a 44px toggle collapses the 3D sheet to its stage
   * header so the 2D canvas keeps the phone stage (HIG sheet pattern).
   */
  @container (max-width: 47.99rem) {
    [data-editor-chrome][data-editor-view-mode="dual"] [data-editor-3d-toggle] {
      display: inline-flex;
    }
    .bao-editor-3d-viewport[data-editor-3d-collapsed="true"] [data-editor-3d-toggle] svg {
      transform: rotate(180deg);
    }
    [data-editor-3d-toggle] svg {
      transition: transform var(--duration-normal) var(--easing-standard, ease);
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .bao-editor-3d-viewport [data-editor-3d-toggle] svg {
      transition: none;
    }
  }







  /* HD-aligned home skeleton tracks (dashboard-like density). */
  .bao-skeleton-home-narrow {
    min-height: 7rem;
    width: 100%;
    border-radius: var(--radius-box, 1rem);
  }
  .bao-skeleton-home-wide {
    min-height: 12rem;
    width: 100%;
    border-radius: var(--radius-box, 1rem);
  }



  /**
   * Canvas region min-height from layoutSize tokens (no arbitrary min-h-*).
   */
  .bao-canvas-region {
    min-height: var(--canvas-region-min-height, clamp(18rem, 42vh, 30rem));
  }
  /**
   * Fabric stage SSOT — layout via CSS custom properties, never Fabric
   * inline width/height/position.
   */
  .bao-fabric-stage {
    position: relative;
    box-sizing: border-box;
    width: 100%;
    height: 100%;
    min-width: 0;
    min-height: 0;
    max-width: 100%;
    overflow: hidden;
    touch-action: none;
    user-select: none;
  }
  /**
   * Dropdown escape hatch — fixed to viewport when open so overflow table
   * ancestors cannot clip menus. Geometry vars published by app-shell-dropdowns
   * via adopted CSS host vars (no element style=).
   * The compound selector must out-rank the later-emitted
   * ".bao-dropdown-panel { position: absolute }" glass-chrome reset — a bare
   * class ties on specificity and loses on source order (clipped 44px menus).
   */
  /* Repeated class = (0,2,0): hosts without .bao-dropdown-panel (runtime
     customizer tray) must still out-rank daisyUI's .dropdown .dropdown-content
     position:absolute, which ties a bare class and wins on order. */
  .bao-dropdown-panel-viewport.bao-dropdown-panel-viewport,
  .bao-dropdown-panel.bao-dropdown-panel-viewport {
    position: fixed;
    /* One anchoring owner in the escaped state. The panel also carries daisyUI's
       .dropdown placement classes, which anchor it with position-area; this
       state anchors it with the measured --bao-dropdown-* insets published by
       app-shell-dropdowns-geometry. Both applied at once and the two offsets
       summed: measured on the chat composer at 824px, a trigger at x=501 with a
       published left of 493px put the open menu at 994px — wholly off-screen,
       so clicking the composer's More button appeared to do nothing at all.
       Neutralising position-area here leaves the measured insets as the single
       owner; panels that already resolved correctly do not move. */
    position-area: none;
    z-index: var(--z-dropdown, 1000);
    max-height: var(--bao-dropdown-max-height, 50vh);
    /* Paired with the two-sided inset clamp in app-shell-dropdowns-geometry:
       the clamp keeps both edges on screen only while the panel fits, so a
       panel wider than the phone is narrowed here rather than clipped. */
    max-width: var(--bao-dropdown-max-width, calc(100vw - 1rem));
    overflow-y: auto;
    top: var(--bao-dropdown-top, auto);
    bottom: var(--bao-dropdown-bottom, auto);
    left: var(--bao-dropdown-left, auto);
    right: var(--bao-dropdown-right, auto);
    /* Popover top layer: neutralize the UA's inset:0 + margin:auto centering
       so the trigger-anchored geometry vars above stay authoritative. */
    margin: 0;
  }
  .bao-fabric-stage > .canvas-container {
    position: relative;
    box-sizing: border-box;
    width: var(--bao-canvas-css-width, 100%);
    height: var(--bao-canvas-css-height, 100%);
    max-width: 100%;
    touch-action: none;
    user-select: none;
  }
  .bao-fabric-stage .lower-canvas,
  .bao-fabric-stage .upper-canvas {
    position: absolute;
    inset-inline-start: 0;
    inset-block-start: 0;
    left: 0;
    top: 0;
    box-sizing: border-box;
    width: var(--bao-canvas-css-width, 100%);
    height: var(--bao-canvas-css-height, 100%);
    max-width: 100%;
    touch-action: none;
    user-select: none;
  }
  .bao-fabric-stage .upper-canvas {
    z-index: var(--z-local, 1);
  }
  [data-sidebar-rail][data-sidebar-expanded="true"] [data-sidebar-collapsed-only][hidden],
  [data-sidebar-rail][data-sidebar-expanded="false"] [data-sidebar-expanded-only][hidden],
  [data-session-rail][data-expanded="true"] [data-session-rail-collapsed-only][hidden],
  [data-session-rail][data-expanded="false"] [data-session-rail-expanded-only][hidden] {
    display: none;
  }
  /* Session-rail width: tokens-layout-session-rail-resize (user-width clamp). */
  /*
   * DaisyUI collapse peer radios/checkboxes default to a ~13px hit box.
   * Stretch the peer across the full collapse row so FAQ / disclosure rows
   * meet HIG 44px (structure audit small-target gate).
   */
  .collapse > input[type="radio"],
  .collapse > input[type="checkbox"] {
    min-height: var(--touch-target-min, 2.75rem);
    min-width: 100%;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
    z-index: var(--z-local, 1);
  }
  .bao-modal-box-shell {
    max-height: min(var(--modal-max-height), var(--vv-height, 100dvh));
    display: flex;
    flex-direction: column;
    overflow: hidden;
    min-width: 0;
    min-height: 0;
  }
  /*
   * Dialog chrome wash — translucent over elevated glass shell (not a second
   * glass sheet; solid only when reduced-transparency).
   */
  .bao-dialog-chrome {
    background: color-mix(in oklab, var(--color-base-100, var(--bg-panel)) 78%, transparent);
  }
  html[data-reduced-transparency="true"] .bao-dialog-chrome,
  [data-reduced-transparency="true"] .bao-dialog-chrome {
    background: var(--color-base-100, var(--bg-panel));
  }
  @media (prefers-reduced-transparency: reduce) {
    .bao-dialog-chrome {
      background: var(--color-base-100, var(--bg-panel));
    }
  }
  /*
   * Dialog footer safe-area pad — max(section token, device inset).
   * Replaces ad-hoc pb-[max(...)] and pairs with solid footer fill.
   * Button/badge chrome uses Button.bao / Badge.bao tokens only
   * (no local bao-btn-ghost-xs / bao-badge-soft substitutes).
   */
  .bao-dialog-footer-safe {
    padding-bottom: max(
      var(--space-section, 0.75rem),
      env(safe-area-inset-bottom, 0px)
    );
  }
  /* Compact status row host for integration / MCP list items. */
  .bao-data-row {
    min-width: 0;
  }
  .bao-modal-scroll { max-height: var(--modal-scroll-max-height); overflow-y: auto; }
  .bao-modal-body-scroll {
    max-height: min(
      var(--modal-body-max-height),
      calc(var(--vv-height, 100dvh) * 0.55)
    );
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    min-height: 0;
    flex: 1 1 0%;
  }
  /* One progress owner: explicit markers keep connectors clear of every circle. */
  .bao-dialog-steps {
    
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    inline-size: 100%;
    flex: 0 0 auto;
    max-inline-size: 100%;
    margin: 0;
    padding: var(--space-inline) var(--space-section);
    list-style: none;
    font-size: var(--text-xs, 0.75rem);
    line-height: 1.4;
  }
  .bao-dialog-step {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: var(--control-height-sm, 2rem) auto;
    justify-items: center;
    align-content: start;
    row-gap: var(--space-inline);
    min-inline-size: 0;
    position: relative;
    text-align: center;
    --step-bg: var(--border-base);
    --step-fg: var(--text-primary);
  }
  .bao-dialog-step + .bao-dialog-step::before {
    content: "";
    position: absolute;
    inset-inline-start: calc(-50% + var(--control-height-sm, 2rem) / 2);
    inset-block-start: calc(var(--control-height-sm, 2rem) / 2);
    inline-size: calc(100% - var(--control-height-sm, 2rem));
    block-size: var(--border-width, 1px);
    background: var(--step-bg);
  }
  .bao-dialog-step-marker {
    display: grid;
    place-items: center;
    inline-size: var(--control-height-sm, 2rem);
    block-size: var(--control-height-sm, 2rem);
    border-radius: var(--radius-full);
    background: var(--step-bg);
    color: var(--step-fg);
    font-weight: 600;
    line-height: 1;
  }
  .bao-dialog-step[data-case-create-reached] {
    --step-bg: var(--color-primary);
    --step-fg: var(--color-primary-content);
  }
  .bao-dialog-step-label {
    max-inline-size: 100%;
    padding-inline: var(--space-micro);
    white-space: normal;
    overflow-wrap: anywhere;
    color: var(--color-base-content);
  }
  .bao-dialog-step[aria-current="step"] .bao-dialog-step-label {
    font-weight: 600;
  }
  /*
   * Bottom-sheet dialogs (phone). daisyUI .modal is display:grid +
   * justify-items:center — justify-content does NOT stretch the box. Use
   * justify-items + align-items (grid axes) so the sheet pins full-width to
   * the bottom instead of a floating middle slab.
   *
   * Gated to <40rem to match the `sm:` breakpoint the markup switches on. At
   * 47.99rem this band contradicted the markup across a 128px window: every
   * sheet carries sm:modal-middle, sm:modal-end or sm:hidden, so between
   * 40rem and 47.99rem the dialog was pinned bottom and stretched while the
   * box stayed a centered capped slab with its bottom corners squared off —
   * measured at 700px, border-top radius 16px against bottom radius 0.
   *
   * The box's width, max-width and max-height are deliberately NOT set here.
   * They belong to the unlayered .modal-box rule in
   * tokens-glass-containment.css: this module emits inside @layer utilities,
   * so declaring them here lost the cascade silently and left every sheet
   * capped at 100vw - 1rem regardless of what this band asked for.
   */
  @media (max-width: 39.99rem) {
    dialog.modal.modal-bottom[open],
    dialog.modal.modal-bottom.modal-open {
      align-items: end;
      justify-items: stretch;
      justify-content: stretch;
      margin: 0;
      padding: 0;
      /* Keep sheet inside the visual viewport (keyboard / browser chrome). */
      max-height: var(--vv-height, 100dvh);
    }
    dialog.modal.modal-bottom[open] .modal-box,
    dialog.modal.modal-bottom[open] .bao-modal-box-shell,
    dialog.modal.modal-bottom.modal-open .modal-box,
    dialog.modal.modal-bottom.modal-open .bao-modal-box-shell {
      margin: 0;
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
    }
    /*
     * Bottom-sheet scroll bodies (keyboard-shortcuts sheet, create flow)
     * end flush at the sheet edge — pad the scroll end past the
     * home-indicator safe area (Apple HIG), same token family as
     * .bao-dialog-footer-safe. Scoped to the pinned bottom-sheet band so
     * centered modals keep flush scroll geometry.
     */
    dialog.modal.modal-bottom .bao-modal-body-scroll {
      padding-block-end: calc(var(--space-section, 0.75rem) + env(safe-area-inset-bottom, 0px));
    }
  }
  /*
   * Dense create flow: description is redundant with step labels on phone.
   * Stays on the ≤47.99rem densify gate alongside the step-label clip above —
   * this is a copy-density concern, not bottom-sheet geometry, so it does not
   * follow that band down to <40rem.
   */
  @media (max-width: 47.99rem) {
    [data-case-create-dialog] [data-dialog-description] {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }
  }
  /* Discrete width changes only — no layout-property animation (design §7.4). */
  .bao-motion-width {
    transition-property: none;
  }
  .bao-context-badge[data-context-status="unset"] {
    color: var(--color-base-content, currentColor);
    opacity: var(--opacity-medium, 0.75);
  }
  .bao-context-badge[data-context-status="set"] {
    border-color: color-mix(in oklab, var(--color-success) 50%, transparent);
  }
  .bao-context-badge[data-context-status="warning"] {
    border-color: color-mix(in oklab, var(--color-warning) 50%, transparent);
  }
  .bao-context-badge[data-context-status="error"] {
    border-color: color-mix(in oklab, var(--color-error) 50%, transparent);
  }
  /* Context cards use the same semantic status colors as badges. */
  .bao-context-card[data-context-status="set"] {
    border-color: color-mix(in oklab, var(--color-success) 50%, transparent);
  }
  .bao-context-card[data-context-status="warning"] {
    border-color: color-mix(in oklab, var(--color-warning) 50%, transparent);
  }
  .bao-context-card[data-context-status="error"] {
    border-color: color-mix(in oklab, var(--color-error) 50%, transparent);
  }


/* Native hr/button chrome off — grip is a pure APG separator host. */
.bao-session-rail-resizer {
  margin: 0;
  border: 0;
  padding: 0;
  background: transparent;
  appearance: none;
  color: inherit;
  font: inherit;
}

/* Session-rail width + resize grip — sole owner of expanded/collapsed width.
 * Drag/keyboard publish --session-rail-user-width via setHostCssVars.
 * position:relative on the rail is required: the grip is position:absolute and
 * the content row (.relative overflow-x-clip) must NOT be the containing block
 * or inset-inline-start pins to the main column, not the rail edge.
 *
 * HIG Dynamic Type: at large root font the rail's rem-based width can push the
 * right edge past the viewport because flex: 0 0 auto held the track open. The
 * existing clamp(min, user, max, 100cqi-main) on [data-session-rail][data-expanded="true"]
 * already caps the upper bound, but a stuck shrink-0 on the rail itself
 * defeated the clamp and let the row overflow. Allow the rail to yield
 * space so the row stays inside the visible viewport; the collapsed floor in
 * [data-session-rail][data-expanded="false"] keeps the expand toggle inside the rail.
 */
[data-session-rail] {
  position: relative;
  flex: 0 1 auto;
  min-width: 0;
  /* HIG Dynamic Type: font-invariant cap so the rem-based clamp (12rem min,
     32rem max) cannot grow 4x at 400% root font and push the rail past the
     viewport. 40vw ≈ --session-rail-max at 1440px and holds at 200%/400%. */
  max-inline-size: 40vw;
}

[data-session-rail][data-expanded="true"] {
  inline-size: clamp(
    var(--session-rail-min),
    var(--session-rail-user-width, var(--session-rail-expanded)),
    min(
      var(--session-rail-max),
      calc(
        100cqi - var(--sidebar-expanded) - var(--session-rail-main-min)
      )
    )
  );
}

/*
 * Derived from what the rail must contain, not a magic width that almost fits.
 *
 * The collapsed rail holds exactly one control — the expand toggle — and that
 * control carries the HIG touch floor (--touch-target-min) inside the rail
 * header's inline padding (--space-section, from Rail.bao `header`). The old
 * flat --session-rail-collapsed of 3rem left 4px for a 44px target sitting in
 * 12px of padding, so the button overflowed its own rail: measured on /cases
 * at 1440x900, the control ran x=1406..1450 inside a rail ending at 1440, and
 * 10px of a primary control sat outside the viewport entirely.
 *
 * max() keeps the token as the floor, so a future wider --session-rail-collapsed
 * still wins and this never silently shrinks the rail.
 */
[data-session-rail][data-expanded="false"] {
  inline-size: max(
    var(--session-rail-collapsed),
    calc(var(--touch-target-min, 2.75rem) + 2 * var(--space-section, 0.75rem))
  );
}

/*
 * Class mirrors of the two data-expanded width contracts above, declared for
 * the Rail primitive's sessionExpanded/sessionCollapsed tokens (Rail.bao).
 * The shell drives rail state through [data-session-rail][data-expanded];
 * wherever a host renders the rail by class instead, these keep the same
 * clamp/max arithmetic so the class form cannot drift from the attribute
 * form (the class-resolution gate resolves both spellings to this owner).
 */
.bao-session-rail-expanded {
  inline-size: clamp(
    var(--session-rail-min),
    var(--session-rail-user-width, var(--session-rail-expanded)),
    min(
      var(--session-rail-max),
      calc(
        100cqi - var(--sidebar-expanded) - var(--session-rail-main-min)
      )
    )
  );
}

.bao-session-rail-collapsed {
  inline-size: max(
    var(--session-rail-collapsed),
    calc(var(--touch-target-min, 2.75rem) + 2 * var(--space-section, 0.75rem))
  );
}

.bao-session-rail-resizer {
  display: none;
}

@media (min-width: 80rem) {
  [data-session-rail][data-expanded="true"] .bao-session-rail-resizer {
    position: absolute;
    z-index: var(--z-content-overlay, 10);
    inset-block: 0;
    /* Center the grip on the rail's inline-start edge (into main by half). */
    inset-inline-start: 0;
    display: block;
    /* The splitter is an <hr>, and the UA sheet gives hr an explicit
       block-size: 0. An explicit size beats inset-block stretching, so the
       grip computed 44x0 — full width, no hit area at all. auto restores the
       stretch that inset-block: 0 is meant to produce. */
    block-size: auto;
    /*
     * One --space-section-wide strip centered on the boundary (±half into each
     * pane), matched to the rail header's own inline padding so the strip can
     * never reach a control: measured on /capture and /editor at desktop, a
     * touch-target-min-wide strip reached 10px INTO the header's first button
     * and the case picker's summary — elementFromPoint gave those pixels to
     * the grip, so a finger aiming at the control's left half dragged the
     * splitter instead (browser-structure-audit hig-touch-target findings).
     * Splitter drag stays a full-height strip with col-resize cursor plus the
     * keyboard path (focusable window-splitter pattern in
     * app-shell-rails-resize.ts); VS Code-class splitters use the same few-
     * pixel band. The visual pill is ::before, unchanged.
     */
    inline-size: var(--space-section, 0.75rem);
    margin-inline-start: calc(-0.5 * var(--space-section, 0.75rem));
    padding: 0;
    border: 0;
    background: transparent;
    cursor: col-resize;
    touch-action: none;
    pointer-events: auto;
    /* Drag must not select rail or canvas text mid-gesture. */
    user-select: none;
    -webkit-user-select: none;
    appearance: none;
    outline-offset: var(--focus-ring-offset-tight);
  }

  [data-session-rail][data-expanded="true"] .bao-session-rail-resizer::before {
    position: absolute;
    inset-inline-start: 50%;
    inset-block: calc(var(--space-section, 0.75rem) * 2);
    inline-size: var(--space-2xs, 0.125rem);
    border-radius: var(--radius-full);
    background: color-mix(in oklab, var(--color-base-content) 28%, transparent);
    box-shadow: 0 0 0 1px color-mix(in oklab, var(--color-base-100) 72%, transparent);
    content: "";
    transform: translateX(-50%);
    pointer-events: none;
  }

  [data-session-rail][data-expanded="true"] .bao-session-rail-resizer:hover::before,
  [data-session-rail][data-expanded="true"] .bao-session-rail-resizer:focus-visible::before,
  [data-session-rail][data-session-rail-resizing="true"] .bao-session-rail-resizer::before {
    inline-size: var(--space-micro, 0.25rem);
    background: var(--color-primary);
  }

  [data-session-rail][data-expanded="true"] .bao-session-rail-resizer:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-primary);
  }
}

/* Dark step paint needs no override: --border-base, --text-primary, --color-primary and --color-primary-content already flip per theme. */

/* Native columns preserve the complete record at every width. The shared
 * scroll owner exposes intrinsic overflow; cell labels duplicate column headers. */
.bao-table-responsive-cell > .bao-table-mobile-label {
  display: none;
}
.bao-table-responsive-cell > .bao-table-mobile-value:not(:is(.bao-table-identity-value, .bao-table-row-actions)) {
  display: contents;
}

section[data-filtered-table],
[data-filtered-table] {
  container-type: inline-size;
  container-name: table;
}

.bao-table-scroll-x {
  max-block-size: var(--panel-scroll-max-height);
  overflow-y: auto;
  scroll-padding-block-start: var(--touch-target-min);
  scroll-padding-inline-end: var(--touch-target-min);
}

.bao-table-column-fit-hidden {
  display: none;
}

.bao-table-pinned-fit-unstuck .bao-table-pinned-action,
.bao-table-pinned-fit-unstuck .bao-table-pinned-divider {
  position: static;
}


/* Keep responsive action groups within the canonical row-action width. */
.bao-table-responsive-cell > .bao-table-mobile-value.bao-table-row-actions:where(:not([hidden])) {
  display: flex;
  justify-content: end;
  flex-wrap: wrap;
  gap: var(--space-micro);
  max-inline-size: var(--table-row-actions-max-inline);
}
/*
 * Identity stacks (name + mono secondary): always start-align, even when
 * values contain multiple lines. This class owns the identity stack.
 */
.bao-table-identity-value {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: flex-start;
  text-align: start;
}

/*
 * Empty rows in TABLE mode — keep table-row / table-cell so HTML colspan
 * spans every column. Forcing display:block here (previous bug) made the
 * empty cell shrink to the first column track (~88px tall brick).
 */
.bao-table-responsive-empty-cell {
  border-width: 0;
  padding-inline: var(--space-inline);
  padding-block: var(--space-inline);
  box-sizing: border-box;
  text-align: center;
  vertical-align: middle;
}
.bao-table-empty-panel {
  display: flex;
  min-block-size: 6rem;
  margin-inline: auto;
  box-sizing: border-box;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-micro, 0.25rem);
  padding-inline: var(--space-section);
  padding-block: var(--space-inline, 0.5rem);
  text-align: center;
  /*
   * Phone band: the colspan cell spans the table's full min-width, which
   * exceeds the visible scrollport in responsive (horizontally scrolled)
   * tables — a width:100% panel centered in that cell lands half off
   * screen and the empty copy reads clipped. The table container bounds
   * the panel even in narrow desktop panes. Container width + dual-edge
   * sticky keeps the whole panel inside the visible scrollport at any
   * scroll position (margin auto still centers it when unconstrained, so
   * desktop renders identically).
   */
  position: sticky;
  inset-inline-start: 0;
  inset-inline-end: 0;
  inline-size: min(36rem, calc(100cqi - (var(--space-inline, 1rem) * 2)));
  max-inline-size: 100%;
}

/*
 * Billing decision row chrome (S04/S20): solid surfaces + semantic border,
 * never opacity-* wash over row text (design.pdf §2.10).
 */
[data-billing-decision="accepted"] {
  border-color: var(--color-success, var(--status-success));
  background-color: color-mix(in oklab, var(--color-success, var(--status-success)) 8%, var(--color-base-100, var(--bg-panel)));
}
[data-billing-decision="rejected"] {
  border-color: var(--border-base, color-mix(in oklab, var(--color-base-content) 12%, transparent));
  background-color: var(--color-base-200, var(--bg-surface));
  color: var(--color-base-content);
}
[data-billing-decision="rejected"] .text-base-content,
[data-billing-decision="rejected"] td {
  color: inherit;
}

/*
 * Pagination join SSOT — phone content columns are ~20rem; five 44px
 * touch targets + labels already press the edge. Controls own max-width
 * + horizontal scroll so page numbers never paint past #app-main (HIG
 * dense toolbar; never stretch join-items with flex-1).
 */
[data-pagination] [data-api-registry-page-buttons],
[data-pagination] .join,
[data-primitive="Pagination"] .join {
  max-width: 100%;
  min-width: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}
@media (max-width: 39.99rem) {
  /* Phone: prev/current/next only — hide non-current page jumps to free
     the strip for 44px targets without horizontal thrash. */
  [data-pagination] button[data-api-registry-page-number]:not([aria-current="page"]),
  [data-primitive="Pagination"] button[data-api-registry-page-number]:not([aria-current="page"]) {
    display: none;
  }
  [data-pagination] .join > span[aria-hidden="true"],
  [data-primitive="Pagination"] .join > span[aria-hidden="true"] {
    display: none;
  }
}

/* Collection metadata and paging belong to the table plane, not striped record cards. */
.table > tbody > tr[data-table-utility-row] {
  background-color: transparent;
  box-shadow: none;
  grid-column: 1 / -1;
}


/* Identity/action cells share an inline primary row; secondary-only identities stay stacked. */
.bao-table-identity-actions {
  display: grid;
  grid-template-columns: minmax(max-content, 1fr) max-content;
  min-inline-size: 0;
  text-align: start;
  align-items: center;
  gap: var(--space-inline);
}
.bao-table-identity-actions > .bao-table-identity-value {
  min-inline-size: 0;
  overflow-wrap: normal;
}
.bao-table-identity-actions > [data-table-row-actions] {
  justify-self: end;
}

/*
 * Case-row column-kind hooks (case-row.bao, caseq-case-row-*.bao).
 * Box layout stays with the co-applied DataTable primitives, responsive
 * display rules, and Tailwind utilities; these rules pin the
 * reading-direction contract for each column kind.
 */
.bao-case-table-identity-cell {
  text-align: start;
}
.bao-case-table-state-cell {
  text-align: start;
}
.bao-case-table-actions-cell {
  text-align: end;
}
.bao-case-table-identity-value {
  text-align: start;
}
.bao-table-cell-stack {
  text-align: start;
}



/* Every resizable column owns one logical end boundary and one content rectangle. */
.bao-registry-table {
  --table-resize-content-end: calc(var(--touch-target-min) + var(--space-inline));
}
.bao-registry-table > thead > tr > th[data-col-resizable] {
  --col-min: var(--table-column-min);
  --col-max: var(--table-column-max);
  min-inline-size: var(--col-min);
  max-inline-size: var(--col-max);
}
.bao-registry-table:not([data-table-resized]) {
  table-layout: auto;
}
.bao-registry-table[data-table-resized] {
  table-layout: fixed;
  inline-size: var(--table-resize-width);
  min-inline-size: var(--table-resize-width);
  max-inline-size: var(--table-resize-width);
}
.bao-registry-table[data-table-resized] > thead > tr:first-child > th {
  box-sizing: border-box;
  width: var(--col-width);
}
.bao-registry-table > thead > tr > th[data-col-resizable],
.bao-registry-table > tbody > tr > td[data-col-resizable] {
  padding-inline-end: var(--table-resize-content-end);
}
.bao-table-resize-handle {
  position: absolute;
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: var(--touch-target-min);
  padding: 0;
  border: 0;
  background: transparent;
  cursor: col-resize;
  touch-action: none;
  z-index: var(--z-local, 1);
}
.bao-table-resize-handle::after {
  content: "";
  position: absolute;
  inset-block: 20%;
  inset-inline-end: 0;
  inline-size: var(--pane-divider);
  border-radius: var(--radius-selector);
  background: color-mix(in oklab, var(--text-primary) 18%, transparent);
  transition: background var(--duration-fast) var(--easing-standard);
}
.bao-table-resize-handle:hover::after,
.bao-table-resize-handle:focus-visible::after,
.bao-table-resize-handle[data-resize-state="active"]::after {
  background: var(--color-primary);
}
.bao-table-resize-handle:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-primary);
  outline-offset: calc(-1 * var(--focus-ring-width));
}
@media (prefers-reduced-motion: reduce) {
  .bao-table-resize-handle::after {
    transition: none;
  }
}

/*
 * Multi-sort (Table.bao sortControl/sortIndicator/sortPrecedence tokens).
 * The control wraps the existing header copy (label = column name); the
 * indicator glyph and precedence badge are decorative siblings exposed via
 * aria-sort on the columnheader.
 */
.bao-table-sort-control {
  display: inline-flex;
  align-items: center;
  gap: var(--space-micro, 0.25rem);
  width: 100%;
  min-width: 0;
  padding: 0;
  border: 0;
  background: transparent;
  font: inherit;
  /*
   * Never inherit a muted thead / text-label colour — axe color-contrast on
   * the label span (button > span:nth-child(1)) failed /cases and dashboard
   * when inherit resolved to ~2.x:1 against the header plate.
   */
  color: var(--color-base-content);
  text-align: start;
  cursor: pointer;
  user-select: none;
}
/* Explicit label span: first child is the column name from decorateHeader. */
.bao-table-sort-control > span:first-child {
  color: var(--color-base-content);
  opacity: 1;
}
.bao-table-sort-control:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-primary);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-selector, 0.25rem);
}
.bao-table-sort-indicator {
  flex: 0 0 auto;
  line-height: 1;
  color: var(--color-base-content);
}
.bao-table-sort-precedence {
  flex: 0 0 auto;
  min-width: 1em;
  padding-inline: var(--space-micro, 0.25rem);
  border-radius: var(--radius-selector, 0.25rem);
  background: var(--color-primary);
  color: var(--color-primary-content);
  font-size: var(--text-2xs, 0.6875rem);
  line-height: 1.4;
  text-align: center;
  font-variant-numeric: tabular-nums;
}
/* Numeric labels and values share the inline end; controls occupy the leading side. */
th.text-end > .bao-table-sort-control {
  justify-content: flex-end;
}
th[data-col-kind="numeric"] > .bao-table-sort-control {
  flex-direction: row-reverse;
  justify-content: flex-start;
}

/*
 * Inline edit (Table.bao inlineEditCell/inlineEditEditor/inlineEditEditing
 * tokens). The editor swaps into the cell, inherits cell typography, and
 * keeps focus rings inside the table density.
 */
td.bao-table-inline-edit-cell {
  cursor: default;
}
td.bao-table-inline-editing {
  padding-block: var(--space-micro, 0.25rem);
}
.bao-table-inline-edit-group {
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
  gap: var(--space-micro, 0.25rem);
}
.bao-table-inline-edit-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  min-inline-size: 0;
  gap: var(--space-micro, 0.25rem);
}
.bao-table-inline-editor {
  inline-size: 100%;
  min-inline-size: var(--touch-target-min, 2.75rem);
  min-block-size: var(--touch-target-min, 2.75rem);
  font: inherit;
  font-size: var(--text-sm);
  color: inherit;
  background: var(--color-base-100);
  border: 1px solid var(--border-base);
  border-radius: var(--radius-field, 0.5rem);
  padding-inline: var(--space-inline, 0.5rem);
  padding-block: var(--space-micro, 0.25rem);
}
/* Keyboard focus is owned by the shared focus-visible control rule. */

/*
 * Long-press selection mode (Table.bao selectionModeActive token).
 * Coarse pointers suppress the iOS callout/text magnifier over selectable
 * rows so the 500ms gesture is not preempted; selected-row tint follows the
 * same base-200 fill the desktop rowSelected token paints.
 */
@media (pointer: coarse) {
  [data-table-selection-host] tbody {
    -webkit-touch-callout: none;
  }
  [data-table-selection-host].bao-table-selection-mode tbody {
    user-select: none;
    -webkit-user-select: none;
  }
}
[data-table-selection-host].bao-table-selection-mode tr[data-row-id] {
  cursor: pointer;
}
.bao-registry-table > tbody > tr[aria-selected="true"] {
  background-color: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
}
.bao-registry-table > tbody > tr[aria-selected="true"] > td {
  background-color: inherit;
}

/* Inline-edit activator is a real button — meet SC 2.5.8 (24) and HIG 44. */
[data-inline-edit-activator],
td.bao-table-inline-edit-cell > button,
td.bao-table-inline-edit-cell > [role="button"] {
  min-height: var(--touch-target-min, 2.75rem);
  min-width: var(--touch-target-min, 2.75rem);
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  justify-content: flex-start;
  padding-block: var(--space-micro, 0.25rem);
  padding-inline: var(--space-inline, 0.5rem);
  line-height: 1.25;
  height: auto;
}

/*
 * Header cells keep daisyUI's muted thead colour (60% base-content), which
 * measures 4.45:1 on the pinned header plate against a 4.5:1 AA floor — the
 * reason axe fails .z-table-action and .bao-table-pinned-divider on /cases
 * and the dashboard at desktop and tablet. Sortable headers already escape
 * it because the sort control above forces full base-content on its label;
 * Actions and the select-all cell have no control to carry that, so the
 * muted inherit reaches the operator. Full base-content measures 15.68:1.
 */
.bao-registry-table > thead > tr > th {
  color: var(--color-base-content);
}

  /*
   * Numeric columns (G-DATA register): counts, sizes, rates, and amounts are
   * end-aligned with fixed-width numerals so digits line up vertically. The
   * kind is stamped into `data-col-kind` by table-column-kind through the
   * head and body emitters, so one rule reaches every table that declares a
   * numeric column — cases captures, review-queue confidence, billing
   * reimbursement, model size, licensing seats, export steps — and no
   * per-table alignment copy exists.
   */
  .table th[data-col-kind="numeric"],
  .table td[data-col-kind="numeric"] {
    text-align: end;
    font-variant-numeric: tabular-nums;
  }


/* Table cells keep their header-aligned content flow at every width.
 * The retired card conversion no longer needs a label/value gap clamp. */


/* DataTable owns responsive record layout for every collection. */



  /*
   * Borders — STYLE only. Tailwind already emits the 1px width for each of
   * these; re-declaring it here shipped the same width a second time from a
   * stylesheet that loads after Tailwind's, in the same `utilities` layer and
   * at the same specificity, so the duplicate won — and `border-width` is the
   * four-side shorthand, so it reset the inline-start width every directional
   * utility had just set. Measured on /specimens: the case picker's selected
   * line carries `border border-s-4`, and its 4px selection accent rendered
   * at 1px, which is the same hairline an unselected card shows.
   *
   * The style half is what this block is for: `--tw-border-style` reaches the
   * width utilities through a registered custom property, and stating `solid`
   * outright keeps the border painted in an engine that does not register it.
   */
  .border,
  .border-t,
  .border-b,
  .border-l,
  .border-r {
    border-style: solid;
  }
  .border-dashed { border-style: dashed; }

  /* Toolbar content stacks use the existing raised-content token. */
  .z-raised-high { z-index: var(--z-raised-high); }

  /* Typography/target/radius vars come ONLY from tokens.bao (@layer base
     :root emission) — never re-declare them here: an unlayered duplicate
     silently forks the scale (text-2xs shipped 0.625rem vs 0.6875rem). */
  .text-2xs { font-size: var(--text-2xs); line-height: 0.875rem; }
  .text-xs { font-size: var(--text-xs); line-height: 1rem; }
  .text-sm { font-size: var(--text-sm); line-height: 1.25rem; }
  .text-base { font-size: var(--text-base); line-height: 1.5rem; }
  .text-lg { font-size: var(--text-lg); line-height: 1.75rem; }
  .text-xl { font-size: var(--text-xl); line-height: 1.75rem; }
  .text-3xl { font-size: var(--text-3xl); line-height: 2.25rem; }
  .font-medium { font-weight: 500; }
  .font-semibold { font-weight: 600; }
  .font-bold { font-weight: 700; }
  /* Typography SSOT — tokens.bao font stacks must reach the document. */
  .font-sans { font-family: var(--font-sans); }
  .font-brand { font-family: var(--font-brand); }
  .font-mono { font-family: var(--font-mono); }
  .leading-none { line-height: 1; }
  .leading-tight { line-height: 1.25; }
  .tracking-tight { letter-spacing: var(--tracking-tight, -0.025em); }
  .tracking-wider { letter-spacing: var(--tracking-wider, 0.05em); }
  .tracking-wide { letter-spacing: var(--tracking-wide, 0.025em); }
  /* Opacity wash for body/row mute is banned (S04/S20). Disabled only. */

  /* Transform motion is .bao-motion-transition-transform. Color motion is .bao-motion-transition-colors. */
  .bao-motion-transition-transform { transition-property: transform; transition-timing-function: var(--easing-standard); transition-duration: var(--duration-normal); }
  .disabled\:pointer-events-none:disabled { pointer-events: none; }
  .disabled\:opacity-50:disabled { opacity: var(--opacity-disabled, 0.5); }
  .placeholder\:text-base-content\/60::placeholder { color: var(--text-secondary); }
  .file\:border-0::file-selector-button { border-width: 0; }
  .file\:bg-transparent::file-selector-button { background-color: transparent; }
  .file\:text-sm::file-selector-button { font-size: var(--text-sm, 0.875rem); }
  .file\:font-medium::file-selector-button { font-weight: 500; }
  .translate-x-0 { transform: translateX(0); }
  .translate-x-4 { transform: translateX(1rem); }
  /* Pulse animation owner is .bao-pulse-alpha in tokens-glass-motion.css. */
  .blur { filter: blur(var(--liquid-blur-clear)); }

  /* The former responsive flex-direction "escape" blocks are gone with the
     structural duplicates that made them necessary — Tailwind's own
     breakpoint-gated variants apply again in their native order. */

  /*
   * Nested solid data panels: table wraps inside form/widget cards must not
   * re-apply card chrome (double border / double shadow). Apple clarity:
   * one surface owns the panel; nested scroll hosts stay transparent.
   */
  .bao-data-panel .bao-data-panel.overflow-x-auto,
  .card .bao-data-panel.overflow-x-auto,
  [data-training-plans-panel] .bao-data-panel.overflow-x-auto,
  [data-training-jobs-table] .bao-data-panel.overflow-x-auto,
  [data-model-lifecycle-section] .bao-data-panel.overflow-x-auto {
    border-width: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  /* One owner per fact: the connector strip announces the SELECTED
     provider's state, so the selected roster row hides its duplicate
     state label (probe dots on non-selected rows stay). */
  [data-provider-selected="true"] [data-provider-state-label] {
    display: none;
  }
}


/* Active recorder controls use the error tone while ordinary pressed selections
   retain their authored control tone. Recording lifecycle owns both state markers. */
.btn[data-video-recording="true"],
.btn[data-audio-recording="true"] {
  border-color: var(--color-error);
  background-color: var(--color-error);
  color: var(--color-error-content);
}

/* One semantic tone scale for operator notices, status dots and state copy.
   Every value resolves from the canonical colour roles; no consumer forks it. */
.alert[data-tone="error"],
.status[data-tone="error"],
[data-state="error"] {
  --tone: var(--color-error);
  --tone-content: var(--color-error-content);
}
.alert[data-tone="success"],
.status[data-tone="success"],
[data-state="success"] {
  --tone: var(--color-success);
  --tone-content: var(--color-success-content);
}
.alert[data-tone="warning"],
.status[data-tone="warning"],
[data-state="warning"] {
  --tone: var(--color-warning);
  --tone-content: var(--color-warning-content);
}
.alert[data-tone="info"],
.status[data-tone="info"],
[data-state="info"] {
  --tone: var(--color-info);
  --tone-content: var(--color-info-content);
}
.alert[data-tone] {
  border-color: var(--tone);
  background-color: color-mix(in oklab, var(--tone) 12%, var(--color-base-100));
  color: var(--tone-content);
}
.status[data-tone] {
  background-color: var(--tone);
}
[data-state="error"],
[data-state="success"],
[data-state="warning"],
[data-state="info"] {
  color: var(--tone);
}

@layer utilities {
  .max-w-page-standard { max-width: var(--page-standard); }
  .max-w-page-wide { max-width: var(--page-wide); }
  .max-w-page-full { max-width: var(--page-full); }
  .max-w-page-conversation { max-width: var(--page-conversation); }
  .max-w-description { max-width: var(--description); }
  .max-w-overlay-panel { max-width: var(--overlay-panel); }
  .max-w-auth { max-width: var(--auth); }
  .max-w-form { max-width: var(--form); }
}


/* Establish the pseudo-element containing block before utilities and the
   late bao-tokens layer. State-owned component geometry therefore retains
   ownership when a glass surface changes between in-flow and overlay modes. */
@layer components {
  :where(.bao-surface-glass-regular, .bao-surface-glass-clear, .bao-surface-glass-strong, .bao-surface-glass-modal) {
    position: relative;
  }
}

@layer bao-tokens {

  /*
   * Responsive SSOT lives on these classes — not Tailwind md:hidden/md:block.
   * A later unscoped display:grid was beating md:hidden and left desktop stuck
   * on the mobile card dump with the table permanently display:none.
   */
  .bao-registry-mobile-list {
    display: grid;
    min-width: 0;
    gap: var(--space-section);
  }
  .bao-registry-desktop-scroll {
    display: none;
    min-width: 0;
    width: 100%;
  }
  @media (min-width: 48rem) {
    .bao-registry-mobile-list {
      display: none;
    }
    .bao-registry-desktop-scroll {
      display: block;
    }
  }
  .bao-registry-meta-grid {
    display: grid;
    min-width: 0;
    gap: var(--space-inline);
  }
  .bao-registry-meta-row {
    display: grid;
    min-width: 0;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: var(--space-inline);
  }
  .bao-registry-mobile-entry {
    min-width: 0;
  }
  .table.bao-registry-table {
    /* Fit available space before scrolling content that cannot wrap. */
    min-width: 100%;
    max-width: none;
  }
  /* Discovery/widget card bodies must not expand main past the viewport. */
  [data-page="models"] .card-body,
  [data-page="models"] [data-widget-value] {
    min-width: 0;
    max-width: 100%;
  }

  /*
     The pinned cell inherits the row-owned content plane so horizontally
     scrolled values never remain legible beneath an action. It used to derive base-100/base-200 from :nth-child itself,
     which made the row and its pinned cell two owners of one colour, and they
     disagreed the moment anything restyled the row: the dashboard's
     home-page case-list rule sets rows transparent at specificity (0,2,2)
     and beats daisyUI's zebra at (0,1,2), so the rows
     went flat while the Actions column carried on painting a stripe nothing
     else had — a plate of white and base-200 floating against unstriped rows,
     and a white header cell beside a base-200 header row.

     The action shelf remains opaque through the row surface while its left depth shadow
     communicates that the column is pinned above the horizontally scrolling
     data plane.
  */
  .table > tbody > tr > .bao-table-pinned-action {
    background-color: inherit;
  }
  /*
     Inheritance alone leaves the shelf transparent on unstriped rows. Zebra
     paints only :nth-child(even), so an odd row computes rgba(0,0,0,0) and the
     pinned cell faithfully inherits nothing. Measured on
     /settings?tab=capture-devices at 1280x800: the devices table lays out at
     783px inside a 713px scrollport, so 70px of the Status column sits under
     the shelf, and its status badge printed straight through the row-actions
     button — half a pill floating over the overflow control.

     Only a still-pinned shelf needs this opaque plate. Released actions
     scroll with their record and inherit its surface, including transparent
     odd rows and hover states; painting them separately leaves a white square.
  */
  .bao-registry-table.bao-table-pinned-scrolls:not(.bao-table-pinned-fit-unstuck) > tbody > tr:nth-child(odd) > .bao-table-pinned-action {
    background-color: var(--bg-panel, var(--color-base-100));
  }
  /*
     Same rule one level up: the header ROW owns the header surface and every
     header cell inherits it, pinned one included. Previously each th carried
     its own bg-base-200 while the header row stayed white, so the sticky cell
     had nothing correct to inherit and rendered white against base-200
     siblings. One owner per row removes the choice.
  */
  .table > thead > tr {
    background-color: var(--bg-surface);
  }
  .table > thead > tr > th {
    background-color: inherit;
  }
  /*
     The pinned action shelf stays stable during row hover. The row content
     communicates hover and focus while the shelf remains an opaque, reliable
     control plane above horizontally scrolling values.
  */
  /* Narrative columns preserve a readable measure inside the shared table scrollport. */
  @media (min-width: 48rem) {
  @container table (width >= 40rem) {
    .bao-registry-table th[data-col-kind="prose"] {
      width: var(--table-prose-min-inline);
    }
  }
  }

  /*
   * Column floors belong to TABLE mode only, so they share the card-stack
   * owner's 40rem CONTAINER threshold (tokens-layout-table-responsive.ts)
   * on the NAMED table container. The extra viewport guard closes the
   * hybrid band: at phone viewports (<48rem) the dock densify module card-
   * stacks registry rows by MEDIA query, and a 640–767px container inside
   * that band satisfied width>=40rem — floors then crushed the first
   * stacked cell to 5.5rem ("Accession" → "Ac…" on dashboard cards).
   */
  /*
   * Column floors belong to what a column HOLDS, not to where it sits.
   *
   * These were `nth-child(1..11)` floors: column two took 14rem on every
   * registry in the product whether it held an episode name or a two-letter
   * state, and reordering a table silently swapped its widths. They totalled
   * 62.5rem before the pinned action column — wider than any desktop
   * container — so a second positional block cancelled `nth-child(2..11)`
   * back to `min-width: 0` between 40rem and 84.5rem. Position asserted a
   * width, then position retracted it, and the band between them was the
   * only place tables actually laid out.
   *
   * `data-col-kind` is emitted per cell by pages-renderers-responsive-table
   * from the column's own i18n key, so a floor follows its column through any
   * reorder. Only these three kinds have a real minimum legible width; every
   * other column is content-driven, which is what the cancelling block was
   * asking for.
   *
   * The threshold is the container width at which the floors are affordable,
   * measured rather than assumed: at a 1042px container the floored table
   * lays out at exactly 1042px, and at 884px it wants 954px and scrolls. A
   * floor is a legibility luxury, so below 60rem of container every column
   * goes content-driven and the table fits itself to the room it has. The
   * viewport guard keeps all of this off the phone card stack.
   */
  @media (min-width: 48rem) {
  @container table (width >= 60rem) {
    /*
     * Header only. A column's floor comes from its widest constraint under
     * `table-layout: auto`, so flooring the header floors the column; adding
     * the matching `td` selectors measured identical at every viewport —
     * 1042/1042 at 1440px, 1330/1330 at 1728px, 900/884 at 1280px — which
     * makes them weight without effect. Cells carry `data-col-kind` for a
     * different consumer: `validate:table-cell-column-parity` reads it to hold
     * each row partial's cells against the columns its section declares.
     */
    .bao-registry-table th[data-col-kind="identifier"] {
      width: var(--table-identifier-column-width);
      white-space: nowrap;
    }
    .bao-registry-table td[data-col-kind="identifier"] {
      white-space: nowrap;
    }
    .bao-registry-table th[data-col-kind="timestamp"] {
      width: var(--table-timestamp-column-width);
    }
    .bao-registry-table th[data-col-kind="actions"] {
      min-width: 6rem;
    }
  }
  }
  /* Technical identities stay atomic; prose wraps between words in the shared scrollport. */
  .bao-registry-cell-mono {
    white-space: nowrap;
  }
  .bao-registry-cell-prose {
    line-height: 1.4;
    overflow-wrap: normal;
    word-break: normal;
  }

}
@layer bao-tokens {
/* Intrinsic table sizing is owned by tokens-layout-registry-surfaces.
 * The shared table scroller and column-fit controller preserve all columns
 * without a breakpoint-specific width or wrapping override. */

}
@layer bao-tokens {
/* design-canon.json liquidGlass.hig — compiled stamps, do not hand-edit */
:root {
  --hig-sticky-chrome-max-layers: mediaPages;
  --hig-glass-layer-content: content;
  --hig-glass-layer-persistent-chrome: persistentChrome;
  --hig-glass-layer-transient: transient;
  --hig-glass-layer-blocking: blocking;
  --hig-clear-glass-dimming: rgba(0, 0, 0, 0.35);
  --hig-type-min: 0.6875rem;
  --hig-bezeled-padding: 0.75rem;
  --hig-unbezeled-padding: 1.5rem;
  --hig-glass-appearance-default: tinted;
  --hig-glass-appearance-stamp: data-liquid-glass;
  --hig-window-radius-token: rounded-box;
}

}
@layer bao-tokens {


/* ============================================================
   Apple Liquid Glass — base layer
   ============================================================
   All glass surfaces share these properties so the highlight ring
   and inner illumination compose consistently across variants. The
   base class is intentionally non-applied (use the named variants
   `.bao-surface-glass-regular`, `.bao-surface-glass-clear`,
   `.bao-surface-glass-strong`, `.bao-surface-glass-modal`, or
   `.bao-surface-glass-solid`).
   Enhanced with better depth, shadows, and accessibility per Apple HIG. */

.bao-surface-glass-regular,
.bao-surface-glass-clear,
.bao-surface-glass-strong,
.bao-surface-glass-modal,
.bao-surface-glass-solid {
  isolation: isolate;
  border-style: solid;
  border-width: 1px;
  transition-property: background-color, border-color;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
}

.bao-surface-glass-regular,
.bao-surface-glass-clear,
.bao-surface-glass-strong,
.bao-surface-glass-modal {
  --liquid-material-illumination: radial-gradient(
    ellipse 120% 80% at 20% 0%,
    var(--glass-illumination-strong) 0%,
    var(--glass-illumination-soft) 50%,
    var(--glass-highlight-clear) 80%
  );
}

/* Unsupported color mixing keeps the original opaque material fallback.
 * Supported engines get their complete paint from the named variant. */
@supports not (background: color-mix(in oklab, black, transparent)) {
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-solid {
    background-color: var(--bg-panel);
    background-blend-mode: var(--glass-noise-blend, overlay);
    background-image: var(--glass-noise-texture, none);
    background-size: var(--glass-noise-size, 128px);
  }
}

/* design.pdf §2.8: grain is an enhancement, never a requirement — hosts
   flagged low-performance (product override) drop the texture entirely. */
html[data-low-performance="true"] {
  --glass-noise-texture: none;
}

/* design.pdf §2.8: never paint grain behind micro labels — the topbar's
   11–12px titles and chip captions lose fidelity over the noise, so the
   chrome that hosts them drops the texture entirely. */
.bao-shell-topbar {
  --glass-noise-texture: none;
}

/*
 * daisyUI drawer-side is position:fixed (closed) / sticky (drawer-open).
 * Unlayered glass position:relative would win the cascade and leave a
 * max-content grid track on mobile, crushing [data-shell-scroll="main"]. Never put glass
 * on .drawer-side — glass belongs on .bao-shell-sidebar / panel chrome only.
 */
.drawer-side.bao-surface-glass-regular,
.drawer-side.bao-surface-glass-clear {
  position: fixed;
}

/* Specular highlight ring (top edge brightness + bottom edge dim).
   The angle is set by `--lg-pointer-angle` (driven by JS, default
   135deg per Apple HIG NW light direction). The gradient uses
   mask-composite to render only as a hairline ring.
   Enhanced with better opacity values for refined depth perception. */
.bao-surface-glass-regular::before,
.bao-surface-glass-clear::before,
.bao-surface-glass-strong::before,
.bao-surface-glass-modal::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: var(--border-width-hairline, 1px);
  background: linear-gradient(
    var(--lg-pointer-angle),
    var(--glass-highlight-strong) 0%,
    var(--glass-highlight-soft) 40%,
    var(--glass-highlight-clear) 70%,
    var(--glass-edge-fade) 100%
  );
  -webkit-mask: linear-gradient(var(--glass-mask-source) 0 0) content-box, linear-gradient(var(--glass-mask-source) 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  pointer-events: none;
  mix-blend-mode: screen;
  /* Pointer angle updates must be instant — transitioning background
     while --lg-pointer-angle changes every frame flashes the pane. */
  transition-property: none;
  /* Specular sits above fill, BELOW interactive children (z-index 3).
     pointer-events:none is required so chrome controls stay clickable. */
  z-index: var(--z-raised, 2);
}

/* Clear, Strong and Modal retain their separate illumination contract.
   Regular composes this decoration beneath its tint in the host background. */
.bao-surface-glass-clear::after,
.bao-surface-glass-strong::after,
.bao-surface-glass-modal::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  pointer-events: none;
  background: var(--liquid-material-illumination);
  mix-blend-mode: screen;
  opacity: 1;
  transition-property: opacity;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
  z-index: var(--z-base, 0);
}

/* Child stacking above specular: tokens-glass-fill.ts (S100 narrow hosts). */

/* ============================================================
   Regular variant — adaptive, works over any content
   ============================================================
   Apple HIG: "Regular is the most versatile and the one you will
   be using the most. This variant gives you all the visual and
   adaptive effects". Use for shell chrome (topbar, sidebar,
   rightRail, command palette, dialogs, sheets). */

/* CANON MAPPING (design.pdf §2.2/§3) — do not let these semantics drift:
   --liquid-fill-* is the panel ALPHA (the bg-panel share in the color-mix),
   so a higher value paints a more opaque pane. Canon requires dark glass to
   run MORE opaque than light (it must suppress bright content underneath),
   so every dark fill value is HIGHER than its light twin in tokens.bao, and
   compact/coarse fills are higher still ("fewer blurred surfaces, stronger
   tint"). Ladder (panel alpha): opacity rises clear < regular(persistent)
   < transient < blocking with the depth layer — a higher layer never has a
   weaker edge/shadow, and dialogs (blocking) never bleed more than the
   menus (transient) stacked beneath them. */

.bao-surface-glass-regular {
  --liquid-material-active-alpha: 0;
  --liquid-material-color: var(--bg-panel);
  --liquid-material-rest-alpha: var(--liquid-fill-persistent);
  --liquid-material-fill: color-mix(
    in oklab,
    var(--liquid-material-color) calc(max(var(--liquid-material-rest-alpha), var(--liquid-material-active-alpha)) * 100%),
    transparent
  );
  background: var(--bg-panel);
  -webkit-backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular));
  backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular));
  border-color: var(--liquid-border-regular);
  /* Depth: broad soft lift + inner shadow for glass depth (Apple HIG). */
  box-shadow:
    var(--shadow-glass-elevated),
    var(--shadow-glass-inner);
}

/* Regular material bounds every decorative glow beneath its tint. The
   transparent background avoids composing the tint twice. Unsupported
   mixing or accessibility preferences retain the solid base above. */
@supports (background: color-mix(in oklab, black, transparent)) {
  @media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (prefers-reduced-motion: no-preference) and (forced-colors: none) {
    .bao-surface-glass-regular {
      background:
        linear-gradient(var(--liquid-material-fill), var(--liquid-material-fill)),
        var(--liquid-material-illumination);
    }
  }
}

/* design.pdf §10–§11: solid fallback first. Engines without backdrop-filter
   keep an opaque surface — never transparency without blur. */
@supports not ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-lens {
    background: var(--bg-panel);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/* Density modifier — size is independent of material. Regular and clear
   chrome share one owner. Apple HIG: glass thickens as the surface grows.
   Small keeps the small blur step and the elevated inner shadow. */
.bao-surface-glass-regular.bao-glass-large,
.bao-surface-glass-clear.bao-glass-large {
  -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular));
  backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular));
  border-color: var(--liquid-border-regular);
}
.bao-surface-glass-regular.bao-glass-small,
.bao-surface-glass-clear.bao-glass-small {
  -webkit-backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-regular));
  backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-regular));
  border-color: var(--liquid-border-regular);
  box-shadow: var(--shadow-glass-elevated), var(--shadow-glass-inner);
}

/* design.pdf §8.2 compact glass treatment: container-query blur reduction on the
   shell host (not viewport width). Blur steps reuse existing scale tokens;
   tint uses dedicated coarse tokens from tokens.bao color.liquid.
   Pair coarse-pointer tint with @media (pointer: coarse) — not width. */
@container shell (max-width: 48rem) {
  .bao-surface-glass-regular {
    -webkit-backdrop-filter: blur(var(--liquid-blur-mobile)) saturate(var(--liquid-saturate-mobile));
    backdrop-filter: blur(var(--liquid-blur-mobile)) saturate(var(--liquid-saturate-mobile));
  }
  .bao-surface-glass-regular.bao-glass-large {
    -webkit-backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-mobile));
    backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-mobile));
  }
}

@media (pointer: coarse) {
  .bao-surface-glass-regular {
    --liquid-material-rest-alpha: var(--liquid-fill-persistent-coarse);
  }
}

/* Tablet optimization: intermediate blur for balanced performance/quality */
@container shell (min-width: 48rem) and (max-width: 63.99rem) {
  .bao-surface-glass-regular {
    -webkit-backdrop-filter: blur(var(--liquid-blur-tablet)) saturate(var(--liquid-saturate-tablet));
    backdrop-filter: blur(var(--liquid-blur-tablet)) saturate(var(--liquid-saturate-tablet));
  }
  .bao-surface-glass-regular.bao-glass-large {
    -webkit-backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-tablet));
    backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-tablet));
  }
}

/*
 * Dense multi-line hosts solidify in tokens-glass-fill.ts (pathologist
 * report, evidence lists, recent-cases) so this base stays under 400 LOC.
 */

/* ============================================================
   Clear variant — permanently transparent, requires dim layer
   ============================================================
   Apple HIG: "Clear should only be used when these 3 conditions
   are met: element is on top of media-rich content; the content
   layer won't be negatively impacted by a dimming layer; the
   content sitting above it is bold and bright." The dim layer
   (.bao-surface-glass-clear-dim) must be applied to the
   text-bearing child container so text never sits directly on
   glass. */

/* Clear consumes its own --liquid-fill-clear, NOT --liquid-fill-control.
   Sharing that token inverted the ladder: tint is a transparency fraction
   (alpha = 1 - tint), so subtle's 0.08 rendered Clear at 92% alpha — the most
   OPAQUE material in the system, above regular (84%), strong (86%) and
   elevated (88%). Clear is applied over the capture preview and annotation
   canvas, exactly where the media must read through, so the inversion was
   most visible on the worst surfaces.
   Clear-glass dimming is --hig-clear-glass-dimming (Apple HIG Materials:
   35% dark layer on bright content). Never retune it via --liquid-fill-control. */
/* Only Clear retains image layers in supported engines; color shorthands
 * on the other variants reset blending to normal. */
.bao-surface-glass-clear {
  background-blend-mode: var(--glass-noise-blend, overlay);
  background-color: var(--glass-fill-bg);
  /*
   * The dimming layer Apple requires, composed into the Clear fill itself.
   * HIG: Clear "is permanently more transparent" and needs a dimming layer for
   * legibility. `.bao-surface-glass-clear-dim` was defined for that job and
   * shipped in ZERO partials — every Clear surface (annotation command bar,
   * canvas toolbars, 3D controls, capture preview overlay) put text straight
   * onto glass over arbitrary specimen media, so contrast was whatever the
   * slide happened to be.
   *
   * Applied as a background-image layer rather than a child element: these
   * hosts are flex containers whose children are the controls themselves, and
   * their ::before/::after already carry the specular ring and edge. A layered
   * paint needs no markup change and stacks under the content exactly as the
   * companion class would have. The a11y suppressions set `background:`
   * (shorthand), which resets background-image too, so reduced-transparency,
   * increased-contrast and forced-colors still drop it to a solid surface.
   */
  background-image: linear-gradient(
    0deg,
    var(--hig-clear-glass-dimming),
    var(--hig-clear-glass-dimming)
  );
  -webkit-backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  border-color: var(--liquid-border-clear);
  box-shadow: var(--shadow-glass-clear);
}

/* Dimming companion for Clear-variant glass — apply to text containers
   that overlay rich/vibrant content. No visible effect when the parent
   is not Clear glass; safe to attach on text hosts defensively. */
.bao-surface-glass-clear-dim {
  background: var(--hig-clear-glass-dimming);
  border-radius: inherit;
}


@container shell (max-width: 48rem) {
  .bao-surface-glass-clear {
    -webkit-backdrop-filter: blur(var(--liquid-blur-mobile)) saturate(var(--liquid-saturate-mobile));
    backdrop-filter: blur(var(--liquid-blur-mobile)) saturate(var(--liquid-saturate-mobile));
  }
}

@container shell (min-width: 48rem) and (max-width: 63.99rem) {
  .bao-surface-glass-clear {
    -webkit-backdrop-filter: blur(var(--liquid-blur-tablet)) saturate(var(--liquid-saturate-tablet));
    backdrop-filter: blur(var(--liquid-blur-tablet)) saturate(var(--liquid-saturate-tablet));
  }
}


/* ============================================================
   Refraction lens modifier (opt-in)
   ============================================================
   Apply .bao-surface-glass-lens alongside a glass variant on hero
   surfaces (command palette, dialog, sheet). The SVG filter
   #bao-liquid-lens must be present in the document — see
   apps/server/public/bao-liquid-lens.svg (compiled from tokens.bao
   color.liquid.liquid-lens-*). Browsers without backdrop-filter
   url() support keep the preceding plain blur declaration
   (Safari/Firefox per the backdrop-filter url() spec). */

@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-lens {
  -webkit-backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  }
}

/*
 * Density + lens: .bao-glass-large is 0,2,0 and was wiping url(#bao-liquid-lens)
 * from plain .bao-surface-glass-lens (0,1,0). Dialogs use large+elevated+lens
 * per design-canon — compound selector must keep refraction + nav blur.
 */
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-regular.bao-glass-large.bao-surface-glass-lens {
  -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  }
}
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-regular.bao-glass-small.bao-surface-glass-lens {
  -webkit-backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  backdrop-filter: blur(var(--liquid-blur-small)) saturate(var(--liquid-saturate-regular)) url(#bao-liquid-lens);
  }
}

/* ============================================================
   Strong variant — menus, sheets, form panels (design.pdf §3)
   ============================================================
   30-55% tint opacity, 20-32px blur. Use for transient surfaces that
   need stronger visual separation from content: dropdown menus,
   bottom sheets, form panels, and contextual overlays. */

.bao-surface-glass-strong {
  background: color-mix(
    in oklab,
    var(--bg-panel) calc(var(--liquid-fill-transient) * 100%),
    transparent
  );
  -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong));
  backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong));
  border-color: var(--liquid-border-regular);
  box-shadow: var(--shadow-glass-floating), var(--shadow-glass-inner);
}

/* ============================================================
   Modal variant — dialogs above scrim (design.pdf §3)
   ============================================================
   50-75% tint opacity, 24-40px blur. Use for blocking dialogs and
   modals that sit above a dimming scrim. Higher opacity ensures
   content beneath the scrim cannot bleed through.
   Panel alpha consumes --liquid-fill-blocking (light 90% / dark 95%
   opaque) so the fill ladder stays monotonic —
   control < clear < persistent < persistent-coarse < transient <
   blocking — and dark glass runs MORE opaque per §2.2.
   The 90% floor is load-bearing, not decorative: browser-structure-audit
   rejects any .modal-box whose computed alpha falls under 0.82
   (scripts/lib/browser-structure-audit-chrome.mjs), because an
   enterprise/medical dialog must never let the page read through when
   backdrop-filter is suppressed. Blur rides on top of that fill so the
   material still refracts wherever the filter is live. */

.bao-surface-glass-modal {
  background: color-mix(
    in oklab,
    var(--bg-panel) calc(var(--liquid-fill-blocking) * 100%),
    transparent
  );
  -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong));
  backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong));
  border-color: var(--liquid-border-regular);
  box-shadow: var(--shadow-glass-floating), var(--shadow-glass-inner);
}

/* Dialog.bao composes modal + lens. This compound owner follows the modal
   variant so the opt-in refraction survives the modal's blocking blur. */
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-modal.bao-surface-glass-lens {
  -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong)) url(#bao-liquid-lens);
  backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-strong)) url(#bao-liquid-lens);
  }
}

/* ============================================================
   Solid variant — accessibility/performance fallback (design.pdf §3)
   ============================================================
   Opaque surface with no blur. Use when backdrop-filter is unsupported,
   disabled via prefers-reduced-transparency, or when performance
   budget prohibits blur layers. Provides visual consistency without
   the glass effect. */

.bao-surface-glass-solid {
  background: var(--bg-panel);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-color: var(--border-base);
  box-shadow: var(--shadow-md);
}

/* Opaque fallback for modal-box with solid material. */
.modal-box.bg-base-100 {
  background-color: var(--color-base-100, var(--bg-panel));
}


/* ============================================================
   Hover-reveal — progressive disclosure for row/card actions
   ============================================================
   Fine-pointer devices: secondary actions fade in on host hover or any
   keyboard focus inside the host. Touch / no-hover devices: always
   visible (parity law — no hover-only affordances). */

@media (hover: hover) and (pointer: fine) {
  .bao-hover-reveal-host .bao-hover-reveal {
    opacity: 0;
    transition-property: opacity;
    transition-timing-function: var(--easing-standard);
    transition-duration: var(--duration-normal);
  }
  .bao-hover-reveal-host:hover .bao-hover-reveal,
  .bao-hover-reveal-host:focus-within .bao-hover-reveal {
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-lens {
    transition-duration: var(--reduced-motion-min-duration);
  }
  .bao-surface-glass-regular::before,
  .bao-surface-glass-clear::before,
  .bao-surface-glass-regular::after,
  .bao-surface-glass-clear::after {
    transition-duration: var(--reduced-motion-min-duration);
  }
  .bao-hover-reveal-host .bao-hover-reveal {
    transition-duration: var(--reduced-motion-min-duration);
  }
}


/* ============================================================
   Reactive lensing — hover/focus strengthens the material
   ============================================================
   Ported from the baobeep glass canon: pointer hover (or keyboard
   focus-within) deepens the tint and sharpens the border so
   interactive glass reads as touchable. Material tint/edge/shadow
   states are owned HERE; transforms and the shared transition list
   are owned by tokens-glass-motion.ts (one owner per concern — the
   transition channel list there excludes blur filters, so blur never
   churns; design.pdf §7.4). Hover is gated to fine pointers so touch
   devices never trap a stuck hover state (design.pdf §6). */
@media (hover: hover) and (pointer: fine) {
  /* design.pdf §6/§7.4: hover is a fine-pointer enhancement — tint, edge,
     and shadow carry the interactive strengthening; blur stays fixed.
     Enhanced with inner shadow for better depth perception (Apple HIG). */
  .bao-surface-glass-reactive:hover {
    border-color: var(--liquid-border-contrast);
    box-shadow:
      var(--shadow-glass-floating, var(--shadow-glass-elevated)),
      var(--shadow-glass-inner);
  }
}

/* Focus strengthening never depends on hover capability (design.pdf §6).
   Enhanced with inner shadow for better visual feedback (Apple HIG). */
.bao-surface-glass-reactive:focus-within {
  border-color: var(--liquid-border-contrast);
  box-shadow:
    var(--shadow-glass-floating, var(--shadow-glass-elevated)),
    var(--shadow-glass-inner);
}

/* State alpha belongs to the Regular material that consumes it. */
@media (hover: hover) and (pointer: fine) {
  .bao-surface-glass-reactive:where(.bao-surface-glass-regular):hover {
    --liquid-material-active-alpha: var(--liquid-fill-transient);
  }
}
.bao-surface-glass-reactive:where(.bao-surface-glass-regular):focus-within {
  --liquid-material-active-alpha: var(--liquid-fill-transient);
}

/* Non-Regular variants retain their own background composition. */
@media (hover: hover) and (pointer: fine) {
  .bao-surface-glass-reactive:where(:not(.bao-surface-glass-regular)):hover {
    background: color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-transient) * 100%), transparent);
  }
}
.bao-surface-glass-reactive:where(:not(.bao-surface-glass-regular)):focus-within {
  background: color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-transient) * 100%), transparent);
}

/* ============================================================
   Disabled glass surfaces — reduced chroma/elevation (design.pdf §6/§2.10)
   ============================================================
   Disabled glass keeps text legible by dropping elevation and chroma
   instead of crushing opacity. Blur reduces to subtle, border fades,
   shadows flatten, and interactive states are suppressed.
   design.pdf §6: "disabled keeps the label readable — drop elevation/chroma
   instead of crushing text via opacity" */
.bao-surface-glass-regular:disabled,
.bao-surface-glass-regular[aria-disabled="true"],
.bao-surface-glass-clear:disabled,
.bao-surface-glass-clear[aria-disabled="true"],
.bao-surface-glass-strong:disabled,
.bao-surface-glass-strong[aria-disabled="true"],
.bao-surface-glass-modal:disabled,
.bao-surface-glass-modal[aria-disabled="true"] {
  /* Reduce blur to subtle level — maintains glass identity without visual weight */
  -webkit-backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  /* Fade border to base-300 — reduces chroma without disappearing */
  border-color: var(--color-base-300);
  /* Flatten shadows — remove depth cues for non-interactive state */
  box-shadow: none;
  /* Suppress pointer events — no hover/focus states on disabled surfaces */
  pointer-events: none;
  /* Maintain text legibility via color-mix instead of opacity reduction */
  color: color-mix(in oklab, var(--color-base-content) 60%, var(--color-base-200));
}

/* Suppress hover/focus on disabled glass surfaces */
.bao-surface-glass-regular:disabled:hover,
.bao-surface-glass-regular[aria-disabled="true"]:hover,
.bao-surface-glass-regular:disabled:focus-within,
.bao-surface-glass-regular[aria-disabled="true"]:focus-within,
.bao-surface-glass-clear:disabled:hover,
.bao-surface-glass-clear[aria-disabled="true"]:hover,
.bao-surface-glass-clear:disabled:focus-within,
.bao-surface-glass-clear[aria-disabled="true"]:focus-within,
.bao-surface-glass-strong:disabled:hover,
.bao-surface-glass-strong[aria-disabled="true"]:hover,
.bao-surface-glass-strong:disabled:focus-within,
.bao-surface-glass-strong[aria-disabled="true"]:focus-within,
.bao-surface-glass-modal:disabled:hover,
.bao-surface-glass-modal[aria-disabled="true"]:hover,
.bao-surface-glass-modal:disabled:focus-within,
.bao-surface-glass-modal[aria-disabled="true"]:focus-within {
  /* Inherit disabled state — no visual change on interaction */
  -webkit-backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  backdrop-filter: blur(var(--liquid-blur-clear)) saturate(var(--liquid-saturate-clear));
  border-color: var(--color-base-300);
  box-shadow: none;
}

/* ============================================================
   Loading glass surfaces — skeleton shimmer overlay (design.pdf §2.10)
   ============================================================
   Loading state keeps each variant's blur and adds a skeleton shimmer
   overlay. Nav blur is already the thickest step, so restating regular
   blur thinned strong and modal. The shimmer is the loading signal. */
.bao-surface-glass-regular[data-state="loading"],
.bao-surface-glass-clear[data-state="loading"],
.bao-surface-glass-strong[data-state="loading"],
.bao-surface-glass-modal[data-state="loading"] {
  /* Strengthen border for better definition */
  border-color: var(--color-base-300);
  /* Add skeleton shimmer overlay via ::after pseudo-element */
  position: relative;
  overflow: hidden;
}

.bao-surface-glass-regular[data-state="loading"]::after,
.bao-surface-glass-clear[data-state="loading"]::after,
.bao-surface-glass-strong[data-state="loading"]::after,
.bao-surface-glass-modal[data-state="loading"]::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: linear-gradient(
    90deg,
    transparent 25%,
    color-mix(in oklab, var(--bg-surface-hover, var(--color-base-300)) 40%, transparent) 50%,
    transparent 75%
  );
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: bao-skeleton-sweep var(--duration-skeleton) var(--easing-standard) infinite;
  pointer-events: none;
  z-index: var(--z-local, 1);
}

/* ============================================================
   Error glass surfaces — visual error indicator (design.pdf §2.10)
   ============================================================
   Error state strengthens the border with error color and adds a
   subtle error indicator. Glass maintains its blur/shadow depth
   but the border shifts to error color to signal failure state. */
.bao-surface-glass-regular[data-state="error"],
.bao-surface-glass-clear[data-state="error"],
.bao-surface-glass-strong[data-state="error"],
.bao-surface-glass-modal[data-state="error"] {
  /* Strengthen border with error color — clear visual signal */
  border-color: var(--color-error);
  border-width: 2px;
  /* Maintain glass depth — keep shadows intact */
  box-shadow:
    var(--shadow-glass-elevated, var(--shadow-md)),
    var(--shadow-glass-inner, 0 0 0 0);
}

/* ============================================================
   Glass-on-glass containment (design.pdf §4 / §10 / §14)
   ============================================================
   A backdrop-filter ancestor establishes a new backdrop root, so a
   nested glass surface (e.g. a dropdown panel inside the glass topbar)
   can never re-blur the page — it renders as raw transparency without
   blur, bleeding unblurred content through menu items. Contained
   surfaces inside glass therefore keep their border/shadow but paint
   as the canonical solid fill plate instead of a second material. */
.bao-surface-glass-regular .bao-surface-glass-regular,
.bao-surface-glass-regular .bao-surface-glass-clear,
.bao-surface-glass-regular .bao-surface-glass-strong,
.bao-surface-glass-regular .bao-surface-glass-modal,
.bao-surface-glass-clear .bao-surface-glass-regular,
.bao-surface-glass-clear .bao-surface-glass-clear,
.bao-surface-glass-clear .bao-surface-glass-strong,
.bao-surface-glass-clear .bao-surface-glass-modal,
.bao-surface-glass-strong .bao-surface-glass-regular,
.bao-surface-glass-strong .bao-surface-glass-clear,
.bao-surface-glass-strong .bao-surface-glass-strong,
.bao-surface-glass-strong .bao-surface-glass-modal,
.bao-surface-glass-modal .bao-surface-glass-regular,
.bao-surface-glass-modal .bao-surface-glass-clear,
.bao-surface-glass-modal .bao-surface-glass-strong,
.bao-surface-glass-modal .bao-surface-glass-modal {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background: var(--bg-panel);
}

/* ============================================================
   Touch target — minimum 44x44dp per Apple HIG
   ============================================================ */

.bao-touch-target {
  min-block-size: var(--touch-target-min);
  min-inline-size: var(--touch-target-min);
}

.input.bao-touch-target,
.select.bao-touch-target,
.file-input.bao-touch-target {
  min-height: var(--touch-target-min);
  min-width: var(--touch-target-min);
}

/*
 * Theme-swap checkbox target (shell theme toggle, app-shell.bao themeInput).
 * The input carries both names: `theme-controller` is the daisyUI canon
 * marker (design-canon components), `bao-theme-controller-target` the
 * geometry hook. The daisyUI swap input is visually replaced by its adjacent
 * icon slots, but its own geometry must still match the label's canonical
 * 44px floor so pointer, keyboard, and accessibility-tool interaction
 * address one control. The input is centred out of flow over the
 * (position: relative) swap label so it never competes with the icon slots
 * for layout; `grid-area: auto` releases daisyUI's `.swap > *` cell
 * placement, because an absolutely positioned grid child with a definite
 * cell resolves its insets against that icon-sized cell rather than the
 * label's padding box, which put the target 7px off-centre.
 *
 * Switching itself is runtime-owned (app-shell-theme.ts writes data-theme):
 * daisyUI's :has(input.theme-controller...) theme branches are stripped at
 * emit for WebView 101, so no served-sheet rule may depend on them existing.
 * Keyboard focus stays visible through the swap label's focus-within ring.
 */
.theme-controller.bao-theme-controller-target {
  grid-area: auto;
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  translate: -50% -50%;
  inline-size: var(--touch-target-min);
  block-size: var(--touch-target-min);
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  margin: 0;
  cursor: pointer;
  opacity: 0;
}

/*
 * A checkbox reaches the touch floor by growing, not by projecting a pseudo.
 *
 * This used to keep the box at its painted 24px and hang a 44x44 `::after`
 * around it. The pseudo renders — computed 44x44 at inset -11px — but it does
 * not extend the input's hit region: measured on /cases at 375x812 with
 * `pointer: coarse`, `elementFromPoint` 21px from the checkbox centre returned
 * the ancestor section, not the checkbox. So every table's row selector
 * carried `bao-touch-target`, satisfied every gate that checks for the class,
 * and offered a 24px target to a finger.
 *
 * Grown at every pointer, not only coarse ones. The first attempt gated this
 * on `(pointer: coarse)` to keep dense pointer-driven tables compact, and the
 * rendered-geometry gate refused it: it measures every control at desktop and
 * reported `input "Select all rows" 24.0x24.0` on /settings. The 44pt floor is
 * the contract that gate enforces, and a control that meets it only on some
 * input devices does not meet it.
 */
.checkbox.bao-touch-target {
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  /*
   * The tick keeps its old weight inside the bigger box. daisyUI paints the
   * mark into the content box, so growing the control alone scaled the mark
   * with it and a report form filled with 44px boxes and heavy ticks —
   * measured on /reports at 375px right after the growth landed. Padding the
   * difference restores the painted mark to its 1.5rem while the box, and the
   * hit area, stay at the floor.
   *
   * Growing the BOX is load-bearing, not a shortcut. A 24px box with the area
   * grown by an absolutely positioned ::after was tried and measured: the
   * pseudo computes as rendered (content:"", inset -11px, pointer-events
   * auto) and still never takes the hit inside a table row — elementFromPoint
   * 16px from centre returns the tr, at any z-index on either the pseudo or
   * the input. It DOES take the hit for a checkbox injected into a fixed,
   * high-z-index host, which is how that approach came to look verified.
   * Measure a real row before changing this.
   */
  padding: calc((var(--touch-target-min) - var(--checkbox-mark-size)) / 2);
  /*
   * The 44px box takes the touch; it must not also DRAW one. Left visible,
   * the border outlined the whole target and a phone cases card showed nine
   * 44pt rectangles that read as empty input fields rather than checkboxes —
   * which is the dense-table regression the mark size exists to avoid.
   * Transparent here, redrawn at mark size on ::after below.
   */
  border-color: transparent;
  /* Component shadows must not outline the invisible touch-size box. */
  box-shadow: none;
  position: relative;
}

/*
 * The visible control, at mark size, inside the touch-size box.
 *
 * ::after and not ::before: daisyUI paints the tick on ::before as a 22px
 * clip-path polygon rotated 45deg, so an outline declared there replaces the
 * checkmark — measured, it rendered as a single black wedge overflowing the
 * control. ::after is unused by the component and inherits the padding box,
 * so the same inset arithmetic that centres the tick centres this.
 *
 * pointer-events: none — the input keeps every hit; this is paint only.
 */
/*
 * The daisyUI size modifier decides the painted mark, not the hit box.
 *
 * The touch rule above grows every checkbox to the 44pt floor and paints the
 * visible control at `--checkbox-mark-size`, which was a single global 1.5rem.
 * That made `checkbox-sm` inert: measured on /evidence, a row selector marked
 * `checkbox checkbox-sm bao-touch-target` painted the same 24px mark as an
 * unmodified checkbox, so the modifier every dense table carries changed
 * nothing and the tables it was meant to compact rendered at the default size.
 *
 * The size comes from daisyUI's own `--size-selector` — the variable its
 * `.checkbox-sm` rule multiplies by 5, against 6 for the base control — so the
 * mark tracks the component's scale instead of restating a pixel value. The
 * 44pt box, and the hit region measured through it, are untouched.
 */
.checkbox-sm.bao-touch-target {
  --checkbox-mark-size: calc(var(--size-selector, 0.25rem) * 5);
}

.checkbox.bao-touch-target::after {
  content: "";
  position: absolute;
  inset: calc((100% - var(--checkbox-mark-size)) / 2);
  /*
   * The boundary is the only thing that identifies an unchecked checkbox, so
   * it carries the shared control token rather than a local alpha. At
   * base-content 20% over base-100 it measured 1.53:1 against the surface it
   * sits on — WCAG 2.2 SC 1.4.11 asks 3:1 of a user-interface component
   * boundary, and the sibling radio was already at 4.64:1, so the two
   * selection controls disagreed about how visible a selection control is.
   */
  border: 1px solid var(--border-control, var(--color-base-300));
  /* Inherited from the .checkbox this pseudo belongs to — see the cap there. */
  border-radius: var(--checkbox-mark-radius, var(--radius-xs, 0.25rem));
  pointer-events: none;
}

/* Gated hover utilities, scrim SSOT, and readable-disabled live in
   tokens-glass-hover-scrim.ts (400-LOC monolith gate). */


}
@layer bao-tokens {

/* ============================================================
   Glass control — baobeep nested chrome (no glass-on-glass)
   ============================================================
   Toolbar / workflow controls nested inside a glass shell use a
   vibrancy fill without a second backdrop-filter layer. Tokens from
   resources/bao/tokens/tokens.bao (color.glass + color.liquid). */

.bao-glass-control {
  min-height: var(--touch-target-min, 2.75rem);
  min-width: var(--touch-target-min, 2.75rem);
  background-color: var(--glass-fill-bg);
  border-color: var(--liquid-border-clear);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* iOS and iPadOS zoom the whole viewport whenever a focused form control
   computes under 16px, and this product ships into WKWebView through the
   Tauri mobile shell. daisyUI sizes -sm at 0.875rem and -xs smaller still,
   so the badge, PIN, search and settings fields all yanked the layout out
   from under the operator the moment the keyboard opened. Coarse pointer
   rather than viewport width: an iPad at desktop width zooms identically,
   and a narrow desktop window does not. Doubled class selectors outrank
   daisyUI's single-class sizing on specificity, so the floor holds on
   specificity alone — no priority override, no dependence on load order. */
@media (pointer: coarse) {
  .bao-table-inline-editor,
  .input.input,
  .select.select,
  .textarea.textarea,
  .file-input.file-input,
  .input.input-xs,
  .input.input-sm,
  .select.select-xs,
  .select.select-sm,
  .textarea.textarea-xs,
  .textarea.textarea-sm,
  .file-input.file-input-xs,
  .file-input.file-input-sm {
    font-size: var(--text-base);
  }
}

@media (hover: hover) and (pointer: fine) {
  .bao-glass-control:hover {
    background-color: color-mix(
      in oklab,
      var(--color-primary) calc(var(--liquid-fill-control) * 100%),
      var(--glass-fill-bg)
    );
    border-color: var(--liquid-border-regular);
    box-shadow: inset 0 1px 0 var(--glass-highlight-soft);
  }
}
.bao-glass-control:focus-visible {
  background-color: color-mix(
    in oklab,
    var(--color-primary) calc(var(--liquid-fill-control) * 100%),
    var(--glass-fill-bg)
  );
  border-color: var(--liquid-border-regular);
  box-shadow: inset 0 1px 0 var(--glass-highlight-soft);
  outline: var(--focus-ring-width) solid var(--color-primary, currentColor);
  outline-offset: var(--focus-ring-offset);
}

/* One dimension control morphs from a flat plane to a spatial volume. */
.bao-dimension-toggle {
  color: var(--text-primary);
}
.bao-dimension-toggle.swap-active {
  color: var(--color-primary);
  background-color: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  border-color: var(--liquid-border-regular);
}
@media (prefers-reduced-motion: reduce) {
  .bao-dimension-toggle .swap-on,
  .bao-dimension-toggle .swap-off {
    transition: none;
  }
}

/* Nested soft buttons on glass shells: auto glass-control (no second frost). */
.bao-surface-glass-regular .btn-soft.bao-toolbar-action,
.bao-surface-glass-regular .btn-soft:not(.btn-primary):not(.btn-error),
.bao-surface-glass-clear .btn-soft.bao-toolbar-action {
  background-color: var(--glass-fill-bg);
  border-color: var(--liquid-border-clear);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* A popover panel's display belongs to its open state, never to a utility
   class in markup. Tailwind's display utilities sit directly in
   @layer utilities, while daisyUI's closed-popover display:none sits in a
   NESTED sublayer of it, and a rule outside a nested sublayer wins over one
   inside it whatever the specificity. Two panels carried the flex utility and
   so stayed laid out while closed: invisible at opacity 0, yet hit-testing
   over the page beneath them and focusable by keyboard. Declaring the layout
   on the open state keeps a closed panel out of layout entirely and gives an
   open one the flex row its wrap and alignment utilities assume. */
[data-dropdown-panel][popover]:popover-open {
  display: flex;
}

/* Scroll-edge: sticky glass topbar gains separation as content scrolls under. */
.bao-shell-topbar.bao-surface-glass-regular {
  box-shadow:
    var(--shadow-glass-elevated),
    0 1px 0 0 var(--liquid-border-regular);
}

/* Scrolled state (data-scroll-edge from app-shell-glass.ts): deeper, broader
   shadow + stronger bottom edge while content passes beneath using the canonical scroll-edge state.
   Blur and --liquid-saturate-strong stay on the gated nav owner. This rule is shadow only. */
.bao-shell-topbar.bao-surface-glass-regular[data-scroll-edge="true"] {
  box-shadow:
    var(--shadow-glass-floating),
    0 1px 0 0 var(--liquid-border-contrast);
}

/* Page content column: reclaim vertical chrome waste from the canonical density tokens. */
.bao-page-track {
  padding-block: var(--space-micro, 0.25rem);
  padding-inline: min(var(--space-inline, 0.5rem), 5%);
  max-width: 100%;
}
.bao-page-header + [data-case-journey-host],
.bao-page-header + section[data-case-journey-host] {
  margin-top: 0;
}

/* Nested grid/flex hosts must not invent columns — fill the panel cell. */
.bao-grid-reactive-panels > * {
  min-width: 0;
  min-height: 0;
}
/* Widget projection: a lone card/primitive fills its panel cell. Stacked
   panel content (e.g. FilterBar above a list section) must NOT inherit the
   fill — percentage heights inside the auto-height panel inflate the first
   child and strand its controls at the bottom of a blank band. */
.bao-grid-reactive-panels > * > .card:only-child,
.bao-grid-reactive-panels > * > [data-dashboard-widget]:only-child,
.bao-grid-reactive-panels > * > [data-primitive]:only-child {
  height: var(--bao-panel-height, 100%);
  min-height: 0;
}

/* ============================================================
   Composite chrome (LAW2) — one class replaces ≥8-token utility clones
   ============================================================ */

/* Empty / error / denied / offline host stack (page state surfaces).

   No :not([hidden]) guard and no [hidden] counter-rule: the global
   [hidden]:not([hidden="until-found"]) owner in tokens-daisyui-emission
   outranks this (0,1,0) display, so the attribute means what it says here
   without this block restating it. */
.bao-state-stack,
[data-primitive="EmptyState"],
[data-primitive="ErrorState"],
[data-primitive="DeniedState"] {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-micro, 0.25rem);
  text-align: center;
  padding-block: var(--space-section);
  padding-inline: var(--space-section);
}

/* Dropdown list geometry composes with both popover panels and nested lists.
   Native popover state owns panel display; panel tokens own the only inset. */
.bao-menu-list {
  flex-direction: column;
  flex-wrap: nowrap;
  flex: 1 1 auto;
  gap: var(--space-micro);
  min-inline-size: 0;
}
.bao-menu-list:not([popover]) {
  display: flex;
}
.bao-menu-list > * {
  z-index: var(--z-raised-high);
}

/* Menu items own layout and state paint independently of daisyUI list rules. */
.bao-menu-item {
  display: flex;
  flex-wrap: wrap;
  width: 100%;
  align-items: center;
  justify-content: flex-start;
  text-align: start;
  gap: var(--space-inline);
  border-radius: var(--radius-field);
  padding-inline: var(--space-section);
  padding-block: var(--space-micro);
  cursor: pointer;
  min-width: 0;
}

.bao-menu-label {
  flex: 1 1 0;
}

.bao-menu-item-hint {
  flex-basis: 100%;
}

.bao-menu-item:disabled,
.bao-menu-item[aria-disabled="true"] {
  color: var(--text-secondary);
  cursor: not-allowed;
  pointer-events: none;
}

.bao-menu-item:not(:disabled):not([aria-disabled="true"]):focus-visible {
  background-color: var(--bg-surface-hover);
  outline: var(--focus-ring-width) solid var(--color-primary);
  outline-offset: var(--focus-ring-offset-tight);
}
:is(.bao-surface-glass-regular, .bao-surface-glass-strong, .bao-surface-glass-modal, .bao-surface-glass-clear) .bao-menu-item:not(:disabled):not([aria-disabled="true"]):focus-visible {
  background-color: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  outline: var(--focus-ring-width) solid var(--color-primary);
  outline-offset: var(--focus-ring-offset-tight);
}

@media (hover: hover) and (pointer: fine) {
  .bao-menu-item:not(:disabled):not([aria-disabled="true"]):not(:focus-visible):hover {
    background-color: var(--bg-surface-hover);
  }
}
@media (hover: hover) and (pointer: fine) {
  :is(.bao-surface-glass-regular, .bao-surface-glass-strong, .bao-surface-glass-modal, .bao-surface-glass-clear) .bao-menu-item:not(:disabled):not([aria-disabled="true"]):not(:focus-visible):hover {
    background-color: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  }
}

/* Page header chrome edge (border + density) — layout is grid SSOT above. */
.bao-page-header {
  flex: 0 0 auto;
  border-block-end: 1px solid var(--liquid-border-regular);
  padding-block-end: var(--space-micro, 0.25rem);
}

/* Header action cluster. */
.bao-page-header-actions {
  display: flex;
  min-width: 0;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2xs, 0.125rem);
  justify-content: flex-end;
}

.bao-action-inline > .fieldset {
  padding-block: 0;
}



/* Stat / data panel shell — card + metric host stack. */
.bao-stat-panel {
  position: relative;
  display: flex;
  min-width: 0;
  flex-direction: column;
  overflow-x: clip;
  background-color: var(--color-base-100, var(--bg-panel));
  scroll-margin-top: var(--space-section, 0.75rem);
}

.bao-stat-panel:focus-within {
  outline: none;
  box-shadow: 0 0 0 2px var(--accent-primary);
}

/* Form fieldset density for filter/search bars. */
.bao-field-stack {
  display: flex;
  min-width: 0;
  width: 100%;
  flex: none;
  flex-direction: column;
  gap: var(--space-micro, 0.25rem);
}

/* Plain fields take their outer spacing from the form, not inherited fieldset padding. */
.bao-form-field {
  padding-block: 0;
}

/* Explicit labels participate in their parent gap; they need no second margin. */
.fieldset-legend:not(legend) {
  padding-block: 0;
  margin-block: 0;
}

/* Native legends sit outside the flex gap; one spacing owner prevents doubled gaps. */
fieldset > legend.fieldset-legend,
.bao-field-stack > .fieldset-legend {
  padding-block: 0;
  margin-block-start: 0;
  margin-block-end: var(--space-micro);
}

@media (min-width: 40rem) {
  .bao-field-stack {
    flex: 1 1 auto;
  }
}

/* Trailing action cluster in filter bars / headers. */
.bao-action-end {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  min-inline-size: 0;
  max-inline-size: 100%;
  grid-column: 1 / -1;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-micro, 0.25rem);
  align-self: flex-end;
}

@media (max-width: 39.99rem) {
  .bao-action-end {
    width: 100%;
  }
}

/* Filter action spacing belongs to its semantic host, including runtime-created hosts. */
@media (min-width: 40rem) {
  [data-filter-actions] {
    margin-inline-start: auto;
  }
}

/* Dialog chrome header row. */
.bao-dialog-chrome {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-inline, 0.5rem);
  padding-inline: var(--space-section);
  padding-block: var(--space-micro, 0.25rem);
  border-block-end: 1px solid var(--color-base-300, var(--border-base));
}
.bao-dialog-chrome > [data-dialog-title-block] {
  min-width: 0;
  flex: 1 1 auto;
}
.bao-dialog-chrome > form {
  flex: 0 0 auto;
  width: fit-content;
  max-width: fit-content;
}
/*
 * Compact-only back control. Layered `md:hidden` loses to unlayered `.btn`
 * display, so this lives in the token layer with the header.
 */
@media (min-width: 48rem) {
  [data-capability-group-back].btn {
    display: none;
  }
}

/* Full-width control fill (select/input density). */
.bao-control-fill {
  width: 100%;
  min-width: 0;
  max-width: 100%;
  background-color: var(--color-base-100, var(--bg-panel));
  color: var(--color-base-content, var(--text-primary));
}

/* Sidebar nav item density chrome (gap/padding/radius). */
.bao-nav-item-chrome {
  gap: var(--space-inline, 0.5rem);
  border-radius: var(--radius-field, 0.75rem);
  padding-inline: var(--space-inline, 0.5rem);
  padding-block: var(--space-micro, 0.25rem);
}

.bao-nav-item-chrome:focus-visible {
  background-color: var(--color-base-200, var(--bg-surface));
}

/* Shell list / overflow menu row.

   The touch floor lives here rather than on a `bao-touch-target` in markup.
   Its sibling `.bao-menu-item` is paired with that class at every one of its
   call sites, but the 86 command-palette rows in the app shell and the 83 in
   the device shell are not — and the palette is the primary way to reach a
   page on a phone, so its rows computed to roughly 28pt against the 44pt
   minimum the canon declares (hig-canon.json `hitTargetMinPt`). A floor on the
   row class cannot be forgotten by the next caller the way a markup class can.

   The press and focus treatments are here for the same reason: the shared
   `:active` rules in tokens-glass-motion key off `bao-touch-target`, so
   without them a tap on a palette row produced no acknowledgement at all,
   and `.bao-hover-soft:hover` is correctly gated to fine pointers. */
.bao-shell-list-row {
  display: flex;
  width: 100%;
  min-width: 0;
  min-height: var(--touch-target-min, 2.75rem);
  align-items: center;
  gap: var(--space-inline, 0.5rem);
  border-radius: var(--radius-field, 0.75rem);
  padding-inline: var(--space-section);
  padding-block: var(--space-micro, 0.25rem);
  text-align: start;
}

.bao-shell-list-row:active,
.bao-shell-list-row:focus-visible {
  background-color: var(--color-base-300, var(--bg-surface));
}

/* Responsive trailing action stack (filter footers, form actions). */
.bao-action-end-stack {
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-inline, 0.5rem);
}

@media (max-width: 39.99rem) {
  .bao-action-end-stack {
    flex-direction: column;
    align-items: stretch;
  }

  /*
   * A stacked action already fills the row, so a label that cannot break runs
   * straight past the viewport instead of wrapping into it. daisyUI's .btn is
   * white-space: nowrap, which makes the control's min-content width the full
   * width of its label, and a stretched flex item cannot shrink below that.
   *
   * Measured on /licensing-admin at 390px with root font 200%: "Activate this
   * device online" rendered 459px wide inside a 276px stack and its right edge
   * reached 516px — off screen, unreachable, and a WCAG 1.4.4 failure, since
   * text must resize to 200% without loss of content or functionality.
   *
   * The label span needs no rule of its own: white-space inherits, so
   * releasing the control releases the text inside it. Scoped to this stack so
   * the editor toolbar's label-reveal, which collapses .bao-toolbar-label to a
   * zero max-inline-size, is untouched.
   *
   * The :not() chain is specificity, not filtering, and it is load-bearing.
   * A plain `.bao-action-end-stack .btn` is (0,2,0) and loses to two later
   * rules that buy weight the same way: `.btn:not([hidden]):not(.hidden)
   * :not(.bao-fab)` at (0,4,0) re-asserts nowrap, and
   * `.bao-touch-target:not([hidden]):not(.hidden)` at (0,3,0) re-asserts the
   * 2.75rem floor. Measured: with the plain selector the emitted rule reached
   * the browser, matched the control, and still lost — computed white-space
   * stayed nowrap and min-width stayed at the token. Carrying the same guards
   * plus the ancestor makes this (0,5,0), which is the smallest weight that
   * actually wins, and it keeps the hidden/fab exclusions those rules intend.
   *
   * white-space alone, deliberately. An earlier revision also set min-width: 0
   * to let the flex item shrink past its content, and that is unnecessary once
   * the text can break — min-content collapses to the longest word, which fits
   * the stack. It is also unsafe: min-width: 0 cancels the 2.75rem touch floor
   * that .bao-touch-target exists to guarantee, and a stack that is not being
   * stretched would then be free to render a control under 44pt.
   *
   * .bao-toolbar-action carries the same release because the same failure
   * reaches it outside any stack. Measured on /setup at 390px with root font
   * 200%: "Open full models page" rendered 359px wide inside a 292px section
   * and reached 408px. Icon-only toolbar buttons share that class and are
   * unaffected — white-space: normal permits a break, it does not force one,
   * and a control with no text has nothing to break.
   */
  .bao-action-end-stack .btn:not([hidden]):not(.hidden):not(.bao-fab),
  .btn.bao-toolbar-action:not([hidden]):not(.hidden):not(.bao-fab) {
    white-space: normal;
  }

  /*
   * A form label wraps on a phone rather than running off the edge. daisyUI
   * declares `.label { white-space: nowrap }` in its own layer, and the text
   * inside inherits it, so a long label cannot use the room its container has.
   *
   * Measured on /integrations at 390px: "Retry on failure" reached 395px with
   * WCAG text spacing applied — a 1.4.12 Text Spacing failure specifically,
   * since at 200% type alone the same row ends at 307px and fits. Letter and
   * word spacing are exactly what a nowrap label cannot absorb.
   *
   * No specificity guard is needed here, unlike the button rules above, and the
   * reason is layer ORDER rather than weight. daisyUI's `.label` lands in its
   * own `daisyui` layer; this sheet emits into `@layer bao-tokens`. Neither
   * name appears in the `@layer theme, base, components, utilities` statement,
   * so both are ordered by first appearance, and `bao-tokens.css` is linked
   * after `tailwind-daisyui.css` — which puts `bao-tokens` last. A later layer
   * wins whatever the selectors say, so a bare `.label` suffices where `.btn`
   * needed (0,5,0) against same-layer rivals.
   *
   * An earlier revision of this comment said the declaration was UNLAYERED and
   * won on that basis. That was wrong. Walking the emitted sheet's brace depth
   * puts this rule inside `@layer bao-tokens`, and the browser's own
   * matched-rule enumeration reports the same layer. The outcome is identical
   * either way, which is exactly why the wrong mechanism survived — the rule
   * worked, so nothing contradicted the explanation.
   *
   * Confined to the phone breakpoint, where wrapping is preferable to clipping.
   */
  .label {
    white-space: normal;
  }
}

/*
 * A disabled control is rendered inside a tooltip host, so the host — not the
 * control — is the flex item the stack stretches. Measured on /robot at 375px:
 * the host reached the full 317px while the button inside it stayed 119px
 * beside two 317px siblings. The host exists to carry the tooltip, so it
 * carries the stretch through to the one control it holds.
 */
/*
 * Inline action rows reflow instead of escaping their viewport.
 * hig-dynatype measured at 390px root font 400% with WCAG text spacing: the
 * class owned only child overrides, so the row held max-content width past
 * the phone viewport. Wrap beats clip at WCAG 1.4.10; min-inline-size keeps
 * every wrapped row shrinkable inside flex ancestors with min-w-0 chains.
 */
.bao-action-inline {
  display: flex;
  flex-wrap: wrap;
  min-inline-size: 0;
  max-inline-size: 100%;
}

@media (max-width: 39.99rem) {
  .bao-action-end-stack > .tooltip,
  .bao-action-inline > .tooltip {
    display: flex;
    width: 100%;
  }

  .bao-action-end-stack > .tooltip > .btn,
  .bao-action-inline > .tooltip > .btn {
    flex: 1 1 auto;
  }
}

/* Card action row at panel foot. */
.bao-card-actions {
  position: relative;
  z-index: var(--z-table-action, 20);
  margin-top: auto;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-micro, 0.25rem);
  padding-inline: var(--space-inline, 0.5rem);
  padding-bottom: var(--space-inline, 0.5rem);
  padding-top: 0;
  min-width: 0;
}

/* Compact bordered inline toolbar (widget tool strips). */
.bao-inline-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-micro, 0.25rem);
  border-radius: var(--radius-field, 0.75rem);
  border: 1px solid var(--liquid-border-regular);
  background-color: var(--color-base-100, var(--bg-panel));
  padding: var(--space-inline, 0.5rem);
  min-width: 0;
}

/* Shell topbar overflow menu. Geometry only; .bao-surface-glass-strong owns the material. */
.bao-shell-dropdown {
  z-index: var(--z-shell-topbar, 1250);
  border-radius: var(--radius-box, 1rem);
  padding: var(--space-micro, 0.25rem);
  width: var(--sidebar-expanded, 16rem);
  gap: var(--space-micro, 0.25rem);
}

/* Shared sampling container (Apple HIG Materials / Liquid Glass).
   One backdrop lives on the container. A nested material would sample
   that glass, so it keeps a solid fill and no second backdrop-filter.
   The account overlay is a sibling of the topbar in the canonical tree;
   it samples page content independently of persistent chrome. */
:is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-lens
),
:is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
  background-color: var(--bg-panel);
  background-image: none;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Account availability is semantic session data; source owns visibility. */
.bao-shell-account-control[data-shell-account-state="anonymous"] {
  display: none;
}

/* Collection filters share one unframed row; search takes flexible space and facets keep their intrinsic size. */
.bao-filter-search,
.bao-filter-bar-sticky > search {
  flex: 1 1 var(--grid-context-min);
  min-inline-size: 0;
  max-inline-size: 100%;
  margin: 0;
  padding: 0;
  border: 0;
}
.bao-filter-field {
  display: flex;
  flex: 0 1 auto;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-micro);
  min-inline-size: 0;
  max-inline-size: 100%;
}
.bao-filter-field > select {
  flex: 0 1 auto;
}

}
@layer bao-tokens {

@layer bao-tokens {
.bao-action-inline .input,
.bao-action-inline .select,
fieldset .input,
fieldset .select {
  min-inline-size: 0;
  max-inline-size: 100%;
}

dl.flex > div,
dl.flex > div > dt,
dl.flex > div > dd {
  min-inline-size: 0;
  max-inline-size: 100%;
}

dl.flex > div > dt,
dl.flex > div > dd {
  overflow-wrap: anywhere;
}

dl.flex > div {
  flex-wrap: wrap;
}

.list-row > *,
.toast,
.toast .alert,
.bao-context-badge,
.bao-context-badge > *,
.bao-ai-provenance-sticky,
.bao-ai-provenance-sticky dd,
.bao-filter-bar-sticky,
.bao-data-panel .flex > *,
.bao-filter-bar-sticky .flex > *,
.bao-editor-canvas .flex > *,
.mt-space-inline .flex > *,
.bao-composer-shell .flex > * {
  min-inline-size: 0;
  max-inline-size: 100%;
}

.list-row > *,
.toast .alert,
.bao-context-badge,
.bao-context-badge > *,
.bao-ai-provenance-sticky dd {
  overflow-wrap: anywhere;
}

.tooltip::before,
.tooltip::after {
  white-space: normal;
  overflow-wrap: anywhere;
  max-inline-size: 100vw;
}

/* Wrapping children may shrink without replacing their explicit width
   caps. Tabs and progress meters retain their own containment limits. */
.flex.flex-wrap > * {
  min-inline-size: 0;
}

.tabs-box .tab,
dd .progress {
  min-inline-size: 0;
  max-inline-size: 100%;
}

.tabs-box .tab {
  white-space: normal;
  overflow-wrap: anywhere;
}

/* A button in a wrapping row must release daisyUI's flex: 0 0 auto —
   the row wraps BETWEEN items, but a single item wider than the row
   still has to compress so its label can break. max-inline-size: 100%
   hard-caps the button to its row, so intrinsic label width can never
   push it past the viewport even while the row is still settling. */
.flex.flex-wrap > .btn {
  flex: 0 1 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
}

/* Scoped dynatype release: the models voice-actions panel host. Its action
   button is a nowrap flex row, so at root font 400% the toolbar label cannot
   fold under the glyph and the row escapes the viewport (measured /models
   "Voice command" span right edge 449px on a 390px viewport, audit:hig).
   Let the button wrap glyph and label into two lines inside the panel. */
[data-voice-actions-panel] .btn {
  flex-wrap: wrap;
}

/* Floating editor chrome must stay within the stage column, not the pannable
   canvas surface: 100cqw resolves against the editor-stage inline-size
   container (the canvas column), so the sticky context bar can never track
   the canvas' JS-driven width. The horizontal scroller keeps long context
   rows reachable inside the cap (measured /editor "Custody" dt right edge
   450px on a 390px viewport, audit:hig). */
.bao-editor-canvas .sticky {
  min-inline-size: 0;
  max-inline-size: 100cqw;
  overflow-x: auto;
  overscroll-behavior-x: contain;
}
/* Shared control captions and segmented navigation have one owner.
 * Icon shapes keep their names in the accessibility tree; labeled density
 * uses content width. Segments never split a destination into partial words. */
.bao-toolbar-label {
  display: inline-block;
  min-inline-size: 0;
  max-inline-size: 100%;
  white-space: normal;
  overflow-wrap: normal;
  word-break: normal;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
}
.bao-toolbar-action.btn-square:not([data-toolbar-density="labeled"] *) > .bao-toolbar-label,
.bao-toolbar-action.btn-circle:not([data-toolbar-density="labeled"] *) > .bao-toolbar-label {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}
[data-toolbar-density="labeled"] .bao-toolbar-action {
  inline-size: auto;
  block-size: auto;
  min-block-size: var(--touch-target-min);
  flex: 0 0 auto;
  padding-inline: var(--space-inline);
}
.bao-tablist-segmented {
  display: inline-grid;
  flex: 0 0 auto;
  min-block-size: calc(var(--touch-target-min) + 2 * var(--space-micro));
  inline-size: max-content;
  align-items: stretch;
  grid-auto-flow: column;
  grid-auto-columns: minmax(max-content, 1fr);
  gap: var(--space-micro);
  max-inline-size: 100%;
  padding: var(--space-micro);
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}
.bao-tab-segment {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-micro);
  min-inline-size: var(--touch-target-min);
  min-block-size: var(--touch-target-min);
  block-size: auto;
  padding: var(--space-micro) var(--space-inline);
  border: var(--border) solid transparent;
  border-radius: var(--radius-field);
  background: transparent;
  color: var(--color-base-content);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  white-space: nowrap;
  overflow-wrap: normal;
  word-break: normal;
  cursor: pointer;
  transition: color var(--duration-normal) var(--easing-standard), background-color var(--duration-normal) var(--easing-standard);
}
.bao-tab-segment:has(input[type="radio"]:checked),
.bao-tab-segment[aria-current="page"],
.bao-tab-segment[aria-selected="true"],
.bao-tab-segment[aria-pressed="true"] {
  color: var(--color-primary);
  background-color: var(--glass-fill-bg);
  border-color: var(--glass-control-border);
  font-weight: var(--font-weight-semibold);
  box-shadow: var(--shadow-sm);
}
.bao-tab-segment:disabled,
.bao-tab-segment[aria-disabled="true"],
.bao-tab-segment:has(input[type="radio"]:disabled) {
  opacity: var(--opacity-disabled);
  cursor: not-allowed;
}
.bao-tab-segment:has(input[type="radio"]:focus-visible),
.bao-tab-segment:focus-visible {
  outline: var(--border) solid var(--color-primary);
  outline-offset: var(--space-micro);
}
}

}
@layer bao-tokens {
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .btn.bao-glass-control:not([hidden]):not(.hidden) {
    background-color: var(--glass-control-fill);
    border-color: var(--liquid-border-clear);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

}
@layer bao-tokens {

/* Pathologist workflow current step — page SSOT via data-page + session-mode.
   Capture sets data-session-mode (acquire|annotate) from app-shell-session-mode. */
[data-page="capture"][data-session-mode="annotate"] [data-pathologist-workflow-step="annotate"],
[data-page="capture"][data-session-mode="acquire"] [data-pathologist-workflow-step="capture"],
[data-page="capture"]:not([data-session-mode]) [data-pathologist-workflow-step="capture"],
[data-page="ai-analysis"] [data-pathologist-workflow-step="ai-analysis"],
[data-page="evidence"] [data-pathologist-workflow-step="evidence"],
[data-page="reports"] [data-pathologist-workflow-step="reports"],
[data-page="cases"] [data-pathologist-workflow-step="cases"] {
  border-color: var(--liquid-border-regular);
  background-color: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  box-shadow: inset 0 0 0 1px var(--liquid-border-regular);
}

[data-page="capture"][data-session-mode="annotate"] [data-pathologist-workflow-step="annotate"] .badge,
[data-page="capture"][data-session-mode="acquire"] [data-pathologist-workflow-step="capture"] .badge,
[data-page="capture"]:not([data-session-mode]) [data-pathologist-workflow-step="capture"] .badge,
[data-page="ai-analysis"] [data-pathologist-workflow-step="ai-analysis"] .badge,
[data-page="evidence"] [data-pathologist-workflow-step="evidence"] .badge,
[data-page="reports"] [data-pathologist-workflow-step="reports"] .badge {
  background-color: var(--color-primary);
  color: var(--color-primary-content);
  border-color: transparent;
}

/*
 * Case-row next actions (join) — not a page content workflow panel.
 * Clinical path SSOT is shell sidebar order; row CTAs are contextual shortcuts.
 */
.bao-pathologist-journey {
  display: inline-flex;
  flex-wrap: nowrap;
  gap: 0;
  max-width: 100%;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  -webkit-overflow-scrolling: touch;
}

.bao-pathologist-journey .bao-toolbar-action.btn-square,
.bao-pathologist-journey .bao-toolbar-action {
  width: auto;
}

/*
 * Progressive path CTAs: icon-first on fine pointer; labels on hover/focus
 * (design.pdf hover-to-reveal). Touch keeps ≥44px targets with labels hidden
 * under compact width so the row does not steal case-card geometry.
 */
.bao-pathologist-journey .join-item.btn .text-2xs {
  display: inline-block;
  max-width: 4.5rem;
  margin-inline-start: var(--space-micro, 0.25rem);
  overflow: hidden;
  white-space: nowrap;
}
@media (hover: hover) and (pointer: fine) {
  .bao-pathologist-journey .join-item.btn .text-2xs {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
    max-width: 0;
    opacity: 0;
  }
  .bao-pathologist-journey .join-item.btn:hover .text-2xs,
.bao-pathologist-journey .join-item.btn:focus-visible .text-2xs {
    position: static;
    width: auto;
    height: auto;
    margin: 0;
    margin-inline-start: var(--space-micro, 0.25rem);
    clip: auto;
    max-width: 4.5rem;
    opacity: 1;
  }
}

.bao-table-responsive-cell .bao-pathologist-journey,
td .bao-pathologist-journey {
  justify-content: flex-end;
  max-width: min(100%, 28rem);
}
/* Phone density: keep ≥44px targets. Labels stay visible on coarse pointers
   (design.pdf: essentials must not depend on hover); fine-pointer hover rules
   above still densify desktop. */
@media (max-width: 47.99rem) {
  .bao-pathologist-journey .join-item.btn {
    min-width: var(--touch-target-min, 2.75rem);
    min-height: var(--touch-target-min, 2.75rem);
    padding-inline: var(--space-inline, 0.5rem);
  }
  @media (hover: hover) and (pointer: fine) {
    .bao-pathologist-journey .join-item.btn .text-2xs {
      display: none;
    }
  }
}

/* Slim case-journey host — solid in-flow strip (content plane, no glass).
   Placement belongs to the journey-summary layout module. */
[data-case-journey-host] {
  min-width: 0;
  margin-block: 0;
  padding-block: var(--space-2xs, 0.125rem);
  padding-inline: var(--space-micro, 0.25rem);
}
[data-case-journey-host] > h2 {
  display: none;
}
/* The continuation, case identity and optional workflow share one in-flow band. */
[data-case-journey] {
  min-width: 0;
  width: 100%;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-micro, 0.25rem) var(--space-section, 0.75rem);
}
[data-case-journey] > * {
  margin-block: 0;
}
[data-case-journey] > p {
  flex: 1 1 auto;
  min-width: min(8rem, 60vw);
  margin: 0;
  text-align: end;
}
/*
 * The empty-state sentence leads its action and keeps reading order aligned
 * with the document start.
 */
[data-case-journey][data-state="empty"] > p {
  text-align: start;
}
/*
 * Dense horizontal journey — re-implement daisyUI steps as a fixed 5-track
 * grid (WebView 101 / design.pdf density). Caps width so connectors never
 * leave huge voids on wide workbenches.
 */
[data-case-journey] .steps,
[data-case-journey] ul.steps,
[data-case-journey] ul[data-case-journey-steps] {
  display: grid;
  /* Auto column tracks — the rail carries however many steps the journey
     declares; a fixed count would silently clip added steps. */
  grid-auto-flow: column;
  grid-auto-columns: minmax(var(--touch-target-min), 1fr);
  width: 100%;
  max-width: min(100%, 40rem);
  margin-inline: 0;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  gap: var(--space-inline);
  padding-inline: var(--space-micro, 0.25rem);
  min-height: 3.5rem;
  align-items: start;
  justify-items: stretch;
}
/* Each measured step owns its complete readable label and native touch target. */
[data-case-journey] .step {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-2xs, 0.125rem);
  min-width: 0;
  max-width: 100%;
  min-height: 0;
  flex: unset;
  grid-template-columns: unset;
  grid-template-rows: unset;
  justify-items: center;
  font-size: var(--text-2xs, 0.6875rem);
  line-height: 1.2;
  padding-inline: var(--space-2xs, 0.125rem);
  padding-block-start: 0;
  text-align: center;
}
/* Kill daisyUI step min-width / row geometry that forces sprawl. State glyphs
   come from the fragment's data-content (done "✓", current "●", else empty) —
   never a step number (workflow labels stay unnumbered). */
[data-case-journey] .step::before {
  content: attr(data-content);
  display: grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  margin-inline: auto;
  border-radius: var(--radius-full);
  background: var(--color-base-200, var(--bg-surface));
  color: var(--color-base-content, inherit);
  font-size: var(--text-2xs, 0.6875rem);
  font-weight: 600;
  line-height: 1;
  z-index: var(--z-local, 1);
}
[data-case-journey] .step.step-primary::before,
[data-case-journey] .step[data-journey-state="current"]::before,
[data-case-journey] .step[data-journey-state="done"]::before {
  background: var(--color-primary, var(--accent-primary));
  color: var(--color-primary-content, var(--accent-primary-content));
}
/* Connector between equal tracks — half of each cell, never full viewport. */
[data-case-journey] .step::after {
  content: "";
  position: absolute;
  top: 0.85rem;
  inset-inline-start: calc(50% + 0.9rem);
  inset-inline-end: calc(-50% + 0.9rem);
  height: 2px;
  background: var(--liquid-border-regular);
  z-index: var(--z-base, 0);
}
/* Dark-mode contrast: --color-base-300 at 80% transparent is barely
   distinguishable from --color-base-100 (both are near-black blues in the
   capture-dx-dark palette). Lift the alpha so the upcoming-path connector
   stays readable as "not-yet" without overdrawing the "done" path. */
[data-theme="capture-dx-dark"] [data-case-journey] .step::after,
[data-theme="capture-dx-dark"] [data-case-journey] .step:not([data-journey-state="done"])::after {
  background: var(--liquid-border-regular);
}
[data-theme="capture-dx-dark"] [data-case-journey] .step[data-journey-state="done"]::after {
  background: var(--color-primary);
}
[data-case-journey] .step:last-child::after {
  display: none;
}
/* Completed spans read as progress: the connector leaving a done step fills
   with the primary accent instead of the idle border tone. */
[data-case-journey] .step[data-journey-state="done"]::after {
  background: var(--color-primary);
}
[data-case-journey] .step .bao-journey-step-label {
  display: flex;
  align-items: center;
  justify-content: center;
  min-inline-size: 0;
  max-inline-size: 100%;
  min-block-size: var(--touch-target-min);
  white-space: normal;
  overflow-wrap: anywhere;
  font-size: inherit;
  line-height: var(--text-sm--line-height);
  padding: var(--space-inline) var(--space-micro);
  background: transparent;
  border: 0;
  box-shadow: none;
}
.bao-journey-capsule {
  display: flex;
  flex: 0 1 auto;
  min-width: var(--touch-target-min);
  max-width: 100%;
  align-items: center;
  gap: var(--space-inline, 0.5rem);
  min-height: var(--touch-target-min, 2.75rem);
  padding-inline: var(--space-inline, 0.5rem);
  border-radius: var(--radius-field, 0.75rem);
  border: 0;
  background: transparent;
}
/* Accession is readable context, visually distinct from the continuation action. */
.bao-journey-compact-hint {
  display: block;
  min-width: 0;
  max-width: 100%;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--text-secondary);
  white-space: normal;
  overflow-wrap: anywhere;
}

.bao-journey-compact-hint:empty {
  display: none;
}
/* Native disclosure state owns rail visibility at every container width. */
[data-case-journey-details]:not([open]) > [data-case-journey-steps] {
  display: none;
}
[data-case-journey-details][open] {
  flex-basis: 100%;
}
[data-case-journey-details][open] .bao-journey-disclosure-icon {
  transform: rotate(180deg);
}



  /* Clinical navigation stays in document flow. A sticky progress rail covered the first action row while scrolling. */
  [data-case-journey-host] {
    position: relative;
    top: auto;
    z-index: auto;
  }

  /* Context and commands share one in-flow band; DOM order matches focus order. */
  [data-page-context-bar] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-inline) var(--space-section);
    min-inline-size: 0;
  }
  [data-page-context-bar] > [data-case-journey-host] {
    flex: 1 1 var(--grid-context-min);
    min-inline-size: 0;
    padding: 0;
  }
  [data-page-context-bar] > [data-primitive="PageHeader"]:not(.sr-only) {
    flex: 0 1 auto;
    grid-template-columns: minmax(0, 1fr);
    min-inline-size: 0;
    inline-size: auto;
    margin-block: 0;
    padding-block: 0;
    border-block: 0;
    align-self: flex-start;
  }
  [data-case-journey][data-case-journey-empty] {
    justify-content: flex-start;
  }
  [data-case-journey][data-case-journey-empty] > p {
    flex: 0 1 auto;
    min-inline-size: 0;
  }



[data-case-journey] [data-case-journey-steps][hidden],
[data-case-journey] [data-case-journey-hint-row][hidden] {
  display: none;
}

}
@layer bao-tokens {
/* Native dialog defaults defeat the Sheet flex track and allow focus to scroll the fullscreen wrapper. The body owns scrolling; clip also prevents programmatic wrapper scrolling. */
dialog[data-primitive="Sheet"][open] {
  display: flex;
  overflow: clip;
}
dialog[data-primitive="Sheet"] > [data-dialog-dismiss] { z-index: var(--z-base, 0); }
/* Panel owns stacking and paint clipping; its body owns scrolling. */
dialog[data-primitive="Sheet"] > .bao-sheet-panel {
  z-index: var(--z-local, 1);
  overflow: clip;
}

/* A compact bottom Sheet becomes a trailing context panel when its native fields fit. */
.bao-sheet-panel-bottom {
  align-self: flex-end;
}
@media (max-width: 39.99rem) {
  .bao-sheet-panel-bottom {
    inline-size: 100%;
    max-block-size: min(var(--sheet-panel-max-height), var(--vv-height, 100dvh));
    padding-block-end: env(safe-area-inset-bottom, 0px);
    border-block-start-width: 1px;
    border-start-start-radius: var(--radius-box);
    border-start-end-radius: var(--radius-box);
  }
}
@media (min-width: 40rem) {
  .bao-sheet-panel-bottom {
    inline-size: min(100%, var(--sheet-panel-width));
    max-inline-size: min(100%, var(--sheet-panel-max-width));
    block-size: 100%;
    max-block-size: var(--vv-height, 100dvh);
    border-inline-start-width: 1px;
    border-start-start-radius: var(--radius-box);
    border-end-start-radius: var(--radius-box);
  }
}
.bao-sheet-body {
  min-inline-size: 0;
  overscroll-behavior-block: contain;
}
/* Sheet header band — leading control / title / trailing slot. The track template lives here (the layout SSOT) instead of a literal grid-cols-N utility so the band can flex at the phone-narrow floor: below 40rem the title takes the remaining inline space and truncates, above it the title recenters between equal side tracks. */
.bao-sheet-header-band {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--space-inline);
  padding-inline: var(--space-page);
  padding-block: var(--space-section);
  flex: 0 0 auto;
}
@media (min-width: 40rem) {
  .bao-sheet-header-band {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  }
}

}
@layer bao-tokens {

/* Shared motion consumes the canonical tokens.bao timing scale. */
.bao-motion-transition-colors {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
}
.bao-motion-transition-opacity {
  transition-property: opacity;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
}
.bao-motion-transition {
  transition-property: color, background-color, border-color, text-decoration-color, fill, stroke, opacity, box-shadow, transform;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
}

/* Material changes keep blur fixed; controls share one acknowledgment cadence. */
.bao-surface-glass-reactive {
  transition-property: background-color, border-color;
  transition-duration: var(--duration-normal);
  transition-timing-function: var(--easing-standard);
}
button.bao-touch-target,
a.bao-touch-target,
summary.bao-touch-target,
label.bao-touch-target[for],
.btn:not([hidden]):not(.hidden),
.bao-nav-item,
.bao-surface-glass-reactive:where(button, a, [role="button"]),
.bao-surface-glass-regular:where(button, a, [role="button"]),
.bao-surface-glass-strong:where(button, a, [role="button"]),
.bao-surface-glass-clear:where(button, a, [role="button"]) {
  transition-property: transform, background-color, border-color, color, box-shadow;
  transition-duration: var(--duration-normal);
  transition-timing-function: var(--easing-standard);
}
.bao-toolbar-action {
  transition-property: transform, background-color, border-color, color, box-shadow, max-width, padding;
  transition-duration: var(--duration-normal);
  transition-timing-function: var(--easing-standard);
}

/* Replaced context chips retain a stable position during live updates. */
.bao-context-card,
[data-capture-context],
[data-chat-context-card],
.bao-shell-context-chip {
  transition-property: color, background-color, border-color, box-shadow;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-fast);
  transform: none;
}

/* Hover indicates a control, without lifting ordinary content surfaces. */
@media (hover: hover) and (pointer: fine) {
  .bao-surface-glass-reactive:where(button, a, [role="button"]):hover,
  .bao-nav-item:hover,
  .btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):hover {
    transform: translateY(-1px);
  }
}

/* Press acknowledgment uses the same short token at every available size. */
button.bao-touch-target:active:not(:disabled):not([aria-disabled="true"]),
a.bao-touch-target:active:not([aria-disabled="true"]),
summary.bao-touch-target:active,
label.bao-touch-target[for]:active,
.bao-surface-glass-reactive:where(button, a, [role="button"]):active,
.bao-surface-glass-regular:where(button, a, [role="button"]):active,
.bao-surface-glass-strong:where(button, a, [role="button"]):active,
.bao-surface-glass-clear:where(button, a, [role="button"]):active,
.btn.bao-touch-target:active:not(:disabled),
.btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):active,
.bao-nav-item:active {
  transform: scale(0.985);
  transition-duration: var(--duration-press);
}

/* Equal-specificity OS overrides beat the corresponding active/hover rules. */
@media (prefers-reduced-motion: reduce) {
  button.bao-touch-target:active:not(:disabled):not([aria-disabled="true"]),
  a.bao-touch-target:active:not([aria-disabled="true"]),
  summary.bao-touch-target:active,
  label.bao-touch-target[for]:active,
  .bao-surface-glass-reactive:where(button, a, [role="button"]):hover,
  .bao-surface-glass-reactive:where(button, a, [role="button"]):active,
  .btn.bao-touch-target:active:not(:disabled),
  .btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):hover,
  .btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):active {
    transform: none;
  }
  .bao-nav-item:hover,
  .bao-nav-item:active {
    transform: scale(1);
  }
}

/* The product preference reaches the same controls without an OS media event. */
html[data-reduced-motion="true"] button.bao-touch-target:active,
html[data-reduced-motion="true"] a.bao-touch-target:active,
html[data-reduced-motion="true"] summary.bao-touch-target:active,
html[data-reduced-motion="true"] label.bao-touch-target[for]:active,
html[data-reduced-motion="true"] .bao-nav-item:hover,
html[data-reduced-motion="true"] .bao-nav-item:active,
html[data-reduced-motion="true"] .bao-surface-glass-reactive:where(button, a, [role="button"]):hover,
html[data-reduced-motion="true"] .bao-surface-glass-reactive:where(button, a, [role="button"]):active,
html[data-reduced-motion="true"] .btn.bao-touch-target:active:not(:disabled),
html[data-reduced-motion="true"] .btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):hover,
html[data-reduced-motion="true"] .btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]):active {
  transform: scale(1);
}

/* Touch feedback remains available without hover-only movement. */
@media (hover: none), (pointer: coarse) {
  .bao-surface-glass-reactive:where(button, a, [role="button"]):hover,
  .bao-nav-item:hover {
    transform: scale(1);
    background-color: transparent;
  }
}

/* Recording and loading share declared pulse utilities and static reduced motion. */
@keyframes bao-pulse-scale {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(var(--pulse-scale-peak)); }
}
@keyframes bao-pulse-alpha {
  0%, 100% { opacity: 1; }
  50% { opacity: var(--pulse-alpha-floor); }
}
.bao-pulse {
  transform-origin: center;
}
.bao-pulse-scale {
  animation: bao-pulse-scale var(--duration-pulse) var(--easing-standard) infinite;
}
.bao-pulse-alpha {
  animation: bao-pulse-alpha var(--duration-pulse-alpha) var(--easing-standard) infinite;
}
.bao-pulse-scale.bao-pulse-alpha {
  animation:
    bao-pulse-scale var(--duration-pulse) var(--easing-standard) infinite,
    bao-pulse-alpha var(--duration-pulse-alpha) var(--easing-standard) infinite;
}
@media (prefers-reduced-motion: reduce) {
  .bao-pulse,
  .bao-pulse-scale,
  .bao-pulse-alpha {
    animation: none;
    opacity: 1;
    will-change: auto;
  }
}
html[data-reduced-motion="true"] *,
html[data-reduced-motion="true"] *::before,
html[data-reduced-motion="true"] *::after {
  animation-duration: var(--reduced-motion-min-duration);
  animation-iteration-count: 1;
  animation-delay: var(--duration-instant);
  transition-delay: var(--duration-instant);
  transition-duration: var(--reduced-motion-min-duration);
  scroll-behavior: auto;
}
html[data-reduced-motion="true"] .bao-pulse,
html[data-reduced-motion="true"] .bao-pulse-scale,
html[data-reduced-motion="true"] .bao-pulse-alpha,
html[data-reduced-motion="true"] [data-motion-pulse] {
  animation: none;
  opacity: 1;
}

/* Sticky action cells stay hittable and show depth only while content scrolls. */
.bao-table-pinned-action,
td.bao-table-pinned-action,
th.bao-table-pinned-action {
  overflow: visible;
}
.bao-table-pinned-divider {
  .bao-table-pinned-scrolls:not(.bao-table-pinned-fit-unstuck) & {
    box-shadow: -0.5rem 0 0.5rem -0.5rem color-mix(in oklab, var(--color-base-content) 12%, transparent);
  }
}
@container (width < 40rem) {
  .bao-table-pinned-divider,
  tr.bao-table-responsive-row > .bao-table-pinned-action,
  .table.table-zebra > tbody > tr.bao-table-responsive-row > .bao-table-pinned-action,
  .table.table-zebra > tbody > tr.bao-table-responsive-row:nth-child(even) > .bao-table-pinned-action {
    box-shadow: none;
    background-color: transparent;
  }
}
@media (max-width: 47.99rem) {
  [data-primitive="DataTable"] .bao-table-pinned-action,
  [data-primitive="DataTable"] details.dropdown {
    position: relative;
    z-index: var(--z-local);
  }
  [data-primitive="DataTable"] tr:focus-within,
  [data-primitive="DataTable"] tr:has(details[open]) {
    z-index: var(--z-raised);
    position: relative;
  }
}

/* Sheets use the declared entrance curve; reduced motion retains only opacity. */
.bao-motion-sheet-spring,
.bao-sheet-panel {
  transition-property: transform, opacity;
  transition-duration: var(--duration-normal);
  transition-timing-function: var(--easing-entrance);
}
.bao-motion-sheet-fade {
  transition-property: opacity;
  transition-duration: var(--duration-fast);
  transition-timing-function: var(--easing-standard);
}
@media (prefers-reduced-motion: reduce) {
  .bao-motion-sheet-spring,
  .bao-sheet-panel {
    transition-property: opacity;
    transition-duration: var(--duration-fast);
    transform: none;
  }
}
html[data-reduced-motion="true"] .bao-motion-sheet-spring,
html[data-reduced-motion="true"] .bao-sheet-panel {
  transition-property: opacity;
  transform: scale(1);
}

ul[data-widget="sidebar"][data-state="empty"] [data-sidebar-empty] {
  display: list-item;
}
ul[data-widget="sidebar"][data-state="success"] [data-sidebar-empty],
ul[data-widget="sidebar"] [data-sidebar-empty][hidden] {
  display: none;
}
[data-sidebar-rail][data-sidebar-expanded="true"] .bao-nav-item.tooltip::before,
[data-sidebar-rail][data-sidebar-expanded="true"] .bao-nav-item.tooltip::after {
  display: none;
}

/* The scroll-scheduled specular drift is retired, not retuned. Every
   * surface it matched (topbar, primary nav, sidebar) is interactive
   * chrome: a scroll-timeline animation reports itself running for the
   * lifetime of its scroller, which left document.getAnimations()
   * permanently non-empty and destabilized pointer actionability across
   * the whole shell. One-shot bounding cannot fix that — a scroll-driven
   * animation is active whenever its timeline is — so interactive chrome
   * keeps its glass paint with no ambient motion at all (canon: motion
   * sparingly and deliberately). */

}
@layer bao-tokens {

/* ============================================================
   Nested glass fill plate (baobeep concentric anatomy)
   ============================================================
   Apply to text/form/list hosts nested inside a glass shell.
   Never put bare body copy on .bao-surface-glass-*.
   Content widgets use solid bao-data-panel — do not co-tag glass. */

.bao-glass-fill {
  background-color: var(--glass-fill-bg, var(--bg-panel, var(--color-base-100)));
  border: 1px solid var(--glass-fill-border, var(--liquid-border-regular));
  color: var(--text-primary, var(--color-base-content));
  border-radius: calc(var(--radius-box, 1rem) - 2px);
  box-shadow: inset 0 1px 0 var(--glass-highlight-soft);
}

/*
 * S100 — stack fill + interactive hosts above specular (z=2). Never
 * position:relative on every child (breaks absolute/fixed/sticky geometry).
 */
.bao-surface-glass-regular > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]),
.bao-surface-glass-clear > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]),
.bao-surface-glass-strong > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]),
.bao-surface-glass-modal > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]) {
  z-index: var(--z-raised-high, 3);
}
.bao-surface-glass-regular > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]):where(:not(.absolute):not(.fixed):not(.sticky)),
.bao-surface-glass-clear > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]):where(:not(.absolute):not(.fixed):not(.sticky)),
.bao-surface-glass-strong > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]):where(:not(.absolute):not(.fixed):not(.sticky)),
.bao-surface-glass-modal > :is(.bao-glass-fill,.bao-dialog-chrome,[data-result-host],.btn,a,button,input,select,textarea,summary,.menu,.navbar-start,.navbar-center,.navbar-end,.bao-touch-target,.bao-shell-brand,[data-primitive],[role="toolbar"],[role="navigation"],search,[role="search"],[role="menu"],[role="listbox"]):where(:not(.absolute):not(.fixed):not(.sticky)) {
  position: relative;
}

/* KPI / metric card body plate — nested under glass metric shells. */
[data-primitive="Card"][data-variant="metric"] .bao-glass-fill,
.card.bao-surface-glass-regular .bao-glass-fill {
  min-width: 0;
}

/*
 * L0 workbench under L1 shell glass — AnnotationWorkbench + AIAssistant
 * content planes stay solid (design-canon liquidGlass.placementRule.content).
 * L2 floating toolbars/menus keep Toolbar/DropdownMenu glass SSOT.
 */
[data-shell-scroll="main"] [data-primitive="AnnotationWorkbench"] .bao-data-panel,
[data-shell-scroll="main"] [data-primitive="AIAssistant"] .bao-data-panel,
[data-shell-scroll="main"] [data-primitive="AIAssistant"] .card.card-border,
[data-editor-chrome] .bao-data-panel,
[data-capture-chrome] .bao-data-panel {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  background-color: var(--bg-panel, var(--color-base-100));
}

/*
 * The media stages are the exception to the panel plate: the specimen canvas
 * and the 3D viewport are content the operator inspects, and Apple's layout
 * guidance wants media on a recessed ground, not floating in the same
 * base-100 white as the panels around it — measured 2026-08-22, the aspect-fit
 * letterbox above and below the slide painted the identical white as the page,
 * so the image's bounds were invisible. `--bg-surface` is the same recessed
 * step `.bg-base-200` resolves to, stated here because the panel plate above
 * outranks any utility class on the same element.
 */
[data-shell-scroll="main"] [data-primitive="AnnotationWorkbench"] [data-editor-canvas-region].bao-data-panel,
[data-shell-scroll="main"] [data-primitive="AnnotationWorkbench"] [data-editor-3d-viewport].bao-data-panel,
[data-editor-chrome] [data-editor-canvas-region].bao-data-panel,
[data-editor-chrome] [data-editor-3d-viewport].bao-data-panel {
  background: var(--bg-surface, var(--color-base-200));
}

/* Reduced transparency / high contrast: fill plate is already solid. */
@media (prefers-reduced-transparency: reduce) {
  .bao-glass-fill {
    background-color: var(--bg-surface, var(--bg-panel));
    box-shadow: none;
  }
}
html[data-reduced-transparency="true"] .bao-glass-fill {
  background-color: var(--bg-surface, var(--bg-panel));
  box-shadow: none;
}

}
@layer bao-tokens {


/* ============================================================
   Page chrome — sticky strip only (blur comes from glass classes)
   ============================================================
   Never re-apply raw backdrop-filter here. Toolbars already carry
   .bao-surface-glass-regular.bao-glass-small so one sheet blurs. */

.bao-page-chrome {
  position: sticky;
  top: 0;
  z-index: var(--z-content-overlay, 10);
  box-shadow: 0 var(--pane-divider) 0 0 var(--liquid-border-regular);
}

.bao-page-chrome::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  bottom: calc(-1 * var(--space-inline, 0.5rem));
  height: var(--space-inline, 0.5rem);
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-clear) * 100%), transparent),
    transparent
  );
  opacity: var(--opacity-near, 0.9);
}

/*
 * Scroll-edge adaptation (design.pdf §5.1/§7.5) lives with the topbar owners:
 * shadow in tokens-glass-control-chrome.ts, tint in
 * tokens-glass-shell-webview-theme.ts. State: app-shell-glass.ts.
 */

/* Toolbar geometry and disclosure; shared motion owns control transitions. */
.bao-toolbar-action {
  align-items: center;
  justify-content: center;
  gap: var(--space-compact);
  overflow: visible;
}
@media (pointer: coarse) {
  .bao-toolbar-action.btn-square,
  .bao-toolbar-action.btn-xs {
    min-height: var(--touch-target-min);
    min-width: var(--touch-target-min);
  }
}

/* Native popover invocation owns the anchor; daisyUI owns placement variants. */
.bao-dropdown-panel[popover] {
  inset: auto;
  margin-block: var(--space-inline);
  margin-inline: 0;
  max-inline-size: calc(100dvw - var(--space-page));
  max-block-size: min(var(--panel-scroll-max-height), calc(100dvh - var(--space-2xl)));
  overflow-y: auto;
  overscroll-behavior: contain;
  position-try-fallbacks: flip-inline, flip-block, flip-inline flip-block;
  position-visibility: anchors-visible;
}
@media (hover: hover) and (pointer: fine) {
  .bao-toolbar-action:not(.btn-primary):not(.btn-secondary):not(.btn-accent):not(.btn-error):not(.btn-warning):not(.btn-success):not(.btn-info):not(.bao-settings-tab):hover,
  .bao-toolbar-action:not(.btn-primary):not(.btn-secondary):not(.btn-accent):not(.btn-error):not(.btn-warning):not(.btn-success):not(.btn-info):not(.bao-settings-tab):focus-visible {
    background-color: color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-persistent) * 100%), transparent);
    box-shadow: 0 0 0 1px var(--liquid-border-regular);
  }
}
.bao-toolbar-action.btn-square:not([data-toolbar-density="labeled"] *) [data-hig-key-hint] {
  display: inline-block;
  max-width: 0;
  margin-inline-start: 0;
  padding-inline: 0;
  padding-block: 0;
  border-width: 0;
  opacity: 0;
  overflow: hidden;
  white-space: nowrap;
  transition-property: max-width, opacity, margin-inline-start, padding-inline, border-width;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-normal);
}
@media (hover: none), (pointer: coarse) {
  .bao-toolbar-action [data-hig-key-hint] {
    display: none;
  }
}

[data-toolbar-density="labeled"] .bao-toolbar-action.btn-square {
  width: auto;
  max-width: none;
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  height: auto;
  padding-inline: var(--toolbar-action-pad-inline);
}

[data-primitive="FilterBar"] .filter-reset,
[data-primitive="FilterBar"] [data-case-filter-reset],
form[data-case-filters] [data-case-filter-reset] {
  width: auto;
  max-width: none;
  min-width: var(--touch-target-min, 2.75rem);
  min-height: var(--touch-target-min, 2.75rem);
  justify-content: center;
  gap: var(--space-micro, 0.25rem);
  padding-inline: var(--space-inline, 0.5rem);
}

/* Square actions keep their compact geometry. Explicit labeled density is
 * the single opt-in for visible action captions and content-sized controls. */

/* Navigation geometry and selected-state paint; shared motion owns transitions. */
.bao-nav-item {
  display: flex;
  align-items: center;
  min-height: var(--touch-target-min);
  gap: var(--space-inline);
  border-radius: var(--radius-control);
}
@media (hover: hover) and (pointer: fine) {
  .bao-nav-item:hover {
    background: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  }
}
.bao-nav-item:focus-visible {
  background: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
}
.bao-shell-sidebar .menu-title {
  background-color: var(--bg-surface);
}
.bao-nav-item.menu-active,
.bao-nav-item[aria-current="page"] {
  background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  color: var(--text-primary);
  box-shadow: inset 0 0 0 1px var(--liquid-border-regular);
  font-weight: 600;
}
.bao-nav-item.menu-active svg,
.bao-nav-item[aria-current="page"] svg {
  stroke-width: 2.1;
  color: var(--accent-primary);
}
.bao-mobile-dock-item:is([aria-current="page"], [aria-pressed="true"]) .dock-label {
  color: var(--text-primary);
}

/* In-flow rails preserve navigation rows without forcing their min-content width. */
.bao-sidebar-rail-header {
  position: relative;
  z-index: var(--z-dropdown);
  display: none;
}
@media (min-width: 48rem) {
  .bao-sidebar-rail-header {
    display: flex;
  }
}
.bao-shell-sidebar [data-sidebar-group-member] {
  min-width: 0;
}
.bao-shell-sidebar [data-sidebar-group-member] > a {
  width: 100%;
}

/* Settings destinations retain visible labels and canonical target geometry. */
.bao-settings-tab {
  width: auto;
  min-width: var(--touch-target-min);
  min-height: var(--touch-target-min);
  flex: 0 0 auto;
  padding-inline: var(--space-inline);
}
.bao-shell-sidebar [data-sidebar-group] {
  position: static;
  background: transparent;
  color: var(--text-secondary);
}



/* Inactive tabpanel concealment has ONE owner:
   tokens-glass-shell-settings-panels-part-1.css, whose rule covers these three
   selectors plus the [data-page="settings"] [data-settings-panel] variants.
   The mirror that used to sit here was a second owner for the same question
   (LAW1) and is deliberately gone — not emptied by accident. */



/* API registry mobile entries — dense list items, not nested data panels. */


/* ============================================================
   Solid data panels — content plane (design.pdf §4)
   ============================================================ */

.bao-data-panel {
  border: 1px solid var(--border-base, var(--color-base-300));
  border-radius: var(--radius-box, 1rem);
  transition-property: border-color, box-shadow;
  transition-duration: var(--duration-normal);
  transition-timing-function: var(--easing-standard);
}

@media (hover: hover) and (pointer: fine) {
  .bao-data-panel:hover {
    border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
    box-shadow: var(--shadow-md);
  }
}
.bao-data-panel:focus-within {
  border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
  box-shadow: var(--shadow-md);
}




.modal-box {
  box-sizing: border-box;
  /* Variant tracks come from the existing size utilities. The containment
   * owner clamps them to the viewport without replacing compact dialogs
   * with the settings width or defeating the command/shortcuts size tokens. */
  --modal-box-gutter: calc(var(--space-inline) * 2);
  --modal-box-max-block: min(100dvh - 1.5rem, var(--modal-max-height, min(92dvh, 92vh)));
  inline-size: min(100%, var(--modal-box-track, var(--modal-default-max-width)));
  max-inline-size: min(100vw - var(--modal-box-gutter), var(--modal-box-track, var(--modal-default-max-width)), var(--modal-box-viewport-track, 100vw));
  max-block-size: var(--modal-box-max-block);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  min-inline-size: 0;
}
/*
 * Phone bottom sheet is full-bleed: a compact-width sheet spans the screen and
 * pins to the bottom edge, so a viewport gutter reads as a misaligned panel
 * rather than as a sheet.
 *
 * Gated to <40rem to match the `sm:` breakpoint the markup switches on — every
 * bottom sheet carries sm:modal-middle, sm:modal-end or sm:hidden, so at
 * >=40rem the centered track above is the correct one and this band must not
 * reach it.
 *
 * --vv-height tracks the visual viewport (app-shell-case-create.ts binds it on
 * visualViewport resize/scroll for the whole document), so the sheet shrinks
 * to clear a software keyboard instead of hiding its own controls behind it.
 */
@media (max-width: 39.99rem) {
  dialog.modal.modal-bottom > .modal-box {
    --modal-box-track: 100%;
    --modal-box-gutter: 0px;
    --modal-box-max-block: min(92dvh, var(--vv-height, 92vh));
    inline-size: 100%;
    max-inline-size: 100%;
  }
}
/* Tablet band (t10): centered modal with a token-driven cap instead of the
   near-full-width desktop track — sm:modal-middle already centers the grid,
   so only the width track tightens. */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  .modal-box {
    --modal-box-viewport-track: var(--modal-tablet-max-width);
    --modal-box-gutter: calc(var(--space-page) * 2);
  }
}
.bao-modal-body-scroll,
.modal-box > [class*="dialogBody"],
.modal-box > .px-space-section {
  min-width: 0;
  max-width: 100%;
  overflow-x: hidden;
}
.bao-data-panel fieldset.bao-settings-group.bao-data-panel,
.bao-data-panel .bao-settings-group.bao-data-panel {
  background: transparent;
  border-width: 0;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
}
/* An open dropdown explains itself — its summary tooltip would overlap
   (and clip against chrome edges above) the menu it just opened. */
details[open] > summary.tooltip::before,
details[open] > summary.tooltip::after {
  display: none;
}

}
@layer bao-tokens {

/* Shared padding for floating toolbar surfaces. */
.bao-toolbar-surface-padding {
  padding: var(--space-micro);
}

/*
 * Toolbar zones. Primary claims the free inline space so the secondary cluster
 * and the compact overflow trigger dock to the trailing edge; both stay
 * shrinkable (min-width:0) so a long verb label wraps inside its zone instead of
 * widening the toolbar and forcing the row to scroll.
 */
.bao-toolbar-primary {
  flex: 1 1 auto;
  min-width: 0;
}
.bao-toolbar-secondary {
  flex: 0 1 auto;
  min-width: 0;
  justify-content: flex-end;
}/*
 * FilterBar secondary dimensions (status,
priority,
…) as opposed to the
 * primary search field. They pair up beneath the full-width search on the
 * compact 2-column grid,
and the floor keeps each control at the 44px Apple HIG
 * target once its legend is painted.
 */
.bao-filter-secondary {
  min-width: 0;
}.bao-filter-secondary > .select,
.bao-filter-secondary > select,
.bao-filter-secondary > .input,
.bao-filter-secondary > input {
  min-height: var(--touch-target-min, 2.75rem);
  min-width: 0;
  width: 100%;
}/*
 * Overflow host. At >=48rem it stays display:contents so its children take part
 * directly in the FilterBar grid. On compact it must become a real box,
or the
 * col-span-full it carries has nothing to apply to — display:contents generates
 * no box and cannot be a grid item. Becoming a grid row is what lets collapsed
 * secondary dimensions stack full width under the search.
 */
@media (max-width: 47.99rem) {
  .bao-filter-overflow {
    display: grid;
    grid-column: 1 / -1;
    gap: var(--space-micro);
    min-width: 0;
  }
}

/*
 * Collection FilterBar — sticky filter band under page header / journey host.
 * Primitive classes carry sticky;this pins z-index + solid surface so table
 * scroll never paints over filter controls (one owner,
every collection page).
 */
[data-primitive="FilterBar"] {
  position: sticky;
  top: 0;
  z-index: calc(var(--z-sticky, 1100) - 1);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/*
 * Toolbar phone overflow — secondary zone hides; overflow trigger opens a
 * bottom sheet with full-width touch targets (Apple HIG dense toolbar).
 */
@media (max-width: 47.99rem) {
  [data-primitive="Toolbar"] .bao-toolbar-secondary {
    display: none;
  }
  [data-primitive="Toolbar"] [data-toolbar-overflow]:not(:checked) ~ .bao-toolbar-overflow-panel {
    display: none;
  }
  [data-primitive="Toolbar"] [data-toolbar-overflow]:checked ~ .bao-toolbar-overflow-panel {
    display: flex;
  }
  [data-primitive="Toolbar"] .bao-toolbar-overflow-panel {
    position: fixed;
    inset-inline: 0;
    inset-block-end: 0;
    z-index: var(--z-modal, 1300);
    flex-direction: column;
    gap: var(--space-micro);
    padding: var(--space-section);
    padding-block-end: max(var(--space-section), env(safe-area-inset-bottom, 0px));
    background: var(--color-base-100, var(--bg-panel));
    border-block-start: 1px solid var(--liquid-border-regular);
    box-shadow: var(--shadow-glass-elevated);
  }
  [data-primitive="Toolbar"] .bao-toolbar-overflow-panel .btn {
    width: 100%;
    justify-content: flex-start;
    min-height: var(--touch-target-min, 2.75rem);
  }
}

/* Collection control priority: one navigation disclosure, flexible search, then actions. */
.bao-filter-bar-collection > label:has(input[type="search"]) {
  flex: 1 1 var(--grid-choice-min);
  inline-size: auto;
  min-inline-size: 0;
}
.bao-filter-bar-collection > [data-commerce-list-filter-state],
.bao-filter-bar-collection > nav {
  flex: 0 0 auto;
  min-inline-size: 0;
}
.bao-filter-bar-collection > [data-filter-actions] {
  flex: 0 0 auto;
  flex-wrap: nowrap;
  inline-size: auto;
  margin-inline-start: 0;
}
.bao-filter-bar-collection[data-filter-sheet-open="true"] > label:has(input[type="search"]) {
  flex: 0 1 auto;
  inline-size: 100%;
}
@media (max-width: 47.99rem) {
  .bao-filter-bar-collection:not([data-filter-sheet-bound]) {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Native compact facets share the search row and expand into one full-width field row. */
.bao-filter-disclosure-compact {
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
}
.bao-filter-disclosure-compact[open] {
  flex-basis: 100%;
}
.bao-filter-bar-collection:has(> .bao-filter-disclosure-compact[open]) {
  flex-wrap: wrap;
}
.bao-filter-disclosure-compact > div {
  padding-block-start: var(--space-inline);
}

/* Commands shrink within one row before their own horizontal scrollport. */
.bao-toolbar-commands {
  flex: 1 1 0%;
}

/* Canvas Toolbars use the shared flex row and explicit overflow contract. */
.bao-toolbar-canvas-surface {
  padding: max(0px, calc(var(--radius-box) - var(--radius-control) - var(--border)));
}

/* Toolbar catalog groups own their layout independently of registry disclosure rows. */
.bao-toolbar-catalog-group {
  display: grid;
  inline-size: 100%;
  grid-template-columns: repeat(auto-fit, minmax(min(var(--toolbar-label-reveal-max-width), 100%), 1fr));
  align-items: start;
  gap: var(--space-micro);
}
@media (max-width: 47.99rem) {
  .bao-toolbar-catalog-group {
    grid-template-columns: minmax(0, 1fr);
  }
}

}
@layer bao-tokens {

/*
 * App-shell drawer host — mobile-first, WebView-hardened (BlueStacks ships
 * Chromium ~101; do not rely solely on daisyUI is-drawer-close variants).
 * - Side rail is position:fixed off-canvas until the checkbox opens it
 * - ≥80rem permanent in-flow rail (never daisyUI lg:drawer-open)
 * - Content fills remaining track; no stacked dual sidebars
 */
/*
 * No overflow here: the drawer-part-b block owns it with `overflow: clip`
 * (same visual clip, no scroll container). Declaring `hidden` earlier only
 * created a dead declaration the ratchet had to flag.
 */
.bao-shell-drawer {
  position: relative;
  display: flex;
  width: 100%;
  max-width: 100%;
  container-type: inline-size;
  container-name: shell;
}

.bao-shell-drawer > .drawer-toggle {
  position: fixed;
  width: 0;
  height: 0;
  opacity: 0;
  pointer-events: none;
}

.bao-shell-drawer > .drawer-content {
  display: flex;
  min-width: 0;
  flex-direction: column;
  width: 100%;
  max-width: 100%;
}

/*
 * Closed rail host: fixed, fully opaque host (children own the slide).
 * daisyUI sets opacity:0% / visibility:hidden on .drawer-side — reset both.
 */
.bao-shell-drawer > .drawer-side {
  position: fixed;
  inset-block: 0;
  inset-inline-start: 0;
  /*
   * Off-canvas rank: above the mobile dock (--z-overlay: 1200) AND above the
   * sticky topbar (--z-shell-topbar: 1250). Neither may paint over an open
   * rail/scrim. The modal drawer owns this rank; in-flow rails use their local rank.
   */
  z-index: var(--z-shell-drawer-overlay, 1300);
  display: flex;
  flex-direction: column;
  width: min(var(--shell-drawer-width), var(--shell-drawer-max-viewport));
  max-width: var(--shell-drawer-width);
  height: 100%;
  margin: 0;
  translate: none;
  opacity: 1;
  visibility: visible;
  pointer-events: none;
  overscroll-behavior: contain;
  background-color: transparent;
  transition-property: none; transition-duration: var(--duration-instant);
}

/*
 * Panel slides; host stays painted so open/close is not an opacity fade.
 * .bao-shell-sidebar owns its Liquid Glass material through bao-surface-glass-*.
 * This geometry rule must not reset its background: transparent paint erases
 * the accessibility variant, while solid paint erases the normal material.
 * Accessibility solidification stays with the material owner.
 */
.bao-shell-drawer > .drawer-side > *:not(.drawer-overlay) {
  pointer-events: none;
  height: 100%;
  width: 100%;
  max-width: 100%;
  /* Closed: clip layout overflow so mobile smoke does not count off-canvas nav. */
  overflow: hidden;
  visibility: hidden;
  overscroll-behavior: contain;
  /* Material classes own paint, including opaque accessibility variants. */
  color: var(--text-primary, var(--color-base-content));
  transform: translate3d(-100%, 0, 0);
  translate: none;
  transition-property: transform; transition-duration: var(--duration-normal); transition-timing-function: var(--easing-standard);
}

/* Promote during the open/close transition only — reverts to auto at rest. */
.bao-shell-drawer:has(> .drawer-toggle:checked) > .drawer-side > *:not(.drawer-overlay),
.bao-shell-drawer:has(> .drawer-toggle:focus) > .drawer-side > *:not(.drawer-overlay) {
  will-change: transform;
}

.bao-shell-drawer:not(:has(> .drawer-toggle:checked)):not(:has(> .drawer-toggle:focus))
  > .drawer-side
  > *:not(.drawer-overlay) {
  will-change: auto;
}

.bao-shell-drawer > .drawer-side > .drawer-overlay {
  position: fixed;
  inset: 0;
  /* Scrim must cover the viewport for tap-outside-to-close.
     z-index -1 painted under the rail panel but still receives hits
     across the full viewport once pointer-events are enabled. */
  z-index: var(--z-base, 0);
  /* Theme-safe scrim — never raw black-only; readable on light/dark. */
  background: color-mix(in oklab, var(--color-base-content) 40%, transparent);
  opacity: 0;
  pointer-events: none;
  transition-property: opacity; transition-duration: var(--duration-normal); transition-timing-function: var(--easing-standard);
  cursor: pointer;
}

/* Open: checkbox checked (mobile menu / dock More) */
.bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side {
  pointer-events: auto;
  /* Expand hit host to full viewport so the fixed scrim is reachable. */
  width: 100%;
  max-width: none;
}

/* Hide dock while the rail owns the viewport — prevents dock-on-scrim stacking. */
.bao-shell-drawer > .drawer-toggle:checked ~ .drawer-content .bao-mobile-dock,
.bao-shell-drawer:has(> .drawer-toggle:checked) .bao-mobile-dock {
  visibility: hidden;
  pointer-events: none;
}

.bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
  pointer-events: auto;
  overflow-y: auto;
  visibility: visible;
  transform: translate3d(0, 0, 0);
  translate: none;
  /* Keep panel at mobile rail width while host spans viewport for scrim. */
  width: min(var(--shell-drawer-width), var(--shell-drawer-max-viewport));
  max-width: var(--shell-drawer-width);
  z-index: var(--z-local, 1);
}

.bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .drawer-overlay {
  opacity: 1;
  pointer-events: auto;
}

/*
 * Permanent rail from 80rem (1280px) only.
 * Phones report 1080 CSS px (hits Tailwind lg: 1024) — must stay off-canvas.
 * Do not use daisyUI lg:drawer-open on phones; this media query is the SSOT.
 *
 * Topbar hamburger SSOT (matches webview-drawer; single owner):
 * - Phone (<48rem): dock "More" opens drawer — hide header hamburger.
 * - Tablet (48–79.99rem): persistent icon rail owns nav — hamburger retired
 *   (the drawer retires in this band; see the tablet rail block below).
 * - Permanent rail (≥80rem): hide header hamburger — #desktop-sidebar-collapse
 *   in the sidebar owns collapse (no dual collapse controls).
 */


/* The phone drawer owns navigation; the in-flow rail disclosure starts at tablet. */
@media (max-width: 47.99rem) {
  .bao-shell-drawer .bao-shell-sidebar [data-sidebar-rail-toggle].btn {
    display: none;
  }
}

/* Tablet and desktop share the declared rail state; the viewport owns placement only. */
@media (min-width: 48rem) {
  .bao-shell-drawer[data-sidebar-expanded="false"] {
    --shell-rail-track: var(--sidebar-collapsed);
  }
}

.bao-shell-sidebar .menu,
.bao-shell-sidebar ul.menu {
  display: flex;
  flex-direction: column;
  flex-wrap: nowrap;
  overflow-x: hidden;
}

@media (min-width: 48rem) and (max-width: 79.99rem) {
  .bao-shell-drawer {
    display: grid;
    grid-template-columns: var(--shell-rail-track, var(--sidebar-expanded)) minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    align-items: stretch;
  }

  .bao-shell-drawer > .drawer-content {
    grid-column: 2;
    grid-row: 1;
    width: auto;
    max-width: none;
    min-height: 0;
  }

  .bao-shell-drawer > .drawer-side,
  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side {
    grid-column: 1;
    grid-row: 1;
    height: 100%;
    min-height: 0;
    align-self: stretch;
    translate: none;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    overflow: visible;
  }

  .bao-shell-drawer:not(.bao-shell-sidebar-peek) > .drawer-side,
  .bao-shell-drawer:not(.bao-shell-sidebar-peek) > .drawer-toggle:checked ~ .drawer-side {
    position: relative;
    inset: auto;
    z-index: var(--z-local, 1);
    width: 100%;
    max-width: none;
  }

  .bao-shell-drawer.bao-shell-sidebar-peek > .drawer-side,
  .bao-shell-drawer.bao-shell-sidebar-peek > .drawer-toggle:checked ~ .drawer-side {
    position: absolute;
    inset-block: 0;
    inset-inline-start: 0;
    inset-inline-end: auto;
    z-index: var(--z-shell-drawer-overlay);
    width: var(--sidebar-expanded);
    max-width: var(--sidebar-expanded);
  }

  .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay),
  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
    pointer-events: auto;
    visibility: visible;
    overflow: visible;
    transform: none;
    translate: none;
    will-change: auto;
    transition-property: none; transition-duration: var(--duration-instant);
    height: 100%;
    width: 100%;
    max-width: none;
  }

  .bao-shell-drawer > .drawer-side > .drawer-overlay,
  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .drawer-overlay {
    display: none;
    opacity: 0;
    pointer-events: none;
  }

  /* In-flow tablet rail — LAYOUT ONLY. The material is owned by the
     bao-surface-glass-regular + bao-glass-large pair app-shell.bao puts on
     .bao-shell-sidebar; this block previously repainted it solid and killed the
     specular/illumination plates, so one property had two owners and the
     .bao declaration was dead. Apple HIG Sidebars: sidebars float above
     content in the Liquid Glass layer, as toolbars and tab bars do; HIG
     Materials names sidebars as a regular-variant surface because they
     carry a significant amount of text. Reduced transparency and increased
     contrast still solidify it — tokens-glass-a11y-prefers owns that.
     Padding stays with .bao-shell-sidebar/p-space-micro — no shorthand here
     or the safe-area-aware block padding is clobbered on notched tablets. */
  .bao-shell-sidebar,
  .bao-shell-sidebar.bao-surface-glass-regular,
  .bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="true"],
  .bao-shell-sidebar[data-sidebar-rail][data-sidebar-expanded="false"] {
    width: 100%;
    /* Inline padding, never the shorthand — the note above is right that a
       shorthand here clobbers the safe-area-aware block padding on notched
       tablets. It has to be stated all the same: this band owns the rail mode,
       but the expanded/collapsed CLASS is owned by the toggle, and the toggle
       does not know the band exists. A rail sitting in the 3.5rem track while
       still classed [data-sidebar-rail][data-sidebar-expanded="true"] took that class's
       padding: var(--space-section) shorthand — 12px a side, sized for the
       16rem sidebar — which outranks the p-space-micro utility the note relies
       on. Measured at 1100px: 56px rail, 32px left after the rail padding, 20px
       after .menu's own inline padding, holding a 44px HIG target that then
       ran from x=18 to x=62 and was clipped by the rail's own edge. The band
       decides the padding for both classes; .menu adds none inside a rail. */
    padding-inline: var(--space-micro);
  }

  .bao-shell-sidebar[data-sidebar-expanded="false"] .menu {
    padding-inline: 0;
  }

  /* One affordance per function: the band owns rail state. */
  .bao-shell-topbar .bao-drawer-toggle-control,
  .bao-shell-topbar [data-drawer-toggle] {
    display: none;
  }

  /* The existing rail toggle remains a reachable expansion control in this band. */

  /*
   * Pinned (the explicit ui.sidebar.tabletPinned preference): the band yields its fixed icon track to the
   * expanded track. The pin is a deliberate user action — reflow is intended.
   */
  .bao-shell-drawer.bao-shell-sidebar-pinned {
    grid-template-columns: var(--sidebar-expanded) minmax(0, 1fr);
  }

  /*
   * Peek (an ephemeral hover disclosure, not a preference): the rail track stays
   * collapsed and the panel paints over the content column instead of pushing
   * it. A peek that reflowed would be a second pin — the pin is the only
   * user-owned expansion in this band, so the peek must not move any track.
   */
  .bao-shell-drawer.bao-shell-sidebar-peek {
    grid-template-columns: var(--sidebar-collapsed) minmax(0, 1fr);
  }

  /*
   * Expanded vocabulary while pinned — mirrors the ≥80rem expanded
   * sidebar: group titles and labels paint, nav items align inline-start.
   * Scoped selectors (drawer class + .bao-shell-sidebar) outrank the band's
   * icon-rail presentation rules above.
   */
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar .menu-title {
    display: list-item;
  }
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar [data-sidebar-expanded-only] {
    display: inline;
  }
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar .bao-nav-item {
    justify-content: flex-start;
    padding-inline: var(--space-inline, 0.5rem);
  }
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar .bao-nav-item.tooltip::before,
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar .bao-nav-item.tooltip::after {
    display: none;
  }
  /* The pin control lives inside the expanded sidebar while pinned. */
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar [data-sidebar-rail-toggle] {
    display: inline-flex;
    visibility: visible;
    pointer-events: auto;
  }
  /*
   * Expanded presentation paints the chevron; the collapsed-only logo must
   * not stack under it when the pin arrives without a prior toggle (the
   * [hidden] mirror for collapsed-only is toggle-driven and never fired).
   */
  .bao-shell-drawer.bao-shell-sidebar-pinned .bao-shell-sidebar [data-sidebar-rail-toggle] [data-sidebar-collapsed-only] {
    display: none;
  }
}


@media (min-width: 80rem) {

  .bao-drawer-toggle-control {
    display: none;
  }

  /*
   * Dock ↔ permanent-rail CQ ownership (viewport rem SSOT, unlayered):
   * phone (<48rem) paints .bao-mobile-dock; tablet (48–79.99rem) paints the
   * in-flow icon rail (dock already hidden in tokens-layout-dock-base);
   * ≥80rem replaces both with the full in-flow left sidebar. Must stay unlayered —
   * @layer utilities hide was dropped on WebView 101 so the dock still
   * painted at 1280 beside the rail.
   */

  /*
   * Right session rail: CSS owns visibility (never Tailwind xl:flex), and
   * this module is its one owner across both bands — the hide lives in the
   * `max-width: 79.99rem` block below.
   *
   * The in-flow geometry moved here from tokens-layout-editor-workbench-grid,
   * which declared it from `min-width: 64rem`. That was an editor-scoped file
   * making a shell-wide claim, and because it repeated `display` at equal
   * specificity from a later module it also outranked the hide across the
   * 64–80rem band. On /capture at 1200x900 the rail then painted beside the
   * in-page session card, which only stands down at 80rem
   * (`body:has(#session-rail) [data-capture-workbench-secondary]`): two live
   * session-control surfaces, the preview crushed to 464px, and a Collapse
   * that left the in-page copy behind so the rail read as relocating into the
   * preview instead of collapsing.
   */
  #session-rail.bao-shell-session-rail,
  #session-rail {
    display: flex;
    visibility: visible;
    pointer-events: auto;
    align-self: stretch;
    flex: 0 0 auto;
    min-block-size: 0;
  }
  #session-rail.bao-surface-glass-regular {
    background-color: var(--bg-panel);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  /* Session-rail sheet trigger retires once the permanent rail is in-flow.
     The selector must carry the full icon-geometry weight
     (#id + .navbar-end + .bao-shell-topbar-actions + attr + .btn +
     .bao-shell-icon-action). The plain ".bao-shell-topbar [attr]" form here scored
     (1,1,0) and lost every cascade to the unlayered icon-geometry rules at
     (1,4,0), so this hide NEVER applied: the phone sheet trigger shipped in
     the desktop topbar next to the permanent rail's own collapse control —
     two visible session-rail affordances at >=80rem. The <40rem band in
     tokens-glass-shell-topbar-zones-narrow.ts already matches this weight;
     this band had been left behind. */
  .bao-shell-topbar .navbar-end .bao-shell-topbar-actions [data-session-rail-sheet-open].btn.bao-shell-icon-action {
    display: none;
  }

  /*
   * These two style the shell host itself, so this band must stay @media.
   * .bao-shell-drawer declares container-name: shell, and a container query
   * never matches the element establishing the container — nesting them in
   * @container shell (min-width: 80rem) dropped them silently: base
   * display:flex won, .drawer-side kept width:100%, .drawer-content
   * collapsed to 0px, and the desktop shell painted as a full-viewport
   * sidebar with no content.
   */
  .bao-shell-drawer {
    display: grid;
    /* The rail grid track is the ONE owner of sidebar width. Collapse swaps
       the track var (drawer-level class from applySidebarRailState) — aside
       children are width:100% of the track and must never fight it.
       HIG Dynamic Type: the bare minmax(14rem, 16rem) computes 896–1024px
       at root font 400%, leaving the content column ~30% of a 1440px window
       and pushing every topbar control past the right edge (measured capsule
       right 1691px, badge left 1057px). The vw terms are font-invariant:
       18vw resolves to 16rem at 1440px and 14vw resolves to 14rem at 1024px,
       so the default-font arithmetic is unchanged while enlarged text cannot
       starve the shell. */
    grid-template-columns: var(--shell-rail-track, minmax(min(14rem, 14vw), min(16rem, 18vw))) minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    align-items: stretch;
  }

  /*
   * Collapsing the rail narrowed the grid track and nothing else, so the nav
   * kept painting full-width labels inside a 56px rail and the track clipped
   * them mid-word — "Primary" rendered as "Primar", "Annotation Review" as
   * "An". A collapsed rail is an ICON rail (design.pdf 8.3: medium width
   * becomes a navigation rail), so label text and section headings stop
   * painting at that width.
   *
   * Safe to remove from the box rather than sr-only-clip: every .bao-nav-item
   * carries its own aria-label AND the .tooltip class, so the accessible name
   * survives and hover/focus still reveals the text (9.6 "icon-only controls
   * must retain accessible names").
   */
  .bao-shell-drawer[data-sidebar-expanded="false"] .bao-nav-item > span {
    display: none;
  }
  .bao-shell-drawer[data-sidebar-expanded="false"] .menu-title {
    display: none;
  }
  .bao-shell-drawer[data-sidebar-expanded="false"] .bao-nav-item {
    justify-content: center;
    padding-inline: var(--space-micro, 0.25rem);
  }
  /*
   * The 44px touch floor on .bao-nav-item is non-negotiable, so the list
   * padding has to yield instead: the expanded rail's inline padding left the
   * item starting 17px in, pushing its right edge to 61px inside a 56px rail
   * and clipping the glyph. Trim the inset at rail width so the full target
   * fits (design.pdf 8.2 large touch areas).
   */
  .bao-shell-drawer[data-sidebar-expanded="false"] .menu,
  .bao-shell-drawer[data-sidebar-expanded="false"] .bao-shell-sidebar > nav,
  .bao-shell-drawer[data-sidebar-expanded="false"] .bao-shell-sidebar {
    padding-inline: var(--space-micro, 0.25rem);
  }

  .bao-shell-drawer > .drawer-toggle {
    display: none;
  }

  .bao-shell-drawer > .drawer-content {
    grid-column: 2;
    grid-row: 1;
    width: auto;
    max-width: none;
    min-height: 0;
  }

  .bao-shell-drawer > .drawer-side {
    position: relative;
    inset: auto;
    grid-column: 1;
    grid-row: 1;
    z-index: var(--z-local, 1);
    width: 100%;
    max-width: none;
    height: 100%;
    min-height: 0;
    align-self: stretch;
    translate: none;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    flex: 0 0 auto;
    overflow: visible;
  }

  /*
   * Permanent rail is never toggle-checked. Base closed rules leave the panel
   * at pointer-events:none + visibility:hidden — without this override the
   * entire sidebar is dead on desktop (clicks fall through).
   */
  .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay) {
    pointer-events: auto;
    visibility: visible;
    /* The menu owns scrolling; the header tooltip must escape the rail. */
    overflow: visible;
    /* Closed-state off-canvas shift uses transform (not translate) — reset
       BOTH or the permanent rail renders as an empty reserved track. */
    transform: none;
    translate: none;
    will-change: auto;
    transition-property: none; transition-duration: var(--duration-instant);
    height: 100%;
    width: 100%;
    max-width: none;
  }

  .bao-shell-drawer > .drawer-side > .drawer-overlay {
    display: none;
    pointer-events: none;
  }

  /* Permanent left sidebar (≥80rem) keeps the regular Liquid Glass material
     app-shell.bao declares on .bao-shell-sidebar. Apple HIG Sidebars: sidebars
     float above content in the Liquid Glass layer, as toolbars and tab bars
     do; HIG Materials assigns the regular variant to text-heavy chrome and
     names sidebars explicitly. The solid content-plane override that used to
     live here repainted the surface and hid the specular/illumination
     plates, so the .bao declaration was dead markup and the desktop rail
     rendered a different material from the phone drawer. Accessibility still
     wins: tokens-glass-a11y-prefers and the data-reduced-transparency /
     data-high-contrast branches solidify every glass surface including this
     one. The permanent full-height backdrop is the cost of that compliance. */


}

/* Below permanent-rail: session rail out of flow (CSS SSOT, not xl:).
 * display:none + visibility:hidden so HTMX intersect never fires and AT
 * skips the complementary pane until ≥80rem. JS mirrors inert (HTML). */
@media (max-width: 79.99rem) {
  #session-rail.bao-shell-session-rail,
  #session-rail {
    display: none;
    visibility: hidden;
    pointer-events: none;
  }

  /* RTL: off-canvas from the inline end (mobile / tablet only) */
  [dir="rtl"] .bao-shell-drawer > .drawer-side {
    inset-inline-start: auto;
    inset-inline-end: 0;
  }

  [dir="rtl"] .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay) {
    transform: translate3d(100%, 0, 0);
  }

  [dir="rtl"] .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
    transform: translate3d(0, 0, 0);
  }
}

/* RTL tablet band: the in-flow icon rail never sits off-canvas — reset the
   RTL off-canvas shift above (equal specificity; later source order wins). */
@media (min-width: 48rem) and (max-width: 79.99rem) {
  [dir="rtl"] .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay),
  [dir="rtl"] .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > *:not(.drawer-overlay) {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay),
  .bao-shell-drawer > .drawer-side > .drawer-overlay {
    transition-property: none; transition-duration: var(--duration-instant);
  }
}

/* Product Settings → reduced motion must match OS prefers-reduced-motion. */
html[data-reduced-motion="true"] .bao-shell-drawer > .drawer-side > *:not(.drawer-overlay),
html[data-reduced-motion="true"] .bao-shell-drawer > .drawer-side > .drawer-overlay {
  transition-property: none; transition-duration: var(--duration-instant);
}

/*
 * Sidebar capability-empty state. The nav list is a .menu, so the empty row has
 * to opt out of menu item geometry (hover/active plate, inline padding) or it
 * paints as a misleading, hoverable destination. The row also stops being a flex item
 * that stretches to the rail width so the centred copy stays readable while the
 * rail is collapsed.
 */
.bao-sidebar-empty-item {
  display: block;
  width: 100%;
  min-width: 0;
  /* Kill .menu li hover/active plate for every pointer — no :hover gate needed. */
  background: none;
}
.bao-sidebar-empty {
  min-width: 0;
  border-radius: var(--radius-field, 0.75rem);
  background: var(--bg-panel, var(--color-base-100));
  color: var(--text-secondary, var(--color-base-content));
}

}
@layer bao-tokens {

/* A phone More sheet is an expanded touch menu, independent of the persisted rail preference. */
@media (max-width: 47.99rem) {
  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .bao-shell-sidebar {
    width: 100%;
    max-width: none;
    padding-block: var(--space-section, 0.75rem);
    padding-inline: min(var(--space-section), 5%);
  }

  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .bao-shell-sidebar [data-sidebar-expanded-only] {
    display: inline;
  }

  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .bao-shell-sidebar .menu-title {
    display: list-item;
  }

  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .bao-shell-sidebar .bao-nav-item {
    justify-content: flex-start;
    padding-inline: min(var(--space-inline, 0.5rem), 5%);
  }

  .bao-shell-drawer > .drawer-toggle:checked ~ .drawer-side > .bao-shell-sidebar [data-sidebar-rail-toggle] {
    display: none;
  }
}

}
@layer bao-tokens {

/* Shared window field: static, low-frequency color beneath functional glass.
 * Palette values live in tokens.bao; content panels retain their own fill.
 * Theme declarations are emitted once by the token and Daisy UI compilers. */
.bao-shell-ambient {
  background-color: var(--bg-app);
}
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-ambient {
    background-image:
      radial-gradient(ellipse 100% 85% at 0% 0%, color-mix(in srgb, var(--accent-primary) 12%, transparent), transparent 72%),
      radial-gradient(ellipse 90% 90% at 100% 45%, color-mix(in srgb, var(--accent-secondary) 8%, transparent), transparent 74%),
      radial-gradient(ellipse 105% 75% at 25% 100%, color-mix(in srgb, var(--accent-primary) 6%, transparent), transparent 76%);
    background-attachment: fixed;
    background-repeat: no-repeat;
  }
}

/* Elevation from the canonical token (theme-aware via --glass-shadow-*),
   plus the shared inset top-light line — no bespoke shadow recipes. */
.bao-surface-glass-regular.bao-glass-large,
[data-theme="capture-dx-dark"] .bao-surface-glass-regular.bao-glass-large {
  box-shadow:
    var(--shadow-glass-floating),
    0 1px 0 0 color-mix(in oklab, var(--glass-highlight-strong) 70%, transparent) inset;
}

details.dropdown:not([open]) > .dropdown-content,
  details.bao-locale-chrome:not([open]) > .dropdown-content,
  details.dropdown:not([open]) > [data-dropdown-panel],
  details.dropdown:not([open]) > .bao-dropdown-panel {
  display: none;
}

/*
 * daisyUI 5 only paints .dropdown-content on .dropdown-open / :focus-within.
 * Android WebView opens <details> without focusing the summary, so the menu
 * stayed at opacity 0. Force open visibility from the native open attribute.
 *
 * align-content is load-bearing, not decoration. This rule replaces daisyUI's
 * .menu (display: flex; flex-direction: column) with a grid, and a grid whose
 * align-content is left at the initial 'normal' resolves to STRETCH: every
 * implicit row is sized by the panel box instead of by its own content. The
 * panel is content-sized today only by accident — nothing currently resolves
 * both of its block edges — so the defect stayed latent until a host pinned
 * the panel's block size, and then the rows split it evenly between them.
 *
 * Measured at 390x844 on /capture with the two-row page-toolbar overflow, the
 * panel forced to a definite 600px block size: rows landed at y=156 and y=453
 * (297px apart — 600/2 per track) with blank space between and after them,
 * while the controls stayed 44px tall. The reported production panel is the
 * same arithmetic one size up: 1340px tall, two rows, second row ~670px below
 * the first. With align-content: start the same 600px box lays the rows at
 * y=156 and y=204 — 44px plus the 4px gap, a uniform list — and the panel
 * collapses back to its content height wherever the block size is free.
 *
 * A menu's height is its content's height. Declare it; never infer it.
 */
details.dropdown[open] > .dropdown-content,
details.dropdown.dropdown-open > .dropdown-content,
details.dropdown[open] > [data-dropdown-panel],
details.dropdown.dropdown-open > [data-dropdown-panel] {
  display: grid;
  align-content: start;
  opacity: 1;
  scale: 1;
  visibility: visible;
  pointer-events: auto;
  z-index: var(--z-dropdown, 1000);
}

/*
 * Compact scrim behind an open menu (§8.6: popovers become sheets on compact).
 *
 * Measured at 390x844 and 320x720: every open dropdown panel — page-toolbar
 * overflow, account menu, capture overflow, row overflow — floated over a live,
 * fully lit page with nothing separating the layers and nothing to dismiss
 * against. The panel's own backdrop-filter blurred what was directly behind it
 * and stopped there.
 *
 * The scrim is the panel's own ::backdrop, not a rendered element: the shell
 * dropdown controller already promotes open panels to the top layer via
 * popover, so the pseudo-element costs no markup and no class strings composed
 * in TypeScript. It is also not hit-testable — measured with
 * elementFromPoint(40, panelBottom + 200), which resolves to the page content
 * underneath with and without the scrim — so the controller's outside-click
 * dismissal keeps working unchanged (verified: the menu closes on a scrim tap).
 *
 * Recipe mirrors .bao-filter-sheet-backdrop (the canonical compact scrim) so
 * both sheets read as one material. Phone band only: a pointer-first dropdown
 * on tablet/desktop is an anchored popover, and HIG does not scrim those.
 */
@media (max-width: 47.99rem) {
  .bao-dropdown-panel:popover-open::backdrop {
    background-color: var(--glass-scrim, var(--glass-scrim));
  }
  /* Blur is glass: it degrades off with every other material under
     reduced-transparency / increased-contrast signals (OS + product). */
  @media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
    html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-dropdown-panel:popover-open::backdrop {
      -webkit-backdrop-filter: blur(var(--liquid-blur-clear));
      backdrop-filter: blur(var(--liquid-blur-clear));
    }
  }
}

/* Topbar paint only; topbar-zones owns layout and safe-area geometry. */
.bao-shell-topbar.navbar,
.bao-shell-topbar[data-shell-topbar] {
  /* Solid first — WebView 101 drops color-mix declarations entirely. */
  background-color: var(--bg-panel, var(--color-base-100));
  border-bottom: 1px solid var(--border-base);
  box-sizing: border-box;
  -webkit-backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular));
  backdrop-filter: blur(var(--liquid-blur-regular)) saturate(var(--liquid-saturate-regular));
}
/* WebView 101: color-mix declarations are dropped there, so the solid panel
 * fill above is the resting style. Capable engines re-enable the translucent
 * glass fill via feature detection through the canonical capability rule, and
 * strengthen the tint with --liquid-fill-transient while content scrolls beneath.
 * Blur and --liquid-saturate-strong stay on the nav owner. The scroll-edge rule is fill only.
 * Translucency stays off for every reduced-transparency / increased-contrast
 * signal — OS preference and product toggle alike for every accessibility preference signal. */

@supports (background-color: color-mix(in oklab, red 50%, transparent)) and ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) {
  @media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (prefers-reduced-motion: no-preference) and (forced-colors: none) {
    html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]):not([data-reduced-motion="true"]) .bao-shell-topbar.navbar,
    html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]):not([data-reduced-motion="true"]) .bao-shell-topbar[data-shell-topbar] {
      background-color: transparent;
    }
    html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]):not([data-reduced-motion="true"]) .bao-shell-topbar[data-shell-topbar][data-scroll-edge="true"] {
      --liquid-material-active-alpha: var(--liquid-fill-transient);
    }
  }
}



/*
 * Topbar zone/strip/search/status rules live in ONE owner:
 * tokens-glass-shell-context-density.ts. This module keeps only
 * WebView-specific hardening that is not topbar chrome.
 */
/*
 * Keyboard cheatsheet control only — .btn.hidden permanently beats sm:inline-flex.
 * Theme toggle + voice must NEVER use this class (always-visible chrome).
 */
.bao-shell-topbar .bao-shell-kbd-control {
  display: none;
}
@media (min-width: 40rem) {
  .bao-shell-topbar .bao-shell-kbd-control {
    display: inline-flex;
  }
}

/*
 * Topbar hamburger:
 * - Phone (<48rem): dock "More" opens the drawer — hide duplicate hamburger.
 * - Tablet (48–79.99rem): persistent icon rail owns nav — hamburger retired
 *   (tokens-glass-shell-drawer.ts tablet band renders the rail in-flow).
 * - Permanent sidebar (≥80rem): hide hamburger — rail collapse lives in
 *   .bao-shell-sidebar [data-sidebar-rail-toggle] (no dual collapse controls).
 */
.bao-shell-topbar [data-drawer-toggle],
.bao-shell-topbar .bao-drawer-toggle-control {
  display: none;
}
@media (min-width: 80rem) {
  .bao-shell-topbar [data-drawer-toggle],
  .bao-shell-topbar .bao-drawer-toggle-control {
    display: none;
  }
}


@media (max-width: 63.99rem) {
  /*
   * Dual-title ban on phone (design.pdf §4 / §5.1): when content PageHeader
   * owns naming, keep shell title demoted. Restore shell title only when
   * shell mode owns naming (immersive/media demoted H1).
   */
  body[data-page-header-mode="shell"] #shell-page-title,
  body[data-page-header-mode="shell"] [data-shell-page-title] {
    position: static;
    width: auto;
    height: auto;
    max-width: 9rem;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip: auto;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
  /* Page body breadcrumbs still hide on phone — H1 owns in-page naming. */
  [data-page-breadcrumbs] {
    display: none;
  }
}


.bao-shell-topbar details.dropdown > summary {
  list-style: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* Floor via the canonical touch-target token max(2.75rem, 44px):
     never below the 44px HIG minimum, growing with root text scale
     (Dynamic Type); at extreme scales the topbar reflows instead of
     capping hit targets below the floor. */
  min-width: var(--touch-target-min, 2.75rem);
  min-height: var(--touch-target-min, 2.75rem);
  cursor: pointer;
}

.bao-shell-topbar details.dropdown > summary::-webkit-details-marker {
  display: none;
}

.bao-shell-topbar [data-user-avatar],
.bao-shell-topbar .avatar-placeholder > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  max-width: 1.75rem;
  max-height: 1.75rem;
  overflow: hidden;
  border-radius: var(--radius-full);
  background: var(--color-neutral);
  color: var(--color-neutral-content);
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  line-height: 1;
  text-overflow: clip;
  white-space: nowrap;
}

/* Topbar account control — square circle only (never expand to label width). */
.bao-shell-topbar details.dropdown[data-topbar-user-menu] > summary {
  width: var(--touch-target-min, 2.75rem);
  height: var(--touch-target-min, 2.75rem);
  overflow: hidden;
}
.bao-shell-topbar details.dropdown[data-topbar-user-menu] > summary .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Shell scroll chain — nested daisyUI drawer flex is ignored on WebView 101. */
html.h-full,
html {
  height: 100%;
  max-height: 100%;
  /* tokens.bao typography SSOT — platform-native Apple stack on every surface. */
  font-family: var(--font-sans);
}

body.bao-shell-ambient,
body {
  display: flex;
  flex-direction: column;
  height: 100%;
  max-height: 100%;
  min-height: 0;
  margin: 0;
  overflow: hidden;
  font-family: var(--font-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.bao-shell-drawer {
  flex: 1 1 0%;
  min-height: 0;
  max-height: 100%;
  /*
   * The drawer itself was still `overflow-x: hidden` — a scroll container.
   * Measured on /cases at 1440x900: the topbar account control's tooltip
   * pseudo (111px, absolute, centered under a 44px control) extends 24px
   * past the header's inline end, so the drawer reported scrollWidth 1464
   * in a 1440 box; opening any row menu focused into it and scrolled the
   * whole shell 24px sideways — the sidebar painted at x=-24 with no way
   * back. `clip` keeps the visual clip and removes the scroll container.
   */
  overflow: clip;
}

/*
 * These two are layout columns, not scrollports: `clip`, never `hidden`.
 *
 * `hidden` clips visually but still creates a scroll container the browser may
 * scroll programmatically — a focus() or scrollIntoView() on anything wider
 * than the column shoves the entire content column sideways, with no scrollbar
 * to bring it back. Measured on /cases at 1440x900: .drawer-content sat at
 * scrollLeft 23.5 and its child at 10, so [data-shell-scroll="main"] painted at x=23 while the
 * 56px rail painted over it — elementFromPoint at the breadcrumb's leading
 * edge returned NAV.bao-shell-sidebar, and the breadcrumb lost its leading glyphs.
 *
 * Both axes, not just the inline one. CSS Overflow 3: when one axis is `clip`
 * and the other is neither `clip` nor `visible`, the `clip` computes back to
 * `hidden` — so `overflow-x: clip; overflow-y: hidden` is a no-op that still
 * measures as `hidden` on both. Neither column ever needed to scroll: [data-shell-scroll="main"]
 * is the scrollport, and it is a descendant, so sticky offsets inside it are
 * unaffected by removing the scroll container here.
 *
 * The child already carries the `overflow-x-clip` utility, which asked for
 * exactly this — but that utility lives in @layer utilities while these rules
 * are unlayered, so the `overflow` shorthand silently overrode it.
 */
.bao-shell-drawer > .drawer-content {
  flex: 1 1 0%;
  min-height: 0;
  max-height: 100%;
  overflow: clip;
}

.bao-shell-drawer > .drawer-content > .relative {
  flex: 1 1 0%;
  min-height: 0;
  display: flex;
  flex-direction: column;
  overflow: clip;
}
/* Permanent-rail band (80rem SSOT): [data-shell-scroll="main"] and #session-rail share the
   row — column direction here stacked the rail beneath main and painted it
   over the page content. */
@media (min-width: 80rem) {
  .bao-shell-drawer > .drawer-content > .relative {
    flex-direction: row;
  }
}

[data-shell-scroll="main"] {
  
  
  
  overflow-x: hidden;
  
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
  /* Happydumpling page gutter: section rhythm, not raw rem hardcodes.
   * Do not set padding-block shorthand — dock clearance owns block-end
   * (tokens-layout-dock) so collection pages keep dock+safe-area room. */
  padding-inline: min(var(--page-gutter-inline, var(--space-section, 1rem)), 5%);
  padding-block-start: var(--page-gutter-block, var(--space-section, 0.75rem));
}

/* Main block-end clearance is owned only by tokens-layout-dock. */
/*
 * Immersive media/conversation: zero side/top gutters so workbench fills,
 * but keep dock clearance so shutter/composer never sits under fixed dock.
 * WebView 101 has no :has() — use data-main-page-type mirrored by app-shell JS.
 */
[data-shell-scroll="main"][data-main-page-type="media"],
[data-shell-scroll="main"][data-main-page-type="conversation"],
[data-shell-scroll="main"]:has([data-page-type="media"]),
[data-shell-scroll="main"]:has([data-page-type="conversation"]) {
  
  
  /*
   * Stays hidden at every width. The stacked phone layout does NOT need
   * [data-shell-scroll="main"] to scroll: the acquire panel's own section is already the
   * scrollport (measured on /capture at 320x720 — clientHeight 528,
   * scrollHeight 564), so opening a second one here would nest scrollers for
   * no reachability gain.
   */
  overflow: hidden;
}
/*
 * Mobile-dock material is NOT declared here. tokens-layout-dock-base is the
 * single owner (border/background/color + backdrop-filter). TOKENS_LAYOUT_DOCK_CSS
 * emits after TOKENS_GLASS_CSS (tokens.ts), so a dock surface rule in this
 * module would be dead weight that only looks authoritative.
 */

/* Content primitives declare their own material. Behavioral widget hosts do not paint. */
/* Data panel borders belong to chrome-part, including their image reset. */
.card,
[data-dashboard-widget],
.fieldset.bao-settings-group {
  border-color: var(--border-base, var(--color-base-300));
}

/*
 * Form controls — solid theme vars (no color-mix/oklch required).
 *
 * The boundary is --border-control, not --border-base. These controls paint
 * their background with the panel they sit on, so the border is the ONLY
 * thing that says "this is a field": measured on /api-keys at 1280x800, the
 * input background matched its host exactly (1.00:1) and --border-base gave
 * the outline 1.31:1, against the 3:1 WCAG 2.2 SC 1.4.11 asks of a component
 * boundary. --border-base stays where it belongs — the decorative hairlines
 * between cards and panels, which identify nothing.
 */
.input,
.select,
.textarea,
.file-input {
  background-color: var(--bg-panel, var(--color-base-100));
  color: var(--text-primary, var(--color-base-content));
}
/* Input/select/textarea borders belong to shell-controls-part-1. */
.file-input {
  border-color: var(--border-control, var(--color-base-300));
}
.input::placeholder,
.textarea::placeholder {
  color: var(--text-secondary, var(--color-base-content));
  opacity: var(--opacity-medium, 0.75);
}

/* Button variant paint is owned by shell-controls-part-1. */

body,
body.bao-shell-ambient {
  background-color: var(--bg-app, var(--color-base-100));
  color: var(--text-primary, var(--color-base-content));
}

/* Shell sidebar surface — safe-area insets clear mobile notches and
   rounded desktop edges; smooth scroll honors reduced-motion. */
.bao-shell-sidebar {
  padding-top: max(var(--safe-area-inset-top, var(--space-micro, 0.25rem)), env(safe-area-inset-top));
  padding-bottom: max(var(--safe-area-inset-bottom, var(--space-micro, 0.25rem)), env(safe-area-inset-bottom));
  scroll-behavior: smooth;
}
/*
 * The sidebar surface has ONE owner: the regular Liquid Glass material on
 * .bao-shell-sidebar itself. This block used to paint an opaque var(--bg-panel)
 * plate across the nav list, which covered the entire visible rail and left
 * the material showing only in the padding gutter — glass in the class list,
 * solid on screen. Apple HIG Materials answers legibility over a material
 * with the regular variant ("blurs and adjusts the luminosity of background
 * content") plus vibrant foreground colors, not with an opaque nested plate.
 * WWDC26 Golden Gate: the rail is edge-to-edge. Inner lists and the brand header do not float as inset cards and do not paint a second fill.
 */
.bao-shell-sidebar.bao-shell-sidebar > [data-widget="sidebar"],
.bao-shell-sidebar.bao-shell-sidebar > .menu,
.bao-shell-sidebar.bao-shell-sidebar > ul.menu {
  border-radius: var(--radius-none, 0);
  color: var(--text-primary, var(--color-base-content));
}
.bao-shell-sidebar.bao-shell-sidebar > [data-sidebar-brand],
.bao-shell-sidebar.bao-shell-sidebar > [data-sidebar-rail-header] {
  background: transparent;
  border-radius: var(--radius-none, 0);
}
@media (prefers-reduced-motion: reduce) {
  .bao-shell-sidebar {
    scroll-behavior: auto;
  }
}

/* When measured chrome leaves no interaction row, one outer scrollport owns the entire shell. */
.bao-shell-drawer[data-shell-chrome-flow] > .drawer-content {
  display: block;
  overflow-y: auto;
  overflow-x: clip;
}
.bao-shell-drawer[data-shell-chrome-flow] .bao-shell-topbar {
  position: relative;
}
.bao-shell-drawer[data-shell-chrome-flow] .bao-shell-content {
  flex: none;
  height: auto;
  min-height: min-content;
  overflow: visible;
}
.bao-shell-drawer[data-shell-chrome-flow] [data-shell-scroll="main"] {
  display: block;
  height: auto;
  min-height: min-content;
  overflow: visible;
}
.bao-shell-drawer[data-shell-chrome-flow] [data-shell-scroll="main"] > [data-page] {
  height: auto;
  min-height: min-content;
}
.bao-shell-drawer[data-shell-chrome-flow] .bao-mobile-dock {
  position: relative;
  inset: auto;
}

/*
 * Chat bubble shell chrome (shell-chat fragment) — happydumpling parity
 * hooks, anchored to the shell gutter tokens instead of the upstream
 * bespoke chat-fab vars. The launcher is the ONLY chat entry point in this
 * app (the panel is a peer-checked drawer), so unlike upstream it must not
 * disappear on narrow viewports; it just leaves the safe areas clear.
 */
.bao-chat-fab-launcher {
  position: fixed;
  inset-inline-end: max(var(--space-section, 0.75rem), env(safe-area-inset-right, 0px));
  inset-block-end: max(var(--space-section, 0.75rem), env(safe-area-inset-bottom, 0px));
}

/*
 * The panel and its open-content reserve consume one shared width. The
 * touch-target lane left outside the panel keeps nonmodal tap-away reachable.
 */
:root {
  --chat-panel-inline-size: min(var(--chat-panel-width), calc(100vw - var(--touch-target-min)));
}
.bao-chat-panel {
  inline-size: var(--chat-panel-inline-size);
}


/*
 * Form action rows — full-width labeled verbs on phone (save is primary,
 * never a floating icon-only square under WebView 101 / no-hover).
 */
@media (max-width: 47.99rem) {
  [data-licensing-admin-form] form > .flex.flex-row,
  [data-licensing-serial-admin] form > .flex.flex-row,
  form .flex.flex-row.flex-wrap.items-center.justify-end {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: var(--space-inline, 0.5rem);
  }
  [data-licensing-admin-form] .btn,
  [data-licensing-serial-admin] .btn,
  form .flex.flex-row.flex-wrap.items-center.justify-end > .btn {
    width: 100%;
    min-width: 0;
    min-height: var(--touch-target-min, 2.75rem);
    justify-content: center;
  }
  form .bao-toolbar-action.btn-square {
    width: 100%;
    min-width: 0;
    padding-inline: 0.75rem;
  }
  [data-page-header-actions] > .btn {
    flex: 1 1 auto;
    min-height: var(--touch-target-min, 2.75rem);
    justify-content: center;
  }
}


@media (max-width: 47.99rem) {
  /* Freeze infinite motion that reflows under HTMX load on Chromium 101. */
  .skeleton-shimmer,
.htmx-added,
[data-page] [data-state-content] {
    animation: none;
  }
}


/* Later material rules reuse the same selectors. A media query adds no
   specificity, so the earlier none lost to the blur that follows it.
   This restatement is the last owner: reduced transparency, increased
   contrast, reduced motion, and forced colors keep a solid surface. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more), (prefers-reduced-motion: reduce) {
  :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal,
    .bao-surface-glass-regular.bao-glass-large,
    .bao-surface-glass-clear.bao-glass-large,
    .bao-surface-glass-regular.bao-glass-small,
    .bao-surface-glass-clear.bao-glass-small,
    .bao-shell-topbar.navbar,
    .bao-shell-topbar
  ),
  :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal
  ):is(
    :disabled,
    [aria-disabled="true"],
    :disabled:hover,
    [aria-disabled="true"]:hover,
    :disabled:focus-within,
    [aria-disabled="true"]:focus-within
  ) {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
@media (forced-colors: active) {
  :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal,
    .bao-surface-glass-regular.bao-glass-large,
    .bao-surface-glass-clear.bao-glass-large,
    .bao-surface-glass-regular.bao-glass-small,
    .bao-surface-glass-clear.bao-glass-small,
    .bao-shell-topbar.navbar,
    .bao-shell-topbar
  ),
  :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal
  ):is(:disabled, [aria-disabled="true"]) {
    color: CanvasText;
    background: Canvas;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
html[data-reduced-transparency="true"] :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-small,
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-shell-topbar.navbar,
  .bao-shell-topbar
),
html[data-high-contrast="true"] :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-small,
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-shell-topbar.navbar,
  .bao-shell-topbar
),
html[data-reduced-motion="true"] :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-small,
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-shell-topbar.navbar,
  .bao-shell-topbar
),
html[data-reduced-transparency="true"] :is(.bao-surface-glass-regular, .bao-surface-glass-clear, .bao-surface-glass-strong, .bao-surface-glass-modal):is(:disabled, [aria-disabled="true"]),
html[data-high-contrast="true"] :is(.bao-surface-glass-regular, .bao-surface-glass-clear, .bao-surface-glass-strong, .bao-surface-glass-modal):is(:disabled, [aria-disabled="true"]),
html[data-reduced-motion="true"] :is(.bao-surface-glass-regular, .bao-surface-glass-clear, .bao-surface-glass-strong, .bao-surface-glass-modal):is(:disabled, [aria-disabled="true"]) {
  background: var(--bg-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Framed solid panels retain their own fill; unframed DataSections do not opt in. */
.bao-data-panel {
  background: var(--bg-panel, var(--color-base-100));
}

}
@layer bao-tokens {

/*
 * WebKit hardening: daisyUI emits unprefixed `appearance: none` only, so iOS
 * Safari still paints the NATIVE checkbox/toggle/select control UNDER the
 * styled one (the doubled toggle: outline pill + filled native square). The
 * prefixed reset is required on every appearance-styled control — this is the
 * single SSOT owner (never a per-page override).
 */
/* Specificity above daisyUI .checkbox { appearance: none } alone so WebKit
 * never reverts to native double-paint under dialog stacking (audit:structure
 * dialog@phone native-control-paint). Input-typed selectors win UA+daisy. */
.toggle,
input.toggle[type="checkbox"],
.checkbox,
input.checkbox[type="checkbox"],
.radio,
input.radio[type="radio"],
.select,
select.select,
.range,
input.range[type="range"],
.file-input,
input.file-input[type="file"] {
  -webkit-appearance: none;
  appearance: none;
}
/* The input retains the shared touch floor. Track and thumb paint have their
 * own geometry: growing the input must never grow the filled slider shadow.
 * Engine pseudo-elements remain separate because an unsupported selector
 * invalidates the entire selector list in older WebViews. */
input.range[type="range"] {
  background-color: transparent;
  background-image: none;
  overflow: visible;
  clip-path: none;
  padding: 0;
}
input.range[type="range"]::-webkit-slider-runnable-track {
  display: block;
  height: var(--space-micro);
  border-radius: var(--radius-selector);
  background-color: var(--border-control);
  background-image: none;
}
input.range[type="range"]::-moz-range-track {
  display: block;
  height: var(--space-micro);
  border-radius: var(--radius-selector);
  background-color: var(--border-control);
  background-image: none;
}
input.range[type="range"]::-webkit-slider-thumb {
  /* Native margin owns centering; component inset/transform must not shift it again. */
  inset-block-start: 0;
  transform: none;
  -webkit-appearance: none;
  appearance: none;
  width: var(--space-xl);
  height: var(--space-xl);
  margin-block-start: calc((var(--space-micro) - var(--space-xl)) / 2);
  border: var(--border) solid var(--border-control);
  border-radius: var(--radius-full);
  background-color: var(--bg-panel);
  background-image: none;
  box-shadow: var(--shadow-sm);
  clip-path: none;
}
input.range[type="range"]::-moz-range-thumb {
  width: var(--space-xl);
  height: var(--space-xl);
  border: var(--border) solid var(--border-control);
  border-radius: var(--radius-full);
  background-color: var(--bg-panel);
  background-image: none;
  box-shadow: var(--shadow-sm);
  clip-path: none;
}

/*
 * Checkbox affordance: daisyUI couples checkbox+toggle radius on one
 * --radius-selector token; at the theme's capsule value a small checkbox
 * reads as a RADIO (multi-select sections looked single-choice). Toggles
 * keep the capsule; the checkbox mark caps at the canon 0.25rem step so
 * square = multi-select, circle = single-select stays legible. Single
 * owner — never per-page.
 */
/* Switch tracks and thumbs share the capsule token; checkbox corners remain separate. */
.toggle {
  --radius-selector: 9999px;
}
/* Track carries the state; the thumb remains a single white circular surface. */
input.toggle[type="checkbox"] {
  background-color: var(--bg-surface-hover);
  background-image: none;
  border-color: var(--border-control);
  box-shadow: none;
}
input.toggle[type="checkbox"]:checked {
  background-color: var(--color-primary);
  border-color: var(--color-primary);
}
input.toggle[type="checkbox"]::before,
input.toggle[type="checkbox"]:checked::before {
  background-color: var(--white);
  background-image: none;
  color: var(--white);
  box-shadow: var(--shadow-sm);
  outline: none;
}
@media (forced-colors: active) {
  input.toggle[type="checkbox"] {
    background-color: Canvas;
    border-color: ButtonText;
  }
  input.toggle[type="checkbox"]:checked {
    background-color: Highlight;
    border-color: Highlight;
  }
  input.toggle[type="checkbox"]::before,
  input.toggle[type="checkbox"]:checked::before {
    background-color: ButtonText;
    box-shadow: none;
  }
}

.checkbox {
  /*
   * Published as a custom property, not just applied: the painted affordance
   * is drawn by `.checkbox.bao-touch-target::after`, and a pseudo-element
   * inherits its originating element's custom properties. Declaring the cap
   * here and reading it there keeps ONE owner for the shape. It was applied
   * here alone once, and the pseudo went on resolving --radius-selector
   * directly — so the input the reader cannot see was square while the box
   * the reader does see stayed a 12px circle on a 24px mark, i.e. a radio.
   */
  --checkbox-mark-radius: min(var(--radius-selector, 0.25rem), var(--radius-xs, 0.25rem));
  border-radius: var(--checkbox-mark-radius);
}
/* WebView button metrics retain component display ownership so semantic
 * visibility rules remain authoritative. Variant selectors keep equal specificity.
 * `.bao-fab` owns radius and band display in the dock/FAB tokens — leaving it
 * in this (0,3,0) rule forced a quadruple-class outrank. */
.btn:not([hidden]):not(.hidden):not(.bao-fab) {
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--button-content-gap, var(--space-compact, 0.375rem));
  border-width: 1px;
  border-style: solid;
  font-weight: var(--font-weight-medium);
  font-size: var(--text-sm);
  line-height: var(--leading-snug);
  padding: var(--space-inline) var(--button-inline-padding, var(--space-section));
  text-decoration: none;
  cursor: pointer;
  box-sizing: border-box;
}
/* A daisyUI swap that is also a button keeps the swap's single-cell grid so
 * its icon slots stack and cross-fade in place. The component
 * inline-flex display would lay the slots out side by side (measured on the
 * public theme control: the active icon sat 8px off-centre and overflowed
 * the 44px button once the checkbox became a real in-cell target). Equal
 * specificity, declared later, so only display and centring change. */
.btn.swap:not([hidden]):not(.hidden) {
  display: inline-grid;
  place-content: center;
}


/* Labeled controls grow around wrapped captions; explicit icon shapes keep their dimensions. */
.btn:not([hidden]):not(.hidden):not(.bao-fab):not(.btn-circle):not(.btn-square) {
  height: auto;
}

/* Shared button geometry and material composition; variants own palette paint. */
.btn:where(:not([hidden]):not(.hidden):not(.bao-fab)) {
  justify-content: center;
  background-image: var(--button-material-sheen, none);
  box-shadow: var(--button-material-shadow, none);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  flex-wrap: wrap;
  white-space: normal;
  overflow-wrap: break-word;
  max-inline-size: 100%;
}
.btn:where(:not([hidden]):not(.hidden)) .truncate {
  white-space: nowrap;
  max-inline-size: 100%;
}
/* Chrome controls receive illumination from their declared navigation owner.
 * Content and form buttons keep their declared variant paint. The host owns frost. */
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) :where([data-shell-topbar], [data-mobile-dock], [data-primitive="Toolbar"]) .btn:where(:not(:disabled):not([aria-disabled="true"]):not(.btn-disabled):not(.btn-ghost):not(.btn-link)) {
    --button-neutral-fill: var(--glass-control-fill);
    --button-tint-opacity: var(--glass-button-tint-opacity);
    --button-material-sheen: linear-gradient(var(--lg-pointer-angle), var(--glass-button-highlight), var(--glass-highlight-clear) 52%, var(--glass-illumination-soft));
    --button-material-shadow: var(--shadow-glass-clear), var(--shadow-glass-inner);
  }
}

/* Hidden controls retain their semantic state independently of button styling. */
.btn[hidden],
.btn.hidden,
button.btn[hidden],
button.btn.hidden,
[hidden].btn,
button.hidden,
button[hidden] {
  display: none;
}

.btn svg {
  width: 1rem;
  height: 1rem;
  flex: 0 0 auto;
}

/* Declared semantic variants own button palette paint. */
.btn-primary:not([hidden]):not(.hidden),
.btn.btn-primary:not([hidden]):not(.hidden),
.btn:where([data-training-submit-open])[aria-disabled="false"]:not([hidden]):not(.hidden) {
  background-color: var(--color-primary);
  background-color: color-mix(in oklab, var(--color-primary) calc(var(--button-tint-opacity, 1) * 100%), transparent);
  border-color: var(--color-primary);
  color: var(--color-primary-content);
}

.btn-error:not([hidden]):not(.hidden),
.btn.btn-error:not([hidden]):not(.hidden) {
  background-color: var(--color-error);
  background-color: color-mix(in oklab, var(--color-error) calc(var(--button-tint-opacity, 1) * 100%), transparent);
  border-color: var(--color-error);
  color: var(--color-error-content);
}

.btn-success:not([hidden]):not(.hidden),
.btn.btn-success:not([hidden]):not(.hidden) {
  background-color: var(--color-success);
  background-color: color-mix(in oklab, var(--color-success) calc(var(--button-tint-opacity, 1) * 100%), transparent);
  border-color: var(--color-success);
  color: var(--color-success-content);
}

.btn-warning:not([hidden]):not(.hidden),
.btn.btn-warning:not([hidden]):not(.hidden) {
  background-color: var(--color-warning);
  background-color: color-mix(in oklab, var(--color-warning) calc(var(--button-tint-opacity, 1) * 100%), transparent);
  border-color: var(--color-warning);
  color: var(--color-warning-content);
}

/* Link actions retain their canonical text treatment inside shared button geometry. */
.btn.btn-link:not([hidden]):not(.hidden) {
  background-color: transparent;
  border-color: transparent;
  color: var(--color-primary);
  text-decoration: underline;
}

.btn-outline:not([hidden]):not(.hidden),
.btn.btn-outline:not([hidden]):not(.hidden) {
  background-color: transparent;
  border-color: var(--border-base, var(--color-base-300));
  color: var(--text-primary, var(--color-base-content));
}

.btn-soft:not([hidden]):not(.hidden),
.btn.btn-soft:not([hidden]):not(.hidden),
.btn:where([data-training-submit-open])[aria-disabled="true"]:not([hidden]):not(.hidden) {
  background-color: var(--button-neutral-fill, var(--bg-surface));
  border-color: var(--border-base);
  color: var(--text-primary, var(--color-base-content));
}

/* Hover is a fine-pointer enhancement (design.pdf §6) — touch keeps the
   resting fill and acknowledges presses via the :active rule below. */
@media (hover: hover) and (pointer: fine) {
  .btn-soft:not([hidden]):not(.hidden):hover,
  .btn.btn-soft:not([hidden]):not(.hidden):hover,
  .btn:where([data-training-submit-open])[aria-disabled="true"]:not([hidden]):not(.hidden):hover {
    background-color: var(--bg-surface-hover);
    border-color: var(--border-control);
  }
}

.btn-soft:not([hidden]):not(.hidden):active,
.btn.btn-soft:not([hidden]):not(.hidden):active,
.btn:where([data-training-submit-open])[aria-disabled="true"]:not([hidden]):not(.hidden):active,
.btn-soft:not([hidden]):not(.hidden).btn-active,
.btn.btn-soft:not([hidden]):not(.hidden).btn-active,
.btn:where([data-training-submit-open])[aria-disabled="true"]:not([hidden]):not(.hidden).btn-active,
.btn-soft:not([hidden]):not(.hidden)[aria-pressed="true"],
.btn.btn-soft:not([hidden]):not(.hidden)[aria-pressed="true"],
.btn:where([data-training-submit-open])[aria-disabled="true"]:not([hidden]):not(.hidden)[aria-pressed="true"] {
  background-color: var(--bg-surface-hover);
  border-color: var(--border-control);
  color: var(--color-base-content);
}

/* Filled segmented tabs use primary; border tabs retain their underline treatment.
   Session mode tabs are single-owned by tokens-glass-shell-capture (the
   reactive-state-owner gate) — only the generic canon arm may touch them. */
.tab.tab-active:not([hidden]):not(.hidden):not(.tabs-border > *),
.tab[aria-selected="true"]:not([hidden]):not(.hidden):not(.tabs-border > *),
.bao-settings-tab[aria-selected="true"]:not([hidden]):not(.hidden):not(.tabs-border > *),
.bao-settings-tab.tab-active:not([hidden]):not(.hidden):not(.tabs-border > *) {
  background: var(--color-primary);
  border-color: var(--color-primary);
  color: var(--color-primary-content);
}

.btn-primary:not([hidden]):not(.hidden):active,
.btn.btn-primary:not([hidden]):not(.hidden):active,
.btn:where([data-training-submit-open])[aria-disabled="false"]:not([hidden]):not(.hidden):active,
.btn-primary:not([hidden]):not(.hidden)[aria-pressed="true"],
.btn.btn-primary:not([hidden]):not(.hidden)[aria-pressed="true"],
.btn:where([data-training-submit-open])[aria-disabled="false"]:not([hidden]):not(.hidden)[aria-pressed="true"] {
  background-color: color-mix(in oklab, var(--color-primary) calc(var(--glass-button-tint-opacity) * 100%), var(--color-base-content));
  border-color: color-mix(in oklab, var(--color-primary) calc(var(--glass-button-tint-opacity) * 100%), var(--color-base-content));
  color: var(--color-primary-content);
}

/* Ensure soft/ghost/outline remain hit-testable even under dense shell CSS. */
.btn:not([hidden]):not(.hidden):not(:disabled):not([aria-disabled="true"]) {
  pointer-events: auto;
  cursor: pointer;
}

/* Dense daisyUI sizes yield to the canonical touch-target utility. */
.btn:not([hidden]):not(.hidden):not(.bao-touch-target) {
  min-height: 2.5rem;
  padding: 0.5rem 0.875rem;
  font-size: var(--text-sm, 0.875rem);
  line-height: 1.2;
}

.btn-sm:not([hidden]):not(.hidden):not(.bao-touch-target),
.btn-xs:not([hidden]):not(.hidden):not(.bao-touch-target) {
  min-height: 2rem;
  padding: 0.25rem 0.625rem;
  font-size: var(--text-sm, 0.875rem);
}

.btn-square:not([hidden]):not(.hidden):not(.bao-touch-target) {
  width: 2.5rem;
  min-width: 2.5rem;
  padding-inline: 0;
}

/* Canonical touch floor yields to component minimums; visibility guards add no specificity. The floor reads the
 * touch-target token — max(2.75rem, 44px), single-owned in tokens.bao /
 * design-canon liquidGlass.hig — so it never drops below the 44px HIG
 * minimum and grows with the root text scale (Dynamic Type). At extreme
 * text scales controls grow and layouts reflow or scroll; capping the
 * floor with min() would shrink hit targets below 44px, which the HIG
 * canon gate (validate-hig-surface-conformance-canons) rejects. */
.bao-touch-target:where(:not([hidden]):not(.hidden)) {
  min-height: var(--touch-target-min, 2.75rem);
}
.bao-touch-target:not([hidden]):not(.hidden) {
  min-width: var(--touch-target-min, 2.75rem);
}

/*
 * The square width applies only where the control is genuinely icon-only.
 *
 * This is a 44px touch FLOOR, not a cap, and it was acting as both. At
 * (0,4,0) it outranked the labeled-density contract at (0,3,0) — so a toolbar
 * that declared data-toolbar-density="labeled" revealed its caption and then
 * painted it inside a box pinned to 44px. Measured on the editor dock:
 * "Rectangle" natural width 59px, button 44px, and an inline width:auto probe
 * returned 97px, proving the layout was fine and only this rule was in the
 * way. Six modules clipped that label; this is the one that actually won.
 *
 * min-width keeps the WCAG 2.5.8 / HIG floor intact for labelled controls too.
 *
 * The cap outlived that fix. Excluding only labelled density left it capping
 * every deliberately-larger variant, and the capture shutter is one: it
 * declares `btn-circle btn-lg` and its own rule asks for 3.5rem square, but
 * this selector scores (0,5,0) against that rule's (0,2,0), so the width was
 * clamped to 44px while the height it does not touch stayed at 56px.
 * Measured on /capture at 1440x900: the sole primary action of the page, the
 * shutter, rendered 44x56 — a vertical rectangle, the only control on the
 * surface whose height was not 44, and not the circle its classes describe.
 *
 * `btn-lg`/`btn-xl` are excluded for the same reason labelled density is: a
 * control that asked to be large is not an icon button, and a floor may not
 * decide its size. The sibling coarse-pointer rule below already draws the
 * line in exactly this place.
 */
.btn-square.bao-touch-target:not([hidden]):not(.hidden):not(.btn-lg):not(.btn-xl):not([data-toolbar-density="labeled"] *),
.btn-circle.bao-touch-target:not([hidden]):not(.hidden):not(.btn-lg):not(.btn-xl):not([data-toolbar-density="labeled"] *) {
  width: var(--touch-target-min, 2.75rem);
  min-width: var(--touch-target-min, 2.75rem);
  padding-inline: 0;
  --button-content-gap: 0px;
}
[data-toolbar-density="labeled"] .btn-square.bao-touch-target:not([hidden]):not(.hidden) {
  width: auto;
  min-width: var(--touch-target-min, 2.75rem);
}

/* Enforce the touch floor on coarse pointers without shrinking larger variants. */
@media (pointer: coarse), (hover: none) {
  .btn:not([hidden]):not(.hidden):not(.bao-touch-target):not(.btn-lg):not(.btn-xl),
  .btn.btn-sm:not([hidden]):not(.hidden):not(.bao-touch-target),
  .btn.btn-xs:not([hidden]):not(.hidden):not(.bao-touch-target) {
    min-height: var(--touch-target-min, 2.75rem);
  }
  .btn.btn-circle:not([hidden]):not(.hidden):not(.bao-touch-target),
  .btn.btn-square:not([hidden]):not(.hidden):not(.bao-touch-target) {
    min-width: var(--touch-target-min, 2.75rem);
  }
  /* Text controls join the floor — input-sm/select-sm computed 30-36px on
     phones (WCAG 2.5.8 / design.pdf §8.2 primary mobile controls 44-48). */
  .input:not([hidden]):not(.hidden),
  .select:not([hidden]):not(.hidden),
  .range:not([hidden]):not(.hidden) {
    min-height: var(--touch-target-min, 2.75rem);
  }
}

/*
 * Switch/checkbox/radio target floor (ALL pointers — not coarse-only).
 * Playwright audits measure the INPUT border box; packing toggle-sm (≈20px)
 * next to another control failed WCAG 2.5.8 on phone-narrow. Keep daisyUI 5
 * pill morphology (≈2:1 track, thumb slides on grid) — never force a 44×44
 * square that collapses the thumb animation. Floor: mark ≥24px (WCAG 2.5.8);
 * label row ≥44px isolates packing so the spacing exception is not required.
 */
.toggle:not([hidden]):not(.hidden),
.checkbox:not([hidden]):not(.hidden),
.radio:not([hidden]):not(.hidden) {
  position: relative;
  flex: 0 0 auto;
  box-sizing: border-box;
  min-height: 1.5rem;
  min-width: 1.5rem;
}
/*
 * The switch is sized through daisyUI's own variable, never by pinning width
 * and height.
 *
 * daisyUI 5 derives the whole control from `--size`:
 * `width: calc((var(--size) * 2) - (var(--border) + var(--toggle-p)) * 2)`,
 * `height: var(--size)`, `--toggle-p: calc(var(--size) * 0.125)`, and the knob
 * rides a `grid-template-columns: 0fr 1fr 1fr` track. Hand-set width/height
 * moved the track without moving that math: measured on /reports, a switch
 * carrying the generic 44pt floor computed 44x44 with `padding: 10px 3px` and
 * a 24px knob, so the knob overflowed a square track and the control read as
 * half-drawn. The previous fix layered a second 1.5rem track on `::after` and
 * `border: 0` on the real one, which hid the symptom and left two elements
 * claiming to be the same switch.
 *
 * Raising `--size` to the touch floor keeps the 2:1 pill, scales knob, padding
 * and corner radius together, and satisfies WCAG 2.2 SC 2.5.8 on BOTH axes —
 * the 44x24 track this replaced met the floor only horizontally.
 */
.toggle.bao-touch-target:not([hidden]):not(.hidden) {
  --size: var(--touch-target-min, 2.75rem);
  max-inline-size: 100%;
}
/* Label rows that host a switch grow to the touch floor so packing is isolated. */
.label:has(> .toggle),
.label:has(> .checkbox),
.label:has(> .radio) {
  min-height: var(--touch-target-min, 2.75rem);
  align-items: center;
  gap: var(--space-inline, 0.5rem);
}

/*
 * Touch: labeled square buttons may grow for visible verbs. Icon-only shell
 * chrome (bao-shell-icon-action) stays fixed — reasserted in topbar-icons CSS.
 */
@media (hover: none), (pointer: coarse) {
  .btn-square:not([hidden]):not(.hidden):not(.bao-shell-icon-action) {
    width: auto;
    min-width: var(--touch-target-min, 2.75rem);
    min-height: var(--touch-target-min, 2.75rem);
    padding-inline: 0.625rem;
  }
}

/* Sticky toolbar under shell chrome — tokenized offset with no arbitrary positioning utility. */
.bao-sticky-toolbar {
  position: sticky;
  top: calc(var(--chrome-min-height, max(2.75rem, 44px)) + env(safe-area-inset-top, 0px));
}

/* AI analysis overlay stage — reserved geometry (CLS), no min-h-48 raw utility. */
.bao-min-h-overlay-stage {
  min-height: var(--overlay-stage-min-height, 12rem);
}

/* Stage empty CTA only while state is empty (success paints canvas overlays). */
[data-ai-analysis-overlay-stage]:not([data-state="empty"]) [data-ai-analysis-overlay-empty] {
  display: none;
}

/* Textarea default height — tokenized (no min-h-32 raw utility). */
.textarea.bao-min-h-textarea {
  min-block-size: var(--textarea-min-height, 8rem);
}
/* Composer sizing belongs with textarea controls, above generic touch floors. */
.textarea.bao-min-h-composer {
  min-block-size: var(--composer-min-height);
}

/* PageHeader grid, H1, and phone collapse live in
 * tokens-glass-shell-page-header.ts (400-LOC monolith gate). */

/* background-color LONGHAND only: the background shorthand resets
 * background-image and erases the daisyUI select caret gradients app-wide
 * (unlayered rule beats the layered component). Selects also keep the
 * 1.75rem inline-end pad — that band IS the caret zone. */
.input,
.select {
  min-height: 2.5rem;
}
.input,
.select,
.textarea {
  align-items: center;
  gap: var(--space-inline);
  /*
   * --border-control, matching the shorthand-free declaration in
   * tokens-glass-shell-webview-surfaces. Both rules sit in @layer bao-tokens
   * at equal specificity, so the later one decides — and while this one still
   * named --border-base, moving the other to the control token changed
   * nothing on screen. A field's border is its only affordance: measured on
   * /reports, the control background matched its host exactly and this border
   * gave the outline 1.31:1 in light and 1.46:1 in dark, against the 3:1 WCAG
   * 2.2 SC 1.4.11 asks of a component boundary.
   */
  border: var(--control-border-width, 1px) solid var(--border-control, var(--color-base-300));
  /*
   * Four corners, for the reason the base `.btn` rule states above: a text
   * field is joined too. The specimen and login search rows compose
   * `input input-sm … join-item grow` against a trailing button, and a
   * `border-radius` shorthand from this layer resolved all four corners, so
   * the field kept its full radius where it meets the button and the pair
   * read as two controls that happen to touch. Outside a `.join` the four
   * variables are unset and every corner still resolves to `--radius-field`.
   */
  border-start-start-radius: var(--join-ss, var(--radius-field));
  border-start-end-radius: var(--join-se, var(--radius-field));
  border-end-start-radius: var(--join-es, var(--radius-field));
  border-end-end-radius: var(--join-ee, var(--radius-field));
  /* Form-control paint is owned by webview-surfaces. */
  font-size: var(--text-sm, 0.875rem);
  box-sizing: border-box;
}
.textarea {
  --field-control-radius: 1.25rem;
}
/*
 * Validation and tone states keep their semantic border by re-pointing the
 * control boundary token, not by declaring a second border: the control rule
 * above stays the single owner of the boundary (control-affordance-contrast).
 * Before this, `.input-error`, `.validator:user-invalid` and
 * `aria-invalid="true"` all rendered the neutral control border: measured on
 * the public quote request form, a rejected required field kept
 * rgb(155 157 161) while the error token stayed unused, so an invalid field
 * looked valid. Wrapper fields (a label.input around its input) follow the
 * state of the control they contain.
 */
:is(.input, .select, .textarea):is(
  .input-error,
  .select-error,
  .textarea-error,
  [aria-invalid="true"],
  :user-invalid,
  :has(:is([aria-invalid="true"], :user-invalid))
) {
  --border-control: var(--status-error);
}
:is(.input, .select, .textarea):is(.input-warning, .select-warning, .textarea-warning) {
  --border-control: var(--status-warning);
}
:is(.input, .select, .textarea):is(.input-success, .select-success, .textarea-success) {
  --border-control: var(--status-success);
}
/*
 * The validation runtime swaps a field hint for its error message and keeps
 * the original copy in `data-validation-hint`. While the field is invalid the
 * message reads as an error, not as muted helper text; the text itself
 * carries the meaning, so colour is never the only signal.
 */
[aria-invalid="true"] ~ [data-validation-hint] {
  color: var(--color-error);
}
:where(.input, .select, .textarea).border-0 {
  --control-border-width: 0px;
  box-shadow: none;
}
.select {
  padding-inline-end: 1.75rem;
}

.input-sm,
.select-sm {
  min-height: 2.25rem;
  padding: 0.375rem 0.625rem;
  font-size: var(--text-sm, 0.875rem);
}
.select-sm {
  padding-inline-end: 1.75rem;
}

/* Inline filter controls share the parent content plane; the open sheet owns its surface. */
[data-case-filters],
[data-primitive="FilterBar"] {
  padding: var(--space-inline) 0;
  gap: var(--space-inline);
  border: 0;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
}
/*
 * FilterBar host layout is CSS-only (FilterBar.bao no longer bakes flex/wrap).
 * Desktop/tablet: horizontal wrap row. Phone: 2-col grid (cascade owner late).
 */
form[data-case-filters],
form[data-primitive="FilterBar"],
form[data-filter-bar],
[data-case-filters],
[data-primitive="FilterBar"],
[data-filter-bar] {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  width: 100%;
  min-width: 0;
}


/* Disabled controls remain legible while clearly leaving the active action hierarchy. */
.btn:disabled:not([hidden]):not(.hidden),
.btn[aria-disabled="true"]:not([hidden]):not(.hidden),
.btn.btn-disabled:not([hidden]):not(.hidden) {
  background: color-mix(in oklab, var(--bg-panel, var(--color-base-100)) 88%, var(--color-base-200));
  border-color: var(--border-base, var(--color-base-300));
  color: var(--text-secondary, var(--color-base-content));
  box-shadow: none;
  cursor: not-allowed;
  opacity: var(--opacity-disabled, 0.5);
}
@media (max-width: 47.99rem) {
  form[data-case-filters]:not([data-filter-sheet-open="true"]),
  form[data-primitive="FilterBar"]:not([data-filter-sheet-open="true"]),
  form[data-filter-bar]:not([data-filter-sheet-open="true"]),
  [data-case-filters]:not([data-filter-sheet-open="true"]),
  [data-primitive="FilterBar"]:not([data-filter-sheet-open="true"]),
  [data-filter-bar]:not([data-filter-sheet-open="true"]) {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: end;
    gap: var(--space-micro);
    flex-wrap: unset;
  }
form[data-case-filters] fieldset:has(input[type="search"]),
form[data-case-filters] fieldset:has([data-case-search]),
[data-case-filters] fieldset:has(input[type="search"]),
[data-case-filters] .fieldset:has(input[type="search"]),
[data-case-filters] fieldset:has([data-case-search]),
[data-primitive="FilterBar"] fieldset:has(input[type="search"]),
[data-primitive="FilterBar"] .fieldset:has(input[type="search"]),
[data-primitive="FilterBar"] fieldset:has([data-filter-search]),
[data-filter-bar] fieldset:has(input[type="search"]) {
    grid-column: 1 / -1;
  }
  /* Only SEARCH legends are AT-only on phone (placeholder carries the cue).
     Select legends stay visible: status and priority both default to "All",
     so value-only selects are ambiguous side by side (HIG: controls
     identifiable without a tooltip). */
  form[data-case-filters] fieldset:has(input[type="search"]) .fieldset-legend,
  form[data-case-filters] fieldset:has(input[type="search"]) legend,
  form[data-case-filters] fieldset:has([data-case-search]) .fieldset-legend,
  form[data-case-filters] fieldset:has([data-case-search]) legend,
  [data-case-filters] fieldset:has(input[type="search"]) .fieldset-legend,
  [data-case-filters] fieldset:has(input[type="search"]) legend,
  [data-case-filters] fieldset:has([data-case-search]) .fieldset-legend,
  [data-case-filters] fieldset:has([data-case-search]) legend,
  [data-primitive="FilterBar"] fieldset:has(input[type="search"]) .fieldset-legend,
  [data-primitive="FilterBar"] fieldset:has(input[type="search"]) legend,
  [data-primitive="FilterBar"] fieldset:has([data-filter-search]) .fieldset-legend,
  [data-primitive="FilterBar"] fieldset:has([data-filter-search]) legend {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
}


[data-case-filters] legend,
[data-case-filters] .fieldset-legend {
  padding: 0;
  /* Sentence case — HIG typography: all-caps/tracking-eyebrow labels shout
     and hurt legibility; the settings SSOT already moved to sentence case
     (Apple HIG: avoid shouting labels). Same here, same reason. */
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
  letter-spacing: normal;
  text-transform: none;
  color: var(--text-secondary);
}

[data-case-filters] fieldset,
[data-case-filters] .fieldset,
[data-primitive="FilterBar"] fieldset,
[data-primitive="FilterBar"] .fieldset {
  display: flex;
  /*
   * flex-basis must stay auto. A fixed rem basis becomes HEIGHT when the bar
   * is flex-direction:column on phone — ADB S26 measured ~192px voids under
   * Debug Search. Inline min uses tokens.bao --grid-context-min only.
   */
  flex: 0 1 auto;
  flex-direction: column;
  gap: var(--space-micro);
  min-width: min(100%, var(--grid-context-min));
  margin: 0;
  padding: 0;
  border: 0;
}

@media (min-width: 48rem) {
  [data-case-filters] > fieldset,
  [data-case-filters] > .fieldset,
  [data-primitive="FilterBar"] > fieldset,
  [data-primitive="FilterBar"] > .fieldset {
    flex: 1 1 var(--grid-context-min);
    min-width: 0;
  }
}

/* Expanded disclosures leave the filter row and lay their fields out responsively. */
[data-primitive="FilterBar"] > details[open] {
  flex: 1 0 100%;
  grid-column: 1 / -1;
}
[data-primitive="FilterBar"] > details[open] > :not(summary) {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-context-min)), 1fr));
  align-items: end;
  gap: var(--space-inline);
}

/* Phone FilterBar fields fill their grid track without growing vertically. */
@media (max-width: 47.99rem) {
  [data-case-filters] fieldset,
  [data-case-filters] .fieldset,
  [data-primitive="FilterBar"] fieldset,
  [data-primitive="FilterBar"] .fieldset,
  [data-filter-bar] fieldset,
  [data-filter-bar] .fieldset {
    flex: 0 0 auto;
    min-width: 0;
    width: 100%;
    max-width: none;
    min-height: 0;
  }
  [data-case-filters] .bao-field-basis,
  [data-primitive="FilterBar"] .bao-field-basis,
  [data-filter-bar] .bao-field-basis {
    flex-basis: auto;
  }
}

/*
 * Case list, case card, case status, context card, context grid,
 * card/card-body/card-title, dashboard widget — all SSoT in
 * tokens-layout-page-shell-surfaces.ts (token-driven, no hardcoded hex).
 * Do NOT redefine them here.
 */

/* Conversation composer — unique WebView harden (no token source). */
[data-page="chat"] .bao-conversation-composer,
[data-page-type="conversation"] [data-composer] {
  border: 1px solid var(--border-base);
  border-radius: var(--radius-field, 0.75rem);
  background: var(--bg-panel);
  box-shadow: 0 4px 16px color-mix(in oklab, var(--color-neutral, var(--color-base-content)) 10%, transparent);
}



}
@layer bao-tokens {

/*
 * PageHeader follows the enterprise-page.bao title/action grid.
 *
 * `:not(.sr-only)` because a conversation page demotes its header to the
 * document outline — pages-renderers-header emits `class="sr-only"` on the
 * same element that still carries `data-primitive="PageHeader"` for the state
 * contract. `.sr-only` lives in @layer utilities and this grid lives in
 * @layer bao-tokens, so the grid won on width and margin and the hidden
 * header laid out at `width: 100%` with a painted `margin-block-end`.
 * Measured on /chat at 1280x800: the 1px-tall clipped node was 956px wide
 * inside a 902px shell and pushed #app-main to scrollWidth 982 against
 * clientWidth 956 — 26px of horizontal scroll owned by something no reader
 * can see. A header that paints nothing owns no painted layout.
 */
/* Breadcrumbs reserve the full touch-target height in PageHeader.bao.
 * Clip the block axis so horizontal trail scrolling never creates a nested
 * vertical scroll region; links fit within the declared navigation height. */
.breadcrumbs {
  overflow-y: clip;
}

.bao-page-header:not(.sr-only),
[data-primitive="PageHeader"]:not(.sr-only) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: end;
  justify-items: stretch;
  column-gap: var(--space-section, 0.75rem);
  row-gap: var(--space-inline, 0.5rem);
  margin-block-end: var(--space-section, 0.75rem);
  width: 100%;
  min-width: 0;
  text-align: start;
}

@media (min-width: 40rem) {
  .bao-page-header:not(.sr-only),
  [data-primitive="PageHeader"]:not(.sr-only) {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

/* A content heading and its commands share one intrinsic row. Flex wrapping
 * follows available space instead of forcing a second band on every phone. */
[data-primitive="PageHeader"][data-page-header-mode="content"] {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
}
[data-primitive="PageHeader"][data-page-header-mode="content"] > div:first-child {
  flex-basis: auto;
}

/* Header action row — touch targets without arbitrary child selectors in tokens. */
.bao-page-header-actions > .btn {
  min-height: var(--touch-target-min, 2.75rem);
}

[data-primitive="PageHeader"] > .flex.min-w-0.flex-col,
[data-primitive="PageHeader"] > div:first-child {
  min-width: 0;
  justify-self: stretch;
  text-align: start;
}

[data-page-header-actions],
[data-primitive="PageHeader"] [data-page-header-actions] {
  /* Action contents own width; breakpoint shards must not claim a whole row. */
  inline-size: fit-content;
  flex: 0 1 auto;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-start;
  gap: var(--space-micro, 0.25rem);
  min-width: 0;
  max-width: 100%;
}

@media (min-width: 40rem) {
  [data-page-header-actions],
  [data-primitive="PageHeader"] [data-page-header-actions] {
    justify-content: flex-end;
    justify-self: end;
  }
}

[data-page-header-actions] .btn {
  flex-direction: row;
}

[data-primitive="PageHeader"] h1 {
  margin: 0;
  font-weight: var(--font-weight-semibold, 600);
  letter-spacing: var(--tracking-tight, -0.025em);
  color: var(--text-primary);
  text-align: start;
}

/*
 * Phone page headers: H1 only (dock + shell orient). Subtitles/leads hide.
 * One primary action remains full-width touch target. Icon-only chrome
 * (btn-square / soft tool buttons) must stay compact — never stretched into
 * full-width bars that read as accidental blocks (design.pdf §5.4 hierarchy).
 */
@media (max-width: 47.99rem) {
  [data-primitive="PageHeader"] p.text-sm.leading-snug,
  [data-primitive="PageHeader"] .max-w-description {
    display: none;
  }
  /*
   * Phone: shell already paints page title in chrome — page H1 becomes a
   * second title band that wastes vertical density and can overflow at
   * 320px when actions wrap. Visually hide H1 (keep in a11y tree via
   * clip) so the action row is the sole page chrome under the topbar.
   */
  [data-primitive="PageHeader"][data-page-header-mode="shell"] h1,
  [data-primitive="PageHeader"][data-page-header-mode="shell"] [id^="page-header-title-"] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  /*
   * Phone: shell already paints page title — breadcrumbs are secondary
   * orientation. Keep them for AT (visually hide) so the action row owns
   * the full width without a second chrome band (design.pdf §5.1 / HIG).
   */
  [data-primitive="PageHeader"] [data-page-breadcrumbs] {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
  }
  [data-page-header-actions] {
    justify-content: flex-end;
  }
  [data-page-header-actions] > .btn.btn-primary,
  [data-page-header-actions] > a.btn.btn-primary,
  [data-page-header-actions] > [data-disabled-tip-host]:has(.btn-primary) {
    flex: 1 1 auto;
    justify-content: center;
    min-height: var(--touch-target-min, 2.75rem);
  }
  [data-page-header-actions] > .btn:not(.btn-primary),
  [data-page-header-actions] > a.btn:not(.btn-primary),
  [data-page-header-actions] > [data-disabled-tip-host]:not(:has(.btn-primary)) {
    flex: 0 1 auto;
    min-height: var(--touch-target-min, 2.75rem);
  }
}

/* Tablet: keep labels for soft secondaries — more horizontal room. */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  [data-page-header-actions] {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    max-width: 100%;
  }
}

}
@layer bao-tokens {

/*
 * Shell icon action — theme, voice, account, drawer toggle.
 * Fixed 44px square;absolute stack centers glyph + daisyUI swap layers.
 * Nested under .bao-shell-topbar-actions (not navbar-end > .btn direct child).
 */
.bao-shell-topbar .bao-shell-icon-action.btn,
.bao-shell-topbar .bao-shell-icon-action.btn.btn-square,
.bao-shell-topbar .bao-shell-icon-action.btn.tooltip,
.bao-shell-topbar .bao-shell-icon-action.btn.swap,
.bao-shell-topbar .bao-shell-icon-action.btn.swap-rotate,
.bao-shell-topbar .bao-shell-topbar-actions .bao-shell-icon-action.btn,
.bao-shell-topbar .bao-shell-topbar-actions summary.bao-shell-icon-action,
.bao-shell-topbar button.bao-shell-icon-action,
.bao-shell-topbar summary.bao-shell-icon-action {
  position: relative;
  display: inline-grid;
  place-content: center;
  place-items: center;
  width: var(--touch-target-min);
  min-width: var(--touch-target-min);
  max-width: var(--touch-target-min);
  height: var(--touch-target-min);
  min-height: var(--touch-target-min);
  max-height: var(--touch-target-min);
  padding: 0;
  margin: 0;
  gap: 0;
  line-height: 0;
  flex: 0 0 auto;
  box-sizing: border-box;
  /* visible: tooltips; icon layers use absolute so overflow does not clip glyph */
  overflow: visible;
  vertical-align: middle;
  grid-template-columns: 1fr;
  grid-template-rows: 1fr;
  grid-template-areas: "stack";
}/* Kill bao-toolbar-action overflow:hidden clip + label-expand geometry on shell. */
.bao-shell-topbar .bao-toolbar-action.bao-shell-icon-action,
.bao-shell-topbar .bao-shell-topbar-actions .bao-toolbar-action.bao-shell-icon-action {
  overflow: visible;
  gap: 0;
}.bao-shell-topbar .bao-shell-icon-action.btn:hover,
.bao-shell-topbar .bao-shell-icon-action.btn:focus-visible,
.bao-shell-topbar .bao-shell-icon-action.btn:focus-within,
.bao-shell-topbar .bao-shell-icon-action.btn[aria-pressed="true"],
.bao-shell-topbar .bao-shell-icon-action.btn[aria-expanded="true"],
.bao-shell-topbar .bao-shell-icon-action.btn.swap-active,
.bao-shell-topbar details[open] > summary.bao-shell-icon-action,
.bao-shell-topbar .bao-shell-topbar-actions .bao-shell-icon-action.btn:hover,
.bao-shell-topbar .bao-shell-topbar-actions .bao-shell-icon-action.btn[aria-pressed="true"] {
  width: var(--touch-target-min);
  min-width: var(--touch-target-min);
  max-width: var(--touch-target-min);
  height: var(--touch-target-min);
  min-height: var(--touch-target-min);
  padding: 0;
  gap: 0;
}/*
 * Absolute stack: every glyph layer shares the same box center.
 * swap-rotate's 45deg must not invent a second layout box.
 */
.bao-shell-topbar .bao-shell-icon-action > svg,
.bao-shell-topbar .bao-shell-icon-action > .swap-on,
.bao-shell-topbar .bao-shell-icon-action > .swap-off,
.bao-shell-topbar .bao-shell-icon-action > .avatar,
.bao-shell-topbar .bao-shell-icon-action > span:not(.sr-only):not(.htmx-indicator):not(.loading) {
  grid-area: stack;
  place-self: center;
  position: absolute;
  inset: 0;
  align-items: center;
  justify-content: center;
  padding: 0;
  line-height: 0;
  pointer-events: none;
  /* kill daisyUI swap-rotate optical skew for shell chrome */
  rotate: none;
  transform: none;
}
.bao-shell-topbar .bao-shell-icon-action > .swap-on,
.bao-shell-topbar .bao-shell-icon-action > .swap-off,
.bao-shell-topbar .bao-shell-icon-action > .avatar,
.bao-shell-topbar .bao-shell-icon-action > span:not(.sr-only):not(.htmx-indicator):not(.loading) {
  display: inline-flex;
  width: 100%;
  height: 100%;
  margin: 0;
}.bao-shell-topbar .bao-shell-icon-action.swap-rotate > .swap-on,
.bao-shell-topbar .bao-shell-icon-action.swap-rotate > .swap-off,
.bao-shell-topbar .bao-shell-icon-action.swap-active.swap-rotate > .swap-on,
.bao-shell-topbar .bao-shell-icon-action.swap-active.swap-rotate > .swap-off {
  rotate: none;
  transform: none;
}.bao-shell-topbar .bao-shell-icon-action > svg,
.bao-shell-topbar .bao-shell-icon-action .swap-on svg,
.bao-shell-topbar .bao-shell-icon-action .swap-off svg {
  display: block;
  width: 1rem;
  height: 1rem;
  margin: 0;
  flex: 0 0 auto;
}/* Avatar glyph inside account summary — circle centered in square. */
.bao-shell-topbar .bao-shell-icon-action .avatar > span,
.bao-shell-topbar .bao-shell-icon-action [data-user-avatar] {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.75rem;
  height: 1.75rem;
  min-width: 1.75rem;
  min-height: 1.75rem;
  margin: 0;
  line-height: 1;
  border-radius: var(--radius-full);
}.bao-shell-topbar .bao-shell-icon-action > .sr-only,
.bao-shell-topbar .bao-shell-icon-action .sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}/* Coarse pointer: re-assert fixed square after general btn-square grow rule. */
@media (hover: none),
(pointer: coarse) {.bao-shell-topbar .bao-shell-icon-action.btn,
.bao-shell-topbar .bao-shell-icon-action.btn.btn-square,
.bao-shell-topbar .bao-shell-topbar-actions .bao-shell-icon-action.btn,
.bao-shell-topbar .bao-shell-topbar-actions summary.bao-shell-icon-action,
.bao-shell-topbar button.bao-shell-icon-action,
.bao-shell-topbar summary.bao-shell-icon-action,
.bao-shell-topbar .navbar-end .btn.btn-square,
.bao-shell-topbar .navbar-start .btn.btn-square {
    width: var(--touch-target-min);
    min-width: var(--touch-target-min);
    max-width: var(--touch-target-min);
    height: var(--touch-target-min);
    min-height: var(--touch-target-min);
    padding: 0;
      gap: 0;
  }
}

/*
 * Topbar action cluster — single dense toolbar row (design.pdf §5.1 chrome).
 * Indicators absolute so HTMX spinners never reflow the icon row.
 */
.bao-shell-topbar .bao-shell-topbar-actions {
  display: inline-flex;
  flex-direction: row;
  flex-wrap: nowrap;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-2xs, 0.125rem);
  position: relative;
  flex: 0 0 auto;
  min-width: 0;
}.bao-shell-topbar .bao-shell-topbar-actions > .htmx-indicator,
.bao-shell-topbar .bao-shell-topbar-actions > .loading,
.bao-shell-topbar .bao-shell-topbar-actions > [id$="-indicator"],
.bao-shell-topbar .bao-shell-topbar-actions > [id$="-status"],
.bao-shell-topbar .navbar-end > .htmx-indicator,
.bao-shell-topbar .navbar-end > .loading {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
  pointer-events: none;
}/* Voice status is optional text — never crush icon alignment. */
.bao-shell-topbar .navbar-end [data-voice-command-status],
.bao-shell-topbar .bao-shell-topbar-actions [data-voice-command-status] {
  max-width: min(6rem, 40vw);
  min-width: 0;
  flex: 0 1 auto;
}

/*
 * Responsive drawer-toggle contract must survive the icon-geometry override
 * above (its display: inline-grid outranks the drawer modules' hide rules).
 * Phone (<48rem): dock "More" owns the drawer. Tablet (48–79.99rem): the
 * persistent icon rail owns nav. Permanent rail (≥80rem): .bao-shell-sidebar
 * [data-sidebar-rail-toggle] owns collapse — one affordance per function
 * (design.pdf §5.1).
 */
.bao-shell-topbar button.bao-shell-icon-action.bao-drawer-toggle-control[data-drawer-toggle] {
  display: none;
}/*
 * Forced colors (SH-09,
WCAG 1.4.11): the UA strips glass fills and the
 * quiet transparent rest borders,
leaving glyph-only controls with no
 * perceivable boundary. Restore system-color boundaries + glyphs for shell
 * icon actions,
the status chip,
and dock items.
 */
@media (forced-colors: active) {.bao-shell-topbar .bao-shell-icon-action,
.bao-shell-topbar summary.bao-shell-icon-action,
.bao-shell-topbar .bao-shell-status-badge,
.bao-mobile-dock .bao-mobile-dock-item {
    border: 1px solid ButtonBorder;
    background: Canvas;
    color: ButtonText;
  }
  .bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"] {
    border-color: ButtonBorder;
    color: CanvasText;
  }.bao-shell-topbar .bao-shell-icon-action:focus-visible,
.bao-mobile-dock .bao-mobile-dock-item:focus-visible {
    outline: var(--focus-ring-width) solid Highlight;
    outline-offset: var(--focus-ring-offset);
  }
}

/* The theme control semantic state owns both direct and nested swap glyphs. */
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]) .swap-on {
  opacity: 1;
}
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]) .swap-off {
  opacity: 0;
}
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]).swap-rotate .swap-on,
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]) [data-theme-toggle-swap].swap-rotate .swap-on {
  rotate: 0deg;
}
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]).swap-rotate .swap-off,
[data-theme-toggle]:is([aria-pressed="true"], [aria-checked="true"]) [data-theme-toggle-swap].swap-rotate .swap-off {
  rotate: calc(45deg * -1);
}

}
@layer bao-tokens {


/* Runtime preference fragments share one vertical content stack. */
.bao-settings-state-strip {
  display: flex;
  flex-direction: column;
  gap: var(--space-inline);
  min-inline-size: 0;
}

/* The wrapper owns query measurement; the settings surface owns named tracks. */
.bao-settings-workspace {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr);
  grid-template-areas: "header" "settings";
  flex: 1 1 0%;
  min-block-size: 0;
  gap: var(--space-section);
  container-type: inline-size;
  container-name: settings-tabs;
}
[data-settings-tabs] {
  grid-area: settings;
  min-block-size: 0;
  display: grid;
  grid-template-rows: auto auto minmax(0, 1fr);
  grid-template-areas: "search" "navigation" "panels";
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-section);
}
[data-settings-search] { grid-area: search; min-inline-size: 0; }
[data-settings-tab-trigger], [data-settings-tab-picker], .bao-settings-source-list { grid-area: navigation; }
.bao-settings-panels-host {
  position: relative;
  grid-area: panels;
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior-block: contain;
  scrollbar-gutter: stable;
}
#settings-panels-indicator { grid-area: panels; justify-self: end; }
.bao-settings-source-item {
  display: flex;
  align-items: center;
  gap: var(--space-inline);
  min-inline-size: 0;
  inline-size: 100%;
}
[data-settings-search-list] {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-micro);
  max-block-size: var(--palette-max-height);
  overflow-y: auto;
  padding: 0;
  margin: 0;
  list-style: none;
}
@container settings-tabs (max-width: 56rem) {
  [data-settings-tabs] > [data-settings-tab-picker] { display: flex; }
  [data-settings-tabs] > .bao-settings-source-list { display: none; }
}
/* The phone sheet uses the same viewport boundary as its Tabs primitive. */
@media (max-width: 39.99rem) {
  [data-settings-tabs] > [data-settings-tab-picker] { display: none; }
}
/* The same compact destination owner closes the native Sheet when its trigger leaves the layout. */
@media (min-width: 40rem) {
  dialog[data-primitive="Sheet"]#settings-tab-sheet[open] { display: none; }
}
@container settings-tabs (min-width: 56.01rem) {
  [data-settings-tabs] {
    grid-template-areas: "search search" "navigation panels";
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-columns: minmax(var(--grid-panel-quarter-min), var(--sidebar-expanded)) minmax(0, 1fr);
  }
  [data-settings-tabs] > [data-settings-tab-picker] { display: none; }
  [data-settings-tabs] > .bao-settings-source-list {
    display: flex;
    flex-direction: column;
    min-inline-size: 0;
    min-block-size: 0;
    align-self: stretch;
    overflow-y: auto;
    scrollbar-gutter: stable;
  }
}

/*
 * Settings destination visibility is single-owned by
 * tokens-glass-shell-settings-responsive.
 *
 * This module previously declared a 56.01rem-96rem container band that revealed
 * the compact select and hid the tablist, on the reasoning that "a full label
 * rail is only useful when every destination is visible". The premise was right
 * and the remedy was not: twelve destinations do not fit a horizontal rail, so
 * the fix is a vertical source list at regular width, not a phone control on
 * every desktop. Because that band spanned 896-1536px of container width, the
 * tablist was unreachable on every realistic display.
 */


/* Every settings group owns one stacked reading column in every application. */
.bao-settings-group {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: var(--space-inline);
  min-inline-size: 0;
  margin: 0;
  padding: var(--space-section);
  container-type: inline-size;
  container-name: settings-group;
}

/* A floated legend participates in the group rather than cutting its border. */
.bao-settings-group > legend.fieldset-legend {
  float: inline-start;
  grid-column: 1 / -1;
  inline-size: 100%;
  margin: 0;
  padding: 0;
}

/*
 * Settings control rows — DataSection.controlRow (toggle flex/grid) and
 * controlField (stacked label/control). This semantic row owns layout and rhythm.
 */
.bao-settings-control-row {
  min-width: 0;
  margin: 0;
  padding-block: var(--space-micro);
  border-block-end: var(--pane-divider) solid var(--border-base);
}

.bao-settings-control-row:first-child {
  padding-block-start: 0;
}

.bao-settings-control-row:last-child {
  padding-block-end: 0;
  border-block-end: 0;
}

/* Reserve the indicator track at rest so a save cannot move the switch. */
.bao-settings-control-row[data-settings-control-kind="toggle"] {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 1fr) auto var(--text-base);
  align-items: center;
  gap: var(--space-inline);
}

.bao-settings-control-row[data-settings-control-kind="toggle"] > label {
  min-width: 0;
  overflow-wrap: anywhere;
  white-space: normal;
}

.bao-settings-control-row[data-settings-control-kind="toggle"] > .htmx-indicator {
  grid-column: 3;
  grid-row: 1;
}

/* Input/select SSOT — explicit label/control stacked in one row. */
.bao-settings-control-row[data-settings-control-kind="input"],
.bao-settings-control-row[data-settings-control-kind="select"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-micro);
  min-width: 0;
}

/* HTMX indicators must not reserve vertical space when idle. */
.bao-settings-control-row .htmx-indicator,
[data-settings-control-kind="input"] > .htmx-indicator,
[data-settings-control-kind="select"] > .htmx-indicator,
[data-page="settings"] .htmx-indicator {
  display: none;
  width: 0;
  height: 0;
  margin: 0;
  padding: 0;
  overflow: hidden;
}

.bao-settings-control-row .htmx-indicator:is(.htmx-request, [data-shell-loading]),
[data-settings-control-kind="input"] > .htmx-indicator:is(.htmx-request, [data-shell-loading]),
[data-settings-control-kind="select"] > .htmx-indicator:is(.htmx-request, [data-shell-loading]),
[data-page="settings"] .htmx-indicator:is(.htmx-request, [data-shell-loading]) {
  display: inline-block;
  inline-size: var(--text-base);
  block-size: var(--text-base);
}

[data-page="settings"] .bao-settings-control-row[data-settings-control-kind="toggle"] > input[type="checkbox"] {
  justify-self: end;
}

/* Hardware capability groups are supplied as newline-delimited runtime state. */
[data-page="settings"] [data-settings-control="capture.hardware-summary"] {
  display: block;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

  .bao-settings-pair-actions {
    display: grid;
    min-width: 0;
    grid-template-columns: repeat(auto-fit, minmax(min(var(--grid-context-min), 100%), 1fr));
    gap: var(--space-inline);
  }
  .bao-settings-pair-actions > button {
    min-width: 0;
    width: 100%;
    justify-content: center;
  }

/* One layout owner for groups, device management and contract summaries. */
.bao-settings-panel-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
  gap: var(--space-section);
  min-inline-size: 0;
}

/*
 * Settings value readout — read-only current-value display (rendered as
 * <output>). Semantic hook composed with the typography/width utilities in
 * READOUT_CLASS and READOUT_MONO_CLASS (packages/shared/settings-controls-classes.ts).
 * Owns the value baseline: a readout never overflows its settings cell.
 */
.bao-settings-value-readout {
  min-width: 0;
  width: 100%;
  max-width: 100%;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-tight);
  color: var(--text-primary);
  overflow-wrap: anywhere;
  user-select: text;
}

.bao-settings-value-readout-mono {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
  word-break: break-all;
}

/*
 * Long settings values: collapsed by default, revealed in full on demand.
 *
 * `DataSection.bao` declared `valueReadoutDisclosure` / `valueReadoutFull` and
 * shipped them with no selector at all, so both rendered unstyled — the same
 * dangling-class defect class as the glass surfaces before them.
 *
 * One owner, here, beside the readout these rules compose with. The same three
 * selectors also lived in tokens-glass-shell-settings-tabs, and the two copies
 * of `.bao-settings-value-disclosure` disagreed: this module set
 * `display: -webkit-box` with `-webkit-line-clamp: 2` and `overflow: hidden`;
 * that one set `min-width: 0; max-width: 100%` and gave the summary
 * `display: list-item`. Equal specificity, so source order decided and this
 * copy came last — the identifier disclosure shipped as a two-line clamped box
 * with its expanded value cut off and its native triangle gone, which is
 * precisely the failure the surviving comment below warns about. The clamp
 * goes with the duplicate: the summary already carries the short segment, so
 * there is nothing left to truncate.
 */
.bao-settings-value-disclosure {
  min-width: 0;
  max-width: 100%;
}

/*
 * display: list-item keeps the native disclosure triangle. Setting display to
 * flex here removed it, leaving a control with no affordance that it opens —
 * the value looked like plain truncated text and nothing invited the tap.
 */
.bao-settings-value-disclosure > summary {
  display: list-item;
  list-style-position: inside;
  min-height: var(--touch-target-min);
  min-inline-size: var(--touch-target-min);
  inline-size: fit-content;
  max-inline-size: 100%;
  line-height: var(--touch-target-min);
  padding-block: 0;
  padding-inline: var(--space-micro);
  cursor: pointer;
  border-radius: var(--radius-field);
}

/*
 * The full identifier, revealed. Its own mono/wrap treatment rather than the
 * readout's: this text is selected and copied, so it wraps at any character
 * and never collapses whitespace.
 */
.bao-settings-value-full {
  display: block;
  padding-block-start: var(--space-micro);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  overflow-wrap: anywhere;
  word-break: break-word;
  white-space: pre-wrap;
  user-select: text;
}

/*
 * Settings tabpanels — exclusive visibility (daisyUI tabs content pattern).
 * Inactive panels must leave layout completely so Appearance/theme cannot
 * paint under every tab when all panels were stacked.
 * Cover attribute, utility class, and aria-hidden for WebView 101 + HTMX.
 */
.bao-settings-tab-panel[hidden],
.bao-settings-tab-panel.hidden,
.bao-settings-tab-panel[aria-hidden="true"],
[data-page="settings"] [data-settings-panel][hidden],
[data-page="settings"] [data-settings-panel].hidden,
[data-page="settings"] [data-settings-panel][aria-hidden="true"] {
  display: none;
  visibility: hidden;
  pointer-events: none;
}

.bao-settings-tab-panel:not([hidden]):not(.hidden):not([aria-hidden="true"]),
[data-page="settings"] [data-settings-panel]:not([hidden]):not(.hidden):not([aria-hidden="true"]) {
  display: block;
  visibility: visible;
  pointer-events: auto;
  min-width: 0;
  width: 100%;
}

/* Appearance control layout is owned by the generated DataSection primitive. */

/*
 * Dual Settings sheet banned — theme/locale only on Settings → Accessibility.
 * No #settings-dialog chrome; residual class tokens are compile placeholders only.
 */


/* The leading context, search and command groups share one responsive row. */
.bao-shell-topbar.navbar,
.bao-shell-topbar[data-shell-topbar] {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  grid-template-areas: "context search actions";
  align-items: center;
  gap: var(--space-inline);
  min-block-size: calc(var(--chrome-min-height) + max(var(--safe-area-inset-top, 0px), env(safe-area-inset-top, 0px)));
  block-size: auto;
  padding-block-start: calc(var(--space-micro) + max(var(--safe-area-inset-top, 0px), env(safe-area-inset-top, 0px)));
  padding-block-end: var(--space-micro);
  padding-inline: max(var(--space-inline), var(--safe-area-inset-left, 0px), env(safe-area-inset-left, 0px))
    max(var(--space-inline), var(--safe-area-inset-right, 0px), env(safe-area-inset-right, 0px));
  min-inline-size: 0;
  inline-size: 100%;
  max-inline-size: 100%;
}
/* The shell title and page content share the same desktop reading inset,
 * with either the expanded sidebar or its collapsed rail. Safe areas retain
 * priority; narrow chrome owns its independent compact presentation. */
@media (min-width: 48rem) {
  .bao-shell-topbar.navbar,
  .bao-shell-topbar[data-shell-topbar] {
    padding-inline:
      max(min(var(--page-gutter-inline, var(--space-section)), 5%), var(--safe-area-inset-left, 0px), env(safe-area-inset-left, 0px))
      max(min(var(--page-gutter-inline, var(--space-section)), 5%), var(--safe-area-inset-right, 0px), env(safe-area-inset-right, 0px));
  }
}
.bao-shell-topbar .navbar-start,
.bao-shell-topbar .navbar-center,
.bao-shell-topbar .navbar-end {
  display: flex;
  flex-direction: row;
  align-items: center;
  width: auto;
  max-width: none;
  min-width: 0;
  min-height: var(--chrome-min-height, max(2.75rem, 44px));
}
.bao-shell-topbar .navbar-center,
.bao-shell-topbar .navbar-end {
  flex-wrap: nowrap;
  gap: var(--space-2xs, 0.125rem);
}
/*
 * HIG toolbar item groupings: a leading edge (sidebar control, view title,
 * context menu) and a trailing edge that carries an optional search field,
 * the status glyph and the actions. Apple HIG Toolbars assigns search to the
 * TRAILING edge; the centre area is for common controls or the title.
 *
 * Centring the search column with margin-inline:auto measured 318px of dead
 * space on BOTH sides at 1440x900 — 636px of an 1184px bar, 54% of it empty.
 * The old comment here was trying to avoid a dead void between edge-pinned
 * clusters and produced two of them instead of one. The leading zone now
 * absorbs the slack, so the bar has exactly one spacer, between the groups.
 */
.bao-shell-topbar .navbar-start {
  grid-area: context;
  flex: 1 1 auto;
  flex-wrap: nowrap;
  justify-content: flex-start;
  overflow: visible;
  /* The 2xs gap above is right for the trailing icon clusters and wrong here.
     The leading zone holds the view title next to the workspace capsule — two
     TEXT elements, not two glyphs — and 2px between them reads as a collision:
     measured at 1100px, the title ended at x=182 and the capsule began at
     x=184. Apple HIG Toolbars groups the leading edge as distinct items, so
     they get the same inline gap the bar uses between its zones. */
  gap: var(--space-inline, 0.5rem);
}
.bao-shell-topbar .navbar-center {
  grid-area: search;
  flex: 0 1 auto;
  justify-content: flex-end;
}
.bao-shell-topbar .navbar-end {
  grid-area: actions;
  flex: 0 0 auto;
  justify-content: flex-end;
  /* Anchored menus must remain visible outside the trailing layout zone. */
  overflow: visible;
}
/* Brand title: fluid clamp, never crushes the context strip. */
.bao-shell-topbar .bao-shell-brand {
  display: flex;
  min-width: 0;
  flex: 0 0 auto;
  align-items: center;
}


@media (max-width: 39.99rem) {
  .bao-shell-topbar .navbar-center,
  .bao-shell-topbar .navbar-end .bao-shell-topbar-actions [data-session-rail-sheet-open].btn {
    display: none;
  }

  /* Compact navigation retains the canonical control row and full-width title row. */
  .bao-shell-topbar.navbar {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr) auto;
    grid-template-areas:
      "menu context actions"
      "title title title";
    align-items: center;
    column-gap: var(--space-inline, 0.5rem);
    row-gap: var(--space-inline);
    padding-block-end: var(--space-inline);
  }

  .bao-shell-topbar.navbar .navbar-start {
    display: contents;
  }

  .bao-shell-topbar .navbar-start > [data-drawer-toggle] {
    grid-area: menu;
  }

  .bao-shell-topbar .navbar-start > .bao-shell-brand {
    grid-area: title;
    justify-content: center;
    text-align: center;
    min-width: 0;
    overflow: hidden;
  }

  .bao-shell-topbar .navbar-start > [data-context-capsule].btn {
    grid-area: context;
  }

  .bao-shell-topbar .navbar-end {
    grid-area: actions;
    gap: var(--space-2xs, 0.125rem);
  }

  .bao-shell-topbar .navbar-start > [data-context-capsule].btn.bao-shell-context-capsule {
    width: 100%;
    max-width: 100%;
    justify-content: space-between;
  }

  body[data-page-header-mode="content"] .bao-shell-topbar .bao-shell-brand {
    display: none;
  }

  body[data-page-header-mode="shell"] .bao-shell-topbar .bao-shell-brand #shell-page-title,
  body[data-page-header-mode="shell"] .bao-shell-topbar .bao-shell-brand [data-shell-page-title] {
    display: block;
    max-width: 100%;
    overflow: hidden;
    white-space: normal;
    overflow-wrap: anywhere;

  }
}



@media (min-width: 40rem) {
  .bao-shell-topbar .bao-shell-brand {
    max-width: clamp(4.5rem, 18vw, 12rem);
  }

  /* Medium/expanded: persistent search field is the ONE search affordance. */
  .bao-shell-topbar .navbar-end .bao-shell-topbar-actions [data-command-palette-trigger].btn {
    display: none;
  }
}
/* Voice status text: compact shells never show it; wider shells only when
   the runtime wrote content (owner: this module — never markup utilities). */
.bao-shell-topbar [data-voice-command-status] {
  display: none;
}
@media (min-width: 40rem) {
  .bao-shell-topbar [data-voice-command-status]:not(:empty) {
    display: inline;
  }
}
/* Drawer-toggle visibility is owned by tokens-glass-shell-drawer.ts
   (dock "More" on phone · hamburger 48–80rem · rail collapse ≥80rem). */
/* ---- Compact context capsule (visibility owned above). ---- */
/* Context is a quiet disclosure within the shared navigation material. */
.bao-shell-topbar [data-context-capsule].bao-shell-context-capsule.btn {
  display: inline-flex;
  flex-wrap: nowrap;
  max-inline-size: 100%;
  min-inline-size: 0;
  block-size: auto;
  flex: 0 1 auto;
  padding-inline: var(--space-inline);
  justify-content: flex-start;
  white-space: normal;
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
.bao-shell-topbar .bao-shell-context-capsule > svg {
  flex: none;
}
/* The capsule carries NO status dot.
   It used to paint a 6px ::before that turned success-green once a context was
   set. That was a second green dot in the same topbar as the registry status
   chip, and the two meant different things — context selected vs registry
   reachable — while looking identical. It also signalled by colour alone,
   which the accessibility canon forbids for status.

   The capsule already states its own status in text: the value span names the
   active workspace, and data-context-status drives the sr-only Active/Unset
   label. That is the readable, non-colour-dependent signal, so the dot was
   pure redundancy. Connection state is the registry chip's job, and that chip
   now tints a real glyph per state rather than painting a dot. */

/* Context actions are rendered once in the context sheet; the capsule is its trigger. */

@media (max-width: 47.99rem) {
  /* Compact right cluster: tight gap keeps ≥44px targets without crowding. */
  .bao-shell-topbar .bao-shell-topbar-actions {
    gap: var(--space-2xs, 0.125rem);
  }
}

/* ---- Context sheet (compact bottom sheet, §8.6). ---- */
/* Sheet plate caps at the visual viewport and scrolls internally so the row
   list never pushes the dismiss affordance off a small phone.
   Row-list grid SSOT lives in tokens-glass-shell-overlays.ts
   (.bao-shell-context-sheet-list) — never re-grid the nav wrapper here: a
   second grid on nav halves the list track and quarters every row. */
.bao-shell-context-sheet {
  max-height: min(70vh, var(--vv-height, 100dvh));
  overflow-y: auto;
  overscroll-behavior-y: contain;
}
.bao-shell-context-sheet-item {
  min-height: var(--touch-target-min, 2.75rem);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-context-min)), 1fr));
}
.bao-shell-context-sheet-item[data-context-status="set"] {
  border-inline-start: 2px solid var(--color-success);
  background: color-mix(in oklab, var(--color-success) 6%, transparent);
}
.bao-shell-context-sheet-item[data-context-status="unset"] [data-context-value] {
  opacity: var(--opacity-soft, 0.65);
}
/* Set rows: success text on the state badge — text is the signal, color decorates. */
.bao-shell-context-sheet-item[data-context-status="set"] [data-context-state] {
  color: var(--color-success);
}

/*
 * Account menu → compact bottom sheet (§8.6 canonical transformation:
 * popovers become sheets on compact, matching the context sheet idiom).
 * One SSoT: the same dropdown panel is re-anchored to the dock's top edge;
 * >=40rem keeps the anchored dropdown. Specificity must beat the
 * .dropdown.dropdown-end > .dropdown-content inline-end anchoring.
 *
 * The block-end offset clears the dock, and the dock band is the whole reason
 * this needs saying. Anchoring to the raw safe-area inset put the sheet's lower
 * edge at the viewport floor: measured at 390x844 the account sheet ran to
 * y=836 while nav#mobile-dock starts at y=780, so 56px of the sheet — a full
 * row — sat on top of the dock's first tab. The dock's own box is
 * --dock-height + --dock-safe-area-offset (tokens-layout-dock-base), which is
 * what the filter sheet and the dashboard customizer tray already clear, and
 * it collapses to the bare safe area on its own wherever the dock is retired
 * (--dock-height: 0rem at >=48rem).
 */
@media (max-width: 39.99rem) {
  [data-topbar-user-menu] > [data-dropdown-panel] {
    position: fixed;
    position-area: none;
    inset-inline: var(--space-inline, 0.5rem);
    inset-block-start: auto;
    inset-block-end: calc(
      var(--dock-height, 4rem) +
      var(--dock-safe-area-offset, env(safe-area-inset-bottom, 0px)) +
      var(--space-inline, 0.5rem)
    );
    margin: 0;
    width: auto;
    max-width: none;
    max-height: min(70vh, var(--vv-height, 100dvh));
    overflow-y: auto;
    overscroll-behavior-y: contain;
    border-radius: var(--radius-box, 1rem);
    box-shadow: var(--shadow-glass-floating);
  }
  /* Sheet rows read as destinations: full-width, 44px targets (coarse). */
  [data-topbar-user-menu] > [data-dropdown-panel] [role="menuitem"] {
    width: 100%;
    min-height: var(--touch-target-min, 2.75rem);
  }
}

/*
 * Session rail sheet (SH-06): bottom sheet on compact → side sheet ≥40rem
 * (§8.6 inspector transformation: full sheet → side sheet → persistent pane).
 * daisyUI modal-end owns the side anchoring; these rules only cap the track
 * and give the sheet body an internal scroll so the header never scrolls off.
 */
.bao-session-rail-sheet {
  display: flex;
  flex-direction: column;
  max-height: min(80vh, var(--vv-height, 100dvh));
}
.bao-session-rail-sheet-body {
  padding: var(--space-section);
  min-height: 0;
  flex: 1 1 auto;
}
@media (min-width: 40rem) {
  .bao-session-rail-sheet.modal-box {
    width: min(26rem, 92vw);
    max-width: 92vw;
    height: calc(100% - 2 * var(--space-inline));
    max-height: calc(100% - 2 * var(--space-inline));
    margin: var(--space-inline);
    border-radius: var(--radius-panel);
  }
}

[data-session-rail-session-controls] > .flex {
  gap: var(--space-inline);
}
[data-session-rail-case-picker] [data-case-picker] {
  gap: var(--space-inline);
}

/* Tooltips must paint outside chrome boxes (daisyUI ::before / ::after). */
.bao-shell-topbar.navbar {
  overflow-x: visible;
  overflow-y: visible;
}
/*
 * Topbar blur — nav token. The bar carries .bao-surface-glass-regular.bao-glass-small,
 * which defaults to --liquid-blur-small (14px light / 16px dark). Apple's Liquid Glass nav-bar
 * reads as more diffuse at the bar's stationary height, so this rule overrides
 * the density modifier's blur with --liquid-blur-nav (32px). Phones keep the
 * small blur via the @container shell (max-width: 48rem) override in
 * tokens-glass-base-core.css so a 32px blur never hits a 320px-wide viewport.
 *
 * Gated the way the scroll-edge sibling in tokens-glass-base-variants is: this
 * selector is (1,2,0) and unconditional, so it outranked the (0,1,0)/(0,2,0)
 * suppression paths AND the (0,2,1) product toggle at once — measured under
 * Emulation.setEmulatedMedia, the topbar kept the live 32px nav blur with
 * full saturation for a user who asked the OS for reduced transparency or
 * more contrast. OS media query and product attribute gate together because
 * the two switches are independent and either one alone leaves the other
 * unhonoured.
 */
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
  html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-topbar.navbar.bao-surface-glass-regular {
    -webkit-backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular));
    backdrop-filter: blur(var(--liquid-blur-nav)) saturate(var(--liquid-saturate-regular));
  }
}
/* Theme + voice live in the user menu — keep topbar sparse. That intent is
   now honoured at the SOURCE: layout-shell-html no longer emits a second
   theme or voice button into the toolbar, so there is nothing left here to
   hide. Apple HIG Toolbars asks for items chosen deliberately rather than
   crowded, and hig-canon H2 bans emitting a control and then hiding it with
   display:none instead of routing it through the menu. Only the theme live
   region and its indicator remain in the bar, and neither is a control. */
/* Registry status: icon glyph only (label is aria + title). */
.bao-shell-topbar .bao-shell-status-badge {
  position: relative;
  display: inline-flex;
  align-items: center;
  place-content: center;
  width: var(--touch-target-min);
  height: var(--touch-target-min);
  min-width: 1.5rem;
  min-height: var(--chrome-min-height, max(2.75rem, 44px));
  max-width: 14rem;
  gap: var(--space-micro, 0.25rem);
  padding-block: 0;
  padding-inline: var(--space-micro, 0.25rem);
  border-radius: var(--radius-field, 0.75rem);
}
.bao-shell-topbar .bao-shell-status-badge [data-status-label] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border-width: 0;
}
/* Every topbar control retains the canonical minimum at enlarged text sizes. */
.bao-shell-topbar .navbar-end .bao-shell-topbar-actions .btn,
.bao-shell-topbar .navbar-start [data-drawer-toggle-button].btn {
  min-width: var(--touch-target-min);
}

/*
 * ---- Search (§8.6 canonical): compact = palette overlay, medium/expanded =
 * the ONE persistent field, rest-compact so center chrome never steals
 * workbench width; it expands while focused. Field surface uses the glass
 * FILL tokens — never nested backdrop blur inside already-blurred chrome.
 */
@media (max-width: 39.99rem) {
  /* Compact: palette trigger owns search — inline field must not compete (§8.6). */
  .bao-shell-topbar [data-topbar-search] {
    display: none;
  }
}
@media (min-width: 40rem) and (max-width: 63.99rem) {
  .bao-shell-topbar .navbar-start {
    flex: 1 1 auto;
    min-width: 0;
  }
  .bao-shell-topbar .navbar-center {
    flex: 0 0 auto;
    max-width: min(12rem, 30vw);
  }
  .bao-shell-topbar [data-topbar-search] {
    width: 100%;
    max-width: 100%;
  }
}
/* Canonical label.input host (icon inline — no absolute positioning). */
.bao-shell-topbar [data-topbar-search] .input {
  /* background-color LONGHAND: the shorthand resets background-image and
   * erases daisyUI component chrome (fieldset-bg-longhand gate). */
  background-color: var(--glass-control-fill, color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent));
  /*
   * The FILL is glass; the BOUNDARY is not. --glass-control-border is the
   * decorative hairline of glass chrome, and spending it here left the
   * shell's most-used field identified by nothing: measured on /cases at
   * 1280x800 in light, the border composited to 1.18:1 against the surface
   * behind it while the fill — rgba(255,255,255,0.1) over a white host —
   * added nothing either. A field on glass is still a field, so it carries
   * the same control boundary every other field does.
   */
  border-color: var(--border-control, var(--color-base-300));
}
.bao-shell-topbar [data-topbar-search] .input > svg {
  opacity: var(--opacity-soft, 0.65);
}
/*
 * Tertiary icon actions rest QUIET (design.pdf §6: rest = quiet border, low
 * emphasis) — boxed btn-soft squares made every tertiary action shout.
 * Hover/focus paint the control fill; pressed keeps immediate feedback.
 */
.bao-shell-topbar .navbar-end .bao-shell-topbar-actions .btn.bao-shell-icon-action,
.bao-shell-topbar .navbar-end details.dropdown > summary.bao-shell-icon-action,
.bao-shell-topbar .navbar-start [data-drawer-toggle-button].btn,
.bao-shell-topbar .navbar-end .bao-shell-status-badge:not([data-registry-state="offline"]) {
  background: transparent;
  border-color: transparent;
  box-shadow: none;
}
.bao-shell-topbar .navbar-end .bao-shell-topbar-actions .btn.bao-shell-icon-action:focus-visible,
.bao-shell-topbar .navbar-end details.dropdown > summary.bao-shell-icon-action:focus-visible,
.bao-shell-topbar .navbar-start [data-drawer-toggle-button].btn:focus-visible,
.bao-shell-topbar .navbar-end .bao-shell-status-badge:focus-visible {
  background: var(--glass-control-fill, color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent));
  border-color: var(--glass-control-border, var(--liquid-border-regular));
}
/* Hybrid hover (imp-t04): fill paints only where hover is real — touch taps
   must not leave a sticky-hover fill on header chrome. */
@media (hover: hover) and (pointer: fine) {
  .bao-shell-topbar .navbar-end .bao-shell-topbar-actions .btn.bao-shell-icon-action:hover,
  .bao-shell-topbar .navbar-end details.dropdown > summary.bao-shell-icon-action:hover,
  .bao-shell-topbar .navbar-start [data-drawer-toggle-button].btn:hover {
    background: var(--glass-control-fill, color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent));
    border-color: var(--glass-control-border, var(--liquid-border-regular));
  }
}
@media (hover: hover) and (pointer: fine) {
  .bao-shell-topbar [data-topbar-search] {
    max-width: min(11rem, 30vw);
    transition: none;
  }
  .bao-shell-topbar [data-topbar-search]:focus-within {
    max-width: min(100%, 20rem, 45vw);
  }
  .bao-shell-topbar [data-topbar-search] .input {
    min-height: var(--touch-target-min);
    height: var(--touch-target-min);
  }
}
/* Focus expansion breathes with motion tokens; reduced motion keeps it instant. */
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .bao-shell-topbar [data-topbar-search] {
    transition: max-width var(--duration-fast) var(--easing-standard);
  }
}
@media (pointer: coarse) {
  .bao-shell-topbar [data-topbar-search] {
    max-width: min(100%, 14rem, 40vw);
  }
  .bao-shell-topbar [data-topbar-search] .input {
    min-height: var(--touch-target-min);
  }
}
/*
 * ---- Registry status (navbar-end): glyph-first. Offline keeps shape+tint.
 * The accessible label is visually clipped by the topbar policy owner;
 * connection state uses distinct silhouettes and never color alone.
 */

.bao-shell-topbar .bao-shell-status-badge[data-registry-state="checking"] {
  color: var(--color-warning);
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="connected"] {
  color: var(--color-success);
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="local"] {
  color: var(--color-base-content);
}
/*
 * Status glyph trio (design.pdf §2.11): one simple silhouette per state —
 * network while connected/checking, monitor when only local surfaces serve
 * (a healthy workstation must not wear the brand-adjacent network mark),
 * wifi-off when the runtime stamps data-registry-offline. Shape + tone +
 * label/AT text; never color alone.
 */
.bao-shell-topbar .bao-shell-status-badge [data-status-glyph] {
  display: inline-flex;
  align-items: center;
}
.bao-shell-topbar .bao-shell-status-badge [data-status-glyph="local"],
.bao-shell-topbar .bao-shell-status-badge [data-status-glyph="offline"] {
  display: none;
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="local"] [data-status-glyph="local"] {
  display: inline-flex;
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="local"] [data-status-glyph="connected"] {
  display: none;
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"] [data-status-glyph="offline"],
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="offline"] [data-status-glyph="offline"] {
  display: inline-flex;
}
.bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"] [data-status-glyph="connected"],
.bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"] [data-status-glyph="local"],
.bao-shell-topbar .bao-shell-status-badge[data-registry-state="offline"] [data-status-glyph="connected"] {
  display: none;
}
/* Checking: the network glyph pulses a bounded once and settles — an
   infinite status breath never lets document.getAnimations() empty and
   destabilizes actionability for a state the words already announce.
   Stable dimensions: the pulse is opacity-only, never layout. */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-reduced-motion="true"]) .bao-shell-topbar .bao-shell-status-badge[data-registry-state="checking"] [data-status-glyph="connected"],
  html:not([data-reduced-motion="true"]) .bao-shell-topbar .bao-shell-status-badge:not([data-registry-state]) [data-status-glyph="connected"] {
    animation: bao-status-checking var(--duration-slow) var(--easing-standard, ease-in-out) 1;
  }
}
@keyframes bao-status-checking {
  from { opacity: 1; }
  to { opacity: 0.45; }
}
/* Reduced motion (either signal) never enters: the positive gate above owns it. */
/* OPERATOR-CONFIRMED DESIGN DECISION (supersedes plan P2 wording — do not
   resurrect the text pills): the chip is glyph-only at EVERY width. wifi-off
   is an unambiguous silhouette (§2.11); words live in title/aria-label and
   the fine-pointer hover/focus reveal above. */
/* Offline: the wifi-off glyph in error tone carries the signal at rest —
   never a permanent alarm-tinted slab in global chrome (SH-10, §4 tint
   selectively). The severity plate appears on hover/focus, where the chip's
   retry affordance is actually targeted; forced-colors keeps a system border. */
.bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"] {
  background: transparent;
  border-color: transparent;
  color: var(--color-error);
  cursor: pointer;
}
@media (hover: hover) and (pointer: fine) {
  .bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"]:hover,
  .bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"]:focus-visible,
  .bao-shell-topbar .bao-shell-status-badge[data-registry-offline="true"]:focus-within {
    background: color-mix(in oklab, var(--color-error) 10%, transparent);
    border-color: color-mix(in oklab, var(--color-error) 30%, transparent);
  }
}
/* Offline chip is actionable (retry registry) — match touch target + keyboard. */
.bao-shell-topbar button.bao-shell-status-badge[data-registry-offline="true"] {
  min-height: var(--touch-target-min, 2.75rem);
  appearance: none;
  -webkit-appearance: none;
  font: inherit;
}
@media (pointer: coarse) {
  .bao-shell-topbar .bao-shell-status-badge {
    min-height: var(--touch-target-min, 2.75rem);
  }
}


/*
 * AI overlay findings: selectable assessment rows (provider/model/confidence/shape).
 * Solid content plane inside glass chrome; selected uses a primary tint and ring.
 */
[data-ai-overlay-item] {
  cursor: pointer;
  border-radius: var(--radius-field, 0.75rem);
  border: 1px solid transparent;
  padding: var(--space-micro, 0.25rem);
  min-height: var(--touch-target-min, 2.75rem);
  transition: background-color var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard);
}
[data-ai-overlay-item]:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
}
[data-ai-overlay-item][data-selected="true"],
[data-ai-overlay-item][aria-selected="true"] {
  outline: var(--focus-ring-width) solid var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  background: color-mix(in oklab, var(--color-primary) 8%, var(--color-base-100));
  border-color: color-mix(in oklab, var(--color-primary) 35%, var(--color-base-300));
}
@media (hover: hover) and (pointer: fine) {
  [data-ai-overlay-item]:hover:not([data-selected="true"]):not([aria-selected="true"]) {
    background: color-mix(in oklab, var(--color-base-200) 55%, transparent);
  }
}


/*
 * Context sheet (compact bottom sheet): single column on phone, two-up on
 * tablet so five context rows fit without a tall scroll wall.
 */
.bao-shell-context-sheet-list,
.bao-shell-context-sheet .bao-shell-context-sheet-list {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-micro, 0.25rem);
  width: 100%;
  min-width: 0;
  list-style: none;
  margin: 0;
  padding: var(--space-section, 0.75rem);
  padding-block-start: var(--space-micro, 0.25rem);
  /*
   * Bottom sheet pins to the screen edge on phone — the last rows must
   * clear the home-indicator safe area (Apple HIG). Same token/formula
   * family as .bao-dialog-footer-safe (tokens-layout-fabric-stage.ts),
   * additive here because the section pad stays.
   */
  padding-block-end: calc(var(--space-section, 0.75rem) + env(safe-area-inset-bottom, 0px));
}
@media (min-width: 40rem) and (max-width: 63.99rem) {
  .bao-shell-context-sheet-list,
  .bao-shell-context-sheet .bao-shell-context-sheet-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
.bao-shell-context-sheet-list > li,
.bao-shell-context-sheet .bao-shell-context-sheet-list > li {
  min-width: 0;
}

/*
 * Command palette — glass box chrome (CommandPalette.bao) + solid list rows.
 * Active row uses base-200 fill; hover is pointer-gated only.
 */
#command-palette [data-command-palette-results] [data-command-palette-item] {
  display: flex;
  align-items: center;
  min-height: var(--touch-target-min, 2.75rem);
  width: 100%;
  min-width: 0;
  padding-inline: var(--space-inline, 0.5rem);
  padding-block: var(--space-micro, 0.25rem);
  border-radius: var(--radius-field, 0.75rem);
  border: 1px solid transparent;
  background: var(--color-base-100, var(--bg-panel));
  color: var(--color-base-content);
}
/* Native hidden removes nonmatching command rows from the painted tree. */
#command-palette [data-command-palette-results] [data-command-palette-item][hidden] {
  display: none;
}
#command-palette [data-command-palette-results] [data-command-palette-item][data-command-palette-active="true"] {
  background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  border-color: var(--liquid-border-regular);
  color: var(--color-base-content);
}
@media (hover: hover) and (pointer: fine) {
  #command-palette [data-command-palette-results] [data-command-palette-item]:hover:not([data-command-palette-active="true"]) {
    background: var(--bg-surface-hover);
  }
}
#command-palette [data-command-palette-results] .menu {
  gap: var(--space-2xs, 0.125rem);
}

/* Settings row and group rhythm is owned by tokens-glass-shell-settings-part-1.
 * Shared data-panel radius is owned by tokens-glass-chrome-part. */


}
@layer bao-tokens {

/* Capture owns a single preview; context forms live in the canonical rail or sheet. */
[data-session-mode-tabs] {
  display: inline-flex;
}
[data-page="capture"]:not([data-session-mode="annotate"]) > [data-state-content] {
  overflow-x: clip;
  overflow-y: auto;
  overscroll-behavior-block: contain;
}



[data-capture-workbench] {
  display: flex;
  flex: 1 0 auto;
  min-inline-size: 0;
  min-block-size: 0;
}
.bao-preview-region {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 1 0 auto;
  min-inline-size: 0;
  min-block-size: min(48dvh, 28rem);
  overflow: clip;
  container-type: inline-size;
  background: var(--color-base-200);
}
.bao-preview-region > [data-camera-preview-video] {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  background: transparent;
  z-index: var(--z-base);
}
.bao-preview-region:not([data-preview-state="live"]) > [data-camera-preview-video] {
  visibility: hidden;
  pointer-events: none;
}
.bao-preview-region > [data-camera-preview-placeholder],
.bao-preview-region > [data-capture-case-required] {
  position: relative;
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-inline);
  min-inline-size: 0;
  padding: var(--space-section);
  text-align: center;
}
.bao-preview-region > [data-capture-preview-overlay] {
  flex: 0 0 auto;
  align-self: center;
  inline-size: max-content;
  max-inline-size: calc(100% - 2 * var(--space-section));
  margin: var(--space-section);
}
.bao-preview-region[data-preview-state="live"] > [data-capture-preview-overlay] {
  position: absolute;
  inset-block-end: var(--space-section);
  inset-inline-start: 50%;
  transform: translateX(-50%);
  margin: 0;
  z-index: var(--z-overlay);
}
html[data-capture-mirror-preview="true"] [data-camera-preview-video] { transform: scaleX(-1); }
[data-capture-preview-overlay] [data-capture-depth-status] {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}


/* Align collapse is global (all breakpoints) — not phone-media nested. */

/* Preview overlay control rows wrap at Dynamic Type scales: the camera
   picker and rescan action sit over a fixed-size video region, so the row
   must break onto extra lines instead of sliding past the viewport. */
.bao-preview-region fieldset {
  flex-wrap: wrap;
  max-inline-size: 100%;
}

.bao-preview-region fieldset > * {
  min-inline-size: 0;
  max-inline-size: 100%;
}

/* Only active alignment fades secondary controls. Live preview alone must
   keep More actions reachable after dialogs close (all breakpoints).
   The overlay is ONE bottom bar (shutter row + action bar) — only the action
   bar fades while retaining its layout space, so revealing it on pointerdown
   cannot move the shutter before pointerup. */
.bao-preview-region[data-preview-aligning="true"] [data-capture-action-bar] {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(0.5rem);
  transition-property: opacity, transform;
  transition-duration: var(--duration-fast);
  transition-timing-function: var(--easing-standard);
}.bao-preview-region[data-preview-state="live"][data-preview-controls="expanded"] [data-capture-action-bar] {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
}
@media (prefers-reduced-motion: reduce) {.bao-preview-region[data-preview-aligning="true"] [data-capture-action-bar] {
    transition-property: none; transition-duration: var(--duration-instant);
    transform: none;
  }
}

/*
 * Capture device fieldsets — flat, content-sized groups. The command chrome
 * band owns the surface; per-field card boxes multiplied five empty panels
 * across the capture fold, so fields carry no border/background of their own.
 */
fieldset[data-capture-control] {
  display: flex;
  flex-direction: column;
  gap: var(--space-micro, 0.25rem);
  min-width: 0;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
}

fieldset[data-capture-control] legend {
  padding-inline: var(--space-micro, 0.25rem);
  font-size: var(--text-xs, 0.75rem);
  font-weight: var(--font-weight-semibold, 600);
  letter-spacing: normal;
  /* Sentence case (HIG): typography.avoidUppercaseCss bans uppercase legends;
     text-2xs is the badge/timestamp floor, field labels use text-xs. */
  /* Label copy uses solid text-secondary — not translucent body (design.pdf §2.10). */
  color: var(--text-secondary, var(--color-base-content));
}

/* Media pathologist workflow: one dense horizontal strip, never a second page. */
[data-page-type="media"] > [data-related-links][data-pathologist-workflow],
[data-page="capture"] > [data-related-links][data-pathologist-workflow],
[data-page="editor"] > [data-related-links][data-pathologist-workflow],
[data-page="ai-analysis"] [data-related-links][data-pathologist-workflow] {
  flex: 0 0 auto;
  max-height: 3.25rem;
  overflow-x: auto;
  overflow-y: hidden;
  overscroll-behavior-x: contain;
  margin-block: 0;
  padding-block: var(--space-2xs, 0.125rem);
}
[data-page-type="media"] [data-related-links][data-pathologist-workflow] > h2,
[data-page="capture"] [data-related-links][data-pathologist-workflow] > h2,
[data-page="editor"] [data-related-links][data-pathologist-workflow] > h2,
[data-page="ai-analysis"] [data-related-links][data-pathologist-workflow] > h2 {
  display: none;
}
[data-page-type="media"] [data-related-links][data-pathologist-workflow] ol,
[data-page="capture"] [data-related-links][data-pathologist-workflow] ol,
[data-page="editor"] [data-related-links][data-pathologist-workflow] ol,
[data-page="ai-analysis"] [data-related-links][data-pathologist-workflow] ol {
  flex-wrap: nowrap;
  width: max-content;
  min-width: 100%;
}
[data-page-type="media"] [data-related-links][data-pathologist-workflow] ol > li,
[data-page="capture"] [data-related-links][data-pathologist-workflow] ol > li,
[data-page="editor"] [data-related-links][data-pathologist-workflow] ol > li,
[data-page="ai-analysis"] [data-related-links][data-pathologist-workflow] ol > li {
  flex: 0 0 auto;
  min-width: 0;
  max-width: none;
}
  /*
   * Overflow panel scroll containment (long action lists on small hosts).
   * The anchored panel's ceiling is the room the dropdown geometry
   * controller measures between the trigger and the viewport edge and
   * publishes as --bao-dropdown-max-height (app-shell-dropdowns-geometry).
   * A fixed rem cap layered over that var overrode the measurement: at
   * 1280x720 the nine-row menu was cut to 24rem, the Review group (AI
   * Analysis, Evidence, Reports) scrolled out of sight behind no scroll cue,
   * and 570px of stage stood empty above the trigger. The literal ceiling now
   * serves only hosts where the controller has not stamped; the row cue is
   * the shared bao-scroll-edge-y mask on the panel token.
   */
  [data-page="capture"] [data-capture-action-disclosure] > [data-capture-overflow-panel] {
    max-height: var(--bao-dropdown-max-height, min(60dvh, 24rem));
    overflow-y: auto;
    overscroll-behavior: contain;
  }
  /*
   * §8.6 canonical transformation: the overflow panel is a bottom sheet on
   * compact — same idiom as the account-menu sheet in
   * tokens-glass-shell-topbar-context-sheet.ts. The panel is popover-promoted
   * (top layer) because the page track's container-type traps fixed panels
   * under the toolbar clip; these rules must out-rank the controller's
   * .bao-dropdown-panel-viewport geometry and the popover UA inset defaults.
   *
   * The block-end offset clears the dock band, not just the safe area:
   * measured at 390x844 the sheet's lower edge landed at y=836 against a
   * nav#mobile-dock whose top edge is y=780, burying the "Capture" tab under
   * the last two rows. --dock-height + --dock-safe-area-offset is the dock's
   * own box (tokens-layout-dock-base) and it zeroes itself at >=48rem, so the
   * same expression is correct in every band.
   */
  @media (max-width: 39.99rem) {
    [data-page="capture"] [data-capture-action-disclosure] > [data-capture-overflow-panel] {
      position: fixed;
      inset-inline: var(--space-inline, 0.5rem);
      inset-block-start: auto;
      inset-block-end: calc(
        var(--dock-height, 4rem) +
        var(--dock-safe-area-offset, env(safe-area-inset-bottom, 0px)) +
        var(--space-inline, 0.5rem)
      );
      margin: 0;
      width: auto;
      max-width: none;
      /*
       * The sheet pins to the dock, not to the trigger, so the controller's
       * trigger-relative ceiling does not describe it: measured at 375x812 it
       * held the nine rows to 250px with 400px of viewport free above. Size
       * it to the visual viewport above the dock, capped so the topbar band
       * stays clear; rows past the cap scroll behind the shared edge cue.
       */
      max-height: min(80vh, calc(var(--vv-height, 100dvh) - var(--dock-height, 4rem) - var(--dock-safe-area-offset, env(safe-area-inset-bottom, 0px)) - var(--space-inline, 0.5rem) * 2));
      z-index: var(--z-modal, 1300);
    }
  }
  /* ≥40rem keeps the anchored dropdown, sized to its rows — never the 44px
     trigger column daisyUI infers from the icon-button host. */
  @media (min-width: 40rem) {
    [data-page="capture"] [data-capture-action-disclosure] > [data-capture-overflow-panel] {
      width: max-content;
      min-width: 14rem;
      max-width: min(92vw, 24rem);
    }
  }
  /* Grouped sheet sections read as one list with hairline separators. */
  [data-capture-overflow-group] + [data-capture-overflow-group] {
    border-block-start: 1px solid
      var(--liquid-border-regular);
    padding-block-start: var(--space-micro, 0.25rem);
  }
  /* 44px touch floor on plain menu rows (route items carry no .btn). */
  @media (pointer: coarse) {
    [data-capture-overflow-panel] [role="menuitem"] {
      min-height: var(--touch-target-min, 2.75rem);
    }
  }
  /*
   * Overflow menu rows are labeled list items rendered with the menuItemRow
   * token (route-row parity) — never btn-square toolbar chrome. The retired
   * .bao-toolbar-action/.bao-toolbar-label restore blocks fought the
   * icon-first hover-reveal cascade property-by-property and lost to a
   * higher-specificity fine-pointer clipper; fixing the row markup at the
   * emitter ends that war (pages-renderers-capture-actions.ts).
   */
  [data-page="capture"] [data-capture-action-disclosure] > [data-capture-overflow-panel] {
    flex-direction: column;
    align-items: stretch;
  }
  [data-page="capture"] [data-capture-action-disclosure] > [data-capture-overflow-panel] [data-disabled-tip-host] {
    width: 100%;
  }

/* Inspector disclosures: keep long AI/spatial panels inside the rail. */
[data-editor-inspector-disclosure] .collapse-content {
  max-height: min(24rem, 50vh);
  overflow-y: auto;
}

/*
 * Primary shutter — the bar's primary action at the bar's control size: the
 * circle and touch-target tokens own the 44px geometry shared with the gallery
 * and overflow controls; tint and glow live with the overlay vibrancy rules
 * above. The former 56/72px discs fought those tokens and painted a 44x72
 * ringed pill (measured 390x844 and 768x1024).
 */


/* ============================================================
   Capture pipeline phase + recording overlay (Bao-Translate UX)
   SINGLE definition — the class-based twin in
   tokens-glass-shell-capture-recording.ts was removed (SSOT: one
   scrim treatment, one data-phase state driver).
   Phase truth on [data-capture-chrome][data-phase]; CSS reflects only.
   ============================================================ */

[data-capture-chrome][data-phase="idle"] [data-capture-recording-overlay],
[data-capture-chrome][data-phase="error"] [data-capture-recording-overlay],
[data-capture-chrome][data-phase] [data-capture-recording-overlay][hidden] {
  display: none;
}

[data-capture-chrome][data-phase="starting"] [data-capture-recording-overlay][open],
[data-capture-chrome][data-phase="recording"] [data-capture-recording-overlay][open],
[data-capture-chrome][data-phase="processing"] [data-capture-recording-overlay][open] {
  display: flex;
}

[data-capture-recording-overlay] {
  position: absolute;
  inset: 0;
  z-index: var(--z-modal, 1300);
  inline-size: 100%;
  block-size: 100%;
  max-inline-size: none;
  max-block-size: none;
  margin: 0;
  border: 0;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-inline, 0.5rem);
  padding: var(--space-section, 0.75rem);
  padding-block-end: calc(var(--space-section, 0.75rem) + env(safe-area-inset-bottom, 0px));
  background: color-mix(in oklab, var(--color-base-content) 55%, transparent);
}

[data-capture-recording-overlay]::backdrop {
  background: var(--glass-scrim, transparent);
}

[data-capture-recording-dock] {
  width: min(100%, var(--max-w-form, 28rem));
}

[data-capture-recording-halo] {
  display: grid;
  place-items: center;
  inline-size: 4.5rem;
  block-size: 4.5rem;
  border-radius: var(--radius-full);
  background: color-mix(in oklab, var(--color-error) 88%, transparent);
  color: var(--color-error-content, var(--color-base-100));
}

[data-capture-chrome][data-phase="recording"] [data-capture-action="record-audio"],
[data-capture-chrome][data-phase="recording"] [data-capture-action="record-video"],
[data-capture-chrome][data-phase="starting"] [data-capture-action="record-audio"],
[data-capture-chrome][data-phase="starting"] [data-capture-action="record-video"] {
  color: var(--color-error-content, var(--color-base-100));
  background: var(--color-error);
  border-color: transparent;
}

[data-capture-live-source] {
  font-style: italic;
  opacity: var(--opacity-strong, 0.85);
  max-inline-size: min(36rem, 100%);
  text-align: center;
}

[data-capture-live-final] {
  font-style: normal;
  font-weight: 600;
  max-inline-size: min(36rem, 100%);
  text-align: center;
}

[data-capture-waveform] {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: var(--space-2xs, 0.125rem);
  inline-size: min(16rem, 80%);
  block-size: 2.5rem;
}

[data-capture-waveform] span {
  flex: 1 1 0;
  min-inline-size: 0.125rem;
  block-size: 30%;
  border-radius: var(--radius-full);
  background: color-mix(in oklab, var(--color-primary) 70%, var(--color-base-content));
  transform-origin: bottom center;
  /* Amplitude via data-waveform-level 0..10 — never inline CSS custom props. */
  transform: scaleY(0.22);
}

[data-capture-waveform] span[data-waveform-level="0"] { transform: scaleY(0.22); }
[data-capture-waveform] span[data-waveform-level="1"] { transform: scaleY(0.3); }
[data-capture-waveform] span[data-waveform-level="2"] { transform: scaleY(0.38); }
[data-capture-waveform] span[data-waveform-level="3"] { transform: scaleY(0.46); }
[data-capture-waveform] span[data-waveform-level="4"] { transform: scaleY(0.54); }
[data-capture-waveform] span[data-waveform-level="5"] { transform: scaleY(0.62); }
[data-capture-waveform] span[data-waveform-level="6"] { transform: scaleY(0.7); }
[data-capture-waveform] span[data-waveform-level="7"] { transform: scaleY(0.78); }
[data-capture-waveform] span[data-waveform-level="8"] { transform: scaleY(0.86); }
[data-capture-waveform] span[data-waveform-level="9"] { transform: scaleY(0.94); }
[data-capture-waveform] span[data-waveform-level="10"] { transform: scaleY(1); }


/* Tuning scrubbers: 44px touch floor on the primary touch surface. */
@media (pointer: coarse) {
  [data-uvc-tuning-panel] input,
  [data-uvc-tuning-panel] .btn {
    min-height: var(--touch-target-min, 2.75rem);
  }
}



/* Context strip: muted skeleton pulse while HTMX hydrates live context. */
[data-capture-context-strip][aria-busy="true"] [data-capture-context],
[data-capture-context-strip][data-state="loading"] [data-capture-context] {
  opacity: var(--pulse-alpha-floor, 0.55);
  pointer-events: none;
}

/* Live preview: hide placeholder when stream is attached (WebView 101). */
[data-camera-preview][data-preview-state="live"] [data-camera-preview-placeholder] {
  display: none;
}

/* WKWebView paint-recovery kick: app-shell-camera-preview.ts sets the
   attribute for two animation frames once the stream is live. The promoted
   layer forces WebKit to rebuild the accelerated compositing layer that a
   stalled first frame never created (Tauri grey-preview state; Safari and
   Chromium composite the same stream without it). */
[data-camera-preview-video][data-preview-kick="true"] {
  transform: translateZ(0);
}

/*
 * WKWebView raster preview: WebKit decodes a MediaStream attached to a
 * dynamically inserted <video> (soft navigation) but never composites it —
 * the stage stays grey until a hard reload rebuilds the document.
 * app-shell-camera-preview-raster.ts mirrors each decoded frame into a
 * sibling canvas, whose compositing path is unaffected. The canvas overlays
 * the region only while the region is live and rastering. The video element
 * stays rendered underneath (WebKit suspends decode of non-rendered videos,
 * which would starve drawImage of frames); the opaque canvas paints above it
 * as a later sibling in the same stacking order.
 */
.bao-preview-region > [data-camera-preview-raster] {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: none;
  pointer-events: none;
}
.bao-preview-region[data-preview-state="live"][data-preview-raster="true"]
  > [data-camera-preview-raster] {
  display: block;
}
html[data-capture-mirror-preview="true"]
  [data-page="capture"]
  [data-camera-preview-raster] {
  transform: scaleX(-1);
}
/* Status readout chips (not fieldsets) share the same solid control shell. */
[data-capture-command-chrome] [data-capture-control][role="status"] {
  display: flex;
  flex-direction: column;
  gap: var(--space-micro, 0.25rem);
  min-width: 0;
  margin: 0;
  padding: var(--space-micro, 0.25rem) var(--space-inline, 0.5rem);
  border: 1px solid var(--color-base-300, var(--border-base));
  border-radius: var(--radius-field, 0.75rem);
  background: var(--color-base-100, var(--bg-panel));
}

[data-capture-command-chrome] [data-capture-control][role="status"] .badge,
[data-capture-command-chrome] [data-capture-control][role="status"] span:last-child {
  font-size: var(--text-sm, 0.875rem);
  font-weight: 500;
  color: var(--color-base-content);
}

/*
 * AI analysis context collapse is global (all breakpoints).
 * Shell context chips already surface case/specimen/patient/accession.
 * Keep readonly fields in the DOM (sr-clip) for form submit + app-shell
 * prefill — never paint raw UUIDs or duplicate chrome on desktop/tablet.
 */
[data-ai-analysis-form] fieldset:has([data-ai-analysis-context-field]),
[data-ai-analysis-form] [data-ai-analysis-context-hint] {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
[data-capture-chrome][data-capture-case-ready="false"] [data-capture-preview-overlay],
[data-capture-chrome][data-capture-case-ready="false"] [data-camera-preview-placeholder] {
  display: none;
}
[data-capture-chrome][data-capture-case-ready="false"] [data-capture-case-required] {
  display: flex;
}
[data-capture-chrome][data-capture-case-ready="true"] [data-capture-case-required] {
  display: none;
}
/* Camera preflight keeps device setup separate from patient capture. The Device Controls trigger and native Sheet remain reachable independently of case readiness. */
[data-capture-chrome][data-capture-case-ready="false"] [data-camera-preview][data-preview-state="live"] [data-capture-case-required] {
  display: none;
}
[data-capture-chrome][data-capture-case-ready="false"] [data-camera-preview][data-preview-state="live"] [data-camera-preview-video] {
  display: block;
}


[data-capture-device-sheet][hidden] {
  display: none;
}
@media (min-width: 80rem) {
  body:has(#session-rail) [data-page="capture"] [data-capture-recent-captures] {
    display: none;
  }
  body:has(#session-rail) [data-page="capture"] [data-capture-workbench-secondary] {
    display: none;
  }
}
}
@layer bao-tokens {

/* Ownership note: the tablet acquire sizing facts for the capture workbench primary (flex, height, overflow) are owned by tokens-layout-page-shells-capture-responsive under the single-owner selector law; this module deliberately declares none. */

}
@layer bao-tokens {

/* ============================================================
   Focus visibility — 2px outline per WCAG 2.2 SC 2.4.11
   ============================================================ */

/* Inputs wrapped by a daisyUI label control (.input/.select) announce focus
   on the WRAPPER via :focus-within — outlining the inner element too paints
   a double ring (one owner per reactive state; focus stays visible). */
.btn:focus-visible,
a:focus-visible,
button:focus-visible,
input:focus-visible:not(.input input, .select select),
textarea:focus-visible:not(.textarea textarea),
select:focus-visible:not(.select select),
.bao-touch-target:focus-visible,
.bao-toolbar-action:focus-visible,
.bao-settings-tab:focus-visible,
.tab:focus-visible,
.bao-nav-item:focus-visible,
[tabindex]:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color, var(--accent-primary));
  outline-offset: var(--focus-ring-offset);
}

.input input:focus-visible,
.select select:focus-visible,
.textarea textarea:focus-visible {
  outline: none;
}

:focus:not(:focus-visible) {
  outline: none;
}

/*
 * Programmatic focus targets (skip link destination, htmx history element).
 * `outline-none` on the host keeps mouse focus clean, but keyboard focus
 * landing on [data-shell-scroll="main"] itself must stay visible (WCAG 2.4.7) — the inset
 * ring reads as the pane boundary without fighting the scrolled content.
 */
main[data-shell-scroll="main"]:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color, var(--accent-primary));
  outline-offset: var(--focus-ring-offset-tight);
}

/* ============================================================
   HTMX indicator + swap motion (CSP-safe; no runtime style inject)
   Aligned with the happydumpling app-shell contract.
   ============================================================ */

.htmx-indicator {
  opacity: 0;
  visibility: hidden;
}

:is(.htmx-request, [data-shell-loading]) .htmx-indicator,
:is(.htmx-request, [data-shell-loading]).htmx-indicator {
  opacity: 1;
  visibility: visible;
  transition-property: opacity;
  transition-timing-function: var(--easing-entrance);
  transition-duration: var(--duration-normal);
}

/* Form controls inherit readable base-content (theme-safe). */


/* Card border polish — data panels lift without nested glass.
   design.pdf §7.2: hover/focus color transitions run in the 120–180ms band
   (duration-fast = 120ms), never the 200ms menu band. */
.card-border.bao-data-panel,
.bao-data-panel.card-border {
  transition-property: border-color, box-shadow;
  transition-timing-function: var(--easing-standard);
  transition-duration: var(--duration-fast);
}
@media (hover: hover) and (pointer: fine) {
  .card-border.bao-data-panel:hover,
  .bao-data-panel.card-border:hover {
    border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
    box-shadow: 0 1px 0 0 var(--liquid-border-regular);
  }
}

/* Named main content for view transitions (SPA-like HTMX swaps). */
[data-shell-scroll="main"] {
  view-transition-name: main-content;
}

/* ============================================================
   Skeleton shimmer a11y overrides (phone densify + reduced motion)
   Base declaration + bao-skeleton-sweep keyframes live in
   tokens-glass-runtime-interactions.ts (single owner — DRY).
   ============================================================ */

/* Phone densify: freeze shimmer — infinite anim + HTMX load loops = vibration. */
@media (max-width: 47.99rem) {
  .skeleton-shimmer {
    background-image: none;
  }
}

/*
 * Table-region loading spinner (admin-table-fragment): the reduced-motion
 * twin of the skeleton freeze above. daisyUI paints the indicator as an
 * infinite rotation, which vibrates under the same conditions the shimmer
 * freeze exists for; frozen it stays a static status disc, and the
 * surrounding role="status" region keeps the announcement.
 */
@media (prefers-reduced-motion: reduce) {
  .table-loading-indicator {
    animation: none;
  }
}

/*
 * Entrance motion is transform-only. Opacity-from-0 stuck on WebView 101
 * (BlueStacks Chromium, tile_manager pressure) painted pure-white voids
 * over real SSR case rows while the header still painted. Never gate
 * readability on an animation that may not complete.
 */
@keyframes slide-up-fade {
  from {
    transform: translateY(var(--entrance-offset));
  }
  to {
    transform: translateY(0);
  }
}

/* Standardized entrance motion.
   Desktop main-nav uses View Transitions (hx-swap with VT modifier) —
   do NOT also run page-content entrances on those swaps (double refresh
   flash). Toasts and in-page .htmx-added fragments still animate. */
@media (prefers-reduced-motion: no-preference) {
  :is(#toast-region > *, [data-toast]) {
    animation: slide-up-fade var(--duration-normal) var(--easing-entrance);
  }
  /* Desktop only — on phone HTMX re-adds nodes every poll and re-animates = vibrate.
   * Context strips remount on every context-changed — never entrance-animate them. */
  @media (min-width: 48rem) {
    .htmx-added:not([data-chat-context]):not([data-capture-context-strip]):not(.bao-context-card):not(.bao-shell-context-chip) {
      animation: slide-up-fade var(--duration-normal) var(--easing-entrance) both;
    }
  }
  [data-chat-context].htmx-added,
  [data-chat-context] .htmx-added,
  [data-capture-context-strip].htmx-added,
  [data-capture-context-strip] .htmx-added,
  .bao-context-card.htmx-added,
  .bao-shell-context-chip.htmx-added {
    animation: none;
    transform: none;
  }
  /* design.pdf §7.2: button color/edge feedback is hover+press — 120ms
     (duration-fast) sits at the press ceiling and hover floor. */
  .btn {
    transition-property: color, background-color, border-color, box-shadow;
    transition-timing-function: var(--easing-standard);
    transition-duration: var(--duration-fast);
  }
  /* View transitions thrash WebView 101 compositing; desktop only. */
  @media (min-width: 48rem) {
    ::view-transition-old(main-content) {
      animation: fade-out-content var(--duration-normal) var(--easing-exit) both;
    }
    ::view-transition-new(main-content) {
      animation: slide-up-fade var(--duration-normal) var(--easing-entrance) var(--view-transition-new-delay) both;
    }
  }
}
@media (max-width: 47.99rem) {
  [data-shell-scroll="main"] {
    view-transition-name: none;
  }
  
}
.bao-toast-exit {
  opacity: 0;
  transition-property: opacity;
  transition-timing-function: var(--easing-exit);
  transition-duration: var(--duration-slow);
}

@keyframes fade-out-content {
  to { opacity: 0; }
}

/* Empty / error surfaces: solid panel, generous padding, no sparse float.
 *
 * The descendant selectors deliberately exclude two classes of element that
 * carry [role="status"]/[role="alert"] without being empty-state *content*:
 *
 *   :not([data-state])    — an element that declares its own state contract
 *                           owns its own presentation. Without this guard the
 *                           slim inline case-journey strip
 *                           ([data-case-journey][data-state="empty"]
 *                           [role="status"]) matched as a descendant of its own
 *                           empty wrapper and was inflated from a one-line flex
 *                           row into a 192px dashed column, overriding
 *                           [data-case-journey] purely on source order.
 *   :not(.htmx-indicator) — request indicators are transient chrome, not
 *                           content. loading-xs spinners were being given
 *                           min-block-size:12rem, so every indicator reserved
 *                           192px of layout even while at opacity 0.
 *   :not([data-empty-state-presentation="stage"])
 *                         — the annotation stage's empty overlay is full-bleed
 *                           (absolute inset-0 over the canvas), not a card. It
 *                           was taking the panel's rounded corner while the
 *                           stage beneath stayed square, so each corner showed
 *                           the square edge through the curve as a notch.
 *
 * The two guards below stop that list growing an entry per indicator. Both
 * state the same invariant: a COSMETIC rule must never resurrect an element
 * something else deliberately hid.
 *
 *   :not([hidden])        — the runtime hid it by attribute. This selector is
 *                           ancestor-qualified, so validate-hidden-attribute-
 *                           authority's "conditional rules may outrank
 *                           [hidden]" carve-out let it win: the tablet case
 *                           detail pane's [data-case-detail-loading] span ships
 *                           `hidden`, and was still painted as a 192px dashed
 *                           panel with a lone spinner in it.
 *   :not([data-transient-chrome])
 *                         — chrome its own component contract hides in CSS
 *                           rather than by attribute, where an attribute would
 *                           break the states that must show it. The cases
 *                           pull-to-refresh indicator is display:none off
 *                           touch, but this rule outranked that (0,6,0 beats
 *                           0,1,0) and reserved 192px above every desktop case
 *                           list.
 *
 * Genuine empty panels (a [role="status"] child inside an empty host, or an
 * explicit .bao-empty-panel) still receive the full treatment.
 *
 *   :not(:is([data-state]:not([data-state="empty"]) *))
 *                         — the nearest declared state owns the chrome. Every
 *                           exception above was one surface discovering that a
 *                           descendant combinator crosses state boundaries, and
 *                           answering with another attribute to opt out; this
 *                           says the thing they were each working around.
 *                           Measured on the dashboard: the widget card still
 *                           read data-state="empty" from its initial render
 *                           while its body and fragment had both swapped to
 *                           "success", so every widget's status chip — a
 *                           62px-wide "Active" pill — was painted as a
 *                           192px dashed empty panel. 22 elements app-wide, on
 *                           surfaces that had loaded their data correctly.
 *                           A nested success subtree is not empty, whatever an
 *                           ancestor still claims.
 */
[data-page] [data-state="empty"] [role="status"]:not([data-state]):not([hidden]):not(.htmx-indicator):not([data-empty-state-presentation="stage"]):not([data-transient-chrome]):not(:is([data-state]:not([data-state="empty"]) *)),
[data-page] [data-state="error"] [role="alert"]:not([data-state]):not([hidden]):not(.htmx-indicator):not([data-empty-state-presentation="stage"]):not([data-transient-chrome]):not(:is([data-state]:not([data-state="error"]) *)),
.bao-empty-panel {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-inline);
  text-align: center;
  min-block-size: 12rem;
  padding-block: var(--space-page);
  padding-inline: var(--space-section);
  border: 1px dashed var(--liquid-border-regular);
  border-radius: var(--radius-box, 1rem);
  background: color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-tinted) * 100%), var(--bg-surface));
}

/* daisyUI paints the field focus ring in base-content (a black 2px ring on
   light themes). HIG keyboard focus is the accent colour on every control,
   so the field wrappers take the shared focus-ring colour. */
.input:focus,
.input:focus-within,
.select:focus,
.select:focus-within,
.textarea:focus,
.textarea:focus-within {
  --input-color: var(--focus-ring-color, var(--accent-primary));
}

/* ============================================================
   Apple HIG accessibility preference modes
   ============================================================
   These media queries are emitted unconditionally so the system
   respects accessibility settings automatically. They are NOT
   opt-in. */

/* Reduced Transparency: solid chrome surface, no backdrop blur.
   WCAG/governance: glass loses to reduced-transparency prefs.
   Also honors product override data-reduced-transparency on html. */
@media (prefers-reduced-transparency: reduce) {
  .bao-glass-control {
    min-height: var(--touch-target-min, 2.75rem);
    min-width: var(--touch-target-min, 2.75rem);
    border-color: var(--color-base-300);
    box-shadow: none;
    background: var(--bg-panel, var(--color-base-100));
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .dropdown-content,
  .bao-dropdown-panel {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /*
   * The shell topbar is painted by ID-specificity rules —
   * .bao-shell-topbar[data-shell-topbar] at (1,1,0) and
   * .bao-shell-topbar.navbar.bao-surface-glass-regular at (1,2,0) — which outrank
   * every class selector above, so the header kept its blur and saturation
   * under both OS preferences while the app's own data-attribute toggles
   * flattened it correctly. Honouring the settings switch but ignoring the
   * operating system is the defect; these selectors match that specificity
   * rather than reaching for !important.
   */
  .bao-shell-topbar[data-shell-topbar],
  .bao-shell-topbar.navbar.bao-surface-glass-regular,
  .bao-shell-topbar.navbar.bao-surface-glass-regular.bao-glass-small {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-clear-dim,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-modal.bao-surface-glass-lens {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-strong.bao-glass-large,
  .bao-surface-glass-strong.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-small {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  .bao-surface-glass-lens {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  .bao-surface-glass-regular .btn-soft.bao-toolbar-action,
  .bao-surface-glass-regular .btn-soft:not(.btn-primary):not(.btn-error),
  .bao-surface-glass-clear .btn-soft.bao-toolbar-action {
    background-color: var(--color-base-100, var(--bg-panel));
    border-color: var(--color-base-300);
    box-shadow: none;
  }
  .bao-surface-glass-regular::before,
  .bao-surface-glass-regular::after,
  .bao-surface-glass-clear::before,
  .bao-surface-glass-clear::after,
  .bao-surface-glass-strong::before,
  .bao-surface-glass-strong::after,
  .bao-surface-glass-modal::before,
  .bao-surface-glass-modal::after {
    display: none;
  }
  /* Raw-blur surfaces outside the variant classes (GLASS-06): the sticky
     journey band and the filter-sheet scrim must solidify too. */
  [data-case-journey-host] {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /* Disabled, loading and open-popover glass are re-declared at (0,2,0) in
     tokens-glass-base-reactive and tokens-glass-control-chrome — the disabled
     rule drops to an 8px blur, the loading rule RAISES it to the regular blur,
     and an open dropdown panel paints the 32px nav blur. All three outrank the
     (0,1,0) suppressions above, so an operator who asked the OS to reduce
     transparency kept a live backdrop-filter on every disabled control, every
     surface mid-fetch, and every menu they opened. A media query adds no
     specificity, so the suppression has to be written at the same reach the
     rule it is answering. */
  .bao-surface-glass-regular:disabled,
  .bao-surface-glass-regular[aria-disabled="true"],
  .bao-surface-glass-clear:disabled,
  .bao-surface-glass-clear[aria-disabled="true"],
  .bao-surface-glass-strong:disabled,
  .bao-surface-glass-strong[aria-disabled="true"],
  .bao-surface-glass-modal:disabled,
  .bao-surface-glass-modal[aria-disabled="true"],
  .bao-surface-glass-regular[data-state="loading"],
  .bao-surface-glass-clear[data-state="loading"],
  .bao-surface-glass-strong[data-state="loading"],
  .bao-surface-glass-modal[data-state="loading"],
  .bao-dropdown-panel:popover-open,
  .bao-dropdown-panel[data-popover-open="true"],
  .bao-shell-dropdown {
    background-color: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  /* Reactive hover/focus is (0,2,0) and the suppression selectors above are
     (0,1,0); a media query adds no specificity, so an OS-level
     reduce-transparency user got the translucent material back on hover and
     on keyboard focus — transparency without blur, over live content, on the
     exact surface they asked to be made solid. */
  .bao-surface-glass-reactive:hover,
  .bao-surface-glass-reactive:focus-within {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  /* The RESTING state needed the same (0,2,0) reach and never got it. Measured
     on the deployed build under Increased Contrast: every other glass surface
     computed backdrop-filter:none while
     .bao-surface-glass-regular.bao-surface-glass-reactive still computed a live
     14px blur with saturation — the one surface that kept live material for a
     user who asked for maximum contrast, and it only solidified once they
     hovered it. Repeated class buys the specificity with no id selector and no
     cascade override. */
  .bao-surface-glass-reactive.bao-surface-glass-reactive {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
}
html[data-reduced-transparency="true"] .bao-surface-glass-regular,
html[data-reduced-transparency="true"] .bao-surface-glass-clear,
html[data-reduced-transparency="true"] .bao-surface-glass-clear-dim,
html[data-reduced-transparency="true"] .bao-surface-glass-strong,
html[data-reduced-transparency="true"] .bao-surface-glass-modal,
html[data-reduced-transparency="true"] .bao-surface-glass-lens {
  background: var(--bg-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transition-duration: var(--duration-instant);
}
html[data-reduced-transparency="true"] .bao-surface-glass-regular::before,
html[data-reduced-transparency="true"] .bao-surface-glass-regular::after,
html[data-reduced-transparency="true"] .bao-surface-glass-clear::before,
html[data-reduced-transparency="true"] .bao-surface-glass-clear::after,
html[data-reduced-transparency="true"] .bao-surface-glass-strong::before,
html[data-reduced-transparency="true"] .bao-surface-glass-strong::after,
html[data-reduced-transparency="true"] .bao-surface-glass-modal::before,
html[data-reduced-transparency="true"] .bao-surface-glass-modal::after {
  display: none;
}
html[data-reduced-transparency="true"] [data-case-journey-host] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
/* Shell density: compact clinical chrome (HIG 44px min chrome). */
html[data-density="compact"] {
  --space-page: 0.75rem;
  --space-section: 0.75rem;
  --space-inline: 0.5rem;
  --chrome-min-height: max(2.75rem, 44px);
}
html[data-density="comfortable"] {
  --space-page: 1.25rem;
  --space-section: 1rem;
  --space-inline: 0.75rem;
  --chrome-min-height: max(2.75rem, var(--touch-target-min));
}
html[data-density="spacious"] {
  --space-page: 1.5rem;
  --space-section: 1.25rem;
  --space-inline: 1rem;
  --chrome-min-height: max(3rem, var(--touch-target-min));
}

/* Increased Contrast: drop the blur and tint entirely; rely on a solid
   border for the panel edge so the pane reads against any background.
   Apple HIG: "Increased contrast makes elements predominantly black or
   white and highlights them with a contrasting border".
   Also honors product override data-high-contrast on html so the
   Settings → Accessibility toggle can force the same behavior. */
@media (prefers-contrast: more) {
  .dropdown-content,
  .bao-dropdown-panel,
  .bao-glass-control {
    border-color: var(--liquid-border-contrast);
  }
  /*
   * The shell topbar is painted by ID-specificity rules —
   * .bao-shell-topbar[data-shell-topbar] at (1,1,0) and
   * .bao-shell-topbar.navbar.bao-surface-glass-regular at (1,2,0) — which outrank
   * every class selector above, so the header kept its blur and saturation
   * under both OS preferences while the app's own data-attribute toggles
   * flattened it correctly. Honouring the settings switch but ignoring the
   * operating system is the defect; these selectors match that specificity
   * rather than reaching for !important.
   */
  .bao-shell-topbar[data-shell-topbar],
  .bao-shell-topbar.navbar.bao-surface-glass-regular,
  .bao-shell-topbar.navbar.bao-surface-glass-regular.bao-glass-small {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-clear-dim,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-modal.bao-surface-glass-lens,
  .bao-surface-glass-lens,
  .bao-surface-glass-reactive,
  .bao-glass-large,
  .bao-glass-small,
  .bao-glass-fill,
  .bao-glass-control,
  .dropdown-content,
  .bao-dropdown-panel,
  /* Mobile dock needs ID-level reach: tokens-layout-dock-base is emitted
     after this module, so a plain .bao-mobile-dock.dock ties on specificity
     and loses — the dock kept its blur under Increased Contrast.
     The conversation input owns its contrast border in its canonical component. */
  .bao-mobile-dock.dock.bao-mobile-dock,
  nav.bao-mobile-dock[data-mobile-dock] {
    background: var(--bg-panel);
    border-width: 2px;
    /* The comment above promises the blur is dropped "entirely". Only the
       lens/strong follow-up rule used to do that, so regular, clear and modal
       kept a live 20-36px backdrop-filter behind an opaque fill — invisible
       output at full GPU cost. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  /* Density modifiers are (0,2,0) too, and the same reasoning applies to
     them — but only the reduced-transparency block above ever got these
     pairs. Measured live under Increased Contrast with glass on:
     .bao-shell-sidebar kept blur(32px) because .bao-surface-glass-regular
     .bao-glass-large (0,2,0) outranked the (0,1,0) suppression, while the
     identical sidebar went solid correctly under reduced transparency. The
     product toggle path was never affected: html[data-high-contrast="true"]
     .bao-glass-large is (0,2,1) and already won, which is exactly why this
     survived every check that used the in-app switch. */
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-strong.bao-glass-large,
  .bao-surface-glass-strong.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-small {
    background: var(--bg-panel);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  /* Reactive hover/focus is (0,2,0); the suppression selectors above are
     (0,1,0) and a media query adds no specificity, so without these the
     material came back translucent the moment a pointer or focus entered. */
  .bao-surface-glass-reactive:hover,
  .bao-surface-glass-reactive:focus-within {
    background: var(--bg-panel);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }
  .bao-surface-glass-regular::before,
  .bao-surface-glass-regular::after,
  .bao-surface-glass-clear::before,
  .bao-surface-glass-clear::after,
  .bao-surface-glass-strong::before,
  .bao-surface-glass-strong::after,
  .bao-surface-glass-modal::before,
  .bao-surface-glass-modal::after {
    display: none;
  }
  /* GLASS-06: raw-blur surfaces outside the variant classes lose blur. */
  [data-case-journey-host] {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
html[data-high-contrast="true"] .bao-surface-glass-regular,
html[data-high-contrast="true"] .bao-surface-glass-clear,
html[data-high-contrast="true"] .bao-surface-glass-clear-dim,
html[data-high-contrast="true"] .bao-surface-glass-strong,
html[data-high-contrast="true"] .bao-surface-glass-modal,
html[data-high-contrast="true"] .bao-surface-glass-lens,
html[data-high-contrast="true"] .bao-surface-glass-reactive,
html[data-high-contrast="true"] .bao-glass-large,
html[data-high-contrast="true"] .bao-glass-small,
html[data-high-contrast="true"] .bao-glass-fill,
html[data-high-contrast="true"] .bao-glass-control {
  min-height: var(--touch-target-min, 2.75rem);
  background: var(--bg-panel);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transition-duration: var(--duration-instant);
  /* Increase Contrast (HIG): the plate goes opaque and its edge goes to the
     full-contrast hairline. It stays a hairline — a 2px outline on every
     toolbar, palette, sheet and control read as a wireframe (measured
     2026-08-23 on an operator with the setting persisted: 2px rgba(24,24,27,.65)
     on all four editor plates), and the edge is not what carries contrast;
     the opaque fill against the stage is. */
  border-color: var(--liquid-border-contrast);
  border-width: 1px;
}
html[data-high-contrast="true"] .bao-surface-glass-regular::before,
html[data-high-contrast="true"] .bao-surface-glass-regular::after,
html[data-high-contrast="true"] .bao-surface-glass-clear::before,
html[data-high-contrast="true"] .bao-surface-glass-clear::after,
html[data-high-contrast="true"] .bao-surface-glass-strong::before,
html[data-high-contrast="true"] .bao-surface-glass-strong::after,
html[data-high-contrast="true"] .bao-surface-glass-modal::before,
html[data-high-contrast="true"] .bao-surface-glass-modal::after {
  display: none;
}
html[data-high-contrast="true"] [data-case-journey-host] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-page] [data-state-content]:not([hidden]),
  #toast-region > *,
  .htmx-added {
    animation: none;
  }
  .bao-pulse,
  .bao-pulse-scale,
  .bao-pulse-alpha {
    transform: none;
  }
  ::view-transition-old(main-content),
  ::view-transition-new(main-content) {
    animation: none;
  }
  :is(.htmx-request, [data-shell-loading]) .htmx-indicator,
  :is(.htmx-request, [data-shell-loading]).htmx-indicator {
    transition-duration: var(--duration-instant);
    transition-property: none;
  }
}

/* Reduced Motion: keep the global 1ms clamp, and drop live backdrop blur.
   Liquid Glass blur is motion. Reduce Motion and data-reduced-motion
   solidify the same functional glass Reduce Transparency already flattens. */
@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    animation-duration: var(--reduced-motion-min-duration);
    animation-iteration-count: 1;
    animation-delay: var(--duration-instant);
    transition-delay: var(--duration-instant);
    transition-duration: var(--reduced-motion-min-duration);
    scroll-behavior: auto;
  }
}

/* Same surfaces as Reduce Transparency. Blur off, solid fill on the
   variant classes. Scrim and journey host only lose the filter. */
@media (prefers-reduced-motion: reduce) {
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-clear-dim,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-lens {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  [data-case-journey-host] {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
html[data-reduced-motion="true"] .bao-surface-glass-regular,
html[data-reduced-motion="true"] .bao-surface-glass-clear,
html[data-reduced-motion="true"] .bao-surface-glass-clear-dim,
html[data-reduced-motion="true"] .bao-surface-glass-strong,
html[data-reduced-motion="true"] .bao-surface-glass-modal,
html[data-reduced-motion="true"] .bao-surface-glass-lens {
  background: var(--bg-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  transition-duration: var(--duration-instant);
}
html[data-reduced-motion="true"] [data-case-journey-host] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}

/* Accessibility preference modes must win over the topbar's ID-specificity
 * chrome above: drop the (now pointless) blur behind the solid fill and give
 * increased contrast a stronger bottom edge for every accessibility preference signal. */
@media (prefers-reduced-transparency: reduce), (prefers-contrast: more) {
  .bao-shell-topbar.navbar,
  .bao-shell-topbar[data-shell-topbar] {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
html[data-reduced-transparency="true"] .bao-shell-topbar.navbar,
html[data-reduced-transparency="true"] .bao-shell-topbar[data-shell-topbar],
html[data-high-contrast="true"] .bao-shell-topbar.navbar,
html[data-high-contrast="true"] .bao-shell-topbar[data-shell-topbar] {
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
@media (prefers-contrast: more) {
  .bao-shell-topbar.navbar,
  .bao-shell-topbar[data-shell-topbar] {
    border-bottom-width: 2px;
  }
}
html[data-high-contrast="true"] .bao-shell-topbar.navbar,
html[data-high-contrast="true"] .bao-shell-topbar[data-shell-topbar] {
  border-bottom-width: 2px;
}

/* Equal reach for the sampling-container descendant rule (0,2,0).
   A media query adds no specificity, so the nested solidify would
   outrank the class-only degrade and keep a themed fill under
   forced colors, reduced transparency, and increased contrast. */
@media (prefers-reduced-transparency: reduce) {
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal,
    .bao-surface-glass-lens
  ),
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}
html[data-reduced-transparency="true"] :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-lens
),
html[data-reduced-transparency="true"] :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
  background: var(--bg-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
@media (prefers-contrast: more) {
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal,
    .bao-surface-glass-lens
  ),
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
    background: var(--bg-surface);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    border-color: var(--liquid-border-contrast);
  }
}
html[data-high-contrast="true"] :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-lens
),
html[data-high-contrast="true"] :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
  background: var(--bg-surface);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-color: var(--liquid-border-contrast);
}


/* Tinted appearance decorates material edges. The base variants own fill;
   the sampling-container contract owns opaque nested surfaces. Repainting
   their fill here made nested menus translucent after their blur was removed. */
@media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (forced-colors: none) {
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-regular,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-strong,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-surface-glass-modal {
  border-color: var(--liquid-border-regular);
}
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-glass-control {
  min-height: var(--touch-target-min, 2.75rem);
  min-width: var(--touch-target-min, 2.75rem);
  background-color: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  border-color: var(--liquid-border-regular);
}
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-sidebar,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-sidebar.bao-shell-sidebar,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-topbar,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-topbar.bao-shell-topbar,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-mobile-dock,
html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-mobile-dock.bao-mobile-dock {
  --liquid-material-color: var(--bg-surface);
  --liquid-material-rest-alpha: var(--liquid-fill-tinted);
}

/* Sidebar appearance retains its existing coarse-pointer opacity token. */
@media (pointer: coarse) {
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-sidebar,
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-sidebar.bao-shell-sidebar,
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-topbar,
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-shell-topbar.bao-shell-topbar,
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-mobile-dock,
  html[data-liquid-glass="tinted"]:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]) .bao-mobile-dock.bao-mobile-dock {
    --liquid-material-rest-alpha: var(--liquid-fill-persistent-coarse);
  }
}
}

/* ============================================================
   Forced colors — respect user-selected system colors
   ============================================================ */

@media (forced-colors: active) {
  .bao-surface-glass-regular,
  .bao-surface-glass-clear,
  .bao-surface-glass-clear-dim,
  .bao-surface-glass-strong,
  .bao-surface-glass-modal,
  .bao-surface-glass-modal.bao-surface-glass-lens,
  .bao-surface-glass-solid,
  .bao-surface-glass-lens,
  .bao-shell-topbar.navbar,
  .bao-shell-topbar[data-shell-topbar],
  .bao-mobile-dock.dock.bao-mobile-dock,
  nav.bao-mobile-dock[data-mobile-dock],
  .bao-dropdown-panel {
    color: CanvasText;
    background: Canvas;
    border: 1px solid ButtonText;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  /* Density modifiers need equal selector reach because media queries add no
     specificity and backdrop-filter is not force-adjusted by the browser. */
  .bao-surface-glass-regular.bao-glass-large,
  .bao-surface-glass-regular.bao-glass-small,
  .bao-surface-glass-strong.bao-glass-large,
  .bao-surface-glass-strong.bao-glass-small,
  .bao-surface-glass-clear.bao-glass-large,
  .bao-surface-glass-clear.bao-glass-small {
    color: CanvasText;
    background: Canvas;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  .bao-glass-control {
    min-height: var(--touch-target-min, 2.75rem);
    min-width: var(--touch-target-min, 2.75rem);
    color: CanvasText;
    background: Canvas;
    border: 1px solid ButtonText;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  .bao-surface-glass-reactive.bao-surface-glass-reactive,
  .bao-surface-glass-reactive:hover,
  .bao-surface-glass-reactive:focus-within {
    color: CanvasText;
    background: Canvas;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
    transition-duration: var(--duration-instant);
  }

  /* Specular ring and inner illumination are decorative gradient layers. */
  .bao-surface-glass-regular::before,
  .bao-surface-glass-regular::after,
  .bao-surface-glass-clear::before,
  .bao-surface-glass-clear::after,
  .bao-surface-glass-strong::before,
  .bao-surface-glass-strong::after,
  .bao-surface-glass-modal::before,
  .bao-surface-glass-modal::after {
    display: none;
  }

  [data-case-journey-host] {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }

  .skeleton-shimmer {
    animation: none;
    background-image: none;
  }

  .btn:focus-visible,
  a:focus-visible,
  button:focus-visible,
  input:focus-visible,
  textarea:focus-visible,
  select:focus-visible,
  [tabindex]:focus-visible {
    outline: var(--focus-ring-width) solid Highlight;
    outline-offset: var(--focus-ring-offset);
  }

  .bao-nav-item.menu-active,
  .bao-nav-item[aria-current="page"] {
    background: SelectedItem;
    color: SelectedItemText;
    box-shadow: none;
    border: 1px solid SelectedItemText;
  }
}

@media (forced-colors: active) {
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) :is(
    .bao-surface-glass-regular,
    .bao-surface-glass-clear,
    .bao-surface-glass-strong,
    .bao-surface-glass-modal,
    .bao-surface-glass-lens
  ),
  :is(.bao-glass-sampling-container, .bao-page-chrome, .bao-shell-topbar, .bao-shell-sidebar, .bao-mobile-dock, .bao-surface-glass-modal, .bao-sheet-panel) .bao-shell-dropdown {
    color: CanvasText;
    background: Canvas;
    border: 1px solid ButtonText;
    box-shadow: none;
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}

/*
 * Dynamic Type reach (HIG Text & Custom Settings / accessibility zoom).
 */

[data-camera-preview-placeholder] [data-capture-empty-cta],
[data-capture-case-required] [data-capture-empty-cta] {
  max-width: 100%;
  min-width: 0;
  white-space: normal;
  height: auto;
  min-height: var(--touch-target-min, 2.75rem);
}


/* ---- 4. Page-root pan: content blows past, the page reveals it. ---- */
/*
 * At 400% root font a DataTable's rem-padded columns demand more than the
 * viewport; the grid track stretches to min-content and every sibling
 * control rides past the edge (measured: headings and buttons at
 * right 1583px on a 1440px viewport across /specimens, /training, /debug,
 * /setup, /settings). densify-b clips the page root, which hides the
 * content but provides no way to reach it — the audit fails every rider.
 * The page root owns the scroll: one pan reveals the whole blown track.
 * min-width: 0 on the state-content column stops the grid itself from
 * stretching where the layout allows it.
 */
[data-page] > [data-state-content] {
  min-width: 0;
  max-width: 100%;
}
[data-page-type="collection"],
[data-page-type="form"],
[data-page-type="detail"],
[data-page-type="home"] {
  max-width: 100%;
  /*
   * clip, never auto: overflow-x:auto forces computed overflow-y:auto,
   * turning every page track into a second vertical scroller nested in
   * #app-main — wheel momentum then overruns the real content into a
   * blank void. Horizontal Dynamic-Type reach lives on the inner wide
   * widgets (table wrap, code, QR panes), each already its own x-scroller.
   */
  overflow-x: clip;
}


}
@layer bao-tokens {

/* ============================================================
   Pointer-gated hover utilities (design.pdf §6: hover is an
   enhancement for fine pointers only — touch never traps a
   stuck hover state). Replace raw `hover:` utilities with these
   canonical classes so every hover effect is media-gated.
   ============================================================ */

@media (hover: hover) and (pointer: fine) {
  .bao-hover-row:hover {
    background-color: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  .bao-hover-soft:hover {
    background-color: var(--bg-surface-hover);
  }
  .bao-hover-soft-veil:hover {
    background-color: color-mix(in oklab, var(--bg-surface) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  .bao-hover-strong:hover {
    background-color: var(--color-base-300);
  }
  .bao-hover-panel-border:hover {
    border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  .bao-hover-text-primary:hover {
    color: var(--color-primary);
  }
  .bao-hover-underline:hover {
    text-decoration-line: underline;
  }
  .bao-hover-panel:hover {
    background-color: var(--color-base-100);
  }
  .bao-hover-border-s-primary:hover {
    border-inline-start-color: var(--color-primary);
  }
  .bao-hover-overlay-btn:hover {
    background-color: var(--overlay-btn-secondary-bg);
  }
}

/* ============================================================
   Scrim SSOT — one overlay-backdrop token owns every blocking
   scrim. daisyUI .modal-backdrop defaults to a raw black tint;
   align it with the canonical overlay token (design.pdf §5.8).
   ============================================================ */

.modal .modal-backdrop,
.modal-backdrop {
  background: var(--overlay-backdrop);
}

/* design.pdf §6: disabled keeps the label readable — drop elevation/chroma
   instead of crushing text via daisyUI opacity (design.pdf §2.10). */
.btn:disabled,
.btn-disabled {
  opacity: 1;
  background-color: var(--color-base-200, var(--bg-panel));
  border-color: var(--color-base-300);
  /* Readable chroma drop via solid mix against panel — never element opacity
   * (design.pdf §2.10 / §6; gate S113 requires ≥45% content in the mix). */
  color: color-mix(in oklab, var(--color-base-content) 55%, var(--color-base-200, var(--bg-panel)));
  pointer-events: none;
  box-shadow: none;
}


}
@layer bao-tokens {

/* Structural transitions consume the shared motion scale. */
.bao-shell-sidebar {
  transition-property: width;
  transition-duration: var(--duration-slow);
  transition-timing-function: var(--easing-standard);
}

/* Capture tooltip hosts leave their actual controls hittable. */
[data-capture-action-bar] .tooltip {
  pointer-events: none;
}
[data-capture-action-bar] .tooltip > :is(.btn, .bao-menu-item):not(:disabled):not([aria-disabled="true"]) {
  pointer-events: auto;
}
@container shell (min-width: 48rem) and (max-width: 63.99rem) {
  [data-capture-action-bar] .tooltip.inline-flex {
    display: inline-block;
    width: auto;
    height: auto;
  }
}

/* A dragged widget retains its purposeful placement cue. */
@container shell (max-width: 47.99rem) {
  .bao-dashboard-widget-dragging {
    transform: scale(0.95);
  }
}

}
@layer bao-tokens {

/* Responsive layout changes geometry; shared motion owns press feedback. */
@media (max-width: 47.99rem) {
  .bao-mobile-dock-item {
    min-height: var(--touch-target-min);
    min-width: var(--touch-target-min);
  }
}

}
@layer bao-tokens {

/* ═══════════════════════════════════════════════════════════════════
   REDUCED MOTION — disable all fluid animations
   Specificity: scoped to each class + media query (no cascade force).
   ═══════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
  .bao-surface-glass-regular:where(button, a, [role="button"]):active,
  .bao-surface-glass-clear:where(button, a, [role="button"]):active {
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .bao-dashboard-widget-dragging,
  .bao-surface-glass-strong:where(button, a, [role="button"]):hover,
  .bao-surface-glass-strong:where(button, a, [role="button"]):active {
    animation: none;
    transition: none;
    transform: scale(1);
  }
}

/* The in-app preference has the same motion contract as the OS setting. */
html[data-reduced-motion="true"] .bao-dashboard-widget-dragging,
html[data-reduced-motion="true"] .bao-surface-glass-regular:where(button, a, [role="button"]):active,
html[data-reduced-motion="true"] .bao-surface-glass-clear:where(button, a, [role="button"]):active,
html[data-reduced-motion="true"] .bao-surface-glass-strong:where(button, a, [role="button"]):hover,
html[data-reduced-motion="true"] .bao-surface-glass-strong:where(button, a, [role="button"]):active {
  animation: none;
  transition: none;
  transform: scale(1);
}

@media (prefers-reduced-motion: reduce) {
  .bao-shell-sidebar {
    transition: none;
  }
}
html[data-reduced-motion="true"] .bao-shell-sidebar {
  transition: none;
}

}
@layer bao-tokens {

/* Touch target minimum sizing (44x44px per Apple HIG) */
.min-h-touch-target {
  min-height: var(--touch-target-min, 2.75rem);
}

/*
 * Drag handles only when customize mode is on. Default browse must not
 * expose grab affordances on every metric card (Apple HIG: chrome vs content).
 * Nested navigation remains interactive in browse mode.
 */
[data-dashboard-layout-root]:not([data-dashboard-editing="true"]) [data-dashboard-drag-handle] {
  cursor: default;
}
/*
 * The editing handle owns its touch floor and spacing on every input type.
 * Ordinary reading headers retain their content geometry. touch-action:none
 * keeps coarse-pointer dragging from being claimed by page scrolling.
 */
[data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-drag-handle] {
  position: relative;
  z-index: var(--z-content-overlay);
  min-height: var(--touch-target-min, 2.75rem);
  padding-block: var(--space-inline);
  cursor: grab;
  touch-action: none;
  transition: background-color var(--duration-fast) var(--easing-standard);
}

@media (hover: hover) and (pointer: fine) {
  [data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-drag-handle]:hover {
    background-color: var(--bg-surface-hover);
    border-radius: var(--radius-sm, 0.5rem);
  }
}

/* The handle state owns its active cursor as well as its feedback paint. */
[data-dashboard-layout-root][data-dashboard-editing="true"] [data-dashboard-drag-handle]:active {
  cursor: grabbing;
  background-color: var(--bg-surface);
}/* Widget dragging state — geometry from setHostCssVars (--bao-drag-*). */
.bao-dashboard-widget-dragging,
[data-dashboard-widget][data-bao-dragging="true"] {
  position: fixed;
  left: var(--bao-drag-left, 0);
  top: var(--bao-drag-top, 0);
  width: var(--bao-drag-width, auto);
  transition: none;
  pointer-events: none;
}/* Drag placeholder — size from setHostCssVars (--bao-placeholder-*).
   The dashed primary outline lives here,
not on the element: the browser bundle
   used to append rounded-box,
border-2,
border-dashed,
border-primary/50 and
   bg-primary/5 to this class in app-shell-dashboard-drag-geometry.ts,
so half the
   placeholder's appearance was decided in TypeScript where no canon gate reads
   it. */
.bao-dashboard-widget-placeholder {
  width: var(--bao-placeholder-width, 100%);
  height: var(--bao-placeholder-height, 8rem);
  border-radius: var(--radius-box, 1rem);
  border: 2px dashed var(--color-primary);
  background-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  transition: box-shadow var(--duration-normal) var(--easing-standard),
    opacity var(--duration-normal) var(--easing-standard),
    transform var(--duration-normal) var(--easing-standard);
}

/* ═══════════════════════════════════════════════════════════════════
   CAPTURE PAGE LAYOUT FIXES
   ═══════════════════════════════════════════════════════════════════ */

/* Fix shutter chrome z-index on tablet to avoid occluding session controls */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  [data-capture-shutter-chrome] {
    z-index: var(--z-canvas-controls, 30);
  }

  [data-session-controls] {
    z-index: var(--z-canvas-controls, 30);
    position: relative;
  }
}

/* Ensure Evidence/Reports buttons are not occluded */
[data-capture-actions] .btn {
  position: relative;
  z-index: var(--z-canvas-actions, 40);
}

[data-dashboard-panel-id][data-dashboard-dragging="true"] {
  opacity: 0.6;
}
[data-dashboard-panel-id][data-dashboard-drop-target="true"] {
  outline: var(--focus-ring-width) solid var(--accent-primary);
  outline-offset: 0;
}

}
@layer bao-tokens {

/* ═══════════════════════════════════════════════════════════════════
   VIEW TRANSITIONS — Apple HIG page navigation
   ═══════════════════════════════════════════════════════════════════ */

/*
 * Same-document transitions only (htmx transition:true swaps).
 * No @view-transition navigation opt-in: cross-document transitions
 * permanently freeze the post-login document in Chromium (see module doc).
 */

::view-transition-old(root) {
  animation: bao-view-transition-fade-out var(--duration-normal) var(--easing-exit);
}

::view-transition-new(root) {
  animation: bao-view-transition-fade-in var(--duration-slow) var(--easing-entrance);
}

@keyframes bao-view-transition-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes bao-view-transition-fade-in {
  from {
    opacity: 0;
    transform: scale(1.02);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

/*
 * Shared element transitions for navigation items
 */
.bao-nav-item {
  view-transition-name: var(--vt-nav-item, none);
}

[data-route-id="dashboard"] {
  --vt-nav-item: nav-dashboard;
}

[data-route-id="cases"] {
  --vt-nav-item: nav-cases;
}

[data-route-id="capture"] {
  --vt-nav-item: nav-capture;
}

[data-route-id="editor"] {
  --vt-nav-item: nav-editor;
}

[data-route-id="models"] {
  --vt-nav-item: nav-models;
}::view-transition-group(nav-dashboard),
::view-transition-group(nav-cases),
::view-transition-group(nav-capture),
::view-transition-group(nav-editor),
::view-transition-group(nav-models) {
  animation-duration: var(--duration-normal);
  animation-timing-function: var(--easing-standard);
}

/*
 * Page header transitions
 */
[data-primitive="PageHeader"] {
  view-transition-name: page-header;
}

::view-transition-group(page-header) {
  animation-duration: var(--duration-slow);
  animation-timing-function: var(--easing-entrance);
}

/*
 * Dashboard widget transitions
 */
[data-dashboard-widget] {
  view-transition-name: var(--vt-widget, none);
}

[data-widget="cases"] {
  --vt-widget: widget-cases;
}

[data-widget="capture"] {
  --vt-widget: widget-capture;
}

[data-widget="models"] {
  --vt-widget: widget-models;
}

[data-widget="ai-analysis"] {
  --vt-widget: widget-ai;
}::view-transition-group(widget-cases),
::view-transition-group(widget-capture),
::view-transition-group(widget-models),
::view-transition-group(widget-ai) {
  animation-duration: var(--duration-slow);
  animation-timing-function: var(--easing-entrance);
}

/*
 * Reduced motion: disable all view transitions
 */
@media (prefers-reduced-motion: reduce) {::view-transition-old(root),
::view-transition-new(root),
::view-transition-group(*) {
    animation-duration: var(--reduced-motion-min-duration);
  }
}

/*
 * Fallback for browsers without View Transitions API
 */
@supports not (view-transition-name: none) {
  [data-page] {
    animation: bao-page-fallback-enter var(--duration-slow) var(--easing-entrance);
  }

  @keyframes bao-page-fallback-enter {
    from {
      opacity: 0;
      transform: translateY(var(--entrance-offset, 0.375rem));
    }
    to {
      opacity: 1;
      transform: translateY(0);
    }
  }
}

/* Respect the product preference even when the OS preference is unchanged. */
html[data-reduced-motion="true"]::view-transition-old(*),
html[data-reduced-motion="true"]::view-transition-new(*),
html[data-reduced-motion="true"]::view-transition-group(*) {
  animation: none;
}

@keyframes bao-view-transition-fade-reduced {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

/* OS Reduce Motion: the entrance keyframe still scales. Replace that
   zoom with a fade. Duration stays on the earlier reduced-motion rule. */
@media (prefers-reduced-motion: reduce) {
  ::view-transition-new(root) {
    animation-name: bao-view-transition-fade-reduced;
  }
}

@supports not (view-transition-name: none) {
  @media (prefers-reduced-motion: reduce) {
    [data-page] {
      animation-name: bao-view-transition-fade-reduced;
      animation-duration: var(--reduced-motion-min-duration);
    }
  }
}

html[data-reduced-motion="true"] [data-page] {
  animation-name: bao-view-transition-fade-reduced;
}

}
@layer bao-tokens {


/* ═══════════════════════════════════════════════════════════════════
   RUNTIME INTERACTIONS — JS-driven CSS custom properties + data attrs
   ═══════════════════════════════════════════════════════════════════ */

/* The top-layer region carries layout only. Empty space and stack gaps must pass input to the editor, while interactive notices retain their own targets. */
#toast-region {
  pointer-events: none;
}

#toast-region > :not(.alert-success) {
  pointer-events: auto;
}

/* ─── Success toasts never block the surface beneath ───
   Center-top toasts can render over the compact tool dock the instant the
   pointer clicks there, and a parked pointer pauses auto-dismissal. Passive
   success notices pass pointer events straight through except their close
   control; interactive error toasts (retry affordances) keep capturing. */
#toast-region > .alert-success {
  pointer-events: none;
}

#toast-region > .alert-success :is(button, a[href], [role="button"]) {
  pointer-events: auto;
}

/* ─── Card 3D Tilt (driven by app-shell-card-interactions.ts) ───
   JS sets --card-tilt-x/--card-tilt-y via setHostCssVars and gates
   with data-bao-tilt (never style=). CSS owns the transform. */

/*
   The tilt carries its own perspective in the transform function below, so
   the standalone `perspective` and `transform-style` here bought nothing and
   cost the whole product its overlay positioning: each one establishes a
   containing block for fixed-position descendants, on every bordered card, at
   all times. app-shell-dropdowns escapes clipping ancestors by promoting an
   open panel to position: fixed and publishing viewport-relative geometry in
   --bao-dropdown-left; inside a card that geometry resolved against the CARD
   instead. Measured on the chat composer at 824px: a trigger at x=501 with a
   published left of 493px put the open menu at 994px — entirely off-screen,
   and forcing position: fixed moved it not at all. */
.card.card-border,
  [data-dashboard-widget][data-primitive="DashboardWidget"] {
  --card-tilt-x: 0deg;
  --card-tilt-y: 0deg;
}

@media (hover: hover) and (pointer: fine) {
  .card.card-border[data-bao-tilt="true"],
  [data-dashboard-widget][data-primitive="DashboardWidget"][data-bao-tilt="true"] {
    transform: perspective(800px) rotateX(var(--card-tilt-x)) rotateY(var(--card-tilt-y)) translateY(-2px);
    transition: transform var(--duration-fast) var(--easing-standard);
  }
}

/* Reduced motion suppresses the movement itself. This used to reset the
   perspective properties, which is a no-op now that the tilt owns its own
   perspective — and a reset of something never set would have left the motion
   running. */
@media (prefers-reduced-motion: reduce) {
  .card.card-border[data-bao-tilt="true"] {
    transform: none;
    transition: none;
  }
}

/* ─── Touch Press Feedback (driven by app-shell-touch-feedback.ts) ───
   JS sets data-bao-press="true" on touchstart, removes on touchend.
   CSS applies instant visual feedback — zero-latency feel. */

.bao-touch-target[data-bao-press="true"],
.btn[data-bao-press="true"],
a[href][data-bao-press="true"],
[role="button"][data-bao-press="true"],
[data-action][data-bao-press="true"],
summary[data-bao-press="true"] {
  transform: scale(0.97);
  opacity: var(--opacity-strong, 0.85);
  transition: none;
}

/* OS + product reduced-motion: no press spring scale (dock/topbar haptic). */
@media (prefers-reduced-motion: reduce) {
  .bao-touch-target[data-bao-press="true"],
  .btn[data-bao-press="true"],
  a[href][data-bao-press="true"],
  [role="button"][data-bao-press="true"],
  [data-action][data-bao-press="true"],
  summary[data-bao-press="true"] {
    transform: none;
    opacity: 1;
  }
}
html[data-reduced-motion="true"] .bao-touch-target[data-bao-press="true"],
html[data-reduced-motion="true"] .btn[data-bao-press="true"],
html[data-reduced-motion="true"] a[href][data-bao-press="true"],
html[data-reduced-motion="true"] [role="button"][data-bao-press="true"],
html[data-reduced-motion="true"] [data-action][data-bao-press="true"],
html[data-reduced-motion="true"] summary[data-bao-press="true"] {
  transform: none;
  opacity: 1;
}

/* ─── Toast Swipe Tracking (driven by app-shell-toast-swipe.ts) ───
   JS writes --bao-swipe-dx and --bao-swipe-alpha via setProperty
   during touchmove. CSS reads them for live transform + opacity. */

#toast-region > [data-bao-swiping="true"] {
  transform: translateX(var(--bao-swipe-dx, 0px));
  opacity: var(--bao-swipe-alpha, 1);
  transition: none;
}

#toast-region > [data-toast-dismissing] {
  transform: translateX(100%);
  opacity: 0;
  transition: transform var(--duration-normal) var(--easing-standard),
              opacity var(--duration-normal) var(--easing-standard);
}

@media (min-width: 48rem) {
  #toast-region > [data-toast-dismissing] {
    transform: translateX(120%);
  }
}

/* ─── Toast Entrance Animation ─── */

@keyframes bao-toast-enter {
  from {
    opacity: 0;
    transform: translateY(var(--space-section, 0.75rem)) scale(0.96);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

#toast-region > *:not([data-toast-dismissing]):not([data-bao-swiping]) {
  animation: bao-toast-enter var(--duration-slow) var(--easing-entrance) both;
}

/* ─── Toast Region Top-Layer Promotion (driven by app-shell-toast.ts) ───
   JS promotes #toast-region via popover=manual (shown persistently) so
   error toasts paint — and stay interactive — above open native dialogs
   and the mobile drawer. The popover UA box (centered inset, border,
   padding, canvas background) must not fight the daisyUI .toast geometry,
   which already owns placement; neutralize it here. */
#toast-region[popover] {
  inset: auto;
  inset-inline-start: 50%;
  inset-inline-end: auto;
  --toast-x: -50%;
  inset-block-start: calc(var(--chrome-min-height) + var(--space-section) + var(--space-inline));
  inset-block-end: auto;
  inline-size: min(var(--toast-max-inline-size), calc(100vw - (2 * var(--space-inline))));
  max-inline-size: min(var(--toast-max-inline-size), calc(100vw - (2 * var(--space-inline))));
  margin: 0;
  padding: 0;
  border: none;
  overflow: visible;
  background: transparent;
  color: inherit;
}

#toast-region[popover] > * {
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
}

/* ─── Selection Highlight ─── */

::selection {
  background-color: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  color: var(--text-primary, var(--color-base-content));
}

/* ─── Spring Hover Scale (driven by app-shell-fluid-interactions.ts) ───
   JS sets data-bao-hover="true" on pointerenter, removes on pointerleave.
   Spring easing overshoots then settles — Apple HIG material feel. */

/* Only explicit Button primitives participate; content panels keep stable bounds. */
@media (hover: hover) and (pointer: fine) {
  [data-primitive="Button"]:where(:not([data-bao-dock-resize]))[data-bao-hover="true"] {
    transform: scale(var(--hover-scale));
    transition: transform var(--duration-slow) var(--easing-standard);
  }
}

/* A pointer marker survives until pointerleave. Match the Button spring
   specificity so a live OS preference change cancels the retained scale. */
@media (prefers-reduced-motion: reduce) {
  [data-primitive="Button"][data-bao-hover="true"],
  [data-bao-hover="true"] {
    transform: none;
    transition: none;
  }
}
html[data-reduced-motion="true"] [data-bao-hover="true"] {
  transform: none;
  transition: none;
}

/* ─── Mobile Dock Snap (driven by app-shell-fluid-interactions.ts) ─── */

.bao-mobile-dock[data-bao-dock-snap="true"] {
  scroll-snap-type: x mandatory;
}

.bao-mobile-dock[data-bao-dock-snap="true"] .bao-mobile-dock-item {
  scroll-snap-align: center;
}

/* ─── Pull-to-Refresh Indicator (driven by app-shell-swipe-navigation.ts) ───
   JS publishes --pull-distance via setHostCssVars (data-bao-var-host),
   never inline style attrs. CSS pseudo-element renders the indicator. */

[data-shell-scroll="main"][data-bao-var-host]::before {
  content: "";
  position: fixed;
  top: 0;
  left: 50%;
  width: 2rem;
  height: 2rem;
  transform: translateX(-50%) translateY(var(--pull-distance, 0px));
  border-radius: var(--radius-full);
  background: var(--bg-surface, var(--color-base-200));
  border: 1px solid var(--border-base, var(--color-base-300));
  box-shadow: var(--shadow-md);
  z-index: var(--z-toast, 1400);
  pointer-events: none;
}

/* ─── Skeleton Shimmer Enhancement ─── */

@keyframes bao-skeleton-sweep {
  0% { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

.skeleton-shimmer {
  background-color: var(--bg-surface-hover, var(--color-base-200));
  background-image: linear-gradient(
    90deg,
    var(--bg-surface, var(--color-base-200)) 25%,
    color-mix(in oklab, var(--bg-surface-hover, var(--color-base-300)) 60%, transparent) 50%,
    var(--bg-surface, var(--color-base-200)) 75%
  );
  background-size: 200% 100%;
  background-repeat: no-repeat;
  animation: bao-skeleton-sweep var(--duration-skeleton) var(--easing-standard) infinite;
}

@media (prefers-reduced-motion: reduce) {
  .skeleton-shimmer {
    animation: none;
    background-image: none;
    background-color: var(--bg-surface, var(--color-base-200));
  }
}

/* ─── Modal Glass Enhancement + Entrance ─── */

/* Keep blocking messages legible throughout entrance motion. */
@keyframes bao-modal-enter {
  from {
    transform: translateY(var(--space-section, 0.75rem)) scale(0.97);
  }
  to {
    transform: none;
  }
}

/* Open state owns entrance motion only. Material paint stays with the
   canonical modal + lens variants, and :where() prevents state markup from
   outranking accessibility preference selectors. */
:where(dialog.modal[open], dialog.modal.modal-open) .bao-modal-box-shell {
  animation: bao-modal-enter var(--duration-slow) var(--easing-entrance) both;
}

@media (prefers-reduced-motion: reduce) {
  :where(dialog.modal[open], dialog.modal.modal-open) .bao-modal-box-shell {
    animation: none;
  }
}


/* ═══════════════════════════════════════════════════════════════════
   UX ENHANCEMENTS — hover, focus, mobile interactions
   ═══════════════════════════════════════════════════════════════════ */

/* ─── Glass Hover Illumination (design.pdf §2.7) ───
   A subtle radial glow near the pointer on glass surfaces. JS sets
   --glass-pointer-x/y via pointermove; CSS composes the glow as an
   additional background layer on the existing ::after inner illumination.
   Falls back gracefully when JS is unavailable (no glow, no break). */

@media (hover: hover) and (pointer: fine) {
  :is(.bao-surface-glass-regular, .bao-surface-glass-clear) {
    --glass-pointer-x: 50%;
    --glass-pointer-y: 50%;
  }
  .bao-surface-glass-regular:hover,
  .bao-surface-glass-clear:hover {
    --liquid-material-illumination:
      radial-gradient(
        circle min(var(--glass-specular-radius-max), 6px) at var(--glass-pointer-x) var(--glass-pointer-y),
        var(--glass-highlight-strong),
        transparent 70%
      ),
      radial-gradient(
        600px circle at var(--glass-pointer-x) var(--glass-pointer-y),
        var(--glass-illumination-strong),
        transparent 40%
      ),
      radial-gradient(
        ellipse 120% 80% at 20% 0%,
        var(--glass-illumination-strong) 0%,
        var(--glass-illumination-soft) 50%,
        var(--glass-highlight-clear) 80%
      );
  }
}


/* ─── Pointer-Lens Snap Matrix (design.pdf §2.7) ───
   Continuous pointermove writes --glass-pointer-x/y directly. Consumers that
   only know a coarse zone — touch drag, keyboard focus snapping, SSR
   snapshots — write data-bao-glass-pointer="<col>-<row>" instead, and the
   lens snaps to one of nine discrete positions on a 3×3 grid (16.67% /
   50% / 83.33% per axis, column-then-row). The material illumination
   reads the same custom properties, so snapped and continuous positioning
   compose through one code path. */
:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="0-0"] {
  --glass-pointer-x: 16.67%;
  --glass-pointer-y: 16.67%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="0-1"] {
  --glass-pointer-x: 16.67%;
  --glass-pointer-y: 50%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="0-2"] {
  --glass-pointer-x: 16.67%;
  --glass-pointer-y: 83.33%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="1-0"] {
  --glass-pointer-x: 50%;
  --glass-pointer-y: 16.67%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="1-1"] {
  --glass-pointer-x: 50%;
  --glass-pointer-y: 50%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="1-2"] {
  --glass-pointer-x: 50%;
  --glass-pointer-y: 83.33%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="2-0"] {
  --glass-pointer-x: 83.33%;
  --glass-pointer-y: 16.67%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="2-1"] {
  --glass-pointer-x: 83.33%;
  --glass-pointer-y: 50%;
}

:is(.bao-surface-glass-regular, .bao-surface-glass-clear)[data-bao-glass-pointer="2-2"] {
  --glass-pointer-x: 83.33%;
  --glass-pointer-y: 83.33%;
}


/* ─── Focus Ring Pulse (design.pdf §6) ───
   Subtle pulse on focus-visible to draw attention without being distracting.
   Only triggers on keyboard focus (focus-visible), not mouse clicks. */

@keyframes bao-focus-pulse {
  0%, 100% { outline-offset: var(--focus-ring-offset); }
  50% { outline-offset: calc(var(--focus-ring-offset) + var(--focus-ring-offset-snug)); }
}

:focus-visible {
  outline: var(--focus-ring-width) solid var(--focus-ring-color, var(--color-primary));
  outline-offset: var(--focus-ring-offset);
  animation: bao-focus-pulse var(--duration-focus-pulse) var(--easing-standard) 1;
}

@media (prefers-reduced-motion: reduce) {
  :focus-visible {
    animation: none;
  }
}

/* ─── Sidebar Hover-Expand — DELETED (second width owner) ───
   `.bao-sidebar-collapsed:hover { width: 16rem }` widened the NAV while the
   grid track on .bao-shell-drawer stayed at --sidebar-collapsed, and
   .drawer-side clips (overflow:hidden). Measured at 1440px: nav 256px inside
   a 56px track, elementFromPoint(150, item) landed on page content, and the
   label spans stayed display:none because the drawer kept
   .bao-shell-rail-collapsed — so the hover revealed no labels at all. It did
   produce two artefacts: a 200px dead hit area, and .bao-nav-item.tooltip
   bubbles laid out against a 238px-wide item whose body fell outside the clip,
   leaving a stray arrow at the rail edge. The drawer grid track is the ONE
   owner of rail width (tokens-glass-shell-drawer-part-b) and the peek
   controller is the one owner of hover expansion — it moves the panel out of
   the track first, so nothing clips. The [data-sidebar-*-only] display swaps
   keep their real owners: app-shell-rails.ts (hidden class, per state) plus
   the peek/pinned/checked rules in tokens-glass-shell-drawer-part-1. */

/* ─── Smooth Theme Transition (light↔dark crossfade) ───
   Crossfade between themes when data-theme changes. Only applies to
   color properties — not layout/transform (would cause reflow). */

html {
  transition: background-color var(--duration-slow) var(--easing-standard),
              color var(--duration-slow) var(--easing-standard);
}

@media (prefers-reduced-motion: reduce) {
  html {
    transition: none;
  }
}

/* ─── Empty State Entrance Animation (transform-only stagger) ───
   Empty states enter with a subtle upward motion for perceived performance.
   Children stagger by --stagger-step (30ms default from tokens.bao).
   WebView 101 law (tokens-glass-a11y.ts): entrance motion is
   transform-only — opacity-from-0 can stick and paint voids over real
   content, so readability never depends on an animation completing. */

@keyframes bao-empty-enter {
  from {
    transform: translateY(var(--entrance-offset, 0.375rem));
  }
  to {
    transform: none;
  }
}

[data-state="empty"] [data-state-content],
[data-primitive="EmptyState"] {
  animation: bao-empty-enter var(--duration-slow) var(--easing-entrance) both;
}

@media (prefers-reduced-motion: reduce) {
  [data-state="empty"] [data-state-content],
  [data-primitive="EmptyState"] {
    animation: none;
  }
}

/* ─── Card Hover Lift (design.pdf §5.3) ───
   Clickable cards lift on hover with increased shadow and slight translateY.
   Only on fine pointers — touch devices use press feedback instead. */

@media (hover: hover) and (pointer: fine) {
  [data-primitive="Card"][data-clickable="true"],
  .card.card-border[data-clickable="true"] {
    transition: transform var(--duration-fast) var(--easing-standard),
                box-shadow var(--duration-fast) var(--easing-standard),
                border-color var(--duration-fast) var(--easing-standard);
  }
  [data-primitive="Card"][data-clickable="true"]:hover,
  .card.card-border[data-clickable="true"]:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-glass-elevated, var(--shadow-lg));
    border-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), var(--border-base));
  }
  [data-primitive="Card"][data-clickable="true"]:active,
  .card.card-border[data-clickable="true"]:active {
    transform: translateY(0) scale(0.99);
    box-shadow: var(--shadow-sm);
  }
}

/* Coarse pointers receive press feedback on declared clickable cards. */
@media (hover: none), (pointer: coarse) {
  [data-primitive="Card"][data-clickable="true"]:active,
  .card.card-border[data-clickable="true"]:active {
    transform: scale(0.985);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-primitive="Card"][data-clickable="true"],
  .card.card-border[data-clickable="true"] {
    transition: none;
  }
  [data-primitive="Card"][data-clickable="true"]:hover,
  .card.card-border[data-clickable="true"]:hover {
    transform: none;
  }
}

/* ─── Dialog Drag Handle (mobile bottom sheets) ───
   Visual indicator on bottom-sheet dialogs for drag-to-dismiss affordance.
   Gated at the same sm breakpoint where Dialog.bao swaps modal-bottom for
   sm:modal-middle: above 40rem the dialog centers, and a grabber on a
   centered sheet is a phantom affordance — and only where the dismiss gesture
   actually binds: the sheet drag answers touch on coarse pointers
   (app-shell-sheet-gesture binds touchstart there, never mouse), so a fine
   pointer in a narrow window would otherwise see a pill promising a drag the
   surface cannot perform. */

@media (pointer: coarse) and (max-width: 39.99rem) {
  dialog.modal.modal-bottom .modal-box::before {
    content: "";
    display: block;
    width: 2.5rem;
    height: 0.25rem;
    border-radius: var(--radius-full);
    background: color-mix(in oklab, var(--text-tertiary) 30%, transparent);
    margin: var(--space-micro) auto var(--space-inline);
  }
}

/* Filter sheet, row-swipe, dashboard drag-reorder, fuzzy-search, and the
   bao-sheet-enter keyframes are owned solely by
   tokens-glass-runtime-interactions-mobile.ts (single owner — DRY, S42).
   The scroll-to-top button was deleted: zero markup/JS consumers exist. */


/* ─── Scrollbar Refinement (Webkit) ─── */

::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}

::-webkit-scrollbar-track {
  background: transparent;
}

::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--text-tertiary, var(--color-base-content)) 30%, transparent);
  border-radius: var(--radius-full);
}

[data-theme="capture-dx-dark"] ::-webkit-scrollbar-thumb {
  background: color-mix(in oklab, var(--text-tertiary, var(--color-base-content)) 25%, transparent);
}

/* Hybrid hover (imp-t04): thumb emphasis only where a pointer can hover —
   overlay scrollbars on touch never receive a hoverable thumb. */
@media (hover: hover) and (pointer: fine) {
  ::-webkit-scrollbar-thumb:hover {
    background: color-mix(in oklab, var(--text-secondary, var(--color-base-content)) 50%, transparent);
  }

  [data-theme="capture-dx-dark"] ::-webkit-scrollbar-thumb:hover {
    background: color-mix(in oklab, var(--text-secondary, var(--color-base-content)) 40%, transparent);
  }
}



/* ─── Filter Bar Mobile Bottom Sheet ───
   On mobile (<48rem), filter overflow transforms into a bottom sheet
   pattern. The overflow summary button triggers a details/summary
   disclosure that slides up from the bottom. */

@media (max-width: 47.99rem) {
  [data-primitive="FilterBar"] details.bao-filter-overflow {
    position: relative;
  }
  [data-primitive="FilterBar"] details.bao-filter-overflow[open] > summary ~ * {
    animation: bao-sheet-enter var(--duration-slow) var(--easing-entrance) both;
  }
  [data-primitive="FilterBar"] details.bao-filter-overflow > summary ~ * {
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    z-index: var(--z-overlay, 1200);
    max-height: 70dvh;
    overflow-y: auto;
    background: var(--bg-panel, var(--color-base-100));
    border-top: 1px solid var(--border-base, var(--color-base-300));
    border-radius: var(--radius-box, 1rem) var(--radius-box, 1rem) 0 0;
    padding: var(--space-section);
    box-shadow: var(--shadow-glass-floating);
  }
}

@keyframes bao-sheet-enter {
  from {
    opacity: 0;
    transform: translateY(100%);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-primitive="FilterBar"] details.bao-filter-overflow[open] > summary ~ * {
    animation: none;
  }
}

/* ─── Data Table Row Swipe Actions (mobile) ───
   Swipe left on a table row to reveal action buttons.
   JS (app-shell-table-row-swipe) sets --row-swipe-dx via setHostCssVars.
   Only on coarse pointers (touch devices). Card-stack rows keep actions
   visible via opacity:1 rules; swipe still works for denser table mode. */

@media (hover: none) and (pointer: coarse) {
  [data-primitive="DataTable"] tbody tr.bao-table-responsive-row,
  [data-primitive="DataTable"] tbody tr.bao-hover-row {
    position: relative;
    touch-action: pan-y;
  }
  [data-primitive="DataTable"] tbody tr[data-bao-swiping="true"] {
    transform: translateX(var(--row-swipe-dx, 0px));
    transition: none;
    z-index: var(--z-local, 1);
  }
  [data-primitive="DataTable"] tbody tr[data-bao-swipe-open="true"]:not([data-bao-swiping]) {
    transform: translateX(var(--row-swipe-dx, -88px));
    transition: transform var(--duration-fast) var(--easing-standard);
  }
  [data-primitive="DataTable"] tbody tr:not([data-bao-swiping]):not([data-bao-swipe-open]) {
    transition: transform var(--duration-fast) var(--easing-standard);
  }
  /* Keep action cluster tappable while the row is translated. */
  [data-primitive="DataTable"] tbody tr[data-bao-swipe-open="true"] .bao-table-pinned-action,
  [data-primitive="DataTable"] tbody tr[data-bao-swiping="true"] .bao-table-pinned-action {
    position: relative;
    z-index: var(--z-raised, 2);
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-primitive="DataTable"] tbody tr {
    transition: none;
  }
}

/* ─── Sheet Back Gesture (mobile) ───
   iOS-style swipe right from the left edge dismisses the topmost sheet.
   JS (app-shell-sheet-gesture) publishes --sheet-gesture-dx on the dialog
   via setHostCssVars and flips data-bao-sheet-gesture: "drag" follows the
   finger with no transition, "settle" transitions back to 0 on cancel.
   Sheet wrappers stay fixed (backdrop must not move); the panel translates.
   Reduced-motion never receives the attribute — dismiss is instant. */

@media (hover: none) and (pointer: coarse) and (max-width: 47.99rem) {
  dialog[data-bao-sheet-gesture] {
    transform: translateX(var(--sheet-gesture-dx, 0px));
  }
  dialog[data-bao-sheet-gesture="drag"] {
    transition: none;
  }
  dialog[data-bao-sheet-gesture="settle"] {
    transition: transform var(--duration-fast) var(--easing-standard);
  }
  dialog[data-primitive="Sheet"][data-bao-sheet-gesture] {
    transform: none;
  }
  dialog[data-primitive="Sheet"][data-bao-sheet-gesture] .bao-sheet-panel {
    transform: translateX(var(--sheet-gesture-dx, 0px));
  }
  dialog[data-primitive="Sheet"][data-bao-sheet-gesture="drag"] .bao-sheet-panel {
    transition: none;
  }
  dialog[data-primitive="Sheet"][data-bao-sheet-gesture="settle"] .bao-sheet-panel {
    transition: transform var(--duration-fast) var(--easing-standard);
  }
}

/* ─── Dashboard Widget Drag-to-Reorder ───
   Widgets get a drag handle on hover (desktop) and long-press (mobile).
   JS sets data-bao-dragging="true" during drag; CSS handles visual state. */

[data-dashboard-widget][data-bao-dragging="true"] {
  opacity: var(--opacity-strong, 0.85);
  box-shadow: var(--shadow-glass-floating);
  transform: scale(1.02);
  z-index: var(--z-overlay, 1200);
  cursor: grabbing;
}

[data-dashboard-widget][data-bao-drag-over="true"] {
  outline: var(--focus-ring-width) dashed var(--accent-primary, var(--color-primary));
  outline-offset: var(--focus-ring-offset-tight);
}

@media (prefers-reduced-motion: reduce) {
  [data-dashboard-widget][data-bao-dragging="true"] {
    transform: none;
    transition: none;
  }
}

/* ─── Command Palette Fuzzy Search ───
   Enhanced search results with highlighted matching characters.
   JS sets data-bao-match="true" on matching characters; CSS styles them. */

[data-bao-match="true"] {
  font-weight: var(--font-weight-semibold, 600);
  color: var(--accent-primary, var(--color-primary));
}

/* ─── Case Card Swipe-Right Quick Claim (imp-m06, mobile) ───
   Swipe right on a worklist case row to slide the claim affordance in from
   the inline-start edge. JS (app-shell-card-swipe) sets --case-swipe-dx via
   setHostCssVars and data-case-swiping / data-case-swipe-armed on the row.
   The row itself never transforms — the table-row swipe-left contract owns
   row translation, so the two gestures compose without a transform race. */

[data-case-swipe-affordance] {
  display: none;
}

@media (hover: none) and (pointer: coarse) {
  [data-case-swipe-affordance] {
    position: absolute;
    inset-inline-start: 0;
    inset-block: 0;
    z-index: var(--z-raised, 2);
    display: flex;
    align-items: center;
    padding-inline: var(--space-inline);
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
    color: var(--color-primary);
    transform: translateX(-100%);
    opacity: 0;
    visibility: hidden;
    transition:
      transform var(--duration-fast) var(--easing-standard),
      opacity var(--duration-fast) var(--easing-standard);
  }
  tr[data-case-swiping] [data-case-swipe-affordance] {
    transform: translateX(calc(-100% + var(--case-swipe-dx, 0px)));
    opacity: 1;
    visibility: visible;
    transition: none;
  }
  tr[data-case-swipe-armed] [data-case-swipe-affordance] {
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-case-swipe-affordance] {
    transition: none;
  }
}

/* ─── Cases List Pull-to-Refresh (imp-m07, mobile) ───
   Pull down at scrollTop 0 to re-issue the list's canonical hx-get. JS
   (app-shell-pull-refresh) sets --pull-refresh-dy and data-pull-refresh-state
   on the list host; the spinner markup is generated from
   partials/case-list-table.bao. Reduced-motion removes the rubber-band
   transform entirely (mission constraint) — the state spinner still reports. */

[data-pull-refresh-indicator] {
  display: none;
}

@media (hover: none) and (pointer: coarse) {
  [data-case-list] {
    position: relative;
    overscroll-behavior-y: contain;
  }
  [data-pull-refresh-indicator] {
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    z-index: var(--z-raised, 2);
    display: flex;
    justify-content: center;
    padding-block: var(--space-micro);
    color: var(--text-secondary);
    transform: translateY(calc(-100% + var(--pull-refresh-dy, 0px)));
    opacity: 0;
    pointer-events: none;
  }
  [data-case-list][data-pull-refresh-state="pulling"] [data-pull-refresh-indicator],
  [data-case-list][data-pull-refresh-state="armed"] [data-pull-refresh-indicator] {
    opacity: 1;
  }
  [data-case-list][data-pull-refresh-state="armed"] [data-pull-refresh-indicator],
  [data-case-list][data-pull-refresh-state="refreshing"] [data-pull-refresh-indicator] {
    color: var(--color-primary);
  }
  [data-case-list][data-pull-refresh-state="refreshing"] [data-pull-refresh-indicator] {
    position: static;
    transform: none;
    opacity: 1;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-case-list] [data-pull-refresh-indicator] {
    transform: none;
  }
}

@keyframes bao-sheet-enter-fade {
  from { opacity: 0; }
  to { opacity: 1; }
}
html[data-reduced-motion="true"] [data-primitive="FilterBar"] details.bao-filter-overflow[open] > summary ~ * {
  animation-name: bao-sheet-enter-fade;
  animation-duration: var(--reduced-motion-min-duration);
}
html[data-reduced-motion="true"] [data-primitive="DataTable"] tbody tr {
  transition: none;
}
html[data-reduced-motion="true"] [data-dashboard-widget][data-bao-dragging="true"] {
  transform: none;
  transition: none;
}
html[data-reduced-motion="true"] [data-case-swipe-affordance] {
  transition: none;
}
html[data-reduced-motion="true"] [data-case-list] [data-pull-refresh-indicator] {
  transform: none;
}


/* ─── Filter Bar Bottom Sheet (Mobile) ───
   Transforms filter bar into bottom sheet on mobile (<48rem).
   The native dialog owns modal state; the form publishes its drag displacement.
   CSS owns the panel and native scrim material. */

@media (max-width: 47.99rem) {
  [data-primitive="FilterBar"] {
    --filter-sheet-drag-y: 0px;
  }

  /*
   * Collapse inline filters only after the shared trigger exists. Before
   * enhancement, or when its template cannot load, search and selects remain
   * usable instead of leaving an empty strip. The same controls become the
   * sheet contents once its trigger is mounted; no duplicate mobile form.
   */
  [data-primitive="FilterBar"]:has(> [data-filter-actions] > [data-filter-sheet-trigger]):not([data-filter-sheet-open="true"]) {
    flex-wrap: nowrap;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-micro, 0.25rem);
    padding-block: var(--space-micro, 0.25rem);
  }
  [data-primitive="FilterBar"]:has(> [data-filter-actions] > [data-filter-sheet-trigger]):not([data-filter-sheet-open="true"]) > :not([data-filter-actions]) {
    display: none;
  }
  [data-primitive="FilterBar"]:has(> [data-filter-actions] > [data-filter-sheet-trigger]):not([data-filter-sheet-open="true"]) > [data-filter-actions] {
    width: 100%;
    max-width: 100%;
    margin-inline-start: 0;
    justify-content: flex-end;
  }
  /* Closed chip row: only the sheet trigger — clear/export stay in the open sheet. */
  [data-primitive="FilterBar"]:has(> [data-filter-actions] > [data-filter-sheet-trigger]):not([data-filter-sheet-open="true"]) > [data-filter-actions] > :not([data-filter-sheet-trigger]) {
    display: none;
  }

  /* Native top layer owns modal geometry and outside interaction. */
  .bao-filter-sheet-dialog {
    position: fixed;
    inset: 0;
    margin: 0;
    inline-size: 100%;
    block-size: 100%;
    max-inline-size: none;
    max-block-size: none;
    padding: 0;
    border: 0;
    background: transparent;
    color: inherit;
    overflow: visible;
  }
  .bao-filter-sheet-dialog::backdrop {
    background: var(--color-base-100);
  }
  @media (prefers-reduced-transparency: no-preference) and (prefers-contrast: no-preference) and (prefers-reduced-motion: no-preference) and (forced-colors: none) {
    html:not([data-reduced-transparency="true"]):not([data-high-contrast="true"]):not([data-reduced-motion="true"]) .bao-filter-sheet-dialog::backdrop {
      background: var(--glass-scrim);
      -webkit-backdrop-filter: blur(var(--liquid-blur-clear));
      backdrop-filter: blur(var(--liquid-blur-clear));
    }
  }

  /* The same form stays above dock safe-area clearance inside its native dialog. */
  [data-primitive="FilterBar"][data-filter-sheet-open="true"] {
    position: fixed;
    isolation: isolate;
    inset-inline: 0;
    inset-block-start: auto;
    top: auto;
    --filter-sheet-bottom-clearance: calc(
      var(--dock-height, 4rem) + var(--dock-safe-area-offset, 0px) +
      env(safe-area-inset-bottom, 0px)
    );
    inset-block-end: var(--filter-sheet-bottom-clearance);
    max-height: min(
      80dvh, 36rem,
      calc(100dvh - var(--filter-sheet-bottom-clearance) - env(safe-area-inset-top, 0px))
    );
    overflow-y: auto;
    border-radius: var(--radius-box, 1rem) var(--radius-box, 1rem) 0 0;
    box-shadow: var(--shadow-glass-floating);
    transition: transform var(--duration-normal) var(--easing-standard);
    background: var(--color-base-100);
    border: 1px solid var(--color-base-300);
    padding: var(--space-inline, 0.5rem);
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
  }

  /* Fieldsets above any residual in-bar chrome; relative stacks within the bar. */
  [data-primitive="FilterBar"][data-filter-sheet-open="true"] > :not([data-filter-actions]) {
    position: relative;
    z-index: var(--z-local, 1);
  }

  /* Active dragging moves the form while the native scrim remains in the top layer. */
  [data-primitive="FilterBar"][data-filter-sheet-open="true"][data-filter-sheet-dragging="true"] {
    transform: translateY(var(--filter-sheet-drag-y));
  }

  /* The real dismiss handle owns pointer gestures; fields retain native scrolling. */
  .bao-filter-sheet-handle {
    display: flex;
    align-items: center;
    justify-content: center;
    touch-action: none;
    cursor: grab;
  }
  .bao-filter-sheet-handle::before {
    content: "";
    inline-size: var(--touch-target-min);
    block-size: var(--space-micro);
    border-radius: var(--radius-full);
    background: var(--color-base-content);
  }
  .bao-filter-sheet-handle:active {
    cursor: grabbing;
  }

  /* Trigger button: full-width filter chip when closed. */
  .bao-filter-sheet-trigger {
    gap: var(--space-micro);
  }
  [data-primitive="FilterBar"]:has(> [data-filter-actions] > [data-filter-sheet-trigger]):not([data-filter-sheet-open="true"]) .bao-filter-sheet-trigger {
    flex: 1 1 auto;
    justify-content: center;
    min-height: var(--touch-target-min, 2.75rem);
  }
  /* Active filter count badge (Mail/Photos idiom) — only when count > 0. */
  .bao-filter-active-count[hidden] {
    display: none;
  }
  [data-primitive="FilterBar"][data-filter-active="true"]:not([data-filter-sheet-open="true"]) .bao-filter-sheet-trigger {
    border-color: var(--liquid-border-regular);
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  }

  /*
   * Progressive hide when a FilterBar has nothing to filter (training connector
   * offline, empty API keys inventory, etc.). JS stamps
   * data-training-filters-deferred or data-filter-bar-deferred. Specificity
   * must beat phone FilterBar display:grid + closed-sheet chip layout so the
   * sheet trigger leaves the layout (not just aria-hidden).
   */
  form[data-primitive="FilterBar"][data-training-filters][data-training-filters-deferred],
  [data-primitive="FilterBar"][data-training-filters][data-training-filters-deferred],
  form[data-training-filters][data-training-filters-deferred],
  [data-training-filters][data-training-filters-deferred],
  form[data-primitive="FilterBar"][data-filter-bar-deferred],
  [data-primitive="FilterBar"][data-filter-bar-deferred],
  form[data-filter-bar][data-filter-bar-deferred],
  [data-filter-bar][data-filter-bar-deferred] {
    display: none;
    visibility: hidden;
    pointer-events: none;
    height: 0;
    max-height: 0;
    min-height: 0;
    overflow: hidden;
    margin: 0;
    padding: 0;
    border-width: 0;
  }
}

/* Desktop/tablet: same deferred hide (filter noise without inventory). */
form[data-primitive="FilterBar"][data-training-filters][data-training-filters-deferred],
[data-primitive="FilterBar"][data-training-filters][data-training-filters-deferred],
form[data-training-filters][data-training-filters-deferred],
[data-training-filters][data-training-filters-deferred],
form[data-primitive="FilterBar"][data-filter-bar-deferred],
[data-primitive="FilterBar"][data-filter-bar-deferred],
form[data-filter-bar][data-filter-bar-deferred],
[data-filter-bar][data-filter-bar-deferred] {
  display: none;
  visibility: hidden;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-primitive="FilterBar"][data-filter-sheet-open="true"] {
    transition: none;
  }
}

/* ─── Print Optimization ─── */

@media print {
  .bao-shell-topbar,
  .bao-shell-sidebar,
  /* ID-level: tokens-layout-dock-base is emitted after this module and its
     .bao-mobile-dock.dock display:flex outranks a plain class here, so the
     dock printed on every page. */
  .bao-mobile-dock.dock.bao-mobile-dock,
  nav.bao-mobile-dock[data-mobile-dock],
  #toast-region,
  .drawer-toggle,
  [data-page-header-actions],
  .htmx-indicator {
    display: none;
  }
  [data-shell-scroll="main"] {
    overflow: visible;
  }
  .card.card-border,
  [data-dashboard-widget][data-primitive="DashboardWidget"] {
    break-inside: avoid;
    box-shadow: none;
    border: 1px solid color-mix(in oklab, var(--color-base-content) 15%, transparent);
  }
}


/* ─── Desktop File Drop Zone (drag-and-drop upload affordance) ───
   JS sets data-bao-drop-active + data-state via app-shell-file-drop.ts;
   CSS owns every visual. Surface styles are gated to fine-pointer devices;
   preview list + error styles apply everywhere. */

@media (hover: hover) and (pointer: fine) {
  .bao-file-drop-zone {
    display: flex;
    flex-direction: column;
    gap: var(--space-inline, 0.5rem);
    border: 2px dashed var(--border-base, var(--color-base-300));
    border-radius: var(--radius-box, 1rem);
    padding: var(--space-page, 1.5rem);
    text-align: center;
    cursor: pointer;
    background: color-mix(in oklab, var(--bg-panel) calc(var(--liquid-fill-persistent) * 100%), transparent);
    transition: border-color var(--duration-normal) var(--easing-standard, ease),
                background var(--duration-normal) var(--easing-standard, ease),
                box-shadow var(--duration-normal) var(--easing-standard, ease);
  }
  .bao-file-drop-zone[data-bao-drop-active="true"] {
    border-color: var(--color-primary);
    background: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
    box-shadow: 0 0 0 3px var(--liquid-border-regular);
  }
  .bao-file-drop-zone[data-state="error"] {
    border-color: var(--color-error);
    background: color-mix(in oklab, var(--color-error) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  .bao-file-drop-zone:focus-within {
    outline: var(--focus-ring-width) solid var(--color-primary);
    outline-offset: var(--focus-ring-offset);
  }
}
.bao-file-drop-zone__prompt {
  inline-size: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--text-secondary, var(--color-base-content));
  cursor: inherit;
  font: inherit;
  font-size: var(--text-sm, 0.875rem);
  text-align: inherit;
}
.bao-file-drop-zone__files {
  display: flex;
  flex-direction: column;
  gap: var(--space-micro, 0.25rem);
  margin: 0;
  padding: 0;
  list-style: none;
}
.bao-file-drop-zone__file-item {
  display: flex;
  align-items: center;
  gap: var(--space-inline, 0.5rem);
  padding: var(--space-micro, 0.25rem) var(--space-inline, 0.5rem);
  border: 1px solid var(--border-base, var(--color-base-300));
  border-radius: var(--radius-field, 0.75rem);
  background: var(--bg-panel, var(--color-base-100));
  text-align: start;
}
.bao-file-drop-zone__file-thumb {
  width: 2rem;
  height: 2rem;
  border-radius: var(--radius-xs, 0.25rem);
  object-fit: cover;
  flex: 0 0 auto;
}
.bao-file-drop-zone__file-meta {
  display: flex;
  min-width: 0;
  flex-direction: column;
  gap: var(--space-2xs, 0.125rem);
}
.bao-file-drop-zone__file-name {
  font-size: var(--text-sm, 0.875rem);
  color: var(--text-primary, var(--color-base-content));
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.bao-file-drop-zone__file-size {
  font-size: var(--text-xs, 0.75rem);
  color: var(--text-tertiary, var(--color-base-content));
  font-variant-numeric: tabular-nums;
}
.bao-file-drop-zone__more {
  font-size: var(--text-xs, 0.75rem);
  color: var(--text-tertiary, var(--color-base-content));
  text-align: start;
  padding-inline: var(--space-inline, 0.5rem);
}
.bao-file-drop-zone__error {
  margin: 0;
  font-size: var(--text-sm, 0.875rem);
  color: var(--color-error-content, var(--color-error));
}
.bao-file-drop-zone__input {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}
@media (prefers-reduced-motion: reduce) {
  .bao-file-drop-zone {
    transition: none;
  }
}

/* ─── Dockable Panels (Desktop) ───
   State lives on data-bao-dock-edge / data-bao-dock-floating; geometry on
   host CSS vars --bao-dock-{x,y,w,h} published by app-shell-dockable-panels.
   Controls stay hidden during normal reading/annotation and reveal only when
   layout customization is active or the panel is floating. */

[data-bao-dockable-panel],
.bao-dockable-panel {
  position: relative;
  transition:
    box-shadow var(--duration-normal) var(--easing-standard),
    opacity var(--duration-normal) var(--easing-standard);
}

[data-bao-dockable-panel][data-bao-docking="true"],
.bao-dockable-panel[data-bao-docking="true"] {
  opacity: var(--opacity-strong);
  box-shadow: var(--shadow-glass-floating);
  z-index: var(--z-overlay);
  transition: none;
}

[data-bao-dockable-panel][data-bao-dock-floating]:not([data-bao-dock-floating="false"]),
.bao-dockable-panel[data-bao-dock-floating]:not([data-bao-dock-floating="false"]) {
  position: fixed;
  inset-inline-start: var(--bao-dock-x, 0);
  inset-block-start: var(--bao-dock-y, 0);
  width: var(--bao-dock-w, 20rem);
  height: var(--bao-dock-h, 24rem);
  z-index: var(--z-overlay);
}

[data-bao-dockable-panel][data-bao-dock-resizing="true"],
.bao-dockable-panel[data-bao-dock-resizing="true"] {
  transition: none;
  box-shadow: var(--shadow-glass-floating);
}

[data-bao-dock-controls] {
  display: none;
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: var(--z-content-overlay);
}

[data-dashboard-layout-root][data-dashboard-editing="true"] [data-bao-dock-controls],
[data-bao-dockable-panel][data-bao-dock-floating]:not([data-bao-dock-floating="false"]) > [data-bao-dock-controls],
.bao-dockable-panel[data-bao-dock-floating]:not([data-bao-dock-floating="false"]) > [data-bao-dock-controls] {
  display: block;
}

[data-bao-dock-controls] > * {
  pointer-events: auto;
}

[data-bao-dock-resize] {
  position: absolute;
  z-index: var(--z-content-overlay);
  inline-size: 0.75rem;
  block-size: 0.75rem;
  cursor: nwse-resize;
  background: transparent;
}
[data-bao-dock-resize="n"],
[data-bao-dock-resize="s"] { inset-inline: 0; cursor: ns-resize; block-size: 0.5rem; }
[data-bao-dock-resize="e"],
[data-bao-dock-resize="w"] { inset-block: 0; cursor: ew-resize; inline-size: 0.5rem; }
[data-bao-dock-resize="n"] { inset-block-start: -0.25rem; }
[data-bao-dock-resize="s"] { inset-block-end: -0.25rem; }
[data-bao-dock-resize="w"] { inset-inline-start: -0.25rem; }
[data-bao-dock-resize="e"] { inset-inline-end: -0.25rem; }
[data-bao-dock-resize="ne"] { inset-block-start: -0.25rem; inset-inline-end: -0.25rem; cursor: nesw-resize; }
[data-bao-dock-resize="nw"] { inset-block-start: -0.25rem; inset-inline-start: -0.25rem; cursor: nwse-resize; }
[data-bao-dock-resize="se"] { inset-block-end: -0.25rem; inset-inline-end: -0.25rem; cursor: nwse-resize; }
[data-bao-dock-resize="sw"] { inset-block-end: -0.25rem; inset-inline-start: -0.25rem; cursor: nesw-resize; }

@media (hover: hover) and (pointer: fine) {
  [data-bao-dock-resize]:hover {
    background-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  }
}

[data-bao-dock-resize]:focus-visible {
  background-color: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
}

[data-bao-dock-handle] {
  position: absolute;
  inset-block-start: var(--space-inline);
  inset-inline-end: var(--space-inline);
  z-index: var(--z-content-overlay);
  cursor: grab;
  touch-action: none;
}
[data-bao-dock-handle]:active { cursor: grabbing; }

.bao-dock-zone {
  position: fixed;
  inset: auto;
  pointer-events: none;
  border-radius: var(--radius-box, 1rem);
  transition:
    background-color var(--duration-fast) var(--easing-standard),
    border-color var(--duration-fast) var(--easing-standard);
}
.bao-dock-zone[data-bao-dock-zone="left"] {
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 22%;
}
.bao-dock-zone[data-bao-dock-zone="right"] {
  inset-block: 0;
  inset-inline-end: 0;
  inline-size: 22%;
}
.bao-dock-zone[data-bao-dock-zone="top"] {
  inset-inline: 0;
  inset-block-start: 0;
  block-size: 22%;
}
.bao-dock-zone[data-bao-dock-zone="bottom"] {
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 22%;
}
.bao-dock-zone[data-bao-dock-zone="float"] {
  inset: 25% 30%;
}
.bao-dock-zone[data-bao-drop-target="true"] {
  background: color-mix(in oklab, var(--accent-primary) 15%, transparent);
  border: 2px dashed var(--accent-primary);
}

@media (prefers-reduced-motion: reduce) {
  [data-bao-dockable-panel],
  .bao-dockable-panel,
  .bao-dock-zone {
    transition: none;
  }
}


/* Keep a co-hosted toast out of mobile dialog actions. The toast remains in the top layer so it is dismissible, but it moves to the dialog's upper edge instead of covering the sticky footer. */
#toast-region.toast[data-toast-cohosted="true"] {
  inset-block-start: max(var(--space-inline, 0.5rem), env(safe-area-inset-top, 0px));
  inset-block-end: auto;
  inset-inline-start: auto;
  inset-inline-end: max(var(--space-inline, 0.5rem), env(safe-area-inset-right, 0px));
}

/*
 * While a stage is live the top-centre banner lands on the stage toolbar's
 * title block (measured 2026-08-23 at 1440x900: "Annotations saved." painted
 * over "Image 1 of 18" at y=64–112, the toolbar's own rows). HIG banners sit
 * over content, not controls: drop the region below the shell header and the
 * toolbar so it floats over the specimen.
 */
body:has([data-editor-chrome][data-annotation-ready="true"]) #toast-region.toast-top:not([data-toast-cohosted="true"]) {
  inset-block-start: calc(var(--chrome-min-height, max(2.75rem, 44px)) + var(--touch-target-min, 2.75rem) + var(--space-section, 0.75rem) * 3 + env(safe-area-inset-top, 0px));
}


}
@layer bao-tokens {

/* ─── Dashboard: widget actions are always visible ───
   The same hover-reveal that was removed from table rows below also ran on
   every .card-actions inside a widget host, and it was not clutter control —
   it was a second owner of visibility fighting the real one.

   [data-dashboard-widget] is not only the dashboard's KPI tiles: the Models
   page wraps its model catalogue in data-widget="models-predefined", so every
   model card's .card-actions footer matched. Each Download button — the
   primary CTA of that page — painted at opacity 0 with pointer-events intact
   until the operator happened to sweep the pointer across the panel, while
   assistive tech announced the whole row the entire time.

   The widget's own control cluster never needed the fade either: the layout
   customizer fieldset carries [hidden], and
   tokens-layout-dashboard-widgets-part-b.ts owns that state unlayered so it
   beats daisyUI's .card-actions. Visibility has one owner again.

   No @media (hover: none) / (pointer: coarse) escape replaces this. A pointer
   query cannot rescue a control that should never have been hidden: a desktop
   with a touchscreen reports both, and a keyboard user reports neither. */

/* ─── Dashboard: Staggered Widget Entrance Animation ───
   Sequential fade-in for dashboard widgets on page load. */

@keyframes bao-widget-entrance {
  from {
    opacity: 0;
    transform: translateY(var(--space-section, 0.75rem));
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/*
   * One-shot per first paint, not per render: the gate is a settled flag
   * the shell raises only AFTER the entrance animations finish (never at
   * DOMContentLoaded — that cancelled the entrance mid-flight and the
   * staggered widgets never played at all). The gate closes behind the
   * entrance instead of cutting it, re-rendered widgets never replay, and
   * the fill is `backwards` — it covers the stagger delay, then the
   * finished animation leaves no applied effect behind, so
   * document.getAnimations() empties after the entrance completes.
   */
@media (prefers-reduced-motion: no-preference) {
  html:not([data-reduced-motion="true"]):not([data-widget-entrance-settled="true"]) [data-dashboard-widget] {
    animation: bao-widget-entrance var(--duration-slow) var(--easing-entrance) backwards;
  }
}

/*
   * One progress cue per widget at first paint: the body slot's skeleton
   * already says loading, so ten concurrent first-load fetches painted ten
   * spinners over ten skeletons (HIG: one clear progress indicator). The
   * indicator span keeps role=status for refresh announcements once the
   * shell settles; it only stays hidden while the shell is still in its
   * initial data-state="loading".
   */
[data-dashboard-widget][data-state="loading"] .htmx-indicator {
  display: none;
}

[data-dashboard-widget]:nth-child(1) { animation-delay: var(--duration-instant); }
[data-dashboard-widget]:nth-child(2) { animation-delay: calc(var(--stagger-step) * 2); }
[data-dashboard-widget]:nth-child(3) { animation-delay: calc(var(--stagger-step) * 4); }
[data-dashboard-widget]:nth-child(4) { animation-delay: calc(var(--stagger-step) * 6); }
[data-dashboard-widget]:nth-child(5) { animation-delay: calc(var(--stagger-step) * 8); }
[data-dashboard-widget]:nth-child(6) { animation-delay: calc(var(--stagger-step) * 10); }
[data-dashboard-widget]:nth-child(7) { animation-delay: calc(var(--stagger-step) * 12); }
[data-dashboard-widget]:nth-child(8) { animation-delay: calc(var(--stagger-step) * 14); }
[data-dashboard-widget]:nth-child(9) { animation-delay: calc(var(--stagger-step) * 16); }
[data-dashboard-widget]:nth-child(10) { animation-delay: calc(var(--stagger-step) * 18); }

/* Reduced motion (either signal) never enters: the positive gate above
   only matches when BOTH the OS preference and the product toggle allow
   motion — one clamp owner, no second `animation: none` escape hatch. */

/* ─── Table row actions: always visible ───
   SSOT action host is bao-table-pinned-action (Table.bao pinnedActionCell);
   bao-table-row-actions is the inner control cluster stamped on the value span.

   These controls used to fade in on row hover. That is removed, not tuned.
   Hover-reveal put opacity 0 on controls that kept pointer-events auto,
   so a worklist row shipped six invisible-but-clickable buttons under a
   visibly EMPTY "Actions" column — a pathologist could click a row action
   they could not see, and could not discover the actions at all without
   sweeping the mouse across every row. Assistive tech announced them the
   whole time, so sighted and screen-reader users saw different UIs.

   A clinical worklist is not a marketing table: row actions are primary
   affordances and stay painted in every state, at every density and pointer
   type. Keeping them visible also deletes an entire reactive state — there is
   no hover/touch/container-width matrix left to get wrong. */

/* Field focus paint is owned by tokens-glass-a11y-part-1. */

/* ─── AI Analysis: Progress Animation ───
   Smooth progress bar fill with gradient sweep. */

@keyframes bao-progress-fill {
  from {
    background-position: 200% 0;
  }
  to {
    background-position: -200% 0;
  }
}

.progress::-webkit-progress-value {
  background-image: linear-gradient(
    90deg,
    var(--color-primary) 0%,
    color-mix(in oklab, var(--color-primary) 80%, var(--color-accent)) 50%,
    var(--color-primary) 100%
  );
  background-size: 200% 100%;
  animation: bao-progress-fill var(--duration-progress) var(--easing-standard) infinite;
  transition: width var(--duration-normal) var(--easing-standard);
}

@media (prefers-reduced-motion: reduce) {
  .progress::-webkit-progress-value {
    animation: none;
    background-image: none;
    background-color: var(--color-primary);
  }
}

/* FAQ copy keeps its complete words when root text and spacing consume the narrow track. */
[data-faq-section] {
  overflow-wrap: anywhere;
}
[data-faq-section] .collapse,
[data-faq-section] .collapse-title,
[data-faq-section] .collapse-content {
  min-inline-size: 0;
}
/* ─── Help: FAQ Accordion Animation ───
   Smooth expand/collapse for FAQ sections. */

details.collapse[open] .collapse-content {
  animation: bao-accordion-expand var(--duration-normal) var(--easing-entrance) both;
}

@keyframes bao-accordion-expand {
  from {
    opacity: 0;
    max-height: 0;
  }
  to {
    opacity: 1;
    max-height: 1000px;
  }
}

@media (prefers-reduced-motion: reduce) {
  details.collapse[open] .collapse-content {
    animation: none;
  }
}


}
@layer bao-tokens {


  :root {
    --dock-height: 4rem;
    --dock-icon-size: 1.25rem;
    --dock-label-size: 0.6875rem;
    --dock-safe-area-offset: env(safe-area-inset-bottom, 0px);
  }
  .bao-mobile-dock.dock,
  .bao-mobile-dock {
    display: flex;
    flex-direction: row;
    flex-wrap: nowrap;
    align-items: stretch;
    justify-content: space-around;
    position: fixed;
    inset-inline: 0;
    bottom: 0;
    z-index: var(--z-overlay, 1200);
    width: 100%;
    max-width: 100%;
    min-height: calc(var(--dock-height) + var(--dock-safe-area-offset));
    height: calc(var(--dock-height) + var(--dock-safe-area-offset));
    padding-bottom: var(--dock-safe-area-offset);
    border-top: 1px solid var(--liquid-border-regular);
    color: var(--color-base-content, var(--text-primary));
    /* Material: bao-surface-glass-regular on .bao-mobile-dock (app-shell.bao). */
    box-shadow:
      0 -1px 0 0 var(--liquid-border-regular),
      var(--shadow-glass-elevated);
    /* Swipe-friendly overflow when locale labels widen past 5 slots. */
    overflow-x: auto;
    overflow-y: hidden;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    touch-action: pan-x;
  }
  [data-reduced-transparency="true"] .bao-mobile-dock.dock,
  [data-reduced-transparency="true"] .bao-mobile-dock {
    /* Glass a11y solidifies .bao-surface-glass-regular — dock keeps edge only. */
    box-shadow:
      0 -1px 0 0 var(--liquid-border-regular);
  }
  @media (prefers-reduced-transparency: reduce) {
    .bao-mobile-dock.dock,
    .bao-mobile-dock {
      box-shadow:
        0 -1px 0 0 var(--liquid-border-regular);
    }
  }
  /*
   * Tablet band and up (≥48rem / 768px at 16px root): the topbar hamburger is
   * the single nav affordance (Apple HIG — iPad-class widths get the sidebar,
   * not a phone tab bar), so the dock yields. Without this the 48–79.99rem band
   * painted BOTH the dock and the hamburger.
   *
   * Zeroing --dock-height is what retires the reserved bottom gutter: every
   * clearance consumer ([data-shell-scroll="main"] padding, conversation footer, capture shutter
   * offsets, canvas-island inset, scroll-padding) reads the token, so no
   * per-surface media forks are needed and none can drift out of sync.
   *
   * This is a nav-affordance band, NOT the permanent-rail band. The rail stays
   * ≥80rem only (Android/WebView phones report ≥1024 CSS px) — see the separate
   * block below and tokens-glass-shell-drawer.
   */
  @media (min-width: 48rem) {
    :root {
      --dock-height: 0rem;
    }
    .bao-mobile-dock.dock.bao-mobile-dock,
    nav.bao-mobile-dock[data-mobile-dock],
    .bao-mobile-dock.dock,
    .bao-mobile-dock {
      display: none;
      height: 0;
      min-height: 0;
      overflow: hidden;
      pointer-events: none;
      visibility: hidden;
    }
  }
  /*
   * Permanent-rail band (≥80rem / 1280px at 16px root): dock yields to the
   * in-flow sidebar. ID selectors beat daisyUI .dock display:flex (components
   * layer) without a priority override. Mirror lives in tokens-glass-shell-drawer.
   * Subsumed by the ≥48rem hide above; kept explicit because the rail band is
   * co-owned and WebView 101 needs the ID-level rule stated at this breakpoint.
   */
  @media (min-width: 80rem) {
    .bao-mobile-dock.dock.bao-mobile-dock,
    nav.bao-mobile-dock[data-mobile-dock],
    .bao-mobile-dock.dock,
    .bao-mobile-dock {
      display: none;
      height: 0;
      min-height: 0;
      overflow: hidden;
      pointer-events: none;
      visibility: hidden;
    }
  }
  /* Keep base paint below every selected, hover, and focus state for links and buttons. */
  .bao-mobile-dock :where(a, .bao-mobile-dock-item, [data-mobile-dock-more]) {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: var(--space-2xs, 0.125rem);
    /* Reserve each destination label before distributing remaining space.
     * Longer locales use the dock scrollport instead of losing their labels. */
    min-width: max-content;
    max-width: none;
    min-height: var(--touch-target-min, 2.75rem);
    flex: 1 0 var(--touch-target-min);
    padding-block: var(--space-micro, 0.375rem);
    padding-inline: var(--space-2xs, 0.125rem);
    margin: 0;
    color: var(--text-secondary);
    text-decoration: none;
    cursor: pointer;
    border: 0;
    border-radius: var(--radius-field, 0.75rem);
    background: transparent;
    box-shadow: none;
    appearance: none;
    -webkit-appearance: none;
    font: inherit;
    line-height: inherit;
    transition-property: background-color, color, opacity, transform;
    transition-duration: var(--duration-fast);
    transition-timing-function: var(--easing-standard);
    scroll-snap-align: center;
  }
  /* More is a <button> — never look selected unless the rail is open. */
  .bao-mobile-dock :where([data-mobile-dock-more])[aria-expanded="true"] {
    color: var(--color-primary, var(--accent-primary, currentColor));
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
  }
  .bao-mobile-dock a:active,
  .bao-mobile-dock-item:active,
  .bao-mobile-dock [data-mobile-dock-more]:active {
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
    opacity: var(--opacity-chrome, 0.92);
    transform: scale(0.96);
  }
  .bao-mobile-dock a:focus-visible,
  .bao-mobile-dock-item:focus-visible,
  .bao-mobile-dock [data-mobile-dock-more]:focus-visible {
    outline: var(--focus-ring-width) solid var(--color-primary, currentColor);
    outline-offset: var(--focus-ring-offset);
  }
  .bao-mobile-dock a[aria-current="page"],
  .bao-mobile-dock-item[aria-current="page"],
  .bao-mobile-dock-item[aria-pressed="true"] {
    color: var(--color-primary, var(--accent-primary, currentColor));
    background: color-mix(in oklab, var(--accent-primary) calc(var(--liquid-fill-control) * 100%), var(--bg-panel));
    box-shadow: inset 0 0 0 1px var(--liquid-border-regular);
  }
  /* Apple HIG active: filled glyph weight via stroke; inactive stays outline. */
  .bao-mobile-dock a[aria-current="page"] svg,
  .bao-mobile-dock-item[aria-current="page"] svg,
  .bao-mobile-dock-item[aria-pressed="true"] svg {
    stroke-width: 2.25;
    fill: color-mix(in oklab, var(--color-primary) calc(var(--liquid-fill-control) * 100%), transparent);
  }
  .bao-mobile-dock svg,
  .bao-mobile-dock .bao-dock-icon {
    width: var(--dock-icon-size);
    height: var(--dock-icon-size);
    flex: 0 0 auto;
  }
  .bao-mobile-dock .dock-label {
    font-size: var(--dock-label-size);
    font-weight: 500;
    line-height: 1.1;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
  @media (prefers-reduced-motion: reduce) {
    .bao-mobile-dock a,
    .bao-mobile-dock-item,
    .bao-mobile-dock [data-mobile-dock-more] {
      transition-property: none;
      transition-duration: var(--duration-instant);
    }
    .bao-mobile-dock a:active,
    .bao-mobile-dock-item:active,
    .bao-mobile-dock [data-mobile-dock-more]:active {
      transform: none;
    }
  }
  [data-reduced-motion="true"] .bao-mobile-dock a:active,
  [data-reduced-motion="true"] .bao-mobile-dock-item:active,
  [data-reduced-motion="true"] .bao-mobile-dock [data-mobile-dock-more]:active {
    transform: none;
  }

  /* ─── FAB (imp-t08): floating page-primary action ───
     Position SSOT: floats above the bottom dock + home-indicator safe area on
     phone, and above the page gutter on tablet; inline-end honors the trailing
     safe-area inset. Visible only below the 64rem desktop band — the header
     CTA owns the verb on desktop (one primary affordance per band).
     Geometry (56px target) and surface live in FAB.bao tokens; this block
     owns placement, band visibility, and the scroll-aware hidden state
     (app-shell-fab.ts stamps data-fab-hidden). */
  .bao-fab {
    position: fixed;
    inset-block-end: calc(var(--dock-height, calc(var(--space-2xl) * 2)) + var(--dock-safe-area-offset, env(safe-area-inset-bottom, 0px)) + var(--space-section, 1rem));
    inset-inline-end: max(var(--space-section, 1rem), env(safe-area-inset-right, 0px));
    z-index: var(--z-sticky, 1100);
    display: inline-flex;
    box-shadow: var(--shadow-glass-floating);
    transition-property: transform, opacity;
    transition-duration: var(--duration-normal);
    transition-timing-function: var(--easing-standard);
  }
  /* Scroll-aware hide: slide below the dock edge and drop hit-testing. */
  .bao-fab[data-fab-hidden="true"] {
    transform: translateY(calc(100% + var(--space-section, 1rem)));
    opacity: 0;
    pointer-events: none;
    visibility: hidden;
  }
  /* Desktop band: header CTA owns the primary verb — FAB yields entirely.
     The repeated class selector lifts this rule to (0,4,0) so the shell-wide
     .btn:not([hidden]):not(.hidden) display rule (0,3,0) cannot re-assert
     inline-flex above 64rem — the same outrank pattern documented in
     tokens-layout-page-shells-capture-responsive (attribute repetition). */
  @media (min-width: 64rem) {
    .bao-fab {
      display: none;
    }
  }
  /* Phone band (< 40rem): the page header's action zone goes full-width in
     flow there (max-sm:w-full, the same 40rem threshold), so the header CTA
     is already a full-bleed primary button a thumb reaches without leaving the
     document flow. The FAB is a fixed second copy of that one verb, and being
     fixed it prints over the list: at 390x844 on /cases it covered the card
     stack's row-select control outright — elementFromPoint at the checkbox
     centre [348,725] returned button.bao-fab, so no tap could reach it. One
     primary action per surface: the in-flow CTA survives because it cannot
     occlude content, and the FAB yields here for the same reason it already
     yields above 64rem. It keeps the 40-64rem band, where the header CTA
     collapses to a trailing btn-sm well out of thumb reach.
     Same (0,4,0) repetition as the desktop rule, for the same reason. */
  @media (max-width: 39.99rem) {
    .bao-fab {
      display: none;
    }
  }
  /* Tablet band has no dock: drop the FAB to the page gutter clearance. */
  @media (min-width: 48rem) and (max-width: 63.99rem) {
    .bao-fab {
      inset-block-end: calc(var(--space-section, 1rem) + var(--dock-safe-area-offset, env(safe-area-inset-bottom, 0px)));
    }
  }
  @media (prefers-reduced-motion: reduce) {
    .bao-fab {
      transition-property: none;
      transition-duration: var(--duration-instant);
    }
    .bao-fab[data-fab-hidden="true"] {
      transform: none;
    }
  }

@media (min-width: 40rem) and (max-width: 63.99rem) {
  .btn[data-header-primary-fab-mirrored]:not([hidden]):not(.hidden) {
    display: none;
  }
}

@media (max-width: 47.99rem) {





  /*
   * Live: the stream owns a 4:3 frame and the bar floats over it. Idle: the
   * placeholder and the in-flow capture bar size the stage — a fixed ratio
   * under overflow:hidden clipped the two-row phone bar (measured 390x844:
   * a 146px bar inside a 281px frame).
   */
  [data-page="capture"] [data-camera-preview].bao-capture-preview[data-preview-state="live"] {
    aspect-ratio: 4 / 3;
  }
}
[data-primitive="ScannerPreview"].bao-scanner-preview {
  aspect-ratio: 16 / 9;
  flex: 0 0 auto;
  min-height: 0;
}


  /* The shared main reserves the actual dock and the canonical page gutter.
   * Touch-target dimensions belong to controls, never to empty page clearance. */
  html[data-plane="workbench"] [data-shell-scroll="main"] {
    padding-block-end: calc(var(--dock-height) + var(--dock-safe-area-offset) + var(--page-gutter-block));
    scroll-padding-block-end: calc(var(--dock-height) + var(--dock-safe-area-offset) + var(--page-gutter-block));
  }
  @media (max-width: 79.99rem) {
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="media"],
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="conversation"] {
      padding-block-end: calc(var(--dock-height) + var(--dock-safe-area-offset));
      scroll-padding-block-end: 0;
    }
  }
  /* Immersive desktop main has no shell gutter; its content owns the stage. */
  @media (min-width: 80rem) {
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="media"],
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="conversation"] {
      padding-block-end: 0;
      scroll-padding-block-end: 0;
    }
  }
  /* A flow dock follows main; it never reserves a fixed dock band in main. */
  .bao-shell-drawer[data-shell-chrome-flow] main[data-shell-scroll="main"] {
    padding-block-end: var(--space-section);
    scroll-padding-block-end: 0;
  }
  /* Print retires shell chrome and every main gutter, including flow chrome. */
  @media print {
    html[data-plane="workbench"] .bao-shell-drawer [data-shell-scroll="main"] {
      padding-block: 0;
      padding-inline: 0;
      scroll-padding-block-end: 0;
    }
  }
  /* Optional keypad geometry; native disclosure owns visibility. */
  .bao-auth-pin-pad {
    grid-template-columns: repeat(auto-fit, minmax(max(var(--touch-target-min), calc((100% - 2 * var(--space-micro)) / 3)), 1fr));
  }
  /* Phone densify: tighter page gutters so workbench fills the docked viewport. */
  @media (max-width: 47.99rem) {
    html[data-plane="workbench"] [data-shell-scroll="main"] {
      padding-inline: var(--space-inline, 0.5rem);
      padding-block-start: var(--space-micro, 0.25rem);
    }
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="media"],
    html[data-plane="workbench"] [data-shell-scroll="main"][data-main-page-type="conversation"] {
      padding-inline: 0;
      padding-block-start: 0;
    }
    [data-page="settings"] .bao-settings-group {
      padding: var(--space-inline, 0.5rem);
    }
    [data-page="settings"] .bao-tabs-scroll {
      margin-inline: 0;
    }
    /* Capture context grid: 2-up on phone, not 4 tiny truncated chips. */
    [data-page="capture"] [data-capture-context-strip] {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }


    /* Chat context: horizontal chip rail, keep ≥44px touch. */
    [data-page="chat"] [data-chat-context],
    [data-chat-context] {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      align-items: center;
      gap: var(--space-micro);
      overflow-x: auto;
      overscroll-behavior-x: contain;
      -webkit-overflow-scrolling: touch;
    }
    /*
     * Context-more dropdown escape hatch (same layer, later position): the
     * chip rail's overflow-y clip amputates the open menu on phone widths
     * and the strip's backdrop-filter traps its stacking context under the
     * message thread. Unclip and lift only while the menu is open.
     */
    [data-page="chat"] [data-chat-context]:has([data-chat-context-more][open]),
    [data-chat-context]:has([data-chat-context-more][open]) {
      overflow-x: visible;
      overflow-y: visible;
      z-index: var(--z-dropdown, 1250);
    }
    [data-page="chat"] [data-chat-context] button,
    [data-chat-context] button {
      min-height: var(--touch-target-min, 2.75rem);
    }
    /*
     * Collection FilterBar densify — 2-col phone grid (Apple dense filters).
     * Search + action row span full width; status/priority pair side-by-side.
     * Replaces column stack that burned 3+ viewport rows on cases/billing.
     */
    [data-page-type="collection"] [data-primitive="FilterBar"],
    [data-page="cases"] [data-case-filters],
    [data-case-filters],
    [data-primitive="FilterBar"],
    [data-filter-bar] {
      justify-content: stretch;
      height: auto;
      min-height: 0;
    }
    [data-case-filters] fieldset,
    [data-case-filters] .fieldset,
    [data-primitive="FilterBar"] fieldset,
    [data-primitive="FilterBar"] .fieldset,
    [data-filter-bar] fieldset,
    [data-filter-bar] .fieldset {
      height: auto;
      align-self: stretch;
    }
    [data-case-filters] .select,
    [data-case-filters] .input,
    [data-primitive="FilterBar"] .select,
    [data-primitive="FilterBar"] .input {
      width: 100%;
      min-height: var(--touch-target-min, 2.75rem);
    }
    [data-case-filters] .btn,
    [data-primitive="FilterBar"] .btn {
      min-height: var(--touch-target-min, 2.75rem);
      justify-content: center;
    }
    /* Reset/clear stays full-width only when alone in the actions row. */
    [data-case-filters] > .flex .btn,
    [data-primitive="FilterBar"] > .flex .btn {
      width: auto;
      min-width: var(--touch-target-min, 2.75rem);
    }
    /* Capture context: 2-up; chat context stays the horizontal rail above. */
    [data-capture-context-strip] {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      gap: var(--space-micro);
    }
    [data-capture-context-strip] button,
    [data-capture-context-strip] [data-capture-context-button] {
      min-height: var(--touch-target-min, 2.75rem);
      max-width: 11rem;
    }
    /*
     * Editor/capture context badges — long image UUIDs single-line ellipsis
     * (never multi-line wrap blowout on phone chips).
     */


    /* Topbar context chips: single owner is tokens-glass-shell-context-density.ts. */
    /*
     * Collection pages (models, licensing, specimens, …): WebView 101 lacks
     * :has() — force single-column panels and full-width form controls.
     * Never fork per data-page id.
     */

    [data-page-type="collection"] .card-body,
    [data-page-type="collection"] .bao-data-panel,
    [data-page-type="collection"] [data-primitive="DataTable"],
    [data-page-type="collection"] .overflow-x-auto {
      max-width: 100%;
      min-width: 0;
    }
    [data-page-type="collection"] table {
      max-width: 100%;
    }
    [data-page-type="collection"] [role="tab"].tab,
    [data-page-type="collection"] [data-lifecycle-tab] {
      min-height: var(--touch-target-min, 2.75rem);
      height: auto;
    }
    [data-page-type="collection"] form .input,
    [data-page-type="collection"] form .select {
      width: 100%;
      min-height: var(--touch-target-min, 2.75rem);
    }
    [data-page="specimens"] [data-specimen-create-form] .btn {
      width: auto;
      min-width: var(--touch-target-min, 2.75rem);
    }
    /* Pagination join controls always ≥44px on phone. */
    [data-pagination] .btn,
    .join .btn.join-item {
      min-height: var(--touch-target-min, 2.75rem);
      min-width: var(--touch-target-min, 2.75rem);
    }
    /*
     * Collection sticky toolbars (evidence, models, …): ONE horizontal rail.
     *
     * The rail is the design this comment always described; wrapping was what
     * it actually did. Measured at 320x720: /reports wrapped 8 soft actions
     * into 246px of STICKY toolbar and /evidence 5 into 198px — a third of
     * the viewport, pinned, painting over the form beneath it. Fifteen
     * controls on /reports lost their centre hit test to that slab
     * (browser-touch-reachability, blocker div.rounded-field at z-index
     * 1100). The wrap was sized for the two or three actions these bars
     * carried when it was written and does not survive eight.
     *
     * `nowrap` with the overflow-x below turns it back into the rail: one
     * 52px row that scrolls, with .bao-scroll-edge-x fading the cut edge so
     * the overflow is visible. The primary CTA leads (order: -1) and sizes to
     * its own label rather than claiming a full-width second row, so the
     * essential action needs no scrolling and long verbs still never clip —
     * they scroll instead of breaking mid-word.
     */
    [data-page-type="collection"] [role="toolbar"] {
      display: flex;
      flex-direction: row;
      flex-wrap: nowrap;
      align-items: center;
      justify-content: flex-start;
      gap: var(--space-micro);
      overflow-x: auto;
      overscroll-behavior-x: contain;
      -webkit-overflow-scrolling: touch;
      max-width: 100%;
    }
    [data-page-type="collection"] [role="toolbar"] .btn {
      flex: 0 0 auto;
      min-height: var(--touch-target-min, 2.75rem);
      min-width: var(--touch-target-min, 2.75rem);
    }
    /* Why-tip hosts wrap disabled primaries — the host is the flex item. */
    [data-page-type="collection"] [role="toolbar"] > .btn-primary,
    [data-page-type="collection"] [role="toolbar"] > [data-disabled-tip-host]:has(.btn-primary),
    [data-page-type="collection"] [role="toolbar"] > span:has(> .btn-primary),
    [data-page-type="collection"] [role="toolbar"] > span:has(> button.btn-primary) {
      flex: 0 0 auto;
      order: -1;
      max-width: 100%;
      width: auto;
    }
    [data-page-type="collection"] [role="toolbar"] .btn-primary {
      justify-content: center;
      width: auto;
      max-width: 100%;
    }

  }/*
   * Touch SSOT — header actions + settings tabs must meet 44px on phone /
   * BlueStacks coarse pointers (btn-sm alone is ~32–36px).
   */
  @media (max-width: 47.99rem),
(pointer: coarse) {
    [data-page-header-actions] .btn {
      height: auto;
    }
    [data-settings-tab].tab,
[data-settings-tab].bao-settings-tab,
.tab.bao-settings-tab,
[data-session-mode-tab].tab,
[data-capture-context-strip] button,
[data-chat-context] button,
.bao-context-card {
      min-height: var(--touch-target-min, 2.75rem);
      height: auto;
      min-width: var(--touch-target-min, 2.75rem);
    }
    /*
     * Topbar densify — hide brand detail + long status chrome;keep icon
     * actions at 44px. Context chips stay horizontal scroll (not 5-up crush).
     */
    .bao-shell-brand-detail,
.navbar .bao-brand-detail,
.bao-shell-topbar .bao-brand-detail {
      display: none;
    }.bao-shell-topbar .navbar-end .btn,
.bao-shell-topbar .navbar-end button.btn,
.bao-shell-topbar .navbar-end .bao-shell-status-badge,
.bao-shell-topbar .navbar-end [data-registry-status],
[data-page-header-actions] .btn,
[data-page-header-actions] a.btn {
      /* Canonical target geometry remains intact; responsive layout owns reflow. */
      min-height: var(--touch-target-min);
      min-width: var(--touch-target-min);
    }
    /* Status badges: label is sr-only on phone;keep HIG 44px hit target. */
    .bao-shell-topbar .bao-shell-status-badge [data-status-label],
.bao-shell-topbar [data-registry-status] [data-status-label] {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border: 0;
    }
/*
     * Collection dual-panel forms (licensing credentials | serials,
models
     * lifecycle | discover): one full-width column — never half-width crush.
     * Reinforces page-shell-surfaces without per-page forks.
     */
    [data-page-type="collection"] .bao-grid-reactive-panels {
      grid-template-columns: minmax(0, 1fr);
    }
    [data-page-type="collection"] .bao-grid-reactive-panels > * {
      grid-column: 1 / -1;
      max-width: none;
      min-width: 0;
    }
    /*
     * FilterBar phone densify — 2-col for select/status filters;search +
     * actions span full width. Beats max-sm:flex-col stack that wasted 3+
     * viewport rows on cases/billing/models (Apple dense filter pattern).
     * Specificity must beat utility flex class on the same host (specificity only).
     */
    [data-shell-scroll="main"] [data-primitive="FilterBar"],
[data-shell-scroll="main"] div[data-primitive="FilterBar"] {
      display: grid;
      grid-template-columns: repeat(2, minmax(0, 1fr));
      align-items: end;
      gap: var(--space-micro, 0.25rem);
    }[data-shell-scroll="main"] [data-primitive="FilterBar"] > .fieldset,
[data-shell-scroll="main"] [data-primitive="FilterBar"] > fieldset {
      min-width: 0;
      width: 100%;
    }
[data-shell-scroll="main"] [data-primitive="FilterBar"] > .fieldset:has(input[type="search"]),
[data-shell-scroll="main"] [data-primitive="FilterBar"] > fieldset:has(input[type="search"]),
[data-shell-scroll="main"] [data-primitive="FilterBar"] > .fieldset:has([data-filter-search]),
[data-shell-scroll="main"] [data-primitive="FilterBar"] > fieldset:has([data-filter-search]),
[data-shell-scroll="main"] [data-primitive="FilterBar"] > .fieldset:has([data-case-search]) {
      grid-column: 1 / -1;
    }/*
     * Form field helpers restate the label/placeholder on phone — hide the
     * visual row,
keep aria-describedby for AT (sr-only geometry).
     */
    [data-shell-scroll="main"] [data-field-helper] {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border-width: 0;
    }/*
     * Empty AI overlay hosts must not reserve a tall gray slab on phone —
     * empty copy + border is enough (Apple form density).
     */
    [data-shell-scroll="main"] [data-ai-overlays-empty],
[data-shell-scroll="main"] [data-ai-overlays-empty] .bao-min-h-panel-body,
[data-shell-scroll="main"] [data-page="ai-analysis"] [data-primitive="VisualizationLayers"][data-state="empty"],
[data-shell-scroll="main"] [data-page="ai-analysis"] [data-primitive="VisualizationLayers"] .bao-min-h-panel-body {
      min-height: 0;
    }
  }/*
   * Phone FilterBar legends stay VISIBLE for select groups: status and
   * priority both default to the same "All" text, so hiding legends left two
   * identical unlabeled selects (HIG: controls identifiable without a
   * tooltip). The sr-only clip for value-carrying search groups is owned by
   * tokens-glass-shell-controls-b (search-scoped, sentence case). This
   * blanket width-only clip was removed: its [data-shell-scroll="main"] id outranked that SSOT
   * and re-hid every phone legend.
   */

}
@layer bao-tokens {
@media (max-width: 47.99rem) {
  [data-page-type="media"] .bao-editor-canvas.bao-editor-canvas-host-bounded {
    border-radius: 0;
    border-inline-width: 0;
  }
}

/* Shared viewport commands use Toolbar's material and logical block-end placement.
 * Spatial commands own horizontal scrolling when a stage is narrow; the bounded planar pair keeps its native visible overflow. */
[data-editor-viewport-controls] {
  inline-size: fit-content;
  justify-content: flex-start;
}
[data-editor-viewport-controls="3d"] {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  touch-action: pan-x;
}
[data-editor-viewport-controls] > button {
  flex: 0 0 auto;
}
[data-shell-scroll="main"] [data-editor-3d-controls] button[aria-label] {
  inline-size: var(--touch-target-min, 2.75rem);
  min-inline-size: var(--touch-target-min, 2.75rem);
  flex-basis: var(--touch-target-min);
  padding-inline: 0;
}

}
@layer bao-tokens {
[data-editor-stage-toolbar] {
  flex-wrap: nowrap;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-x: auto;
  overscroll-behavior-inline: contain;
}
[data-editor-stage-toolbar] > [data-toolbar-region="leading"],
[data-editor-stage-toolbar] > [data-toolbar-region="trailing"] {
  flex: 0 0 auto;
}
[data-editor-stage-toolbar] > [data-toolbar-region="commands"] {
  flex: 0 0 auto;
  min-inline-size: var(--touch-target-min);
  overflow: visible;
}
[data-editor-stage-toolbar] [data-editor-tool-rail] {
  display: flex;
  flex-flow: row nowrap;
  flex: 0 0 auto;
  inline-size: max-content;
  max-inline-size: none;
}

/* Narrow stages cannot hold dimension, tools, history, inspector and save
 * on one 44px row: the scrollport stranded save 258px off-screen at 320px
 * and, after entering canvas Maximize from the trailing menu, stranded the
 * drawing tools off the leading edge instead. Below the one-row floor the
 * plate wraps to two rows — dimension plus trailing essentials first, the
 * tool dock on its own row — so every essential control stays painted and
 * hit-testable without horizontal scrolling. */
@container editor-stage (max-width: 64rem) {
  [data-editor-stage-toolbar] {
    flex-wrap: wrap;
    overflow-x: visible;
  }
}
@container editor-stage (max-width: 38rem) {
  [data-editor-stage-toolbar] {
    flex-wrap: wrap;
    overflow-x: visible;
  }
  [data-editor-stage-toolbar] > [data-toolbar-region="trailing"] {
    order: 2;
  }
  [data-editor-stage-toolbar] > [data-toolbar-region="commands"] {
    order: 3;
    flex: 1 1 100%;
  }
}

}
@layer bao-tokens {
/*
 * Compact inspector sheet stacks on --z-modal, above in-flow workbench chrome.
 * Named `editor-workbench`: an unnamed query rebinds to the nearest container.
 */
@container editor-workbench (max-width: 48rem) {
  .bao-editor-workbench[data-editor-open-surface="inspector"] > [data-editor-canvas-overlays] {
    z-index: var(--z-modal, 1300);
  }
}

}
@layer bao-tokens {
[data-editor-tool-rail] [data-editor-toolbar-controls],
[data-editor-tool-rail] [data-tool-group-label] {
  display: none;
}

[data-editor-tool-rail] [data-tool-group][hidden] {
  display: none;
}

[data-editor-tool-rail] [data-editor-more-tools] {
  display: inline-flex;
}

[data-editor-tool-catalog] {
  display: flex;
  min-width: 0;
  min-height: 0;
  flex-direction: column;
  overflow-y: auto;
  gap: var(--space-inline, 0.5rem);
}

/* Category segments keep their full label width inside the joined scroller. */
[data-editor-tool-catalog] [data-editor-tool-filter] {
  flex: 0 0 auto;
  min-inline-size: max-content;
}

[data-editor-tool-filter][aria-pressed="true"] {
  background: var(--color-base-200);
  color: var(--color-base-content);
}

/* Selected tools keep accent paint above shared soft-Button interaction states.
   Visibility guards match the Button owner; disabled tools retain its disabled paint. */
[data-editor-tool-catalog] .btn[data-tool][aria-pressed="true"]:not([hidden]):not(.hidden):where(:not(:disabled):not([aria-disabled="true"])) {
  background: var(--accent-primary);
  border-color: var(--accent-primary);
  color: var(--accent-primary-content);
}

[data-editor-tool-catalog] [data-tool-group] {
  min-width: 0;
  max-width: 100%;
}

[data-editor-tool-catalog] [data-tool-group][hidden] {
  display: none;
}

[data-editor-tool-catalog] [data-tool-group-label] {
  grid-column: 1 / -1;
  font-size: var(--text-xs, 0.75rem);
  font-weight: 600;
}

[data-editor-tool-catalog] [data-tool] {
  width: 100%;
  min-width: 0;
  justify-content: flex-start;
  gap: var(--space-inline, 0.5rem);
  padding-inline: var(--space-inline, 0.5rem);
  border-radius: var(--radius-field);
  flex-wrap: nowrap;
}
  /* Tool selection follows the declared aria-pressed state. */

  @media (forced-colors: active) {
    [data-editor-toolbar] [data-tool-group][data-tool],
    [data-editor-tool-catalog] [data-tool-group][data-tool] {
      border-color: ButtonText;
      color: ButtonText;
    }
  }

  [data-shell-scroll="main"] [data-editor-tool-catalog] .btn.bao-toolbar-action.btn-square[data-tool] {
    width: 100%;
    min-width: 0;
    justify-content: flex-start;
    gap: var(--space-inline, 0.5rem);
    padding-inline: var(--space-inline, 0.5rem);
  }
[data-editor-tool-palette] [data-editor-tool-catalog] > [data-editor-toolbar-controls] {
  flex: 0 0 auto;
}
@media (min-width: 48rem) and (max-height: 32rem) {
  [data-page-type="media"] .bao-media-page-root {
    position: relative;
    gap: 0;
  }

  [data-page-type="media"] .bao-media-page-root > [data-primitive="PageHeader"] {
    position: absolute;
    inset-block-start: 0;
    inset-inline-end: var(--page-gutter-inline, var(--space-section));
    z-index: var(--z-canvas-overlay);
    width: auto;
    min-width: 0;
    padding-block-end: 0;
    border-block-end: 0;
  }

  [data-page-type="media"] [data-editor-context-bar] > [data-editor-context] {
    display: none;
  }

  [data-page-type="media"] [data-session-mode-tabs]:not([data-session-rail-mode-tabs]) {
    position: relative;
    inset: auto;
    z-index: auto;
  }

  [data-page-type="media"] .bao-editor-workbench,
  [data-page-type="media"] .bao-editor-canvas {
    min-height: 0;
    max-height: 100%;
  }

}

}
@layer bao-tokens {
/* Bottom action bar: discard leading, save form trailing. */
.bao-editor-bottom-bar {
  display: flex;
  min-width: 0;
  flex: 0 0 auto;
  align-items: center;
  gap: var(--space-inline, 0.5rem);
  border-block-start: 1px solid var(--liquid-border-regular);
  background-color: var(--color-base-100);
  padding-inline: var(--space-inline, 0.5rem);
  padding-block: var(--space-micro, 0.25rem);
}

}
@layer bao-tokens {
/* Native overflow catalog: one nonmodal chrome surface, viewport-contained. */
[data-editor-tool-palette-invoker] { anchor-name: --editor-tool-palette-invoker; }
[data-editor-tool-palette] {
  position: fixed;
  position-anchor: --editor-tool-palette-invoker;
  inset: auto;
  inset-block-start: clamp(var(--space-inline), anchor(top), calc(100dvh - var(--modal-scroll-max-height) - var(--space-inline)));
  inset-inline-start: clamp(var(--space-inline), calc(anchor(right) + var(--space-inline)), calc(100dvw - var(--sheet-panel-width) - var(--space-inline)));
  inline-size: min(var(--sheet-panel-width), calc(100dvw - 2 * var(--space-inline)));
  max-block-size: min(var(--modal-scroll-max-height), calc(100dvh - 2 * var(--space-inline)));
  margin: 0;
  padding: 0;
  overflow: clip;
}
[data-editor-tool-palette]:popover-open { display: flex; flex-direction: column; }
.bao-editor-tool-palette-drag-handle { display: none; }
@media (max-width: 47.99rem) {
  [data-editor-tool-palette] {
    inset-block-start: auto;
    inset-block-end: calc(var(--space-inline) + env(safe-area-inset-bottom));
    inset-inline-start: var(--space-inline);
    inline-size: calc(100dvw - 2 * var(--space-inline));
  }
  .bao-editor-tool-palette-drag-handle {
    display: block;
    width: var(--touch-target-min);
    height: var(--space-micro);
    margin: var(--space-micro) auto 0;
    border-radius: var(--radius-full);
    background: color-mix(in oklab, var(--color-base-content) 30%, transparent);
    touch-action: pan-y;
  }
  [data-editor-tool-palette][data-editor-tool-palette-dismiss-pending] {
    animation: bao-editor-tool-palette-dismiss var(--duration-fast) var(--easing-standard) forwards;
  }
}
@media (prefers-reduced-motion: reduce) {
  [data-editor-tool-palette][data-editor-tool-palette-dismiss-pending] { animation: none; }
}
@keyframes bao-editor-tool-palette-dismiss {
  to { transform: translateY(100%); opacity: 0; }
}

}
@layer bao-tokens {

  [data-editor-tool-palette] [data-editor-tool-palette-close] {
    flex: 0 0 auto;
  }

}
@layer bao-tokens {
/* Palette control layout is owned by enterprise-page.bao toolbarControls and toolbarFilterGroup. */

}
@layer bao-tokens {
/*
 * The status HUD is passive: pointer events stay on the specimen, and none of
 * its chips are focus targets. It cannot own a scrollport. Tablet preserves
 * review, save, zoom, and AI provenance in flow while demoting draw telemetry.
 */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  [data-page-type="media"] [data-editor-status-bar] {
    max-block-size: none;
    overflow: visible;
  }

  [data-page-type="media"] [data-editor-status-bar] [data-editor-status="cursor"],
  [data-page-type="media"] [data-editor-status-bar] [data-editor-status="input"],
  [data-page-type="media"] [data-editor-status-bar] [data-editor-status="layer"] {
    display: none;
  }
}
/* Canvas-first tablet pin yield lives in tokens-layout-editor-tablet-canvas-priority.css (editor + capture). This archive stays so the style identity is not deleted. */
/*
 * Shell ancestors yield containment only while the actual AnnotationWorkbench
 * owns the viewport. Main's view transition otherwise creates a clipping
 * containing block; drawer and page query containers do the same for fixed
 * descendants. Their normal responsive ownership returns on Restore.
 */
body[data-canvas-maximized="true"] #session-rail {
  display: none;
}

body[data-canvas-maximized="true"] [data-shell-scroll="main"] {
  z-index: var(--z-local, 1);
  view-transition-name: none;
  contain: none;
  overflow: visible;
}

body[data-canvas-maximized="true"] .bao-shell-drawer {
  container-type: normal;
  overflow: visible;
}

body[data-canvas-maximized="true"] .bao-page-track {
  container-type: normal;
  overflow: visible;
}

/* The pinned sidebar yields stacking to main; an open navigation Sheet
 * keeps its existing overlay order and dismissal lifecycle. */
body[data-canvas-maximized="true"] .bao-shell-drawer:not(.drawer-open) .drawer-side {
  z-index: auto;
}

}
@layer bao-tokens {
.bao-toolbar-readout-surface {
  --toolbar-readout-padding-block: var(--space-micro);
  padding-block: var(--toolbar-readout-padding-block);
}

@media (height <= 32rem) {
  @container editor-surface (width > 40rem) {
    [data-editor-document-status] {
      flex-direction: row;
      --toolbar-readout-padding-block: var(--space-2xs);
    }
    [data-editor-persistence-status] {
      align-self: start;
    }
    [data-editor-document-status-details] {
      flex: 1 1 auto;
    }
  }
}

/* Document facts wrap in their own unpainted row, outside command geometry. */
[data-editor-document-status] [data-editor-context-bar] {
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-2xs) var(--space-inline);
  min-inline-size: 0;
  max-inline-size: 100%;
  padding-inline-end: 0;
  overflow: visible;
  mask-image: none;
}
[data-editor-document-status] [data-editor-context-bar] > [data-editor-context] {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
  flex-wrap: wrap;
  white-space: normal;
  overflow-wrap: anywhere;
  overflow: visible;
  text-overflow: clip;
}
[data-editor-document-status] [data-editor-context-bar] dd {
  display: flex;
  align-items: center;
  min-inline-size: 0;
  margin: 0;
}
@container editor-stage (max-width: 72rem) {
  [data-editor-document-status] [data-editor-stage-title],
  [data-editor-status-bar] [data-editor-status="ai-provider"],
  [data-editor-status-bar] [data-editor-status="ai-model"] {
    display: none;
  }
}
@container editor-stage (max-width: 32rem) {
  [data-editor-status-bar] [data-editor-status="ai-confidence"],
  [data-editor-status-bar] [data-editor-status="ai-shape"] {
    display: none;
  }
}
/*
 * The floating palette's footprint: one control plus its own padding and the
 * stage gutter. Declared once on the root so every band reads the same value —
 * the stage pads for it on the inline-start (roomy) or block-end (compact)
 * edge, and the compact inspector sheet lifts above it by the same token
 * (tokens-layout-editor-workbench-grid).
 */
.bao-editor-root {
  /* What the compact inspector sheet must rise above: the horizontal palette
     at the stage's block end (≤40rem root); nothing when the rail is vertical. */
  --editor-viewport-controls-clearance: calc(var(--touch-target-min, 2.75rem) + 3 * var(--space-micro, 0.25rem));
  --editor-sheet-palette-clearance: var(--editor-viewport-controls-clearance);
}

@container editor-surface (max-width: 40rem) {
  .bao-editor-workbench {
    --editor-sheet-palette-clearance: calc(2 * var(--editor-viewport-controls-clearance));
  }
}

/*
 * View adjustments: the glass shell keeps dismissal and commands in view.
 * Only its fields scroll. Compact stages use a sheet above the tool palette;
 * roomy stages anchor the same panel beside the vertical rail.
 */
[data-editor-view-adjust-panel] {
  inset-inline-start: calc(var(--space-section) + var(--touch-target-min) + var(--space-inline));
  inset-inline-end: var(--space-section);
  inset-block-start: calc(var(--editor-stage-toolbar-block-size, var(--touch-target-min)) + var(--space-section));
  inset-block-end: calc(var(--editor-sheet-palette-clearance) + var(--space-section));
  translate: none;
  inline-size: min(var(--overlay-panel), calc(100% - var(--touch-target-min) - var(--space-inline) - 2 * var(--space-section)));
  max-block-size: calc(100% - var(--editor-stage-toolbar-block-size, var(--touch-target-min)) - var(--editor-sheet-palette-clearance) - 2 * var(--space-section));
  overflow: hidden;
}
[data-editor-view-adjust-body] {
  flex: 1 1 auto;
  scrollbar-gutter: stable;
}
[data-editor-view-adjust-histogram] {
  block-size: calc(var(--touch-target-min) + var(--space-micro));
  flex: 0 0 auto;
}
[data-editor-view-adjust-actions] {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, calc(var(--touch-target-min) * 2.5)), 1fr));
}
@container editor-surface (max-width: 40rem) {
  [data-editor-view-adjust-panel] {
    inset-inline: var(--space-section);
    inline-size: auto;
  }
}

/* Readout separation is decorative; status sizing belongs to Bao primitives. */
[data-editor-document-status] [data-editor-status-bar] > [data-editor-status] + [data-editor-status]::before {
    content: "·";
    margin-inline-end: var(--space-micro, 0.25rem);
  }

}
@layer bao-tokens {
@media (max-width: 47.99rem) {
  [data-page="editor"] [data-session-mode-tabs] {
    box-sizing: border-box;
    block-size: var(--touch-target-min, 2.75rem);
    min-block-size: var(--touch-target-min, 2.75rem);
    margin-block: 0;
    padding: 0;
    border: 0;
    background: transparent;
  }
  [data-page="editor"] > [data-state-content] > [data-primitive="PageHeader"]:not(.sr-only) {
    box-sizing: border-box;
    block-size: var(--touch-target-min, 2.75rem);
    min-block-size: var(--touch-target-min, 2.75rem);
    padding-block: 0;
  }
  /* The shared fact track wraps only when its content exceeds the canvas width. */
  [data-page="editor"] [data-editor-document-status] [data-editor-context-bar],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] {
    min-inline-size: 0;
    max-inline-size: 100%;
  }
  /*
   * Phone HUD: demote cursor/layer telemetry (they belong in the inspector,
   * not the title strip); keep the clinical survivors zoom, calibration,
   * review, and persistence pinned visible.
   */
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="cursor"],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="layer"] {
    display: none;
  }
  /*
   * The selected model's provenance pair belongs to the AI panel on a phone —
   * measured 390x844, the pair alone put a third row on the stage header.
   */
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="ai-provider"],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="ai-model"] {
    display: none;
  }
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="zoom"],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="review"],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="persistence"],
  [data-page="editor"] [data-editor-document-status] [data-editor-status-bar] [data-editor-status="calibration"]:not([hidden]) {
    display: flex;
  }
}

}
@layer bao-tokens {
/* Compact stage clearance; inspector disclosure lives with the workbench. */
@container editor-workbench (max-width: 48rem) {
  /*
   * First-paint clearance estimate for the chrome under the stage — the
   * filmstrip. Runtime stamps the measured height as
   * --editor-stage-chrome-block-size on .bao-editor-workbench.
   */
  [data-page-type="media"] .bao-editor-workbench {
    --editor-stage-chrome-block-size: calc(var(--touch-target-min, 2.75rem) + 2.5rem);
  }
}

/*
 * Phone rails keep complete touch targets for drawing, navigation and
 * history in both dimensions. Secondary tools move into the shared catalog
 * at the phone band, with one more drawing tool moving at the narrow floor.
 * More tools retains every authored tool (HIG canon H2: a band swap). Lives in this bao-tokens module at (0,4,1) because the
 * `.btn:not([hidden]):not(.hidden):not(.bao-fab)` re-enabler in the same
 * layer is (0,4,0) and beat the utilities-layer form of this rule outright.
 */
@media (max-width: 47.99rem) {
  [data-editor-tool-rail] fieldset[data-tool-group] > .btn[data-tool="draw-point"],
  [data-editor-tool-rail] fieldset[data-tool-group] > .btn[data-tool="draw-arrow"],
  [data-editor-tool-rail] fieldset[data-tool-group] > .btn[data-tool="draw-ruler"] {
    display: none;
  }
  [data-editor-tool-rail] > .bao-min-w-toolbar-spacer {
    display: none;
  }
}
@media (max-width: 22rem) {
  [data-editor-tool-rail] fieldset[data-tool-group] > .btn[data-tool="draw-volume-brush"],
  [data-editor-tool-rail] fieldset[data-tool-group] > .btn[data-tool="draw-ellipse"] {
    display: none;
  }
}


}
@layer bao-tokens {
@media (max-width: 47.99rem) {
  /*
   * Phone toolbar density: the zones and the save form tighten to the 2xs
   * step so the leading and trailing zones share one 44px row.
   */
  [data-page-type="media"] [data-editor-stage-toolbar],
  [data-page-type="media"] [data-editor-stage-toolbar] [data-toolbar-zone],
  [data-page-type="media"] [data-editor-stage-toolbar] [data-editor-tool-rail],
  [data-page-type="media"] [data-editor-stage-toolbar] .bao-editor-save-bar {
    gap: var(--space-2xs, 0.125rem);
  }
}

}
@layer bao-tokens {

}
@layer bao-tokens {

}
@layer bao-tokens {
@media (min-width: 48rem) and (max-height: 32rem) {
  [data-editor-canvas-region] {
    position: relative;
  }
  [data-editor-canvas-region] > .canvas-container {
    flex: 1 1 auto;
    min-block-size: 0;
    max-block-size: none;
  }
}

}
@layer bao-tokens {
@media (min-width: 48rem) and (max-height: 32rem) {
  [data-editor-document-status] [data-editor-status]:not([data-editor-status="zoom"]):not([data-editor-status="calibration"]):not([data-editor-status="review"]):not([data-editor-status="persistence"]) {
    display: none;
  }
}

}
@layer bao-tokens {
/* enterpriseEditor palette tokens own catalog/header appearance; SearchField owns its control minimum. */

}
@layer bao-tokens {
.bao-editor-3d-stage-label {
  min-inline-size: 0;
  overflow-wrap: anywhere;
}

/* The native command group never wraps; narrow stages keep named glyphs. */
[data-editor-stage-toolbar] .bao-editor-save-bar {
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
  margin-inline-start: 0;
}
@container editor-stage (max-width: 48rem) {
  [data-editor-stage-toolbar] .bao-toolbar-label {
    position: absolute;
    inline-size: 1px;
    block-size: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }
  [data-editor-stage-toolbar] [data-inspector-toggle],
  [data-editor-stage-toolbar] .bao-editor-save-bar button[type="submit"] {
    inline-size: var(--touch-target-min);
    min-inline-size: var(--touch-target-min);
    max-inline-size: var(--touch-target-min);
    padding-inline: 0;
  }
}

/*
 * Toolbar items on glass (Apple HIG toolbars): the plate is the container,
 * so items are borderless glyphs at rest — no tinted tile, no hairline per
 * button. One owner for every editor plate (stage toolbar, floating palette,
 * 3D header, shared viewport controls). The primary verb keeps its accent; a pressed tool
 * keeps the pressed tint (tokens-layout-editor-phone-dimension-label-paint
 * and the declared aria-pressed toolbar styles own those). Measured 2026-08-23 before this: three
 * button treatments shared one row — white outlined squares, tinted soft
 * tiles and a solid primary — which is what made the toolbar read as a
 * collection of widgets rather than one control.
 *
 * Properties, in the bao-tokens layer: daisyUI paints .btn-soft from its own
 * variables but bao-tokens re-declares border-color (0,3,0) and the glass
 * plate re-declares background-color on `.bao-surface-glass-regular .btn-soft`
 * (0,3,0), so the owner has to sit in the same layer at (0,6,0).
 */
[data-primitive="Toolbar"].bao-surface-glass-regular .btn-soft.bao-toolbar-action:not(.btn-primary):not([aria-pressed="true"]):not(.btn-active),
[data-editor-tool-rail] .btn-soft.bao-toolbar-action:not(.btn-primary):not([aria-pressed="true"]):not(.btn-active),
[data-editor-viewport-controls] .btn-soft.bao-toolbar-action:not(.btn-primary):not([aria-pressed="true"]):not(.btn-active) {
  background-color: transparent;
  border-color: transparent;
  box-shadow: none;
  background-image: none;
  color: var(--color-base-content);
}
/* Layer names wrap within their selectable row. The list is the stable
 * owner: inspector content can move from the stage to the session rail. */
[data-layers-list] [data-layer-select]:not([hidden]) {
  justify-content: flex-start;
  text-align: start;
  white-space: normal;
  overflow-wrap: anywhere;
  block-size: auto;
  height: auto;
}

}
@layer bao-tokens {


}
@layer bao-tokens {
/* Context labels, values, and status readouts share one metadata text ramp. */
[data-editor-chrome] [data-editor-document-status] [data-editor-context-bar],
[data-editor-chrome] [data-editor-document-status] [data-editor-context-bar] [data-editor-context-label],
[data-editor-chrome] [data-editor-document-status] [data-editor-context-bar] dd,
[data-editor-chrome] [data-editor-document-status] [data-editor-status-bar] {
  font-size: var(--text-xs, 0.75rem);
  line-height: var(--text-xs--line-height, 1.33333);
  font-weight: var(--font-weight-normal, 400);
}

[data-editor-context-bar] [data-editor-context] dd,
[data-editor-context-bar] [data-editor-context] [data-status-indicator] {
  min-inline-size: 0;
  max-inline-size: 100%;
  flex-wrap: wrap;
  white-space: normal;
  overflow-wrap: anywhere;
}

}
@layer bao-tokens {
.bao-editor-root {
  display: flex;
  flex-direction: column;
}

/* Flex fallback and the primary grid share one workbench geometry owner and cascade layer. */
.bao-editor-workbench {
  position: relative;
  display: flex;
  flex-wrap: wrap;
  min-width: 0;
  max-width: 100%;
  min-height: 0;
  flex: 1 1 auto;
  align-items: stretch;
  gap: var(--space-section);
  padding-block-end: 0;
  overflow-x: hidden;
  overflow-y: hidden;
  overscroll-behavior-y: contain;
  /* Compact chrome queries the workbench independently of the stage column. */
  container-type: inline-size;
  container-name: editor-workbench;
}

@supports (display: grid) {
  .bao-editor-root {
    grid-template-rows: [source-start] auto [commands-start] auto [viewport-start] minmax(0, 1fr) [status-start] auto [block-end customizer-size-start] auto [customizer-visibility-start] auto [customizer-feedback-start] auto [layout-end];
    row-gap: 0;
  }
  .bao-editor-root {
    display: grid;
    grid-template-columns: [modes-start] minmax(0, 1fr) [inline-end];
  }
  .bao-editor-root > [data-editor-teaching-source-banner] {
    grid-column: modes-start / inline-end;
    grid-row: source-start / commands-start;
  }

  .bao-editor-root > .bao-editor-workbench {
    grid-column: modes-start / inline-end;
    grid-row: commands-start / status-start;
  }
  /* Embedded annotation inherits the session's containment and named tracks. */
  .bao-editor-query-container:not(.bao-media-session-root *) {
    container-type: inline-size;
    container-name: editor-surface;
  }

  .bao-editor-workbench {
    display: grid;
    /* Closed inspector reserves no column. Opening uses a bounded token track,
     * independent of the selected tab and its intrinsic content width. */
    grid-template-areas: "stage";
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: minmax(0, 1fr);
    padding-block-end: 0;
    overflow: hidden;
  }

  .bao-editor-workbench:where(:has(> [data-editor-canvas-overlays][data-inspector-expanded="true"])) {
    grid-template-areas: "stage inspector";
    grid-template-columns: minmax(0, 1fr) minmax(0, var(--sidebar-expanded, 16rem));
  }

  .bao-editor-workbench > [data-editor-canvas-overlays][data-inspector-expanded="false"] {
    display: none;
  }

  .bao-editor-workbench > [data-editor-canvas-overlays] {
    grid-area: inspector;
    inline-size: 100%;
    min-inline-size: 0;
    max-inline-size: 100%;
    block-size: 100%;
    min-block-size: 0;
    max-block-size: 100%;
  }

  /*
   * Sheet band: one stage track; the inspector becomes a bottom sheet and
   * the palette lies along the stage's block end
   * (tokens-layout-editor-toolbar-container-presentation).
   */
  @container editor-surface (max-width: 48rem) {
    .bao-editor-workbench {
      grid-template-areas: "stage";
      grid-template-columns: minmax(0, 1fr);
      grid-template-rows: minmax(0, 1fr);
      padding-block-end: 0;
      overflow: hidden;
    }

    /* The shared Sheet dialog owns compact Inspector presentation. */
  }
}

/*
 * Rail dock (permanent-rail band, ≥64rem): the inspector lives inside
 * #session-rail (app-shell-session-rail-dock), so the workbench is the
 * stage alone and the shell's trailing rail is the one trailing sidebar —
 * before this the page painted its own 24rem inspector column beside a
 * collapsed 66px rail holding a single toggle (measured 2026-08-23 at
 * 1440x900: two trailing sidebars, one of them empty).
 */
@supports (display: grid) {
  [data-editor-chrome][data-inspector-dock="rail"] .bao-editor-workbench {
    grid-template-areas: "stage";
    grid-template-columns: minmax(0, 1fr);
  }
}
#session-rail [data-editor-canvas-overlays][data-inspector-dock="rail"] {
  grid-area: auto;
  inline-size: 100%;
  min-inline-size: 0;
  max-inline-size: 100%;
  block-size: auto;
  min-block-size: 0;
  max-block-size: none;
  flex: 0 1 auto;
}
  /*
   * One list of captures. The rail's capture section feeds the filmstrip
   * (app-shell-editor-filmstrip reads its rows, hidden or not), so while the
   * filmstrip paints under the stage the rail does not paint the same
   * captures again beside it — measured 2026-08-23 at 1440x900: eighteen
   * tiles under the stage and the same eighteen rows in the rail.
   */
  body:has([data-editor-chrome][data-annotation-ready="true"] [data-editor-filmstrip]:not([hidden])) #session-rail [data-session-section="captures"] {
    display: none;
  }
  /*
   * Acquire mode has no stage: the docked inspector (AI review, layers, …)
   * describes an image that is not being annotated — measured 2026-08-23 at
   * 1440x900 the rail opened on "AI review · Loading models…" above the
   * capture controls. Only annotate paints it.
   */
  body:has([data-page="capture"][data-session-mode="acquire"]) #session-rail [data-editor-canvas-overlays][data-inspector-dock="rail"] {
    display: none;
  }
  /* The inspector docked in the rail is rail content: no framed card inside the rail plate. */
  #session-rail [data-editor-canvas-overlays][data-inspector-dock="rail"] [data-editor-inspector-browser] {
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }
  /* The spatial summary pill only exists once it has a sentence; an empty
     live region painted as a bare grey bar under "Add point" (2026-08-23). */
  [data-editor-spatial-summary]:empty {
    display: none;
  }

/* One physical right rail owns annotation context at the lg shell band. */
@media (min-width: 64rem) {
  .bao-shell-drawer > .drawer-content > .relative {
    flex-direction: row;
  }
  .bao-shell-drawer > .drawer-content > .relative > [data-shell-scroll="main"] {
    flex: 1 1 0%;
    inline-size: auto;
    max-inline-size: none;
  }
}

/* Rail-docked disclosure delegation lives with the inspector utilities (tokens-utilities-part-2). */

/*
 * The rail's own in-flow geometry used to be declared here, from
 * `min-width: 64rem`. It now lives with its one owner,
 * tokens-glass-shell-drawer-part-b, at `min-width: 80rem`:
 * `MEDIA_QUERY_PERMANENT_RAIL` (app-shell-media-queries) is 80rem, that
 * module hides the rail below 79.99rem, and capture only surrenders its
 * in-page session controls at 80rem. Declaring `display` for the same
 * selector from a second module let source order decide the winner, and the
 * 64rem band then painted a rail the rest of the stack believed was hidden.
 */



/* Embedded annotation forwards the session tracks in the same layer as its standalone grid. */
@supports (grid-template-columns: subgrid) {
  .bao-media-session-panel[data-session-panel="annotate"] [data-editor-chrome] {
    grid-template-columns: subgrid;
    grid-template-rows: subgrid;
  }
  .bao-media-session-panel [data-editor-chrome]:not([data-canvas-maximized="true"]) [data-editor-stage-toolbar] {
    margin-block: var(--space-micro);
    margin-inline-end: var(--space-micro);
    margin-inline-start: calc(2 * var(--touch-target-min) + 2 * var(--space-inline) + 6 * var(--space-micro) + 2 * var(--border));
    max-inline-size: calc(100% - (2 * var(--touch-target-min) + 2 * var(--space-inline) + 7 * var(--space-micro) + 2 * var(--border)));
  }
}

}
@layer bao-tokens {
@container editor-workbench (max-width: 48rem) {
  .bao-editor-workbench {
    position: relative;
    overflow: hidden;
  }
  .bao-editor-workbench > [data-editor-canvas-overlays] {
    display: none;
  }
  [data-editor-filmstrip-list] a {
    scroll-margin-block-end: calc(var(--editor-stage-chrome-block-size, 8rem) + var(--editor-stage-chrome-block-size-extra, var(--space-micro, 0.25rem)));
  }
}

/* The canonical Sheet owns viewport placement and sizing; the same Inspector keeps its native destination control. */
#editor-inspector-sheet [data-editor-inspector-navigation] {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-local);
}


}
@layer bao-tokens {
/*
 * The canvas rail is a compact, icon-first tool palette. Tool titles and
 * accessible names provide discovery without turning the stage into a text
 * column; the complete, labeled catalog remains behind More tools.
 */
.bao-editor-root {
  --editor-palette-gutter: calc(var(--touch-target-min, 2.75rem) + 3 * var(--space-micro, 0.25rem));
}
/* Rail geometry and label density belong to editor-toolbar-container-presentation. */

}
@layer bao-tokens {

}
@layer bao-tokens {
/* A saved label is meaningful only after the actual annotation document hydrates. */
[data-editor-chrome]:not([data-annotation-ready="true"]) [data-editor-document-status] {
  display: none;
}

/* One stage owns alternate renderer placement, suggestions and the collapsed 3D header. */
.bao-editor-workbench > [data-editor-stage]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]) {
  display: flex;
  min-inline-size: min(100%, var(--editor-canvas-basis));
  max-inline-size: 100%;
  block-size: 100%;
  min-block-size: 0;
  max-block-size: 100%;
  flex: 1 1 var(--editor-canvas-basis);
  flex-direction: column;
  gap: var(--space-inline);
}

[data-editor-chrome][data-editor-view-mode="2d"] [data-editor-stage] > [data-editor-3d-viewport] {
  display: none;
}
[data-editor-chrome][data-editor-view-mode="3d"]:not([data-editor-3d-collapsed="true"]) [data-editor-stage] > [data-editor-canvas-region] {
  display: none;
}

@supports (display: grid) {
  .bao-editor-workbench > [data-editor-stage]:not([hidden]):not([data-dashboard-panel-visibility="hidden"]) {
    grid-area: stage;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: [suggestions] max-content [viewport] minmax(0, 1fr) [collapsed] max-content;
    inline-size: 100%;
    min-inline-size: 0;
    max-inline-size: none;
    block-size: 100%;
    min-block-size: 0;
    max-block-size: 100%;
    column-gap: var(--space-inline);
    row-gap: 0;
    flex: 1 1 var(--editor-canvas-basis);
  }
  [data-editor-stage] > [data-editor-stage-toolbar] {
    grid-column: 1 / -1;
    grid-row: viewport;
    justify-self: start;
    align-self: start;
    z-index: var(--z-canvas-overlay);
  }
  [data-editor-stage] > [data-editor-canvas-region],
  [data-editor-stage] > [data-editor-3d-viewport] {
    grid-column: 1;
    grid-row: viewport;
  }
  /* Document facts remain below the measured toolbar inside the viewport. */
  [data-editor-stage] > [data-editor-document-status] {
    grid-column: 1 / -1;
    grid-row: viewport;
    align-self: start;
    justify-self: start;
    z-index: var(--z-canvas-overlay);
    margin: calc(var(--editor-stage-toolbar-block-size, var(--touch-target-min)) + var(--space-inline)) var(--space-inline) var(--space-inline);
    max-inline-size: calc(100% - 2 * var(--space-inline));
    max-block-size: calc(100% - var(--editor-stage-toolbar-block-size, var(--touch-target-min)) - max(var(--editor-stage-chrome-block-size, 0px), var(--editor-viewport-controls-clearance)) - 2 * var(--space-inline));
    overflow: hidden;
  }
  [data-editor-stage] > [data-ai-suggestion-layer] {
    grid-column: 1 / -1;
    grid-row: suggestions;
  }
  [data-editor-stage] > [data-editor-filmstrip-disclosure] > [data-editor-filmstrip] {
    grid-column: 1 / -1;
    grid-row: viewport;
    align-self: end;
    justify-self: start;
    z-index: var(--z-canvas-overlay);
    max-inline-size: 100%;
    margin: 0;
  }
  [data-editor-chrome][data-editor-view-mode="dual"] [data-editor-stage] {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  [data-editor-chrome][data-editor-view-mode="dual"] [data-editor-stage] > [data-editor-canvas-region],
  [data-editor-chrome][data-editor-view-mode="dual"] [data-editor-stage] > [data-editor-3d-viewport] {
    grid-column: auto;
  }
}

/* Each physical viewport owns its engine bounds and overlay clipping directly. */
.bao-editor-canvas,
.bao-editor-3d-viewport {
  position: relative;
  display: flex;
  flex-direction: column;
  inline-size: 100%;
  min-inline-size: 0;
  max-inline-size: 100%;
  block-size: 100%;
  min-block-size: 0;
  max-block-size: 100%;
  flex: 1 1 0%;
}
.bao-editor-canvas {
  overflow: hidden;
}
.bao-editor-3d-viewport {
  overflow: clip;
}
.bao-editor-canvas-host-bounded {
  min-block-size: 0;
  max-block-size: var(--editor-canvas-host-max-height, 100%);
  overflow: hidden;
}
[data-editor-canvas-region] > .canvas-container {
  flex: 1 1 auto;
  min-block-size: 0;
  inline-size: 100%;
}

@container editor-workbench (max-width: 48rem) {
  [data-editor-chrome][data-editor-view-mode="3d"][data-annotation-ready="true"][data-editor-3d-collapsed="true"] [data-editor-stage] > [data-editor-canvas-region] {
    display: flex;
    order: 0;
    flex: 1 1 0;
  }
  [data-editor-stage] > [data-editor-3d-viewport][data-editor-3d-collapsed="true"] {
    order: 1;
    grid-row: collapsed;
    margin-block-start: var(--space-inline);
    min-block-size: 0;
    block-size: auto;
    max-block-size: none;
    flex: 0 0 auto;
    align-self: stretch;
  }
  [data-editor-3d-viewport][data-editor-3d-collapsed="true"] > [data-editor-3d-status] {
    position: relative;
  }
  [data-editor-3d-viewport][data-editor-3d-collapsed="true"] > canvas,
  [data-editor-3d-viewport][data-editor-3d-collapsed="true"] > [data-editor-3d-controls] {
    display: none;
  }
}

}
@layer bao-tokens {
.bao-editor-stage {
  container-type: inline-size;
  container-name: editor-stage;
}

/* Keyboard hints stay available to assistive technology without crowding the shared toolbar. */
@container editor-stage (min-width: 40.01rem) {
  html #editor-tool-dock[data-editor-tool-rail] .bao-toolbar-action.btn-square [data-hig-key-hint],
html #editor-tool-dock-3d[data-editor-tool-rail] .bao-toolbar-action.btn-square [data-hig-key-hint],
html [data-editor-tool-rail] .bao-toolbar-action.btn-square [data-hig-key-hint] {
    
    position: absolute;
    inline-size: 0;
    block-size: 0;
    max-inline-size: 0;
    margin-inline-start: 0;
    padding: 0;
    border-width: 0;
    overflow: hidden;
    white-space: nowrap;
    opacity: 0;
  }
}

}
@layer bao-tokens {
/* Canvas work keeps the header quiet and preserves search through its command trigger. */
@media (min-width: 64rem) {
  body:has([data-editor-chrome]) .bao-shell-topbar [data-topbar-search] {
    display: none;
  }

  body:has([data-editor-chrome]) .bao-shell-topbar .navbar-end .bao-shell-topbar-actions [data-command-palette-trigger].btn {
    display: inline-flex;
  }

}

}
@layer bao-tokens {
/* Rail presentation owns responsive geometry; generic toolbars exclude this surface. */
[data-editor-tool-rail] {
  display: flex;
}

}
@layer bao-tokens {
/* Final icon-rail density; workbench grid owns inspector tracks. */
body:has([data-editor-chrome][data-inspector-dock=rail]) #session-rail {
  --session-rail-expanded: var(--sidebar-expanded);
}
/* Rail geometry and label density belong to editor-toolbar-container-presentation. */

}
@layer bao-tokens {
/* Review is an inspector action. It remains reachable on every workbench size. */
[data-editor-inspector-panel="review"] [data-review-mode-toggle] {
  display: inline-flex;
}

/* Focus scrolling must use the final native disclosure extent. Its content
 * pseudo-element transitions height independently of the outer grid, and
 * the content animation can continue after a newly focused control scrolls.
 * Cancel both while keyboard focus is within the disclosure; preserve
 * native open/closed semantics and the inspector tab strip scroll owner. */
[data-editor-inspector-panel] details.collapse:focus-within,
[data-editor-inspector-panel] details.collapse:focus-within::details-content,
[data-editor-inspector-panel] details.collapse:focus-within > .collapse-content {
  transition: none;
  animation: none;
}
[data-annotation-history-list] {
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
}
[data-annotation-history-list] > li {
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
}

}
@layer bao-tokens {
/* An empty annotation stage exposes only recovery actions, never inert editor chrome. */
[data-editor-chrome][data-annotation-ready="false"] [data-editor-tool-rail],
[data-editor-chrome][data-annotation-ready="false"] [data-editor-stage-toolbar] > [data-toolbar-region="commands"] {
  display: none;
}

/* Recovery text retains its intrinsic height at large text sizes. Safe centering
 * yields to a start-aligned scrollport when the canvas cannot hold the content. */
[data-primitive="EmptyState"][data-empty-state-presentation="stage"] {
  justify-content: flex-start;
  justify-content: safe center;
  padding-block: var(--space-page);
}
[data-primitive="EmptyState"][data-empty-state-presentation="stage"] > * {
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow-wrap: anywhere;
}
[data-primitive="EmptyState"][data-empty-state-presentation="stage"] > fieldset > .btn {
  min-inline-size: 0;
  max-inline-size: 100%;
  block-size: auto;
  white-space: normal;
  overflow-wrap: anywhere;
}

}
@layer bao-tokens {
/* Apple HIG control ladder + pointer-adaptive chrome (hig-canon.json). */
.bao-shell-topbar.navbar::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: var(--scroll-edge-fade, 1.5rem);
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    color-mix(in oklab, var(--color-base-100) 0%, transparent),
    color-mix(in oklab, var(--color-base-100) 55%, transparent)
  );
  opacity: var(--opacity-strong);
}

.bao-shell-topbar.navbar {
  position: sticky;
  border-block-end-width: 0;
}

/*
 * Pointer-adaptive row height, floored at the product's 44pt target. The
 * fine-pointer rung alone resolves to 1.75rem, and the rendered-geometry audit
 * read every sidebar link on every page as a 222x28 sub-floor control. HIG
 * permits a 28px row for a precise pointer; this product does not, because the
 * same markup ships to touch through Tauri. The floor wins. Glyph size still
 * adapts, on the control, from the type scale.
 */
.bao-shell-sidebar .bao-nav-item {
  min-height: var(--touch-target-min);
}

.bao-shell-sidebar .bao-nav-item > svg {
  inline-size: var(--text-base, 1rem);
  block-size: var(--text-base, 1rem);
  color: var(--color-primary);
}

@media (pointer: fine) {
  .bao-shell-sidebar .bao-nav-item {
    min-height: var(--touch-target-min);
  }

  .bao-shell-sidebar .bao-nav-item > svg {
    inline-size: var(--text-sm, 0.875rem);
    block-size: var(--text-sm, 0.875rem);
  }
}

@media (pointer: coarse) {
  .bao-shell-sidebar .bao-nav-item {
    min-height: var(--touch-target-min);
    background-color: transparent;
    transform: none;
  }

  .bao-shell-sidebar .bao-nav-item > svg {
    inline-size: var(--text-lg, 1.125rem);
    block-size: var(--text-lg, 1.125rem);
  }
}

.bao-shell-sidebar .bao-nav-item.menu-active > svg,
.bao-shell-sidebar .bao-nav-item[aria-current="page"] > svg {
  color: var(--color-primary);
}

.bao-shell-drawer::before {
  content: "";
  position: absolute;
  inset-block: 0;
  inset-inline-end: -1.5rem;
  inline-size: 1.5rem;
  pointer-events: none;
  background: linear-gradient(
    to inline-end,
    color-mix(in oklab, var(--color-base-200) 40%, transparent),
    transparent
  );
}


.bao-editor-inspector-divider {
  inline-size: var(--pane-divider, 1px);
  background: color-mix(in oklab, var(--color-base-content) 18%, transparent);
  cursor: col-resize;
  touch-action: none;
}

[data-hig-key-hint] {
  font-family: var(--font-mono);
  font-size: var(--text-2xs);
  line-height: 1;
  padding-inline: var(--space-micro, 0.25rem);
  padding-block: var(--space-2xs, 0.125rem);
  border-radius: var(--radius-field);
  border: 1px solid color-mix(in oklab, var(--color-base-content) 20%, transparent);
  background: var(--color-base-200);
  color: var(--color-base-content);
}

/*
 * Command-palette rows are keyboard-first on fine pointers, but phone users
 * tap them. Floor the hit area at the product's 44pt target on touch only;
 * fine-pointer density keeps its compact keyboard-first row height.
 */
@media (pointer: coarse) {
  .bao-shell-list-row {
    min-height: var(--touch-target-min, 2.75rem);
  }
}

}
@layer bao-tokens {
@layer components {
  .bao-page-canvas {
    background-color: var(--color-base-200);
  }
  .bao-surface-solid {
    background-color: var(--color-base-100);
  }
  .bao-admin-metric-grid {
    display: grid;
    min-width: 0;
    gap: var(--space-inline);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-choice-min)), 1fr));
  }
  .bao-admin-content-grid {
    display: grid;
    min-width: 0;
    gap: var(--space-section);
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--grid-panel-half-min)), 1fr));
  }
  .bao-training-page-layout {
    display: flex;
    min-width: 0;
    flex-wrap: wrap;
    gap: var(--space-section);
    align-items: flex-start;
  }
  .bao-training-workspace-column { flex: 2 1 var(--training-workspace-basis); min-width: 0; }
  .bao-training-context-column { flex: 1 1 var(--training-context-basis); min-width: 0; }
}

@layer utilities {
  .bao-stagger-1 { animation-delay: calc(var(--stagger-step) * 2); }
  .bao-stagger-2 { animation-delay: calc(var(--stagger-step) * 4); }
  .bao-stagger-3 { animation-delay: calc(var(--stagger-step) * 6); }
  .bao-stagger-4 { animation-delay: calc(var(--stagger-step) * 8); }
  .bao-stagger-5 { animation-delay: calc(var(--stagger-step) * 10); }
  .scrollbar-gutter-stable { scrollbar-gutter: stable; }
  .safe-area-pt-shell { padding-block-start: env(safe-area-inset-top, 0px); }
  .bao-table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }
  [data-bulk-action-bar][hidden] { display: none; }
  .bao-scroll-x-snap {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x proximity;
    scrollbar-width: thin;
    scrollbar-gutter: stable;
  }
  .bao-scroll-x-snap > * { scroll-snap-align: start; }
  @media (prefers-reduced-motion: reduce) {
    .bao-stagger-1, .bao-stagger-2, .bao-stagger-3, .bao-stagger-4, .bao-stagger-5 { animation-delay: var(--duration-instant);
    }
    .bao-scroll-x-snap { scroll-snap-type: none; }
  }
}

}
@layer bao-tokens {
/* GENERATED FROM resources/bao/styles.bao#style.blocks.admin-layout.css — DO NOT EDIT */
/* Distinct admin domain geometry and semantic states; shared shell, markers,
   disclosure visibility and chat-panel geometry remain with their canonical owners. */
:root {
  /* Fluid collection tracks and distinct domain splits are authored here.
     All consumers bind these public recipes; no hand stylesheet duplicates them. */
  --bao-grid-track-5-fluid: repeat(auto-fit, minmax(min(5rem, 100%), 1fr));
  --bao-grid-track-8-fluid: repeat(auto-fit, minmax(min(8rem, 100%), 1fr));
  --bao-grid-track-10-fluid: repeat(auto-fit, minmax(min(var(--grid-context-min), 100%), 1fr));
  --bao-grid-track-12-fluid: repeat(auto-fit, minmax(min(var(--grid-panel-quarter-min), 100%), 1fr));
  --bao-grid-track-14-fluid: repeat(auto-fit, minmax(min(var(--grid-choice-min), 100%), 1fr));
  --bao-grid-track-16-fluid: repeat(auto-fit, minmax(min(var(--grid-panel-third-min), 100%), 1fr));
  /* A semantic stack has one flexible track; it is not a collection recipe. */
  --bao-grid-track-stack: minmax(0, 1fr);
  --bao-grid-kpi-bento: repeat(auto-fit, minmax(min(100%, var(--grid-panel-quarter-min)), 1fr));
  --bao-grid-panel-2-1: minmax(0, 2fr) minmax(22rem, 1fr);
  --bao-grid-panel-14-1: minmax(0, 1.4fr) minmax(22rem, 1fr);
  --bao-grid-panel-125-095: minmax(0, 1.25fr) minmax(20rem, 0.95fr);
  --bao-grid-panel-09-135: minmax(var(--grid-track-min), 0.9fr) minmax(0, 1.35fr);
  --bao-grid-workspace-3: minmax(var(--grid-choice-min), 0.75fr) minmax(0, 1.25fr) minmax(var(--grid-choice-min), 1fr);
  --bao-grid-profile-11-09: minmax(0, 1.1fr) minmax(0, 0.9fr);
  --bao-grid-control-min-12: min(var(--grid-panel-quarter-min), 100%);
  --bao-grid-sidebar-width: var(--sidebar-expanded);
  --bao-grid-sidebar-fluid: min(var(--sidebar-expanded), 100%);
  --bao-grid-split-09-1: minmax(0, 0.9fr) minmax(20rem, 1fr);
  --bao-grid-split-content-20: minmax(0, 1fr) 20rem;
  --bao-grid-split-15-18: minmax(0, 1.5fr) minmax(var(--grid-track-min), 0.8fr);
  --bao-grid-split-115-22: minmax(0, 1.15fr) minmax(22rem, 0.85fr);
  --bao-grid-split-22-1-24: 22rem minmax(0, 1fr) var(--grid-panel-half-min);
  --bao-grid-split-catalog: var(--grid-choice-min) minmax(0, 1fr);
  --bao-grid-split-2-16: minmax(0, 2fr) minmax(var(--grid-panel-third-min), 1fr);
  --bao-grid-split-chat-rail: minmax(var(--grid-panel-third-min), 0.9fr) minmax(0, 2.5fr);
  --bao-grid-split-chat-thread: minmax(0, 1.75fr) minmax(var(--grid-choice-min), 0.7fr);
  --bao-grid-split-admin-form: minmax(0, 1fr) var(--grid-choice-min) var(--grid-panel-quarter-min) auto;
  --bao-grid-split-equal: minmax(0, 1fr) minmax(0, 1fr);
  --bao-grid-split-12-08: minmax(0, 1.2fr) minmax(0, 0.8fr);
  --bao-grid-split-1-auto: minmax(0, 1fr) auto;
  --bao-grid-split-12-20-1: minmax(var(--grid-panel-quarter-min), 20rem) minmax(0, 1fr);
  --bao-grid-split-18-1: var(--grid-track-min) minmax(0, 1fr);
  --bao-grid-split-1-22: minmax(0, 1fr) minmax(22rem, 1fr);
  --bao-grid-split-14-22: minmax(0, 1.4fr) minmax(22rem, 1fr);
  --bao-grid-split-12-22-09: minmax(0, 1.2fr) minmax(22rem, 0.9fr);
  --bao-grid-split-11-22-09: minmax(0, 1.1fr) minmax(22rem, 0.9fr);
  --bao-grid-split-12-18-08: minmax(0, 1.2fr) minmax(var(--grid-track-min), 0.8fr);
  --bao-grid-split-115-18-085: minmax(0, 1.15fr) minmax(var(--grid-track-min), 0.85fr);
  --bao-grid-split-14-18-09: minmax(0, 1.4fr) minmax(var(--grid-track-min), 0.9fr);
  --bao-grid-split-145-18-085: minmax(0, 1.45fr) minmax(var(--grid-track-min), 0.85fr);
  --bao-grid-split-13-07: minmax(0, 1.3fr) minmax(0, 0.7fr);
  --bao-grid-split-3col-equal: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1.15fr);
  /* The registry primary track keeps useful content space at the affordable source band. */
  --bao-grid-split-3col-shell: minmax(var(--grid-track-min), 22rem) minmax(var(--grid-panel-half-min), 1.35fr) minmax(20rem, var(--grid-panel-half-min));

  /* ═══════════════════════════════════════════════════════════════════════════
     PAGE LAYOUT TOKENS
     ═══════════════════════════════════════════════════════════════════════════ */
  --page-gutter-block-compact: clamp(1rem, 2.5vw, 2.5rem);
  --page-section-gap-compact: clamp(0.75rem, 1.5vw, 1.5rem);
  --page-card-gap: clamp(0.75rem, 1.5vw, 1.5rem);
  --page-grid-min: clamp(14rem, 22vw, 20rem);
  --page-content-max: 96rem;
  --page-content-max-wide: 120rem;
  --page-content-min-height-offset: clamp(6rem, 8vh, 10rem);
  --bao-viewport-height: 100vh;

  /* ═══════════════════════════════════════════════════════════════════════════
     SIDEBAR / NAVIGATION TOKENS
     ═══════════════════════════════════════════════════════════════════════════ */

  /* Chat bubble FAB — fixed anchor + main scroll reserve (enterprise overlap lane) */
  --chat-fab-control-height: 3rem;
  --chat-fab-control-min-inline: 4rem;
  --chat-fab-inline-inset: max(1.5rem, env(safe-area-inset-right, 0px));
  --chat-fab-block-inset: calc(
    var(--dock-height) +
    var(--chat-fab-control-height) +
    1.5rem +
    env(safe-area-inset-bottom, 0px)
  );
  --chat-fab-main-reserve: calc(
    var(--chat-fab-block-inset) +
    var(--chat-fab-control-height) +
    1.5rem +
    env(safe-area-inset-bottom, 0px)
  );
  --bao-chat-panel-open-reserve: calc(var(--chat-panel-inline-size) + var(--space-xl));
  --bao-chat-composer-input-min: 12rem;

  /* Topbar / Header */
  --topbar-height: 4rem; /* 64px */
  --bao-topbar-height-compact: 3.5rem; /* 56px */
  --bao-topbar-search-min: 14rem;
  --bao-topbar-search-max: 32rem;
  --bao-topbar-status-max: 24rem;
  --bao-agent-topbar-min-primary: 11rem;
  --bao-agent-topbar-project-max: 22rem;
  --bao-agent-topbar-actions-min: 9rem;
  --bao-agent-topbar-status-compact-max: 50vw;
  --bao-agent-chat-content-max: 48rem;
  --bao-agent-settings-modal-max: 56rem;
  --bao-agent-settings-form-offset: 7rem;
  --bao-agent-command-palette-results-max: 60vh;

  /* ═══════════════════════════════════════════════════════════════════════════
     COMPONENT SIZE TOKENS
     ═══════════════════════════════════════════════════════════════════════════ */
  --bao-panel-width-compact: 18rem; /* 288px */
  --bao-panel-width-medium: 18.75rem; /* 300px */
  --bao-panel-width-wide: 20rem; /* 320px */
  --bao-panel-width-large: 21rem; /* 336px */
  --bao-panel-width-xl: 24rem; /* 384px */
  --bao-panel-width-2xl: 23rem; /* 368px */
  --bao-panel-width-narrow: 16rem;
  --bao-dropdown-width-sm: 12rem; /* 192px */
  --bao-dropdown-width-md: 14rem; /* 224px */
  --bao-dropdown-width-lg: 16rem; /* 256px */
  --bao-dropdown-width-xl: 20rem; /* 320px */
  --bao-dropdown-width-notification: 21rem; /* 336px */
  --bao-menu-width-2xs: 9rem; /* 144px */
  --bao-menu-width-xs: 10rem; /* 160px */
  --bao-menu-width-sm: 11rem; /* 176px */
  --bao-menu-width-md: 13.5rem; /* 216px */
  --bao-menu-width-lg: 14rem; /* 224px */
  --bao-menu-width-xl: 15rem; /* 240px */
  --bao-menu-width-2xl: 17rem; /* 272px */
  --bao-menu-width-3xl: 18rem; /* 288px */
  --bao-control-width-sm: 6rem; /* 96px */
  --bao-control-width-md: 7rem; /* 112px */
  --bao-control-width-lg: 14rem; /* 224px */
  --bao-control-width-compact: 10rem; /* 160px */
  --bao-table-col-min: 14rem;
  --bao-textarea-min-height-xxs: 3rem; /* 48px */
  --bao-textarea-min-height-compact: calc(var(--space-page) * 5); /* 80px */
  --bao-textarea-min-height-xs: calc(var(--space-page) * 6); /* 96px */
  --bao-textarea-min-height-sm: 6.875rem; /* 110px */
  --bao-textarea-min-height-md: 7.5rem; /* 120px */
  --bao-textarea-min-height-lg: calc(var(--space-page) * 8); /* 128px */
  --bao-textarea-min-height-xl: 18.75rem; /* 300px */
  --bao-textarea-max-height: calc(var(--space-page) * 12); /* 192px */
  --bao-media-min-height: 13.75rem; /* 220px */
  --bao-media-max-height: 20rem; /* 320px */
  --bao-viewer-min-height: 60vh;
  --bao-viewer-min-height-lg: 70vh;
  --bao-control-min-width: 7.5rem; /* 120px */
  --bao-code-panel-max-height: 31.25rem; /* 500px */
  --bao-model-id-max-width: 9.375rem; /* 150px */
  --bao-demo-sidebar-min-height: 85vh;
  --bao-grid-min-height-bento: 35rem; /* 560px */
  --bao-chat-drawer-offset: 12.5rem; /* 200px */
  --bao-ai-history-offset: 13.75rem; /* 220px */
  --bao-xr-workspace-offset: calc(var(--space-page) * 8); /* 8rem */
  --bao-chat-drawer-height: calc(var(--bao-viewport-height) - var(--bao-chat-drawer-offset));
  --bao-ai-history-height: calc(var(--bao-viewport-height) - var(--bao-ai-history-offset));
  --bao-xr-workspace-height: calc(var(--bao-viewport-height) - var(--bao-xr-workspace-offset));
  --bao-imaging-workspace-min-height: 70dvh;
  --bao-imaging-stage-min-height: 55dvh;
  --bao-imaging-stage-skeleton-height: 40dvh;
  --bao-ai-panel-max-height: 60dvh;
  --bao-panel-max-height-xs: calc(var(--space-page) * 8); /* 128px */
  --bao-panel-max-height-sm: calc(var(--space-page) * 10); /* 160px */
  --bao-panel-max-height-base: calc(var(--space-page) * 12); /* 192px */
  --bao-panel-max-height-md: calc(var(--space-page) * 14); /* 224px */
  --bao-panel-max-height-lg: calc(var(--space-page) * 16); /* 256px */
  --bao-panel-max-height-compact: 11rem; /* 176px */
  --bao-panel-max-height-xl: 18rem; /* 288px */
  --bao-panel-max-height-2xl: 20rem; /* 320px */
  --bao-panel-max-height-3xl: 24rem; /* 384px */
  --bao-landing-orb-size-lg: 18rem; /* 288px */
  --bao-landing-orb-size-xl: 20rem; /* 320px */
  --bao-landing-orb-size-2xl: 16rem; /* 256px */
  --bao-icon-inline-size: 1em;
  --bao-skeleton-line-short: 50%;
  --bao-skeleton-line-medium: 66%;
  --bao-skeleton-line-long: 75%;
  --bao-skeleton-line-height: 1rem;
  --bao-skeleton-line-height-sm: 0.75rem;
  --bao-skeleton-row-height: 3rem;
  --bao-skeleton-row-height-dense: calc(var(--space-page) * 2.5);
  --bao-skeleton-line-title: calc(var(--space-page) * 7);
  --bao-skeleton-line-subtitle: calc(var(--space-page) * 5);
  --bao-skeleton-avatar-size: 3rem;
  --bao-skeleton-card-image-height-compact: calc(var(--space-page) * 8);
  --bao-skeleton-card-image-height: 8rem;
  --bao-skeleton-card-image-height-expanded: calc(var(--space-page) * 12);
  --bao-skeleton-card-image-side-width: calc(var(--space-page) * 8);
  --bao-skeleton-table-cell-padding: 0.75rem;
  --bao-skeleton-table-col-wide: calc(var(--space-page) * 8);
  --bao-skeleton-table-col-narrow: calc(var(--space-page) * 4);
  --bao-skeleton-list-icon-size: calc(var(--space-page) * 2.5);
  --bao-skeleton-list-action-size: 1.5rem;
  --bao-status-indicator-size: 0.375rem;
  --bao-empty-state-size-sm: calc(var(--space-page) * 4);
  --bao-empty-state-size-md: calc(var(--space-page) * 5);
  --bao-empty-state-size-lg: calc(var(--space-page) * 6);
  --bao-empty-state-size-xl: calc(var(--space-page) * 8);
  --bao-empty-state-padding-sm: 1.5rem;
  --bao-empty-state-padding-md: 2rem;
  --bao-empty-state-padding-lg: 3rem;
  --bao-empty-state-padding-xl: calc(var(--space-page) * 4);
  --bao-chart-apex-height: 23.75rem; /* 380px */
  --bao-chart-apex-height-md: 21.875rem; /* 350px */
  --bao-chart-apex-height-compact: 11.875rem; /* 190px */
  --bao-chart-apex-height-mini: 7.5rem; /* 120px */
  --bao-chart-radial-height: calc(calc(var(--space-page) * 16) + var(--space-2xs));
  --bao-chart-radial-offset-y: calc(var(--space-lg) * -1);
  --bao-chart-radial-track-margin: 0.5rem;
  --bao-chart-radial-track-blur: 0.25rem;
  --bao-chart-radial-start-angle: -90;
  --bao-chart-radial-end-angle: 90;
  --bao-chart-radial-track-stroke-width: 75%;
  --bao-chart-radial-value-offset-y: calc(var(--space-2xs) * -1);
  --bao-chart-radial-grid-padding-top: calc(calc(var(--space-micro) * 2.5) * -1);
  --bao-chart-radial-value-font-size: 1.5rem;
  --bao-datepicker-today-dot-size: 0.3125rem;
  --bao-scrollbar-thumb-offset: 0.1875rem;
  --bao-scrollbar-track-width: 0.375rem;
  --bao-skip-link-hidden-offset: -9999px;
  --bao-skip-link-hidden-translate: -100%;
  
  --bao-skip-link-padding-y: 0.75rem;
  --bao-skip-link-padding-x: 1.5rem;
  --bao-skip-link-focus-top: 1rem;
  --bao-skip-link-outline-width: 2px;
  --bao-skip-link-outline-offset: 2px;
  --bao-timeline-offset: 100%;
  --bao-blur-strong: 160px;
  --bao-blur-stronger: 180px;
  --bao-gradient-stop-soft: 80%;
}

@supports (height: 100dvh) {
  :root {
    --bao-viewport-height: 100dvh;
  }
}

/* Topbar styles */
.app-topbar {
  height: var(--topbar-height);
  min-height: var(--topbar-height);
}

.bao-global-topbar {
  min-height: var(--topbar-height);
  display: grid;
  grid-template-columns:
    minmax(0, 1fr)
    minmax(var(--bao-topbar-search-min), min(42vw, var(--bao-topbar-search-max)))
    minmax(0, auto);
  grid-template-areas: "context search end";
  align-items: center;
}

.bao-global-topbar > :where(.navbar-start, .navbar-center, .navbar-end) {
  width: auto;
  min-width: 0;
}

.bao-global-topbar-context {
  grid-area: context;
  justify-content: flex-start;
}

.bao-global-topbar-search {
  grid-area: search;
  justify-content: center;
}

.bao-global-topbar-search > * {
  width: min(100%, var(--bao-topbar-search-max));
}

.bao-global-topbar-end {
  grid-area: end;
  justify-content: flex-end;
}

.bao-global-topbar-status,
.bao-global-topbar-actions {
  display: flex;
  align-items: center;
  justify-content: flex-end;
}

.bao-global-topbar-status {
  max-width: var(--bao-topbar-status-max);
  gap: var(--space-inline);
}

.bao-global-topbar-actions {
  gap: var(--space-micro);
}

.bao-global-topbar-end :where(.btn, .dropdown, .swap) {
  flex: 0 0 auto;
}

@media (max-width: 64rem) {
  .bao-global-topbar {
    grid-template-columns: auto minmax(0, 1fr) auto;
    column-gap: var(--space-inline);
    min-height: var(--bao-topbar-height-compact);
  }

  .bao-global-topbar-search {
    justify-content: stretch;
    padding-inline: 0;
  }

  .bao-global-topbar-search > * {
    width: 100%;
  }

  .bao-global-topbar-end {
    justify-self: end;
  }

  .bao-global-topbar-status {
    max-width: min(var(--bao-topbar-status-max), 44vw);
  }
}

@media (max-width: 40rem) {
  .bao-global-topbar {
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-areas:
      "context end"
      "search search";
    row-gap: var(--space-inline);
    padding-block: var(--space-inline);
  }

  .bao-global-topbar-status {
    max-width: 38vw;
  }
}

/* ──────────────────────────────────────────────────────────────────────────
 * Density scale — projected from `RegistrySessionUiPreferences.density`
 * onto `<body data-bao-ui-density>` by the app-shell. Compact mode tightens
 * vertical rhythm for power-user dashboards; comfortable mode matches the
 * default iOS Settings-grade spacing.
 * ────────────────────────────────────────────────────────────────────── */

:is(html, body)[data-bao-ui-density="compact"] {
  --bao-shell-row-padding-y: 0.25rem;
  --bao-shell-row-padding-x: 0.5rem;
  --bao-shell-card-padding: 0.75rem;
}

:is(html, body)[data-bao-ui-density="comfortable"] {
  --bao-shell-row-padding-y: 0.75rem;
  --bao-shell-row-padding-x: 1rem;
  --bao-shell-card-padding: 1.25rem;
}

:is(html, body)[data-bao-ui-density="spacious"] {
  --bao-shell-row-padding-y: 1.25rem;
  --bao-shell-row-padding-x: 1.5rem;
  --bao-shell-card-padding: 1.75rem;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Session-level reduced-motion override. Mirrors the OS-level media query
 * for users who opt out of animations explicitly in Settings → UI without
 * changing their OS preference.
 * ────────────────────────────────────────────────────────────────────── */

:is(html, body)[data-bao-ui-motion="reduced"] * {
  animation-duration: var(--duration-instant);
  animation-iteration-count: 1;
  animation-name: none;
  scroll-behavior: auto;
  transition-duration: var(--duration-instant);
  transition-property: none;
}

/* ──────────────────────────────────────────────────────────────────────────
 * Hover-reveal affordance — iOS-style deference for secondary actions
 * (edit-pencil, drag-handle, remove). Affordances stay hidden until the
 * pointer enters the row or the row receives keyboard focus, then fade in
 * over the canonical transition. Touch devices keep essential actions visible.
 *
 * Markup contract:
 *   <li data-hover-reveal>
 *     <a>visible label</a>
 *     <button data-hover-reveal-affordance aria-label="Edit">…</button>
 *   </li>
 * ────────────────────────────────────────────────────────────────────── */

[data-hover-reveal] [data-hover-reveal-affordance] {
  opacity: 0;
  transition: opacity var(--duration-fast) var(--easing-standard);
  pointer-events: none;
}

@media (hover: hover) {
  [data-hover-reveal]:hover [data-hover-reveal-affordance],
  [data-hover-reveal]:focus-within [data-hover-reveal-affordance] {
    opacity: 1;
    pointer-events: auto;
  }
}

@media (hover: none) {
  [data-hover-reveal] [data-hover-reveal-affordance] {
    opacity: 1;
    pointer-events: auto;
  }
}

@media (pointer: coarse) {
  [data-hover-reveal] [data-hover-reveal-affordance] {
    opacity: 1;
    pointer-events: auto;
  }
}

[data-dashboard-editing="true"] [data-hover-reveal-affordance] {
  opacity: 1;
  pointer-events: auto;
}

:is(html, body)[data-bao-ui-motion="reduced"] [data-hover-reveal-affordance] {
  transition: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   ENTRANCE ANIMATIONS
   ═══════════════════════════════════════════════════════════════════════════ */

@keyframes bao-fade-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

@keyframes bao-fade-in-up {
  from {
    opacity: 0;
    transform: translateY(var(--space-inline));
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

@keyframes bao-slide-in-right {
  from {
    opacity: 0;
    transform: translateX(var(--space-page));
  }

  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes bao-pulse-subtle {
  0%,
  100% {
    opacity: 1;
  }

  50% {
    opacity: 0.6;
  }
}

@keyframes bao-shimmer {
  from {
    background-position: -200% 0;
  }

  to {
    background-position: 200% 0;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   GLOBAL INTERACTIVE POLISH
   ═══════════════════════════════════════════════════════════════════════════ */

/*
 * Main content entrance — opacity only.
 * `bao-fade-in-up` leaves `transform: translateY(0)` under `both` fill-mode,
 * which makes axe color-contrast report bgOverlap on descendant text.
 */
@media (prefers-reduced-motion: no-preference) {
  :root:not([data-reduced-motion=true]) #main-content > * {
    animation: bao-fade-in var(--duration-slow) var(--easing-entrance) both;
  }

  /* Auth content entrance animation */
  :root:not([data-reduced-motion=true]) #auth-content {
    animation: bao-fade-in var(--duration-slow) var(--easing-entrance) both;
  }
}

.bao-icon-inline-size {
  width: var(--bao-icon-inline-size);
  height: var(--bao-icon-inline-size);
}

.bao-grid-cols-label-value {
  grid-template-columns: max-content 1fr;
}

.bao-grid-cols-auto-fr {
  grid-template-columns: auto 1fr;
}

.bao-grid-cols-fr-auto {
  grid-template-columns: minmax(0, 1fr) auto;
}

@media (min-width: 40rem) {
  .sm\:bao-grid-cols-fr-auto {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

@media (min-width: 40rem) {
  .sm\:bao-grid-cols-label-value {
    grid-template-columns: max-content 1fr;
  }
}

@media (min-width: 48rem) {
  .md\:bao-grid-cols-narrow-wide {
    grid-template-columns: 9rem minmax(0, 1fr);
  }
  .md\:bao-grid-cols-auto-fr-auto {
    grid-template-columns: auto minmax(0, 1fr) auto;
  }
}

@media (min-width: 64rem) {
  .lg\:bao-grid-cols-fr-fr-auto {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) auto;
  }
  .lg\:bao-grid-cols-sidebar-main {
    grid-template-columns: 18rem minmax(0, 1fr);
  }
}

.bao-auto-cols-compact {
  grid-auto-columns: 6rem;
}

.bao-grid-cols-compact-label-value {
  grid-template-columns: minmax(0, 6rem) minmax(0, 1fr);
}

/* ═══════════════════════════════════════════════════════════════════════════
   COMPUTER-USE CANVAS BEHAVIORAL STATES (cursor + overlay opacity)
   ═══════════════════════════════════════════════════════════════════════════ */

[data-bao-computer-use-live-canvas="true"][data-bao-cu-input-state="paused"] {
  cursor: pointer;
}
[data-bao-computer-use-live-canvas="true"][data-bao-cu-input-state="running"] {
  cursor: not-allowed;
}
[data-bao-computer-use-live-canvas="true"][data-bao-cu-input-state="provisioning"] {
  cursor: wait;
}
[data-bao-cu-overlay] {
  opacity: 0;
}
[data-bao-cu-input-state="provisioning"] [data-bao-cu-overlay="provisioning"],
[data-bao-cu-input-state="paused"] [data-bao-cu-overlay="paused"],
[data-bao-cu-input-state="running"] [data-bao-cu-overlay="running"] {
  opacity: 1;
}

.bao-dashboard-panel-dragging {
  opacity: 0.62;
  box-shadow: var(--shadow-lg);
  filter: saturate(0.9);
}

.bao-dashboard-panel-drop-target {
  outline: var(--focus-ring-width) solid
    var(--focus-ring-color);
  outline-offset: var(--focus-ring-offset);
  box-shadow: var(--shadow-md);
}

@media (prefers-reduced-motion: no-preference) {
  .bao-dashboard-panel-dragging,
  .bao-dashboard-panel-drop-target {
    transition-property: opacity, box-shadow, filter, outline-color, outline-offset, transform;
    transition-duration: var(--duration-fast);
    transition-timing-function: var(--easing-entrance);
  }
}

.bao-grid-cols-main-toc {
  grid-template-columns: minmax(0, 1fr) var(--bao-panel-width-compact);
}

.bao-grid-cols-filter-bar {
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--bao-control-width-compact)), 1fr));
}

.bao-form-field-grid-fit {
  inline-size: 100%;
  max-inline-size: 100%;
  min-inline-size: 0;
}

@media (min-width: 64rem) {
  .lg\:bao-grid-cols-main-sidebar {
    grid-template-columns: minmax(0, 1fr) 18rem;
  }
  .lg\:bao-grid-cols-main-narrow {
    grid-template-columns: minmax(0, 1fr) 12rem auto;
  }
}

@media (min-width: 80rem) {
  .xl\:bao-grid-cols-filter-bar {
    grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--bao-control-width-compact)), 1fr));
  }
  .xl\:bao-grid-cols-major-minor {
    grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.95fr);
  }
  .xl\:bao-grid-cols-detail-split {
    grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  }
  .xl\:bao-grid-cols-wide-narrow {
    grid-template-columns: minmax(0, 1.3fr) minmax(0, 0.7fr);
  }
  .xl\:bao-grid-cols-panel-main {
    grid-template-columns: minmax(0, 20rem) 1fr;
  }
  .xl\:bao-grid-cols-panel-wide-main {
    grid-template-columns: minmax(0, 22rem) 1fr;
  }
  .xl\:bao-grid-cols-main-accent {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0.4fr);
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   MOTION UTILITY CLASSES (SSOT — no Tailwind arbitrary tokens)
   ═══════════════════════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: no-preference) {
  .bao-motion-transition-opacity-transform {
    transition-property: opacity, transform;
    transition-duration: var(--duration-fast);
    transition-timing-function: var(--easing-entrance);
  }

  .bao-motion-transition-decoration {
    transition-property: text-decoration-color;
    transition-duration: var(--duration-fast);
    transition-timing-function: var(--easing-entrance);
  }

  .bao-motion-duration-medium {
    transition-duration: var(--duration-normal);
  }

  .bao-motion-transition-all-medium {
    transition-property:
      color, background-color, border-color, text-decoration-color, fill, stroke, opacity,
      box-shadow, transform, filter, backdrop-filter;
    transition-duration: var(--duration-normal);
    transition-timing-function: var(--easing-entrance);
  }
}

.bao-agent-dashboard-header {
  grid-template-columns: minmax(0, 1fr);
}

.bao-agent-card-action-grid {
  grid-template-columns: minmax(0, 1fr) auto;
}

.bao-agent-card-action-grid-stacked {
  grid-template-columns: minmax(0, 1fr);
}

@media (min-width: 40rem) {
  .bao-agent-card-action-grid-stacked {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}

@media (min-width: 64rem) {
  .bao-agent-dashboard-header {
    grid-template-columns: minmax(0, 1fr) auto;
  }
}


.bao-chat-fab-toggle {
  min-block-size: var(--chat-fab-control-height);
  min-inline-size: var(--chat-fab-control-min-inline);
  padding-inline: var(--space-section);
}

.bao-chat-composer {
  display: grid;
  grid-template-columns: auto auto minmax(var(--bao-chat-composer-input-min), 1fr) auto auto;
  align-items: center;
  gap: var(--space-inline);
  padding: var(--space-section);
}

.bao-chat-composer-input {
  inline-size: 100%;
  min-inline-size: 0;
}

@media (max-width: 30rem) {
  .bao-chat-composer {
    grid-template-columns: auto auto minmax(0, 1fr) auto;
  }

  .bao-chat-composer [data-chat-composer-tts="true"] {
    display: none;
  }
}

@media (prefers-reduced-motion: no-preference) {
  .bao-chat-fab-toggle {
    transition-property:
      color, background-color, border-color, text-decoration-color, fill, stroke, opacity,
      box-shadow, transform, filter, backdrop-filter;
    transition-duration: var(--duration-normal);
    transition-timing-function: var(--easing-entrance);
  }

  .bao-chat-fab-toggle:hover,
  .bao-chat-fab-toggle:focus-visible {
    transform: scale(1.05);
    box-shadow: var(--shadow-glass-floating);
  }

  .bao-chat-fab-toggle:active {
    transform: scale(0.95);
  }
}

@media (prefers-reduced-motion: reduce) {
  .bao-chat-fab-toggle {
    transition-property: none;
  }
}

/* Session-level override of the OS media query above — same rule body,
   gated on the explicit `data-reduced-motion` user-preference attribute. */
[data-reduced-motion="true"] .bao-chat-fab-toggle {
  transition-property: none;
}

body:has([data-chat-bubble]) #main-content {
  padding-bottom: var(--chat-fab-main-reserve);
  scroll-padding-bottom: var(--chat-fab-main-reserve);
}

body:has([data-chat-bubble]) [data-shell-swap-region="main"] {
  padding-bottom: calc(1.5rem + env(safe-area-inset-bottom, 0px));
}

/*
 * The closed-state chat FAB floats over the content corner (HIG layout:
 * scrollable content reaches display sides; controls float above content).
 * Only the block-end reserve keeps the last row clear of the FAB; a permanent
 * inline-end reserve would carve a dead channel into every page. The footer's
 * end label clears one FAB lane so the floating control never sits on text.
 */
@media (min-width: 40rem) {
  body:has([data-chat-bubble]) #shell-footer > div {
    padding-inline-end: calc(
      var(--chat-fab-control-min-inline) +
      var(--chat-fab-inline-inset) +
      var(--space-section)
    );
  }
}

@media (min-width: 40rem) and (max-width: 63.999em) {
  :root {
    --chat-fab-block-inset: calc(
      var(--dock-height) +
      var(--chat-fab-control-height) +
      2rem +
      env(safe-area-inset-bottom, 0px)
    );
    --chat-fab-main-reserve: calc(14rem + env(safe-area-inset-bottom, 0px));
  }
}

@media (min-width: 64rem) {
  :root[data-chat-open] body:has([data-chat-bubble]) #main-content {
    padding-inline-end: var(--bao-chat-panel-open-reserve);
    scroll-padding-inline-end: var(--bao-chat-panel-open-reserve);
  }

  :root {
    --chat-fab-block-inset: calc(1.5rem + env(safe-area-inset-bottom, 0px));
    --chat-fab-main-reserve: calc(8rem + env(safe-area-inset-bottom, 0px));
  }
}


/* HTMX lifecycle: data-only runtime classes consume the shared motion scale. */
.htmx-dim {
  opacity: 0.5;
  pointer-events: none;
}
.htmx-fade-out { opacity: 0; }
.htmx-fade-in { opacity: 1; }
@media (prefers-reduced-motion: no-preference) {
  .htmx-dim,
  .htmx-fade-out,
  .htmx-fade-in {
    transition-property: opacity;
    transition-duration: var(--duration-normal);
    transition-timing-function: var(--easing-standard);
  }
}
@layer base {
  form.htmx-request { pointer-events: none; }
}

}
@layer bao-tokens {

/* ---- Runtime customizer host (unlayered structural geometry). ---- */
/* Header-anchored host (created at runtime next to the edit toggle). */
[data-dashboard-customizer-dropdown] {
  position: relative;
  display: inline-flex;
  z-index: var(--z-shell-topbar, 30);
}
[data-dashboard-customizer-dropdown]:not(.dropdown-open) > [data-dashboard-customizer-content] {
  display: none;
  visibility: hidden;
  pointer-events: none;
}
/*
 * Open tray geometry lives HERE, unlayered, at (0,3,0): daisyUI's
 * .dropdown .dropdown-content position:absolute is unlayered too and ties
 * lower specificity; the shared .bao-dropdown-panel-viewport rule cannot be
 * relied on for this host (no .bao-dropdown-panel base class). Anchor vars
 * come from the promote step (edit-toggle rect); absent vars mean the toggle
 * is collapsed and the compact sheet band below takes over.
 */
[data-dashboard-customizer-dropdown].dropdown-open > [data-dashboard-customizer-content] {
  display: flex;
  flex-direction: column;
  visibility: visible;
  pointer-events: auto;
  position: fixed;
  top: var(--bao-dropdown-top, auto);
  right: var(--bao-dropdown-right, var(--space-inline, 0.5rem));
  bottom: auto;
  left: auto;
  margin: 0;
  z-index: var(--z-dropdown, 1000);
  min-width: min(18rem, calc(100vw - 1.5rem));
  width: max-content;
  max-width: min(22rem, calc(100vw - 1.5rem));
  max-height: min(70vh, 28rem);
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}
/*
 * §8.6 compact transformation: below the header-collapse band the customize
 * toggle is folded into the overflow menu (0x0 — nothing to anchor to), so
 * the open tray pins to the viewport bottom as a sheet.
 */
@media (max-width: 47.99rem) {
  [data-dashboard-customizer-dropdown].dropdown-open > [data-dashboard-customizer-content] {
    top: auto;
    bottom: calc(env(safe-area-inset-bottom, 0px) + var(--space-inline, 0.5rem));
    left: var(--space-inline, 0.5rem);
    right: var(--space-inline, 0.5rem);
    width: auto;
    max-width: none;
    max-height: min(70vh, var(--vv-height, 100dvh));
    z-index: var(--z-modal, 1300);
  }
}

}
@layer bao-tokens {

  /* Dialogs always sit above the shell drawer when both are open. */
  dialog.modal,
  dialog[open].modal {
    z-index: var(--z-modal, 1300);
  }
  /*
   * Closed dialogs must not paint or steal hits. daisyUI .modal uses display:grid
   * + pointer-events:none while closed; unlayered [hidden] must still win so a
   * pre-open dialog never sits over the shell as an invisible sheet.
   */
  dialog.modal[hidden]:not([open]),
  dialog.modal[hidden]:not(.modal-open) {
    display: none;
    pointer-events: none;
    visibility: hidden;
  }
  /* Native dialog visibility must stay UNLAYERED so WebView hosts cannot
   * drop open dialogs behind daisyUI @layer modal { display:none }. The
   * modal-open state class is pinned here by the canonical layout-regression
   * contract (tokens-layout-regressions-shell.test): WebView 101 hosts that
   * miss the [open] attribute still honor the class, so both keys stay. */
  dialog.modal.modal-open,
  dialog.modal[open] {
    pointer-events: auto;
    visibility: visible;
  }
  /* Collection/home: single content track — header + primary surface, less chrome stacking. */
  [data-page-type="collection"] > [data-state-content],
  [data-page-type="home"] > [data-state-content] {
    display: flex;
    min-width: 0;
    flex-direction: column;
    gap: var(--page-section-gap);
  }
  /* .bao-page-track structural SSOT lives in tokens-layout-framework.ts only. */
  [data-page-type="collection"] [data-primitive="PageHeader"],
  [data-page-type="home"] [data-primitive="PageHeader"] {
    margin-bottom: 0;
  }
  /* Toolbar under header: no second bordered island. Longhand color only —
     the background shorthand was wiping background-image and with it the
     bao-table-scroll-x scroll-edge cue on the same element.

     Sticky toolbars (.bao-sticky-toolbar, z-sticky) are excluded: once the
     bar pins over scrolling rows a transparent surface bleeds the table
     through the chrome (evidence Finish Case band read as overlapping the
     case-journey strip). Pinned chrome keeps its bg-base-100 plate. */
  [data-page-type="home"] > [data-state-content] > [role="toolbar"]:not(.bao-sticky-toolbar),
  [data-page-type="collection"] > [data-state-content] > [role="toolbar"]:not(.bao-sticky-toolbar) {
    border: 0;
    background-color: transparent;
    padding-inline: 0;
    padding-block: 0;
  }
  /* Dynamic Type reflow (HIG / WCAG 1.4.10): daisyUI .btn hard-codes
     flex: 0 0 auto and flex-wrap:nowrap, so an enlarged root font pushes the
     active-case journey action past the viewport with no scroller. Cap the
     action to its host and let it shrink; the strip has room to grow, and
     the inner span keeps min-width:0 so its label can ellipsize rather than
     escape. */
  [data-case-journey] a.btn,
  [data-case-journey] .btn {
    min-width: 0;
    max-width: 100%;
    flex: 0 1 auto;
  }
  [data-case-journey] a.btn > *,
  [data-case-journey] .btn > * {
    min-width: 0;
  }
  /* Reflow (HIG Dynamic Type / WCAG 1.4.10): the daisyUI .fieldset-legend
     flex row and the journey payload keep their intrinsic min-content width,
     so an enlarged root font pushes each past the viewport with no scroller.
     min-width:0 + max-width:100% let the box shrink; overflow-wrap:anywhere
     lowers the intrinsic floor so the text reflows instead of driving the
     host wider than the track. Overlaps the existing .btn rule above at the
     same specificity so source order cannot reintroduce the escape. */
  legend.fieldset-legend,
  [data-case-journey] p {
    min-width: 0;
    max-width: 100%;
    overflow-wrap: anywhere;
  }
  /* Plain text bearers in content panels (permission descriptions, mono
     readouts, status copy): same intrinsic-floor rule so a long line
     reflows instead of stretching its row past the viewport. */
  [data-shell-scroll="main"] :is(span, label, summary, li, p, dd, output):not(.btn):not(.bao-touch-target),
  dialog :is(span, label, summary, li, p, dd, output):not(.btn):not(.bao-touch-target) {
    min-width: 0;
  }

  
  /* FilterBar control heights: one row, one target. The search host (label.input
     plus leading icon) and the select controls computed different heights
     (measured 46px vs 36px on /evidence at 1440), so the row never reads as
     aligned; min-height keeps every control at the Apple HIG 44pt target and
     enlarged text preserves that minimum while the surrounding row reflows. */
  [data-primitive="FilterBar"] :is(.input, .select, input, select) {
    min-height: var(--touch-target-min);
    align-self: center;
  }
  /* Inline action clusters (robot forms, annotation-collab action rows):
     intrinsic-min-content rows. The row itself — display, flex-wrap,
     min-inline-size, max-inline-size — is owned by
     tokens-glass-control-chrome; repeating min-width/flex-wrap here put a
     second, unreachable owner of flex-wrap in the same @layer. Only the
     child floor lives here, because the wrapped children need a shrink
     floor that the component base does not set. */
  .bao-action-inline > * {
    min-width: 0;
  }
  /* Chart/form stat rows (models card dl rows, budget fieldsets) and
     composer fieldset clusters: same intrinsic-floor rule. */
  dl.m-0.flex > div,
  fieldset.fieldset.flex dl > div,
  div.group.rounded-field > div.flex.items-start {
    min-width: 0;
    flex-wrap: wrap;
  }
  /* Disclosure rows (specimens "Add specimen" summary) and their panels:
     allow the trigger and content to reflow instead of pushing the card
     past the viewport. */
  details.min-w-0 > summary.btn,
  details.min-w-0 > summary {
    min-width: 0;
    max-width: 100%;
  }
  /* Form-grid cells (integrations save rows, rpa toolbar rows): the grid
     cell is full-span but its intrinsic min-content at an enlarged root
     font still widens the track; floor the cell so the button inside
     reflows instead of the track. */
  form.bao-form-grid-two > *,
  .bao-grid-reactive-panels [data-section-group] > * {
    min-width: 0;
  }
  /* Page-toolbar rows with wrap (rpa create toolbar): the toolbar host
     keeps its child rows inside the track. */
  div.flex.flex-wrap {
    min-width: 0;
  }
  /* Sticky page-toolbar rows (rpa/api-routes filter bars, ai-analysis
     provenance, editor canvas sticky): the sticky host keeps its intrinsic
     min-content at an enlarged root font. Floor the host and let its rows
     wrap; text-bearing children also get the intrinsic floor. */
  div.bao-filter-bar-sticky > div.flex,
  [data-page="rpa-workflows"] div.flex.flex-wrap,
  [data-page="api-routes"] div.space-y-space-inline,
  dl.bao-ai-provenance-sticky,
  fieldset.join.shrink-0 {
    min-width: 0;
    max-width: 100%;
  }
  div.bao-filter-bar-sticky > div.flex > *,
  dl.bao-ai-provenance-sticky > *,
  fieldset.join.shrink-0 > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Form rows (models budget, training plan rows, editor context badges):
     intrinsic-floor on the label + value rows. */
  fieldset.flex.flex-col label.flex,
  fieldset.flex.flex-col dl > div,
  div.bao-context-badge,
  dd.inline-flex.min-w-0,
  form div.flex.items-center,
  section div.flex.items-center {
    min-width: 0;
  }
  form div.flex.items-center > *,
  section div.flex.items-center > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Chat composer send row and models budget rows: the leaf label/value rows
     keep intrinsic min-content at 400%. Floor the row + its children so the
     text reflows inside the track. */
  form.bao-composer-shell.card div.flex.items-center > div.flex.items-center,
  form.mt-space-inline.border-t fieldset label.flex,
  form.mt-space-inline.border-t fieldset div.flex.w-full,
  form.mt-space-inline.border-t dl.m-0.flex > div {
    min-width: 0;
    flex-wrap: wrap;
  }
  form.mt-space-inline.border-t dl.m-0.flex > div > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Toast alert close row (capture): the fixed toast host splits the alert
     across the viewport edges; keep the alert viewport-bounded and let its
     contents reflow. */
  .toast .alert {
    max-width: min(100vw - 1rem, 100%);
    min-width: 0;
  }
  .toast .alert > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Editor canvas sticky context badges / ai-analysis provenance rows:
     children of the sticky hosts already get floors; the direct badge nodes
     also need the intrinsic floor. */
  fieldset.join.min-w-0 > :not(.btn),
  dl.bao-ai-provenance-sticky div.flex.min-w-0 > *,
  dl.flex.min-w-0 > div.bao-context-badge > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* The models budget dl hosts stat rows SIDE BY SIDE (dl = row flex), so
     the last row lands past the viewport at 400% (self-identity chain:
     `dl.m-0.flex > div.flex.items-baseline > dd` right 430px). GLOBAL
     `dl.m-0.flex { flex-wrap }` was measured net-negative (74 — registry
     dls share the class and wrapping them broke their rows), so the wrap is
     scoped to the budget fieldset's dl only; the row floors already exist
     above (same fieldset family). */
  fieldset.flex.flex-col dl.m-0.flex {
    min-width: 0;
    flex-wrap: wrap;
  }
  /* Editor sticky context badges: the badge row keeps intrinsic min-content
     (dt right 450px at 400%, self-identity chain). Floor + wrap the badge,
     and give its label/value cells the intrinsic wrap. */
  div.bao-context-badge.inline-flex {
    min-width: 0;
    flex-wrap: wrap;
  }
  div.bao-context-badge.inline-flex > * {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Flex cell hosts without min-width:0 let their content drive the column
     (measured: models "Voice command" row at 449px inside
     `div.flex.min-h-0`, editor badge dt at 450 — both parents lack the
     zero floor, so the wrap rules above never engage). The floor is inert
     unless a child's min-content exceeds the track. */
  div.flex.min-h-0 {
    min-width: 0;
  }
  div.bao-context-badge.inline-flex {
    max-width: 100%;
  }
  /* Editor workbench columns lack min-width:0 — content-width drove the
     canvas sticky to 450px at 400% (8-hop chain: workbench > stage >
     canvas-column > canvas > sticky > badge > dt). The floors are inert
     unless min-content exceeds the track. */
  div.bao-editor-workbench,
  div.bao-editor-stage {
    min-width: 0;
  }
  /* Main content grids (models page): grid items stretch to content-width
     when the grid host lacks the zero floor (8-hop chain ends
     `section > div.grid.items-stretch > section.card`); floor the host and
     its cells. */
  div.grid.items-stretch {
    min-width: 0;
  }
  div.grid.items-stretch > * {
    min-width: 0;
  }
  /* Editor sticky context-badge dl (dt "Custody" right 450px): wrap the
     badge row and floor its cells — the dl host is a row flex whose items
     keep intrinsic min-content. */
  dl.flex.min-w-0 {
    min-width: 0;
    flex-wrap: wrap;
  }
  dl.flex.min-w-0 > div {
    min-width: 0;
    flex-wrap: wrap;
  }
  dl.flex.min-w-0 dt,
  dl.flex.min-w-0 dd {
    min-width: 0;
    overflow-wrap: anywhere;
  }
  /* Voice-action button + label fold (HIG Dynamic Type / WCAG 1.4.10; measured
     round 20/21: span right 449px on a 390px viewport at 400% + WCAG text spacing).
     The voice button measures 196px with nowrap; both the button parent and the
     inner label require the wrap contract so the control reflows within bounds. */
  div.flex.flex-wrap > .btn:not(.btn-square):not(.btn-circle),
  button[data-voice-command],
  [data-voice-actions-panel] .btn {
    white-space: normal;
    min-width: 0;
    max-width: 100%;
  }
  [data-editor-context-bar] dt,
  [data-editor-context-bar] dd {
    min-width: 0;
    max-width: 100%;
    white-space: normal;
    overflow-wrap: anywhere;
  }

}
@layer bao-tokens {

/* Collection rails retain the full block size of their wrapped controls. */
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar {
  flex: 0 0 auto;
  overflow-y: clip;
}

/* Oversized chrome follows the page scrollport until every action row fits again. */
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar[data-toolbar-flow] {
  position: static;
}

/* Disabled explanations and overflow menus reserve the same bounded cell as direct actions. */
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar > :is(.btn, [data-disabled-tip-host], [data-toolbar-action-overflow]) {
  flex: 0 0 auto;
  min-inline-size: 0;
  max-inline-size: 100%;
}
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar > :is([data-disabled-tip-host], [data-toolbar-action-overflow]) > .btn {
  max-inline-size: 100%;
}

/* Toolbar children own their full touch box above the rail's scroll-edge paint. */
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar > :is(.btn, [data-disabled-tip-host]),
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar > [data-disabled-tip-host] > .btn {
  position: relative;
  z-index: var(--z-local, 1);
}

/* Preserve a paint-safe lower buffer when the rail is horizontally scrolled. */
[data-page-type="collection"] [role="toolbar"].bao-sticky-toolbar {
  padding-block-end: var(--space-inline, 0.5rem);
}

/* Joined controls keep each touch target's border box independently hittable. */
.join.join > .join-item.join-item + .join-item.join-item {
  margin-inline-start: 0;
  border-inline-start-width: 0;
}

/* Collection controls scroll below the pinned toolbar on every platform. */
[data-shell-scroll="main"][data-main-page-type="collection"],
[data-shell-scroll="main"]:has([data-page-type="collection"]) {
  scroll-padding-block-start: calc(var(--scroll-pt-main, 3rem) + var(--touch-target-min, 2.75rem) + var(--space-micro, 0.25rem));
}

[data-page-type="collection"] .bao-table-responsive-row :is(input, select, textarea, button, a) {
  scroll-margin-block-start: calc(var(--touch-target-min, 2.75rem) + var(--space-micro, 0.25rem));
}

/* Pagination inserts an ellipsis between page jumps and tail controls. */
.join.join > .join-item.join-item:not(:first-child) {
  margin-inline-start: 0;
  border-inline-start-width: 0;
}

}
@layer bao-tokens {
/*
 * Tooltip geometry overrides — UNLAYERED on purpose: the daisyui layer
 * follows utilities in cascade-layer order,
so only unlayered author CSS
 * beats daisyUI's own .tooltip rules (z-index: var(--z-raised, 2),
max-width: 20rem).
 */
.tooltip > .tooltip-content,
.tooltip[data-tip]:before,
.tooltip:after {
  /* Toast-tier overlay: tips paint above sticky chrome and dropdowns. */
  z-index: var(--z-tooltip, 1400);
}.tooltip > .tooltip-content,
.tooltip[data-tip]:before {
  /* Viewport-aware cap: the tip never exceeds the viewport safe area. */
  max-width: min(var(--tooltip-max-width, 20rem), calc(100vw - (2 * var(--tooltip-viewport-inset, 0.75rem))));
  max-width: min(var(--tooltip-max-width, 20rem), calc(100dvw - (2 * var(--tooltip-viewport-inset, 0.75rem))));
}

/* Touch-pinned explanations share the tooltip owner and motion preferences. */
.tooltip:is([data-tooltip-pinned], :focus-visible)[data-tip]:not([data-tip=""])::before,
.tooltip:is([data-tooltip-pinned], :focus-visible):is([data-tip]:not([data-tip=""]), :has(.tooltip-content:not(:empty)))::after,
.tooltip:is([data-tooltip-pinned], :focus-visible) > .tooltip-content:not(:empty) {
  opacity: 1;
  --tt-pos: 0rem;
  transition: none;
}
@media (prefers-reduced-motion: no-preference) {
  html:not([data-reduced-motion="true"]) .tooltip:is([data-tooltip-pinned], :focus-visible)::before,
  html:not([data-reduced-motion="true"]) .tooltip:is([data-tooltip-pinned], :focus-visible)::after,
  html:not([data-reduced-motion="true"]) .tooltip:is([data-tooltip-pinned], :focus-visible) > .tooltip-content {
    transition: opacity var(--duration-normal) var(--easing-standard), transform var(--duration-normal) var(--easing-standard);
  }
}

/* Collision placement overrides direction while retaining the canonical tooltip geometry. */
.tooltip[data-tooltip-placement="top"] > .tooltip-content,
.tooltip[data-tooltip-placement="top"][data-tip]::before {
  transform: translateX(var(--tt-trans, -50%)) translateY(var(--tt-pos, 0.25rem));
  inset: auto auto var(--tt-off) 50%;
}
.tooltip[data-tooltip-placement="top"]::after {
  transform: translateX(var(--tt-trans, -50%)) translateY(var(--tt-pos, 0.25rem));
  inset: auto auto var(--tt-tail) 50%;
}
.tooltip[data-tooltip-placement="bottom"] > .tooltip-content,
.tooltip[data-tooltip-placement="bottom"][data-tip]::before {
  transform: translateX(var(--tt-trans, -50%)) translateY(var(--tt-pos, -0.25rem));
  inset: var(--tt-off) auto auto 50%;
}
.tooltip[data-tooltip-placement="bottom"]::after {
  transform: translateX(var(--tt-trans, -50%)) translateY(var(--tt-pos, -0.25rem)) rotate(180deg);
  inset: var(--tt-tail) auto auto 50%;
}

/* Glass and hover transforms create a host stacking context. Elevate that owner
 * while its explanation is visible, so the child tooltip can clear later cards. */
.tooltip:is(:hover, :focus-within, .tooltip-open, [data-tooltip-pinned]) {
  z-index: var(--z-tooltip, 1400);
}

/* Page headers are shared grid items preceding animated cards. Keep their
 * active explanation in the overlay tier across that sibling paint boundary. */
.bao-page-header:has(.tooltip:is(:hover, :focus-within, .tooltip-open, [data-tooltip-pinned])) {
  position: relative;
  z-index: var(--z-tooltip, 1400);
}

/* Drawer chrome owns a stacking context below the shell header. Lift the
 * active explanation owner so collapsed-rail tips can cross that boundary. */
.drawer-side:has(.tooltip:is(:hover, :focus-within, .tooltip-open, [data-tooltip-pinned])) {
  z-index: var(--z-tooltip, 1400);
}

/* Native manual popovers escape scroll clips while retaining the source's
 * canonical tooltip pseudo-elements, theme, and typography. The host box is
 * a zero-area anchor just past the trigger's inline end edge (positioned by
 * the measured --bao-tooltip-left/top variables) — never the trigger's own
 * rectangle — so a promoted layer can never cover its trigger's hit box.
 * Non-hit-testability is structural: the box and its bubble paint reject
 * pointer input here, independently of daisyUI's own tooltip rules. */
.tooltip[data-tooltip-layer][popover] {
  position: fixed;
  inset: var(--bao-tooltip-top) auto auto var(--bao-tooltip-left);
  inline-size: 0;
  block-size: 0;
  margin: 0;
  padding: 0;
  border: 0;
  background: transparent;
  box-shadow: none;
  overflow: visible;
  pointer-events: none;
  font: inherit;
  color: inherit;
  z-index: var(--z-tooltip, 1400);
}
.tooltip[data-tooltip-layer][popover]::before,
.tooltip[data-tooltip-layer][popover]::after {
  pointer-events: none;
}
.tooltip[data-tooltip-layer][popover]:popover-open {
  display: block;
}
/* The authored source remains the accessible control; only duplicate visual
 * paint is suppressed, and only while native promotion or Escape owns it. */
.tooltip:is([data-tooltip-layer-active], [data-tooltip-dismissed])[data-tip]:not([data-tip=""])::before,
.tooltip:is([data-tooltip-layer-active], [data-tooltip-dismissed])[data-tip]:not([data-tip=""])::after {
  opacity: 0;
  visibility: hidden;
  transition: none;
}

/* Native documents have one tooltip box owner. Dormant authored pseudo boxes
 * otherwise enlarge scrollports even at zero opacity. Unsupported documents
 * and an explicitly failed source retain the canonical inline paint. */
html[data-tooltip-native="true"] .tooltip[data-tip]:not([data-tooltip-layer]):not([data-tooltip-inline])::before,
html[data-tooltip-native="true"] .tooltip[data-tip]:not([data-tooltip-layer]):not([data-tooltip-inline])::after {
  display: none;
  content: none;
}

}
@layer bao-tokens {
/* Reduced-motion token clamp: class-level `transition: … var(--duration-*)`
   rules out-specificity the universal `*` clamp, so the durations themselves
   collapse at the variable level. Last in bao-tokens beats every :root above. */
@media (prefers-reduced-motion: reduce) {
  :root {
    --duration-fast: var(--reduced-motion-min-duration);
    --duration-normal: var(--reduced-motion-min-duration);
    --duration-slow: var(--reduced-motion-min-duration);
    --duration-press: var(--reduced-motion-min-duration);
    --duration-focus-pulse: var(--reduced-motion-min-duration);
    --duration-skeleton: var(--reduced-motion-min-duration);
    --duration-progress: var(--reduced-motion-min-duration);
    --duration-reduced-motion-calm: var(--reduced-motion-min-duration);
    --duration-pulse: var(--reduced-motion-min-duration);
    --duration-pulse-alpha: var(--reduced-motion-min-duration);
    --stagger-step: 0ms;
    --view-transition-new-delay: 0ms;
  }
}

}
@layer bao-tokens {
/* Toolbar icons are decoration: joined buttons overlap by the join radius, so
 * an icon must never capture the pointer for the seam it overlaps. */
.bao-toolbar-action > svg {
  pointer-events: none;
}

}
@layer bao-tokens {
/* A compact horizontal 2D rail has no flexible spacer. The spacer is a
 * vertical-rail alignment aid; at tablet width its 100% inline size
 * consumed the whole rail and collapsed the actual tool track to 0px. */
@media (max-width: 64rem) {
  [data-editor-tool-rail][data-editor-tool-dimension="2d"] > .bao-min-w-toolbar-spacer {
    display: none;
  }
}

}
@layer bao-tokens {
/* Guided setup paints a token-owned ring and a status chip in normal flow. */
[data-wizard-tour-target]:target,
[data-wizard-highlight-active="true"] {
  outline: var(--focus-ring-width) solid var(--accent-primary);
  outline-offset: var(--focus-ring-offset);
  border-radius: var(--radius-box);
}

[data-wizard-highlight-active="true"]:not([data-wizard-tour-target]) {
  scroll-margin-block: var(--space-section);
}

/* The native fragment clears the same existing panel bound used by the instructions. */
[data-wizard-tour-target] {
  scroll-margin-block-start: calc(var(--bao-panel-max-height-xl) + var(--space-inline) + var(--space-inline) + var(--space-section));
  scroll-margin-block-end: var(--space-section);
}

/* The toolbar material owns its outer plane; only instruction text scrolls inside it. */
[data-guided-tour-layout] {
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  gap: var(--space-micro);
  inline-size: 100%;
  min-inline-size: 0;
  min-block-size: 0;
  max-block-size: min(var(--bao-panel-max-height-xl), calc(var(--bao-viewport-height) - var(--topbar-height) - var(--dock-height) - var(--touch-target-min) - var(--space-page)));
}

[data-guided-tour-copy] {
  min-block-size: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Trailing alignment is the beside placement; controls never sit beneath the chip. */
.bao-wizard-spotlight-chip {
  display: flex;
  inline-size: fit-content;
  max-inline-size: 100%;
  align-self: flex-end;
  margin-block-start: var(--space-inline);
  margin-inline-start: auto;
  margin-inline-end: 0;
  padding: var(--space-micro) var(--space-inline);
  border-radius: var(--radius-control);
  border: var(--pane-divider) solid var(--border-base);
  background-color: var(--bg-panel);
  color: var(--text-primary);
  pointer-events: none;
}

.bao-wizard-spotlight-chip-title {
  min-inline-size: 0;
  margin: 0;
  overflow-wrap: anywhere;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  line-height: var(--leading-tight);
}

/* Below placement uses the leading edge of the next flow row. */
[data-wizard-highlight-active="true"][data-wizard-chip-placement="below"] > .bao-wizard-spotlight-chip {
  align-self: flex-start;
  margin-inline-start: 0;
  margin-inline-end: auto;
}

}


@layer base {

[data-theme="capture-dx"] {
  color-scheme: light;
  --color-accent: #B04C1B;
  --color-accent-content: #ffffff;
  --color-base-100: #ffffff;
  --color-base-content: #18181b;
  --color-base-200: #eeeef0;
  --color-base-300: #d1d1d6;
  --color-error: #b91c1c;
  --color-error-content: #ffffff;
  --color-info: #0369a1;
  --color-info-content: #ffffff;
  --color-neutral: #18181b;
  --color-neutral-content: #ffffff;
  --color-primary: #16548A;
  --color-primary-content: #ffffff;
  --color-secondary: #eeeef0;
  --color-secondary-content: #18181b;
  --color-success: #065f46;
  --color-success-content: #ffffff;
  --color-warning: #a84d08;
  --color-warning-content: #ffffff;
}

[data-theme="capture-dx-dark"] {
  color-scheme: dark;
  --color-accent: #F56E28;
  --color-accent-content: #18181b;
  --color-base-100: #1c1c1e;
  --color-base-content: #f4f4f5;
  --color-base-200: #2c2c2e;
  --color-base-300: #48484a;
  --color-error: #f87171;
  --color-error-content: #0c1017;
  --color-info: #41B6E6;
  --color-info-content: #0c1017;
  --color-neutral: #f4f4f5;
  --color-neutral-content: #1c1c1e;
  --color-primary: #41B6E6;
  --color-primary-content: #0c1017;
  --color-secondary: #2c2c2e;
  --color-secondary-content: #f4f4f5;
  --color-success: #25ac83;
  --color-success-content: #0c1017;
  --color-warning: #e58212;
  --color-warning-content: #18181b;
}

}
