/* Scrolletta, the site.
   The European Future of Entertainment.

   The identity set on 2026-09-06 and written down in docs/brand.md. It replaces
   the "Zine" palette that was inherited from the reading app: hot pink, four
   faces, monospace meta and a uniform card grid. That combination read as a
   tech product rather than as a trade, which is the same combination that sank
   the rebuilt Blickpunkt:Film.

   What this file is now:

     Two faces. Onest for headlines and the masthead, Newsreader for reading
     copy and for every piece of chrome. There is no monospace anywhere the
     reader can see, because no trade in the sample has one.

     Dark is the brand ground and the one deliberate departure from the genre.
     Light is pure white, with no paper grain: the grain only ever existed to
     sell a cream ground as newsprint, and the ground is not cream any more.

     Red (--chrome) means Scrolletta, or it means urgency. It never labels a
     beat. The beat colours arrive per post as --beat, set inline from the tag's
     accent_color, and ride the kicker and a hairline. Cards, borders, radii and
     shadows are gone; hairline rules separate instead.

     One image ratio, 16:9, enforced on every slot. This is the single strongest
     visual signal the trades share and it is never varied per image.

   Hand written. There is no build step, no PostCSS, no minifier: what is in
   this file is what Ghost serves. Keep it readable.

   Fonts are self hosted. Never load fonts.googleapis.com or fonts.gstatic.com,
   not even as a quick start: it ships the reader's IP address to Google in the
   US, which the Munich Regional Court ruled a GDPR violation
   (3 O 17493/20, January 2022). */


/* ============================================================
   1. Self hosted faces
   ============================================================
   Three files in assets/fonts/, down from ten. Onest is one variable file
   covering weight 100 to 900, so it sets the masthead at 800 and a caption at
   400 out of the same 33kB. Newsreader is variable too, upright and italic. */

@font-face { font-family: 'Onest'; font-style: normal; font-display: swap; font-weight: 100 900; src: url('../fonts/onest-latin-wght-normal.woff2') format('woff2'); }

@font-face { font-family: 'Newsreader Variable'; font-style: normal; font-display: swap; font-weight: 200 800; src: url('../fonts/newsreader-latin-opsz-normal.woff2') format('woff2'); }
@font-face { font-family: 'Newsreader Variable'; font-style: italic; font-display: swap; font-weight: 200 800; src: url('../fonts/newsreader-latin-opsz-italic.woff2') format('woff2'); }


/* ============================================================
   2. Tokens. Dark is the brand default.
   ============================================================ */

:root {
  color-scheme: dark;

  --paper:    #0A0A0A;
  --ink:      #F2F2F0;
  --ink-soft: #A8A8A4;
  --ink-mute: #7C7C78;
  --rule:     #262625;

  /* The house red. Masthead rule, links, the issue stamp and anything urgent.
     Never a beat. #E8442E measures 5.0:1 on the near black ground. */
  --chrome:   #E8442E;

  /* Text laid on a --chrome fill: the issue stamp, the primary button and the
     selection highlight. The right answer flips between the modes, because the
     two reds sit on opposite sides of the point where black overtakes white.
     On the dark red #E8442E near black clears 4.99:1 and white only 3.96:1; on
     the light red #DF301C it is the other way round, white clears 4.59:1 and
     near black only 4.32:1, which fails. So this token is redeclared in the
     light block rather than shared. Do not collapse the two into one value. */
  --on-chrome: #0A0A0A;

  /* A lifted ground for the few surfaces that are genuinely not the page:
     code blocks, the bookmark card, the signup panel. Not a card background;
     nothing in the item stream uses it. */
  --wash:     #141413;

  /* Editorial warning colour. Used only by the flag panel, which never leaves
     the desk, and by the theme error box. */

  /* Beat colours. These are the values stored on each Ghost tag as
     accent_color and they are tuned for the dark ground; a post stamps its own
     on the article as --beat. The classes further down are the fallback for a
     tag whose colour was never set, and they are also what carries the
     separately chosen light mode values.

     Five hues and one neutral. The US system beat runs without a hue on
     purpose: it is the one beat that is not about Europe, and giving it a
     colour would have meant six competing hues in one river. */
  --beat-made-in-europe: #4780E0;
  --beat-money:          #FF9100;
  --beat-buyers:         #FFC300;
  --beat-frontier:       #00A86B;
  --beat-jobs:           #00B7CD;
  --beat-us:             var(--ink-mute);

  /* Light mode is not a tint of dark mode. Orange, yellow, green and cyan all
     fail AA on white at their dark ground values, so they are darkened
     separately. Made In Europe inverts: #003399 is Reflex Blue, the actual
     European flag value, which measures 10.9:1 on white but only 1.8:1 on near
     black, so the dark ground gets a lightened tint of it instead. */
  --beat-made-in-europe-light: #003399;
  --beat-money-light:          #A85F00;
  --beat-buyers-light:         #8A6A00;
  --beat-frontier-light:       #00754A;
  --beat-jobs-light:           #00707E;
  --beat-us-light:             var(--ink-mute);

  /* Default beat: the neutral. Issue posts and untagged pages get it, and it
     is what stops an unsorted item borrowing the house red. */
  --beat: var(--ink-mute);

  --display: 'Onest', system-ui, -apple-system, 'Helvetica Neue', sans-serif;
  --body:    'Newsreader Variable', 'Newsreader', Georgia, 'Times New Roman', serif;

  --wrap: 46rem;
  --wrap-wide: 72rem;
  --gutter: 1.5rem;
}

