Initial commit: CRDC Arrests API demo app
Deploy to Git Pages / build-and-deploy (push) Failing after 19s
Deploy to Git Pages / build-and-deploy (push) Failing after 19s
React + Vite static site demonstrating the CRDC School Arrest Rate API. Features 6 interactive charts comparing observed arrest data against Bayesian model estimates across U.S. school districts, with Civilytics visual identity. - State selector and district search with 'interesting' suggestions (top arrests) - Animated histogram loading grid showing posterior draw progress - Charts: time series, rate by group, district vs national, model comparison quadrants, density proxy, exceedance probability - Static JSON fixture for national rates (no API changes needed) - Dockerfile + docker-compose.yml for self-hosted deployment - GitHub Actions workflow and _config.yml for Git Pages
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
/* =============================================================
|
||||
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;
|
||||
|
||||
/* — Chart-specific colors — */
|
||||
--chart-modeled: #000a9bff; /* dark indigo-blue (from wp_model_palette) */
|
||||
--chart-frequentist: #858585bb; /* gray (from wp_model_palette) */
|
||||
--chart-observed: #A6271D; /* red for observed data points */
|
||||
|
||||
/* — Model quadrant colors — */
|
||||
--model-one-year-baseline: var(--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; } }
|
||||
Reference in New Issue
Block a user