/* base.css — STRUCTURE shared by every base/arrangement (reset, the shell, chrome). POSITIONING
   ONLY: no colours/fonts (the theme's job) and no widths (the arrangement's job — each
   bases/<base>/<arrangement>.css sizes the regions). Global: lives once, not per theme. This is the
   POSITIONING half of Auteur's hard positioning-vs-styling CSS split (see ROADMAP.md). */

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

.shell { margin: 0 auto; padding: 0 1.25rem; }   /* width comes from the arrangement css */

/* Chrome: header + footer rows. Flex layout only; the theme colours/borders them. */
.site-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.25rem 0;
}
.site-nav { display: flex; gap: 1rem; }

/* chrome header/footer VARIANTS — placement only (the theme skins colours). default = brand left +
   nav right. These are drop-in header/footer partials a site picks in Settings; a theme can also
   recommend one. */
.site-header--centered { flex-direction: column; align-items: center; text-align: center; }
.site-header--centered .menu-horizontal > ul { justify-content: center; }

.site-header--hero { display: block; text-align: center; padding: 3.5rem 1.25rem; background-size: cover; background-position: center; }
.site-header--hero .site-hero-inner { max-width: 50rem; margin: 0 auto; position: relative; z-index: 1; }
.site-header--hero .site-hero-title { display: inline-block; font-size: 2.4rem; }
.site-header--hero .site-hero-tagline { margin: .4rem 0 1.1rem; }
.site-header--hero .menu-horizontal > ul { justify-content: center; }
.site-header--hero.has-banner { position: relative; }
.site-header--hero.has-banner::before { content: ""; position: absolute; inset: 0; }

.site-footer--centered { text-align: center; }
.site-footer--centered .menu-horizontal > ul { justify-content: center; }

/* menus (data-driven nav) — structure only; the theme skins colours/dropdown surface.
   horizontal = a row with one level of hover/focus dropdowns; vertical = a stacked list, nested
   items indented. */
.menu ul { list-style: none; margin: 0; padding: 0; }
.menu li { position: relative; }
.menu-horizontal > ul { display: flex; flex-wrap: wrap; align-items: center; gap: 1rem; }
.menu-horizontal li ul { display: none; position: absolute; top: 100%; left: 0; z-index: 50; min-width: 12rem; flex-direction: column; gap: 0; padding: .35rem 0; }
/* .is-open is set by the menu partial's script when a TOUCH tap lands on a parent — a touch device has
   no hover, so without it the children of a dropdown are unreachable. Hover and focus-within still open
   it for a mouse and a keyboard. */
.menu-horizontal li.has-children:hover > ul,
.menu-horizontal li.has-children:focus-within > ul,
.menu-horizontal li.has-children.is-open > ul { display: flex; }
.menu-vertical > ul { display: flex; flex-direction: column; gap: .35rem; }
.menu-vertical li ul { display: flex; flex-direction: column; gap: .25rem; margin: .25rem 0 0 1rem; }

.page { padding: 1.5rem 0 3rem; }   /* the region container; arrangements override its display */
.site-footer { padding: 1.5rem 0; }

/* Cross-base region utilities (structure; skin is the theme's).
   .region-hero  — a full-width band above the page columns (renders only when it holds widgets).
   .region.is-row — a region whose widgets lay out as COLUMNS: drop 1–4+ widgets in and they sit side
                    by side, wrapping when they'd get too narrow. This is how a region becomes a
                    "row of columns" (e.g. a feature/footer strip) — no nested container needed. */
.region-hero { margin: 0 0 1.5rem; }

/* landing-page helpers — structure only (type/colour in the theme). Used inside widget HTML on the
   Home layout: a centred hero block, a CTA button row, centred feature cards. */