@media (prefers-color-scheme: light) {
  :root {
    color-scheme: light;

    --paper:    #FFFFFF;
    --ink:      #0A0A0A;
    --ink-soft: #4A4A48;
    --ink-mute: #6E6E6A;
    --rule:     #DDDDDA;
    --chrome:   #DF301C;
    --on-chrome: #FFFFFF;
    --wash:     #F5F5F3;
  }
}

/* Beat derivations.

   --beat is inherited, so the derived values have to be declared on the element
   that carries the beat rather than on :root, otherwise color-mix would resolve
   against the root fallback instead of the post's own colour. The templates put
   .has-beat on exactly that element, alongside the .beat-<slug> fallback class,
   and everything inside inherits both derivations. Do not add .has-beat to a
   child as well: it would re-derive from the raw --beat and undo the light mode
   correction below. */

.has-beat {
  --beat-ink:  var(--beat);
  --beat-line: color-mix(in oklab, var(--beat) 45%, var(--rule));
}

@media (prefers-color-scheme: light) {
  .has-beat {
    /* A Ghost tag stores one accent colour and it is the dark ground value, so
       a beat with no named class below gets pulled toward ink to clear 4.5:1 on
       white. The named beats do better than this mix and override it. */
    --beat-ink:  color-mix(in oklab, var(--beat) 62%, #0A0A0A);
    --beat-line: color-mix(in oklab, var(--beat) 55%, var(--rule));
  }
}

/* Fallback beats, for templates that would rather name the beat than read the
   tag's accent_color, and for any tag whose colour was never set in Ghost.
   Put the class on the same element as .has-beat. */
.beat-made-in-europe { --beat: var(--beat-made-in-europe); }
.beat-money          { --beat: var(--beat-money); }
.beat-buyers         { --beat: var(--beat-buyers); }
.beat-frontier       { --beat: var(--beat-frontier); }
.beat-jobs           { --beat: var(--beat-jobs); }
.beat-us             { --beat: var(--beat-us); }

@media (prefers-color-scheme: light) {
  /* Declared after the generic derivation and at the same specificity, so a
     named beat wins on the element it shares with .has-beat even when the tag's
     stored dark value has arrived inline as --beat. The inline value still
     drives the mix for anything not named here. */
  .beat-made-in-europe { --beat-ink: var(--beat-made-in-europe-light); --beat-line: color-mix(in oklab, var(--beat-made-in-europe-light) 55%, var(--rule)); }
  .beat-money          { --beat-ink: var(--beat-money-light);          --beat-line: color-mix(in oklab, var(--beat-money-light) 55%, var(--rule)); }
  .beat-buyers         { --beat-ink: var(--beat-buyers-light);         --beat-line: color-mix(in oklab, var(--beat-buyers-light) 55%, var(--rule)); }
  .beat-frontier       { --beat-ink: var(--beat-frontier-light);       --beat-line: color-mix(in oklab, var(--beat-frontier-light) 55%, var(--rule)); }
  .beat-jobs           { --beat-ink: var(--beat-jobs-light);           --beat-line: color-mix(in oklab, var(--beat-jobs-light) 55%, var(--rule)); }
  .beat-us             { --beat-ink: var(--beat-us-light);             --beat-line: var(--rule); }
}


/* ============================================================
   3. Base
   ============================================================ */

*, *::before, *::after { box-sizing: border-box; }

[hidden] { display: none !important; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

body {
  margin: 0;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--body);
  font-size: 18px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

.site {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.site-main {
  flex: 1 0 auto;
  outline: none;
}

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

a {
  color: var(--chrome);
  text-decoration-thickness: 1px;
  text-underline-offset: 2px;
}
a:hover { color: var(--chrome); text-decoration-thickness: 2px; }

:focus-visible {
  outline: 2px solid var(--chrome);
  outline-offset: 2px;
}

::selection { background: var(--chrome); color: var(--on-chrome); }

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

button, input, select, textarea { font: inherit; color: inherit; }


/* ============================================================
   4. Typography roles
   ============================================================
   Two families and a hard split. Onest sets the masthead, the lead and the
   sub-features: the sizes are big enough that a geometric sans reads as
   confidence rather than as a dashboard. Everything else, including every piece
   of chrome, is Newsreader. Sans headline over serif chrome is the unusual half
   of the split and it is what stops the page reading as an app.

   The negative tracking on the headline sizes is not decoration. Onest takes
   more horizontal room than the condensed face it replaces, and a long German
   compound headline needs the width back. If a lead is still too tight, drop
   its size toward 46px; do not add tracking. */

/* Chrome: kickers, nav, dates, buttons, section labels, counters. Tracked
   uppercase Newsreader, per docs/brand.md. This is the one place the old
   identity used a monospace, and it was the clearest dev blog tell on the
   site. */
.meta,
.section-label,
.nav-link,
.btn,
.beat-kicker,
.issue-stamp,
.sources-label,
.flag-label,
.pagination-number,
.pagination-link,
.pagination a {
  font-family: var(--body);
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  font-variant-ligatures: none;
}

.meta {
  font-size: .72rem;
  color: var(--ink-mute);
  line-height: 1.4;
}

.meta a { color: inherit; text-decoration: none; border-bottom: 1px solid var(--rule); }
.meta a:hover { color: var(--chrome); border-bottom-color: currentColor; }

.meta-loud { color: var(--ink-soft); letter-spacing: .15em; }

.section-label {
  display: block;
  font-size: .78rem;
  color: var(--ink);
  padding-bottom: .45rem;
  border-bottom: 1px solid var(--ink);
  margin: 0 0 1.1rem;
}

/* Headlines. Onest 700, never uppercased, so the Title Case Albert published is
   what the reader sees. The masthead is the one exception and takes 800. */
h1, h2, h3, h4, h5, h6 {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -.018em;
  line-height: 1.12;
  text-transform: none;
  margin: 0 0 .5rem;
  text-wrap: balance;
}

h1 { font-size: clamp(2rem, 1.4rem + 2.2vw, 2.9rem); letter-spacing: -.022em; }
h2 { font-size: clamp(1.45rem, 1.15rem + 1.1vw, 1.9rem); }
h3 { font-size: 1.3rem; }
h4 { font-size: 1.12rem; }
h5, h6 { font-size: 1rem; letter-spacing: -.01em; }

p { margin: 0 0 1.1em; }

.dek {
  font-family: var(--body);
  font-size: 1.02rem;
  line-height: 1.5;
  color: var(--ink-soft);
  margin: 0;
}


/* ============================================================
   5. Layout helpers
   ============================================================ */

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

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

.stack > * + * { margin-top: 2.4rem; }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 300;
  background: var(--chrome);
  color: var(--on-chrome);
  padding: .6rem 1rem;
  font-family: var(--body);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: .13em;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

/* Every image slot on the site, without exception. One ratio, enforced in CSS
   rather than trusted to whatever the editor uploaded, because a mixed crop is
   the fastest way to stop looking like a trade. */
.ratio {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  background: var(--wash);
}


/* ============================================================
   6. Buttons
   ============================================================ */

.btn {
  display: inline-block;
  font-size: .76rem;
  padding: .55rem 1.1rem;
  border: 1px solid var(--ink);
  background: transparent;
  color: var(--ink);
  text-decoration: none;
  cursor: pointer;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.btn:hover { background: var(--ink); color: var(--paper); }

.btn-primary {
  background: var(--chrome);
  border-color: var(--chrome);
  color: var(--on-chrome);
}
.btn-primary:hover {
  background: transparent;
  border-color: var(--chrome);
  color: var(--chrome);
}

.btn-small { font-size: .7rem; padding: .38rem .8rem; }


/* ============================================================
   7. Site header, masthead, nav
   ============================================================
   The rule under the masthead is the house red. It is the one place the colour
   is allowed to run the full width of the page. */

.site-header {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--paper);
  border-bottom: 2px solid var(--chrome);
}

.masthead {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  width: 100%;
  max-width: var(--wrap-wide);
  margin-inline: auto;
  padding: .8rem var(--gutter) .65rem;
}

.masthead-id {
  display: flex;
  align-items: baseline;
  gap: .75rem;
  min-width: 0;
}

/* The wordmark is Onest type alone. The wax seal is retired with the pink it
   was drawn in; most trades have no device either, their mark is their name set
   in their own face. */
.masthead-name {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -.015em;
  text-transform: uppercase;
  font-size: clamp(1.3rem, 1rem + 1.1vw, 1.8rem);
  line-height: 1;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}
.masthead-name:hover { color: var(--chrome); }

.masthead-rule {
  display: inline-block;
  width: 1.6rem;
  height: 1px;
  background: var(--rule);
  transform: translateY(-.3em);
  flex: none;
}

.masthead-strap {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.masthead-actions {
  display: flex;
  align-items: center;
  gap: .75rem;
}

.nav-toggle {
  display: none;
  align-items: center;
  gap: .45rem;
  background: transparent;
  border: 1px solid var(--rule);
  padding: .38rem .6rem;
  cursor: pointer;
}

.nav-toggle-label {
  font-family: var(--body);
  font-weight: 600;
  font-size: .72rem;
  letter-spacing: .13em;
  text-transform: uppercase;
}

.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 1rem;
  height: 1px;
  background: currentColor;
  content: "";
}
.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before { position: absolute; top: -5px; }
.nav-toggle-bars::after  { position: absolute; top: 5px; }

.site-nav {
  background: var(--paper);
}

.nav-list {
  display: flex;
  flex-wrap: wrap;
  gap: 0 1.5rem;
  list-style: none;
  margin: 0;
  padding: 0 var(--gutter) .5rem;
  width: 100%;
  max-width: var(--wrap-wide);
  margin-inline: auto;
}

.nav-link {
  font-size: .74rem;
  color: var(--ink-mute);
  text-decoration: none;
  padding: .25rem 0;
  display: inline-block;
  border-bottom: 2px solid transparent;
}
.nav-link:hover { color: var(--ink); }
.nav-item-current .nav-link { color: var(--ink); border-bottom-color: var(--chrome); }

@media (max-width: 719px) {
  .nav-toggle { display: inline-flex; }
  .site-nav { display: none; border-top: 1px solid var(--rule); }
  .site-nav.is-open { display: block; }
  .nav-list { flex-direction: column; gap: 0; padding-block: .3rem .6rem; }
  .nav-link { padding: .5rem 0; width: 100%; }
  .masthead-strap, .masthead-rule { display: none; }
}


/* ============================================================
   8. Beat kicker
   ============================================================
   The beat colour rides the kicker and a hairline. It is not a chip, not a
   pill and not a coloured box: the rainbow of bordered tiles was the other half
   of what made the old front page read as a dashboard. */

.beat-kicker {
  font-size: .68rem;
  color: var(--beat-ink, var(--ink-mute));
  text-decoration: none;
  white-space: nowrap;
}
.beat-kicker:hover { color: var(--beat-ink, var(--ink-mute)); text-decoration: underline; text-underline-offset: 3px; }

/* An item with no public tag still gets a kicker, so the meta line keeps its
   shape. Muted rather than coloured: "unsorted" is a desk state and must not
   read as a seventh beat. */
.beat-kicker-none { color: var(--ink-mute); }

/* The issue stamp is the house red, always, whatever the beat. An issue belongs
   to the publication rather than to a beat. */
.issue-stamp {
  display: inline-block;
  font-size: .68rem;
  color: var(--on-chrome);
  background: var(--chrome);
  padding: .16rem .45rem .1rem;
  text-decoration: none;
}
.issue-stamp:hover { color: var(--on-chrome); background: var(--chrome); text-decoration: underline; }

/* The line of kicker and timestamp that sits over every headline on the site. */
.item-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .8rem;
  margin-bottom: .35rem;
}


/* ============================================================
   9. The front page: lead, sub-features, river
   ============================================================
   Asymmetric on purpose. One lead beside its image, two unequal-to-the-lead
   sub-features, then a dense wire river. A trade has more headlines than it has
   pictures, and the image-less items are a river rather than a second grade of
   card: that distinction is what separates a trade from a blog with a card
   component. */

.lead {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1rem;
  padding-top: .8rem;
  border-top: 1px solid var(--beat-line, var(--rule));
}

.lead-figure { margin: 0; }

.lead-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.125rem, 1.3rem + 2.9vw, 3.375rem);
  line-height: .945;
  letter-spacing: -.022em;
  margin: 0 0 .6rem;
  text-wrap: balance;
}
.lead-title a { color: var(--ink); text-decoration: none; }
.lead-title a:hover { color: var(--beat-ink, var(--chrome)); }

