SPB Git forge

spb/countryatlas

Public
20commits 1branches 0releases
268.3 MBsize
maindefault branch
12 days agolast push
TypeScript 57% Python 38.6% JavaScript 3.6% CSS 0.6%
11.4 KB · 495 lines css
Raw Blame History
1@import 'tailwindcss';23/*4  CountryAtlas design tokens.5  Editorial, calm, data-dense. Raw values live on :root / .dark; Tailwind utilities read them through6  `@theme inline`, so `bg-paper`, `text-ink-2`, `border-rule`, `text-up`, `fill-series-1` … follow the theme.7  Series/sequential colours are the validated dataviz palette (skills/dataviz references/palette.md),8  re-validated against these surfaces on 2026-09-11 (see apps/web/README.md → Design tokens).9*/10@custom-variant dark (&:where(.dark, .dark *));1112:root {13  color-scheme: light;14  --paper: #fbfaf7; /* page plane */15  --surface: #ffffff; /* chart surface, sheets, dialogs */16  --surface-2: #f3f1ec; /* hover wash, chips */17  --ink: #1a1917;18  --ink-2: #5c5a55;19  --ink-3: #8a877f;20  --rule: #e6e3dc;21  --rule-strong: #c9c6bd;22  --accent: #1c5cab;23  --accent-ink: #ffffff;24  --accent-soft: #e8f0fb;25  --up: #006300;26  --down: #b02a2a;27  --warn: #9a6a00;28  --nodata: #d9d6ce;29  --forecast: #8a877f;3031  --series-1: #2a78d6;32  --series-2: #eb6834;33  --series-3: #1baf7a;34  --series-4: #eda100;35  --series-5: #e87ba4;36  --series-6: #008300;37  --series-7: #4a3aa7;38  --series-8: #e34948;3940  --seq-1: #cde2fb;41  --seq-2: #9ec5f4;42  --seq-3: #6da7ec;43  --seq-4: #3987e5;44  --seq-5: #256abf;45  --seq-6: #184f95;46  --seq-7: #0d366b;4748  /* Direction of change (neutral semantics: increase / decrease, NOT good / bad). Teal ↔ sienna diverging ramp. */49  --inc: #0f7b8a;50  --dec: #b4632d;51  --div-1: #8c4a12; /* strong decrease */52  --div-2: #c98a4e;53  --div-3: #e8c9a6;54  --div-4: #ece9e1; /* no change */55  --div-5: #a6d4d9;56  --div-6: #4fa2ad;57  --div-7: #0b5f6b; /* strong increase */58  /* Second sequential ramp (warm) for a second map layer / category maps */59  --seq2-1: #fbe4d0;60  --seq2-2: #f5c39c;61  --seq2-3: #eb9a63;62  --seq2-4: #d97636;63  --seq2-5: #b55b21;64  --seq2-6: #8a4416;65  --seq2-7: #5c2d0c;66  --map-water: #f4f2ec;67  --map-stroke: #ffffff;6869  --shadow-sheet: 0 -8px 32px rgba(26, 25, 23, 0.12);70  --shadow-pop: 0 4px 24px rgba(26, 25, 23, 0.14);71}7273.dark {74  color-scheme: dark;75  --paper: #151513;76  --surface: #1c1c1a;77  --surface-2: #24241f;78  --ink: #f2f0ea;79  --ink-2: #c9c6bd;80  --ink-3: #8a877f;81  --rule: #2c2b28;82  --rule-strong: #3a3935;83  --accent: #5598e7;84  --accent-ink: #0d1b2e;85  --accent-soft: #17304f;86  --up: #0ca30c;87  --down: #e66767;88  --warn: #e0a100;89  --nodata: #33322f;90  --forecast: #8a877f;9192  --series-1: #3987e5;93  --series-2: #d95926;94  --series-3: #199e70;95  --series-4: #c98500;96  --series-5: #d55181;97  --series-6: #008300;98  --series-7: #9085e9;99  --series-8: #e66767;100101  --seq-1: #0d366b;102  --seq-2: #184f95;103  --seq-3: #256abf;104  --seq-4: #3987e5;105  --seq-5: #6da7ec;106  --seq-6: #9ec5f4;107  --seq-7: #cde2fb;108109  --inc: #4fb6c2;110  --dec: #e0955f;111  --div-1: #d58a4a;112  --div-2: #a86a37;113  --div-3: #5e4530;114  --div-4: #2a2926;115  --div-5: #234f55;116  --div-6: #2e8791;117  --div-7: #63c3cf;118  --seq2-1: #3a2410;119  --seq2-2: #5c3512;120  --seq2-3: #8a4a16;121  --seq2-4: #b8641f;122  --seq2-5: #d98a3c;123  --seq2-6: #eeb277;124  --seq2-7: #f8dcb8;125  --map-water: #101010;126  --map-stroke: #1c1c1a;127128  --shadow-sheet: 0 -8px 32px rgba(0, 0, 0, 0.5);129  --shadow-pop: 0 4px 24px rgba(0, 0, 0, 0.55);130}131132@theme inline {133  --color-paper: var(--paper);134  --color-surface: var(--surface);135  --color-surface-2: var(--surface-2);136  --color-ink: var(--ink);137  --color-ink-2: var(--ink-2);138  --color-ink-3: var(--ink-3);139  --color-rule: var(--rule);140  --color-rule-strong: var(--rule-strong);141  --color-accent: var(--accent);142  --color-accent-ink: var(--accent-ink);143  --color-accent-soft: var(--accent-soft);144  --color-up: var(--up);145  --color-down: var(--down);146  --color-warn: var(--warn);147  --color-nodata: var(--nodata);148  --color-forecast: var(--forecast);149  --color-series-1: var(--series-1);150  --color-series-2: var(--series-2);151  --color-series-3: var(--series-3);152  --color-series-4: var(--series-4);153  --color-series-5: var(--series-5);154  --color-series-6: var(--series-6);155  --color-series-7: var(--series-7);156  --color-series-8: var(--series-8);157  --color-seq-1: var(--seq-1);158  --color-seq-2: var(--seq-2);159  --color-seq-3: var(--seq-3);160  --color-seq-4: var(--seq-4);161  --color-seq-5: var(--seq-5);162  --color-seq-6: var(--seq-6);163  --color-seq-7: var(--seq-7);164  --color-inc: var(--inc);165  --color-dec: var(--dec);166  --color-div-1: var(--div-1);167  --color-div-2: var(--div-2);168  --color-div-3: var(--div-3);169  --color-div-4: var(--div-4);170  --color-div-5: var(--div-5);171  --color-div-6: var(--div-6);172  --color-div-7: var(--div-7);173  --color-map-water: var(--map-water);174175  /* Container widths: editorial pages ~1280, wide tables 1400, explorers = viewport. */176  --container-editorial: 80rem;177  --container-wide: 87.5rem;178179  --font-ui: var(--font-ui), ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;180  --font-display: var(--font-display), 'Iowan Old Style', 'Palatino Linotype', Georgia, serif;181  --font-mono: ui-monospace, 'SF Mono', Menlo, Consolas, monospace;182183  /* Typographic scale (rem). Body 15px on mobile, 16px from md. */184  --text-2xs: 0.6875rem;185  --text-2xs--line-height: 1rem;186  --text-xs: 0.75rem;187  --text-xs--line-height: 1.1rem;188  --text-sm: 0.875rem;189  --text-sm--line-height: 1.3rem;190  --text-base: 1rem;191  --text-base--line-height: 1.55rem;192  --text-lg: 1.125rem;193  --text-lg--line-height: 1.6rem;194  --text-xl: 1.3125rem;195  --text-xl--line-height: 1.75rem;196  --text-2xl: 1.625rem;197  --text-2xl--line-height: 2rem;198  --text-3xl: 2rem;199  --text-3xl--line-height: 2.3rem;200  --text-4xl: 2.5rem;201  --text-4xl--line-height: 2.75rem;202  --text-5xl: 3.25rem;203  --text-5xl--line-height: 3.4rem;204205  --shadow-sheet: var(--shadow-sheet);206  --shadow-pop: var(--shadow-pop);207208  --radius-xs: 2px;209  --radius-sm: 4px;210  --radius-md: 6px;211}212213@layer base {214  html {215    font-family: var(--font-ui);216    background: var(--paper);217    color: var(--ink);218    -webkit-text-size-adjust: 100%;219    text-rendering: optimizeLegibility;220    scroll-padding-top: 6.5rem;221  }222  html,223  body {224    /* Never scroll horizontally; individual scrollers opt in with overflow-x-auto. */225    overflow-x: clip;226    max-width: 100%;227  }228  body {229    font-size: 15px;230    line-height: 1.55;231    min-height: 100dvh;232    background: var(--paper);233    color: var(--ink);234  }235  @media (min-width: 48rem) {236    body {237      font-size: 16px;238    }239  }240  h1,241  h2,242  h3 {243    text-wrap: balance;244  }245  p {246    text-wrap: pretty;247  }248  a {249    text-underline-offset: 0.15em;250  }251  :focus-visible {252    outline: 2px solid var(--accent);253    outline-offset: 2px;254    border-radius: 2px;255  }256  ::selection {257    background: var(--accent-soft);258    color: var(--ink);259  }260  svg {261    display: block;262  }263  button {264    cursor: pointer;265  }266  [hidden] {267    display: none !important;268  }269  @media (prefers-reduced-motion: reduce) {270    *,271    *::before,272    *::after {273      animation-duration: 0.01ms !important;274      animation-iteration-count: 1 !important;275      transition-duration: 0.01ms !important;276      scroll-behavior: auto !important;277    }278  }279}280281@utility tnum {282  font-variant-numeric: tabular-nums lining-nums;283  font-feature-settings: 'tnum' 1, 'lnum' 1;284}285@utility pnum {286  font-variant-numeric: proportional-nums lining-nums;287}288@utility display {289  font-family: var(--font-display);290  font-weight: 500;291  letter-spacing: -0.01em;292}293@utility eyebrow {294  font-size: var(--text-2xs);295  line-height: 1rem;296  letter-spacing: 0.08em;297  text-transform: uppercase;298  font-weight: 600;299  color: var(--ink-3);300}301@utility hairline {302  border-top: 1px solid var(--rule);303}304@utility tap {305  min-height: 44px;306  min-width: 44px;307}308@utility scrollbar-none {309  scrollbar-width: none;310  &::-webkit-scrollbar {311    display: none;312  }313}314@utility safe-bottom {315  padding-bottom: env(safe-area-inset-bottom, 0px);316}317@utility no-data-hatch {318  background-color: var(--nodata);319  background-image: repeating-linear-gradient(135deg, transparent 0 3px, rgba(26, 25, 23, 0.14) 3px 4px);320}321@utility link-quiet {322  color: inherit;323  text-decoration: none;324  &:hover {325    color: var(--accent);326  }327}328@utility container-x {329  padding-left: 1rem;330  padding-right: 1rem;331  @media (min-width: 40rem) {332    padding-left: 1.5rem;333    padding-right: 1.5rem;334  }335}336337@utility container-editorial {338  max-width: var(--container-editorial);339  margin-left: auto;340  margin-right: auto;341}342@utility container-wide {343  max-width: var(--container-wide);344  margin-left: auto;345  margin-right: auto;346}347/* Break out of the centred container to the viewport edges. */348@utility full-bleed {349  width: 100vw;350  margin-left: calc(50% - 50vw);351  margin-right: calc(50% - 50vw);352}353/* Horizontal ticker strip: snap-scrolling figures on one rule, no scrollbar. */354@utility ticker {355  display: flex;356  overflow-x: auto;357  scroll-snap-type: x proximity;358  scrollbar-width: none;359  &::-webkit-scrollbar {360    display: none;361  }362  & > * {363    scroll-snap-align: start;364    flex: 0 0 auto;365  }366}367/* Small data badges (quality, freshness, direction). Text + glyph always accompany the colour. */368@utility badge {369  display: inline-flex;370  align-items: center;371  gap: 0.25rem;372  border-radius: 2px;373  padding: 1px 6px;374  font-size: var(--text-2xs);375  line-height: 1rem;376  font-weight: 500;377  letter-spacing: 0.02em;378  border: 1px solid var(--rule);379  color: var(--ink-2);380}381382/* Range inputs (year slider): large thumb, hairline track, accent fill via CSS var --pct set by the component. */383.ca-range {384  -webkit-appearance: none;385  appearance: none;386  background: transparent;387  cursor: pointer;388}389.ca-range:focus-visible {390  outline: none;391}392.ca-range::-webkit-slider-runnable-track {393  height: 4px;394  border-radius: 2px;395  background: var(--rule-strong);396}397.ca-range::-moz-range-track {398  height: 4px;399  border-radius: 2px;400  background: var(--rule-strong);401}402.ca-range::-webkit-slider-thumb {403  -webkit-appearance: none;404  appearance: none;405  width: 22px;406  height: 22px;407  margin-top: -9px;408  border-radius: 50%;409  background: var(--accent);410  border: 3px solid var(--surface);411  box-shadow: 0 0 0 1px var(--rule-strong);412}413.ca-range::-moz-range-thumb {414  width: 22px;415  height: 22px;416  border-radius: 50%;417  background: var(--accent);418  border: 3px solid var(--surface);419  box-shadow: 0 0 0 1px var(--rule-strong);420}421.ca-range:focus-visible::-webkit-slider-thumb {422  box-shadow: 0 0 0 3px var(--accent-soft), 0 0 0 4px var(--accent);423}424.ca-range:disabled {425  opacity: 0.4;426  cursor: default;427}428429/* Chart chrome shared by the SVG kit (class names instead of inline styles so theme swaps repaint). */430.ca-chart text {431  font-family: var(--font-ui);432  font-variant-numeric: tabular-nums;433  fill: var(--ink-3);434  font-size: 11px;435}436.ca-chart .axis line,437.ca-chart .grid line {438  stroke: var(--rule);439  stroke-width: 1;440  shape-rendering: crispEdges;441}442.ca-chart .baseline {443  stroke: var(--rule-strong);444}445.ca-chart .series-line {446  fill: none;447  stroke-width: 2;448  stroke-linejoin: round;449  stroke-linecap: round;450}451.ca-chart .forecast {452  stroke-dasharray: 4 4;453}454.ca-chart .ring {455  stroke: var(--surface);456  stroke-width: 2;457}458.ca-chart .label {459  fill: var(--ink-2);460  font-size: 11px;461}462.ca-chart .label-strong {463  fill: var(--ink);464  font-weight: 600;465}466.ca-hatch {467  fill: url(#ca-nodata-hatch);468}469470/* Motion tokens */471@keyframes ca-sheet-up {472  from {473    transform: translateY(24px);474    opacity: 0;475  }476  to {477    transform: none;478    opacity: 1;479  }480}481@keyframes ca-fade {482  from {483    opacity: 0;484  }485  to {486    opacity: 1;487  }488}489.animate-sheet {490  animation: ca-sheet-up 220ms cubic-bezier(0.2, 0.8, 0.2, 1);491}492.animate-fade {493  animation: ca-fade 160ms ease-out;494}495