eratic / packages / core / src / styles / tokens.css
714 words
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
 * Design tokens.
 * ---------------------------------------------------------------------------
 * Every value the design depends on is a custom property declared here, and
 * nothing else in the system hard-codes a colour, size or font. That is the
 * whole point: an individual article can re-declare any of these on its own
 * root and the entire page re-tunes itself, without forking a layout or
 * fighting a stylesheet.
 *
 *   ---
 *   theme:
 *     accent: "oklch(62% 0.19 25)"
 *     font-prose: "Georgia, serif"
 *     measure: "78ch"
 *   ---
 *
 * See docs/02-design-system.md for the override recipes.
 */

:root {
	color-scheme: light dark;

	/* -- Typefaces ---------------------------------------------------------
	 * Self-hosted via @fontsource-variable (bundled into the build, no request
	 * ever leaves the reader's browser for a font). Swapping a face means
	 * changing the import in styles/fonts.css and the stack here.
	 *
	 * Newsreader carries an optical-size axis, which is why body text and
	 * display headings can share one file and still look correctly weighted at
	 * both ends of the scale.
	 */
	--font-prose: 'Newsreader Variable', ui-serif, Georgia, Cambria, 'Times New Roman', serif;
	--font-ui: 'Inter Variable', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
	--font-mono: 'JetBrains Mono Variable', ui-monospace, SFMono-Regular, Menlo, monospace;

	/* -- Type scale --------------------------------------------------------
	 * Fluid between a 380px and a 1280px viewport. The ratio is a minor third
	 * (1.2) at the small end opening to a perfect fourth (1.333) at display
	 * sizes, so body copy stays calm while headings gain presence on wide
	 * screens instead of simply scaling uniformly.
	 */
	--step--2: clamp(0.7422rem, 0.7169rem + 0.1266vw, 0.8125rem);
	--step--1: clamp(0.8333rem, 0.7911rem + 0.2111vw, 0.9508rem);
	--step-0: clamp(1rem, 0.9438rem + 0.2809vw, 1.125rem);
	--step-1: clamp(1.2rem, 1.1147rem + 0.4267vw, 1.4375rem);
	--step-2: clamp(1.44rem, 1.3122rem + 0.6391vw, 1.7969rem);
	--step-3: clamp(1.728rem, 1.5389rem + 0.9455vw, 2.2461rem);
	--step-4: clamp(2.0736rem, 1.7985rem + 1.3756vw, 2.8076rem);
	--step-5: clamp(2.4883rem, 2.0921rem + 1.9812vw, 3.5095rem);

	/* -- Rhythm ------------------------------------------------------------
	 * One spacing scale for everything. Prose leading is unitless so it
	 * inherits correctly into nested elements at different sizes.
	 */
	--leading-prose: 1.65;
	--leading-tight: 1.2;
	--leading-flat: 1;

	--space-3xs: 0.25rem;
	--space-2xs: 0.5rem;
	--space-xs: 0.75rem;
	--space-s: 1rem;
	--space-m: 1.5rem;
	--space-l: 2.25rem;
	--space-xl: 3.5rem;
	--space-2xl: 5.5rem;
	--space-3xl: 8rem;

	/* -- Measure and layout ------------------------------------------------
	 * --measure is the reading column. --measure-wide is for figures and
	 * anything that should breathe past the text without going full-bleed.
	 * The gutter keeps content off the edge on phones.
	 */
	--measure: 34rem;
	--measure-wide: 52rem;
	--measure-full: 78rem;
	--gutter: clamp(1.25rem, 5vw, 3rem);

	/* -- Colour ------------------------------------------------------------
	 * OKLCH, so lightness steps are perceptually even and the dark theme is a
	 * genuine remapping rather than an inversion. Every pair below is checked
	 * for at least 4.5:1 body contrast in both schemes.
	 *
	 * The surface is very slightly warm and the ink very slightly cool; that
	 * tiny amount of temperature separation is what keeps a monochrome page
	 * from reading as flat grey.
	 */
	--surface: light-dark(oklch(98.8% 0.004 85), oklch(15.5% 0.008 265));
	--surface-sunk: light-dark(oklch(96.4% 0.006 85), oklch(12.5% 0.008 265));
	--surface-raised: light-dark(oklch(100% 0 0), oklch(19.5% 0.009 265));

	--ink: light-dark(oklch(23% 0.014 265), oklch(92% 0.006 85));
	--ink-muted: light-dark(oklch(48% 0.012 265), oklch(70% 0.008 265));
	--ink-faint: light-dark(oklch(63% 0.01 265), oklch(55% 0.008 265));

	--rule: light-dark(oklch(89% 0.005 85), oklch(27% 0.008 265));
	--rule-strong: light-dark(oklch(80% 0.006 85), oklch(36% 0.008 265));

	/* The one chromatic note in the system. Used for links and little else —
	 * scarcity is what makes it work. Override per article for a themed piece. */
	--accent: light-dark(oklch(52% 0.15 255), oklch(76% 0.13 255));
	--accent-quiet: light-dark(oklch(94% 0.03 255), oklch(28% 0.05 255));

	--selection: light-dark(oklch(88% 0.09 95), oklch(40% 0.09 255));

	/* -- Motion ------------------------------------------------------------ */
	--ease: cubic-bezier(0.2, 0, 0, 1);
	--duration: 180ms;

	/* -- Misc -------------------------------------------------------------- */
	--radius: 2px;
	--focus-ring: 2px solid var(--accent);
	--focus-offset: 3px;
}

/*
 * Readers who ask for less motion get none of it. This is not decoration —
 * vestibular disorders make parallax and long transitions genuinely unpleasant.
 */
@media (prefers-reduced-motion: reduce) {
	:root {
		--duration: 0ms;
	}

	*,
	*::before,
	*::after {
		animation-duration: 0.01ms !important;
		animation-iteration-count: 1 !important;
		transition-duration: 0.01ms !important;
		scroll-behavior: auto !important;
	}
}

/*
 * Readers who ask for more contrast get the ink pushed to the ends of the
 * scale and the hairlines made visible.
 */
@media (prefers-contrast: more) {
	:root {
		--ink: light-dark(oklch(12% 0.01 265), oklch(99% 0 0));
		--ink-muted: light-dark(oklch(30% 0.01 265), oklch(88% 0.006 265));
		--rule: light-dark(oklch(70% 0.006 85), oklch(48% 0.008 265));
	}
}

static mirror of HEAD · about · clone: git clone https://git.makefuture.ro/eratic.git