.lead-dek { font-size: 1.125rem; }

@media (min-width: 860px) {
  .lead {
    grid-template-columns: 1.3fr 1fr;
    gap: 2rem;
    align-items: start;
  }
}

/* Two sub-features under the lead, image over text. They are a step down from
   the lead and a step up from the river, which is the whole point of running
   three grades instead of one uniform tile. */
.subfeatures {
  display: grid;
  grid-template-columns: 1fr;
  gap: 1.6rem;
  margin-top: 2.2rem;
}

@media (min-width: 640px) {
  .subfeatures { grid-template-columns: 1fr 1fr; gap: 2rem; }
}

.subfeature {
  display: flex;
  flex-direction: column;
  gap: .7rem;
  padding-top: .7rem;
  border-top: 1px solid var(--beat-line, var(--rule));
}

.subfeature-figure { margin: 0; }

.subfeature-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.5rem, 1.15rem + 1.1vw, 2rem);
  line-height: 1.1;
  letter-spacing: -.018em;
  margin: 0;
  text-wrap: balance;
}
.subfeature-title a { color: var(--ink); text-decoration: none; }
.subfeature-title a:hover { color: var(--beat-ink, var(--chrome)); }

.subfeature .dek { margin: 0; }

/* The river. Dense, hairline separated, headline first. The thumbnail is
   optional per item and is the same 16:9 as everything else. */
