/* Kloti blog. Generated by app/tools/build_blog.py, edit the generator not this file.
   Colours are the app's dark theme tokens from app/frontend/src/index.css. No new hues.

   Type is the one axis this stylesheet spends: the app chrome stays sans, long-form prose
   is set in a system serif (no webfont, no request), and every number, date and label is
   set in mono with tabular figures. A blog whose argument is "here are the measured
   numbers" should look like it counts things.

   Deliberately absent: the multi-stop gradient wordmark that used to live here (it reads as
   a generic AI template, see CLAUDE.md section 7), glow orbs, and any JavaScript at all. */
:root {
  --surface: #0b0f19;
  --panel: #131826;
  --card: #161b2b;
  --border: #292f40;
  --foreground: #e5e7eb;
  --muted: #949dad;
  --accent: #818cf8;
  --radius: 14px;

  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;
  --sans: "Segoe UI", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --mono: ui-monospace, "Cascadia Mono", SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --measure: 68ch;
  --page: 1160px;
  --rail: 17rem;
  color-scheme: dark;
}
* { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  margin: 0;
  background: var(--surface);
  color: var(--foreground);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
.wrap { max-width: var(--page); margin: 0 auto; padding: 0 24px; }
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 4px; }
img { max-width: 100%; height: auto; }

/* ---------------------------------------------------------------- header and footer */
/* Fixed while reading: a long article should always have the way out and the signup CTA in
   reach. Sticky rather than fixed so it still occupies layout space and nothing sits under it.
   The background is nearly opaque plus a blur, because prose scrolling underneath a transparent
   bar is unreadable. */
/* Header geometry mirrors the landing page bar: 64px tall, full bleed with 4vw gutters, rather
   than sitting inside the centred article wrap. Full bleed is the point. A centred header over
   centred prose is a blog; a full-width bar with the mark hard left is what the rest of the site
   does, and matching it is what stops this reading as a separate property. */
.site-header {
  position: sticky; top: 0; z-index: 20;
  border-bottom: 1px solid var(--border);
  background: rgba(11, 15, 25, 0.85);
  -webkit-backdrop-filter: saturate(140%) blur(10px);
  backdrop-filter: saturate(140%) blur(10px);
}
/* Anchor jumps from the contents list must not land under the sticky bar. */
h2[id], h3[id] { scroll-margin-top: 84px; }
.site-header .bar {
  display: flex; align-items: center; justify-content: space-between;
  gap: 16px; height: 64px; padding: 0 4vw;
}
.brand { display: flex; align-items: center; gap: 8px; font-weight: 600; font-size: 16px; color: var(--foreground); }
.brand:hover { text-decoration: none; }
.brand img { width: 28px; height: 28px; border-radius: 6px; }
/* Foreground, NOT accent. The landing wordmark is plain foreground, and a blog that tints it
   accent is the single clearest tell that you have left the site. */
.brand span { color: var(--foreground); }
.nav { display: flex; align-items: center; gap: 6px; font-size: 14px; font-weight: 600; }
.nav a.link { color: rgba(229, 231, 235, 0.8); padding: 6px 12px; border-radius: 8px; }
.nav a.link:hover { color: var(--foreground); text-decoration: none; }
/* btn-primary, transcribed: bg-accent, text-accent-fg, px-5 py-2.5, rounded-lg, font-medium. */
.nav a.cta {
  display: inline-flex; align-items: center; gap: 6px;
  background: var(--accent); color: #111827;
  padding: 10px 20px; border-radius: 8px; font-weight: 500;
}
.nav a.cta:hover { opacity: 0.9; text-decoration: none; }
.nav .chip {
  font-size: 10px; line-height: 1; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.025em;
  background: rgba(255, 255, 255, 0.2); border-radius: 4px; padding: 3px 6px;
}
.cta {
  background: var(--accent); color: #111827; padding: 8px 16px;
  border-radius: 10px; font-weight: 600;
}
.cta:hover { opacity: 0.9; text-decoration: none; }