.hero-block { max-width: 44rem; margin: 0 auto; text-align: center; padding: 1.5rem 0; }
.cta-row { display: flex; flex-wrap: wrap; gap: .75rem; justify-content: center; margin: 1.25rem 0 0; }
.feature-card { text-align: center; }
.feature-icon { display: block; font-size: 2rem; line-height: 1; margin: 0 0 .5rem; }
.text-center { text-align: center; }
/* STRETCH, not start. Cards in a row sized themselves to their own text, so a long brief beside a short
 * one produced a ragged row of different heights. The grid now gives every column the same height and the
 * widgets fill it, which is what makes a row read as a row. Content that would overflow is clamped by the
 * widget's own rules (see .widget-featured-brief) rather than allowed to set the height. */
/* min(14rem, 100%), not 14rem. A minmax() floor WIDER than the container does not collapse — the track
   stays 14rem and the row overflows the page. That matters here beyond a stray scrollbar: the homepage
   hero is full-bleed via `margin-left: calc(50% - 50vw)`, which only lines up while the page and the
   viewport are the same width. Any horizontal overflow and the hero breaks out to the true page width
   while the chrome stays at the viewport's — the "banner spills, everything else is ~70% wide" failure.
   min-width:0 lets a grid item shrink below its content's min-content size, which is the other half of
   the same problem: a grid/flex child defaults to min-width:auto and refuses to. */
.region.is-row { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fit, minmax(min(14rem, 100%), 1fr)); align-items: stretch; }
.region.is-row > .widget { display: flex; flex-direction: column; height: 100%; min-width: 0; }
/* Widgets in a ROW don't stack — the grid `gap` spaces them. Cancel the vertical stacking margin
   (.widget + .widget) so it can't push the 2nd+ widgets down out of top alignment. */
.region.is-row > .widget { margin-top: 0; }
/* prefooter — a full-width strip below the content, above the site footer (present on every base,
   renders only when it holds widgets). It's an is-row region, so its widgets sit as columns. */
.region-prefooter { margin-top: 2.5rem; }

/* per-content banner — a content-width image at the top of a page (the "hero banner"). A BASE includes
   partials/content-banner.php where its layout wants it (article-style bases do; the home/landing bases
   don't). The image shows in FULL: scaled to the container width at its natural aspect ratio (no crop,
   no fixed height). POSITIONING only; radius/surface are the theme's. */
/* The banner is included by the BASE, directly after the header and OUTSIDE .page — so .page's top
 * padding never reaches it and it sat flush against the menu bar. The gap belongs here rather than on the
 * header, because a page without a banner should not gain one. The partial self-suppresses when there is
 * no banner, so this margin only ever exists alongside an image. */
.content-banner { margin: 1.25rem 0 1.5rem; overflow: hidden; }
.content-banner-img { display: block; width: 100%; height: auto; }

/* featured-article widget — a content CARD linking to one article: the image on top (object-fit: cover
   so it fills + centre-crops, never a corner) with a category pill over its lower-left, then the title +
   brief on the card surface below. POSITIONING only; the card surface, pill + text colours are the theme's. */
.widget-featured { display: flex; flex-direction: column; text-decoration: none; }
.widget-featured-media { position: relative; display: block; flex: none; }
.widget-featured-img { display: block; width: 100%; height: 11rem; object-fit: cover; object-position: center; }
.widget-featured-cat { position: absolute; left: .6rem; bottom: .6rem; }
/* The body takes the leftover height so cards in a row end level, and the "more" cue is pushed to the
   bottom by the brief rather than floating under short text. */
.widget-featured-body { display: flex; flex-direction: column; gap: .35rem; padding: .85rem 1rem 1.05rem; flex: 1; min-width: 0; }
.widget-featured-title { font-size: 1.05rem; font-weight: 700; line-height: 1.25; }
/* Clamped to three lines: the brief is what varied most between cards, and letting it set the height is
   what made the row ragged. Clamping keeps the card a predictable size and the ellipsis, with the cue
   below, says there is more to read rather than pretending the text ended. */
.widget-featured-brief {
    font-size: .9rem; line-height: 1.45; flex: 1;
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden;
}
.widget-featured-more { font-size: .85rem; font-weight: 600; margin-top: auto; }

/* sensible structural defaults for content blocks; skin is the theme's */
.article-body > * + * { margin-top: 1rem; }

/* BODY IMAGES. An author sizes and places these in the editor, which stores the result as inline styles
 * on the <img>; these rules are the container's side of that bargain and nothing more.
 *
 * max-width keeps an image that is wider than the column — a 1536px banner-sized render in a 40rem
 * measure — from overflowing it, while leaving a deliberately smaller width alone. `height: auto`
 * preserves the aspect ratio when only a width was set.
 *
 * display: flow-root makes the body its own block formatting context, so a floated image is contained by
 * the article instead of escaping past its end and pushing into whatever follows. That is the failure a
 * float causes and it is invisible until somebody actually uses one. */
.article-body { display: flow-root; }
.article-body img { max-width: 100%; height: auto; }
.article-body img[style*="float: left"]  { margin: .25rem 1.5rem .75rem 0; }
.article-body img[style*="float: right"] { margin: .25rem 0 .75rem 1.5rem; }

/* series banner + prev/next pager on an article — structure only; skin is the theme's */
.series-banner { margin: .5rem 0 0; }
.series-pager { display: flex; gap: 1rem; flex-wrap: wrap; margin-top: 2.5rem; }
.series-pager a { display: grid; gap: .15rem; }
.series-next { margin-left: auto; text-align: right; }
.widget + .widget { margin-top: 1.5rem; }
.feed { list-style: none; padding: 0; margin: 0; display: grid; gap: 1.25rem; }
.feed-item { display: grid; gap: .15rem; }
.feed-item .feed-excerpt { margin: .15rem 0 0; }
/* series list: a number column beside the title + excerpt */
.series-item { grid-template-columns: auto 1fr; column-gap: .65rem; align-items: baseline; }
.series-item > * { grid-column: 2; }
.series-num { grid-column: 1; grid-row: 1 / -1; align-self: center; }

/* "In this series" box on an article — the whole reading order, with the current part un-linked.
   Mostly structure, but it carries a restrained skin of its own (via theme vars WITH fallbacks) rather
   than living purely in the themes: series skinning is uneven across them — only `default` styles the
   pager and numbers, and no theme has a dark variant for it — so a theme-only skin would leave this
   widget bare under nebula/sepia. A theme can still override any of it. */
.series-box { margin-top: 2.5rem; padding-top: 1rem; border-top: 1px solid var(--line, rgba(128, 128, 128, 0.25)); }
.series-box-title { margin: 0 0 .75rem; font-size: 1rem; }
.series-box-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .4rem; }
.series-box-item { display: grid; grid-template-columns: auto 1fr; column-gap: .65rem; align-items: baseline; }
.series-box-item .series-num { grid-column: 1; grid-row: 1; }
.series-box-item.is-current { font-weight: 600; }
.series-box-current { color: var(--muted, inherit); }
.series-box-more { margin: .75rem 0 0; font-size: .9rem; }

/* The same reading order as a SIDEBAR widget. Structure lives here rather than in a theme for the
   reason given above — series skinning is uneven, so a theme-only skin leaves it bare under half of
   them. Deliberately lighter than .series-box: no top rule (a widget is already a card in its column)
   and tighter spacing, because a narrow sidebar cannot carry the article version's weight. */
.widget-series-name { margin: 0 0 .5rem; font-size: .9rem; }
.widget-series-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .35rem; }
.widget-series-item { display: grid; grid-template-columns: auto 1fr; column-gap: .5rem;
    align-items: baseline; font-size: .92rem; line-height: 1.35; }
.widget-series-item .series-num { grid-column: 1; grid-row: 1; }
.widget-series-item.is-current { font-weight: 600; }
/* The current part is not a link, so it must still read as "you are here" rather than as dead text. */
.widget-series-current { color: var(--muted, inherit); }
.widget-series-more { margin: .6rem 0 0; font-size: .85rem; }

/* widgets — structure only (skin in the theme). image: keep within its column; callout: stack body. */
.widget-image { margin: 0; }
.widget-image img { display: block; max-width: 100%; height: auto; }
.widget-image figcaption { margin-top: .4rem; }
.callout-body > * + * { margin-top: .5rem; }