.river {
  list-style: none;
  margin: 0;
  padding: 0;
}

.river-item {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
  padding: .8rem 0;
  border-top: 1px solid var(--rule);
}
.river-item:first-child { border-top: 0; padding-top: 0; }

.river-text { flex: 1 1 auto; min-width: 0; }

.river-title {
  font-family: var(--body);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.3;
  letter-spacing: 0;
  margin: 0;
  text-wrap: pretty;
}
.river-title a { color: var(--ink); text-decoration: none; }
.river-title a:hover { color: var(--beat-ink, var(--chrome)); }

.river-thumb {
  flex: 0 0 7.5rem;
  display: block;
  line-height: 0;
}

@media (max-width: 419px) {
  .river-thumb { flex-basis: 5.5rem; }
}

/* The river's own meta line runs kicker, then timestamp, on one row above the
   headline, so a reader scanning down the column reads the beats as a stripe. */
.river-item .item-meta { margin-bottom: .2rem; }


/* ============================================================
   10. Issue hero and the issue archive
   ============================================================ */

.issue-hero {
  display: flex;
  flex-direction: column;
  gap: .7rem;
  padding-top: .8rem;
  border-top: 2px solid var(--chrome);
}

.issue-hero-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .5rem .8rem;
}

.issue-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.7rem, 1.3rem + 1.8vw, 2.5rem);
  line-height: 1.06;
  letter-spacing: -.02em;
  margin: 0;
  text-wrap: balance;
}
.issue-title a { color: var(--ink); text-decoration: none; }
.issue-title a:hover { color: var(--chrome); }

