/* aincient-labs.com — prose pages (blog, security advisories, imprint, privacy, 404).
   Monograph bridge (DECISIONS 0490): loads after chrome.css, which owns the face, the tokens, the
   masthead and the footer. Pages sit as one spread: the masthead in the left column, the text in
   the right at reading width. */

:root {
  /* Monograph bridge (0490): the brand tokens live in chrome.css (load it first). These names
     are this sheet's own vocabulary, aliased onto them; nothing here is a second source. */
  --card: var(--paper); --paper-2: var(--well);
  --muted: var(--grey);
  --line: var(--hair); --line-strong: color-mix(in srgb, var(--ink) 16%, transparent);
  --cinnabar: var(--mark); --cinnabar-deep: var(--mark);
  --on-accent: var(--mark-ink);
  --mint:#0E8A5F; --coral:#C4432F; --amber:#B87400;
  /* Square, flat paper: depth only where a physical object sits on a photo (DESIGN.md). */
  --shadow: none; --shadow-lift: none;
  --r1:0; --r2:0; --r3:0; --r4:0;
  /* code cards — see .code-block. The status hues pulled DARKER so 14px code clears AA. */
  --code-edge: var(--line-strong);
  --code-string:#0C7A54; --code-number:#A66700;
  /* Diagram strokes are OPAQUE: an arrowhead drawn in a translucent colour
     compounds with the lane running under it and reads as a darker blob. */
  --dgm-stroke:#BDB7AC; --dgm-edge:#DCD6CB;


  --wrap: 960px;
}

@media (prefers-color-scheme: dark) {
  :root {
    --mint:#3FCF9B; --coral:#F0715C; --amber:#E0A23C;
    --dgm-stroke:#6C665C; --dgm-edge:#3C3730;
    /* on the dark paper the status hues already clear AA. */
    --code-string:var(--mint); --code-number:var(--amber);
  }
}

*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } }

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3 {
  font-family: var(--sans);
  font-weight: 500;
  line-height: 1.1;
  letter-spacing: -.022em;
  text-wrap: balance;
  margin: 0;
}
h3 { letter-spacing: -.01em; }
p { margin: 0; max-width: 66ch; }

img { max-width: 100%; height: auto; display: block; }
code { font-family: var(--mono); }
strong { font-weight: 600; }

.wrap { width: 100%; max-width: var(--wrap); margin-inline: auto; padding-inline: 28px; }

/* command block — a quiet terminal, not a glowing box */
.cmd {
  display: flex; align-items: center; gap: 12px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: var(--r3);
  padding: 14px 14px 14px 18px;
  box-shadow: var(--shadow);
  max-width: 700px;
  overflow: hidden;
}
/* Prompt shares the command's exact font metrics so the centred row puts `$` on the command's
   baseline — otherwise the 17px body-size `$` rides low next to 14.5px code. (Not `align-items:
   baseline`: the taller Copy button then pushes the text to the top of the box.) */
.cmd-prompt { color: var(--muted); font-family: var(--mono); font-size: 14.5px; line-height: 1.45; user-select: none; }
.cmd code {
  flex: 1; min-width: 0;
  font-size: 14.5px; color: var(--ink); line-height: 1.45;
  /* Wrap at spaces instead of scrolling — no horizontal scrollbar. Fits on one
     line at the box's desktop width; wraps cleanly on narrow viewports. */
  white-space: normal; overflow-wrap: break-word; word-break: normal;
}
.cmd-copy {
  display: inline-flex; align-items: center; gap: 7px; flex-shrink: 0;
  font-family: var(--sans); font-size: 13px; font-weight: 500;
  color: var(--muted); background: var(--paper-2);
  border: 1px solid var(--line); border-radius: var(--r1);
  padding: 6px 11px; cursor: pointer;
  transition: color .15s ease, border-color .15s ease;
}
.cmd-copy:hover { border-color: var(--muted); color: var(--ink); }
.cmd-copy.is-copied { color: var(--cinnabar); border-color: var(--cinnabar); }
.cmd-copy.is-copied svg { display: none; }
.btn {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--sans); font-weight: 600; font-size: 15px;
  padding: 11px 22px; border-radius: var(--r2);
  border: 1px solid transparent; text-decoration: none;
  transition: background .15s ease, color .15s ease, border-color .15s ease, transform .1s ease;
}
.btn:active { transform: translateY(1px); }
/* primary action: ink at rest, cinnabar on hover (DESIGN.md, The One Accent Rule) */
.btn-primary { background: var(--btn); color: var(--btn-ink); }
.btn-primary:hover { background: var(--mark); color: var(--mark-ink); }
.btn-ghost { background: var(--card); color: var(--ink); border-color: var(--line-strong); box-shadow: var(--shadow); }
.btn-ghost:hover { border-color: var(--muted); }

