/* bleedink — the design system in CSS. BRAND.md is the source of truth for every value here;
   a test asserts the :root tokens match its table so the two cannot drift.

   The idea: the page is the black, gold is the ink, violet is where it bleeds. Colour marks what
   matters; nothing is themed. Dark only — a light theme would be a second token block. */

/* ── Fonts ──────────────────────────────────────────────────────────────────────────────────
   IBM Plex Mono + Plex Sans, self-hosted (SIL OFL — see /fonts/OFL.txt), Latin subset, swap.
   No third-party font host: one less dependency at request time and no per-visitor leak. */
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url(/fonts/plex-mono-400.woff2) format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: normal; font-weight: 600; font-display: swap; src: url(/fonts/plex-mono-600.woff2) format("woff2"); }
@font-face { font-family: "IBM Plex Mono"; font-style: italic; font-weight: 400; font-display: swap; src: url(/fonts/plex-mono-400i.woff2) format("woff2"); }
/* Plex Sans upright is served as one variable file covering the weight range (the 400 and 600
   downloads were byte-identical), so a single face declares the range. Mono ships static weights. */
@font-face { font-family: "IBM Plex Sans"; font-style: normal; font-weight: 400 600; font-display: swap; src: url(/fonts/plex-sans-400.woff2) format("woff2"); }
@font-face { font-family: "IBM Plex Sans"; font-style: italic; font-weight: 400; font-display: swap; src: url(/fonts/plex-sans-400i.woff2) format("woff2"); }

/* ── Tokens — BRAND.md §2.1 and §3.2 ──────────────────────────────────────────────────────── */
:root {
    color-scheme: dark;

    --ground: #0B0B0F;
    --chrome: #101016;
    --rule: #1E1E28;
    --surface: #141419;
    --ink: #E6E2DA;
    --ink-muted: #9A968E;
    --gold: #DAA520;
    --gold-bright: #F0BE3C;
    --violet: #B49CFF;
    --violet-deep: #5B3FA6;

    /* Fallback stacks are chosen, not defaulted: the page must read with web fonts blocked. */
    --mono: "IBM Plex Mono", ui-monospace, "Cascadia Code", Consolas, Menlo, monospace;
    --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;

    --measure: 42rem;
}

/* ── Base ───────────────────────────────────────────────────────────────────────────────────
   The page is a column at least the viewport tall, with main taking the slack, so on a short
   page the footer band sits at the bottom of the viewport rather than mid-page above bare
   ground. Not a sticky footer: on a long page it follows the content. */
body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--ground);
    color: var(--ink);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

@media (min-width: 48rem) {
    body { font-size: 18px; }
}

img, video { max-width: 100%; height: auto; }

::selection { background: var(--violet); color: var(--ground); }

/* Violet focus ring on everything focusable, keyboard only. Never outline:none without this. */
:focus-visible { outline: 2px solid var(--violet); outline-offset: 2px; }

a {
    color: var(--gold);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 0.15em;
    transition: color 120ms ease;
}

a:hover { color: var(--gold-bright); }

@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after { transition: none !important; }
}

/* ── Type — BRAND.md §3 ─────────────────────────────────────────────────────────────────────
   Mono where it carries meaning; proportional where people read. Headings in mono, in gold, on
   black is the strongest form of the identity; body prose in mono is the form that tires a reader. */
h1, h2, h3, h4 {
    font-family: var(--mono);
    font-weight: 600;
    line-height: 1.25;
    margin: 2rem 0 0.75rem;
}

h1 { font-size: 2rem; color: var(--gold); margin-top: 0; }
h2 { font-size: 1.375rem; color: var(--gold); }
h3 { font-size: 1.125rem; color: var(--ink); }
h4 { font-size: 1rem; color: var(--ink); }

p, ul, ol, blockquote, pre, table { margin: 0 0 1.25rem; }

code, kbd, samp, pre, time, .meta, .tags, .lang, .draft {
    font-family: var(--mono);
}

/* Inline code: on surface, no border. Block code: on surface, scrolls sideways, never wraps. */
code {
    font-size: 0.9375em;
    background: var(--surface);
    padding: 0.1em 0.35em;
    border-radius: 3px;
}

pre {
    background: var(--surface);
    padding: 1rem 1.25rem;
    border-radius: 4px;
    overflow-x: auto;
    line-height: 1.4;
    font-size: 0.9375rem;
}

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

/* Where a highlighter has tokenised code (the FileServer mounts use GitHub's pl-* classes),
   keywords take the bleed. Our own Markdown pipeline does not tokenise; blocks simply sit on
   the surface. */
.pl-k, .pl-s { color: var(--violet); }
.pl-c { color: var(--ink-muted); }

blockquote {
    border-left: 3px solid var(--violet-deep);
    margin-left: 0;
    padding-left: 1rem;
    color: var(--ink-muted);
}

hr { border: 0; border-top: 1px solid var(--rule); margin: 2rem 0; }

table { border-collapse: collapse; width: 100%; font-size: 0.9375em; }
th, td { text-align: left; padding: 0.4rem 0.6rem; border-bottom: 1px solid var(--rule); }
th { font-family: var(--mono); font-weight: 600; color: var(--ink-muted); }

/* ── Layout — BRAND.md §4 ───────────────────────────────────────────────────────────────────
   One column, one measure. The header and footer bands span the full width so their chrome
   reads as chrome; only their contents are constrained, alongside main. */
header > nav,
main,
footer > div {
    max-width: var(--measure);
    margin: 0 auto;
    padding: 1rem;
}

/* width: 100% matters: as a flex item with auto side margins, main would otherwise shrink to
   its content on a short page instead of holding the measure. */