.issue-hero-list {
  list-style: none;
  margin: .3rem 0 0;
  padding: 0;
}
.issue-hero-list li {
  display: flex;
  gap: .7rem;
  align-items: baseline;
  border-top: 1px solid var(--rule);
  padding: .5rem 0;
}
.issue-hero-slot {
  font-family: var(--body);
  font-weight: 600;
  font-size: .72rem;
  letter-spacing: .13em;
  color: var(--chrome);
  flex: none;
}
.issue-hero-list a {
  color: var(--ink);
  text-decoration: none;
  font-family: var(--body);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.3;
}
.issue-hero-list a:hover { color: var(--chrome); }

/* The archive at /issues/. One column, because an issue is a document rather
   than a tile. */
.issue-list {
  list-style: none;
  margin: 0;
  padding: 0;
}
.issue-list > li {
  padding: 1.1rem 0;
  border-top: 1px solid var(--rule);
}
.issue-list > li:first-child { border-top: 0; padding-top: 0; }
.issue-list .issue-title { font-size: clamp(1.35rem, 1.1rem + .9vw, 1.7rem); margin-bottom: .35rem; }


/* ============================================================
   11. Sources, and how this item was made
   ============================================================
   Every item resolves to a primary document. The sources block is where that
   document is named, so it is marked as a filed record: a beat coloured hairline
   above it and the label in the tracked chrome register. It is deliberately not
   a box; the desk writes it into the post body as <div class="sources has-beat">
   and it has to sit inside the reading column without competing with it. */

.sources,
.ai-notice {
  margin: 2rem 0 0;
  border-top: 1px solid var(--beat-line, var(--rule));
  padding-top: .9rem;
}

.sources p { margin: 0 0 .4rem; }
.sources p:last-child { margin-bottom: 0; }

