/* * prism — crystal-clear glass theme. * * Iridescent multi-hue palette (lavender → peach → cyan → mint) refracted * through frosted-glass surfaces. Earns its name twice: once for the * literal glass refraction, once for the hue spectrum the corner glows * span. Born in skyai-finance; lifted into a standalone theme when the * shape stabilised. * * Forked from skyrise (lib-theme-skyrise) with four product-driven * changes that became theme-wide: * * 1. Bakes in --warning + --warning-foreground (skyrise had them; * pristine did not). Any product that displays health/risk needs * warning semantics in both modes. * 2. Adds a --text-hero size step (3.5rem) above display, for KPI * heroes and editorial mastheads. * 3. Ships a `.num` utility that sets tabular-nums + slashed-zero + * letter-spacing:0 — non-negotiable on money numbers, useful * anywhere digits matter. * 4. Redesigns the dark-mode background. Skyrise's dark blobs sat at * L≈0.18 with chroma≈0.12, near OKLCH gamut edges, which clipped * to muddy gray. Here the corner glows are pushed to L≈0.30 with * lower chroma, paired with a cleaner near-black base — they read * as soft brand-accent light instead of tinted fog. * * Also dropped: the 11 background atmospheres and 4 surface tints * skyrise shipped for white-label flexibility. Prism picks one brand * surface (light + dark) and ships it. If alternates return, re-import * from skyrise. * * Fonts loaded by the consuming app via Google Fonts URL @import at the * very top of its entry CSS — see README. Do NOT @import them here. */ :root { /* ── Colors ── * Light mode rests on an iridescent lavender→peach→mint→rose gradient * (defined in @layer base below). Glass surfaces sit at low alpha so the * gradient reads through; foreground is pushed to L=0.16 for vivid, * never-faint text against translucent surfaces. */ --background: oklch(0.97 0.015 295); --foreground: oklch(0.16 0.025 285); --card: oklch(1 0 0 / 0.58); --card-foreground: oklch(0.16 0.025 285); --popover: oklch(1 0 0 / 0.74); --popover-foreground: oklch(0.16 0.025 285); --primary: oklch(0.55 0.22 295); --primary-foreground: oklch(1 0 0); --secondary: oklch(0.96 0.012 290); --secondary-foreground: oklch(0.22 0.025 285); --muted: oklch(0.95 0.012 290); --muted-foreground: oklch(0.42 0.02 285); --accent: oklch(0.93 0.04 295); --accent-foreground: oklch(0.25 0.05 295); --destructive: oklch(0.6 0.24 25); --success: oklch(0.5 0.18 150); --success-foreground: oklch(1 0 0); --warning: oklch(0.7 0.18 75); --warning-foreground: oklch(0.18 0.04 75); --border: oklch(0 0 0 / 0.09); --input: oklch(0 0 0 / 0.09); --ring: oklch(0.55 0.22 295 / 0.55); /* Charts: violet → blue-cyan → amber → rose → emerald. Hues spread ≥60° * apart and lightness is varied between adjacent indices so adjacent * series stay perceptually distinct in multi-line / stacked charts. */ --chart-1: oklch(0.55 0.24 295); --chart-2: oklch(0.62 0.2 230); --chart-3: oklch(0.82 0.18 80); --chart-4: oklch(0.72 0.2 350); --chart-5: oklch(0.5 0.18 150); --sidebar: oklch(1 0 0 / 0.5); --sidebar-foreground: oklch(0.16 0.025 285); --sidebar-primary: oklch(0.55 0.22 295); --sidebar-primary-foreground: oklch(1 0 0); --sidebar-accent: oklch(0.93 0.04 295); --sidebar-accent-foreground: oklch(0.25 0.05 295); --sidebar-border: oklch(0 0 0 / 0.07); --sidebar-ring: oklch(0.55 0.22 295 / 0.55); --syntax-keyword: oklch(0.5 0.22 295); --syntax-string: oklch(0.5 0.16 150); --syntax-number: oklch(0.55 0.18 35); --syntax-comment: oklch(0.52 0.02 285); --syntax-function: oklch(0.48 0.18 235); --syntax-type: oklch(0.48 0.14 195); /* ── Chat surfaces ── * Contract for lib-agent-chat-ui / lib-agent-dock-ui. User bubble is * a filled, deep, high-contrast panel with light text; assistant * bubble is a card-like surface with a hairline border. */ --chat-user-bg: oklch(0.48 0.2 295); --chat-user-fg: oklch(1 0 0); --chat-assistant-bg: oklch(1 0 0 / 0.7); --chat-assistant-fg: oklch(0.16 0.025 285); --chat-assistant-border: oklch(0 0 0 / 0.09); /* ── Radius ── Generous, premium feel. */ --radius: 1rem; /* ── Motion ── Apple-style spring physics. */ --duration-fast: 180ms; --duration-base: 320ms; --duration-slow: 450ms; --duration-slower: 600ms; --duration-spring: 520ms; --ease-standard: cubic-bezier(0.4, 0, 0.2, 1); --ease-decelerate: cubic-bezier(0, 0, 0.2, 1); --ease-accelerate: cubic-bezier(0.4, 0, 1, 1); --ease-spring-gentle: linear(0, 0.04 8%, 0.12 15%, 0.23 22%, 0.37 30%, 0.51 38%, 0.63 46%, 0.74 54%, 0.83 62%, 0.89 70%, 0.94 78%, 0.97 86%, 0.99 94%, 1); --ease-spring-snappy: linear(0, 0.06 6%, 0.18 12%, 0.33 18%, 0.5 25%, 0.65 32%, 0.8 40%, 0.9 48%, 0.98 56%, 1.015 64%, 1.02 72%, 1.015 80%, 1.005 88%, 1); --ease-spring-bouncy: linear(0, 0.08 8%, 0.22 16%, 0.4 24%, 0.58 32%, 0.75 40%, 0.88 48%, 0.98 56%, 1.04 64%, 1.06 72%, 1.04 80%, 1.01 86%, 0.995 92%, 1); --ease-emphasized: var(--ease-spring-snappy); /* ── Typography ── Bumped one notch from typical sizes for readability. * Body sits at 17px (1.0625rem) — never-faint text. All scales ride * along proportionally. Hero is the finance KPI step above display. */ --text-hero-size: 3.5rem; --text-hero-lh: 3.75rem; --text-display-size: 3rem; --text-display-lh: 3.25rem; --text-headline-size: 2rem; --text-headline-lh: 2.375rem; --text-title-size: 1.5rem; --text-title-lh: 1.875rem; --text-body-size: 1.0625rem; --text-body-lh: 1.625rem; --text-label-size: 0.9375rem; --text-label-lh: 1.25rem; --text-caption-size: 0.8125rem; --text-caption-lh: 1.125rem; /* ── Elevation ── Soft layered shadows in line with glass philosophy. */ --elevation-0: none; --elevation-1: 0 1px 2px oklch(0 0 0 / 0.06); --elevation-2: 0 2px 8px oklch(0 0 0 / 0.07), 0 1px 2px oklch(0 0 0 / 0.04); --elevation-3: 0 4px 16px oklch(0 0 0 / 0.08), 0 2px 4px oklch(0 0 0 / 0.04); --elevation-4: 0 12px 36px oklch(0.5 0.18 295 / 0.14), 0 4px 12px oklch(0 0 0 / 0.06); --elevation-5: 0 20px 56px oklch(0.5 0.18 295 / 0.18), 0 8px 20px oklch(0 0 0 / 0.08); --spacing: 0.25rem; --border-width-thin: 0.5px; --border-width-base: 1px; --border-width-thick: 2px; --border-width-heavy: 4px; /* ── Glass vibrancy ── Heavy frost, like the skyrise reference. */ --glass-blur: 32px; --glass-saturate: 220%; --glass-brightness: 1.06; --glass-contrast: 1.02; /* ── Font stacks ── Loaded by the consuming app. */ --font-sans: "Inter", "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; --font-heading: "Instrument Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --font-mono: "Geist Mono", ui-monospace, SFMono-Regular, Menlo, "Cascadia Mono", Consolas, monospace; /* Tailwind utility families. Distinct names so a consuming app's * `@theme inline` can indirect to these (--font-heading/--font-sans collide * with Tailwind's own font-* namespace). Mirror --font-heading/--font-sans. */ --heading-family: "Instrument Sans", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; --body-family: "Inter", "Inter Variable", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; } /* * Dark mode — clean deep-violet base. Foreground stays high-L for the * vivid, never-faint feel. Corner accents live in the body bg block below. */ .dark { --background: oklch(0.10 0.015 285); --foreground: oklch(0.97 0.005 280); --card: oklch(0.22 0.04 290 / 0.55); --card-foreground: oklch(0.97 0.005 280); --popover: oklch(0.22 0.04 290 / 0.78); --popover-foreground: oklch(0.97 0.005 280); --primary: oklch(0.7 0.2 295); --primary-foreground: oklch(0.14 0.04 295); --secondary: oklch(0.26 0.03 290); --secondary-foreground: oklch(0.95 0.005 280); --muted: oklch(0.26 0.03 290); --muted-foreground: oklch(0.78 0.015 285); --accent: oklch(0.32 0.06 295); --accent-foreground: oklch(0.95 0.04 295); --destructive: oklch(0.7 0.22 25); --success: oklch(0.74 0.16 150); --success-foreground: oklch(0.12 0.02 150); --warning: oklch(0.78 0.16 75); --warning-foreground: oklch(0.16 0.04 75); --border: oklch(1 0 0 / 0.1); --input: oklch(1 0 0 / 0.1); --ring: oklch(0.7 0.2 295 / 0.55); --chart-1: oklch(0.68 0.24 295); --chart-2: oklch(0.72 0.2 230); --chart-3: oklch(0.88 0.18 80); --chart-4: oklch(0.82 0.2 350); --chart-5: oklch(0.6 0.18 150); --sidebar: oklch(0.2 0.04 290 / 0.55); --sidebar-foreground: oklch(0.97 0.005 280); --sidebar-primary: oklch(0.7 0.2 295); --sidebar-primary-foreground: oklch(0.14 0.04 295); --sidebar-accent: oklch(0.32 0.06 295); --sidebar-accent-foreground: oklch(0.95 0.04 295); --sidebar-border: oklch(1 0 0 / 0.08); --sidebar-ring: oklch(0.7 0.2 295 / 0.55); --syntax-keyword: oklch(0.78 0.18 295); --syntax-string: oklch(0.8 0.16 150); --syntax-number: oklch(0.82 0.16 35); --syntax-comment: oklch(0.65 0.02 285); --syntax-function: oklch(0.78 0.16 235); --syntax-type: oklch(0.78 0.14 195); /* ── Chat surfaces (dark) ── */ --chat-user-bg: oklch(0.54 0.2 295); --chat-user-fg: oklch(1 0 0); --chat-assistant-bg: oklch(0.24 0.04 290 / 0.7); --chat-assistant-fg: oklch(0.97 0.005 280); --chat-assistant-border: oklch(1 0 0 / 0.1); --elevation-1: 0 1px 2px oklch(0 0 0 / 0.4); --elevation-2: 0 2px 8px oklch(0 0 0 / 0.4), 0 1px 2px oklch(0 0 0 / 0.3); --elevation-3: 0 4px 16px oklch(0 0 0 / 0.45), 0 2px 4px oklch(0 0 0 / 0.3); --elevation-4: 0 12px 36px oklch(0.4 0.16 295 / 0.18), 0 4px 12px oklch(0 0 0 / 0.5); --elevation-5: 0 20px 56px oklch(0.4 0.16 295 / 0.22), 0 8px 20px oklch(0 0 0 / 0.55); --glass-brightness: 0.92; --glass-saturate: 200%; } /* ── Accent palettes ────────────────────────────────────────────── * Apply by setting `data-palette="sky|rose|sage"` on `` (or any * subtree). Pairs with `.dark`. Violet is the default — no attribute * needed. Calibrated to Prism's L/C scale so the crystal-glass surfaces * stay coherent; we don't try to match Avalon's flatter palette. * Consumed by arcadia-personal-cloud-web's accent picker. */ /* Sky — calm blue, the default consumer accent on me.sky-ai.com. */ [data-palette="sky"] { --primary: oklch(0.55 0.18 235); --primary-foreground: oklch(1 0 0); --accent: oklch(0.93 0.04 235); --accent-foreground: oklch(0.25 0.05 235); --ring: oklch(0.55 0.18 235 / 0.55); --chart-1: oklch(0.55 0.2 235); --sidebar-primary: oklch(0.55 0.18 235); --sidebar-accent: oklch(0.93 0.04 235); --sidebar-accent-foreground: oklch(0.25 0.05 235); --sidebar-ring: oklch(0.55 0.18 235 / 0.55); --chat-user-bg: oklch(0.48 0.18 235); --syntax-keyword: oklch(0.5 0.18 235); } /* Rose — warm coral-pink. */ [data-palette="rose"] { --primary: oklch(0.6 0.2 10); --primary-foreground: oklch(1 0 0); --accent: oklch(0.93 0.05 10); --accent-foreground: oklch(0.28 0.08 10); --ring: oklch(0.6 0.2 10 / 0.55); --chart-1: oklch(0.6 0.22 10); --sidebar-primary: oklch(0.6 0.2 10); --sidebar-accent: oklch(0.93 0.05 10); --sidebar-accent-foreground: oklch(0.28 0.08 10); --sidebar-ring: oklch(0.6 0.2 10 / 0.55); --chat-user-bg: oklch(0.52 0.2 10); --syntax-keyword: oklch(0.55 0.18 10); } /* Sage — calm green, personal and organic. */ [data-palette="sage"] { --primary: oklch(0.55 0.13 155); --primary-foreground: oklch(1 0 0); --accent: oklch(0.92 0.045 150); --accent-foreground: oklch(0.3 0.08 155); --ring: oklch(0.55 0.13 155 / 0.55); --chart-1: oklch(0.55 0.15 155); --sidebar-primary: oklch(0.55 0.13 155); --sidebar-accent: oklch(0.92 0.045 150); --sidebar-accent-foreground: oklch(0.3 0.08 155); --sidebar-ring: oklch(0.55 0.13 155 / 0.55); --chat-user-bg: oklch(0.48 0.13 155); --syntax-keyword: oklch(0.5 0.13 155); } .dark[data-palette="sky"], .dark [data-palette="sky"] { --primary: oklch(0.72 0.18 235); --primary-foreground: oklch(0.14 0.04 235); --accent: oklch(0.32 0.06 235); --accent-foreground: oklch(0.95 0.04 235); --ring: oklch(0.72 0.18 235 / 0.55); --chart-1: oklch(0.7 0.2 235); --sidebar-primary: oklch(0.72 0.18 235); --sidebar-primary-foreground: oklch(0.14 0.04 235); --sidebar-accent: oklch(0.32 0.06 235); --sidebar-accent-foreground: oklch(0.95 0.04 235); --sidebar-ring: oklch(0.72 0.18 235 / 0.55); --chat-user-bg: oklch(0.56 0.18 235); --syntax-keyword: oklch(0.78 0.16 235); } .dark[data-palette="rose"], .dark [data-palette="rose"] { --primary: oklch(0.74 0.18 10); --primary-foreground: oklch(0.16 0.04 10); --accent: oklch(0.32 0.06 10); --accent-foreground: oklch(0.95 0.04 10); --ring: oklch(0.74 0.18 10 / 0.55); --chart-1: oklch(0.72 0.2 10); --sidebar-primary: oklch(0.74 0.18 10); --sidebar-primary-foreground: oklch(0.16 0.04 10); --sidebar-accent: oklch(0.32 0.06 10); --sidebar-accent-foreground: oklch(0.95 0.04 10); --sidebar-ring: oklch(0.74 0.18 10 / 0.55); --chat-user-bg: oklch(0.58 0.2 10); --syntax-keyword: oklch(0.8 0.16 10); } .dark[data-palette="sage"], .dark [data-palette="sage"] { --primary: oklch(0.72 0.13 155); --primary-foreground: oklch(0.14 0.04 155); --accent: oklch(0.3 0.05 155); --accent-foreground: oklch(0.95 0.04 155); --ring: oklch(0.72 0.13 155 / 0.55); --chart-1: oklch(0.7 0.15 155); --sidebar-primary: oklch(0.72 0.13 155); --sidebar-primary-foreground: oklch(0.14 0.04 155); --sidebar-accent: oklch(0.3 0.05 155); --sidebar-accent-foreground: oklch(0.95 0.04 155); --sidebar-ring: oklch(0.72 0.13 155 / 0.55); --chat-user-bg: oklch(0.56 0.13 155); --syntax-keyword: oklch(0.8 0.13 155); } @layer base { body { background-attachment: fixed; min-height: 100vh; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; letter-spacing: -0.011em; font-family: var(--font-sans); font-size: var(--text-body-size); line-height: var(--text-body-lh); } /* Themed text selection — keeps the violet identity. */ ::selection { background-color: oklch(0.55 0.22 295 / 0.28); color: var(--foreground); } .dark ::selection { background-color: oklch(0.7 0.2 295 / 0.4); color: var(--foreground); } /* Themed scrollbars (Firefox + Chromium; macOS overlay ignores both). */ * { scrollbar-width: thin; scrollbar-color: oklch(0 0 0 / 0.18) transparent; } .dark * { scrollbar-color: oklch(1 0 0 / 0.18) transparent; } ::-webkit-scrollbar { width: 10px; height: 10px; } ::-webkit-scrollbar-track { background: transparent; } ::-webkit-scrollbar-thumb { background-color: oklch(0 0 0 / 0.18); border-radius: 999px; border: 2px solid transparent; background-clip: padding-box; } ::-webkit-scrollbar-thumb:hover { background-color: oklch(0 0 0 / 0.28); background-clip: padding-box; } .dark ::-webkit-scrollbar-thumb { background-color: oklch(1 0 0 / 0.18); background-clip: padding-box; } .dark ::-webkit-scrollbar-thumb:hover { background-color: oklch(1 0 0 / 0.28); background-clip: padding-box; } /* Headings get the display family — Instrument Sans's tighter counters * against Inter's open body feel. */ h1, h2, h3, h4, h5, h6, [data-slot="card-title"], [data-slot="dialog-title"], [data-slot="alert-dialog-title"], [data-slot="sheet-title"], [data-slot="drawer-title"] { font-family: var(--font-heading); letter-spacing: -0.02em; font-weight: 600; } /* * ── Light-mode body ── iridescent drift, the brand surface. */ body, body[data-bg="drift"], .bg-variant-drift { background-image: radial-gradient(ellipse 80% 60% at 12% 8%, oklch(0.92 0.09 295 / 0.7), transparent 60%), radial-gradient(ellipse 70% 60% at 88% 14%, oklch(0.93 0.1 350 / 0.7), transparent 55%), radial-gradient(ellipse 80% 60% at 92% 88%, oklch(0.93 0.1 200 / 0.7), transparent 60%), radial-gradient(ellipse 70% 60% at 8% 92%, oklch(0.94 0.09 145 / 0.65), transparent 55%), linear-gradient(180deg, oklch(0.985 0.02 295), oklch(0.96 0.025 320)); } /* * ── Dark-mode body ── deep clean base + four soft corner glows. * * Design: blob L pushed to ~0.30 (vs skyrise's 0.18) so they sit well * above the L=0.10 base — perceived as *light* rather than coloured * fog. Chroma dropped to 0.06–0.09 (vs 0.12–0.14) to stay inside OKLCH * dark-gamut sweet-spot and avoid the gray clip. Base gradient is * near-monochrome (chroma 0.01–0.02) so the accents do all the colour * work — same hue palette as light (purple→pink→cyan→mint), but * articulated through light, not stain. */ html.dark body, html.dark body[data-bg="drift"], html.dark .bg-variant-drift { background-image: radial-gradient(ellipse 70% 55% at 10% 8%, oklch(0.32 0.09 295 / 0.65), transparent 60%), radial-gradient(ellipse 60% 50% at 90% 14%, oklch(0.30 0.09 340 / 0.60), transparent 55%), radial-gradient(ellipse 70% 55% at 92% 90%, oklch(0.28 0.07 200 / 0.55), transparent 60%), radial-gradient(ellipse 60% 50% at 8% 92%, oklch(0.30 0.06 145 / 0.50), transparent 55%), linear-gradient(180deg, oklch(0.10 0.012 285), oklch(0.08 0.018 295)); } /* * Animated drift layer — two large radial-blob fields that translate * and rotate slowly, driving the chroma the glass refracts. */ [data-slot="aurora-field"] { display: none; } body[data-bg="drift"] [data-slot="aurora-field"], body:not([data-bg]) [data-slot="aurora-field"] { display: block; } .aurora-blob { position: absolute; inset: -25%; background-repeat: no-repeat; will-change: transform; } .aurora-blob-1 { background-image: radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.9 0.13 295 / 0.85), transparent 60%), radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.9 0.13 350 / 0.8), transparent 55%); animation: prism-drift-a 32s ease-in-out infinite; } .aurora-blob-2 { background-image: radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.9 0.14 200 / 0.8), transparent 60%), radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.92 0.12 145 / 0.75), transparent 55%); animation: prism-drift-b 40s ease-in-out infinite; } /* Dark variant of the drifting aurora — same L/chroma discipline as * the static dark base above. Same hues, tame chroma, well above base. */ html.dark .aurora-blob-1 { background-image: radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.32 0.09 295 / 0.55), transparent 60%), radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.30 0.10 340 / 0.50), transparent 55%); } html.dark .aurora-blob-2 { background-image: radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.28 0.08 200 / 0.50), transparent 60%), radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.30 0.07 145 / 0.45), transparent 55%); } /* * ── Calm variant ── opt-in via body[data-bg="calm"]. Quieter AND * narrower than drift: corner gradients drop to ~45% alpha, the * drift layer dims to match, and the hue story tightens from the * full rainbow (violet/pink/cyan/mint) to an analogous violet * family (periwinkle 245 → lavender 280 → violet 295 → pink 330). * The cyan/green corners sat opposite the violet brand on the hue * wheel and made consumer pages read as four different brands at * once. For consumer surfaces (me.sky-ai.com) where full-strength * drift floods short pages and the app reads as a white card * floating on a poster. */ body[data-bg="calm"] { background-image: radial-gradient(ellipse 80% 60% at 12% 8%, oklch(0.92 0.09 295 / 0.32), transparent 60%), radial-gradient(ellipse 70% 60% at 88% 14%, oklch(0.93 0.09 330 / 0.30), transparent 55%), radial-gradient(ellipse 80% 60% at 92% 88%, oklch(0.93 0.08 245 / 0.30), transparent 60%), radial-gradient(ellipse 70% 60% at 8% 92%, oklch(0.94 0.07 280 / 0.28), transparent 55%), linear-gradient(180deg, oklch(0.985 0.012 295), oklch(0.97 0.015 310)); } html.dark body[data-bg="calm"] { background-image: radial-gradient(ellipse 70% 55% at 10% 8%, oklch(0.32 0.09 295 / 0.65), transparent 60%), radial-gradient(ellipse 60% 50% at 90% 14%, oklch(0.30 0.08 330 / 0.60), transparent 55%), radial-gradient(ellipse 70% 55% at 92% 90%, oklch(0.28 0.06 245 / 0.55), transparent 60%), radial-gradient(ellipse 60% 50% at 8% 92%, oklch(0.30 0.05 280 / 0.50), transparent 55%), linear-gradient(180deg, oklch(0.10 0.012 285), oklch(0.08 0.018 295)); } body[data-bg="calm"] [data-slot="aurora-field"] { display: block; } body[data-bg="calm"] .aurora-blob { opacity: 0.4; } html.dark body[data-bg="calm"] .aurora-blob { opacity: 0.7; } /* Calm drift blobs ride the same narrowed violet-family hues. */ body[data-bg="calm"] .aurora-blob-1 { background-image: radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.9 0.11 295 / 0.85), transparent 60%), radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.9 0.1 330 / 0.8), transparent 55%); } body[data-bg="calm"] .aurora-blob-2 { background-image: radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.9 0.1 245 / 0.8), transparent 60%), radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.92 0.08 280 / 0.75), transparent 55%); } html.dark body[data-bg="calm"] .aurora-blob-1 { background-image: radial-gradient(ellipse 44% 36% at 22% 28%, oklch(0.32 0.09 295 / 0.55), transparent 60%), radial-gradient(ellipse 38% 32% at 78% 22%, oklch(0.30 0.08 330 / 0.50), transparent 55%); } html.dark body[data-bg="calm"] .aurora-blob-2 { background-image: radial-gradient(ellipse 48% 38% at 82% 74%, oklch(0.28 0.06 245 / 0.50), transparent 60%), radial-gradient(ellipse 42% 34% at 16% 80%, oklch(0.30 0.05 280 / 0.45), transparent 55%); } @keyframes prism-drift-a { 0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); } 33% { transform: translate3d(5%, -3%, 0) rotate(10deg) scale(1.07); } 66% { transform: translate3d(-3%, 4%, 0) rotate(-8deg) scale(0.96); } } @keyframes prism-drift-b { 0%, 100% { transform: translate3d(0, 0, 0) rotate(0deg) scale(1); } 33% { transform: translate3d(-5%, 4%, 0) rotate(-12deg) scale(1.09); } 66% { transform: translate3d(4%, -3%, 0) rotate(8deg) scale(0.94); } } @media (prefers-reduced-motion: reduce) { .aurora-blob { animation: none; } } /* * ── Glass surfaces ── Apple-vibrancy stack on every shadcn surface * that exposes a [data-slot]. blur softens, saturate pumps the * gradient chroma the glass is sampling, brightness/contrast keep * edges legible. */ [data-slot="card"], [data-slot="popover-content"], [data-slot="dropdown-menu-content"], [data-slot="context-menu-content"], [data-slot="menubar-content"], [data-slot="hover-card-content"], [data-slot="select-content"], [data-slot="combobox-content"], [data-slot="command"], [data-slot="tooltip-content"], [data-slot="sheet-content"], [data-slot="dialog-content"], [data-slot="alert-dialog-content"], [data-slot="drawer-content"], [data-slot="sidebar"] { position: relative; backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(var(--glass-brightness)) contrast(var(--glass-contrast)); -webkit-backdrop-filter: blur(var(--glass-blur)) saturate(var(--glass-saturate)) brightness(var(--glass-brightness)) contrast(var(--glass-contrast)); transition-timing-function: var(--ease-spring-snappy); animation-timing-function: var(--ease-spring-snappy); animation-duration: var(--duration-spring); } /* Springy press feel on interactive bits. */ [data-slot="button"], [data-slot="chip"], [data-slot="toggle"], [data-slot="item"] { transition-timing-function: var(--ease-spring-bouncy); transition-duration: var(--duration-fast); } /* * Premium primary button — gradient derived from --primary (subtle * ±12° hue sweep) + top-edge sheen. Deriving rather than hardcoding * keeps buttons on-brand with whatever --primary resolves to: the * old fixed 290→350 sweep ended in hot pink, so CTAs read magenta * against violet nav/links — and ignored the data-palette accents. */ [data-slot="button"].bg-primary { background-image: linear-gradient( 135deg, oklch(from var(--primary) calc(l + 0.04) c calc(h - 12)) 0%, var(--primary) 50%, oklch(from var(--primary) calc(l - 0.02) c calc(h + 14)) 100% ); position: relative; isolation: isolate; } [data-slot="button"].bg-primary::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background: linear-gradient( 180deg, oklch(1 0 0 / 0.35) 0, oklch(1 0 0 / 0.08) 45%, oklch(1 0 0 / 0) 60% ); mix-blend-mode: plus-lighter; } /* Dark needs no gradient override — it derives from dark --primary. */ .dark [data-slot="button"].bg-primary::after { background: linear-gradient( 180deg, oklch(1 0 0 / 0.18) 0, oklch(1 0 0 / 0.04) 45%, oklch(1 0 0 / 0) 60% ); } /* * Premium card padding — roomy 24px vs the lib's compact 16px. */ [data-slot="card"], [data-slot="dialog-content"], [data-slot="alert-dialog-content"], [data-slot="sheet-content"], [data-slot="drawer-content"], [data-slot="popover-content"] { --card-padding: calc(var(--spacing) * 6); gap: calc(var(--spacing) * 5); } [data-slot="card-header"], [data-slot="card-content"], [data-slot="card-footer"] { padding-inline: var(--card-padding, calc(var(--spacing) * 6)); } /* * AI orb avatar — any avatar fallback marked `data-ai` gets the * rainbow gradient signature. */ [data-slot="avatar-fallback"][data-ai] { background-image: conic-gradient( from 210deg at 50% 50%, oklch(0.6 0.24 295) 0deg, oklch(0.7 0.22 350) 90deg, oklch(0.78 0.18 35) 180deg, oklch(0.7 0.18 200) 270deg, oklch(0.6 0.24 295) 360deg ); background-color: transparent; color: oklch(1 0 0); font-weight: 600; position: relative; } [data-slot="avatar-fallback"][data-ai]::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background: linear-gradient( 180deg, oklch(1 0 0 / 0.3) 0, oklch(1 0 0 / 0) 50% ); mix-blend-mode: plus-lighter; } .dark [data-slot="avatar-fallback"][data-ai] { background-image: conic-gradient( from 210deg at 50% 50%, oklch(0.7 0.22 295) 0deg, oklch(0.78 0.2 350) 90deg, oklch(0.84 0.16 35) 180deg, oklch(0.78 0.16 200) 270deg, oklch(0.7 0.22 295) 360deg ); } /* * Inner top highlight — the wet-glass sheen Apple uses on surfaces. */ [data-slot="card"]::after, [data-slot="popover-content"]::after, [data-slot="dropdown-menu-content"]::after, [data-slot="context-menu-content"]::after, [data-slot="menubar-content"]::after, [data-slot="hover-card-content"]::after, [data-slot="select-content"]::after, [data-slot="combobox-content"]::after, [data-slot="command"]::after, [data-slot="tooltip-content"]::after, [data-slot="sheet-content"]::after, [data-slot="dialog-content"]::after, [data-slot="alert-dialog-content"]::after, [data-slot="drawer-content"]::after, [data-slot="sidebar"]::after { content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; background: linear-gradient( 180deg, oklch(1 0 0 / 0.6) 0, oklch(1 0 0 / 0) 1.5px, oklch(1 0 0 / 0.14) 1.5px, oklch(1 0 0 / 0) 35% ); mix-blend-mode: plus-lighter; } .dark [data-slot="card"]::after, .dark [data-slot="popover-content"]::after, .dark [data-slot="dropdown-menu-content"]::after, .dark [data-slot="context-menu-content"]::after, .dark [data-slot="menubar-content"]::after, .dark [data-slot="hover-card-content"]::after, .dark [data-slot="select-content"]::after, .dark [data-slot="combobox-content"]::after, .dark [data-slot="command"]::after, .dark [data-slot="tooltip-content"]::after, .dark [data-slot="sheet-content"]::after, .dark [data-slot="dialog-content"]::after, .dark [data-slot="alert-dialog-content"]::after, .dark [data-slot="drawer-content"]::after, .dark [data-slot="sidebar"]::after { background: linear-gradient( 180deg, oklch(1 0 0 / 0.2) 0, oklch(1 0 0 / 0) 1.5px, oklch(1 0 0 / 0.05) 1.5px, oklch(1 0 0 / 0) 35% ); } /* * ── `.num` utility ── Apply to any element that displays money or * counts. Forces tabular monospaced digits, the unambiguous slashed- * zero stylistic set Inter ships, and resets the body's negative * tracking that would otherwise crash digits into each other. */ .num { font-feature-settings: "tnum", "ss01", "cv01"; font-variant-numeric: tabular-nums; letter-spacing: 0; } } /* ── Root size & font-scale ── * 18px root by default. Body lands ~19px once the --text-body-size * 1.0625rem multiplier applies. The data-font-scale hook lets the * consuming app expose a user-facing size toggle. */ @layer base { html { font-size: 18px; } html[data-font-scale="sm"] { font-size: 16px; } html[data-font-scale="md"] { font-size: 18px; } html[data-font-scale="lg"] { font-size: 20px; } html[data-font-scale="xl"] { font-size: 22px; } }