.site-footer {
  border-top: 1px solid var(--border); margin-top: 72px;
  padding: 26px 0 52px; font-size: 14px; color: var(--muted);
}
.site-footer .wrap { display: flex; flex-wrap: wrap; gap: 8px 18px; align-items: center; }
.site-footer a { color: var(--muted); }

/* ---------------------------------------------------------------- shared type devices */
main { padding: 40px 0 8px; }

.eyebrow, .kicker, .dateline, .rail-title, .rule-label, .figure figcaption, .plate figcaption {
  font-family: var(--mono);
  font-variant-numeric: tabular-nums;
}
.eyebrow, .kicker, .rail-title, .rule-label {
  font-size: 11.5px; letter-spacing: 0.14em; text-transform: uppercase; font-weight: 600;
}
.eyebrow { color: var(--muted); margin: 0 0 14px; }
.eyebrow a { color: var(--muted); }
.eyebrow .sep { padding: 0 8px; opacity: 0.45; }
.kicker { color: var(--accent); margin: 0 0 10px; }
.dateline { font-size: 12.5px; color: var(--muted); margin: 0; letter-spacing: 0.02em; }
.dateline .dot { padding: 0 7px; opacity: 0.45; }

.headline { font-family: var(--serif); font-weight: 600; letter-spacing: -0.005em; }

.standfirst {
  font-family: var(--serif); color: var(--muted);
  font-size: 20px; line-height: 1.55; margin: 0 0 18px;
}

/* A labelled hairline. Used to break the index into "the lead" and "everything else". */
.rule { display: flex; align-items: center; gap: 16px; margin: 64px 0 30px; }
.rule::after { content: ""; flex: 1; height: 1px; background: var(--border); }
.rule-label { color: var(--muted); white-space: nowrap; }

/* ---------------------------------------------------------------- plates (cover images)
   Every cover on this blog is a render Kloti produced, so covers are presented like
   catalogue plates: a framed image with a printed caption and a credit line. */
.plate { margin: 0; }
.plate img {
  display: block; width: 100%; height: 100%; object-fit: cover;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--panel);
}
.plate figcaption {
  display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: baseline;
  font-size: 11.5px; line-height: 1.5; color: var(--muted); margin-top: 10px;
}
.plate .credit { color: var(--accent); letter-spacing: 0.08em; text-transform: uppercase; }

/* ---------------------------------------------------------------- index: masthead */
.masthead { max-width: 46rem; padding-bottom: 34px; border-bottom: 1px solid var(--border); }
.masthead h1 {
  font-family: var(--serif); font-size: 46px; line-height: 1.08; letter-spacing: -0.02em;
  margin: 0 0 14px; font-weight: 600;
}
.masthead .standfirst { margin-bottom: 0; max-width: 34rem; }

/* ---------------------------------------------------------------- index: lead post */
.lead {
  display: grid; grid-template-columns: 1.15fr 1fr; gap: 40px; align-items: center;
  margin-top: 40px; color: inherit;
}
.lead:hover { text-decoration: none; }
.lead .plate img { aspect-ratio: 4 / 3; height: auto; transition: border-color 0.18s ease; }
.lead:hover .plate img { border-color: var(--accent); }
.lead h2 {
  font-family: var(--serif); font-weight: 600; font-size: 36px; line-height: 1.14;
  letter-spacing: -0.018em; margin: 0 0 14px; color: var(--foreground);
}
.lead:hover h2 { color: var(--accent); }
.lead .standfirst { font-size: 18px; }
.read-on {
  display: inline-block; margin-top: 18px; font-family: var(--sans);
  font-size: 14px; font-weight: 600; color: var(--accent);
}
.lead:hover .read-on { text-decoration: underline; }

