@layer reset, tokens, base, layout, components, ads, utils;

/* ==========================================================================
   TOKENS
   ========================================================================== */
@layer tokens {
  :root {
    /* Both schemes are declared so light-dark() has something to pick from.
       The toggle narrows this to one value on the root element. */
    color-scheme: light dark;

    /* Neutrals — very slightly warm, so white does not read as clinical */
    --bg:        light-dark(#FCFCFB, #0D100E);
    --surface:   light-dark(#FFFFFF, #141815);
    --surface-2: light-dark(#F4F5F2, #1B211D);
    --text:      light-dark(#14171A, #E9ECEA);
    --text-soft: light-dark(#3F464B, #C0C6C2);
    --muted:     light-dark(#6E767C, #8B938E);
    --border:    light-dark(#E6E7E5, #262C28);
    --border-str:light-dark(#D2D5D1, #333B36);

    /* Accent — botanical green, one hue, used sparingly */
    --accent:      light-dark(#1F6F43, #62D39B);
    --accent-soft: light-dark(#EAF4EE, #16241C);
    --accent-text: light-dark(#175334, #8FE4BB);

    /* Newsreader carries an optical-size axis, so the same family stays
       readable at 1rem in a sidebar and still has presence at 3rem on a
       headline. A display face such as Instrument Serif does not: its high
       contrast and tall, narrow letterforms fall apart at text sizes. */
    --font-display: 'Newsreader', Georgia, 'Times New Roman', serif;
    --font-body:    'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;

    /* Fluid scale. Each step interpolates between a phone and a wide desktop
       so nothing jumps at a breakpoint. */
    --step--1: clamp(0.82rem, 0.14vw + 0.79rem, 0.9rem);
    --step-0:  clamp(1rem, 0.2vw + 0.95rem, 1.125rem);
    --step-1:  clamp(1.18rem, 0.35vw + 1.1rem, 1.4rem);
    --step-2:  clamp(1.4rem, 0.7vw + 1.24rem, 1.85rem);
    --step-3:  clamp(1.7rem, 1.3vw + 1.4rem, 2.6rem);
    --step-4:  clamp(1.95rem, 1.9vw + 1.4rem, 3.05rem);
    /* One step down, for titles long enough that --step-4 would run to five
       or six lines. Applied from PHP, which is the only place the length of
       the string is known. */
    --step-4-long: clamp(1.75rem, 1.3vw + 1.35rem, 2.5rem);

    /* Article reading measure. In rem, not ch: ch resolves against the
       element's own font-size, which makes headings absurdly wide. */
    --measure: 40rem;
    --shell:   78rem;
    --gutter:  clamp(1rem, 3vw, 2rem);

    /* Every card image comes from si_wide at 800x420 */
    --img-ar: 40 / 21;

    --radius:    14px;
    --radius-sm: 9px;
    --radius-pill: 100px;

    --shadow: 0 1px 2px light-dark(rgba(20,30,24,.05), rgba(0,0,0,.4)),
              0 12px 32px light-dark(rgba(20,30,24,.07), rgba(0,0,0,.35));

    --nav-h: 66px;
    --ease:  cubic-bezier(.4, 0, .2, 1);
    --dur:   .2s;
  }

  :root[data-theme="light"] { color-scheme: light; }
  :root[data-theme="dark"]  { color-scheme: dark; }
}

/* ==========================================================================
   RESET
   ========================================================================== */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }

  * { margin: 0; }

  html {
    -webkit-text-size-adjust: 100%;
    scroll-behavior: smooth;
    scroll-padding-top: calc(var(--nav-h) + 1.5rem);
    /* Painted before body styles resolve; without it the new document flashes
       the UA default between navigations. */
    background: var(--bg);
  }

  body {
    min-height: 100svh;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font-body);
    font-size: var(--step-0);
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    text-rendering: optimizeLegibility;
    display: flex;
    flex-direction: column;
  }

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

  input, button, textarea, select { font: inherit; color: inherit; }
  button { background: none; border: 0; cursor: pointer; }

  a { color: inherit; text-decoration: none; }

  h1, h2, h3, h4 { text-wrap: balance; font-weight: 400; }
  p, li { text-wrap: pretty; }

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

  [hidden] { display: none !important; }

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

/* ==========================================================================
   BASE
   ========================================================================== */
@layer base {
  .shell {
    width: 100%;
    max-width: var(--shell);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }

  .main { flex: 1; padding-block: clamp(1.25rem, 3vw, 2.5rem); }

  .skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 1000;
    background: var(--accent);
    color: #fff;
    padding: .75rem 1.25rem;
    border-radius: 0 0 var(--radius-sm) 0;
  }
  .skip-link:focus { left: 0; }
}

/* ==========================================================================
   LAYOUT
   ========================================================================== */
@layer layout {
  /* Content plus sidebar. The sidebar is fixed-width so the ad units always
     have their 300px, and the article column takes what is left. */
  .layout {
    display: grid;
    gap: clamp(1.5rem, 4vw, 3rem);
    align-items: start;
  }

  @media (min-width: 62rem) {
    .layout {
      grid-template-columns: minmax(0, 1fr) 320px;
    }
  }

  .layout--narrow { grid-template-columns: minmax(0, 1fr); max-width: calc(var(--measure) + 8rem); }

  .layout__main { min-width: 0; }

  .sidebar {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    min-width: 0;
  }

  @media (min-width: 62rem) {
    .sidebar {
      position: sticky;
      top: calc(var(--nav-h) + 1rem);
    }
  }
}

/* ==========================================================================
   COMPONENTS
   ========================================================================== */
@layer components {

  /* ---------- Masthead ---------------------------------------------- */
  .masthead {
    position: sticky;
    top: 0;
    z-index: 100;
    background: light-dark(rgba(252,252,251,.82), rgba(13,16,14,.82));
    -webkit-backdrop-filter: saturate(180%) blur(14px);
    backdrop-filter: saturate(180%) blur(14px);
    border-bottom: 1px solid var(--border);
  }
  @supports not (backdrop-filter: blur(1px)) {
    .masthead { background: var(--bg); }
  }

  .masthead__inner {
    min-height: var(--nav-h);
    display: flex;
    align-items: center;
    gap: 1.5rem;
  }

  .brand {
    display: inline-flex;
    align-items: center;
    gap: .55rem;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.3rem;
    letter-spacing: -.01em;
    white-space: nowrap;
  }
  .brand svg { color: var(--accent); }
  .brand__name { line-height: 1; }

  /* ---------- Primary nav ------------------------------------------- */
  .nav { margin-inline-start: auto; }
  .nav > .nav__list,
  .nav__list {
    display: flex;
    align-items: center;
    gap: .15rem;
    list-style: none;
    padding: 0;
  }

  .nav__item { position: relative; }

  /* The chevron is appended inside the title span, so that span has to be the
     flex line — otherwise it wraps below the label and the pill turns oval. */
  .nav__item > a > span {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
  }

  .nav__item > a {
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    white-space: nowrap;
    padding: .5rem .8rem;
    border-radius: var(--radius-pill);
    font-size: var(--step--1);
    font-weight: 500;
    color: var(--text-soft);
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .nav__item > a:hover,
  .nav__item > a:focus-visible { background: var(--accent-soft); color: var(--accent-text); }

  .nav__item.current-menu-item > a,
  .nav__item.current-menu-parent > a { color: var(--text); background: var(--surface-2); }

  /* Submenu: a floating panel, opened on hover and on focus-within so
     keyboard users get the same behaviour without any script. */
  .nav .sub-menu {
    position: absolute;
    top: calc(100% + .35rem);
    inset-inline-start: 0;
    min-width: 12rem;
    padding: .35rem;
    margin: 0;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    box-shadow: var(--shadow);
    opacity: 0;
    visibility: hidden;
    transform: translateY(-4px);
    transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease), visibility var(--dur);
  }
  .nav__item--parent:hover > .sub-menu,
  .nav__item--parent:focus-within > .sub-menu {
    opacity: 1;
    visibility: visible;
    transform: none;
  }
  .nav .sub-menu a {
    display: block;
    padding: .5rem .7rem;
    border-radius: 6px;
    font-size: var(--step--1);
    color: var(--text-soft);
  }
  .nav .sub-menu a:hover { background: var(--accent-soft); color: var(--accent-text); }

  /* ---------- Header tools ------------------------------------------ */
  .masthead__tools { display: flex; align-items: center; gap: .25rem; }

  .iconbtn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 40px;
    height: 40px;
    border-radius: var(--radius-pill);
    color: var(--muted);
    transition: background var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .iconbtn:hover { background: var(--surface-2); color: var(--text); }

  .nav-toggle { display: inline-flex; }
  @media (min-width: 62rem) { .nav-toggle { display: none; } }
  @media (max-width: 61.999rem) { .masthead > .masthead__inner > .nav { display: none; } }

  /* Only one of the two theme glyphs is ever shown */
  :root[data-theme="dark"] .only-light,
  .only-dark { display: none; }
  :root[data-theme="dark"] .only-dark { display: inline-flex; }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .only-light { display: none; }
    :root:not([data-theme="light"]) .only-dark { display: inline-flex; }
  }

  /* ---------- Mobile nav -------------------------------------------- */
  .mobilenav {
    border-top: 1px solid var(--border);
    background: var(--bg);
    padding-block: .75rem 1.25rem;
  }
  .mobilenav .nav__list { flex-direction: column; align-items: stretch; gap: .1rem; }
  .mobilenav .nav__item > a {
    padding: .8rem .9rem;
    border-radius: var(--radius-sm);
    font-size: var(--step-0);
    justify-content: space-between;
  }
  .mobilenav .sub-menu {
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    box-shadow: none;
    border: 0;
    background: none;
    padding: 0 0 .35rem .9rem;
  }

  /* ---------- Language pills ---------------------------------------- */
  .langs { display: flex; gap: .3rem; list-style: none; padding: 0; }
  .langs a {
    display: inline-block;
    padding: .25rem .6rem;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--muted);
  }
  .langs a:hover { border-color: var(--accent); color: var(--accent-text); }
  .langs a[aria-current] { background: var(--accent-soft); color: var(--accent-text); border-color: transparent; }
  .langs--head { display: none; }
  @media (min-width: 48rem) { .langs--head { display: flex; } }
  .langs--post { margin-bottom: 1rem; }
  .langs--mobile { margin-top: 1rem; }

  /* ---------- Search modal ------------------------------------------ */
  /* A dialog is centred by the UA with margin:auto, which the `* { margin: 0 }`
     reset wipes out. Setting only margin-block left it pinned to the left edge,
     so the inline margins have to be restored explicitly. */
  .searchmodal {
    width: min(42rem, calc(100vw - 2rem));
    margin: 12vh auto auto;
    padding: 0;
    border: 1px solid var(--border-str);
    border-radius: var(--radius);
    background: var(--surface);
    box-shadow: 0 24px 60px light-dark(rgba(20,30,24,.18), rgba(0,0,0,.6));
    color: var(--text);
  }
  .searchmodal:not([open]) { display: none; }
  .searchmodal::backdrop {
    background: light-dark(rgba(20,26,22,.45), rgba(0,0,0,.62));
    -webkit-backdrop-filter: blur(8px);
    backdrop-filter: blur(8px);
  }
  .searchmodal__form {
    display: flex;
    align-items: center;
    gap: .85rem;
    padding: .5rem .75rem .5rem 1.15rem;
  }
  .searchmodal__form > svg { color: var(--muted); flex: none; }
  .searchmodal input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: none;
    padding: .9rem 0;
    font-size: var(--step-1);
    font-family: var(--font-body);
    outline: none;
  }
  .searchmodal input::placeholder { color: var(--muted); }
  .searchmodal .iconbtn { flex: none; }

  /* ---------- Reading progress -------------------------------------- */
  .progress {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
    height: 3px;
    z-index: 200;
    pointer-events: none;
  }
  .progress__bar {
    display: block;
    height: 100%;
    width: 100%;
    transform-origin: 0 50%;
    transform: scaleX(0);
    background: linear-gradient(90deg, var(--accent), light-dark(#3FA46B, #A7F0CA));
  }
  /* Scroll-driven where supported; silently absent where not. */
  @supports (animation-timeline: scroll()) {
    .progress__bar {
      animation: si-progress linear;
      animation-timeline: scroll(root block);
    }
  }
  @keyframes si-progress { to { transform: scaleX(1); } }

  /* ---------- Page heading ------------------------------------------ */
  .pagehead { margin-bottom: clamp(1.5rem, 3vw, 2.25rem); }
  .pagehead__title {
    font-family: var(--font-display);
    font-size: var(--step-3);
    line-height: 1.05;
    letter-spacing: -.02em;
  }
  .pagehead__sub { margin-top: .5rem; color: var(--muted); max-width: var(--measure); }

  /* ---------- Cards -------------------------------------------------- */
  /* The container is the list, not the card. An element cannot query the
     container it establishes itself: with container-type on .card, the rules
     below skipped .card (leaving it display:block) but still reached
     .card__media img, which lost its aspect-ratio. That mismatch is what made
     the thumbnails stretch. */
  .cards {
    container-type: inline-size;
    display: flex;
    flex-direction: column;
    gap: clamp(1rem, 2vw, 1.5rem);
  }

  .card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
  }
  .card:hover { border-color: var(--border-str); box-shadow: var(--shadow); transform: translateY(-2px); }

  .card__media { display: block; overflow: hidden; background: var(--surface-2); }
  .card__media img {
    width: 100%;
    aspect-ratio: var(--img-ar);
    object-fit: cover;
    transition: transform .5s var(--ease);
  }
  .card:hover .card__media img { transform: scale(1.03); }

  .card__body { padding: clamp(1rem, 2.5cqi, 1.4rem); display: flex; flex-direction: column; gap: .45rem; }

  .card__kicker {
    align-self: start;
    padding: .25rem .6rem;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--accent-text);
    transition: background var(--dur) var(--ease);
  }
  .card__kicker:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }

  /* Fixed at two lines. With a variable-height title the card height varies,
     and in the side-by-side layout the image is cropped to a different ratio
     on every row — which is what makes a listing look ragged. */
  .card__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--step-1);
    line-height: 1.28;
    letter-spacing: -.015em;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }
  .card__title a { transition: color var(--dur) var(--ease); }
  .card:hover .card__title a { color: var(--accent-text); }

  .card__excerpt {
    color: var(--muted);
    font-size: var(--step--1);
    line-height: 1.6;
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
  }

  .card__meta {
    display: flex;
    align-items: center;
    gap: .35rem;
    font-size: .78rem;
    color: var(--muted);
  }

  /* Side-by-side once the card itself is wide enough — a container query, so
     it responds to the column it sits in rather than the viewport. */
  @container (min-width: 34rem) {
    /* Side by side. The image sets the row height at its native ratio, so
       nothing is cropped and every card is exactly as tall as the one above.
       For that to hold the body has to fit inside that height, which is why
       the excerpt is dropped here — the lead card keeps it. */
    .card:not(.card--lead) {
      display: grid;
      grid-template-columns: minmax(14rem, 38%) minmax(0, 1fr);
    }
    .card:not(.card--lead) .card__media {
      aspect-ratio: var(--img-ar);
      height: auto;
    }
    .card:not(.card--lead) .card__media img {
      width: 100%;
      height: 100%;
      aspect-ratio: auto;
      object-fit: cover;
    }
    .card:not(.card--lead) .card__excerpt { display: none; }
    .card:not(.card--lead) .card__body { justify-content: center; gap: .55rem; }
    .card:not(.card--lead) .card__title { font-size: var(--step-1); }
  }

  .card--lead .card__title { font-size: var(--step-2); -webkit-line-clamp: 3; }
  .card--lead .card__excerpt { -webkit-line-clamp: 3; font-size: var(--step-0); }
  .card--lead .card__body { padding: clamp(1.2rem, 3cqi, 1.75rem); }

  /* ---------- Article ------------------------------------------------ */
  .post {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    padding: clamp(1.25rem, 4vw, 3.5rem);
  }

  .post__kickers {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .4rem;
    margin-bottom: 1rem;
  }
  .post__kickers a {
    padding: .3rem .7rem;
    border-radius: var(--radius-pill);
    background: var(--accent-soft);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: var(--accent-text);
    transition: background var(--dur) var(--ease);
  }
  .post__kickers a:hover { background: color-mix(in srgb, var(--accent) 22%, transparent); }
  .post__kickers .sep { display: none; }

  .post__title {
    font-family: var(--font-display);
    font-weight: 600;
    font-size: var(--step-4);
    /* 1.02 is fine for a two-line headline and unreadable at six. */
    line-height: 1.14;
    letter-spacing: -.02em;
    max-width: 26ch;
  }

  .post__title--long {
    font-size: var(--step-4-long);
    line-height: 1.16;
    max-width: 30ch;
  }

  .post__meta {
    display: flex;
    flex-wrap: wrap;
    gap: 1.25rem;
    margin-top: 1.25rem;
    padding-bottom: 1.75rem;
    border-bottom: 1px solid var(--border);
    font-size: var(--step--1);
    color: var(--muted);
  }
  .post__meta span { display: inline-flex; align-items: center; gap: .4rem; }

  /* ---------- Prose --------------------------------------------------
     Text is capped at the reading measure. Images, ad units and embeds are
     explicitly released back to full column width — that contrast is the
     whole point of the layout. */
  .prose { padding-top: 1.75rem; }

  .prose > * {
    max-width: var(--measure);
    margin-inline: auto;
  }

  .prose > p {
    font-size: var(--step-0);
    line-height: 1.78;
    color: var(--text-soft);
    margin-block: 0 1.4rem;
  }

  /* Opening paragraph sets the tone: larger, full-contrast */
  .prose > p:first-of-type {
    font-size: var(--step-1);
    line-height: 1.6;
    color: var(--text);
  }

  .prose > h2, .prose > h3, .prose > h4 {
    font-family: var(--font-display);
    letter-spacing: -.02em;
    line-height: 1.15;
    color: var(--text);
    margin-block: 2.75rem .75rem;
    scroll-margin-top: calc(var(--nav-h) + 1.5rem);
  }
  .prose > h2 { font-size: var(--step-2); }
  .prose > h3 { font-size: var(--step-1); }
  .prose > h4 {
    font-family: var(--font-body);
    font-size: var(--step-0);
    font-weight: 700;
    margin-block: 2rem .5rem;
  }

  .prose > ul, .prose > ol { padding-inline-start: 1.4rem; margin-block: 0 1.4rem; }
  .prose li { margin-bottom: .55rem; line-height: 1.7; color: var(--text-soft); }
  .prose li::marker { color: var(--accent); }

  .prose strong { color: var(--text); font-weight: 650; }

  .prose a {
    color: var(--accent-text);
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: 3px;
    text-decoration-color: color-mix(in srgb, var(--accent) 40%, transparent);
    transition: text-decoration-color var(--dur) var(--ease);
  }
  .prose a:hover { text-decoration-color: var(--accent); }

  .prose blockquote {
    border-inline-start: 2px solid var(--accent);
    padding-inline-start: 1.5rem;
    margin-block: 2rem;
    font-family: var(--font-display);
    font-size: var(--step-1);
    line-height: 1.4;
    color: var(--text);
  }

  /* Full-bleed inside the column */
  .prose > figure,
  .prose > img,
  .prose > .wp-block-image,
  .prose > .wp-block-embed,
  .prose > table {
    max-width: 100%;
    margin-block: 2rem;
  }

  /* Ad containers escape the reading measure entirely, and any descendant the
     ad script injects escapes with them. */
  .prose > .ad-slot,
  .prose > .ad-mgid,
  .prose > [id^="adngin-"],
  .prose > [data-type="_mgwidget"] {
    max-width: none;
    width: 100%;
    margin-block: 2rem;
  }

  .prose img { border-radius: var(--radius-sm); background: var(--surface-2); }

  .prose figcaption {
    margin-top: .6rem;
    font-size: var(--step--1);
    color: var(--muted);
    text-align: center;
  }

  .prose table { width: 100%; border-collapse: collapse; font-size: var(--step--1); }
  .prose th, .prose td { border: 1px solid var(--border); padding: .6rem .75rem; text-align: start; }
  .prose thead th { background: var(--surface-2); }

  .prose .wp-block-embed__wrapper { position: relative; }

  /* Scoped to embeds on purpose. A blanket `.prose iframe` rule also catches
     ad iframes, which are served at fixed sizes — forcing them to 100% width
     and 16:9 clipped the creative.
     Matching on the full host matters: `*="youtube"` would also hit an ad whose
     URL merely mentions it. youtube-nocookie is the domain WordPress uses when
     privacy-enhanced embeds are switched on.

     The host match alone is still not enough. Click-tracking URLs routinely
     carry their destination as a parameter, so an ad served from
     ads.example.com/serve?ref=youtube.com matches too — verified, it was being
     stretched to 16/9. Hence the explicit exclusion of anything inside an ad
     container. */
  .prose :is(.wp-block-embed, .wp-block-video, figure) iframe:not(.ad-slot *, .ad-mgid *),
  .prose iframe:is(
    [src*="youtube.com"],
    [src*="youtube-nocookie.com"],
    [src*="youtu.be"],
    [src*="vimeo.com"],
    [src*="dailymotion.com"]
  ):not(.ad-slot *, .ad-mgid *) {
    width: 100%;
    aspect-ratio: 16 / 9;
    height: auto;
    border: 0;
    border-radius: var(--radius-sm);
  }

  /* ---------- Share -------------------------------------------------- */
  .post__foot { margin-top: 3rem; padding-top: 2rem; border-top: 1px solid var(--border); }

  .share__prompt { font-size: var(--step--1); color: var(--muted); margin-bottom: .85rem; }

  .share { display: flex; flex-wrap: wrap; gap: .6rem; }

  .share__btn {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .65rem 1.1rem;
    border: 1px solid var(--border-str);
    border-radius: var(--radius-pill);
    font-size: var(--step--1);
    font-weight: 600;
    color: var(--text);
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .share__btn:hover { background: var(--text); border-color: var(--text); color: var(--bg); }
  .share__btn[data-copied] { background: var(--accent-soft); border-color: var(--accent); color: var(--accent-text); }

  /* ---------- Post + archive navigation ------------------------------ */
  .postnav, .pagination {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 2.5rem;
  }
  .postnav a, .pagination a {
    display: inline-flex;
    align-items: center;
    gap: .45rem;
    padding: .65rem 1.1rem;
    border: 1px solid var(--border-str);
    border-radius: var(--radius-pill);
    font-size: var(--step--1);
    font-weight: 600;
    transition: background var(--dur) var(--ease), border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .postnav a:hover, .pagination a:hover { background: var(--text); border-color: var(--text); color: var(--bg); }
  .postnav__item--next { margin-inline-start: auto; }

  /* ---------- Sidebar widgets ---------------------------------------- */
  .widget__title {
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 1rem;
  }

  /* Sidebar items stack: image full width at its native ratio, title beneath.
     A square thumbnail beside the title is more compact, but every image here
     is 40:21, so a square box throws away nearly half the frame — wide graphics
     in particular become unreadable. Stacking also hands the title the full
     column width, which is what lets it be set at a readable size. */
  .minicards { list-style: none; padding: 0; display: flex; flex-direction: column; gap: .6rem; }

  .minicard {
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--surface);
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
  }
  .minicard:hover { border-color: var(--border-str); box-shadow: var(--shadow); transform: translateY(-1px); }

  .minicard__link { display: block; }

  .minicard__media { display: block; overflow: hidden; background: var(--surface-2); }
  .minicard__media img {
    width: 100%;
    aspect-ratio: var(--img-ar);
    object-fit: cover;
    transition: transform .45s var(--ease);
  }
  .minicard:hover .minicard__media img { transform: scale(1.04); }

  /* Padding sits on the wrapper, never on the clamped element: with padding on
     the -webkit-box itself, the padding-bottom is inside the overflow box and a
     third line shows through it. */
  .minicard__text { display: block; padding: .6rem .75rem .7rem; }

  .minicard__title {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.02rem;
    line-height: 1.3;
    letter-spacing: -.01em;
    color: var(--text);
  }
  .minicard:hover .minicard__title { color: var(--accent-text); }

  /* The related-posts plugin emits its own markup and cannot be templated:
     li > a > img, then span > a > span for the title. Styled here to match the
     theme's own minicards, so the two are indistinguishable. */
  .sidebar .widget ul { list-style: none; padding: 0; margin: 0; }

  .sidebar .widget > ul:not(.minicards) {
    display: flex;
    flex-direction: column;
    gap: .6rem;
  }

  /* The plugin nests: li > a(img), then span > a > span(title). Given the same
     stacked treatment as .minicard above.
     :not(.minicards) matters — the theme's own list is also a <ul> inside a
     .widget, and without it these rules applied to both. */
  .sidebar .widget > ul:not(.minicards) > li {
    display: block;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    background: var(--surface);
    transition: border-color var(--dur) var(--ease), box-shadow var(--dur) var(--ease), transform var(--dur) var(--ease);
  }
  .sidebar .widget > ul:not(.minicards) > li:hover {
    border-color: var(--border-str);
    box-shadow: var(--shadow);
    transform: translateY(-1px);
  }

  .sidebar .widget > ul:not(.minicards) > li > a:first-child {
    display: block;
    overflow: hidden;
    background: var(--surface-2);
  }
  .sidebar .widget > ul:not(.minicards) > li > a:first-child img {
    display: block;
    width: 100%;
    aspect-ratio: var(--img-ar);
    object-fit: cover;
    border-radius: 0;
    transition: transform .45s var(--ease);
  }
  .sidebar .widget > ul:not(.minicards) > li:hover > a:first-child img { transform: scale(1.04); }

  .sidebar .widget > ul:not(.minicards) > li > span { display: block; min-width: 0; }
  /* Plugin markup is span > a > span: padding on the anchor, clamp on the
     inner span, for the same reason as .minicard__text above. */
  .sidebar .widget > ul:not(.minicards) > li > span a {
    display: block;
    padding: .6rem .75rem .7rem;
    color: var(--text);
  }
  .sidebar .widget > ul:not(.minicards) > li > span a > span {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    font-family: var(--font-display);
    font-weight: 600;
    font-size: 1.02rem;
    line-height: 1.3;
    letter-spacing: -.01em;
  }
  .sidebar .widget > ul:not(.minicards) > li:hover > span a { color: var(--accent-text); }

  .sidebar .widget h2.title,
  .sidebar .widget .widget__title {
    font-family: var(--font-body);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--muted);
    margin-bottom: 1rem;
  }

  /* The widget itself arrives wrapped in an <li>; strip that list styling. */
  .sidebar > .widget,
  .sidebar li.widget { list-style: none; display: block; }

  /* ---------- Search form, empty state, 404 --------------------------- */
  .searchform {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .35rem .35rem .35rem .9rem;
    border: 1px solid var(--border-str);
    border-radius: var(--radius-pill);
    background: var(--surface);
    max-width: 26rem;
  }
  .searchform > svg { color: var(--muted); flex: none; }
  .searchform input { flex: 1; min-width: 0; border: 0; background: none; outline: none; padding: .5rem 0; }
  .searchform button {
    padding: .5rem 1.1rem;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    font-size: var(--step--1);
    font-weight: 600;
  }

  .empty, .notfound {
    text-align: center;
    padding: clamp(2.5rem, 8vw, 5rem) 1rem;
    display: grid;
    gap: 1rem;
    justify-items: center;
  }
  .notfound svg { color: var(--accent); opacity: .5; }
  .notfound h1, .empty h2 { font-family: var(--font-display); font-size: var(--step-3); letter-spacing: -.02em; }
  .notfound p, .empty p { color: var(--muted); max-width: 40ch; }

  .btn {
    display: inline-flex;
    align-items: center;
    gap: .5rem;
    padding: .7rem 1.4rem;
    border-radius: var(--radius-pill);
    background: var(--accent);
    color: #fff;
    font-weight: 600;
    font-size: var(--step--1);
  }
  .btn:hover { filter: brightness(1.08); }

  /* ---------- Back to top -------------------------------------------- */
  .totop {
    position: fixed;
    inset-block-end: 1.25rem;
    inset-inline-end: 1.25rem;
    z-index: 90;
    width: 44px;
    height: 44px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: var(--radius-pill);
    border: 1px solid var(--border);
    background: light-dark(rgba(255,255,255,.85), rgba(20,24,21,.85));
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
    color: var(--text);
    box-shadow: var(--shadow);
    transition: transform var(--dur) var(--ease), background var(--dur) var(--ease);
  }
  .totop:hover { transform: translateY(-2px); background: var(--text); color: var(--bg); }

  /* ---------- Footer -------------------------------------------------- */
  .siteftr {
    margin-top: clamp(3rem, 8vw, 6rem);
    border-top: 1px solid var(--border);
    background: var(--surface);
    padding-block: clamp(2rem, 5vw, 3.5rem);
  }
  .siteftr__inner { display: grid; gap: 1.5rem; justify-items: center; text-align: center; }
  .brand--footer { font-size: 1.15rem; }

  .footernav__list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: .25rem 1.5rem;
    list-style: none;
    padding: 0;
  }
  .footernav a { font-size: var(--step--1); color: var(--muted); }
  .footernav a:hover { color: var(--accent-text); }

  .siteftr__social a {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    border: 1px solid var(--border);
    border-radius: var(--radius-pill);
    color: var(--muted);
    transition: border-color var(--dur) var(--ease), color var(--dur) var(--ease);
  }
  .siteftr__social a:hover { border-color: var(--accent); color: var(--accent-text); }

  .siteftr__legal { font-size: var(--step--1); color: var(--muted); }
}

/* ==========================================================================
   ADS
   Creatives are authored for white backgrounds. In dark mode they are placed
   on a light plate so they read as a deliberate frame rather than as bright
   rectangles punched through the page.
   ========================================================================== */
@layer ads {
  /* Hands off whatever the ad server injects.
     Creatives arrive at fixed dimensions and are laid out by the ad script.
     Any theme rule that resizes them — a width, an aspect-ratio, a radius
     inherited from a generic img or iframe rule — clips or distorts the ad and
     costs revenue. These resets are deliberately broad for that reason. */
  .ad-slot iframe, .ad-mgid iframe,
  .ad-slot img,    .ad-mgid img,
  .ad-slot video,  .ad-mgid video,
  .ad-slot ins,    .ad-mgid ins {
    /* Only undo what the theme would otherwise impose. Nothing is asserted
       here: setting width/height to auto looks harmless but overrides the
       width and height attributes on an ad iframe, dropping it to the CSS
       default of 300x150 and squashing the creative. max-width is the one
       exception, and only so a wide unit cannot force a horizontal scrollbar. */
    max-width: 100%;
    border-radius: 0;
    background: none;
  }

  /* The ad script sizes its own containers; do not constrain them. */
  .ad-slot > div, .ad-mgid > div {
    max-width: 100%;
  }

  .ad-slot, .ad-mgid {
    margin-block: clamp(1.25rem, 3vw, 2rem);
    text-align: center;
  }
  .ad-slot:empty, .ad-mgid:empty { margin: 0; }

  .ad-slot > div { margin-inline: auto; }

  .ad-slot--leaderboard { min-height: 90px; margin-block-start: 0; }
  @media (max-width: 48rem) { .ad-slot--leaderboard { min-height: 100px; } }

  .ad-stack { display: flex; flex-direction: column; gap: 1.25rem; }
  .ad-slot--rail { min-width: 300px; margin: 0; }

  /* The two fixed rails. No room for them below a wide desktop. */
  .ad-rail { position: fixed; top: calc(var(--nav-h) + 12px); z-index: 50; }
  .ad-rail--left  { inset-inline-start: 10px; }
  .ad-rail--right { inset-inline-end: 10px; }
  @media (max-width: 80rem) {
    .ad-rail { display: none; }
  }

  /* Creatives are drawn for white backgrounds, so in dark mode they sit on a
     light plate. It shrink-wraps the ad rather than spanning the column —
     a full-width panel around a 300px creative reads as a mistake. */
  :root[data-theme="dark"] .ad-slot:not(:empty),
  :root[data-theme="dark"] .ad-mgid:not(:empty),
  :root:not([data-theme="light"]) .ad-slot:not(:empty),
  :root:not([data-theme="light"]) .ad-mgid:not(:empty) {
    background: none;
    padding: 0;
  }

  :root[data-theme="dark"] .ad-slot:not(:empty) > div:not(:empty),
  :root[data-theme="dark"] .ad-mgid:not(:empty) {
    background: #F7F7F5;
    border-radius: var(--radius-sm);
    padding: .4rem;
    width: fit-content;
    max-width: 100%;
    margin-inline: auto;
  }

  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) .ad-slot:not(:empty) > div:not(:empty),
    :root:not([data-theme="light"]) .ad-mgid:not(:empty) {
      background: #F7F7F5;
      border-radius: var(--radius-sm);
      padding: .4rem;
      width: fit-content;
      max-width: 100%;
      margin-inline: auto;
    }
  }
}