main {
    flex: 1;
    width: 100%;
    box-sizing: border-box;
    padding: 2.5rem 1rem;
}

header {
    background: var(--chrome);
    border-bottom: 1px solid var(--rule);
}

footer {
    background: var(--chrome);
    border-top: 1px solid var(--rule);
    font-family: var(--mono);
    font-size: 0.875rem;
}

header > nav,
footer > div {
    display: flex;
    gap: 1.25rem;
    align-items: baseline;
}

/* ── Header: wordmark, signature, nav ───────────────────────────────────────────────────── */
header > nav { font-family: var(--mono); font-size: 0.9375rem; }

header > nav a { text-decoration: none; color: var(--ink); }
header > nav a:hover { color: var(--gold-bright); }
header > nav a.active { color: var(--gold); }

/* The wordmark is the domain the request arrived on. It is the first nav item, sits apart from
   the links that follow it, and carries the one signature: a hairline that bleeds from gold to
   violet beneath it. Nowhere else — a signature repeated is a pattern. */
.wordmark {
    margin-right: auto;
    color: var(--gold);
    font-weight: 600;
    position: relative;
    padding-bottom: 0.2rem;
}

.wordmark::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    height: 1px;
    background: linear-gradient(90deg, var(--gold), var(--violet));
}

header > nav a.wordmark:hover { color: var(--gold-bright); }

/* Keyboard users get a way past the header; everyone else never sees it. */
.skip { position: absolute; left: -999px; }
.skip:focus { position: static; display: block; padding: 0.5rem 1rem; }

/* ── Home ──────────────────────────────────────────────────────────────────────────────────
   The site title: Brian's name, bright gold, larger — the one place the name is set large. */
.site-title {
    font-size: 2.5rem;
    color: var(--gold-bright);
    margin: 0 0 0.5rem;
}

.tagline {
    color: var(--ink-muted);
    margin: 0 0 2.5rem;
}

.repo-list { list-style: none; padding: 0; }
.repo-list > li { margin-bottom: 1.5rem; }
.repo-list > li > a { font-family: var(--mono); font-weight: 600; text-decoration: none; }
.repo-list > li > a:hover { text-decoration: underline; }
.repo-list .lang { margin-left: 0.6rem; font-size: 0.8125rem; color: var(--violet); }
.repo-list p { margin: 0.25rem 0 0; }

/* ── Writing (suppressed in v1; styled anyway) ───────────────────────────────────────────── */
.post-list { list-style: none; padding: 0; }
.post-list > li { margin-bottom: 2.25rem; }
.post-list > li > a { font-family: var(--mono); font-weight: 600; font-size: 1.125rem; text-decoration: none; }
.post-list > li > a:hover { text-decoration: underline; }
.post-list time { display: block; font-size: 0.8125rem; color: var(--ink-muted); margin-top: 0.15rem; }
.post-list p { margin: 0.35rem 0 0; }

article > header { margin-bottom: 2rem; }
article > header time,
article > header span { font-size: 0.8125rem; color: var(--ink-muted); }
article > header span { margin-left: 0.75rem; }

.tags a {
    margin-right: 0.6rem;
    font-size: 0.8125rem;
    color: var(--violet);
    text-decoration: none;
}
.tags a:hover { text-decoration: underline; }

.draft {
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--ink-muted);
    margin-left: 0.6rem;
}

/* ── /docs — the FileServer component in the skin (BRAND.md §5) ─────────────────────────
   IncludeDefaultStyles is off on the /docs mount, so the component emits its markup — the
   bnfs- classes — and nothing else: no stylesheet, no colour-scheme toggle, no script. The
   chrome is mono, like the header; a rendered document inside .bnfs-markdown inherits the
   base rules above and needs nothing of its own. /files keeps the component's own layout. */
.bnfs-header {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.5rem 1.25rem;
    font-family: var(--mono);
    padding-bottom: 0.5rem;
    margin-bottom: 1.5rem;
    border-bottom: 1px solid var(--rule);
}

/* The crumb trail is the page's title: the mount, the path, and the current name in ink. */
.bnfs-crumbs {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 1.125rem;
    font-weight: 600;
}

.bnfs-crumbs li + li::before { content: "/"; margin-right: 0.35rem; color: var(--ink-muted); }
.bnfs-crumbs a { text-decoration: none; }
.bnfs-crumbs a:hover { text-decoration: underline; }
.bnfs-current { color: var(--ink); }

/* Up, View raw and Download are actions, so gold: plain words, no borders, no fills. */
.bnfs-actions { display: flex; gap: 1rem; font-size: 0.875rem; }
.bnfs-btn { color: var(--gold); text-decoration: none; }
.bnfs-btn:hover { color: var(--gold-bright); text-decoration: underline; }
.bnfs-btn-icon { margin-right: 0.3em; }

/* The listing. Ligatures off because a file name is an exact string; sizes and dates muted, in
   tabular figures; a row takes the surface on hover. No icons: the slash the component appends
   to a directory name says what the emoji said, the way ls -p does. */
.bnfs-table { font-family: var(--mono); font-size: 0.875rem; font-variant-ligatures: none; line-height: 1.4; }
.bnfs-table a { text-decoration: none; }
.bnfs-table a:hover { text-decoration: underline; }
.bnfs-table tbody tr:hover { background: var(--surface); }
.bnfs-name { width: 100%; overflow-wrap: anywhere; }
.bnfs-size, .bnfs-date { color: var(--ink-muted); font-variant-numeric: tabular-nums; white-space: nowrap; }
.bnfs-icon { display: none; }
.bnfs-empty { font-family: var(--mono); color: var(--ink-muted); }

@media (max-width: 40rem) {
    .bnfs-date, .bnfs-date-h { display: none; }
}