.sources,
.ai-notice,
.sources-list li {
  font-size: .95rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.sources strong,
.ai-notice strong {
  font-weight: 600;
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

.sources-label {
  font-size: .68rem;
  color: var(--ink-mute);
  margin: 0 0 .5rem;
  display: block;
}

.sources-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.sources-list li {
  display: flex;
  gap: .5rem;
  flex-wrap: wrap;
  padding: .3rem 0;
}

.sources-kind {
  font-family: var(--body);
  font-weight: 600;
  font-size: .64rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
  flex: none;
  padding-top: .3em;
}

.sources a { word-break: break-word; }


/* How this item was made: the AI disclosure. One fact on two surfaces.

   The kicker sits in the post header meta line beside the beat and the
   timestamp, so it takes the tracked uppercase chrome register the rest of that
   line is set in, at the smaller size the sources label uses, and the quietest
   ink in the palette. It is a provenance note, not a headline, and it must not
   compete with the beat next to it. The "/" that separates it is a real
   character in the markup rather than CSS pseudo content, so a screen reader
   reads it as part of the line, the way the footer legal line works.

   The notice at the foot of the item is the same filed-record shape as the
   sources block above: a hairline in the beat colour, the label in the chrome
   register, then the sentence. It shares those rules by selector rather than
   repeating them, and only the label going full width is its own. It carries no
   .has-beat of its own: the article already has one, and section 2 explains why
   a second one on a child re-derives the hairline from the raw --beat and
   undoes the light mode correction. */

.ai-kicker {
  font-family: var(--body);
  font-weight: 600;
  font-size: .68rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  font-variant-ligatures: none;
  color: var(--ink-mute);
}

.ai-notice strong {
  display: block;
  margin-bottom: .45rem;
}

.ai-notice p { margin: 0; }


/* ============================================================
   12. Signup call to action
   ============================================================ */

.signup-cta {
  margin: 3rem 0 0;
  border-top: 2px solid var(--chrome);
  background: var(--wash);
  padding: 1.6rem 1.5rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .7rem;
}

.signup-cta-title {
  font-family: var(--display);
  font-weight: 700;
  letter-spacing: -.018em;
  font-size: clamp(1.35rem, 1.1rem + 1vw, 1.8rem);
  line-height: 1.08;
  margin: 0;
  color: var(--ink);
}

.signup-cta-text {
  font-family: var(--body);
  color: var(--ink-soft);
  margin: 0;
  max-width: 36rem;
}

.signup-cta-note {
  font-family: var(--body);
  font-size: .78rem;
  line-height: 1.5;
  color: var(--ink-mute);
  margin: 0;
  max-width: 36rem;
}

.signup-cta .btn-primary { margin-top: .2rem; }


/* ============================================================
   13. Pagination
   ============================================================ */

.pagination {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin: 2.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--ink);
}

.pagination-number {
  font-size: .7rem;
  color: var(--ink-mute);
}

.pagination a,
.pagination .pagination-link {
  font-size: .72rem;
  color: var(--ink);
  text-decoration: none;
  border: 1px solid var(--rule);
  padding: .45rem .9rem;
}
.pagination a:hover { border-color: var(--chrome); color: var(--chrome); }

/* The missing end of the bar keeps the box it leaves behind the same size as
   the link it replaces, so the page counter stays put instead of sliding as the
   reader walks the archive. */
.pagination .pagination-link { border-color: transparent; }
.pagination .is-empty { visibility: hidden; }


/* ============================================================
   14. Post content
   ============================================================
   Reading copy is Newsreader at a comfortable measure. The Koenig card classes
   below cover what the editor can emit; Ghost's card_assets flag handles the
   rest. */

.post-header {
  margin: 2.5rem 0 1.4rem;
  padding-top: .8rem;
  border-top: 1px solid var(--beat-line, var(--rule));
  display: flex;
  flex-direction: column;
  gap: .5rem;
}

.post-header-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: .35rem .9rem;
  margin: 0;
}

.post-title {
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(2.125rem, 1.3rem + 2.9vw, 3.375rem);
  line-height: .96;
  letter-spacing: -.022em;
  margin: 0;
  text-wrap: balance;
}

.post-feature { margin: 0 0 1.8rem; }

.post-feature figcaption {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin: .55rem 0 0;
}

.post-content {
  font-family: var(--body);
  font-size: 1.09rem;
  line-height: 1.68;
  color: var(--ink);
}

.post-content > * + * { margin-top: 1.15em; }
.post-content > h2 { margin-top: 2.2rem; }
.post-content > h3 { margin-top: 1.8rem; }

