/* Blogyň Azady — one stylesheet, plain CSS, no build step.
   Light is the default theme; dark is opt-in via [data-theme="dark"] on <html>.
   Type tokens, colour tokens and the spacing rhythm all live in :root.

   Provenance: every colour below is a value from the Nocturne design system,
   inlined rather than imported — a blog should not pay an extra stylesheet
   request to resolve nine hexes. The Nocturne name is in the comment beside
   each one, so a theme change upstream can be re-synced by hand. Nocturne
   governs the dark theme; the light theme reads the same ramps from the other
   end, which is why both sides resolve to real Nocturne steps.

   Also from Nocturne, structurally: Inter at 400/500, the 8px radius, the
   fading freestanding rule (.rule / .rule-both below), outlined actions with
   no filled primary, and photographs blended into the ground via
   --photo-blend. Nocturne's --shadow-* tokens are deliberately unused: this
   design has no elevated surface. */

/* ── tokens ───────────────────────────────────────────────────────────── */
:root {
  color-scheme: light;
  --bg: #f3f5fe;          /* neutral-100 */
  --surface: #e4e7f5;     /* neutral-200 */
  --text: #292b31;        /* neutral-900 — 13.1:1 on --bg */
  --meta: #595d6c;        /* neutral-700 — 6.0:1, metadata and captions */
  --hairline: #75798c;    /* neutral-600 — rules and borders only, never type */
  --rule: color-mix(in srgb, #292b31 14%, transparent);   /* divider, light side */
  --accent: #796cbf;      /* accent-600 — lines, marks, focus ring */
  --link: #5d5294;        /* accent-700 — 6.2:1, accent at type size */
  --on-accent: #f3f5fe;
  --accent-fill: #5d5294;
  --tint: color-mix(in srgb, #796cbf 7%, transparent);
  --photo-blend: multiply;

  --font: "Inter", system-ui, -apple-system, sans-serif;

  --measure: 640px;
  --rail: 180px;
  --gutter: 48px;
  --shell: 1084px;

  --post-top: 72px;       /* the spine's ::before offset reads this too */
  --step: 22.4px;         /* paragraph rhythm */
  --step-2: 44.8px;       /* above a heading */
  --step-3: 67.2px;       /* around a figure */
  --radius: 8px;
  --radius-sm: 4px;
}

/* Dark is Nocturne's own ground, unmodified: --color-bg, --color-surface,
   --color-text, --color-accent and --color-divider verbatim, with the
   greys taken off the neutral ramp and the link off the accent ramp at the
   step the guide prescribes for paragraph-size accent text on this ground. */
html[data-theme="dark"] {
  color-scheme: dark;
  --bg: #161826;          /* --color-bg */
  --surface: #232532;     /* --color-surface */
  --text: #e9e9ed;        /* --color-text — 14.5:1 on --bg */
  --meta: #b2b6ca;        /* neutral-400 — 8.8:1 */
  --caption: #9397ab;     /* neutral-500 — 6.1:1 */
  --hairline: #595d6c;    /* neutral-700 */
  --rule: color-mix(in srgb, #e9e9ed 16%, transparent);   /* --color-divider */
  --accent: #9184d9;      /* --color-accent */
  --link: #d2cefd;        /* accent-300 — 11.7:1 */
  --on-accent: #161826;
  --accent-fill: #9184d9;
  --tint: color-mix(in srgb, #9184d9 12%, transparent);
  --photo-blend: lighten;
}
:root { --caption: #595d6c; }   /* neutral-700 */

/* ── base ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font);
  font-size: 19px;
  line-height: 1.72;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; }
figure { margin: 0; }
h1, h2, h3, h4 { font-weight: 500; letter-spacing: -0.015em; line-height: 1.2; margin: 0; }
a { color: var(--link); text-underline-offset: 3px; }
:focus { outline: none; }
:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-radius: 2px; }
::selection { background: color-mix(in srgb, var(--accent) 30%, transparent); }

.skip { position: absolute; left: -9999px; top: 0; }
.skip:focus { left: 8px; top: 8px; z-index: 10; background: var(--surface); color: var(--text); padding: 10px 14px; border-radius: var(--radius); font-size: 14px; }

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 var(--gutter); }
.rule { height: 1px; border: 0; margin: 0;
  background: linear-gradient(to right, var(--rule), var(--rule) calc(100% - 48px), transparent); }
.rule-both { background: linear-gradient(to right, transparent, var(--rule) 48px, var(--rule) calc(100% - 48px), transparent); }

/* Photographs blend into the page: dark values fall away on the dark theme,
   light values on the light one. The masthead is the exception — it carries
   type, so it keeps a fixed value and a scrim. */
.photo { mix-blend-mode: var(--photo-blend); background-color: transparent; }
figcaption { font-size: 13px; line-height: 1.5; color: var(--caption); margin-top: 11px; }

/* ── header ───────────────────────────────────────────────────────────── */
.head { border-bottom: 1px solid var(--rule); }
.head-in { max-width: var(--shell); margin: 0 auto; padding: 20px var(--gutter);
  display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.brand { font-size: 15px; font-weight: 500; letter-spacing: -0.01em; color: var(--text); text-decoration: none; }
.nav { display: flex; align-items: center; gap: 22px; }
.nav a { font-size: 13px; color: var(--meta); text-decoration: none; }
.nav a:hover { color: var(--text); }
.nav a[aria-current="page"] { color: var(--text); }
.langs { display: flex; align-items: center; gap: 1px; border: 1px solid var(--rule);
  border-radius: var(--radius-sm); overflow: hidden; }
.langs a { font-size: 11px; letter-spacing: 0.06em; padding: 5px 9px; color: var(--meta); text-decoration: none; }
.langs a:hover { background: var(--tint); }
.langs a[aria-current="true"] { color: var(--on-accent); background: var(--accent-fill); }
.theme-toggle { appearance: none; background: transparent; border: 1px solid var(--rule);
  border-radius: var(--radius-sm); width: 30px; height: 26px; display: grid; place-items: center;
  cursor: pointer; color: var(--meta); padding: 0; }
.theme-toggle:hover { background: var(--tint); color: var(--text); }
.theme-toggle svg { width: 15px; height: 15px; }
.theme-toggle .sun { display: none; }
html[data-theme="dark"] .theme-toggle .sun { display: block; }
html[data-theme="dark"] .theme-toggle .moon { display: none; }

/* ── cover ────────────────────────────────────────────────────────────── */
.cover { position: relative; }
.cover img { width: 100%; height: 280px; object-fit: cover; object-position: 50% 42%; }
.cover-scrim { position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(22,24,38,0.9) 0%, rgba(22,24,38,0.9) 88px,
    rgba(22,24,38,0.45) 55%, rgba(22,24,38,0.08) 100%); }
.cover-text { position: absolute; left: var(--gutter); bottom: 30px;
  display: flex; align-items: flex-end; gap: 16px; }
.cover-text .tick { width: 28px; height: 2px; background: #f3f5fe; margin-bottom: 12px; }
.cover-text p { margin: 0; font-size: 26px; font-weight: 500; letter-spacing: -0.015em; color: #f3f5fe; }

/* ── the reading grid ─────────────────────────────────────────────────── */
.grid { display: grid; grid-template-columns: var(--rail) minmax(0, var(--measure)) 1fr;
  gap: var(--gutter); max-width: var(--shell); margin: 0 auto; padding: 0 var(--gutter); }
.rail { display: flex; flex-direction: column; gap: 20px; padding-top: 12px; }
.rail .tick { width: 20px; height: 2px; background: var(--accent); }
.kicker { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--meta); }
.kicker-dim { font-size: 12px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--caption); }
.tags { display: flex; flex-wrap: wrap; gap: 6px; }
.tag { font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--link);
  border: 1px solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: var(--radius-sm); padding: 3px 8px; text-decoration: none; }
.tag:hover { background: var(--tint); }

/* ── feed: text first ─────────────────────────────────────────────────── */
.feed { display: flex; flex-direction: column; padding: 40px 0 0; }
.feed-head { display: flex; flex-direction: column; gap: 6px; padding-top: 40px; }
.row { display: flex; gap: 24px; align-items: baseline; text-decoration: none;
  padding: 20px 0; border-bottom: 1px solid var(--rule); position: relative; }
.row:last-of-type { border-bottom: 0; }
.row:hover { background: var(--tint); }
.row-date { font-size: 12px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--meta);
  width: 96px; flex: none; font-variant-numeric: tabular-nums; }
.row-body { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.row-title { font-size: 21px; font-weight: 500; line-height: 1.25; letter-spacing: -0.015em; color: var(--text); }
.row:hover .row-title { color: var(--link); }
.row-excerpt { font-size: 15px; line-height: 1.55; color: var(--meta); text-wrap: pretty; }
/* The photograph is a reward for pointing at a row, and only where the margin
   has room for it. Nothing depends on it: without hover, or on a phone, the
   row is text. */
.row-thumb { display: none; }
@media (min-width: 1180px) {
  .row-thumb { display: block; position: absolute; left: 100%; margin-left: 24px; top: 14px;
    width: 96px; mix-blend-mode: var(--photo-blend); border-radius: var(--radius-sm);
    overflow: hidden; opacity: 0; transition: opacity 160ms ease; }
  .row:hover .row-thumb, .row:focus-visible .row-thumb { opacity: 1; }
  .row-thumb img { width: 100%; height: 72px; object-fit: cover; }
}
@media (prefers-reduced-motion: reduce) { .row-thumb { transition: none; } }
.feed-empty { padding: 40px 0; font-size: 19px; line-height: 1.72; color: var(--meta); }
.feed-empty-actions { display: flex; gap: 10px; margin-top: 24px; }

/* ── pagination ───────────────────────────────────────────────────────── */
.pager { display: flex; align-items: center; justify-content: space-between; padding: 32px 0 72px; }
.pager a { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; text-decoration: none; }
.pager a:hover { color: var(--text); }
.pager span[aria-disabled] { font-size: 13px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--meta); }
.pager .count { font-size: 12px; letter-spacing: 0.08em; color: var(--meta); font-variant-numeric: tabular-nums; opacity: 1; }

/* ── post ─────────────────────────────────────────────────────────────── */
.post { padding: var(--post-top) 0 64px; position: relative; }
/* The page's one mark: an accent hairline down the column, released before the
   end. `top` resolves against the padding box, so it has to clear the article's
   own top padding — otherwise the line drops out of the header. */
.post::before { content: ""; position: absolute; left: -24px; top: calc(var(--post-top) + 6px); bottom: 0; width: 1px;
  background: linear-gradient(to bottom, color-mix(in srgb, var(--accent) 70%, transparent),
    color-mix(in srgb, var(--accent) 70%, transparent) calc(100% - 120px), transparent); }
.post h1 { font-size: 44px; line-height: 1.12; }
.post .excerpt { font-size: 19px; line-height: 1.6; color: var(--meta); margin: var(--step) 0 0; text-wrap: pretty; }
.post .feature { margin: var(--step-2) 0 0; width: calc(100% + var(--gutter) + 72px); max-width: none; }
.post .feature .photo { border-radius: var(--radius); overflow: hidden; }
.post .feature img { width: 100%; height: 380px; object-fit: cover; }
.body { margin-top: var(--step-2); }
/* One reset for every child: the rhythm below owns top margins, so no element
   can leak a UA bottom margin into it. */
.body > * { margin-bottom: 0; }
.body > * + * { margin-top: var(--step); }
.body > *:first-child { margin-top: 0; }
.body p { text-wrap: pretty; }
.body h2 { font-size: 26px; margin-top: var(--step-2); }
.body h3 { font-size: 20px; letter-spacing: -0.01em; margin-top: var(--step-2); }
.body ul, .body ol { padding-left: 22px; }
.body li + li { margin-top: 6px; }
.body blockquote { margin: var(--step-2) 0 0; padding-left: 24px;
  border-left: 2px solid var(--accent); font-size: 22px; line-height: 1.5; letter-spacing: -0.005em; }
.body blockquote p { margin: 0; }
.body figure { margin-top: var(--step-3); }
.body figure .photo { border-radius: var(--radius); overflow: hidden; }
.body pre { margin-top: var(--step-2); padding: 18px 20px; background: var(--surface);
  border: 1px solid var(--rule); border-radius: var(--radius);
  font-size: 14px; line-height: 1.6; overflow-x: auto; }
.body code { font-family: ui-monospace, SFMono-Regular, Menlo, monospace; font-size: 0.86em; }
.body .lines { display: flex; flex-direction: column; gap: 6px; }
.neighbours { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; margin-top: 28px; }
.neighbours a { display: flex; flex-direction: column; gap: 8px; text-decoration: none; }
.neighbours a:last-child { text-align: right; }
.neighbours .n-title { font-size: 18px; font-weight: 500; line-height: 1.3; letter-spacing: -0.01em; color: var(--text); }
.neighbours a:hover .n-title { color: var(--link); }
.post-foot { margin-top: var(--step-3); }

/* ── archive heading, about, 404 ──────────────────────────────────────── */
.archive { padding: 64px 0 0; display: flex; flex-direction: column; gap: 10px; }
.archive h1 { font-size: 38px; line-height: 1.12; letter-spacing: -0.018em; }
.page { padding: var(--post-top) 0 80px; position: relative; }
.page h1 { font-size: 44px; line-height: 1.12; }
.page .body { margin-top: var(--step-2); }
.notfound { padding: 120px 0 140px; display: flex; flex-direction: column; gap: 14px; }
.notfound h1 { font-size: 44px; line-height: 1.12; }
.notfound p { margin: 0; color: var(--meta); max-width: 30em; }

/* ── buttons ──────────────────────────────────────────────────────────── */
.btn { display: inline-flex; align-items: center; justify-content: center;
  font-size: 14px; font-weight: 500; line-height: 1.2; text-decoration: none;
  padding: 8px 14px; border-radius: var(--radius); border: 1px solid transparent; cursor: pointer; }
.btn-primary { color: var(--link); border-color: var(--accent); }
.btn-primary:hover { background: var(--tint); }
.btn-secondary { color: var(--text); border-color: var(--rule); }
.btn-secondary:hover { background: color-mix(in srgb, var(--text) 7%, transparent); }

/* ── page transitions ─────────────────────────────────────────────────────
   Cross-document view transitions: pure CSS, no script. Browsers without
   support navigate exactly as before, so nothing depends on this. The header
   and footer are named only so they animate as their own group rather than
   travelling with the content; they keep the default cross-fade, which is
   invisible when they are identical and correct when they are not (the nav
   labels and the filled language pill change between /, /en/ and /ru/).
   ─────────────────────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: no-preference) {
  /* The at-rule lives inside the motion query: nothing in the spec suppresses
     view transitions for reduced motion, so leaving it outside would keep the
     UA's default root cross-fade for exactly the readers who asked for none. */
  @view-transition { navigation: auto; }

  .head { view-transition-name: head; }
  .foot { view-transition-name: foot; }
  main { view-transition-name: main; }
  ::view-transition-old(main) { animation: page-out 120ms ease both; }
  ::view-transition-new(main) { animation: page-in 260ms cubic-bezier(0.2, 0.6, 0.2, 1) 30ms both; }
}
/* No `transition` on colour, background or border anywhere. Every one of those
   values comes from a theme token, and a declared colour transition leaves the
   property stuck at the outgoing theme's value when [data-theme] flips — the
   brand, nav, tags, buttons and all inherited body copy stayed light on the
   dark ground. Hover and theme changes are discrete here; the page transition
   above carries the motion. */
@keyframes page-out { to { opacity: 0; transform: translateY(-4px); } }
@keyframes page-in { from { opacity: 0; transform: translateY(8px); } }

/* ── footer ───────────────────────────────────────────────────────────── */
.foot { border-top: 1px solid var(--rule); margin-top: 0; }
.foot-in { max-width: var(--shell); margin: 0 auto; padding: 28px var(--gutter);
  display: flex; justify-content: space-between; gap: 24px; flex-wrap: wrap;
  font-size: 13px; color: var(--meta); }
.foot-in a { color: var(--meta); text-decoration: none; }
.foot-in a:hover { color: var(--text); }

/* ── narrow ───────────────────────────────────────────────────────────── */
@media (max-width: 1080px) {
  :root { --gutter: 32px; }
  .post .feature { width: 100%; }
}
@media (max-width: 900px) {
  .grid { grid-template-columns: minmax(0, 1fr); gap: 0; }
  .rail { flex-direction: row; flex-wrap: wrap; align-items: center; gap: 12px 16px; padding-top: 0; }
  .rail .tick { width: 14px; }
  .rail .translations { width: 100%; }
  :root { --post-top: 32px; }
  .post::before { left: -16px; }
  /* The nav drops to its own row and scrolls sideways rather than disappearing:
     six tag archives and the about page have to stay reachable on a phone, and
     a disclosure would need script. The overflow edge fades the way the rules
     fade elsewhere. */
  .head-in { flex-wrap: wrap; row-gap: 2px; }
  .nav { order: 3; width: 100%; min-height: 44px; gap: 20px; overflow-x: auto;
    scrollbar-width: none; -webkit-overflow-scrolling: touch;
    margin: 0 calc(var(--gutter) * -1); padding: 0 var(--gutter);
    mask-image: linear-gradient(to right, #000 calc(100% - 28px), transparent); }
  .nav::-webkit-scrollbar { display: none; }
  .nav a { white-space: nowrap; display: flex; align-items: center; min-height: 44px; }
  /* touch targets */
  .theme-toggle { width: 44px; height: 44px; }
  .langs a { display: flex; align-items: center; min-height: 44px; padding: 0 11px; }
  .archive { padding-top: 40px; }
  .notfound { padding: 72px 0 96px; }
}
@media (max-width: 640px) {
  :root { --gutter: 20px; --step: 20px; --step-2: 32px; --step-3: 40px; }
  body { font-size: 17px; }
  .post h1, .page h1, .notfound h1 { font-size: 30px; line-height: 1.14; }
  .post .excerpt { font-size: 17px; }
  .post .feature { margin-left: calc(var(--gutter) * -1); margin-right: calc(var(--gutter) * -1); width: auto; }
  .post .feature .photo { border-radius: 0; }
  .post .feature img { height: 220px; }
  .post .feature figcaption { margin-left: var(--gutter); }
  .body h2 { font-size: 22px; }
  .body h3 { font-size: 18px; }
  .body blockquote { font-size: 19px; padding-left: 18px; }
  .cover img { height: 200px; }
  .cover-text p { font-size: 20px; }
  .row { flex-direction: column; gap: 8px; }
  .row-date { width: auto; }
  .archive h1 { font-size: 30px; }
  .neighbours { grid-template-columns: 1fr; gap: 20px; }
  .neighbours a:last-child { text-align: left; }
}

/* ── site logo ─────────────────────────────────────────────────────────────
   Added after handoff. .brand above is styled for a text wordmark, but this
   site has a logo image set, so templates.js renders an <img>. That file is a
   white-on-transparent wordmark drawn for the old dark header, which leaves it
   invisible on the light ground. brightness(0) paints its opaque pixels black
   while preserving the alpha; dark keeps the file as drawn. A filter, not a
   colour, so the no-colour-transition rule still holds. */
.brand img { display: block; }
:root[data-theme="light"] .brand img { filter: brightness(0); opacity: .82; }
