210 lines
9.9 KiB
CSS
210 lines
9.9 KiB
CSS
@import "tailwindcss";
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Lora, vendored from Google Fonts — self-hosted, not linked.
|
|
---------------------------------------------------------------------------
|
|
The files live in wwwroot/fonts (served by the dev server straight out of
|
|
./wwwroot), so the app pulls no third-party request at runtime: no CDN to be
|
|
blocked, no extra DNS round trip, and no dependency on fonts.gstatic.com being
|
|
up. It is a VARIABLE font, so ONE file per style covers weights 400-700 —
|
|
hence "font-weight: 400 700" rather than a file per weight.
|
|
|
|
Only the latin and latin-ext subsets are vendored (~120 KB in total). The
|
|
unicode-range on each face is what lets the browser skip downloading latin-ext
|
|
entirely unless the page actually uses a character from it.
|
|
|
|
To refresh: fetch
|
|
https://fonts.googleapis.com/css2?family=Lora:ital,wght@0,400..700;1,400..700
|
|
and re-download the woff2 URLs it names.
|
|
--------------------------------------------------------------------------- */
|
|
|
|
@font-face {
|
|
font-family: "Lora";
|
|
font-style: italic;
|
|
font-weight: 400 700; /* a variable font: one file covers the whole range */
|
|
font-display: swap;
|
|
src: url("/fonts/lora-latin-ext-italic.woff2") format("woff2");
|
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Lora";
|
|
font-style: italic;
|
|
font-weight: 400 700; /* a variable font: one file covers the whole range */
|
|
font-display: swap;
|
|
src: url("/fonts/lora-latin-italic.woff2") format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Lora";
|
|
font-style: normal;
|
|
font-weight: 400 700; /* a variable font: one file covers the whole range */
|
|
font-display: swap;
|
|
src: url("/fonts/lora-latin-ext-normal.woff2") format("woff2");
|
|
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
|
}
|
|
|
|
@font-face {
|
|
font-family: "Lora";
|
|
font-style: normal;
|
|
font-weight: 400 700; /* a variable font: one file covers the whole range */
|
|
font-display: swap;
|
|
src: url("/fonts/lora-latin-normal.woff2") format("woff2");
|
|
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Dark mode: `dark:` as a CLASS, not a media query.
|
|
---------------------------------------------------------------------------
|
|
Tailwind's built-in dark variant follows the operating system. A site with its own
|
|
theme switch cannot use it: the OS says one thing, the switch says another, and the
|
|
media query wins — so the switch appears to do nothing.
|
|
|
|
This redefines it against a class on <html>, which webui.Theme toggles. The OS is
|
|
still respected: it is the DEFAULT (see the boot script in server/main.go), just no
|
|
longer the last word.
|
|
--------------------------------------------------------------------------- */
|
|
@custom-variant dark (&:where(.dark, .dark *));
|
|
|
|
/* App-side design tokens the webui kit references (Tailwind v4 @theme). Brand
|
|
values live with the app; the kit stays generic.
|
|
|
|
The surface/line/ink tokens are the kit's THEME CONTRACT (see webui.ThemeTokens):
|
|
components say bg-surface / border-line / text-ink and never name a colour, so the
|
|
whole kit changes theme by changing these ten values rather than by carrying a dark:
|
|
variant on four hundred class strings. */
|
|
@theme {
|
|
--radius-default: 0.375rem;
|
|
|
|
/* Navy and red — the flag, muted. kjøl is a Norwegian word and the palette says so.
|
|
Both are dark and low-key: the page is mostly prose, code and tables, and the brand's
|
|
job is to mark the few things you can act on, not to compete with them for attention.
|
|
(The previous sky blue did the same job, but said nothing.) */
|
|
--color-primary: #1e3a63; /* muted navy — FILLS; they carry white text */
|
|
--color-primary-hover: #16294a;
|
|
--color-primary-subtle: #eef2f8; /* a navy wash — tinted panels, badges, callouts */
|
|
--color-primary-border: #c5d1e2;
|
|
|
|
/* accent is for TEXT and icons, and it is the RED — which is why it is a separate token
|
|
from primary rather than a lighter shade of it. The two have opposite constraints: a
|
|
fill must be dark enough for white text on top of it, and accent text must be readable
|
|
ON the surface. Here they are not even the same hue: navy fills, red links. */
|
|
--color-accent: #9e1b32; /* dark red */
|
|
|
|
/* Surfaces, lines, ink — the kit's theme contract. */
|
|
--color-surface: #ffffff;
|
|
--color-surface-muted: #fafafa;
|
|
--color-surface-raised: #f5f5f5;
|
|
--color-surface-strong: #e5e5e5;
|
|
--color-line: #e5e5e5;
|
|
--color-line-strong: #d4d4d4;
|
|
--color-ink: #171717;
|
|
--color-ink-soft: #525252;
|
|
--color-ink-muted: #737373;
|
|
--color-ink-faint: #a3a3a3;
|
|
|
|
--color-text-heading: #111827;
|
|
--color-text-on-dark: #f9fafb;
|
|
--color-text-on-dark-muted: #9ca3af;
|
|
|
|
/* Lora is the body face. Declaring it as --font-sans makes it the default for
|
|
everything (Tailwind's preflight sets `font-family: var(--font-sans)` on
|
|
html), and also gives you `font-sans` as a utility. --font-serif points at it
|
|
too, so `font-serif` is not a different, unvendored face. */
|
|
--font-sans: "Lora", ui-serif, Georgia, Cambria, "Times New Roman", serif;
|
|
--font-serif: "Lora", ui-serif, Georgia, Cambria, "Times New Roman", serif;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
Grid background
|
|
---------------------------------------------------------------------------
|
|
Plain CSS, not a utility: Tailwind's arbitrary-value syntax cannot carry a
|
|
background-image with commas in it without becoming unreadable, and this is a
|
|
single named thing rather than a composition of atoms. kjol's Tailwind engine
|
|
passes rules it does not recognise straight through, so this lands in the output
|
|
untouched.
|
|
|
|
The grid is drawn with two 1px gradients — a vertical set and a horizontal set —
|
|
tiled at --grid-size. It is deliberately faint: it should register as texture, not
|
|
as graph paper you have to read the page through.
|
|
--------------------------------------------------------------------------- */
|
|
:root {
|
|
--grid-line: rgba(30, 58, 99, 0.06); /* the navy, at the edge of visible */
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------------
|
|
The dark theme.
|
|
---------------------------------------------------------------------------
|
|
Only the token VALUES change. Not one component knows this block exists — they ask
|
|
for bg-surface and text-ink, and here is where those come to mean something else.
|
|
|
|
This is a plain rule, not another @theme block: @theme generates utilities, and these
|
|
are overrides of utilities that already exist.
|
|
|
|
The surfaces are not pure black. Black gives a dark UI a hard, glaring edge against
|
|
white text and makes every border invisible; a very dark grey leaves room for the
|
|
raised surfaces and lines above it to actually be seen. --------------------------- */
|
|
.dark {
|
|
--color-surface: #101013;
|
|
--color-surface-muted: #17171b;
|
|
--color-surface-raised: #1f1f24;
|
|
--color-surface-strong: #2c2c33;
|
|
--color-line: #2a2a30;
|
|
--color-line-strong: #3d3d45;
|
|
--color-ink: #f2f2f3;
|
|
--color-ink-soft: #c6c6cc;
|
|
--color-ink-muted: #9a9aa3;
|
|
--color-ink-faint: #71717a;
|
|
|
|
/* Both brand tokens move in the dark, and for different reasons.
|
|
|
|
The accent has to CLIMB: a dark red on a near-black surface is unreadable, so it goes
|
|
up to a light rose. It is still the flag's red, just the only version of it you can
|
|
read here.
|
|
|
|
The fill has to climb too — which the sky blue it replaced did not. Navy is dark
|
|
enough that on a #101013 page a navy button loses its edges and reads as a hole in the
|
|
surface. So it lifts to a steel blue that still carries white text (~7:1) and still
|
|
looks like a button. */
|
|
--color-accent: #f0a3ad;
|
|
--color-primary: #2b4f80;
|
|
--color-primary-hover: #37619b;
|
|
--color-primary-subtle: #182234;
|
|
--color-primary-border: #2c3e5c;
|
|
|
|
--color-text-heading: #f5f5f5;
|
|
|
|
/* The grid is drawn in ink, not in shadow, once the page is dark. */
|
|
--grid-line: rgba(226, 232, 240, 0.05);
|
|
}
|
|
|
|
/* The page's own background — painted before the app mounts, and behind it afterwards.
|
|
Without this, a dark app sits in a white window. */
|
|
html {
|
|
background-color: var(--color-surface);
|
|
color: var(--color-ink);
|
|
}
|
|
|
|
.bg-grid {
|
|
background-image:
|
|
linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
|
|
linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
|
|
/* Written out rather than as var(--size) var(--size): the CSS minifier drops the
|
|
space between two adjacent var() calls, and while that is still legal CSS, a
|
|
background-size that depends on how a minifier tokenises is not worth the cleverness. */
|
|
background-size: 56px 56px;
|
|
background-position: center top;
|
|
}
|
|
|
|
/* Fades the grid out towards the bottom, so it frames the hero and then gets out of
|
|
the way of the content below rather than running under it the whole page. */
|
|
.grid-fade {
|
|
-webkit-mask-image: linear-gradient(to bottom, #000, #000 35%, transparent 100%);
|
|
mask-image: linear-gradient(to bottom, #000, #000 35%, transparent 100%);
|
|
}
|
|
|
|
/* (The hero glow that used to live here went with the hero. A coloured wash behind an
|
|
oversized headline is the most recognisable gesture in framework marketing, and this
|
|
page is not making that argument any more.) */
|