.post-content a { text-decoration: underline; }

.post-content strong { font-weight: 700; }

.post-content blockquote {
  margin: 1.6rem 0;
  padding: .2rem 0 .2rem 1.1rem;
  border-left: 1px solid var(--beat-line, var(--rule));
  color: var(--ink-soft);
  font-style: italic;
}

.post-content ul, .post-content ol { padding-left: 1.3rem; }
.post-content li + li { margin-top: .35em; }

/* There is no monospace in this identity, so the two places code can appear are
   set in the body face and marked by the lifted ground alone. In practice the
   desk never writes either one. */
.post-content code {
  font-size: .92em;
  background: var(--wash);
  padding: .1em .35em;
}
.post-content pre {
  font-size: .92rem;
  background: var(--wash);
  border: 1px solid var(--rule);
  padding: 1rem;
  overflow-x: auto;
  white-space: pre-wrap;
}
.post-content pre code { background: none; padding: 0; }

.post-content figure { margin: 1.8rem 0; }
.post-content figcaption {
  font-size: .72rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
  margin-top: .55rem;
}

.post-content img { display: block; width: 100%; aspect-ratio: 16 / 9; object-fit: cover; }

.post-content table {
  width: 100%;
  border-collapse: collapse;
  font-size: .95rem;
}
.post-content th, .post-content td {
  text-align: left;
  padding: .5rem .6rem;
  border-bottom: 1px solid var(--rule);
}
.post-content th {
  font-size: .68rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-mute);
}

/* Wide and full width Koenig cards break the measure. */
.post-content .kg-card { margin-inline: auto; }
.post-content .kg-width-wide  { max-width: min(60rem, 100vw - 2 * var(--gutter)); width: 100vw; margin-inline: calc(50% - min(30rem, 50vw - var(--gutter))); }
.post-content .kg-width-full  { width: 100vw; margin-inline: calc(50% - 50vw); max-width: none; }
.post-content .kg-width-full img { width: 100%; }

.post-content .kg-bookmark-card a.kg-bookmark-container {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--rule);
  background: var(--wash);
  text-decoration: none;
  color: var(--ink);
  overflow: hidden;
}
.post-content .kg-bookmark-content { padding: 1rem 1.15rem; }
.post-content .kg-bookmark-title { font-family: var(--display); font-weight: 700; letter-spacing: -.015em; font-size: 1.1rem; }
.post-content .kg-bookmark-description { color: var(--ink-soft); font-size: .95rem; margin-top: .3rem; }
.post-content .kg-bookmark-metadata { font-size: .68rem; font-weight: 600; letter-spacing: .13em; text-transform: uppercase; color: var(--ink-mute); margin-top: .6rem; display: flex; align-items: center; gap: .4rem; }
.post-content .kg-bookmark-icon { width: 1rem; height: 1rem; aspect-ratio: auto; }
.post-content .kg-bookmark-thumbnail img { width: 100%; display: block; }

.post-content .kg-callout-card {
  display: flex;
  gap: .8rem;
  border-top: 1px solid var(--beat-line, var(--rule));
  border-bottom: 1px solid var(--beat-line, var(--rule));
  padding: 1rem 0;
}

.post-content .kg-button-card { display: flex; }
.post-content .kg-btn {
  font-family: var(--body);
  font-weight: 600;
  font-size: .76rem;
  letter-spacing: .13em;
  text-transform: uppercase;
  background: var(--chrome);
  color: var(--on-chrome);
  padding: .55rem 1.1rem;
  text-decoration: none;
}

.post-content .kg-toggle-card { border-top: 1px solid var(--rule); border-bottom: 1px solid var(--rule); padding: 1rem 0; }
.post-content .kg-toggle-heading-text { font-family: var(--display); font-weight: 700; letter-spacing: -.015em; }

/* Conflict of interest disclosure. The desk writes it as a <p class="disclosure">
   inside its own HTML card, so it arrives as part of the post body and would
   otherwise read as one more paragraph. Marked by a neutral rule, quieter than
   the copy around it, never a box that competes with the sources record above
   it. The rule is deliberately hueless: every hue in this palette names a beat,
   so a coloured rule here would read as "this post is Buyers" rather than
   "this is a disclosure". */
.post-content .disclosure {
  font-size: .95rem;
  line-height: 1.5;
  color: var(--ink-mute);
  border-left: 1px solid var(--ink-mute);
  padding: .15rem 0 .15rem .85rem;
  margin-block: 1.4rem;
}

.post-footer {
  margin: 2.5rem 0 0;
  padding-top: 1rem;
  border-top: 1px solid var(--ink);
  display: flex;
  flex-direction: column;
  gap: .8rem;
}

