open-navigator / web_app /src /index.css
jcbowyer's picture
Clean HuggingFace deployment without binary files
e59d91d
Raw
History Blame Contribute Delete
18.4 kB
@tailwind base;
@tailwind components;
@tailwind utilities;
:root {
font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
line-height: 1.5;
font-weight: 400;
/* App shell is light (see Layout). Dark scheme + white inherited color broke native controls (e.g. <select>). */
color-scheme: light;
color: #0f172a;
background-color: #cbd5e1;
}
html {
scroll-behavior: smooth;
overflow-x: clip;
}
body {
margin: 0;
min-height: 100vh;
overflow-x: clip;
}
@layer base {
h1 {
@apply text-4xl font-bold;
}
h2 {
@apply text-3xl font-semibold;
}
h3 {
@apply text-2xl font-semibold;
}
}
@layer components {
.card {
@apply bg-white rounded-lg shadow-md p-6;
}
.btn-primary {
@apply bg-neutral-600 hover:bg-neutral-700 text-white font-medium py-2 px-4 rounded-lg transition-colors;
}
.btn-secondary {
@apply bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-2 px-4 rounded-lg transition-colors;
}
/* Hide scrollbar but keep functionality */
.scrollbar-hide {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
.scrollbar-hide::-webkit-scrollbar {
display: none; /* Chrome, Safari and Opera */
}
}
@keyframes slideUp {
from {
opacity: 0;
transform: translateY(30px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
/* Census explorer: D3-like cubic-in-out on fills (style-based, not attribute-only) */
.leaflet-container.census-choropleth-map {
background: #ffffff;
}
/* Align default zoom (+/βˆ’) with map card horizontal padding (toolbar uses px-3). */
.leaflet-container.census-choropleth-map .leaflet-top.leaflet-left {
top: 0.5rem;
left: 0.75rem;
}
.leaflet-container.census-choropleth-map .leaflet-control-zoom {
margin-top: 0;
}
.leaflet-container.census-choropleth-map svg path.leaflet-interactive {
transition: fill 1.2s cubic-bezier(0.65, 0, 0.35, 1), fill-opacity 0.5s cubic-bezier(0.65, 0, 0.35, 1);
}
@keyframes census-map-year-pop {
0% {
transform: scale(0.88);
opacity: 0.35;
filter: blur(1px);
}
100% {
transform: scale(1);
opacity: 1;
filter: blur(0);
}
}
.census-map-year-badge {
animation: census-map-year-pop 0.55s cubic-bezier(0.22, 1, 0.36, 1) forwards;
}
/* Jurisdiction mapping quality β€” light palette only: keep page fill on --jmq-bg (no full-bleed dark / #0d1117).
* `.jmq-modal-portal-root` repeats the same custom properties so modals portaled to `document.body` still resolve
* `var(--jmq-surface)` etc. (those tokens are not inherited from `.jmq-quality-page` when the modal is outside it). */
.jmq-quality-page,
.jmq-modal-portal-root {
--jmq-bg: #f6f8fa;
--jmq-surface: #ffffff;
--jmq-surface2: #eff2f5;
--jmq-border: #d0d7de;
/* Modal overlay: cool slate, not black β€” avoids a β€œblack screen” feel on this page. */
--jmq-scrim: rgba(71, 85, 105, 0.42);
--jmq-teal: #117a72;
--jmq-teal-dim: rgba(17, 122, 114, 0.1);
--jmq-amber: #9a6700;
--jmq-amber-dim: rgba(154, 103, 0, 0.12);
--jmq-red: #a40e26;
--jmq-red-dim: rgba(164, 14, 38, 0.08);
--jmq-green: #116329;
--jmq-green-dim: rgba(17, 99, 41, 0.1);
--jmq-blue: #0969da;
--jmq-text: #1f2328;
--jmq-text-muted: #656d76;
--jmq-text-dim: #8c959f;
}
.jmq-quality-page {
font-family: 'IBM Plex Sans', 'DM Sans', ui-sans-serif, system-ui, sans-serif;
font-size: 14px;
line-height: 1.6;
color: var(--jmq-text);
background: var(--jmq-bg);
}
.jmq-modal-scrim {
background: var(--jmq-scrim);
}
.jmq-quality-page .font-mono,
.jmq-quality-page code {
font-family: 'IBM Plex Mono', ui-monospace, monospace;
}
.jmq-quality-page code {
background: var(--jmq-surface);
border: 1px solid var(--jmq-border);
border-radius: 3px;
padding: 1px 5px;
font-size: 10px;
color: var(--jmq-teal);
}
.jmq-header {
display: flex;
align-items: center;
gap: 12px;
padding: 18px 32px;
border-bottom: 1px solid var(--jmq-border);
background: var(--jmq-surface);
}
.jmq-logo {
width: 32px;
height: 32px;
border: 2px solid var(--jmq-teal);
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 600;
color: var(--jmq-teal);
flex-shrink: 0;
}
.jmq-hdr-title {
font-size: 15px;
font-weight: 500;
}
.jmq-hdr-sub {
font-size: 11px;
color: var(--jmq-text-muted);
font-family: 'IBM Plex Mono', monospace;
margin-left: auto;
}
.jmq-tab-nav {
display: flex;
padding: 0 32px;
border-bottom: 1px solid var(--jmq-border);
background: var(--jmq-surface);
}
.jmq-tab-btn {
padding: 11px 18px;
font-size: 13px;
font-family: 'IBM Plex Sans', sans-serif;
color: var(--jmq-text-muted);
background: none;
border: none;
border-bottom: 2px solid transparent;
cursor: pointer;
transition: color 0.15s, border-color 0.15s;
white-space: nowrap;
}
.jmq-tab-btn:hover {
color: var(--jmq-text);
}
.jmq-tab-btn--active {
color: var(--jmq-teal);
border-bottom-color: var(--jmq-teal);
}
.jmq-main {
padding: 28px 32px;
max-width: 1300px;
margin: 0 auto;
}
.jmq-sec-label {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 1.5px;
color: var(--jmq-teal);
margin-bottom: 14px;
}
.jmq-sec-label--spaced {
margin-top: 22px;
}
.jmq-kpi-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
gap: 10px;
margin-bottom: 24px;
}
.jmq-kpi {
background: var(--jmq-surface);
border: 1px solid var(--jmq-border);
border-radius: 8px;
padding: 15px 16px;
position: relative;
overflow: hidden;
box-shadow: 0 1px 0 rgba(31, 35, 40, 0.04);
}
.jmq-kpi::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
height: 2px;
}
.jmq-kpi--good::before {
background: var(--jmq-green);
}
.jmq-kpi--warn::before {
background: var(--jmq-amber);
}
.jmq-kpi--bad::before {
background: var(--jmq-red);
}
.jmq-kpi--info::before {
background: var(--jmq-teal);
}
.jmq-kpi-label {
font-size: 11px;
color: var(--jmq-text-muted);
margin-bottom: 5px;
font-family: 'IBM Plex Mono', monospace;
}
.jmq-kpi-value {
font-size: 24px;
font-weight: 600;
font-family: 'IBM Plex Mono', monospace;
line-height: 1;
}
.jmq-kpi-sub {
font-size: 11px;
color: var(--jmq-text-muted);
margin-top: 4px;
font-family: 'IBM Plex Mono', monospace;
}
.jmq-kpi--good .jmq-kpi-value {
color: var(--jmq-green);
}
.jmq-kpi--warn .jmq-kpi-value {
color: var(--jmq-amber);
}
.jmq-kpi--bad .jmq-kpi-value {
color: var(--jmq-red);
}
.jmq-kpi--info .jmq-kpi-value {
color: var(--jmq-teal);
}
.jmq-g2 {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 14px;
margin-bottom: 16px;
}
.jmq-g3 {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 14px;
margin-bottom: 16px;
}
@media (max-width: 900px) {
.jmq-g2,
.jmq-g3 {
grid-template-columns: 1fr;
}
}
.jmq-card {
background: var(--jmq-surface);
border: 1px solid var(--jmq-border);
border-radius: 10px;
padding: 18px;
box-shadow: 0 1px 0 rgba(31, 35, 40, 0.04);
}
.jmq-card--flush {
padding: 0;
overflow: hidden;
}
.jmq-card-hd {
padding: 14px 18px;
border-bottom: 1px solid var(--jmq-border);
}
.jmq-card-bd {
padding: 18px;
}
.jmq-card-title {
font-size: 13px;
font-weight: 600;
margin-bottom: 3px;
color: var(--jmq-text);
}
.jmq-card-sub {
font-size: 11px;
color: var(--jmq-text-muted);
margin-bottom: 16px;
font-family: 'IBM Plex Mono', monospace;
}
.jmq-bar-row {
display: flex;
align-items: center;
gap: 8px;
margin-bottom: 7px;
}
.jmq-bar-label {
width: 170px;
flex-shrink: 0;
font-size: 11px;
color: var(--jmq-text-muted);
text-align: right;
font-family: 'IBM Plex Mono', monospace;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.jmq-bar-track {
flex: 1;
height: 20px;
background: var(--jmq-surface2);
border-radius: 3px;
overflow: hidden;
}
.jmq-bar-fill {
height: 100%;
border-radius: 3px;
display: flex;
align-items: center;
justify-content: flex-end;
padding: 0 7px;
transition: width 0.7s cubic-bezier(0.4, 0, 0.2, 1);
}
.jmq-bar-pct {
font-size: 10px;
font-family: 'IBM Plex Mono', monospace;
font-weight: 600;
color: rgba(255, 255, 255, 0.95);
white-space: nowrap;
}
.jmq-bar-n {
width: 80px;
flex-shrink: 0;
font-size: 10px;
font-family: 'IBM Plex Mono', monospace;
color: var(--jmq-text-muted);
text-align: right;
}
.jmq-fill-teal {
background: var(--jmq-teal);
}
.jmq-fill-amber {
background: #c98700;
}
.jmq-fill-red {
background: #cf222e;
}
.jmq-fill-green {
background: var(--jmq-green);
}
.jmq-fill-blue {
background: var(--jmq-blue);
}
.jmq-alert {
display: flex;
align-items: flex-start;
gap: 10px;
padding: 12px 16px;
border-radius: 7px;
margin-bottom: 16px;
border: 1px solid transparent;
border-left-width: 3px;
font-size: 12px;
line-height: 1.5;
}
.jmq-alert-icon {
font-size: 14px;
flex-shrink: 0;
margin-top: 1px;
}
.jmq-alert--warn {
background: var(--jmq-amber-dim);
border-color: rgba(154, 103, 0, 0.35);
border-left-color: var(--jmq-amber);
color: #4d2d00;
}
.jmq-alert--bad {
background: var(--jmq-red-dim);
border-color: rgba(164, 14, 38, 0.25);
border-left-color: var(--jmq-red);
color: #6e0111;
}
.jmq-alert--info {
background: var(--jmq-teal-dim);
border-color: rgba(17, 122, 114, 0.25);
border-left-color: var(--jmq-teal);
color: #0a3d39;
}
.jmq-src-badge {
display: inline-flex;
align-items: center;
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 600;
padding: 2px 6px;
border-radius: 3px;
letter-spacing: 0.5px;
margin-right: 3px;
}
.jmq-src-badge--naco {
background: rgba(17, 122, 114, 0.14);
color: var(--jmq-teal);
}
.jmq-src-badge--uscm {
background: rgba(9, 105, 218, 0.1);
color: var(--jmq-blue);
}
.jmq-src-badge--nces_directory {
background: rgba(110, 64, 201, 0.12);
color: #6e40c9;
}
.jmq-src-badge--gsa {
background: rgba(17, 99, 41, 0.12);
color: var(--jmq-green);
}
.jmq-src-badge--league {
background: rgba(130, 80, 223, 0.12);
color: #8250df;
}
.jmq-src-badge--wikidata {
background: rgba(153, 0, 85, 0.12);
color: #990055;
}
.jmq-src-badge--override {
background: var(--jmq-amber-dim);
color: var(--jmq-amber);
}
.jmq-tbl-wrap {
overflow-x: auto;
}
.jmq-quality-page table.jmq-dt {
width: 100%;
border-collapse: collapse;
font-size: 12px;
}
.jmq-quality-page table.jmq-dt th {
font-family: 'IBM Plex Mono', monospace;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.8px;
color: var(--jmq-text-muted);
padding: 7px 10px;
text-align: left;
border-bottom: 1px solid var(--jmq-border);
}
.jmq-quality-page table.jmq-dt td {
padding: 8px 10px;
border-bottom: 1px solid rgba(208, 215, 222, 0.7);
font-family: 'IBM Plex Mono', monospace;
vertical-align: middle;
}
.jmq-quality-page table.jmq-dt tr:last-child td {
border-bottom: none;
}
.jmq-quality-page table.jmq-dt tbody tr:hover td {
background: var(--jmq-surface2);
}
.jmq-dt-num {
text-align: right;
}
.jmq-dt-pc {
text-align: right;
font-weight: 600;
}
.jmq-pc-g {
color: var(--jmq-green);
}
.jmq-pc-w {
color: var(--jmq-amber);
}
.jmq-pc-b {
color: var(--jmq-red);
}
.jmq-heat-table {
width: 100%;
border-collapse: separate;
border-spacing: 3px;
font-size: 12px;
}
.jmq-heat-table th:first-child {
text-align: left;
}
.jmq-heat-table td {
padding: 7px 5px;
border-radius: 4px;
text-align: center;
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
font-weight: 500;
}
.jmq-heat-rl {
text-align: left !important;
color: var(--jmq-text-muted) !important;
background: transparent !important;
padding-left: 2px !important;
font-size: 11px !important;
}
.jmq-h0 {
background: #ddf4e8;
color: var(--jmq-green);
}
.jmq-h1 {
background: #fff8c5;
color: #7d4e00;
}
.jmq-h2 {
background: #ffebe9;
color: var(--jmq-red);
}
.jmq-hx {
background: var(--jmq-surface2);
color: var(--jmq-text-dim);
font-size: 10px;
}
.jmq-placeholder {
background: var(--jmq-surface2);
border: 1px dashed var(--jmq-border);
border-radius: 8px;
padding: 28px;
text-align: center;
color: var(--jmq-text-muted);
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
line-height: 2;
}
.jmq-placeholder strong {
color: var(--jmq-amber);
display: block;
margin-bottom: 6px;
font-size: 12px;
}
.jmq-step {
display: flex;
gap: 12px;
align-items: flex-start;
padding: 11px;
background: var(--jmq-surface2);
border-radius: 6px;
border-left: 3px solid var(--jmq-teal);
margin-bottom: 8px;
}
.jmq-step-n {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
color: var(--jmq-teal);
width: 18px;
flex-shrink: 0;
font-weight: 600;
}
.jmq-step-title {
font-size: 12px;
font-weight: 600;
margin-bottom: 2px;
}
.jmq-step-cmd {
font-family: 'IBM Plex Mono', monospace;
font-size: 11px;
color: var(--jmq-text-muted);
}
.jmq-step-note {
font-size: 11px;
color: var(--jmq-text-dim);
margin-top: 3px;
}
.jmq-step--muted {
border-left-color: var(--jmq-border);
}
.jmq-step--muted .jmq-step-n {
color: var(--jmq-text-muted);
}
.jmq-step--muted .jmq-step-title {
color: var(--jmq-text-muted);
}
.jmq-legend {
display: flex;
gap: 14px;
flex-wrap: wrap;
margin-bottom: 14px;
}
.jmq-leg-item {
display: flex;
align-items: center;
gap: 5px;
font-size: 11px;
color: var(--jmq-text-muted);
font-family: 'IBM Plex Mono', monospace;
}
.jmq-leg-dot {
width: 10px;
height: 10px;
border-radius: 2px;
flex-shrink: 0;
}
.jmq-insight-box {
padding: 13px 16px;
background: var(--jmq-surface2);
border-radius: 6px;
font-size: 12px;
color: var(--jmq-text-muted);
font-family: 'IBM Plex Mono', monospace;
line-height: 1.8;
margin-top: 14px;
}
.jmq-insight-box strong {
color: var(--jmq-teal);
}
.jmq-details {
border: 1px solid var(--jmq-border);
border-radius: 10px;
background: var(--jmq-surface);
box-shadow: 0 1px 0 rgba(31, 35, 40, 0.04);
}
.jmq-details > summary {
cursor: pointer;
list-style: none;
padding: 14px 18px;
font-weight: 600;
color: var(--jmq-text);
}
.jmq-details > summary::-webkit-details-marker {
display: none;
}
.jmq-details > div {
border-top: 1px solid var(--jmq-border);
padding: 16px 18px;
}
.jmq-pill {
border-radius: 9999px;
padding: 8px 16px;
font-size: 13px;
font-weight: 600;
border: 1px solid var(--jmq-border);
background: var(--jmq-surface2);
color: var(--jmq-text);
cursor: pointer;
transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.jmq-pill:hover {
background: #e6eaef;
color: var(--jmq-text);
}
.jmq-pill--active {
background: var(--jmq-teal);
border-color: var(--jmq-teal);
color: #fff;
}
.jmq-pill--active:hover {
background: #0e655e;
border-color: #0e655e;
color: #fff;
}
.jmq-pill-row {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
.jmq-refresh {
border: 1px solid var(--jmq-border);
border-radius: 10px;
background: var(--jmq-surface);
overflow: hidden;
box-shadow: 0 1px 0 rgba(31, 35, 40, 0.04);
}
.jmq-refresh-toggle {
display: flex;
width: 100%;
align-items: center;
justify-content: space-between;
gap: 12px;
padding: 14px 18px;
text-align: left;
font-size: 15px;
font-weight: 600;
background: var(--jmq-surface);
border: none;
cursor: pointer;
color: var(--jmq-text);
transition: background 0.15s;
}
.jmq-refresh-toggle:hover {
background: var(--jmq-surface2);
}
.jmq-refresh-panel {
padding: 16px 18px;
border-top: 1px solid var(--jmq-border);
}
/* ZCTA (ZIP) outline labels on the Leaflet local view β€” strip the default
tooltip bubble so the bare number floats over the aerial like the SVG map. */
.leaflet-tooltip.zcta-outline-label {
background: transparent;
border: none;
box-shadow: none;
padding: 0;
color: #0e7490;
font-weight: 700;
font-size: 11px;
text-shadow:
0 0 2px #fff, 0 0 2px #fff, 0 0 2px #fff, 0 0 2px #fff;
}
.leaflet-tooltip.zcta-outline-label::before {
display: none; /* hide the tooltip arrow */
}
/* ── Money-game modal: prototype-parity animations (mgm-*) ───────────────── */
@keyframes mgmCtaPulse {
0%, 100% { box-shadow: 0 0 0 0 rgba(26, 107, 107, 0.45); }
50% { box-shadow: 0 0 0 10px rgba(26, 107, 107, 0); }
}
.mgm-pulse { animation: mgmCtaPulse 1.9s ease-in-out infinite; }
@keyframes mgmGrow { from { width: 0; } }
.mgm-grow { animation: mgmGrow 700ms ease both; }
@keyframes mgmFadeUp {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: none; }
}
.mgm-fade { animation: mgmFadeUp 400ms ease both; }
@keyframes mgmNudge {
0%, 100% { transform: translateX(0); }
50% { transform: translateX(5px); }
}
.mgm-nudge { display: inline-block; animation: mgmNudge 1.2s ease-in-out infinite; }
@keyframes mgmRing {
0%, 100% { transform: scale(1); border-color: #cfe0e0; }
50% { transform: scale(1.045); border-color: #1a6b6b; }
}
.mgm-ring { animation: mgmRing 2.2s ease-in-out infinite; }
@media (prefers-reduced-motion: reduce) {
.mgm-pulse, .mgm-grow, .mgm-fade, .mgm-nudge, .mgm-ring { animation: none !important; }
}
/* ── Money-game modal sliders: the design prototype's exact range-x CSS ──── */
input.range-x {
-webkit-appearance: none;
appearance: none;
width: 100%;
height: 8px;
border-radius: 999px;
outline: none;
border: none;
box-shadow: inset 0 0 0 1px rgba(28, 25, 23, 0.08);
}
input.range-x::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 18px;
height: 18px;
border-radius: 50%;
background: #fff;
border: 3px solid var(--tc, #0d9488);
box-shadow: 0 1px 3px rgba(28, 25, 23, 0.25);
cursor: pointer;
}
input.range-x::-moz-range-thumb {
width: 15px;
height: 15px;
border-radius: 50%;
background: #fff;
border: 3px solid var(--tc, #0d9488);
box-shadow: 0 1px 3px rgba(28, 25, 23, 0.25);
cursor: pointer;
}
input.range-x:disabled::-webkit-slider-thumb { border-color: #d6d3d1; cursor: default; }
input.range-x:disabled::-moz-range-thumb { border-color: #d6d3d1; cursor: default; }