/* ---------------------------------------------------------------- index: card grid */
.cards {
  list-style: none; padding: 0; margin: 0;
  display: grid; grid-template-columns: 1fr; gap: 40px 32px;
}
.cards li { margin: 0; min-width: 0; }
.card { display: block; color: inherit; }
.card:hover { text-decoration: none; }
.card .plate img { aspect-ratio: 3 / 2; height: auto; transition: border-color 0.18s ease; }
.card:hover .plate img { border-color: var(--accent); }
.card .kicker { margin: 16px 0 8px; }
.card h3 {
  font-family: var(--serif); font-weight: 600; font-size: 22px; line-height: 1.22;
  letter-spacing: -0.012em; margin: 0 0 8px; color: var(--foreground);
}
.card:hover h3 { color: var(--accent); }
/* The full standfirst stays in the markup (a crawler and a no-CSS reader get all of it);
   the card clamps it to two lines visually rather than the generator truncating the text. */
.card .card-standfirst {
  font-family: var(--serif); color: var(--muted); font-size: 16px;
  line-height: 1.5; margin: 0 0 12px;
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  line-clamp: 2; overflow: hidden;
}
.empty { color: var(--muted); font-family: var(--serif); font-size: 19px; }

/* ---------------------------------------------------------------- article */
.article-head { max-width: 44rem; }
.article-head h1 {
  font-family: var(--serif); font-weight: 600; font-size: 44px; line-height: 1.1;
  letter-spacing: -0.022em; margin: 0 0 18px;
}
.article-head .standfirst { font-size: 21px; }
.article-head .dateline { padding-top: 14px; border-top: 1px solid var(--border); }
.plate--lead { margin: 34px 0 0; }
.plate--lead img { aspect-ratio: 2 / 1; }

/* Body column plus rail. The prose measure is capped in ch so the line length stays
   readable no matter how wide the viewport gets. */
.article-body {
  display: grid; grid-template-columns: minmax(0, 1fr); gap: 0;
  margin-top: 48px;
}
.prose {
  max-width: var(--measure); min-width: 0;
  font-family: var(--serif); font-size: 19px; line-height: 1.78;
  /* A long unbroken token (a URL, a code span) must wrap rather than push the column
     wider than the phone. `body` hides horizontal overflow, so without this it clips. */
  overflow-wrap: break-word;
}
.prose :target { scroll-margin-top: 1.5rem; }
.prose h2, .prose h3 { scroll-margin-top: 1.5rem; }
.prose p { margin: 0 0 22px; }
.prose > p:first-child { font-size: 21px; line-height: 1.62; }
.prose h2 {
  font-family: var(--serif); font-size: 29px; line-height: 1.2; letter-spacing: -0.015em;
  font-weight: 600; margin: 54px 0 16px; padding-top: 18px; position: relative;
}
/* A short accent rule marks each new section. The only ornament in the article. */
.prose h2::before {
  content: ""; position: absolute; top: 0; left: 0;
  width: 34px; height: 2px; background: var(--accent);
}
.prose h3 { font-family: var(--serif); font-size: 22px; font-weight: 600; margin: 36px 0 10px; }
.prose h4 { font-family: var(--sans); font-size: 15px; font-weight: 700; margin: 28px 0 8px;
  letter-spacing: 0.02em; text-transform: uppercase; color: var(--muted); }
.prose strong { font-weight: 700; color: #f3f4f6; }
.prose em { font-style: italic; }
.prose a { text-decoration: underline; text-decoration-thickness: 1px; text-underline-offset: 2px; }
.prose hr { border: none; border-top: 1px solid var(--border); margin: 44px 0; }
.prose ul, .prose ol { padding-left: 24px; margin: 0 0 22px; }
.prose li { margin: 9px 0; }
.prose li > ul, .prose li > ol { margin: 9px 0; }
.prose li::marker { color: var(--muted); }

blockquote {
  margin: 28px 0; padding: 2px 0 2px 22px;
  border-left: 2px solid var(--accent); color: var(--muted);
}
blockquote p:last-of-type { margin-bottom: 0; }
blockquote cite {
  display: block; margin-top: 12px; font-family: var(--mono); font-style: normal;
  font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--muted);
}
/* Pull quote: `> !` on the first line of a blockquote. Meant to be scanned, not read
   in sequence, so it loses the rule and gains size. */
