/* Dziennik wdrożeń – blog index
   One responsive page, drawn at 390px and 1440px and interpolated in between.
   Mobile-first; breakpoints at 46em (736px) and 66em (1056px). */

/* ---------- Fonts ----------
   Self-hosted so nothing reaches a third party before the visitor has consented,
   and so the render-blocking round trip to fonts.googleapis.com disappears.
   Only what the page actually uses: Newsreader roman and IBM Plex Mono 400, no italics.
   latin + latin-ext both ship – Polish diacritics (ł ż ś ę ą ć ń ó ź) live in latin-ext.

   Newsreader comes in two cuts, built by tools/build-fonts.py from the untouched Google
   subsets. Those carry an opsz axis worth about 60% of their bytes, which is what kept
   Lighthouse off 100; dropping it everywhere would have cost the masthead its display
   drawing. So it is spent where it shows:

     Newsreader          body and small headings, opsz pinned at 18 – the value optical
                         sizing picks for 16–24px text anyway – and wght held to 300–600.
     Newsreader Display  masthead and big titles, 29–76px. One static weight at opsz 48,
                         cut to the characters a headline here can contain. A glyph outside
                         that set falls through to Newsreader, not to Georgia, which is why
                         the family is listed second in --serif-display. */

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/newsreader-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 300 600;
  font-display: swap;
  src: url('../fonts/newsreader-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'Newsreader Display';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/newsreader-display-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Newsreader Display';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/newsreader-display-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'IBM Plex Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/ibm-plex-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ---------- Tokens ---------- */

:root {
  --canvas: #e8e4dc;
  --paper: #faf7f0;
  --paper-alt: #f2eee4;
  --ink: #1b1917;
  --ink-strong: #24211e;
  --ink-soft: #45403a;
  --ink-muted: #6b645c;
  --rule: #d8d2c6;
  --accent: #b4472a;
  --highlight: #f3d9a4;
  --hatch-a: #e4dfd4;
  --hatch-b: #efeae0;

  --serif: Newsreader, Georgia, "Times New Roman", serif;
  /* Only for type big enough to want the display cut: 29px and up. Newsreader sits behind
     it so a character missing from the display subset falls back one step, not two. */
  --serif-display: "Newsreader Display", Newsreader, Georgia, "Times New Roman", serif;
  --mono: "IBM Plex Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  /* 20px at 390px, 44px at 1440px */
  --gutter: clamp(1.25rem, 3.1vw, 2.75rem);

  /* Fluid type: each ramp hits its lower value at 390px and its upper one at 1440px */
  --size-masthead: clamp(2.5rem, 1.664rem + 3.43vw, 4.75rem);      /*  40 → 76 */
  --size-lead: clamp(1.8125rem, 1.418rem + 1.62vw, 2.875rem);      /*  29 → 46 */
  --size-card: clamp(1.375rem, 1.282rem + 0.38vw, 1.625rem);       /*  22 → 26 */
  --size-brief: clamp(1.1875rem, 1.094rem + 0.38vw, 1.4375rem);    /*  19 → 23 */
  --size-standfirst: clamp(1.03125rem, 0.973rem + 0.24vw, 1.1875rem); /* 16.5 → 19 */
  --size-note: clamp(1.0625rem, 1.031rem + 0.1vw, 1.125rem);       /*  17 → 18 */
  --size-brand: clamp(1.3125rem, 1.196rem + 0.48vw, 1.625rem);     /*  21 → 26 */
  --size-body: clamp(0.96875rem, 0.951rem + 0.05vw, 1rem);         /* 15.5 → 16 */

  --mono-1: clamp(0.5938rem, 0.559rem + 0.14vw, 0.6875rem);        /* 9.5 → 11 */
  --mono-2: clamp(0.625rem, 0.602rem + 0.1vw, 0.6875rem);          /*  10 → 11 */
  --mono-3: clamp(0.6875rem, 0.664rem + 0.1vw, 0.75rem);           /*  11 → 12 */
}

/* ---------- Base ---------- */

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

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--canvas);
  color: var(--ink);
  font-family: var(--serif);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1, h2, h3, p, ul { margin: 0; }
h1, h2, h3 { font-weight: 500; }
ul { padding: 0; list-style: none; }

a {
  color: var(--ink);
  text-decoration-color: var(--accent);
  text-underline-offset: 3px;
}

a:hover { color: var(--accent); }

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

::selection { background: var(--highlight); }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

