App tree
/app/root.css
@import url("https://fonts.googleapis.com/css2?family=Fredoka:wght@400;500;600&display=swap");
@import url("https://fonts.googleapis.com/css2?family=Nunito+Sans:ital,wght@0,400;0,700;1,400&display=swap");
@import url("https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap");
:root {
color-scheme: light dark;
scrollbar-color: var(--scrollbar-thumb) transparent;
touch-action: manipulation;
interpolate-size: allow-keywords;
/* Brand hues. Every shade below is derived from these in oklch. */
--hue-navy: 275;
--hue-pink: 355;
--navy: oklch(32% 0.11 var(--hue-navy));
--navy-deep: oklch(18% 0.06 var(--hue-navy));
--deep-purple: oklch(28% 0.08 var(--hue-navy));
--blue-background: var(--navy);
--pink: oklch(66% 0.16 var(--hue-pink));
--pink-soft: light-dark(
oklch(80% 0.08 var(--hue-pink)),
oklch(68% 0.08 var(--hue-pink))
);
--lime: oklch(88% 0.17 125);
--sun: oklch(84% 0.15 80);
--sand: oklch(87% 0.09 95);
/* Legacy palette used by demos */
--dark: var(--text);
--bright: var(--surface-raised);
--red: oklch(62% 0.2 20);
--orange: oklch(78% 0.17 75);
--yellow: oklch(90% 0.16 95);
--yellow-bright: oklch(96% 0.06 95);
--green-dark: oklch(58% 0.15 150);
--green: oklch(70% 0.18 150);
--green-bright: light-dark(oklch(94% 0.07 150), oklch(30% 0.06 150));
--red-bright: light-dark(oklch(93% 0.04 20), oklch(28% 0.06 20));
--gray: light-dark(
oklch(70% 0.02 var(--hue-navy)),
oklch(45% 0.03 var(--hue-navy))
);
--gray-1: #fff;
--white: var(--surface-raised);
--blue-dark: oklch(30% 0.12 260);
--blue: oklch(62% 0.19 260);
--blue-bright: light-dark(oklch(95% 0.03 260), oklch(30% 0.07 260));
/* Themed surfaces. Dark mode is near-black indigo, light mode a cool off-white. */
--surface: light-dark(
oklch(94.5% 0.014 300),
oklch(14% 0.02 var(--hue-navy))
);
--surface-raised: light-dark(
oklch(98.5% 0.006 300),
oklch(19% 0.025 var(--hue-navy))
);
--surface-sunken: light-dark(
oklch(91% 0.018 300),
oklch(11% 0.018 var(--hue-navy))
);
--surface-overlay: light-dark(
oklch(98% 0.006 300 / 85%),
oklch(16% 0.02 var(--hue-navy) / 85%)
);
--text: light-dark(
oklch(28% 0.06 var(--hue-navy)),
oklch(88% 0.012 var(--hue-navy))
);
--text-muted: light-dark(
oklch(48% 0.04 var(--hue-navy)),
oklch(64% 0.03 var(--hue-navy))
);
--accent: light-dark(
oklch(56% 0.17 var(--hue-pink)),
oklch(64% 0.1 var(--hue-pink))
);
--accent-soft: color-mix(in oklab, var(--accent) 12%, transparent);
--accent-contrast: #fff;
/* Solid buttons keep the light-theme pink in both modes. */
--button-background: oklch(56% 0.17 var(--hue-pink));
--button-text: #fff;
--border: light-dark(
oklch(28% 0.06 var(--hue-navy) / 12%),
oklch(100% 0 0 / 10%)
);
--border-strong: light-dark(
oklch(28% 0.06 var(--hue-navy) / 24%),
oklch(100% 0 0 / 20%)
);
--shadow: 0 1px 2px
light-dark(oklch(28% 0.06 var(--hue-navy) / 8%), oklch(0% 0 0 / 40%));
--shadow-lg: 0 16px 40px -12px
light-dark(oklch(28% 0.06 var(--hue-navy) / 25%), oklch(0% 0 0 / 70%));
--shadow-bar: 0 4px 16px -8px
light-dark(oklch(28% 0.06 var(--hue-navy) / 35%), oklch(0% 0 0 / 80%));
--scrollbar-thumb: light-dark(
oklch(28% 0.06 var(--hue-navy) / 25%),
oklch(100% 0 0 / 18%)
);
--accent-color: var(--accent);
accent-color: var(--accent-color);
/* Chrome: header and footer. Brand navy in light mode, near-black in dark. */
--chrome-background: light-dark(var(--navy), oklch(12% 0.02 var(--hue-navy)));
--chrome-color: oklch(90% 0.012 var(--hue-navy));
--chrome-muted: oklch(74% 0.03 var(--hue-navy));
--chrome-border: oklch(100% 0 0 / 10%);
--body-background: var(--chrome-background);
--body-color: var(--chrome-color);
--header-background: color-mix(
in oklab,
var(--chrome-background) 85%,
transparent
);
--header-link-color: var(--chrome-muted);
--header-link-hover-color: #fff;
--footer-background: var(--chrome-background);
--footer-color: var(--chrome-muted);
--main-background: var(--surface);
--main-color: var(--text);
--main-link-color: var(--accent);
--breadcrumbs-background: transparent;
--breadcrumbs-color: var(--text-muted);
--menu-background: light-dark(
color-mix(in oklab, var(--pink) 6%, var(--surface)),
var(--surface-sunken)
);
--menu-color: var(--text);
--menu-link-color: var(--text-muted);
--slightly-darker: var(--border);
--slightly-brighter: light-dark(oklch(100% 0 0 / 60%), oklch(100% 0 0 / 12%));
--link-color: var(--accent);
--thin-border: 1px solid var(--border);
--radius: 0.625rem;
--radius-sm: 0.375rem;
height: 100%;
min-height: 100svh;
--page-max-width: 60rem;
--header-height: 3.5rem;
--font-heading: "Fredoka", "Fredoka Fallback", "Nunito Sans", sans-serif;
--font-regular: "Nunito Sans", "Nunito Sans Fallback", system-ui, sans-serif;
--font-mono:
"IBM Plex Mono", "IBM Plex Mono Fallback", ui-monospace, monospace;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
*,
*::before,
*::after {
box-sizing: border-box;
line-height: inherit;
font-size: inherit;
}
body {
margin: 0;
padding: 0;
overflow-y: scroll;
/* Repeated here so the viewport scrollbar follows the theme switcher, which
sets color-scheme on body rather than on the root. */
scrollbar-color: var(--scrollbar-thumb) transparent;
min-height: 100svh;
background: var(--body-background);
color: var(--body-color);
font-family: var(--font-regular);
line-height: 1.6;
/* No fixed height: the body must grow with its content, or sticky
children stop following once the viewport height is scrolled past. */
min-height: 100svh;
display: grid;
/* The header row is fixed so the start page hero can span it. */
grid-template-rows: var(--header-height) 1fr auto;
grid-template-columns: 1fr;
}
:is(h1, h2, h3, h4, h5, h6) {
font-family: var(--font-heading);
font-weight: 500;
letter-spacing: -0.01em;
}
:is(pre, code) {
font-family: var(--font-mono);
}
::view-transition-group(root) {
animation-duration: 200ms;
}