/* Previous and next inside the same beat. Two headlines under two labels, on
   hairlines, rather than two boxes. */
.post-siblings {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1rem 2rem;
  margin-top: 1.2rem;
}

.sibling {
  display: block;
  padding-top: .6rem;
  border-top: 1px solid var(--beat-line, var(--rule));
  text-decoration: none;
  color: var(--ink);
}
.sibling-title {
  display: block;
  font-family: var(--body);
  font-weight: 600;
  font-size: 1.0625rem;
  line-height: 1.3;
  margin-top: .25rem;
}
.sibling:hover .sibling-title { color: var(--beat-ink, var(--chrome)); }


/* ============================================================
   15. Tag, author and archive headers
   ============================================================ */

.tag-header,
.author-header,
.archive-header {
  margin: 2.5rem 0 1.4rem;
  padding-bottom: .8rem;
  border-bottom: 1px solid var(--ink);
  display: flex;
  flex-direction: column;
  gap: .45rem;
}

/* On a beat page the underline is the only place the beat colour appears at
   full width, and the title takes the same hue. */
.tag-header { border-bottom-color: var(--beat-ink, var(--ink)); }
.tag-header .tag-title { color: var(--beat-ink, var(--ink)); }

.archive-count { color: var(--ink-mute); margin: 0 0 1.1rem; }


/* ============================================================
   16. Flags
   ============================================================
   The desk's three flag lists (Unverified, Conflicts, Needs Albert) never leave
   the desk and are never pushed to Ghost. The class exists here so that any
   accidental leak renders as an obvious warning rather than as body copy, and
   so a theme error has somewhere to print.

   Red, not a warm warning colour, for the same reason the disclosure rule is
   hueless: orange and yellow both name beats here, so an amber warning on a
   Money or Buyers post would be indistinguishable from that post's own beat.
   Red is chrome, never a beat, and brand.md already assigns it to urgency.
   .flag-alarm is the louder grade, separated by weight rather than by hue. */

.flag {
  border-top: 2px solid var(--chrome);
  padding: .8rem 0 .9rem;
  margin: 1.5rem 0;
  color: var(--ink-soft);
  font-size: .94rem;
}

.flag-label {
  font-size: .68rem;
  color: var(--chrome);
  display: block;
  margin-bottom: .4rem;
}

.flag-alarm { border-top-width: 4px; }
.flag-alarm .flag-label { font-weight: 700; }


/* ============================================================
   17. Footer
   ============================================================ */

.site-footer {
  flex: none;
  margin-top: 4rem;
  border-top: 1px solid var(--ink);
  background: var(--paper);
}

.footer-inner {
  width: 100%;
  max-width: var(--wrap-wide);
  margin-inline: auto;
  padding: 1.8rem var(--gutter) 2.5rem;
  display: flex;
  flex-direction: column;
  gap: .8rem;
}

.footer-brand { display: flex; align-items: baseline; gap: .75rem; flex-wrap: wrap; }

.footer-name {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -.015em;
  text-transform: uppercase;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--ink);
}

.footer-nav .nav-list { padding: 0; max-width: none; margin: 0; gap: 0 1.3rem; }

.footer-legal { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem; margin: 0; }
.footer-sep { color: var(--rule); }

.footer-colophon { margin: 0; color: var(--ink-mute); }


/* ============================================================
   18. Error page and empty states
   ============================================================ */

.error-page {
  padding: 4rem var(--gutter) 6rem;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: .8rem;
}

.error-code {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(4rem, 3rem + 8vw, 8rem);
  line-height: 1;
  letter-spacing: -.03em;
  color: var(--chrome);
  margin: 0;
}

.error-page p { margin: 0; }
.error-page .flag { max-width: var(--wrap); width: 100%; }
.error-page .flag ul { margin: 0; padding-left: 1.1rem; }

.empty-state {
  border-top: 1px solid var(--rule);
  padding: 1.6rem 0 0;
  color: var(--ink-mute);
}

/* First block on a page that has no header of its own to carry the space.
   Templates whose first child is an .archive-header or a .post-header inherit
   the same 2.5rem through margin collapsing, so the top of every page lines up
   whichever route the reader came in on. */
.page-top { margin-block-start: 2.5rem; }


/* ============================================================
   19. Print
   ============================================================ */

@media print {
  .site-header, .site-footer, .signup-cta, .pagination, .skip-link { display: none !important; }
  body { background: #FFFFFF; color: #000000; }
  .post-content a::after { content: " (" attr(href) ")"; font-size: .8em; }
}