/* ---------- Shell ---------- */

.skip-link {
  position: absolute;
  top: 0;
  left: -100vw;
}

.skip-link:focus {
  left: 0;
  z-index: 10;
  background: var(--ink);
  color: var(--paper);
  padding: 0.75rem 1rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
}

/* The only rule in this file that a reader never sees. The panel's preview renders a real
   page through layout/base.php, and a preview that looks exactly like the live site is one
   you can mistake for it – so it says which it is, in the page's own typography. Kept here
   rather than in panel.css because the preview loads the reader's stylesheet, not the
   panel's, and that is the whole point of it. */
.preview-bar {
  margin: 0;
  padding: 0.625rem var(--gutter);
  background: var(--ink);
  color: var(--paper);
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.04em;
}

.preview-bar--draft { background: #8a3b1f; }

.preview-bar a { color: inherit; }

.page { padding-bottom: 3.5rem; }

.paper {
  max-width: 1440px;
  margin: 0 auto;
  background: var(--paper);
}

#tresc:focus { outline: none; }

/* ---------- Masthead ---------- */

.masthead {
  display: flex;
  flex-direction: column;
}

.masthead > * { padding-inline: var(--gutter); }

.masthead__strap {
  padding-top: 1.125rem;
  font-family: var(--mono);
  font-size: var(--mono-1);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  text-align: center;
}

.masthead__strap-more { display: none; }

/* The title runs at line-height 0.92–0.94, so its glyphs overflow their own line box –
   and "ż" and "ń" put diacritics above the cap height on top of that. The padding here has
   to buy back what the tight leading eats, which is why the top is the larger of the two
   even though the rule above is a hairline and the one below is a double rule. */
.masthead__block {
  border-bottom: 3px double var(--ink);
  padding-block: 1.125rem 1.25rem;
  text-align: center;
}

/* font-weight is stated here rather than inherited from the `h1, h2, h3` base rule,
   because this element is a <p> on every page except the home page. */
.masthead__title {
  font-family: var(--serif-display);
  font-size: var(--size-masthead);
  line-height: 0.94;
  letter-spacing: -0.025em;
  font-weight: 500;
}

/* On every page but the home page the masthead is a link back to /. It has to read as
   the masthead, not as a link in running text, so it takes the colour of its surroundings
   and shows itself only on hover. */
.masthead__title a {
  color: inherit;
  text-decoration: none;
}

.masthead__title a:hover { color: var(--accent); }

.masthead__title-word { display: block; }

.masthead__tagline {
  margin-top: 0.625rem;
  font-family: var(--mono);
  font-size: var(--mono-1);
  line-height: 1.5;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

/* Topic bar: a compact label + search row above the masthead on small screens
   (with the topics themselves in a scrollable strip), a single inline row
   below the masthead from 46em up. */
.topics {
  order: -1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0 1.25rem;
  border-bottom: 1px solid var(--rule);
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

/* Burger and search are both full 44px touch targets – the old scrolling strip of
   bare links gave about 13px, which is what made this so hard to hit on a phone. */
.topics__toggle {
  order: 1;
  margin-right: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: var(--ink-muted);
  cursor: pointer;
}

.topics__toggle:hover,
.topics__toggle[aria-expanded="true"] { color: var(--ink); }

/* Closed shows the burger, open shows the cross – one control, two states. */
.topics__toggle[aria-expanded="true"] .topics__icon--menu,
.topics__toggle[aria-expanded="true"] .topics__toggle-menu,
.topics__toggle[aria-expanded="false"] .topics__icon--close,
.topics__toggle[aria-expanded="false"] .topics__toggle-close { display: none; }

.topics__search {
  order: 2;
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--accent);
  text-decoration: none;
}

.topics__search:hover { text-decoration: underline; }
.topics__search-more { display: none; }

.topics__list {
  order: 3;
  flex: 1 0 100%;
  display: flex;
  flex-direction: column;
  border-top: 1px solid var(--rule);
}

/* Collapsed only when JS can reopen it; the state is read straight off aria-expanded. */
.js .topics__list { display: none; }
.js .topics__toggle[aria-expanded="true"] ~ .topics__list { display: flex; }

.topics__list a {
  display: flex;
  align-items: center;
  min-height: 2.75rem;
  border-bottom: 1px solid var(--rule);
  font-size: var(--mono-3);
  text-decoration: none;
}

.topics__list li:last-child a { border-bottom: 0; }

/* The current topic. Keyed on aria-current so the accessible state and the visible one
   cannot drift apart – there is no second class to remember to set. */
.topics__list a[aria-current] {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 4px;
}

@media (min-width: 46em) {
  .masthead {
    padding: 1.75rem var(--gutter) 0;
  }

  .masthead > * { padding-inline: 0; }

  .masthead__strap {
    padding-top: 0;
    font-size: var(--mono-2);
    letter-spacing: 0.18em;
  }

  .masthead__strap-more { display: inline; }

  .masthead__block {
    margin-top: 0.75rem;
    border-top: 1px solid var(--ink);
    padding-block: 1.75rem 1.5rem;
  }

  .masthead__title {
    line-height: 0.92;
    letter-spacing: -0.03em;
  }

  .masthead__title-word { display: inline; }

  .masthead__tagline {
    margin-top: 0.75rem;
    font-size: var(--mono-3);
    letter-spacing: 0.14em;
  }

  .topics {
    order: 0;
    align-items: baseline;
    padding-block: 0.75rem;
    /* 13px rather than the 12px of the footer nav: this is a primary control and there
       is plenty of room, while staying well below the masthead's register. */
    font-size: 0.8125rem;
    letter-spacing: 0.05em;
  }

  .topics__toggle { display: none; }

  /* Back to inline: the 44px flex target is a mobile concern, and inline-flex trims
     the leading space in " / archiwum". */
  .topics__search {
    display: inline;
    order: 2;
    min-height: 0;
    margin-left: auto;
  }

  .topics__search-more { display: inline; }

  /* Must restate display: the mobile collapse rule (.js .topics__list) sets it to
     none, and this list is always open from 46em up. */
  .js .topics__list,
  .topics__list {
    display: flex;
    order: 1;
    flex: 0 1 auto;
    flex-direction: row;
    flex-wrap: wrap;
    column-gap: 1.625rem;
    row-gap: 0.5rem;
    border-top: 0;
  }

  .topics__list a {
    display: inline-block;
    min-height: 0;
    border-bottom: 0;
    padding-block: 0.25rem;
    font-size: inherit;
    white-space: nowrap;
  }
}

/* ---------- Layout ---------- */

/* .pair and .stack are display: contents below 66em so that every feed item is
   a direct flex child and its hairline rule can run edge to edge on mobile. */
.feed {
  display: flex;
  flex-direction: column;
}

.pair,
.stack { display: contents; }

.lead,
.card,
.brief {
  padding-inline: var(--gutter);
  border-bottom: 1px solid var(--rule);
}

.lead { padding-block: 1.375rem 1.25rem; }
.card,
.brief { padding-block: 1.125rem; }

@media (min-width: 46em) {
  .layout { padding-inline: var(--gutter); }

  .lead,
  .card,
  .brief { padding-inline: 0; }

  .lead { padding-block: 2rem 1.75rem; }

  .pair {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 2rem;
    padding-block: 1.75rem;
    border-bottom: 1px solid var(--rule);
  }

  .card {
    padding-block: 0;
    border-bottom: 0;
  }

  .stack {
    display: flex;
    flex-direction: column;
    gap: 1.375rem;
    padding-top: 1.625rem;
  }

  .brief {
    padding-block: 0;
    border-bottom: 0;
  }
}

@media (min-width: 66em) {
  .layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 344px;
    padding-bottom: var(--gutter);
  }

  .feed { padding-right: 2.25rem; }
}

/* ---------- Feed ---------- */

.eyebrow {
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.meta {
  display: flex;
  flex-wrap: wrap;
  gap: 0.625rem;
}

.meta__topic,
.kicker a {
  color: var(--accent);
  text-decoration: none;
}

.meta__topic:hover,
.kicker a:hover { text-decoration: underline; }

.meta__year { display: none; }

@media (min-width: 46em) {
  .meta { gap: 0.875rem; }
  .meta__year { display: inline; }
}

.lead__title,
.card__title,
.brief__title,
.entry__title,
.pagehead__title,
.post__title { text-wrap: pretty; }

.lead__title a,
.card__title a,
.brief__title a,
.entry__title a { text-decoration: none; }

/* The three headline slots that carry a page: the home lead, a list or about heading,
   and an article's own title. Same size on purpose – each is the largest thing on its
   page, and the masthead h1 sits above all of them. */
.lead__title,
.pagehead__title,
.post__title {
  font-family: var(--serif-display);
  margin-top: 0.5rem;
  font-size: var(--size-lead);
  line-height: 1.04;
  letter-spacing: -0.018em;
}

.lead__standfirst,
.pagehead__intro,
.post__standfirst {
  margin-top: 0.625rem;
  max-width: 60ch;
  font-size: var(--size-standfirst);
  line-height: 1.52;
  color: var(--ink-soft);
  text-wrap: pretty;
}

.card__title {
  margin-top: 0.5rem;
  font-size: var(--size-card);
  line-height: 1.12;
  letter-spacing: -0.01em;
}

.card__excerpt,
.brief__excerpt,
.entry__excerpt {
  margin-top: 0.5rem;
  font-size: var(--size-body);
  line-height: 1.52;
  color: var(--ink-soft);
}

.brief {
  display: grid;
  grid-template-columns: 84px 1fr;
  gap: 0.875rem;
  align-items: start;
}

.brief__title {
  margin-top: 0.3125rem;
  font-size: var(--size-brief);
  line-height: 1.16;
}

.thumb {
  aspect-ratio: 4 / 3;
  display: grid;
  place-items: center;
  border: 1px solid var(--rule);
  background: repeating-linear-gradient(135deg, var(--hatch-a) 0 6px, var(--hatch-b) 6px 12px);
}

.thumb span {
  font-family: var(--mono);
  font-size: 0.5rem;
  line-height: 1.35;
  text-align: center;
  color: var(--ink-muted);
}

@media (min-width: 46em) {
  .lead__title,
  .pagehead__title,
  .post__title { margin-top: 0.625rem; }

  .lead__standfirst,
  .pagehead__intro,
  .post__standfirst { margin-top: 0.875rem; }

  .brief {
    grid-template-columns: 128px 1fr;
    gap: 1.375rem;
  }

  .brief__title { margin-top: 0.375rem; }
  .thumb span { font-size: 0.5625rem; }
}

/* ---------- Index, article, about ---------- */

/* The heading block that opens /wpisy and /o-mnie. The home page has the masthead for
   this job, so it has no .pagehead of its own. */
.pagehead {
  padding-inline: var(--gutter);
  padding-block: 1.375rem 1.25rem;
  border-bottom: 1px solid var(--rule);
}

.entries {
  display: flex;
  flex-direction: column;
}

/* Same hairline-separated rhythm as the feed, one step quieter: the index is a list to
   scan, so the title drops to the brief size and there is no thumbnail. */
.entry {
  padding-inline: var(--gutter);
  padding-block: 1.125rem;
  border-bottom: 1px solid var(--rule);
}

.entry__title {
  margin-top: 0.4375rem;
  font-size: var(--size-brief);
  line-height: 1.16;
}

.post {
  padding-inline: var(--gutter);
  padding-block: 1.375rem 1.75rem;
}

.post__head { border-bottom: 1px solid var(--rule); }

.post__standfirst { padding-bottom: 1.25rem; }

.post__foot {
  margin-top: 1.75rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
}

/* ----- Article body ----- */

/* Measure is set here rather than on .post, so the hairlines above and below the body
   still run the full column while the prose itself stays readable. */
.prose {
  max-width: 68ch;
  margin-top: 1.5rem;
  font-size: var(--size-note);
  line-height: 1.62;
  color: var(--ink-strong);
}

/* On a page with no article header (/o-mnie) the prose is the first thing inside .post,
   where its own top margin would stack on the block's padding. */
.post > .prose:first-child { margin-top: 0; }

.prose > * + * { margin-top: 1.125rem; }

/* .prose h3 sets its own top margin, which would otherwise stack on top of the block's
   own spacing when a body opens with a subheading, as /o-mnie does. */
.prose > :first-child { margin-top: 0; }

/* h2, not h3: the entry title above is the h1, so a subheading is one level down and
   skipping a level would leave a hole in the outline. */
.prose h2 {
  margin-top: 2rem;
  font-size: var(--size-brief);
  line-height: 1.2;
  letter-spacing: -0.008em;
}

.prose ul,
.prose ol { padding-left: 1.25rem; }

.prose ul { list-style: disc; }
.prose ol { list-style: decimal; }

.prose li + li { margin-top: 0.5rem; }

.prose li::marker { color: var(--ink-muted); }

.prose strong { font-weight: 600; }

.prose a { text-decoration-thickness: 1px; }

.prose code {
  font-family: var(--mono);
  font-size: 0.875em;
  background: var(--paper-alt);
  padding: 0.1em 0.35em;
}

/* ----- Previous / next ----- */

.pager {
  display: grid;
  gap: 1px;
  background: var(--rule);
  border-block: 1px solid var(--rule);
}

.pager__link {
  display: block;
  padding: 1rem var(--gutter);
  background: var(--paper);
  text-decoration: none;
}

.pager__link:hover { background: var(--paper-alt); }

.pager__dir {
  display: block;
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.pager__title {
  display: block;
  margin-top: 0.375rem;
  font-size: var(--size-body);
  line-height: 1.32;
  text-wrap: pretty;
}

.pager__link:hover .pager__title { color: var(--accent); }

@media (min-width: 46em) {
  .pagehead { padding-block: 2rem 1.75rem; }

  .pagehead,
  .entry,
  .post { padding-inline: 0; }

  .entry { padding-block: 1.375rem; }

  .post { padding-block: 2rem 2.25rem; }

  .prose { margin-top: 1.75rem; }

  /* Two columns from here up, so "newer" and "older" read left and right. A single
     neighbour still fills the row rather than stranding half of it. */
  .pager {
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    margin-top: 0.5rem;
  }

  .pager__link { padding-inline: 1.125rem; }

  .pager__link--next {
    text-align: right;
    grid-column: -2;
  }
}

/* ---------- Breadcrumbs ---------- */

/* Sentence case, unlike the other mono lines on the page: an entry title in uppercase
   would shout louder than the h1 directly beneath it. */
.crumbs {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.375rem;
  margin-bottom: 0.5rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
  color: var(--ink-muted);
}

.crumbs a {
  color: var(--ink-muted);
  text-decoration: none;
}

.crumbs a:hover {
  color: var(--accent);
  text-decoration: underline;
}

.crumbs__sep { color: var(--rule); }

/* The current page is already the h1 below, so a long title is cut rather than allowed to
   wrap over two lines. The full string stays in the DOM, which is what the BreadcrumbList
   has to match. */
.crumbs__current {
  max-width: 18ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  color: var(--ink-soft);
}

@media (min-width: 46em) {
  .crumbs__current { max-width: 40ch; }
}

/* ---------- Search ---------- */

/* Lives inside .pagehead, so it inherits the gutter and the hairline below it. */
.search { margin-top: 1.125rem; }

.search__label {
  display: block;
  margin-bottom: 0.4375rem;
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.07em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.search__row {
  display: flex;
  max-width: 32rem;
  border: 1px solid var(--ink);
  background: var(--paper);
}

.search__row:focus-within {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.search__input {
  flex: 1;
  min-width: 0;
  border: 0;
  background: none;
  padding: 0.6875rem 0.75rem;
  font-family: var(--serif);
  font-size: var(--size-body);
  color: var(--ink);
}

/* The row already shows the focus ring, so a second one inside it would double up. */
.search__input:focus { outline: none; }

.search__input::placeholder { color: var(--ink-muted); }

/* Safari draws its own clear button in a colour that does not belong here. */
.search__input::-webkit-search-cancel-button { -webkit-appearance: none; }

.search__submit {
  flex: none;
  border: 0;
  border-left: 1px solid var(--ink);
  background: var(--ink);
  color: var(--paper);
  padding: 0 1rem;
  min-height: 44px;
  font-family: var(--mono);
  font-size: var(--mono-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}

.search__submit:hover { background: var(--ink-strong); }

.results__count {
  padding: 1rem var(--gutter) 0;
  font-family: var(--mono);
  font-size: var(--mono-3);
  color: var(--ink-muted);
}

.results__count strong {
  font-weight: 400;
  color: var(--ink);
}

/* Topics are a short, closed list, so they get rows rather than a cloud – there is room
   for the count to be spelled out, and a row is an easier target than a chip. */
.topiclist__items {
  display: flex;
  flex-direction: column;
}

.topiclist__items a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  min-height: 44px;
  padding: 0.6875rem var(--gutter);
  border-bottom: 1px solid var(--rule);
  text-decoration: none;
}

.topiclist__items li:first-child a { border-top: 1px solid var(--rule); }

.topiclist__items a:hover { background: var(--paper-alt); }

.topiclist__name {
  font-size: var(--size-brief);
  line-height: 1.2;
}

.topiclist__count {
  flex: none;
  font-family: var(--mono);
  font-size: var(--mono-3);
  color: var(--ink-muted);
}

.topiclist__items a:hover .topiclist__name { color: var(--accent); }

/* Bigger targets than the rail's tag cloud: on /tagi they are the page's only content. */
.taglist { padding: 1.25rem var(--gutter) 1.75rem; }

.tags--index { font-size: var(--mono-3); }

.tags--index a { padding: 0.4375rem 0.625rem; }

@media (min-width: 46em) {
  .results__count,
  .taglist { padding-inline: 0; }

  .topiclist__items a { padding-inline: 0; }
}

/* ---------- Error page ---------- */

/* Built on .lead, so the gutter, the hairline rule and the headline type all come from
   the feed. Only the mark, the receipt and the call to action are new here. */
.error { padding-bottom: 1.75rem; }

.error__mark {
  display: block;
  width: 3.25rem;
  height: 3.25rem;
  margin-bottom: 0.875rem;
  color: var(--ink);
}

/* A till receipt, the same object the brand mark draws. Mono throughout, because every
   number on this page is a joke and the register has to say so. */
.receipt {
  margin-top: 1.5rem;
  max-width: 25rem;
  border: 1px solid var(--ink);
  background: var(--paper-alt);
  padding: 0.9375rem 1.0625rem 1.0625rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
  line-height: 1.45;
  color: var(--ink-soft);
}

.receipt__head {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 0.25rem 1rem;
  padding-bottom: 0.75rem;
  border-bottom: 1px dashed var(--rule);
  font-size: var(--mono-2);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.receipt__lines {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.receipt__row {
  display: flex;
  align-items: baseline;
  gap: 0.5rem;
}

/* The dotted run between label and amount. Decorative, so it is aria-hidden in the
   markup and carries no text of its own. */
.receipt__leader {
  flex: 1;
  min-width: 1rem;
  border-bottom: 1px dotted var(--rule);
  transform: translateY(-0.25em);
}

.receipt__total {
  margin-top: 0.75rem;
  padding-top: 0.75rem;
  border-top: 1px dashed var(--rule);
  color: var(--ink);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.receipt__note {
  margin-top: 0.875rem;
  font-size: var(--mono-2);
  line-height: 1.5;
  color: var(--ink-muted);
}

.error__cta,
.path__cta {
  display: inline-block;
  font-family: var(--mono);
  font-size: var(--mono-3);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent);
  text-decoration: none;
}

.error__cta { margin-top: 1.5rem; }

.error__cta:hover,
.path__cta:hover { text-decoration: underline; }

@media (min-width: 46em) {
  .error__mark {
    width: 3.75rem;
    height: 3.75rem;
    margin-bottom: 1rem;
  }

  .receipt { margin-top: 1.75rem; }
}

/* ---------- Tags ---------- */

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
}

.tags a {
  display: inline-block;
  border: 1px solid var(--rule);
  padding: 0.25rem 0.4375rem;
  text-decoration: none;
}

.tags a:hover { border-color: var(--accent); }

.tags__count { color: var(--ink-muted); }

.tags--article {
  margin-top: 0.75rem;
  font-size: var(--mono-2);
}

.tags--article a {
  padding: 0.1875rem 0.375rem;
  color: var(--ink-muted);
}

@media (min-width: 46em) {
  .tags { gap: 0.375rem; }
  .tags a { padding: 0.25rem 0.5rem; }
  .tags--article { margin-top: 1rem; }
  .tags--article a { padding: 0.1875rem 0.4375rem; }
}

/* ---------- Rail ---------- */

.rail {
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
  padding-top: 1.375rem;
}

.rail > * { padding-inline: var(--gutter); }

.rail__heading,
.path__eyebrow {
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.rail__heading {
  margin-bottom: 0.625rem;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 0.4375rem;
}

.notes {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
}

/* A note the panel has no target for yet renders as a span rather than as href="#", so the
   page never ships a link that goes nowhere. Both elements carry .notes__link and read the
   same, because the difference is whether there is somewhere to go, not how it looks. */
.notes__link {
  display: block;
  text-decoration: none;
}

.notes__title {
  display: block;
  font-size: var(--size-note);
  line-height: 1.22;
  font-weight: 500;
}

.notes__meta {
  display: block;
  margin-top: 0.1875rem;
  font-family: var(--mono);
  font-size: var(--mono-1);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.path {
  border: 1px solid var(--ink);
  padding: 1.125rem;
}

.path__eyebrow { color: var(--ink-muted); }

.path__title {
  margin-top: 0.5rem;
  font-size: 1.3125rem;
  line-height: 1.2;
  font-weight: 400;
}

.path__meta {
  margin-top: 0.5rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
  color: var(--ink-muted);
}

/* Appearance is shared with .error__cta, in the Error page section above; only the
   spacing differs between the two. */
.path__cta { margin-top: 0.75rem; }

@media (min-width: 46em) {
  /* Tablet: the rail sits under the feed, its sections side by side. */
  .rail {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    gap: 2rem;
    align-items: start;
    border-top: 1px solid var(--rule);
    margin-top: 1.75rem;
    padding-top: 1.75rem;
  }

  .rail > * { padding-inline: 0; }
  .rail__heading { margin-bottom: 0.75rem; }
  .notes { gap: 0.875rem; }
}

@media (min-width: 66em) {
  .rail {
    display: flex;
    flex-direction: column;
    gap: 2rem;
    border-top: 0;
    border-left: 1px solid var(--rule);
    margin-top: 0;
    padding: 2rem 0 0 1.875rem;
  }

  .path { padding: 1.125rem; }
}

/* ---------- Footer ---------- */

.footer {
  margin: 1.625rem var(--gutter) 0;
  border-top: 3px double var(--ink);
  padding-block: 1.25rem 1.5rem;
}

.footer__top { display: grid; }

.footer__brand {
  font-size: var(--size-brand);
  letter-spacing: -0.01em;
}

.footer__text {
  margin-top: 0.5rem;
  font-size: var(--size-body);
  line-height: 1.55;
  color: var(--ink-soft);
}

.footer__nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem 1.25rem;
  margin-top: 1rem;
  font-family: var(--mono);
  font-size: var(--mono-3);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

/* Comfortable thumb targets on small screens – these were ~14px tall rows. */
.footer__nav a {
  display: flex;
  align-items: center;
  min-height: 2.5rem;
  text-decoration: none;
}

/* Same aria-current rule as the topic bar. */
.footer__nav a[aria-current] {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Mobile: copyright and "Na górę" share the first row with the link hard right, the
   cookie button sits underneath. A wrapping flex row stranded "Na górę" on the left. */
.footer__bottom {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 0.375rem 1.25rem;
  margin-top: 1.125rem;
  border-top: 1px solid var(--rule);
  padding-top: 0.75rem;
  font-family: var(--mono);
  font-size: var(--mono-2);
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}

.footer__bottom > p { grid-area: 1 / 1; }

.footer__bottom > a {
  grid-area: 1 / 2;
  display: inline-flex;
  align-items: center;
  justify-self: end;
  min-height: 2.75rem;
  text-decoration: none;
}

.footer__cookies { grid-area: 2 / 1 / 2 / -1; }

@media (min-width: 46em) {
  .footer {
    margin-top: 0;
    padding-block: 2rem 2.5rem;
  }

  .footer__text {
    margin-top: 0.625rem;
    max-width: 46ch;
    font-size: 1.0625rem;
    line-height: 1.6;
  }

  /* Still stacked, but the links read as one row instead of a 2×2 grid. */
  .footer__nav {
    display: flex;
    flex-wrap: wrap;
    gap: 1.75rem;
    margin-top: 1.25rem;
  }

  .footer__nav a { white-space: nowrap; }

  .footer__nav a { min-height: 0; display: inline; }

  .footer__bottom {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0.625rem 1.25rem;
    margin-top: 2rem;
    padding-top: 0.875rem;
    font-size: var(--mono-2);
  }

  .footer__bottom > a { min-height: 0; }
}

@media (min-width: 66em) {
  .footer__top {
    grid-template-columns: minmax(0, 46ch) 1fr;
    gap: 3.5rem;
    align-items: start;
  }

  .footer__nav {
    justify-content: flex-end;
    margin-top: 0;
  }
}

/* ---------- Cookie notice ---------- */

/* A small corner card, not a full-width bar: it has to be seen before the
   visitor scrolls, but it must not take over the page. Hidden in the markup and
   revealed by consent.js only when there is no stored choice, so crawlers and
   returning visitors never get it at all. */
.consent {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 60;
  width: 320px;
  max-height: calc(100svh - 40px);
  overflow-y: auto;
  border: 1px solid var(--ink);
  background: var(--paper);
  box-shadow: 0 20px 44px -20px rgba(27, 25, 23, 0.45);
  animation: consent-in 0.28s ease-out both;
}

.consent[hidden] { display: none; }

@keyframes consent-in {
  from { transform: translateY(12px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .consent { animation: none; }
}

/* Narrow phones: stretch between the edges instead of floating in a corner. */
@media (max-width: 30em) {
  .consent {
    right: 10px;
    bottom: 10px;
    left: 10px;
    width: auto;
  }
}

.consent__inner { padding: 1rem 1.125rem 1.125rem; }

.consent__eyebrow {
  font-family: var(--mono);
  font-size: var(--mono-1);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.consent__text {
  margin-top: 0.375rem;
  font-size: 0.9375rem;
  line-height: 1.45;
  color: var(--ink-strong);
}

.consent__actions {
  display: flex;
  gap: 0.375rem;
  margin-top: 0.875rem;
}

/* Typography lives on the button, not on the row – the save button sits in the
   details panel instead and would otherwise inherit the body serif. */
.btn {
  display: block;
  flex: 1;
  border: 1px solid var(--ink);
  background: transparent;
  padding: 0.5rem 0.375rem;
  font-family: var(--mono);
  font-size: 0.625rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink);
  text-align: center;
  cursor: pointer;
}

.btn:hover {
  border-color: var(--accent);
  color: var(--accent);
}

.btn--ghost {
  border-color: var(--rule);
  color: var(--ink-muted);
}

.btn--primary {
  background: var(--ink);
  color: var(--paper);
}

.btn--primary:hover {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--paper);
}

.btn--full {
  flex: none;
  width: 100%;
  margin-top: 0.875rem;
}

/* ----- Per-category panel ----- */

.consent__details {
  margin-top: 0.875rem;
  border-top: 1px solid var(--rule);
}

.consent__details[hidden] { display: none; }

.consent__cat {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: 0.75rem;
  padding: 0.6875rem 0;
  border-bottom: 1px solid var(--rule);
  cursor: pointer;
}

.consent__cat-name {
  display: block;
  font-size: 0.9375rem;
  line-height: 1.2;
}

.consent__cat-desc {
  display: block;
  margin-top: 0.125rem;
  font-family: var(--mono);
  font-size: var(--mono-1);
  line-height: 1.4;
  color: var(--ink-muted);
}

/* The real checkbox stays focusable but invisible; .consent__box is what you
   see – a letterpress square rather than a rounded switch. */
.consent__input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: 0;
  opacity: 0;
}

.consent__box {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 1rem;
  height: 1rem;
  margin-top: 0.125rem;
  margin-left: auto;
  border: 1px solid var(--ink);
  background: var(--paper);
}

.consent__box::after {
  content: '';
  width: 0.5rem;
  height: 0.25rem;
  border-left: 2px solid var(--ink);
  border-bottom: 2px solid var(--ink);
  transform: rotate(-45deg) translate(1px, -1px);
  opacity: 0;
}

.consent__input:checked + .consent__box::after { opacity: 1; }

.consent__input:focus-visible + .consent__box {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.consent__input:disabled + .consent__box {
  border-color: var(--rule);
  background: var(--paper-alt);
}

.consent__input:disabled + .consent__box::after { border-color: var(--ink-muted); }

.consent__cat:has(.consent__input:disabled) { cursor: default; }

/* ----- Footer trigger to change a choice already made ----- */

.footer__cookies {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  gap: 0.4375rem;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  color: inherit;
  cursor: pointer;
}

.footer__cookies:hover { color: var(--accent); }

.footer__cookies svg {
  display: block;
  overflow: visible;
}

/* Crumbs jump when the cookie is poked. */
.footer__cookies:hover .cookie-crumb,
.footer__cookies:focus-visible .cookie-crumb {
  animation: crumb-hop 0.5s ease-out;
}

@keyframes crumb-hop {
  50% { transform: translateY(-2px); }
}

@media (prefers-reduced-motion: reduce) {
  .footer__cookies:hover .cookie-crumb,
  .footer__cookies:focus-visible .cookie-crumb { animation: none; }
}

@media (min-width: 46em) {
  .page { padding: 2.5rem 2rem 5rem; }

  .paper {
    box-shadow: 0 1px 0 var(--rule), 0 18px 44px -28px rgba(27, 25, 23, 0.4);
  }

  /* Pointer precision makes the enlarged touch targets unnecessary here. */
  .footer__cookies { min-height: 0; }
}
