/* BooCode+ — effects layer. Tasteful sci-fi: calm, premium, Linear-grade. EVERY rule is scoped under `.theme-boocode-plus.dark` so (a) the other 22 themes are byte-for-byte unaffected and (b) the light variant stays a clean flat slate — dark is the priority, so the glass/gradient/glow ship dark-only. No canvas, no animation loop, no scanlines. Just: a faint STATIC ambient gradient on the app background, frosted glass on CHROME ONLY (rails, menus, dialogs, popovers, the composer, pane top-bars), a restrained indigo glow on the primary action, and spring-eased transitions on chrome state changes. iOS / quality guardrails honored: - backdrop-blur capped at 8–12px; no nested blur-on-blur (the dialog overlay's own backdrop-blur is neutralized so only the dialog CONTENT frosts — one layer). - opaque fallback: every glass rule lives inside @supports(backdrop-filter), so a browser without it keeps the plain opaque Tailwind utility (bg-sidebar/bg-popover/bg-card = solid token). prefers-reduced-transparency forces the same opaque path. - spring via cubic-bezier (NOT the linear() function — Safari <17.2 gap), confined to box-shadow / transform / color / filter — never layout props. - chat messages, tool-call cards and code blocks (bg-muted/30·/20, bg-card bubbles) are deliberately NOT targeted — glass never sits behind reading content; the ambient gradient behind it stays faint & opaque-based (AA). Glass targets are stable, verified hooks: bg-sidebar (both rails), bg-popover (all menus/dialogs/popovers/sheets), the composer's unique focus-within:ring-primary/15 box, [data-slot=button][data-variant=default] (the primary action), and the compound .border-b.bg-muted/30·/20 (pane top-bars — distinct from message bubbles, which use .border.rounded-lg). */ .theme-boocode-plus.dark { /* Spring curves. --bcp-spring overshoots a touch (press/glow bloom); --bcp-ease is a smooth Linear-style decel for color/opacity. */ --bcp-spring: cubic-bezier(0.34, 1.42, 0.5, 1); --bcp-ease: cubic-bezier(0.32, 0.72, 0, 1); --bcp-blur: 10px; } /* ── Static ambient gradient ───────────────────────────────────────────── Painted on the app-shell root (.h-dvh is unique to App.tsx). Opaque base (var(--background)) + three faint indigo radials = depth without cost. The MessageList scroll area is transparent, so the gradient reads faintly behind chat — but it's static and opaque-based: the brightest stop (indigo @14% over #0f1117) still gives ~10:1 for #e3e6f1 body text. The glass rails blur it for a premium parallax-of-light feel. No background-attachment:fixed (iOS jank); .h-dvh doesn't scroll, so the field is already viewport-stable. */ .theme-boocode-plus.dark .h-dvh { background-color: var(--background); background-image: radial-gradient(1200px 760px at 8% -12%, color-mix(in oklab, #5e6ad2 14%, transparent), transparent 58%), radial-gradient(1000px 680px at 102% 4%, color-mix(in oklab, #5a73d8 10%, transparent), transparent 54%), radial-gradient(1100px 900px at 50% 128%, color-mix(in oklab, #2c3270 16%, transparent), transparent 60%); background-repeat: no-repeat; } /* ── Frosted glass on chrome ───────────────────────────────────────────── Progressive enhancement: only inside @supports does the surface go translucent + blur. Without backdrop-filter support the rules vanish and the plain opaque utility (solid token bg) shows — that IS the opaque fallback. Each background has an rgba() line first (covers the rare browser that has backdrop-filter but not color-mix, e.g. Safari 15) then the color-mix line. */ @supports ((-webkit-backdrop-filter: blur(1px)) or (backdrop-filter: blur(1px))) { /* Side rails (ProjectSidebar + RightRail). Blur the ambient gradient behind them → the signature glass plane. Kept at 80% so the dense nav text stays crisp; the blur + saturate sells the effect, not heavy transparency. */ .theme-boocode-plus.dark .bg-sidebar { background-color: rgba(19, 21, 29, 0.80); background-color: color-mix(in oklab, var(--sidebar) 80%, transparent); -webkit-backdrop-filter: blur(var(--bcp-blur)) saturate(140%); backdrop-filter: blur(var(--bcp-blur)) saturate(140%); } /* Every floating surface: dialogs, dropdown / context / sub menus, the @-mention & slash pickers, the mobile bottom sheet, the message-actions menu. All carry bg-popover and all float over content → one clean blur. */ .theme-boocode-plus.dark .bg-popover { background-color: rgba(26, 29, 46, 0.84); background-color: color-mix(in oklab, var(--popover) 84%, transparent); -webkit-backdrop-filter: blur(12px) saturate(150%); backdrop-filter: blur(12px) saturate(150%); } /* The composer message box (ChatInput) — unique focus-within ring hook. Frosts the tail of the conversation as it scrolls beneath. 82% keeps the textarea text readable even over a bright code block underneath. */ .theme-boocode-plus.dark .focus-within\:ring-primary\/15 { background-color: rgba(26, 29, 46, 0.82); background-color: color-mix(in oklab, var(--card) 82%, transparent); -webkit-backdrop-filter: blur(var(--bcp-blur)) saturate(140%); backdrop-filter: blur(var(--bcp-blur)) saturate(140%); } /* Pane top-bars (Coder/Workspace/terminal-hotkey/artifact headers). The compound .border-b.bg-muted/N selector excludes chat bubbles & tool cards (those use .border.rounded-lg). Lightest blur (8px) + an inset top hairline for the edge-lit premium feel. */ .theme-boocode-plus.dark .border-b.bg-muted\/30, .theme-boocode-plus.dark .border-b.bg-muted\/20 { background-color: rgba(28, 32, 47, 0.62); background-color: color-mix(in oklab, var(--muted) 62%, transparent); -webkit-backdrop-filter: blur(8px) saturate(130%); backdrop-filter: blur(8px) saturate(130%); box-shadow: inset 0 1px 0 0 color-mix(in oklab, #aab2ff 8%, transparent); } } /* Dialog scrim: deepen the dim (the stock bg-black/10 is too light to anchor a frosted modal) and kill its own backdrop-blur so the only blur layer is the dialog CONTENT above — no nested blur-on-blur. Unconditional: when blur is unsupported the stock overlay had no blur anyway, and the deeper scrim is harmless. */ .theme-boocode-plus.dark [data-slot="dialog-overlay"] { background-color: rgba(7, 8, 14, 0.55); -webkit-backdrop-filter: none; backdrop-filter: none; } /* ── Restrained indigo glow on the primary action ──────────────────────── The default-variant Button only (Send, primary confirm). Resting: a hairline indigo rim + soft drop glow. Hover: the glow blooms with the spring curve. Press: a composited squash. box-shadow/transform/filter only — no reflow. */ .theme-boocode-plus.dark [data-slot="button"][data-variant="default"] { box-shadow: 0 0 0 1px color-mix(in oklab, #5e6ad2 38%, transparent), 0 4px 16px -6px color-mix(in oklab, #5e6ad2 50%, transparent); transition: box-shadow 0.28s var(--bcp-spring), transform 0.2s var(--bcp-spring), filter 0.2s var(--bcp-ease), background-color 0.18s var(--bcp-ease); } .theme-boocode-plus.dark [data-slot="button"][data-variant="default"]:not([disabled]):hover { box-shadow: 0 0 0 1px color-mix(in oklab, #5e6ad2 60%, transparent), 0 8px 26px -6px color-mix(in oklab, #5e6ad2 68%, transparent); filter: brightness(1.06); } .theme-boocode-plus.dark [data-slot="button"][data-variant="default"]:not([disabled]):active { transform: translateY(0.5px) scale(0.985); } /* ── Spring-eased state on the rest of the chrome ───────────────────────── Smooth (non-overshoot) color/bg transitions on menu items and the composer focus, so hovers and focus feel intentional, not instant. Color props only. */ .theme-boocode-plus.dark [data-slot="dropdown-menu-item"], .theme-boocode-plus.dark [data-slot="context-menu-item"], .theme-boocode-plus.dark [data-slot="dropdown-menu-sub-trigger"], .theme-boocode-plus.dark [data-slot="context-menu-sub-trigger"] { transition: background-color 0.16s var(--bcp-ease), color 0.16s var(--bcp-ease); } .theme-boocode-plus.dark .focus-within\:ring-primary\/15 { transition: border-color 0.22s var(--bcp-ease), box-shadow 0.22s var(--bcp-spring), background-color 0.22s var(--bcp-ease); } /* ── Accessibility fallbacks ────────────────────────────────────────────── Reduced transparency: drop every glass surface to its solid token bg and remove all blur. Declared after the @supports block so it wins. */ @media (prefers-reduced-transparency: reduce) { .theme-boocode-plus.dark .bg-sidebar { background-color: var(--sidebar); -webkit-backdrop-filter: none; backdrop-filter: none; } .theme-boocode-plus.dark .bg-popover { background-color: var(--popover); -webkit-backdrop-filter: none; backdrop-filter: none; } .theme-boocode-plus.dark .focus-within\:ring-primary\/15 { background-color: var(--card); -webkit-backdrop-filter: none; backdrop-filter: none; } .theme-boocode-plus.dark .border-b.bg-muted\/30, .theme-boocode-plus.dark .border-b.bg-muted\/20 { background-color: var(--muted); -webkit-backdrop-filter: none; backdrop-filter: none; box-shadow: none; } } /* Reduced motion: no spring/transition, no press transform. The ambient gradient is static, so it (correctly) stays. */ @media (prefers-reduced-motion: reduce) { .theme-boocode-plus.dark [data-slot="button"][data-variant="default"], .theme-boocode-plus.dark [data-slot="dropdown-menu-item"], .theme-boocode-plus.dark [data-slot="context-menu-item"], .theme-boocode-plus.dark [data-slot="dropdown-menu-sub-trigger"], .theme-boocode-plus.dark [data-slot="context-menu-sub-trigger"], .theme-boocode-plus.dark .focus-within\:ring-primary\/15 { transition: none; } .theme-boocode-plus.dark [data-slot="button"][data-variant="default"]:not([disabled]):active { transform: none; } }