/* ------------------------------------------------------------------
   Self-hosted webfonts -- GENERATED, do not hand-edit this block.
   Regenerate with: bash design/fonts/fetch-fonts.sh

   Sourced from Google Fonts but served from our own domain: linking
   fonts.googleapis.com hands every visitor's IP to Google before the
   page renders, which is a GDPR problem for an EU audience, and adds a
   third-party DNS + TLS round trip to the critical path.

   JetBrains Mono ships as one variable file (400-700).
   Newsreader ships as static instances -- its variable build carries an
   optical-size axis that more than doubles the file for no benefit here.

   The latin-ext files are a safety net only: every Portuguese diacritic
   lives in U+00C0-00FF, inside the latin subset, so latin-ext is never
   fetched for the content we actually publish.
   ------------------------------------------------------------------ */

@font-face {
    font-family: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/jetbrains-mono-var-latin-ext.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: 'JetBrains Mono';
    font-style: normal;
    font-weight: 400 700;
    font-display: swap;
    src: url('/fonts/jetbrains-mono-var-latin.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: 'Newsreader';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/newsreader-400-italic-latin-ext.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: 'Newsreader';
    font-style: italic;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/newsreader-400-italic-latin.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: 'Newsreader';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/newsreader-400-latin-ext.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: 'Newsreader';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('/fonts/newsreader-400-latin.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: 'Newsreader';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('/fonts/newsreader-600-latin-ext.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: 'Newsreader';
    font-style: normal;
    font-weight: 600;
    font-display: swap;
    src: url('/fonts/newsreader-600-latin.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;
}
/* ------------------------------------------------------------------
   Type system

   Chrome is mono, running text is serif. Navigation, headings, dates,
   badges and buttons are set in JetBrains Mono; anything that is read
   as a paragraph is set in Newsreader.

   Tailwind's default `sans` stack is remapped to JetBrains Mono in
   baseof.html, so mono is what every element inherits. Prose containers
   below opt back out. That direction -- mono by default, serif on
   purpose -- is deliberate: chrome is the larger surface, and a missed
   selector degrades to mono, which is the house style, rather than to a
   system sans that belongs to neither.

   Weights available: JetBrains Mono 400-700 (variable), Newsreader 400
   and 600 only. Do not ask for a weight outside those -- the browser
   will synthesise it and the result is visibly smeared.
   ------------------------------------------------------------------ */

:root {
    --font-mono: 'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    --font-serif: 'Newsreader', Georgia, 'Times New Roman', serif;

    /* Warm neutrals. These mirror the `gray` ramp overridden in baseof.html's
       tailwind.config -- the utilities cover the templates, these cover the
       rules below, and the two must stay in step. Pure white was dropped as a
       surface entirely: a cream page with a white card reads as a bug, and the
       lower luminance is easier on the eye over a long post. */
    --ink:        #1e1a14;  /* headings, gray-900 */
    --ink-body:   #453e32;  /* running text, gray-700 */
    --ink-muted:  #5a5142;  /* secondary text, gray-600 */
    --wash:       #e5dcca;  /* inline code fill, gray-100 */
    --accent:     #3b6472;  /* links, accent-600 -- sampled from the logo */
    --accent-hi:  #2e505c;  /* link hover, accent-700 */
}

/* Headings carry their tracking as Tailwind `tracking-*` utilities in the
   templates, not as a rule here -- a bare `h1` selector loses to any utility
   class, so a rule at this level would apply only sometimes. Markdown-generated
   headings inside .prose have no classes, so those are set below. */

.fade-in {
    animation: fadeIn 0.3s ease-in;
}

@keyframes fadeIn {
    from {
        opacity: 0;
        transform: translateY(10px);
    }
    to {
        opacity: 1;
        transform: translateY(0);
    }
}

@media (prefers-reduced-motion: reduce) {
    .fade-in {
        animation: none;
    }
}

/* Reserve the scrollbar gutter on every page, scrolling or not. Without it a
   short page (the blog index) has no scrollbar and a long one (the homepage)
   does, so the viewport is ~15px narrower on the long page and every centred
   max-w-* container lands ~7px further left -- the nav logo visibly jumps as
   you move between pages.

   scrollbar-gutter only, deliberately: `overflow-y: scroll` achieves the same
   thing but forces a permanent visible scrollbar track on Windows and Linux
   even for pages that do not scroll, plus a dead scroll region. On a public
   site that is a worse artefact than the shift it fixes.

   Where scrollbar-gutter is unsupported (Safari < 18.2) the nav still cannot
   drift out of line with the page content, because the nav is position:sticky
   and so is measured against the same box as everything below it. */
html {
    scroll-behavior: smooth;
    scrollbar-gutter: stable;
}

/* ---------------------------- prose ---------------------------- */

/* The measure is part of the typeface decision, not separate from it. The
   article container was max-w-4xl, which ran to roughly 95 characters a line --
   fine for the old system sans, actively worse for a reading serif, which is
   the whole reason for switching.

   Set in rem, not ch: `ch` measures the width of "0", and Newsreader's zero is
   far narrower than its average letter, so a ch-based cap came out ~25% wider
   than intended. Measured instead: Newsreader at 1.125rem averages ~7.8px per
   character, so a 70-75 character line is ~34rem of text.

   The container does the work -- max-w-2xl minus the article's p-8 and the
   wrapper's lg:px-8 leaves almost exactly 34rem, so the text fills its card
   with no ragged gutter. The max-width below is a cap for any wider container,
   not the thing setting the measure here.

   The `max-w-none` utility was removed from the templates rather than
   overridden here, so nothing in the cascade fights this. */
.prose {
    font-family: var(--font-serif);
    max-width: none;
    color: var(--ink-body);
    font-size: 1.125rem;
    line-height: 1.75;
}

.prose p {
    margin-bottom: 1.25em;
}

/* Headings inside prose stay mono -- they are structure, not reading. */
.prose h1, .prose h2, .prose h3 {
    font-family: var(--font-mono);
    color: var(--ink);
    font-weight: 700;
    letter-spacing: -0.035em;
}

/* Newsreader has no 700; 600 is its bold. Leaving this at the browser
   default of 700 would trigger synthetic bolding. */
.prose strong {
    font-weight: 600;
    color: var(--ink);
}

.prose em {
    font-style: italic;
}

.prose a {
    color: var(--accent);
    text-decoration: none;
}

.prose a:hover {
    color: var(--accent-hi);
}

/* Mono runs optically larger than serif at the same pixel size, so inline
   code is stepped down to sit level with the surrounding sentence. */
.prose code {
    font-family: var(--font-mono);
    font-size: 0.875em;
    background: var(--wash);
    color: var(--ink);
    padding: 0.1em 0.35em;
    border-radius: 0.25rem;
}

.prose pre {
    font-family: var(--font-mono);
    font-size: 0.875rem;
    line-height: 1.6;
    overflow-x: auto;
}

.prose pre code {
    background: none;
    padding: 0;
    font-size: inherit;
}

/* ------------------------ homepage intro ------------------------ */

.hero-prose {
    font-family: var(--font-serif);
    color: var(--ink-muted);
    font-size: 1.125rem;
    line-height: 1.75;
}

.hero-prose p {
    margin-bottom: 1rem;
}

/* Lead paragraph: size carries the emphasis. Weight deliberately stays at
   400 -- Newsreader ships 400 and 600 here, and 500 would round to one of
   them unpredictably. */
.hero-prose p:first-of-type {
    font-size: 1.375rem;
    line-height: 1.5;
    font-weight: 400;
    color: var(--ink);
    margin-bottom: 1.25rem;
}

.hero-prose strong {
    color: var(--ink);
    font-weight: 600;
}

.hero-prose code {
    font-family: var(--font-mono);
    font-size: 0.875em;
}
