/* * Balinyaar brand color tokens — source of truth for all colors. * * Brand identity (construction + rationale): .claude/skills/frontend-designer/SKILL.md. * #1d4a40 deep teal / forest-green → brand primary * #d98c6a terracotta → brand accent (secondary) * #f3efe9 soft cream → text-on-dark / glyph fill * #faf9f5 cream → page surface * * MUI sets data-mui-color-scheme="dark" on when dark mode is active * (colorSchemeSelector: 'data-mui-color-scheme' in createTheme). The same * attribute drives every custom CSS rule in this file. You never need to * read or write this attribute manually — MUI's useColorScheme() does it for * you at runtime. * * No-flash boot (no JS): when a returning visitor's `color-scheme` cookie is * present, the server stamps the attribute directly and the explicit * `[data-mui-color-scheme]` blocks below apply immediately — zero flash. On a * cookie-less FIRST visit the server renders WITHOUT the attribute * (see lib/cookies/server.ts getThemeMode()), so the `@media * (prefers-color-scheme: dark)` block below — scoped to the attribute being * absent — paints the OS-preferred scheme immediately, with no script. Once * MUI hydrates (ThemeProvider defaultMode="system") it resolves the same * media query and stamps the attribute itself; the values already match, so * there is nothing to visibly flip. The dark values therefore appear twice * below (the media-query fallback + the explicit attribute block) — keep * both in sync when changing a dark-scheme value. * * Usage in custom CSS outside MUI: * color: var(--bal-primary); ← resolves to the active scheme value * background: var(--bal-bg-default); * * Sync rule: any color added/changed here also lands in colors.ts (LIGHT_PALETTE/ * DARK_PALETTE) when it's palette-level (success/error/warning/info, primary, * secondary…). Non-palette tokens (elevation, radius, motion, focus, rating, * trust, money-emphasis) are define-only here — colors.ts never needs them. */ /* ── Scheme-independent tokens (radius scale, motion) ──────────────────── */ :root { /* Radius scale — controls / cards / dialogs. shape.borderRadius (theme.ts) mirrors --bal-radius-md; never invent a radius per component. */ --bal-radius-sm: 4px; --bal-radius-md: 10px; --bal-radius-lg: 16px; /* Motion — durations + easing, consumed by the phase-12 motion pass */ --bal-motion-fast: 120ms; --bal-motion-base: 200ms; --bal-motion-slow: 300ms; --bal-easing-standard: cubic-bezier(0.4, 0, 0.2, 1); } /* * Reduced motion — the token half of the single gate (globals.css carries the universal * transition/animation-duration override that makes this bite even for consumers, like MUI's own * Dialog/Drawer/Menu transitions, that don't read these custom properties directly). Zeroing the * durations here too means anything that DOES read the token (this file's own consumers, any future * one) needs no reduced-motion branch of its own. */ @media (prefers-reduced-motion: reduce) { :root { --bal-motion-fast: 0ms; --bal-motion-base: 0ms; --bal-motion-slow: 0ms; } } /* ── Light scheme — the unconditional default ──────────────────────────── */ :root, [data-mui-color-scheme='light'] { /* Primary — deep teal */ --bal-primary: #1d4a40; --bal-primary-light: #2f6b5e; --bal-primary-dark: #123029; --bal-primary-contrast: #f3efe9; /* Soft primary tint — selected chips, subtle info panels */ --bal-primary-soft: rgba(29, 74, 64, 0.10); /* Secondary — terracotta */ --bal-secondary: #d98c6a; --bal-secondary-light: #e6a98a; --bal-secondary-dark: #bf6f4d; --bal-secondary-contrast: #2a1a12; /* Soft terracotta tint — the "نمای پرستار" nurse-view chip + EVV/financial affordances */ --bal-secondary-soft: rgba(217, 140, 106, 0.14); /* Surfaces */ --bal-bg-default: #faf9f5; --bal-bg-paper: #ffffff; /* Text */ --bal-text-primary: #1b2521; --bal-text-secondary: #5b655f; /* Divider */ --bal-divider: rgba(29, 74, 64, 0.14); /* Feedback — toast / alert backgrounds (brand-harmonized; cream text) */ --bal-success: #1f6b50; --bal-success-contrast: #f3efe9; --bal-error: #a8392a; --bal-error-contrast: #f3efe9; --bal-warning: #8a6418; --bal-warning-contrast: #f3efe9; --bal-info: #1d4a40; --bal-info-contrast: #f3efe9; /* Soft feedback tints — StatusChip v2's default (soft bg + solid text); solid fill is reserved for the alarm tier only. Weight hierarchy: neutral < info < progress < success < warning < alarm (see StatusChip.tsx). */ --bal-success-soft: rgba(31, 107, 80, 0.12); --bal-error-soft: rgba(168, 57, 42, 0.12); --bal-warning-soft: rgba(138, 100, 24, 0.14); --bal-info-soft: rgba(29, 74, 64, 0.10); /* Elevation — teal-tinted shadow steps (replaces MUI's grey default stack). Consumed by theme.ts's `shadows` array + the MuiPaper/MuiDialog overrides. */ --bal-shadow-1: 0 1px 2px rgba(29, 74, 64, 0.06), 0 1px 1px rgba(29, 74, 64, 0.04); --bal-shadow-2: 0 4px 12px rgba(29, 74, 64, 0.10), 0 2px 4px rgba(29, 74, 64, 0.06); --bal-shadow-3: 0 12px 32px rgba(29, 74, 64, 0.14), 0 4px 8px rgba(29, 74, 64, 0.08); /* Focus ring — global :focus-visible treatment (MuiCssBaseline, theme.ts) */ --bal-focus-ring: #1d4a40; /* Rating stars — RatingInput's star fill/empty (retires the muddy --bal-warning use) */ --bal-rating: #c8971e; --bal-rating-empty: rgba(29, 74, 64, 0.20); /* Trust — a distinct identity for verified marks, separate from primary/success */ --bal-trust: #2b6ca8; --bal-trust-soft: rgba(43, 108, 168, 0.12); /* Money emphasis — AA-contrast-safe money-text color (terracotta itself fails AA at small sizes on white: #d98c6a ≈ 2:1). Never use --bal-secondary for small money text; use this instead. */ --bal-money-emphasis: #8a4a2f; /* Avatar — warm auto-colored initials (ui-phase-9). A person with no photo (a care-circle patient, the account holder) gets a deterministic hue from this 6-pair palette (name hash → index), never a hex baked into a component. Each pair is a distinct warm/calm hue harmonized with the brand teal/terracotta, not reused from primary/secondary/feedback. */ --bal-avatar-1: #2f6b5e; --bal-avatar-1-contrast: #f3efe9; --bal-avatar-2: #b56b3f; --bal-avatar-2-contrast: #f3efe9; --bal-avatar-3: #6b5b95; --bal-avatar-3-contrast: #f3efe9; --bal-avatar-4: #3f7690; --bal-avatar-4-contrast: #f3efe9; --bal-avatar-5: #8a6418; --bal-avatar-5-contrast: #f3efe9; --bal-avatar-6: #5c7a4a; --bal-avatar-6-contrast: #f3efe9; /* Map pin drop-shadow — was a hard-coded rgba() in AddressMapPicker; a plain black shadow reads the same in both schemes so it isn't teal-tinted like --bal-shadow-*. */ --bal-pin-shadow: rgba(0, 0, 0, 0.35); } /* ── Dark scheme — OS-preference fallback for the cookie-less first visit ── */ @media (prefers-color-scheme: dark) { :root:not([data-mui-color-scheme]) { --bal-primary: #6fc0ac; --bal-primary-light: #8fd2c1; --bal-primary-dark: #3f8a78; --bal-primary-contrast: #06120f; --bal-primary-soft: rgba(111, 192, 172, 0.16); --bal-secondary: #e6a98a; --bal-secondary-light: #f0bfa3; --bal-secondary-dark: #d98c6a; --bal-secondary-contrast: #2a1a12; --bal-secondary-soft: rgba(230, 169, 138, 0.18); --bal-bg-default: #0f1c19; --bal-bg-paper: #16302a; --bal-text-primary: #f3efe9; --bal-text-secondary: #9fb0a9; --bal-divider: rgba(243, 239, 233, 0.14); --bal-success: #257659; --bal-success-contrast: #f3efe9; --bal-error: #b5402f; --bal-error-contrast: #f3efe9; --bal-warning: #97701f; --bal-warning-contrast: #f3efe9; --bal-info: #2f6b5e; --bal-info-contrast: #f3efe9; --bal-success-soft: rgba(37, 118, 89, 0.18); --bal-error-soft: rgba(181, 64, 47, 0.18); --bal-warning-soft: rgba(151, 112, 31, 0.20); --bal-info-soft: rgba(47, 107, 94, 0.16); --bal-shadow-1: 0 1px 2px rgba(6, 18, 15, 0.24), 0 1px 1px rgba(6, 18, 15, 0.16); --bal-shadow-2: 0 4px 12px rgba(6, 18, 15, 0.32), 0 2px 4px rgba(6, 18, 15, 0.20); --bal-shadow-3: 0 12px 32px rgba(6, 18, 15, 0.40), 0 4px 8px rgba(6, 18, 15, 0.24); --bal-focus-ring: #6fc0ac; --bal-rating: #e0b542; --bal-rating-empty: rgba(243, 239, 233, 0.20); --bal-trust: #7fb8e6; --bal-trust-soft: rgba(127, 184, 230, 0.18); --bal-money-emphasis: #f0bfa3; --bal-avatar-1: #8fd2c1; --bal-avatar-1-contrast: #06120f; --bal-avatar-2: #e3a679; --bal-avatar-2-contrast: #2a1a12; --bal-avatar-3: #b3a4d6; --bal-avatar-3-contrast: #1f1a2e; --bal-avatar-4: #8fc4dc; --bal-avatar-4-contrast: #08222b; --bal-avatar-5: #e0b542; --bal-avatar-5-contrast: #2a2107; --bal-avatar-6: #9fc98a; --bal-avatar-6-contrast: #142a0c; --bal-pin-shadow: rgba(0, 0, 0, 0.5); } } /* ── Dark scheme — explicit (cookie present, or after MUI hydrates/toggles). Keep every value identical to the @media block above. ──────────────── */ [data-mui-color-scheme='dark'] { /* Primary — lifted teal (readable on dark surfaces) */ --bal-primary: #6fc0ac; --bal-primary-light: #8fd2c1; --bal-primary-dark: #3f8a78; --bal-primary-contrast: #06120f; --bal-primary-soft: rgba(111, 192, 172, 0.16); /* Secondary — warm terracotta-light */ --bal-secondary: #e6a98a; --bal-secondary-light: #f0bfa3; --bal-secondary-dark: #d98c6a; --bal-secondary-contrast: #2a1a12; --bal-secondary-soft: rgba(230, 169, 138, 0.18); /* Surfaces — deep teal */ --bal-bg-default: #0f1c19; --bal-bg-paper: #16302a; /* Text */ --bal-text-primary: #f3efe9; --bal-text-secondary: #9fb0a9; /* Divider */ --bal-divider: rgba(243, 239, 233, 0.14); /* Feedback — toast / alert backgrounds (lifted for dark surfaces; cream text) */ --bal-success: #257659; --bal-success-contrast: #f3efe9; --bal-error: #b5402f; --bal-error-contrast: #f3efe9; --bal-warning: #97701f; --bal-warning-contrast: #f3efe9; --bal-info: #2f6b5e; --bal-info-contrast: #f3efe9; --bal-success-soft: rgba(37, 118, 89, 0.18); --bal-error-soft: rgba(181, 64, 47, 0.18); --bal-warning-soft: rgba(151, 112, 31, 0.20); --bal-info-soft: rgba(47, 107, 94, 0.16); /* Elevation — black-teal shadow steps (deeper + darker than light scheme) */ --bal-shadow-1: 0 1px 2px rgba(6, 18, 15, 0.24), 0 1px 1px rgba(6, 18, 15, 0.16); --bal-shadow-2: 0 4px 12px rgba(6, 18, 15, 0.32), 0 2px 4px rgba(6, 18, 15, 0.20); --bal-shadow-3: 0 12px 32px rgba(6, 18, 15, 0.40), 0 4px 8px rgba(6, 18, 15, 0.24); /* Focus ring */ --bal-focus-ring: #6fc0ac; /* Rating stars */ --bal-rating: #e0b542; --bal-rating-empty: rgba(243, 239, 233, 0.20); /* Trust */ --bal-trust: #7fb8e6; --bal-trust-soft: rgba(127, 184, 230, 0.18); /* Money emphasis — lifted warm tone, readable on dark surfaces */ --bal-money-emphasis: #f0bfa3; /* Avatar — same lifted hues as the media-query fallback above (keep in sync) */ --bal-avatar-1: #8fd2c1; --bal-avatar-1-contrast: #06120f; --bal-avatar-2: #e3a679; --bal-avatar-2-contrast: #2a1a12; --bal-avatar-3: #b3a4d6; --bal-avatar-3-contrast: #1f1a2e; --bal-avatar-4: #8fc4dc; --bal-avatar-4-contrast: #08222b; --bal-avatar-5: #e0b542; --bal-avatar-5-contrast: #2a2107; --bal-avatar-6: #9fc98a; --bal-avatar-6-contrast: #142a0c; --bal-pin-shadow: rgba(0, 0, 0, 0.5); }