/* 720 (not 640): both install commands fit one line at 14.5px mono inside the 770px card; a wrapped
   command reads as broken. No bottom padding on the code — it broke the symmetric 14px box. */
.cmd-inline { margin-top: 16px; max-width: 720px; }
.cmd-inline code { background: none; border: none; padding: 0; }

/* mobile: stack the command block so the command keeps the full row width and
   wraps at spaces — otherwise the non-shrinking Copy button (plus the step's
   numeral gutter + nested card padding) squeezes the code into a tall, thin
   single-character column. Copy drops to its own line, right-aligned. */
@media (max-width: 560px) {
  .cmd { flex-wrap: wrap; row-gap: 12px; }
  .cmd-prompt { display: none; }          /* decorative ($), reclaim its width */
  /* `anywhere` (not `break-word`) so the long install URL's intrinsic width
     collapses — otherwise its min-content keeps the card wider than the phone
     viewport and the page scrolls sideways. */
  .cmd code { flex-basis: 100%; overflow-wrap: anywhere; }
  .cmd-copy { margin-left: auto; }
}

/* ---------- legal pages (imprint, privacy) ---------- */
/* Long-form editorial prose for the legal notices. One column, generous
   measure, hairline dividers between sections. */
.legal { padding: 68px 0 40px; }
.legal-inner { max-width: 720px; }
.legal h1 { font-size: clamp(30px, 5vw, 44px); margin-bottom: 14px; }
.legal .legal-lede { color: var(--muted); font-size: 18px; margin-bottom: 8px; }
.legal .legal-updated { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.legal section { margin-top: 40px; padding-top: 32px; border-top: 1px solid var(--line); }
.legal h2 { font-size: 23px; margin-bottom: 16px; }
.legal h3 { font-size: 17px; margin: 24px 0 8px; }
.legal p { color: var(--ink); margin-bottom: 14px; }
.legal p.muted { color: var(--muted); font-size: 15px; }
.legal ul { margin: 0 0 14px; padding-left: 22px; color: var(--ink); }
.legal li { margin-bottom: 8px; max-width: 62ch; }
.legal address { font-style: normal; line-height: 1.7; }
.legal a { text-decoration: underline; }

/* ---------- blog (generated from blog/posts by blog/build.mjs) ---------- */
/* Same editorial register as the legal pages: one measured column, hairline rules, no
   accent at rest. Dark mode via the tokens. */
.post, .post-list { padding: 68px 0 40px; }
.post-inner { max-width: 720px; }
.post h1, .post-list h1 { font-size: clamp(30px, 5vw, 44px); margin-bottom: 14px; }
.post-lede { color: var(--muted); font-size: 18px; margin-bottom: 10px; }
.post-meta { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.post-tags { list-style: none; display: flex; flex-wrap: wrap; gap: 8px; margin: 14px 0 0; padding: 0; }
.post-tags li {
  font-size: 13px;
  color: var(--muted); border: 1px solid var(--line); border-radius: var(--r2); padding: 2px 8px;
}
/* The category is the post's register (who it is for): it sits in the muted
   eyebrow/date line but carries full ink, so it reads as a label rather than as
   more metadata. Not cinnabar: colour lives in the photographs and the mark. */
.post-cat { color: var(--ink); }
.post-header { padding-bottom: 32px; border-bottom: 1px solid var(--line); }
.post-body { padding-top: 32px; }
.post-body h2 { font-size: 23px; margin: 40px 0 16px; }
.post-body h3 { font-size: 17px; margin: 24px 0 8px; }
.post-body p { color: var(--ink); margin-bottom: 14px; }
.post-body ul, .post-body ol { margin: 0 0 14px; padding-left: 22px; color: var(--ink); }
.post-body li { margin-bottom: 8px; max-width: 62ch; }
.post-body a { text-decoration: underline; }
.post-body img { border-radius: var(--r3); border: 1px solid var(--line); margin: 24px 0; }
.post-body blockquote {
  margin: 24px 0; padding: 4px 0 4px 18px; border-left: 1px solid var(--ink);
  color: var(--muted);
}
/* the Subscribe button on the blog and security listings (blog/lib.mjs subscribeButton) */
.feed-subscribe { margin: 18px 0 4px; }
.feed-subscribe svg { color: currentColor; flex: none; }

/* security advisories: the facts block at the top of an advisory (blog/security.mjs) */
.advisory-facts {
  display: grid; grid-template-columns: max-content 1fr; gap: 6px 20px;
  margin: 0 0 28px; padding: 16px 18px; border: 1px solid var(--line-strong); border-radius: var(--r2);
  font-size: 15px;
}
.advisory-facts dt { color: var(--muted); font-size: 13px; padding-top: 2px; }
.advisory-facts dd { margin: 0; color: var(--ink); }
.advisory-facts a { text-decoration: underline; }
/* ---------- post figures: screenshots and inline-SVG diagrams ----------
   Both are <figure> written as raw HTML in a post. The CSP is `style-src 'self'`,
   so a diagram carries CLASSES and is themed from here — never inline `style`.
   Colours come from the same tokens as the rest of the page, so a diagram
   follows light/dark with no second drawing. */
.post-figure { margin: 28px 0; }
.post-figure img { display: block; margin: 0 auto; max-width: 100%; height: auto; }
.post-figure.is-rail img { max-width: 340px; }
.post-figure figcaption {
  margin-top: 10px; color: var(--muted); font-size: 13.5px; line-height: 1.5; text-align: center;
}
.post-figure svg { display: block; width: 100%; height: auto; }
.dgm-box { fill: var(--paper-2); stroke: var(--dgm-edge); stroke-width: 1; }
.dgm-box-quiet { fill: none; stroke: var(--dgm-edge); stroke-width: 1; stroke-dasharray: 3 3; }
.dgm-line { stroke: var(--dgm-stroke); stroke-width: 1.25; fill: none; }
.dgm-arrow { fill: var(--dgm-stroke); }
/* The lane the post is about gets the one pigment, so a reader traces it in a
   glance instead of comparing two identical arrows. */
.dgm-line-hot { stroke: var(--cinnabar); stroke-width: 2; fill: none; }
.dgm-arrow-hot { fill: var(--cinnabar); }
.dgm-band { fill: var(--paper-2); stroke: var(--dgm-edge); stroke-width: 1; }
.dgm-fill-hot { fill: var(--cinnabar); }
.dgm-fill-hot-soft { fill: var(--cinnabar); fill-opacity: .3; }
.dgm-line-dash { stroke: var(--dgm-stroke); stroke-width: 1; stroke-dasharray: 3 3; fill: none; }
.dgm-t { fill: var(--ink); font-family: var(--sans); font-size: 13px; }
.dgm-t-b { fill: var(--ink); font-family: var(--sans); font-size: 13px; font-weight: 600; }
.dgm-m { fill: var(--ink); font-family: var(--mono); font-size: 12px; }
.dgm-sub { fill: var(--muted); font-family: var(--sans); font-size: 12px; }
.dgm-accent { fill: var(--cinnabar); font-family: var(--sans); font-size: 12px; font-weight: 600; }

/* ---------- code cards (blog/build.mjs → figure.code-block) ----------
   Same shape as the code blocks on /docs (Fumadocs): a header bar naming the
   language or the file, Copy on the right, the code on a card below. The token
   palette is OURS, though — mint for strings, amber for numbers, ink for names,
   muted for comments and punctuation. No cinnabar: it is the mark's colour and only
   marks a state (DESIGN.md, The One Accent Rule). */
.code-block {
  margin: 0 0 18px; border: 1px solid var(--line); border-radius: var(--r3);
  background: var(--card); overflow: hidden; box-shadow: var(--shadow);
}
.code-head {
  display: flex; align-items: center; gap: 10px;
  padding: 8px 10px 8px 14px; border-bottom: 1px solid var(--line);
  background: var(--paper-2);
  font-family: var(--mono); font-size: 12px; color: var(--muted);
}
.code-name { display: inline-flex; align-items: center; gap: 7px; color: var(--ink); }
.code-name svg { flex: none; color: var(--muted); }
.code-lang { letter-spacing: .08em; text-transform: uppercase; }
.code-copy {
  margin-left: auto; display: inline-flex; align-items: center; gap: 6px;
  padding: 4px 9px; border: 1px solid transparent; border-radius: var(--r2);
  background: none; color: var(--muted); cursor: pointer;
  font-family: var(--mono); font-size: 12px; line-height: 1;
}
.code-copy:hover { color: var(--ink); border-color: var(--line-strong); background: var(--card); }
.code-copy.is-copied { color: var(--code-string); border-color: transparent; }
.code-block pre {
  margin: 0; padding: 14px 16px; overflow-x: auto;
  font-family: var(--mono); font-size: 14px; line-height: 1.55; color: var(--ink);
  /* Scroll affordance without JS: the two `local` layers ride the content and
     uncover the two `scroll` shadows at whichever edge still has code behind it.
     A block that fits shows neither. */
  background:
    linear-gradient(to right, var(--card) 62%, rgba(0,0,0,0)) left / 56px 100% no-repeat local,
    linear-gradient(to left,  var(--card) 62%, rgba(0,0,0,0)) right / 56px 100% no-repeat local,
    radial-gradient(farthest-side at 0 50%, var(--code-edge), rgba(0,0,0,0)) left / 26px 100% no-repeat scroll,
    radial-gradient(farthest-side at 100% 50%, var(--code-edge), rgba(0,0,0,0)) right / 26px 100% no-repeat scroll;
}
/* The scrollbar is part of the card, not the OS. Firefox takes the two-value
   form; WebKit needs the pseudo-elements, and the transparent border is what
   keeps the thumb from touching the card edge. */
.code-block pre { scrollbar-width: thin; scrollbar-color: var(--line-strong) transparent; }
.code-block pre::-webkit-scrollbar { height: 11px; }
.code-block pre::-webkit-scrollbar-track { background: transparent; }
.code-block pre::-webkit-scrollbar-thumb {
  background: var(--line-strong); background-clip: padding-box;
  border: 3px solid rgba(0,0,0,0); border-radius: 999px;
}
.code-block pre::-webkit-scrollbar-thumb:hover { background: var(--muted); background-clip: padding-box; }
.code-block pre:focus-visible { outline: 2px solid var(--cinnabar); outline-offset: -2px; }

/* hljs tokens (class prefix `hl-`, emitted at build time — the CSP forbids the
   inline styles a runtime highlighter would need). Anything unmapped inherits
   --ink, so an unstyled token is plain code, never invisible. */
.hl-comment, .hl-quote { color: var(--muted); font-style: italic; }
.hl-attr, .hl-attribute, .hl-property, .hl-selector-tag, .hl-selector-class, .hl-selector-id,
.hl-title, .hl-section, .hl-name { color: var(--ink); font-weight: 600; }
.hl-string, .hl-regexp, .hl-symbol, .hl-bullet, .hl-addition { color: var(--code-string); }
.hl-number, .hl-literal, .hl-variable, .hl-template-variable, .hl-type, .hl-deletion { color: var(--code-number); }
.hl-keyword, .hl-built_in, .hl-meta, .hl-function, .hl-doctag { color: var(--ink); }
.hl-punctuation, .hl-operator { color: var(--muted); }
/* A colour literal in a code card carries a square of the colour itself (an
   <img> data: URI — the CSP forbids the inline style a background would need).
   Hairline border so a white or near-white swatch still has an edge on the card;
   `alt=""` because the hex beside it already says what it is.
   Specificity note: it has to out-rank `.post-body img` (block, 24px margins,
   r3 corners) — as a bare `.sw` it rendered as a lone round dot on its own line. */
.post-body .sw, .sw {
  display: inline-block; width: .78em; height: .78em;
  margin: 0 .38em 0 0; vertical-align: -.02em;
  border-radius: 3px; border: 1px solid var(--line-strong);
}
.hl-emphasis { font-style: italic; }
.hl-strong { font-weight: 700; }
.post-body :not(pre) > code {
  font-size: .92em; background: var(--paper-2); border: 1px solid var(--line);
  border-radius: var(--r1); padding: 1px 5px;
}
.post-body .cmd { margin: 0 0 18px; max-width: none; }
.post-body .cmd code,
.post-body .cmd-prompt { font-size: 13.5px; }
.post-body .cmd code { background: none; border: 0; border-radius: 0; padding: 0; }
/* The article column is narrower than the command's natural width: below ~720px viewport the install command
   would break mid-line, which reads as broken. Stack Copy under the command instead (same shape as
   the site-wide 560px rule above). */
@media (max-width: 720px) {
  .post-body .cmd { flex-wrap: wrap; row-gap: 10px; }
  .post-body .cmd-prompt { display: none; }
  .post-body .cmd code { flex-basis: 100%; overflow-wrap: anywhere; }
  .post-body .cmd-copy { margin-left: auto; }
}
.post-body hr { border: 0; border-top: 1px solid var(--line); margin: 32px 0; }
.post-body table { border-collapse: collapse; margin: 0 0 18px; font-size: 15px; }
.post-body th, .post-body td { text-align: left; padding: 8px 12px; border-bottom: 1px solid var(--line); }
.post-footer { margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--line); font-size: 15px; }
.post-list-items { list-style: none; margin: 28px 0 0; padding: 0; }
.post-list-item { padding: 28px 0; border-top: 1px solid var(--line); }
.post-list-item h2 { font-size: 24px; margin: 6px 0 10px; }
.post-list-item h2 a { color: var(--ink); }
.post-list-item h2 a:hover { color: var(--cinnabar); }
.post-list-date { color: var(--muted); font-size: 13px; font-variant-numeric: tabular-nums; }
.post-list-desc { color: var(--muted); font-size: 16px; }
.post-list-empty { padding: 28px 0; border-top: 1px solid var(--line); }

/* ---------- Page spread: masthead column + text (prose pages) ---------- */
.page {
  display: grid;
  grid-template-columns: var(--col) minmax(0, 1fr);
  max-width: 1920px; margin: 0 auto;
}
.page > main { border-left: 1px solid var(--hair); min-width: 0; }
.page .wrap { max-width: 760px; margin-inline: 0; padding-inline: var(--pad); }
.page .masthead {
  position: sticky; top: 0; align-self: start;
  padding: var(--pad) var(--pad) 0;
  padding-left: max(var(--pad), env(safe-area-inset-left, 0px));
}
@media (max-width: 960px) {
  .page { grid-template-columns: 1fr; }
  .page > main { border-left: 0; }
  .page .wrap { padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px)) max(var(--gutter), env(safe-area-inset-right, 0px)); }
  .page .masthead { padding: 12px max(var(--gutter), env(safe-area-inset-right, 0px)) 12px max(var(--gutter), env(safe-area-inset-left, 0px)); }
}
