/* BooCode Classic — effects layer. Faithful revival of /opt/boolab data-mode='boocode' terminal-HUD chrome. Scoping contract (immutable): - EVERY rule is scoped under `.theme-boocode-classic` so the other 22 themes are byte-for-byte unaffected. - EVERY continuous keyframe animation is *additionally* scoped under `html.bc-anim-on.theme-boocode-classic`. ThemeFx sets `bc-anim-on` only when the Animated-background toggle is ON *and* prefers-reduced-motion is not set — so toggling either off removes the class and freezes all motion. @keyframes names are global (CSS can't scope the at-rule itself); they are `bc-`-prefixed and only *referenced* under the gated selector, so no animation runs unless the gate is on. The matrix-rain canvas lives in components/fx/MatrixRain.tsx (mounted by ThemeFx). This sheet adds: an Orbitron display wordmark + blinking caret, an app-wide scanline sweep, orange card hover glow + lift, terminal-frame chrome on the rails, and the ported boolab `.bc-*` / `.boocode-*` design-system classes (dormant until a HUD component consumes them). */ .theme-boocode-classic { --bc-orange: #f97316; --bc-amber: #fbbf24; --bc-rust: #c2410c; --bc-glow-orange: 0 0 24px color-mix(in srgb, var(--bc-orange) 32%, transparent); --bc-glow-soft: 0 0 40px color-mix(in srgb, var(--bc-orange) 14%, transparent); } /* ── Orbitron display wordmark ──────────────────────────────────────────── Applied to the "BooCode" text heading via the additive `boocode-display` class (the only text wordmark — the sidebar wordmark is an , which a font can't restyle). Orbitron 800 is JS-imported in main.tsx. */ .theme-boocode-classic .boocode-display { font-family: 'Orbitron', var(--font-sans); font-weight: 800; letter-spacing: 0.06em; color: var(--bc-orange); text-shadow: 0 0 14px color-mix(in srgb, var(--bc-orange) 45%, transparent); } /* Terminal cursor after the wordmark. Always rendered (a solid block when motion is off — boolab's reduced-motion behaviour); blinks only when gated. */ .theme-boocode-classic .boocode-display::after { content: '▮'; margin-left: 0.12em; color: var(--bc-amber); opacity: 1; } html.bc-anim-on.theme-boocode-classic .boocode-display::after { animation: bc-caret-blink 1s steps(1, end) infinite; } /* ── App-wide scanline sweep ────────────────────────────────────────────── A soft warm band that drifts down the viewport on a calm 8s cycle. `position: fixed` keeps it viewport-locked (never creates document overflow); mix-blend-mode: screen only lightens, so text underneath stays legible. Defined ONLY under the gate → vanishes entirely when motion is off (the warm palette + static rain-off state is the reduced-motion fallback). `.h-dvh.bg-background` is unique to the AppShell root (App.tsx). */ html.bc-anim-on.theme-boocode-classic .h-dvh.bg-background::after { content: ''; position: fixed; inset: 0; z-index: 2; pointer-events: none; background: linear-gradient( 180deg, transparent 46%, color-mix(in srgb, var(--bc-orange) 9%, transparent) 50%, transparent 54% ); mix-blend-mode: screen; animation: bc-scanline 8s linear infinite; will-change: transform; } /* ── Card hover glow + lift ─────────────────────────────────────────────── The shadcn Card primitive (`data-slot="card"`). The orange rim + drop glow apply on hover under any condition (hover feedback is acceptable under reduced motion); the transition timing and the 1px lift are gated so motion off = instant, no travel. */ .theme-boocode-classic [data-slot="card"]:hover { border-color: color-mix(in srgb, var(--bc-orange) 55%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--bc-orange) 22%, transparent), 0 6px 18px -8px color-mix(in srgb, var(--bc-orange) 40%, transparent); } html.bc-anim-on.theme-boocode-classic [data-slot="card"] { transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease; } html.bc-anim-on.theme-boocode-classic [data-slot="card"]:hover { transform: translateY(-1px); } /* ── Terminal-frame chrome on the rails ─────────────────────────────────── Monospace + a hairline orange edge-light on the sidebar (vertical list that already truncates — low overflow risk). Pane top-bars are intentionally left alone: they are crowded control rows where a wider mono font risks wrapping. */ .theme-boocode-classic .bg-sidebar { font-family: var(--font-mono); box-shadow: inset -1px 0 0 0 color-mix(in srgb, var(--bc-orange) 8%, transparent); } /* Floating surfaces (menus / dialogs / popovers) are intentionally NOT given an inset box-shadow here — that would clobber shadcn's `shadow-md` elevation (higher specificity) and flatten menus over the rain. The warm `--popover` / `--border` tokens already theme them. */ /* ────────────────────────────────────────────────────────────────────────── Ported boolab design-system classes. These are faithful copies of the /opt/boolab `.bc-*` / `.boocode-*` chrome. No component in this repo renders these class names yet (boolab's RepoStatusBar / HUD components don't exist here), so they are DORMANT — shipped so the Classic design system is complete and any future HUD element (prompt line, status pill, kbd hint, breadcrumb) lights up automatically. All scoped to the theme; animations gated. ────────────────────────────────────────────────────────────────────────── */ /* Terminal prompt line: `$ boocode @host: path (branch)` */ .theme-boocode-classic .bc-prompt-line { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; row-gap: 0.25rem; font-family: var(--font-mono); font-size: 0.8125rem; color: var(--muted-foreground); padding: 0.5rem 0.75rem; background: var(--popover); border-bottom: 1px solid var(--border); } .theme-boocode-classic .bc-prompt-host { color: var(--bc-orange); } .theme-boocode-classic .bc-prompt-branch { color: var(--bc-orange); opacity: 0.8; } .theme-boocode-classic .bc-prompt-dollar { color: var(--bc-orange); text-shadow: 0 0 6px var(--bc-orange); margin-right: 0.25rem; } /* Standalone blinking block caret. */ .theme-boocode-classic .bc-caret { display: inline-block; width: 0.6em; height: 1em; background: currentColor; vertical-align: text-bottom; margin-left: 0.1em; } html.bc-anim-on.theme-boocode-classic .bc-caret { animation: bc-caret-blink 1s steps(1, end) infinite; } /* IDLE / SYNCING / ERROR status pills. */ .theme-boocode-classic .bc-status-pill { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.1rem 0.5rem; border-radius: 999px; border: 1px solid var(--border); background: var(--card); font-size: 0.6875rem; text-transform: uppercase; letter-spacing: 0.12em; font-family: var(--font-mono); } .theme-boocode-classic .bc-status-idle { color: #7ae07a; border-color: rgba(122, 224, 122, 0.4); } .theme-boocode-classic .bc-status-syncing { color: var(--bc-orange); border-color: color-mix(in srgb, var(--bc-orange) 60%, transparent); } .theme-boocode-classic .bc-status-error { color: #ff6b6b; border-color: rgba(255, 107, 107, 0.5); } .theme-boocode-classic .bc-status-syncing::before { content: '▮'; color: var(--bc-orange); } html.bc-anim-on.theme-boocode-classic .bc-status-syncing::before { animation: bc-caret-blink 1s steps(1, end) infinite; } /* Keyboard hint chip. */ .theme-boocode-classic .bc-key-hint { display: inline-flex; align-items: center; justify-content: center; min-width: 1.25rem; padding: 0 0.3rem; height: 1.1rem; border: 1px solid var(--border); border-radius: 0.25rem; font-family: var(--font-mono); font-size: 0.625rem; color: var(--muted-foreground); background: var(--popover); } /* Uppercase orange breadcrumb / overline. */ .theme-boocode-classic .boocode-breadcrumb { font-family: 'Orbitron', var(--font-sans); font-size: 0.6875rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--bc-orange); text-shadow: 0 0 8px color-mix(in srgb, var(--bc-orange) 40%, transparent); } /* Inset terminal-frame border. */ .theme-boocode-classic .boocode-terminal-frame { border: 1px solid var(--border); box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--bc-orange) 5%, transparent), 0 0 0 1px #0a0604; } /* Card hover glow + lift utility (boolab `.bc-card`), for non-shadcn surfaces. */ .theme-boocode-classic .bc-card { position: relative; border: 1px solid color-mix(in srgb, var(--bc-orange) 22%, transparent); background: var(--card); padding: 1rem; border-radius: 0.375rem; overflow: hidden; } .theme-boocode-classic .bc-card:hover { border-color: color-mix(in srgb, var(--bc-orange) 55%, transparent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--bc-orange) 22%, transparent), 0 6px 18px -8px color-mix(in srgb, var(--bc-orange) 40%, transparent); } html.bc-anim-on.theme-boocode-classic .bc-card { transition: border-color 160ms ease, box-shadow 160ms ease, transform 160ms ease; } html.bc-anim-on.theme-boocode-classic .bc-card:hover { transform: translateY(-1px); } /* ── Keyframes (global names, referenced only under the gate above) ───────── */ @keyframes bc-caret-blink { 0%, 49% { opacity: 1; } 50%, 100% { opacity: 0; } } @keyframes bc-scanline { 0% { transform: translateY(-100%); } 100% { transform: translateY(100%); } } /* ── Reduced-motion belt-and-suspenders ─────────────────────────────────── bc-anim-on already excludes reduced-motion (ThemeFx), but if the class ever lingered, this hard-stops every animation and the lift transform. */ @media (prefers-reduced-motion: reduce) { .theme-boocode-classic .boocode-display::after, .theme-boocode-classic .bc-caret, .theme-boocode-classic .bc-status-syncing::before { animation: none; opacity: 1; } .theme-boocode-classic .h-dvh.bg-background::after { animation: none; display: none; } .theme-boocode-classic [data-slot="card"], .theme-boocode-classic .bc-card { transition: none; } .theme-boocode-classic [data-slot="card"]:hover, .theme-boocode-classic .bc-card:hover { transform: none; } }