@import "tailwindcss"; @import "tw-animate-css"; @import "shadcn/tailwind.css"; /* * Exclude planning + docs directories from Tailwind v4's content scan. * * v4's scanner walks the entire project root by default and picks any * class-shaped token out of every text file. Planning reports and * design docs often quote literal class-name fragments such as * `bg-[var(...)]/12` as examples, and the bracketed-CSS-variable form * combined with an opacity modifier generates an escaped selector that * Turbopack's CSS parser rejects with `Unexpected token Delim('.')`, * 500-ing every page. Constraining the scan to source code avoids * fixture-style strings poisoning the generated CSS. */ @source not "../../.planning"; @source not "../../docs"; @custom-variant dark (&:is(.dark *)); @theme inline { --color-background: var(--background); --color-foreground: var(--foreground); --font-sans: var(--font-sans); --font-mono: var(--font-mono); --color-sidebar-ring: var(--sidebar-ring); --color-sidebar-border: var(--sidebar-border); --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); --color-sidebar-accent: var(--sidebar-accent); --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); --color-sidebar-primary: var(--sidebar-primary); --color-sidebar-foreground: var(--sidebar-foreground); --color-sidebar: var(--sidebar); --color-chart-5: var(--chart-5); --color-chart-4: var(--chart-4); --color-chart-3: var(--chart-3); --color-chart-2: var(--chart-2); --color-chart-1: var(--chart-1); --color-ring: var(--ring); --color-input: var(--input); --color-border: var(--border); --color-destructive: var(--destructive); --color-accent-foreground: var(--accent-foreground); --color-accent: var(--accent); --color-muted-foreground: var(--muted-foreground); --color-muted: var(--muted); --color-secondary-foreground: var(--secondary-foreground); --color-secondary: var(--secondary); --color-primary-foreground: var(--primary-foreground); --color-primary: var(--primary); --color-popover-foreground: var(--popover-foreground); --color-popover: var(--popover); --color-card-foreground: var(--card-foreground); --color-card: var(--card); --radius-sm: calc(var(--radius) - 4px); --radius-md: calc(var(--radius) - 2px); --radius-lg: var(--radius); --radius-xl: calc(var(--radius) + 4px); --radius-2xl: calc(var(--radius) + 8px); --radius-3xl: calc(var(--radius) + 12px); --radius-4xl: calc(var(--radius) + 16px); /* Dracula semantic colors for charts */ --color-dracula-purple: var(--dracula-purple); --color-dracula-pink: var(--dracula-pink); --color-dracula-green: var(--dracula-green); --color-dracula-cyan: var(--dracula-cyan); --color-dracula-orange: var(--dracula-orange); --color-dracula-red: var(--dracula-red); --color-dracula-yellow: var(--dracula-yellow); --color-dracula-lavender: var(--dracula-lavender); /* * Semantic feedback tokens — aliases over the Dracula palette so badges, * banners, and status pills can stop hard-coding `text-dracula-green` / * `bg-dracula-orange/15` and ask for the *meaning* instead. Each is a * straight alias of the existing colour at the time of introduction so * the visual stays pixel-identical to v1.4.6 — what changes is intent. * - success → dracula-green (positive outcome, e.g. published) * - warning → dracula-orange (caution / non-blocking attention) * - info → dracula-cyan (neutral informational note) */ --color-success: var(--success); --color-warning: var(--warning); --color-info: var(--info); } /* * Dracula Theme * Based on https://draculatheme.com/contribute * Mapped to shadcn/ui CSS variable system */ /* ── Dracula palette (shared) ────────────────────── */ :root { --dracula-bg: #282a36; --dracula-current: #44475a; --dracula-fg: #f8f8f2; --dracula-comment: #9aa3b3; --dracula-cyan: #8be9fd; --dracula-green: #50fa7b; --dracula-orange: #ffb86c; --dracula-pink: #ff79c6; --dracula-purple: #bd93f9; --dracula-red: #ff5555; --dracula-yellow: #f1fa8c; --dracula-lavender: #d6acff; /* * Semantic feedback tokens (see @theme `--color-success` / `--color-warning` * / `--color-info` re-exports). Aliased over the Dracula palette so existing * dark-mode visuals stay identical; light mode (Alucard) below provides the * higher-contrast counterpart so AA contrast lands on the white card. */ --success: var(--dracula-green); --warning: var(--dracula-orange); --info: var(--dracula-cyan); --radius: 0.625rem; } /* ── Dark mode (default) ─────────────────────────── */ :root.dark { --background: #282a36; --foreground: #f8f8f2; --card: #1e1f29; --card-foreground: #f8f8f2; --popover: #1e1f29; --popover-foreground: #f8f8f2; --primary: #bd93f9; --primary-foreground: #282a36; --secondary: #44475a; --secondary-foreground: #f8f8f2; --muted: #44475a; --muted-foreground: #9aa3b3; --accent: #44475a; --accent-foreground: #f8f8f2; --destructive: #ff5555; --border: #44475a; --input: #44475a; --ring: #bd93f9; --chart-1: #bd93f9; --chart-2: #50fa7b; --chart-3: #ff79c6; --chart-4: #8be9fd; --chart-5: #ffb86c; --sidebar: #1e1f29; --sidebar-foreground: #f8f8f2; --sidebar-primary: #bd93f9; --sidebar-primary-foreground: #f8f8f2; --sidebar-accent: #44475a; --sidebar-accent-foreground: #f8f8f2; --sidebar-border: #44475a; --sidebar-ring: #bd93f9; color-scheme: dark; } /* ── Light mode (Alucard — official Dracula light) ── */ :root.light { --background: #f5f5f5; --foreground: #1f1f1f; --card: #ffffff; --card-foreground: #1f1f1f; --popover: #ffffff; --popover-foreground: #1f1f1f; --primary: #644ac9; --primary-foreground: #ffffff; --secondary: #dcdeef; --secondary-foreground: #1f1f1f; --muted: #dcdeef; --muted-foreground: #5b6273; --accent: #dcdeef; --accent-foreground: #1f1f1f; --destructive: #cb3a2a; /* * Alucard light-mode overrides for the semantic tokens — straight Dracula * green/orange/cyan would fail AA contrast on a white card. These match the * darker palette already used for `--destructive`/`--chart-*` in light mode. */ --success: #14720a; --warning: #a34d14; --info: #036a96; --border: #cfcfde; --input: #cfcfde; --ring: #644ac9; --chart-1: #644ac9; --chart-2: #14720a; --chart-3: #a3134d; --chart-4: #036a96; --chart-5: #a34d14; --sidebar: #ffffff; --sidebar-foreground: #1f1f1f; --sidebar-primary: #644ac9; --sidebar-primary-foreground: #ffffff; --sidebar-accent: #dcdeef; --sidebar-accent-foreground: #1f1f1f; --sidebar-border: #cfcfde; --sidebar-ring: #644ac9; color-scheme: light; } @layer base { * { @apply border-border outline-ring/50; } body { @apply bg-background text-foreground; } p { color: var(--foreground); } } /* * `.no-scrollbar` — keeps a container scrollable but hides the visible * bar. Used by the mobile section strips in `` and * `` so 13 admin / 10 settings entries can swipe * horizontally without painting an always-on scrollbar at the top of * every admin/settings page (a recurring maintainer complaint — most * recently mistaken for a `/admin/api-tokens` table scrollbar in * v1.4.16/17 because the strip sits right above the api-tokens card). * * Standard `scrollbar-width: none` (Firefox) + `::-webkit-scrollbar` * (Chromium/WebKit) covers every browser HealthLog targets. Touch * scrolling, keyboard arrow scrolling, and `Tab` focus traversal all * keep working — this is a purely cosmetic suppression, not an * `overflow: hidden`. */ .no-scrollbar { scrollbar-width: none; -ms-overflow-style: none; } .no-scrollbar::-webkit-scrollbar { display: none; } /* ── Insight card animations ─────────────────────── */ @keyframes insight-fade-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } } .animate-insight-in { animation: insight-fade-in 0.4s ease-out forwards; } @media (prefers-reduced-motion: reduce) { .animate-insight-in { animation: none; } } /* ── v1.4.20 phase B1 — Insights redesign hero strip ─────────────── */ /* * `.hero-gradient` — purple → pink linear gradient at low opacity, for * the new band on /insights. Sits above `var(--card)` so * the band reads as a richer surface than the card it overlays. * * Matches the design handoff (`prototype/artboard-fullpage.jsx → * BriefingHero` background) — purple/pink at ~12% opacity over the * card colour, with a subtle border-tint to anchor it on the dark bg. */ .hero-gradient { background: linear-gradient( 135deg, color-mix(in srgb, var(--dracula-purple) 18%, var(--card)) 0%, color-mix(in srgb, var(--dracula-pink) 12%, var(--card)) 100% ); border: 1px solid color-mix(in srgb, var(--dracula-purple) 24%, transparent); } /* * `.glow-purple` — soft purple aura behind the hero card, painted via * `box-shadow` so it stays GPU-cheap and respects the existing card * border radius without an extra wrapper element. */ .glow-purple { box-shadow: 0 0 0 1px color-mix(in srgb, var(--dracula-purple) 16%, transparent), 0 18px 48px -28px color-mix(in srgb, var(--dracula-purple) 50%, transparent); } /* * `pulseDot` keyframes — the "live, refreshed N min ago" green dot in * the hero meta row. Used as `.pulse-dot { animation: pulseDot ... }`. * Reduced-motion users get a static dot via the prefers-reduced-motion * guard below. */ @keyframes pulseDot { 0%, 100% { opacity: 1; transform: scale(1); } 50% { opacity: 0.5; transform: scale(0.85); } } .pulse-dot { animation: pulseDot 1.8s ease-in-out infinite; } @media (prefers-reduced-motion: reduce) { .pulse-dot { animation: none; } }