@tailwind base; @tailwind components; @tailwind utilities; /* Theme palettes. The Tailwind color tokens (tailwind.config.js) resolve to these CSS variables, so setting `data-theme` on re-themes the whole app. `:root` is the default (Classic Cream) palette, also used when no/an unknown data-theme is set. Each named theme overrides the same ten tokens. Keep this list in sync with the registry in src/lib/theme.js. */ :root, [data-theme='classic'] { --color-surface: #f7f3ec; --color-surface-raised: #ffffff; --color-surface-sunken: #ede8de; --color-border: #d4c9b4; --color-text-primary: #1c1a16; --color-text-secondary: #6b6354; --color-accent: #4a6741; --color-accent-hover: #3a5233; --color-accent-warm: #c47d2e; --color-danger: #b34040; } /* Dashboard stat-tile tokens. Defined once here on :root so EVERY theme inherits them (theme blocks below don't redefine them), and they resolve through the per-theme color tokens — so by default the eight tiles all read as a plain raised surface, exactly like the rest of the app. The vibrant `carnival` theme below overrides each tile with its own color. The tile foreground vars let the colored variant flip to light text without touching the global text tokens. Dashboard.jsx references these as literal `bg-[var(--stat-N)]` classes (Tailwind only generates classes it can see as complete strings, so the per-tile names are spelled out, not built up). */ :root { /* Text on accent-warm fills (the For Sale badge, "Check" flags). The warm oranges are too light for white text in the light themes, so this is the theme's dark ink everywhere — on Midnight that's the surface color. */ --color-on-accent-warm: var(--color-text-primary); --stat-fg: var(--color-text-primary); --stat-fg-muted: var(--color-text-secondary); --stat-1: var(--color-surface-raised); --stat-2: var(--color-surface-raised); --stat-3: var(--color-surface-raised); --stat-4: var(--color-surface-raised); --stat-5: var(--color-surface-raised); --stat-6: var(--color-surface-raised); --stat-7: var(--color-surface-raised); --stat-8: var(--color-surface-raised); --stat-1-hover: var(--color-surface-sunken); --stat-2-hover: var(--color-surface-sunken); --stat-3-hover: var(--color-surface-sunken); --stat-4-hover: var(--color-surface-sunken); --stat-5-hover: var(--color-surface-sunken); --stat-6-hover: var(--color-surface-sunken); --stat-7-hover: var(--color-surface-sunken); --stat-8-hover: var(--color-surface-sunken); } /* Dark theme: accent-hover is *lighter* than accent (the opposite of the light themes), since a darker hover would disappear against dark surfaces. */ [data-theme='midnight'] { --color-surface: #1a1d1a; --color-surface-raised: #242823; --color-surface-sunken: #151814; --color-border: #3a3f38; --color-text-primary: #ece8e0; --color-text-secondary: #a8a294; --color-accent: #7fa56e; --color-accent-hover: #94b884; --color-accent-warm: #d9954a; --color-danger: #d46a6a; --color-on-accent-warm: var(--color-surface); } [data-theme='ocean'] { --color-surface: #f0f5f8; --color-surface-raised: #ffffff; --color-surface-sunken: #e1eaf0; --color-border: #c2d3de; --color-text-primary: #14222b; --color-text-secondary: #516a79; --color-accent: #2e6e8e; --color-accent-hover: #245870; --color-accent-warm: #e0913b; --color-danger: #c0504d; } [data-theme='berry'] { --color-surface: #f8f2f6; --color-surface-raised: #ffffff; --color-surface-sunken: #efe2ea; --color-border: #dcc6d3; --color-text-primary: #2a1a26; --color-text-secondary: #7a6070; --color-accent: #9b3b6e; --color-accent-hover: #7e2d58; --color-accent-warm: #c9762e; --color-danger: #c0392b; } [data-theme='sunset'] { --color-surface: #fbf3ec; --color-surface-raised: #ffffff; --color-surface-sunken: #f4e6da; --color-border: #e6cdb8; --color-text-primary: #2a1c14; --color-text-secondary: #7a604d; --color-accent: #b84a26; --color-accent-hover: #9a3d1c; --color-accent-warm: #e0913b; --color-danger: #b33a3a; } /* Carnival: the deliberately loud theme. A clean light base lets the multi-colored dashboard tiles (overridden below) pop. The stat tiles flip to white text via --stat-fg. */ [data-theme='carnival'] { --color-surface: #faf7fd; --color-surface-raised: #ffffff; --color-surface-sunken: #f0eaf7; --color-border: #e2d9ec; --color-text-primary: #1b1228; --color-text-secondary: #6a5c7c; --color-accent: #7c3aed; --color-accent-hover: #6d28d9; --color-accent-warm: #ea580c; --color-danger: #e11d48; --stat-fg: #ffffff; --stat-fg-muted: rgba(255, 255, 255, 0.82); --stat-1: #7c3aed; /* herd — violet */ --stat-2: #2563eb; /* bucks — blue */ --stat-3: #db2777; /* does — pink */ --stat-4: #ea580c; /* kits — orange */ --stat-5: #059669; /* for sale — green*/ --stat-6: #d97706; /* on hold — amber */ --stat-7: #0891b2; /* sold — cyan */ --stat-8: #475569; /* archived — slate*/ --stat-1-hover: #6d28d9; --stat-2-hover: #1d4ed8; --stat-3-hover: #be185d; --stat-4-hover: #c2410c; --stat-5-hover: #047857; --stat-6-hover: #b45309; --stat-7-hover: #0e7490; --stat-8-hover: #334155; } /* Theme-aware form controls. Inputs/textareas/selects across the app don't set their own background or text color, so without this they fall back to the browser default (white background, near-black text) — fine on the light themes (where it matches `surface-raised`) but unreadable on the dark Midnight theme, which renders a glaring white box with washed-out placeholder text. Tying the controls to the theme tokens keeps them legible everywhere without touching each component. */ @layer base { input:not([type='checkbox']):not([type='radio']):not([type='file']):not([type='range']):not([type='color']), textarea, select { background-color: var(--color-surface-raised); color: var(--color-text-primary); } /* iOS Safari zooms the page when focusing a control whose font-size is under 16px, which is jarring in the installed PWA. Most controls use text-sm, so bump them to 16px on small screens only; desktop keeps the denser size. */ @media (max-width: 767px) { input:not([type='checkbox']):not([type='radio']):not([type='file']):not([type='range']):not([type='color']), textarea, select { font-size: 16px; } } input::placeholder, textarea::placeholder { color: var(--color-text-secondary); opacity: 1; } } /* `!important` is deliberate: several inputs/buttons already set `focus:outline-none` (paired with their own `focus:ring-2`) which would otherwise win on specificity over a plain `:focus-visible` rule and leave keyboard focus invisible on exactly the elements that most need it. This guarantees every focusable element gets a visible accent-colored ring on keyboard focus, app-wide, without auditing each component individually. */ :focus-visible { outline: 2px solid theme('colors.accent') !important; outline-offset: 2px; } @media (prefers-reduced-motion: reduce) { *, *::before, *::after { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } }