/* =====================================================================================
   Растителна Защита -- public site design system.

   Ported from the Claude Design mock "Растителна Защита.dc.html". That file expresses the
   whole design as inline styles on a single component, including ~20 `style-hover` states
   that have no HTML equivalent; everything here is the class-based translation of it.

   Served from the jar at /site-assets/, NOT /assets/ -- see WebSiteAssetsConfiguration.

   This stylesheet REPLACES the volume-side stack (bootstrap.min.css, styles.min.css,
   video.min.css, fontawesome, ionicons) on the templates that load it. Two consequences:

     * .video-container is defined here. widgets.html and article.html inject raw YouTube
       iframes into it; video.min.css used to make them responsive and no longer runs.
     * .article-body carries guards for 2,269 archived bodies full of <font>, inline widths,
       <style> blocks and tables. Bootstrap's img-fluid is gone, so without them a legacy
       body blows the measure out horizontally. A freshly seeded article will not show this.

   Icons are inline SVG or plain characters -- no icon font is loaded.
   ===================================================================================== */

/* ---------- tokens ------------------------------------------------------------------ */

:root {
    --bg: #F4F0E6;
    --surface: #FBF9F3;
    --line: #DED7C6;
    --ink: #1E1C17;
    --ink2: #26241E;
    --muted: #4A4536;
    --muted2: #6B6455;
    --faint: #8A8271;
    --green: #2C4A32;
    --greenDark: #243D29;
    --greenText: #2C4A32;
    --rust: #9A5433;
    --ph1: #EAE4D4;
    --ph2: #F2EDE0;
    --tint: #EDF1E7;
    --hover: #EFEADC;
    --panel: #1E1C17;
    --onPanel: #F4F0E6;
    --onPanelMuted: #CFC8B6;
    --onPanelFaint: #9E9686;
    --onPanelLine: #4A463C;
    --panelAccent: #A8C39A;

    --serif: 'Lora', Georgia, 'Times New Roman', serif;
    --sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;
    --mono: 'IBM Plex Mono', ui-monospace, 'SF Mono', Menlo, monospace;

    /* The mock sets its label system at 9-11px. Uppercase Cyrillic at 9px is not legible on
       a real screen, so the floor is raised here and the scale keeps the same rhythm. */
    --mono-xs: 11px;
    --mono-sm: 12px;

    --shell: 1280px;
    --gutter: 32px;

    color-scheme: light;
}

.night {
    --bg: #12110B;
    --surface: #1B1913;
    --line: #332F26;
    --ink: #EFEADB;
    --ink2: #E3DDCC;
    --muted: #C0B9A5;
    --muted2: #9C9583;
    --faint: #7F7867;
    --green: #26382A;
    --greenDark: #33503A;
    --greenText: #93BE8B;
    --rust: #CE9061;
    --ph1: #211F19;
    --ph2: #27241E;
    --tint: #1A2118;
    --hover: #25231C;
    --panel: #0C0B06;

    color-scheme: dark;
}

/* ---------- reset ------------------------------------------------------------------- */

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

html, body {
    margin: 0;
    padding: 0;
    background: var(--bg);
}

body {
    color: var(--ink);
    font-family: var(--sans);
    font-size: 16px;
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    min-height: 100vh;
}

a { color: var(--greenText); text-decoration: none; }
a:hover { color: var(--rust); }

img { max-width: 100%; }

button { font: inherit; cursor: pointer; }
input, select, textarea { font: inherit; }

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

::selection { background: #DCE4D3; }
.night ::selection { background: #33503A; }

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

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

/* ---------- shell ------------------------------------------------------------------- */

.shell {
    max-width: var(--shell);
    margin: 0 auto;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
}

.layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 320px;
    gap: 40px;
    align-items: start;
    padding-top: 26px;
    margin-bottom: 1rem;
}

.layout__main { min-width: 0; }

.layout__aside {
    display: flex;
    flex-direction: column;
    gap: 20px;
}

/* ---------- masthead ---------------------------------------------------------------- */

.site-header {
    background: var(--surface);
    border-bottom: 1px solid var(--line);
}

.masthead {
    display: flex;
    align-items: center;
    gap: 24px;
    padding-top: 18px;
    padding-bottom: 18px;
}

/* The logo now ships in two inks -- head.svg (dark green wordmark) for this cream masthead and
   head-dark.svg (white wordmark) for night mode -- so the green plate that head.png needed is
   gone rather than commented out, and so is the hover plate: --greenDark behind the dark-green
   wordmark leaves it very nearly invisible, verified by rendering it. The link still reads as
   interactive through the wordmark's own hover opacity below.

   Both assets live on the web-content volume, outside this repo. */
.masthead__logo {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    padding: 10px 18px;
}

.masthead__logo:hover img { opacity: .78; }

.masthead__logo img {
    display: block;
    /* The asset is a 335x55 viewBox whose top 38 units are the Cyrillic wordmark and whose
       bottom 13 are the PLANT PROTECTION line, so the wordmark renders at height * 38/55 and
       the box is always taller than the name inside it. 66.6px is what puts the Cyrillic back
       at the 46px head.png drew it at -- the number to hold constant is 46, so if the artwork
       is ever re-cut to different proportions this has to be recomputed, not carried over. */
    height: 66.6px;
    width: auto;
}

/* Night mode is a class on <html>, so this is a display swap rather than a media query.
   display:none and not visibility/opacity: both images are in the DOM, and anything that
   leaves the inactive one in flow adds its full ~280px to the masthead.

   Each selector names the parent as well as the image, and that is load-bearing rather than
   decorative: `.masthead__logo img` above is (0,1,1) and a bare `.masthead__logo-dark` is
   (0,1,0), so display:block wins on specificity whatever the source order and BOTH logos
   render side by side. Verified -- it is what the first draft of this did. Keep two classes
   in every selector here. */
.masthead__logo .masthead__logo-dark { display: none; }
html.night .masthead__logo .masthead__logo-light { display: none; }
html.night .masthead__logo .masthead__logo-dark { display: block; }

.masthead__side {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 8px;
    align-items: flex-end;
}

.masthead__tagline {
    font: 400 var(--mono-xs)/1.3 var(--mono);
    letter-spacing: .09em;
    color: var(--faint);
    text-transform: uppercase;
    text-align: right;
}

.masthead__tools {
    display: flex;
    align-items: center;
    gap: 8px;
    justify-content: flex-end;
    width: 100%;
}

.site-search {
    flex: 1 1 140px;
    min-width: 0;
    max-width: 360px;
    display: flex;
    align-items: center;
    gap: 8px;
    border: 1px solid var(--line);
    background: var(--bg);
    padding: 9px 12px;
}

.site-search__icon { color: var(--faint); font-size: 13px; line-height: 1; }

.site-search__input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: transparent;
    outline: none;
    font-size: 13px;
    color: var(--ink);
}

.site-search__input::placeholder { color: var(--faint); }

.tool-button,
.lang-select {
    flex-shrink: 0;
    height: 36px;
    background: var(--bg);
    color: var(--muted);
    border: 1px solid var(--line);
    padding: 0 10px;
    font: 400 var(--mono-sm)/1 var(--mono);
    display: flex;
    align-items: center;
    justify-content: center;
}

.tool-button { width: 36px; padding: 0; font-size: 15px; }

.tool-button:hover,
.lang-select:hover {
    border-color: var(--greenText);
    color: var(--greenText);
}

/* The language menu is a real menu, not a <select>: each entry has to carry data-lang for
   the volume-side lang.js to pick up. */
.lang-menu { position: relative; flex-shrink: 0; }

.lang-menu__list {
    position: absolute;
    top: 100%;
    right: 0;
    z-index: 80;
    display: none;
    width: 190px;
    max-height: 360px;
    overflow-y: auto;
    background: var(--surface);
    border: 1px solid var(--line);
    box-shadow: 0 14px 32px rgba(30, 28, 23, .16);
}

.lang-menu:hover .lang-menu__list,
.lang-menu:focus-within .lang-menu__list { display: block; }

.lang-menu__item {
    display: block;
    padding: 8px 14px;
    font: 400 13px/1.35 var(--sans);
    color: var(--muted);
}

.lang-menu__item:hover { background: var(--hover); color: var(--rust); }

/* ---------- navigation -------------------------------------------------------------- */

.site-nav {
    border-top: 1px solid var(--line);
    background: var(--green);
    position: relative;
    z-index: 50;
}

.site-nav__inner {
    display: flex;
    align-items: stretch;
}

/* display:contents so the nav items are direct flex children of .site-nav__inner on desktop
   while still having a wrapper the mobile breakpoint can hide as one unit. */
.site-nav__items { display: contents; }

.nav-toggle {
    display: none;
    background: transparent;
    border: 0;
    padding: 14px 20px;
    color: var(--onPanel);
    font: 500 14px/1 var(--sans);
}

.nav-item { position: relative; display: flex; }

.nav-item__label {
    display: flex;
    align-items: center;
    background: transparent;
    border: 0;
    padding: 14px 20px;
    font: 500 14px/1 var(--sans);
    color: var(--onPanel);
    letter-spacing: .01em;
    white-space: nowrap;
}

.nav-item__label:hover { color: var(--onPanel); }

.nav-item:hover > .nav-item__label,
.nav-item:focus-within > .nav-item__label { background: var(--greenDark); }

/* Hover/focus driven, so no JavaScript is involved on the desktop breakpoint. */
.nav-menu {
    position: absolute;
    top: 100%;
    left: 0;
    display: none;
    grid-template-columns: repeat(var(--cols, 1), minmax(170px, auto));
    gap: 2px 26px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-top: 0;
    box-shadow: 0 14px 32px rgba(30, 28, 23, .16);
    padding: 18px 22px;
    z-index: 60;
}

.nav-item:hover > .nav-menu,
.nav-item:focus-within > .nav-menu { display: grid; }

.nav-menu__link {
    padding: 7px 0;
    font: 400 13px/1.35 var(--sans);
    color: var(--muted);
    white-space: nowrap;
}

.nav-menu__link:hover { color: var(--rust); }

.nav-spacer { flex: 1; }

/* ---------- section headings -------------------------------------------------------- */

.section-head {
    display: flex;
    align-items: baseline;
    gap: 12px;
    flex-wrap: wrap;
    border-bottom: 2px solid var(--ink);
    padding-bottom: 8px;
    margin-bottom: 22px;
}

.section-head__title {
    font: 600 15px/1 var(--sans);
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink);
}

.section-head__link {
    margin-left: auto;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .06em;
    color: var(--greenText);
    text-transform: uppercase;
}

.section-head__link:hover { color: var(--rust); }

.section { padding-top: 48px; }

/* Closes a block that is not a .section of its own -- the cards under the hero, which are
   the same category read as the hero and share its heading. */
.section-rule { padding-bottom: 30px; border-bottom: 1px solid var(--line); }

/* Bare, centred column: the printable article view has no shell around it. */
.page-narrow { max-width: 820px; padding-top: 40px; padding-bottom: 60px; }
.measure-full { max-width: none; }

/* ---------- advertising ------------------------------------------------------------- */

/*
 * THE CLASS NAMES ARE `partner-card` / `partner-row` AND MUST NOT GO BACK TO `ad-box` / `ad-row`.
 *
 * They were exactly that, and every reader running a blocker saw nothing. EasyList -- the default
 * list in uBlock Origin, AdBlock Plus, AdGuard and Brave Shields -- carries two GENERIC cosmetic
 * filters, `##` meaning every domain, no site-specific rule required:
 *
 *     ##.ad-box:not(#ad-banner):not(:empty)
 *     ##.ad-row
 *
 * Both matched this file verbatim, so every box on every page was hidden with
 * `display: none !important` from an injected stylesheet. The failure is invisible from the
 * server: the markup renders, all eight bookings resolve, every creative returns 200, and curl
 * sees a page that is completely correct. It is also invisible to the render tests, which assert
 * on the emitted HTML -- the same blind spot `make smoke` prints a Location header to avoid.
 *
 * Before renaming these for any reason, grep the current easylist.txt for the replacement. The
 * paths are a separate question and were checked: no network rule matches /resources/banners/,
 * /assets/img/ads/ or /b/{id}, and those three cannot be renamed anyway -- Banner.source stores
 * whole public paths in MongoDB and nginx routes on the prefixes.
 *
 * This is a treadmill, not a cure: EasyList adds site-specific rules once a publisher renames.
 * The «РЕКЛАМА» label stays regardless -- disclosing an ad is not the thing that was breaking.
 */

/*
 * The number of leaderboard bookings is data, not markup, so the columns cannot be a fixed
 * `1fr 1fr` any more: one booking would leave half the row empty and three would wrap into a
 * ragged second line. `grid-auto-flow: column` gives exactly as many equal columns as there are
 * boxes. minmax(0, 1fr) rather than 1fr because a grid item's default min-width is `auto`, which
 * an iframe's intrinsic width would push the track past.
 */
.partner-row {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: minmax(0, 1fr);
    gap: 18px;
    padding-top: 18px;
}

.partner-card {
    border: 1px solid var(--line);
    background: var(--surface);
    padding: 9px;
}

.partner-card__label {
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .14em;
    color: var(--faint);
    margin-bottom: 8px;
}

.partner-card__frame {
    position: relative;
    display: block;
    width: 100%;
    overflow: hidden;
}

.partner-card__frame iframe {
    display: block;
    width: 100%;
    height: 100%;
    border: 0;
}

.partner-card__frame img { display: block; width: 100%; height: auto; }

/* Optional line of copy under an image creative. Muted so it reads as part of the ad box rather
   than as editorial text next to it. */
.partner-card__caption {
    margin-top: 8px;
    font-size: 13px;
    line-height: 1.45;
    color: var(--muted);
}

.partner-card__frame--top { height: 90px; }
.partner-card__frame--square { height: 250px; }
.partner-card__frame--tall { height: 600px; }
.partner-card__frame--auto { height: auto; }

/* ---------- hero -------------------------------------------------------------------- */

.lead { display: block; margin-bottom: 34px; }

.lead__media {
    display: block;
    position: relative;
    border: 1px solid var(--line);
    background: repeating-linear-gradient(135deg, var(--ph1) 0 8px, var(--ph2) 8px 16px);
    overflow: hidden;
}

.lead__media img {
    display: block;
    width: 100%;
    height: auto;
}

.lead__meta {
    display: flex;
    align-items: center;
    gap: 10px;
    flex-wrap: wrap;
    margin: 16px 0 10px;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .08em;
}

.kicker {
    background: var(--green);
    color: var(--onPanel);
    padding: 4px 7px;
    text-transform: uppercase;
}

a.kicker:hover { background: var(--greenDark); color: var(--onPanel); }

.meta-note { color: var(--faint); }

.lead__title {
    font: 600 38px/1.15 var(--serif);
    letter-spacing: -.01em;
    text-wrap: pretty;
    max-width: 24ch;
    color: var(--ink);
}

.lead__title a { color: inherit; }
.lead__title a:hover { color: var(--rust); }

.lead__dek {
    margin-top: 14px;
    font: 400 17px/1.6 var(--serif);
    color: var(--muted);
    max-width: 62ch;
    text-wrap: pretty;
}

/* ---------- cards ------------------------------------------------------------------- */

.card-grid {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 28px;
}

.card-grid--four { grid-template-columns: repeat(4, minmax(0, 1fr)); }

.card { display: flex; flex-direction: column; min-width: 0; }

.card__media {
    display: block;
    border: 1px solid var(--line);
    background: repeating-linear-gradient(135deg, var(--ph1) 0 8px, var(--ph2) 8px 16px);
    overflow: hidden;
}

.card__media img { display: block; width: 100%; height: auto; }

.card__meta {
    display: flex;
    gap: 9px;
    flex-wrap: wrap;
    margin: 12px 0 8px;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .08em;
    color: var(--rust);
}

.card__title {
    font: 600 20px/1.22 var(--serif);
    text-wrap: pretty;
    color: var(--ink);
}

.card__title a { color: inherit; }
.card__title a:hover { color: var(--rust); }

.card__byline {
    margin-top: 8px;
    font: 400 13px/1.55 var(--sans);
    color: var(--muted2);
}

.card__title--compact { font-size: 16px; line-height: 1.28; }

/* ---------- list rows --------------------------------------------------------------- */

.list-row {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr);
    gap: 22px;
    align-items: start;
    padding: 20px 0;
    border-bottom: 1px solid var(--line);
    transition: background-color .12s ease;
}

.list-row:hover { background: var(--hover); }

.list-row__thumb {
    display: block;
    border: 1px solid var(--line);
    background: repeating-linear-gradient(135deg, var(--ph1) 0 8px, var(--ph2) 8px 16px);
    overflow: hidden;
}

.list-row__thumb img { display: block; width: 100%; height: auto; }

/* The placeholder an imageless article gets, so the text column does not jump. */
.list-row__thumb--empty { aspect-ratio: 4 / 3; }

.list-row__body { display: flex; flex-direction: column; gap: 8px; min-width: 0; }

.list-row__meta {
    font: 400 var(--mono-xs)/1.5 var(--mono);
    letter-spacing: .08em;
    color: var(--rust);
}

.list-row__title { font: 600 23px/1.22 var(--serif); color: var(--ink); text-wrap: pretty; }
.list-row__title a { color: inherit; }
.list-row__title a:hover { color: var(--rust); }

.list-row__author { font: 400 12px/1.5 var(--sans); color: var(--muted2); }

/* ---------- stacked widget lists (verticals, most read) ----------------------------- */

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

.stack__item {
    display: flex;
    flex-direction: column;
    gap: 7px;
    padding: 14px 0;
    border-bottom: 1px solid var(--line);
}

.stack__item:first-child { padding-top: 0; }

.stack__media {
    display: block;
    border: 1px solid var(--line);
    background: repeating-linear-gradient(135deg, var(--ph1) 0 8px, var(--ph2) 8px 16px);
    overflow: hidden;
    margin-bottom: 4px;
}

.stack__media img { display: block; width: 100%; height: auto; }

.stack__title { font: 600 17px/1.28 var(--serif); color: var(--ink); text-wrap: pretty; }
.stack__title a { color: inherit; }
.stack__title a:hover { color: var(--rust); }

.stack__meta { font: 400 var(--mono-xs)/1.4 var(--mono); color: var(--faint); }

/* Most read: a bordered panel with a counter instead of thumbnails. */
.ranked { border: 1px solid var(--line); background: var(--surface); }

.ranked__item {
    display: grid;
    grid-template-columns: 34px minmax(0, 1fr);
    gap: 12px;
    align-items: baseline;
    padding: 14px 16px;
    border-bottom: 1px solid var(--line);
}

.ranked__item:last-child { border-bottom: 0; }
.ranked__item:hover { background: var(--hover); }

.ranked__no {
    font: 600 18px/1 var(--serif);
    color: var(--greenText);
}

.ranked__title { font: 600 15px/1.3 var(--serif); color: var(--ink); text-wrap: pretty; }
.ranked__title a { color: inherit; }
.ranked__title a:hover { color: var(--rust); }

.ranked__meta { font: 400 var(--mono-xs)/1.4 var(--mono); color: var(--faint); margin-top: 5px; }

/* ---------- buttons, chips, pager --------------------------------------------------- */

.button-ghost {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    background: transparent;
    border: 1px solid var(--line);
    padding: 12px 18px;
    font: 500 13px/1 var(--sans);
    color: var(--greenText);
}

.button-ghost:hover { background: var(--hover); border-color: var(--greenText); color: var(--greenText); }

.button-ghost--block { width: 100%; margin-top: 18px; padding: 13px; }

.button-ghost--small {
    padding: 8px 11px;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .05em;
    color: var(--muted);
    text-transform: uppercase;
}

.button-ghost--small:hover { border-color: var(--greenText); color: var(--greenText); }

/* Keyword tags. The mock also has filter chips with an active state; the real site has no
   filtering, so only the resting style exists here. */
.chip {
    display: inline-block;
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--muted);
    padding: 8px 13px;
    font: 400 var(--mono-sm)/1 var(--mono);
    letter-spacing: .04em;
}

.chip:hover { border-color: var(--greenText); color: var(--greenText); }

.pager {
    display: flex;
    gap: 6px;
    align-items: center;
    flex-wrap: wrap;
    margin-top: 26px;
}

.pager__item {
    background: transparent;
    border: 1px solid var(--line);
    padding: 10px 14px;
    font: 400 var(--mono-sm)/1 var(--mono);
    color: var(--muted);
}

.pager__item:hover { border-color: var(--greenText); color: var(--greenText); }

.pager__item--current {
    background: var(--panel);
    border-color: var(--panel);
    color: var(--onPanel);
}

.pager__item--current:hover { color: var(--onPanel); }

.pager__count {
    font: 400 var(--mono-sm)/1 var(--mono);
    color: var(--faint);
    margin-left: auto;
}

/* ---------- page headers (list) ----------------------------------------------------- */

.page-head {
    border-bottom: 2px solid var(--ink);
    padding-bottom: 20px;
    margin-bottom: 22px;
}

.page-head__kicker {
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .1em;
    color: var(--faint);
    margin-bottom: 10px;
    text-transform: uppercase;
}

.page-head__title {
    font: 600 44px/1.06 var(--serif);
    letter-spacing: -.02em;
    color: var(--ink);
    text-wrap: pretty;
}

/* ---------- article ----------------------------------------------------------------- */

.breadcrumb {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
    font: 400 var(--mono-xs)/1.5 var(--mono);
    letter-spacing: .06em;
    color: var(--faint);
    margin-bottom: 20px;
    text-transform: uppercase;
}

.breadcrumb a { color: var(--faint); }
.breadcrumb a:hover { color: var(--rust); }

.article-title {
    font: 600 42px/1.1 var(--serif);
    letter-spacing: -.015em;
    text-wrap: pretty;
    max-width: 26ch;
    color: var(--ink);
}

.article-dek {
    margin-top: 18px;
    font: 400 19px/1.55 var(--serif);
    color: var(--muted);
    max-width: 62ch;
    text-wrap: pretty;
}

.byline {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
    margin-top: 24px;
    padding: 16px 0;
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
}

.byline__who { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.byline__name { font: 500 14px/1.4 var(--sans); color: var(--ink); }
.byline__meta { font: 400 var(--mono-xs)/1.4 var(--mono); color: var(--faint); }
.byline__actions { display: flex; gap: 8px; align-items: center; flex-wrap: wrap; margin-left: auto; }

.figure { margin: 28px 0; }

.figure__frame {
    border: 1px solid var(--line);
    background: repeating-linear-gradient(135deg, var(--ph1) 0 8px, var(--ph2) 8px 16px);
    overflow: hidden;
}

.figure__frame img { display: block; width: 100%; height: auto; }

.figure__caption {
    margin-top: 10px;
    font: 400 var(--mono-sm)/1.5 var(--mono);
    color: var(--faint);
}

/* Replaces the bootstrap carousel: a scroll-snapped strip, no JavaScript.

   The carousel it replaces was almost certainly already dead. Its markup used data-ride /
   data-slide -- Bootstrap 4 attribute names -- while the navbar in the same template used
   data-bs-toggle, which is Bootstrap 5. Under 5 the auto-init never fired and the prev/next
   controls did nothing, so images 2..n were display:none with no way to reach them.

   grid-auto-columns is 92%, not 100%, so the next image visibly peeks. Without the controls
   below a reader has no other cue that the strip scrolls -- and those controls are injected
   by site.js, so this state is exactly what no JavaScript gets. A single image simply sits
   at 92% and the strip never scrolls. */
.gallery {
    display: grid;
    grid-auto-flow: column;
    grid-auto-columns: 92%;
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    gap: 10px;
    padding: 10px;
    border: 1px solid var(--line);
    background: var(--ph1);
}

.gallery__item { margin: 0; scroll-snap-align: start; }
.gallery__item img { display: block; width: 100%; height: auto; }

/* Every image keeps its own caption. The old markup showed only images[0].caption. */
.gallery__item figcaption { padding-top: 8px; }

/* ---------- carousel ---------------------------------------------------------------- */

/* The controls over the strip above. site.js builds this whole subtree at runtime and adds
   .is-carousel; none of it is in the template, and none of it hides a slide -- see the
   initGallery comment in site.js for why both of those are deliberate.

   Structure, so the offsets below make sense:

       .carousel > .carousel__frame > .gallery + the two arrows
                 > .carousel__dots

   The arrows are centred on the frame, not on .carousel, because the dots row sits inside
   .carousel and would push a top:50% off the image by half its height. */
.carousel__frame { position: relative; }

/* With arrows and dots present the 92 % peek has done its job -- the controls are now the
   cue that the strip scrolls -- so a slide fills the frame.

   The side padding has to go with it. Padding is inside the scrollport, so a 100 % column
   leaves exactly that much of the next slide showing through on either side: a 10px dark
   sliver down the edge of every image. Top and bottom keep theirs.

   The scrollbar goes too, and only here: it was the strip's one visible affordance, and the
   arrows and dots have replaced it. Nothing it did is lost -- swipe, drag, trackpad and the
   arrow keys all still scroll, and all of them still move the controls. */
.gallery.is-carousel {
    grid-auto-columns: 100%;
    padding-left: 0;
    padding-right: 0;
    scrollbar-width: none;
}

.gallery.is-carousel::-webkit-scrollbar { display: none; }

.carousel__nav {
    position: absolute;
    top: 50%;
    transform: translateY(-50%);
    width: 38px;
    height: 48px;
    display: grid;
    place-items: center;
    padding: 0;
    background: var(--surface);
    border: 1px solid var(--line);
    color: var(--muted);
    font: 400 22px/1 var(--sans);
    cursor: pointer;
    transition: color .15s, border-color .15s;
}

.carousel__nav:hover { border-color: var(--greenText); color: var(--greenText); }
.carousel__nav--prev { left: 14px; }
.carousel__nav--next { right: 14px; }

/* At the ends, not hidden: an arrow that vanishes shifts the layout under the pointer. */
.carousel__nav[disabled] { opacity: .3; cursor: default; }
.carousel__nav[disabled]:hover { border-color: var(--line); color: var(--muted); }

.carousel__dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 4px;
    margin-top: 10px;
    min-height: 22px;
}

/* The mark is 9px but the button is 22px: a 9px tap target is not one. */
.carousel__dot {
    width: 22px;
    height: 22px;
    display: grid;
    place-items: center;
    padding: 0;
    background: transparent;
    border: 0;
    cursor: pointer;
}

.carousel__dot::before {
    content: "";
    width: 9px;
    height: 9px;
    border: 1px solid var(--faint);
    transition: background .15s, border-color .15s;
}

.carousel__dot:hover::before { border-color: var(--greenText); }
.carousel__dot[aria-current="true"]::before { background: var(--panel); border-color: var(--panel); }

/* Shown instead of the dots once there are more images than dots can carry. */
.carousel__count { font: 400 var(--mono-sm)/1 var(--mono); color: var(--faint); }

.article-body {
    margin-top: 28px;
    max-width: 68ch;
    font: 400 18px/1.72 var(--serif);
    color: var(--ink2);
    overflow-wrap: break-word;
}

.article-body p { margin: 0 0 22px; }
.article-body h1, .article-body h2, .article-body h3, .article-body h4 {
    font-family: var(--serif);
    line-height: 1.24;
    margin: 32px 0 14px;
    color: var(--ink);
}
.article-body h1 { font-size: 30px; }
.article-body h2 { font-size: 26px; }
.article-body h3 { font-size: 22px; }
.article-body h4 { font-size: 19px; }
.article-body ul, .article-body ol { margin: 0 0 22px; padding-left: 1.4em; list-style: revert; }
.article-body li { margin-bottom: 8px; }
.article-body a { color: var(--greenText); text-decoration: underline; text-underline-offset: 2px; }
.article-body a:hover { color: var(--rust); }

.article-body blockquote {
    margin: 30px 0;
    padding: 22px 26px;
    background: var(--tint);
    border-left: 3px solid var(--greenText);
    font: 500 21px/1.45 var(--serif);
    color: var(--ink);
}

/* --- guards for the archived bodies. Do not remove: 2,269 documents predate this design
       and carry inline widths, <font>, <style> and Word markup. --- */
.article-body img,
.article-body video,
.article-body iframe,
.article-body embed,
.article-body object {
    max-width: 100%;
    height: auto;
}

.article-body table {
    max-width: 100%;
    display: block;
    overflow-x: auto;
    border-collapse: collapse;
}

.article-body td, .article-body th { padding: 6px 10px; border: 1px solid var(--line); }
.article-body pre { overflow-x: auto; }

/* Archived bodies hardcode near-black text, which is unreadable on the night surface.
   The inline colour wins over a plain rule, so this is scoped and marked important --
   the one place in this file where that is justified. */
.night .article-body [style*="color"],
.night .article-body font[color] { color: var(--ink2) !important; }

.night .article-body [style*="background"] { background-color: transparent !important; }

.tags-block { margin-top: 34px; padding-top: 20px; border-top: 2px solid var(--ink); }

.tags-block__title {
    font: 600 15px/1 var(--sans);
    letter-spacing: .06em;
    text-transform: uppercase;
    margin-bottom: 14px;
}

.tags { display: flex; flex-wrap: wrap; gap: 8px; }

/* ---------- video ------------------------------------------------------------------- */

/* video.min.css is no longer loaded; the raw YouTube iframes injected by th:utext are made
   responsive here. The iframe carries its own width/height attributes, so both are reset. */
.video-container {
    position: relative;
    width: 100%;
    padding-top: 56.25%;
    background: var(--panel);
    border: 1px solid var(--line);
    overflow: hidden;
}

.video-container iframe,
.video-container object,
.video-container embed,
.video-container video {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border: 0;
}

.video-panel {
    background: var(--surface);
    border-top: 1px solid var(--line);
    border-bottom: 1px solid var(--line);
    padding: 40px 0 44px;
    margin-top: 48px;
}

/* ---------- footer ------------------------------------------------------------------ */

.site-footer {
    margin-top: 56px;
    background: var(--panel);
    color: var(--onPanelMuted);
}

.site-footer__grid {
    display: grid;
    grid-template-columns: 1fr 1fr 1.4fr;
    gap: 40px;
    padding: 44px 0 30px;
}

.site-footer__label {
    display: block;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .12em;
    color: var(--panelAccent);
    margin-bottom: 12px;
    text-transform: uppercase;
}

.site-footer__col { display: flex; flex-direction: column; gap: 11px; }
.site-footer__text { font: 400 14px/1.75 var(--sans); color: var(--onPanelMuted); }
.site-footer__col a { color: var(--onPanelMuted); font: 400 13px/1.4 var(--sans); }
.site-footer__col a:hover { color: var(--onPanel); }

.site-footer__social { display: flex; gap: 8px; margin-top: 2px; flex-wrap: wrap; }

.site-footer__social a {
    border: 1px solid var(--onPanelLine);
    padding: 7px 11px;
    font: 400 var(--mono-xs)/1 var(--mono);
    letter-spacing: .05em;
    color: var(--onPanelMuted);
}

.site-footer__social a:hover { color: var(--onPanel); border-color: var(--onPanelMuted); }

.site-footer__bottom { border-top: 1px solid var(--onPanelLine); }

.site-footer__bottom-inner {
    display: flex;
    gap: 18px;
    flex-wrap: wrap;
    padding: 16px 0;
    font: 400 var(--mono-xs)/1.5 var(--mono);
    letter-spacing: .05em;
    color: var(--onPanelFaint);
}

.site-footer__bottom-inner a { color: var(--onPanelFaint); }
.site-footer__bottom-inner a:hover { color: var(--onPanel); }

/* ---------- misc -------------------------------------------------------------------- */

.parallax-strip {
    height: 420px;
    background-position: center;
    background-size: cover;
    border-top: 1px solid var(--line);
}

.empty-note {
    padding: 40px 0;
    font: 400 15px/1.6 var(--sans);
    color: var(--faint);
}

.banner-inline { margin: 26px 0; text-align: center; }
.banner-inline.mobile { display: none; }

/* ---------- responsive -------------------------------------------------------------- */

@media (max-width: 1080px) {
    :root { --gutter: 24px; }

    .layout { grid-template-columns: minmax(0, 1fr); }
    .layout__aside { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
    .card-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .card-grid--four { grid-template-columns: repeat(2, minmax(0, 1fr)); }
    .site-footer__grid { grid-template-columns: 1fr 1fr; }
}

@media (max-width: 860px) {
    :root { --gutter: 18px; }

    .masthead { flex-direction: column; align-items: flex-start; gap: 14px; }
    .masthead__side { align-items: stretch; }
    .masthead__tagline { text-align: left; }
    .masthead__tools { flex-wrap: wrap; }
    .site-search { max-width: none; }

    .nav-toggle { display: block; }
    .site-nav__inner { flex-wrap: wrap; }
    .site-nav__items { display: none; width: 100%; flex-direction: column; }
    .site-nav.is-open .site-nav__items { display: flex; }
    .site-nav__items .nav-item { display: block; width: 100%; }
    .site-nav__items .nav-item__label { width: 100%; text-align: left; }
    .nav-spacer { display: none; }

    .nav-menu {
        position: static;
        display: grid;
        grid-template-columns: 1fr;
        border: 0;
        border-top: 1px solid var(--onPanelLine);
        box-shadow: none;
        background: var(--greenDark);
        padding: 6px 20px 14px;
    }

    .nav-menu__link { color: var(--onPanelMuted); white-space: normal; }
    .nav-menu__link:hover { color: var(--onPanel); }

    /* Stack them. `grid-template-columns: 1fr` no longer does this -- the row sizes itself with
       grid-auto-flow now, so the flow direction is what has to change. */
    .partner-row { grid-auto-flow: row; }
    .card-grid, .card-grid--four, .card-grid--two { grid-template-columns: 1fr; }

    .list-row { grid-template-columns: 110px minmax(0, 1fr); gap: 16px; }

    .lead__title { font-size: 28px; max-width: none; }
    .article-title { font-size: 30px; max-width: none; }
    .page-head__title { font-size: 32px; }
    .article-body { font-size: 17px; }

    .site-footer__grid { grid-template-columns: 1fr; gap: 28px; }
    .parallax-strip { height: 240px; }

    /* The arrows sit over the image, and the image is now the width of the phone. */
    .carousel__nav { width: 32px; height: 40px; font-size: 19px; }
    .carousel__nav--prev { left: 8px; }
    .carousel__nav--next { right: 8px; }

    .banner-inline.desktop { display: none; }
    .banner-inline.mobile { display: block; }
}

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

/* ---------------------------------------------------------------- standing pages */

/*
 * The notices on a page shown in a language it was not written in.
 *
 * Two variants, never both at once -- PageService picks which applies, because a reader shown two
 * overlapping banners learns to skip both. The legal one is warmer-toned because it states which
 * text governs, rather than apologising for a missing translation. It uses --rust, the palette's
 * one warm accent, so it stays inside the design system instead of introducing a fifth colour.
 */
.page-notice {
    margin: 0 0 1.25rem;
    padding: .7rem .9rem;
    border-left: 3px solid var(--line);
    background: var(--tint);
    border-radius: 4px;
    font-size: .92rem;
    line-height: 1.5;
    color: var(--muted);
    font-family: var(--sans);
}

.page-notice--legal {
    border-left-color: var(--rust);
    background: var(--ph2);
    color: var(--ink2);
}

/* The page's own language switcher: only the languages it is actually written in. */
.page-langs {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem .9rem;
    align-items: center;
    margin-top: 2rem;
    padding-top: 1rem;
    border-top: 1px solid var(--line);
    font-family: var(--sans);
    font-size: .9rem;
}

.page-langs__item { color: var(--greenText); text-decoration: none; }
.page-langs__item:hover { text-decoration: underline; }
.page-langs__current { font-weight: 600; color: var(--ink); }

/* ---------- error page ---------------------------------------------------------------
 *
 * error.html is one column, so it cannot use .layout: that grid reserves a 320px aside, and an
 * error page carries no ad column -- nobody bought a booking on one. The padding-top is what
 * .layout gives every other page below the masthead, restated here rather than inherited.
 */
.error-page {
    padding-top: 26px;
    padding-bottom: 3.5rem;
    max-width: 42rem;
}

.error-page__text {
    font-family: var(--sans);
    font-size: 1rem;
    line-height: 1.6;
    color: var(--muted);
    margin: 0 0 .9rem;
}

/* The English line is a second voice, not a second paragraph of equal weight. */
.error-page__text--en { color: var(--faint); font-size: .92rem; }

.error-page__actions {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem 1.4rem;
    margin: 1.6rem 0 0;
    font-family: var(--sans);
    font-size: .95rem;
}

.error-page__actions a { color: var(--greenText); text-decoration: none; }
.error-page__actions a:hover { text-decoration: underline; }