blockquote.pull {
  border-left: none; padding: 0; margin: 40px 0;
  color: var(--foreground); font-size: 26px; line-height: 1.34; letter-spacing: -0.01em;
}
blockquote.pull p { text-indent: -0.42em; }
blockquote.pull p::before { content: "\201C"; color: var(--accent); }
blockquote.pull p::after { content: "\201D"; color: var(--accent); }

code {
  font-family: var(--mono); font-size: 0.84em; background: var(--panel);
  border: 1px solid var(--border); border-radius: 6px; padding: 1px 5px;
}
pre {
  background: var(--panel); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 16px; overflow-x: auto; margin: 0 0 26px;
}
pre code { background: none; border: none; padding: 0; font-size: 14px; line-height: 1.6; }

/* Data is not prose: tables drop to the utility face with tabular figures. They scroll
   inside their own box so the page body never scrolls sideways. */
.table-wrap {
  overflow-x: auto; margin: 0 0 28px;
  border: 1px solid var(--border); border-radius: var(--radius); background: var(--card);
}
table {
  border-collapse: collapse; width: 100%;
  font-family: var(--sans); font-size: 14.5px; line-height: 1.55;
  font-variant-numeric: tabular-nums;
}
th, td { padding: 12px 15px; text-align: left; border-bottom: 1px solid var(--border); vertical-align: top; }
th {
  background: var(--panel); font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.09em; text-transform: uppercase; color: var(--muted); white-space: nowrap;
}
tbody tr:last-child td { border-bottom: none; }

.figure { margin: 32px 0; }
.figure img { border: 1px solid var(--border); border-radius: var(--radius); width: 100%; }
.figure figcaption {
  font-family: var(--mono); font-size: 11.5px; line-height: 1.5;
  color: var(--muted); margin-top: 10px;
}

/* ---------------------------------------------------------------- article end matter */
.tags { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; padding: 0; margin: 0; }
.tags li { margin: 0; }
.tag {
  display: inline-block; font-family: var(--mono); font-size: 11.5px; font-weight: 600;
  letter-spacing: 0.06em; color: var(--muted);
  background: var(--panel); border: 1px solid var(--border);
  border-radius: 999px; padding: 4px 11px;
}
.article-end {
  margin-top: 52px; padding-top: 28px; border-top: 1px solid var(--border);
  font-family: var(--sans); font-size: 15px;
}
.article-end .colophon { color: var(--muted); margin: 20px 0 0; line-height: 1.65; }
.article-end .end-links { display: flex; flex-wrap: wrap; gap: 10px 24px; margin: 16px 0 0; font-weight: 600; }

/* ---------------------------------------------------------------- side rail */
.rail { min-width: 0; }
.rail-block { margin-bottom: 40px; }
.rail-title { color: var(--muted); margin: 0 0 14px; padding-bottom: 10px; border-bottom: 1px solid var(--border); }

.contents { list-style: none; padding: 0; margin: 0; font-size: 14.5px; }
.contents li { margin: 0 0 10px; line-height: 1.45; }
.contents a { color: var(--muted); }
.contents a:hover { color: var(--accent); }

