/* ============================================================= Civilytics Design Tokens — single source of truth. Mirrored from crdc-arrests/theme/_tokens.scss so this demo app stays in sync with the white paper / social media visual style. Neutrals: warm paper → civic ink Brand: Civic Navy (primary) + Ember (accent) VIZ: Supporting palette for data series ============================================================ */ :root { /* — Paper (backgrounds) — */ --cv-paper: #FAF7F2; --cv-paper-2: #F2EDE4; --cv-paper-3: #E6DFD1; /* — Rule / borders — */ --cv-rule: #D6CEBD; --cv-rule-strong: #B8AE97; /* — Ink (text) — */ --cv-ink: #0E1A2B; --cv-ink-2: #2B3A52; --cv-ink-3: #5A6A82; --cv-ink-4: #8C97AB; /* — Civic Navy (primary brand) — */ --cv-navy-50: #EEF3FA; --cv-navy-100: #DDE6F2; --cv-navy-200: #B3C6E0; --cv-navy-300: #7A9BCA; --cv-navy-400: #4A74B0; --cv-navy-500: #2E5590; --cv-navy-600: #22406A; /* links, primary buttons */ --cv-navy-700: #1A2E4A; /* hover state */ /* — Ember (accent) — */ --cv-accent: #C25311; /* main accent color */ --cv-accent-text: #A04400; --cv-accent-dark: #923D00; --cv-accent-hover: #7A3600; /* — Supporting data-viz palette (from _tokens.scss) — */ --teal-600: #1F6F70; --plum-600: #6B3A5E; --moss-600: #4A6B2F; --brass-600: #B8751C; /* — Semantic status colors — */ --cv-success: #4A6B2F; /* moss */ --cv-warning: #9A5F18; --cv-danger: #A6271D; /* — Font stacks (from _tokens.scss) — */ --font-display: 'Libre Franklin', 'Franklin Gothic', 'Inter', system-ui, sans-serif; --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif; --font-mono: 'JetBrains Mono', 'SF Mono', Menlo, Consolas, monospace; /* — Spacing scale (from _tokens.scss) — */ --space-1: 0.5rem; --space-2: 1rem; --space-3: 1.5rem; --space-4: 2rem; --space-5: 3rem; --space-6: 4rem; --space-7: 6rem; /* — Border radius (from _tokens.scss) — */ --radius-sm: 4px; --radius-md: 6px; --radius-lg: 12px; /* — Race categorical palette (validated, see src/utils/colors.js) — */ --race-wh: #3D6FC4; --race-bl: #C98A2A; --race-hi: #9C3F86; --race-am: #3D9A6B; /* — Chart-specific colors — aliased onto the tokens charts actually use */ --chart-modeled: var(--cv-navy-600); --chart-frequentist: var(--cv-ink-4); --chart-observed: var(--cv-ink); /* — Model quadrant colors — */ --model-one-year-baseline: var(--cv-navy-600); --model-three-year-baseline: var(--teal-600); } /* ============================================================= Base reset + typography (from crdc-arrests/theme/civilytics.scss) ============================================================ */ * { box-sizing: border-box; } html { font-size: 100%; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; } body { margin: 0; background: var(--cv-paper); color: var(--cv-ink); font-family: var(--font-sans); line-height: 1.65; } h1, h2, h3, h4 { font-family: var(--font-display); font-weight: 800; letter-spacing: -0.025em; line-height: 1.08; color: var(--cv-ink); text-wrap: pretty; margin: 0 0 .4em; } h1 { font-size: clamp(2.25rem, 4.2vw, 3.75rem); font-weight: 900; letter-spacing: -0.035em; line-height: 1.0; } h2 { font-size: clamp(1.75rem, 2.8vw, 2.375rem); } h3 { font-size: 1.5rem; font-weight: 700; letter-spacing: -0.022em; color: var(--cv-ink-2); } p, li { line-height: 1.7; text-wrap: pretty; } a { color: var(--cv-navy-600); text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; transition: color 120ms ease; } a:hover { color: var(--cv-navy-700); text-decoration-thickness: 2px; } code, .mono { font-family: var(--font-mono); font-feature-settings: "tnum" 1, "zero" 1; } :focus-visible { outline: 2px solid var(--cv-accent); outline-offset: 2px; } /* ============================================================= Layout helpers (from civilytics.scss) ============================================================ */ .cv-wrap { max-width: 60rem; margin: 0 auto; padding: 0 var(--space-3); } .cv-header { display: flex; align-items: center; justify-content: space-between; padding: var(--space-3) 0; border-bottom: 1px solid var(--cv-rule); } .cv-header .cv-logo { height: 28px; display: block; } /* Eyebrow / section label (from civilytics.scss + extras.css) */ .eyebrow, .cv-eyebrow { font-family: var(--font-sans); font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.1em; color: var(--cv-accent-text); margin: 0 0 0.5rem; display: inline-flex; align-items: center; gap: 0.5rem; } .eyebrow::before, .cv-eyebrow::before { content: ""; display: inline-block; width: 24px; height: 2px; background: var(--cv-accent); } /* Stat callout — hero numbers (from extras.css) */ .stat-callout { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 2rem; margin: 2rem 0 2.5rem; padding: 1.5rem 0; border-top: 3px double var(--cv-ink); border-bottom: 1px solid var(--cv-rule); } .stat-callout .stat-num { font-family: 'Source Serif 4', Georgia, serif; font-weight: 700; font-size: 3rem; line-height: 1; letter-spacing: -0.02em; color: var(--cv-ink); font-variant-numeric: tabular-nums; display: block; } .stat-callout .stat-label { font-family: var(--font-sans); font-size: 0.75rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.08em; color: var(--cv-ink-3); margin-top: 0.4rem; } .stat-callout .stat-label.accent { color: var(--cv-accent); } /* Card component (used for district suggestions, model cards) */ .cv-card { display: flex; flex-direction: column; gap: 0.25rem; background: #fff; border: 1px solid var(--cv-rule); border-top: 3px solid var(--cv-accent); border-radius: var(--radius-lg); padding: var(--space-2) var(--space-3); text-decoration: none; transition: border-color 120ms ease, box-shadow 120ms ease; } .cv-card:hover { border-color: var(--cv-ink-3); box-shadow: 0 2px 8px rgba(0,0,0,0.04); } /* Button (primary) */ .btn-primary { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.625rem 1.25rem; background: var(--cv-navy-600); color: #fff; border: none; border-radius: var(--radius-md); font-family: var(--font-sans); font-size: 0.9rem; font-weight: 600; cursor: pointer; transition: background 120ms ease, transform 20ms ease; } .btn-primary:hover { background: var(--cv-navy-700); } .btn-primary:active { transform: scale(0.98); } .btn-primary:disabled { opacity: 0.5; cursor: not-allowed; } /* Button (secondary / outline) */ .btn-outline { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; padding: 0.5rem 1rem; background: transparent; color: var(--cv-navy-600); border: 1px solid var(--cv-rule); border-radius: var(--radius-md); font-family: var(--font-sans); font-size: 0.85rem; font-weight: 500; cursor: pointer; transition: background 120ms ease, color 120ms ease; } .btn-outline:hover { background: var(--cv-paper-2); color: var(--cv-navy-700); } /* Footer */ .cv-footer { border-top: 1px solid var(--cv-rule); padding: var(--space-4) 0; color: var(--cv-ink-3); font-size: 0.9rem; display: flex; flex-wrap: wrap; gap: var(--space-2); justify-content: space-between; align-items: center; } /* Responsive */ @media (max-width: 680px) { .cv-footer { flex-direction: column; text-align: center; } } /* Spinner used while opt-in multi-shard draw fetches are in flight */ @keyframes cv-spin { to { transform: rotate(360deg); } } @media (prefers-reduced-motion: reduce) { @keyframes cv-spin { to { transform: none; } } }