/* forms (admin login, comment form): structure only — block fields, full-width inputs. */
.form { display: grid; gap: 1rem; max-width: 24rem; }
.form .field { display: grid; gap: .25rem; }
.form input, .form textarea { width: 100%; padding: .5rem; }
.form button { justify-self: start; padding: .5rem 1.25rem; }
.form-errors { margin: 0 0 1rem; padding-left: 1.1rem; }
.form-message { margin: 0 0 1rem; }

/* comments thread (front-end) — structure only; skin is the theme's. The post form widens past the
   narrow .form default since it sits in the content column. */
.comments { margin-top: 2.5rem; }
.comment-list { list-style: none; margin: 0 0 1.5rem; padding: 0; display: grid; gap: 1.25rem; }
.comment-meta { display: flex; gap: .75rem; align-items: baseline; margin: 0 0 .25rem; }
.comment-body > * + * { margin-top: .5rem; }
.comment-pager { display: flex; gap: 1rem; align-items: center; margin: 0 0 1.5rem; }
.comment-form.form { max-width: none; }

/* ── search + category index (structure; skin is the theme's) ──────────────────────────────────────
   A label that is read aloud but not shown. The widget's field is self-evident beside its heading, and
   a visible second label would just repeat it — but a form control with no label at all is unusable to
   a screen reader, so the label exists and is hidden properly rather than display:none'd (which would
   remove it from the accessibility tree as well). */
.visually-hidden {
    position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
    overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0;
}

.search-form { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; margin: .75rem 0 0; }
.search-label { flex: 1 0 100%; font-size: .9rem; }
.search-input { flex: 1 1 12rem; min-width: 0; padding: .5rem .65rem; }
.search-submit { flex: none; padding: .5rem 1rem; cursor: pointer; }
.search-hint { margin: 1.25rem 0 .5rem; }

/* The count line on the category index carries the same weight as a feed item's date, so it reuses
   .feed-meta and needs no rules of its own. */
.cat-index .feed-item { padding-bottom: .35rem; }

/* ── narrow screens ────────────────────────────────────────────────────────────────────────────────
   The site had NO media queries at all: it relied on flex-wrap and auto-fit collapsing, which mostly
   works and leaves the two things below broken.

   A HOVER DROPDOWN CANNOT BE OPENED BY TOUCH. Submenus show on :hover/:focus-within, and a tap on a
   phone is not a hover — it activates the link, so tapping "Categories" navigated to the index and the
   eight archives under it were unreachable. Below this width the submenu is simply always open, laid
   out as an indented list the way the vertical menu already does it. No JavaScript, and nothing to tap
   twice: every item is a plain link you can see.

   Long unbreakable strings — a slug-like URL in body text — are the other classic source of the
   horizontal overflow that breaks the full-bleed hero, so wrap them rather than let one word set the
   page width. */
/* The mobile nav toggle. Desktop never shows it; the media query below turns it on. Drawn with
   currentColor so it inherits whatever the theme paints the bar in, rather than needing a colour here. */
.nav-toggle {
    display: none; margin-left: auto; align-items: center; justify-content: center;
    width: 2.75rem; height: 2.5rem; padding: 0;
    background: none; border: 1px solid currentColor; border-radius: .35rem;
    color: inherit; cursor: pointer;
}
.nav-toggle-bars, .nav-toggle-bars::before, .nav-toggle-bars::after {
    display: block; width: 1.1rem; height: 2px; background: currentColor; border-radius: 2px;
}
.nav-toggle-bars { position: relative; }
.nav-toggle-bars::before, .nav-toggle-bars::after { content: ""; position: absolute; left: 0; }
.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after  { top:  6px; }

@media (max-width: 48rem) {
    .nav-toggle { display: inline-flex; }
    .menu-horizontal > ul { gap: .35rem 1rem; }
    .menu-horizontal li ul {
        display: flex; position: static; min-width: 0;
        margin: .2rem 0 .35rem 1rem; padding: 0; gap: .2rem;
    }
    .menu-horizontal li.has-children { flex: 1 0 100%; }   /* the group owns its own line */

    .article-body { overflow-wrap: break-word; }
    .region.is-row { gap: 1.25rem; }
}