.related { list-style: none; padding: 0; margin: 0; }
.related li { margin: 0 0 18px; }
.related a { display: grid; grid-template-columns: 68px 1fr; gap: 12px; align-items: start; color: inherit; }
.related a:hover { text-decoration: none; }
.related a > span { min-width: 0; }
.related img {
  width: 68px; height: 46px; object-fit: cover; display: block;
  border: 1px solid var(--border); border-radius: 8px;
}
.related a:hover img { border-color: var(--accent); }
.related .r-title {
  display: block; font-family: var(--serif); font-size: 15.5px; line-height: 1.32;
  color: var(--foreground); margin: 0 0 4px;
}
.related a:hover .r-title { color: var(--accent); }
.related .dateline { display: block; font-size: 11.5px; }

.rail-cta {
  background: var(--card); border: 1px solid var(--border); border-radius: var(--radius);
  padding: 20px;
}
.rail-cta h2 {
  font-family: var(--serif); font-size: 20px; font-weight: 600; margin: 0 0 8px;
  line-height: 1.25;
}
.rail-cta p { color: var(--muted); font-size: 14.5px; line-height: 1.55; margin: 0 0 16px; }
.rail-cta .cta { display: block; text-align: center; padding: 10px 14px; font-size: 14px; }

/* ---------------------------------------------------------------- responsive
   Mobile first from here down: the single-column rules above are the phone layout, and
   each breakpoint adds structure only once there is width to spend on it. */

/* Two card columns as soon as a card can still hold a readable headline. */
@media (min-width: 40rem) {
  .cards { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 62rem) {
  .cards { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* The rail appears only once the prose can keep its full measure beside it. Below this
   the rail drops under the article instead of squeezing the body text. */
@media (min-width: 68rem) {
  .article-body {
    grid-template-columns: minmax(0, var(--measure)) minmax(0, var(--rail));
    gap: 0 5rem; justify-content: space-between;
  }
  /* Offsets clear the sticky site header (about 59px: 16px padding either side of a 26px mark,
     plus its 1px border) so the rail parks below it instead of sliding underneath. The
     max-height subtracts the same header so a long contents list still fits on screen. */
  .rail {
    position: sticky; top: 84px; align-self: start;
    max-height: calc(100vh - 108px); overflow-y: auto; scrollbar-width: thin;
  }
  .rail-block:last-child { margin-bottom: 8px; }
}

@media (max-width: 67.99rem) {
  .rail { margin-top: 56px; padding-top: 8px; border-top: 1px solid var(--border); }
  .rail-block { margin-bottom: 34px; }
  .rail-block:first-child { margin-top: 28px; }
  .rail-cta { max-width: 30rem; }
}

@media (max-width: 56rem) {
  .lead { grid-template-columns: 1fr; gap: 22px; }
  .lead h2 { font-size: 30px; }
}

@media (max-width: 40rem) {
  body { font-size: 16px; }
  main { padding-top: 30px; }
  .wrap { padding: 0 18px; }
  .masthead h1 { font-size: 33px; }
  .masthead .standfirst, .lead .standfirst { font-size: 17px; }
  .article-head h1 { font-size: 31px; }
  .article-head .standfirst { font-size: 18px; }
  .prose { font-size: 17.5px; line-height: 1.72; }
  .prose > p:first-child { font-size: 18.5px; }
  .prose h2 { font-size: 24px; margin-top: 42px; }
  .prose h3 { font-size: 19px; }
  blockquote.pull { font-size: 21px; }
  /* On a phone the cover gets its full 3:2 frame back: there is no width to crop for. */
  .plate--lead img { aspect-ratio: 3 / 2; }
  .cards { gap: 34px; }
  .rule { margin: 46px 0 26px; }
  /* Same call the landing header makes: the text links are `hidden sm:block` there, so below
     640px only the mark and the call to action survive. Six items do not fit on a phone, and
     dropping the CTA instead would be the wrong one to lose. */
  .site-header .bar { gap: 10px; padding: 0 5vw; }
  .nav { gap: 4px; }
  .nav a.link { display: none; }
  .nav a.cta { padding: 9px 14px; }
  .nav .chip { display: none; }
  .site-footer { margin-top: 52px; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { transition: none !important; }
}