/* ==========================================================================
   UTILITIES
   ========================================================================== */
@layer utils {
  .u-visually-hidden {
    position: absolute;
    width: 1px; height: 1px;
    padding: 0; margin: -1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  @media (max-width: 30rem) {
    .u-hide-sm { display: none; }
  }
}

/* ==========================================================================
   NAVIGATION FEEDBACK

   Cross-document view transitions were tried here and removed. They freeze a
   snapshot of the outgoing page and fade it out, but any progress indicator
   lives in the incoming document, which has not rendered yet — so on exactly
   the slow navigation where feedback matters, the screen just sat dimmed with
   nothing on it.

   This runs in the outgoing document instead: a top bar that keeps creeping
   forward, plus a spinner once the wait is long enough to feel like one.
   ========================================================================== */
@layer components {
  /* The whole overlay is present as soon as a navigation starts, but its parts
     arrive in stages. Most pages here are served from cache and land in a
     couple of hundred milliseconds; holding everything back behind a delay
     meant the feedback never appeared at all. So the bar shows at once — it is
     three pixels and costs nothing on a fast load — while the veil and spinner
     wait until the delay is long enough to be worth explaining. */
  .loader {
    position: fixed;
    inset: 0;
    z-index: 300;
    pointer-events: none;
    visibility: hidden;
  }
  .loader[data-active] { visibility: visible; }

  /* A light veil, not a blackout: the page stays legible underneath. */
  .loader__veil {
    position: absolute;
    inset: 0;
    background: light-dark(rgba(252,252,251,.5), rgba(13,16,14,.5));
    -webkit-backdrop-filter: blur(1.5px);
    backdrop-filter: blur(1.5px);
    opacity: 0;
    transition: opacity .25s var(--ease);
  }
  .loader[data-active] .loader__veil {
    opacity: 1;
    transition-delay: .35s;
  }

  .loader__bar {
    position: absolute;
    inset-block-start: 0;
    inset-inline: 0;
    height: 3px;
    overflow: hidden;
    opacity: 0;
    transition: opacity .12s var(--ease);
  }
  .loader[data-active] .loader__bar { opacity: 1; }
  .loader__bar::after {
    content: '';
    display: block;
    height: 100%;
    width: 100%;
    transform-origin: 0 50%;
    transform: scaleX(0);
    background: linear-gradient(90deg, var(--accent), light-dark(#3FA46B, #A7F0CA));
  }
  /* Eases toward the end without arriving; the page load is what finishes it. */
  .loader[data-active] .loader__bar::after {
    animation: si-loader 12s cubic-bezier(.05,.7,.1,1) forwards;
  }
  @keyframes si-loader {
    0%   { transform: scaleX(0); }
    30%  { transform: scaleX(.62); }
    100% { transform: scaleX(.97); }
  }

  /* Appears only once the wait is long enough to read as a wait. */
  .loader__spinner {
    position: absolute;
    inset-block-start: 50%;
    inset-inline-start: 50%;
    translate: -50% -50%;
    width: 34px;
    height: 34px;
    border-radius: 50%;
    border: 2.5px solid color-mix(in srgb, var(--accent) 25%, transparent);
    border-top-color: var(--accent);
    opacity: 0;
  }
  .loader[data-active] .loader__spinner {
    animation: si-spin .7s linear infinite, si-spinner-in .2s ease .7s forwards;
  }
  @keyframes si-spin { to { rotate: 360deg; } }
  @keyframes si-spinner-in { to { opacity: 1; } }

  @media (prefers-reduced-motion: reduce) {
    .loader[data-active] .loader__bar::after { animation: none; transform: scaleX(.5); }
    .loader[data-active] .loader__spinner { animation: si-spinner-in .2s ease .55s forwards; }
  }
}
