/* Sole Autosite — bundled default stylesheet.
   ============================================================================
   A CRAFTED-FUNCTIONALIST substrate (Epoch 24.6; ADR-0051, compass §19).
   Not "a look": a COMPLETE, usable theme on its own AND the always-present
   chameleonic layer under a site's custom.css (custom wins the cascade).

   HOW TO RE-THEME
     Edit THE CONTROL PANEL below — the palette / type / space variables in
     :root. Overriding those alone re-colours, re-types, and re-spaces the whole
     site. You never need to touch the rules further down.

   HOW IT STAYS OUT OF YOUR WAY (the chameleon contract)
     - Every COLOUR reads a variable (no colour literal outside :root), and the
       type/space tokens do too — so the palette/type/space control panel
       re-themes the whole site. (A few fixed structural dimensions — hairline
       borders, the focus ring, radii, the logo cap — are relative-unit
       constants by design, not control-panel knobs.)
     - Every themed rule stays within a ONE-CLASS specificity budget: the scope
       and any state/qualifier are wrapped in :where(...) (which costs zero
       specificity), so a single-class rule in your custom.css always wins.
       (Top-level content blocks — .page-title/.page-date/.page-body/.contents —
       are bare single classes on purpose: they must out-rank the browser's own
       h1/ul/etc. defaults; your custom.css still wins them by loading later.)
     - Sizes are all relative (rem / em / ch); the design scales with the
       reader's own font size and zoom. No pixels.

   The page STRUCTURE (which blocks exist, their classes) is emitted by the
   engine and documented in landmarks "Page structure and the CSS theme
   surface"; this file only arranges and dresses it. Fonts are the reader's own
   (generic `serif` / `monospace`) or a site's dropped font.* — nothing is
   fetched from the network (host-agnostic, compass §11).
   ============================================================================ */

/* --- THE CONTROL PANEL — edit here to re-theme in one place --------------- */
:root {
  /* PALETTE — a neutral ink-on-paper base + ONE accent that means "link".
     Colour carries meaning here, not decoration; that is what keeps the base
     chameleonic (override --accent and nothing else clashes). Light mode; the
     dark block below mirrors it. Every pair is >= WCAG AA. */
  --ink:        #1a1a1a;   /* body text                                      */
  --bg:         #ffffff;   /* page background                                */
  --muted:      #595959;   /* secondary text — dates, captions, nav, footer  */
  --accent:     #1f5390;   /* links, active states                          */
  --accent-ink: #14375f;   /* link hover / pressed                          */
  --rule:       #e4e4e4;   /* hairlines, borders                            */
  --code-bg:    #f4f4f4;   /* RESERVED — a code surface if a theme opts in;
                              the default keeps code box-free (see pre/code)  */

  /* TYPE — the reader's OWN fonts (generic families) or a dropped font.*, which
     the engine binds as 'sole-site-font'. We impose no typeface; the craft is
     the scale + rhythm below, not the font. --font-chrome defaults to the body
     face (one voice) but is a separate knob if you want chrome to differ.
     --font-mono is generic monospace for code (NOT the dropped font, so code
     stays fixed-width even under a serif font.*). */
  --font-body:   'sole-site-font', serif;
  --font-chrome: var(--font-body);
  --font-mono:   monospace;

  /* A 1.25 (major-third) modular scale. Change --text-base to re-scale the
     whole hierarchy in one place; each step is derived from it. */
  --text-base: 1rem;
  --text-sm:   calc(var(--text-base) * 0.8);
  --text-lg:   calc(var(--text-base) * 1.25);
  --text-xl:   calc(var(--text-base) * 1.5625);
  --text-2xl:  calc(var(--text-base) * 1.953);
  --leading:       1.6;    /* body                                          */
  --leading-tight: 1.2;    /* headings                                      */
  --measure:   66ch;       /* readable CONTENT width (Butterick 45-90);
                              horizontal padding adds OUTSIDE it, see body   */

  /* SPACE — one vertical rhythm. Every margin / gap references this scale. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 1rem;
  --space-4: 1.5rem;
  --space-5: 2.5rem;
}
@media (prefers-color-scheme: dark) {
  :root {
    --ink:        #e6e6e6;
    --bg:         #171717;
    --muted:      #a2a2a2;
    --accent:     #7fb0ec;
    --accent-ink: #a9caf5;
    --rule:       #333333;
    --code-bg:    #232323;
  }
}

/* --- Flow scaffold + order convention (ADR-0046) --------------------
   Real <header>/<main>/<footer> tags are always in the DOM. <main> is
   always emitted; <header>/<footer> are emitted only when they hold a
   block (empty-block suppression). All three DISSOLVE (display:contents)
   so every block joins ONE flow on <body>, positioned by the order
   numbers: header 100s, content 200s, footer 300s. Change a number to
   move a block anywhere; display:none to hide. Content is always
   element-wrapped (Epoch 22: engine-rendered pages get .page-title /
   .page-date / .page-body; authored bodies are wrapped in .page-body;
   bundled 404/search carry their own elements) so no bare text escapes
   to the default order:0 ahead of the header. `main > *` gives every
   content child the 220 default; .page-title / .page-date override it by
   specificity. A site wanting per-region boxes overrides `display` in
   custom.css; older engines without display:contents fall back to
   ordered block regions via @supports. NOTE: `order` changes VISUAL
   order only — screen readers and Tab follow source order, which is
   header / main / footer. */
body { display: flex; flex-direction: column; }
header, main, footer { display: contents; }
main > * { order: 220; }                  /* content region (.page-body, bundled content) */
.page-title { order: 200; }               /* content blocks (higher specificity wins) */
.page-date  { order: 210; }
header > .logo       { order: 100; }      /* logo above the wordmark (visual only — source order keeps the wordmark first for reading order) */
header > .site-title { order: 105; }      /* site identity wordmark (L10) */
header > .navigation { order: 110; }      /* auto two-tier nav (L9) */
header > .language-switcher { order: 120; } /* auto translation links */
header > .custom-header { order: 130; }   /* authored header.html */
footer > .recent { order: 300; }          /* recent-items feed (E24.8) — above the authored footer */
footer > .custom-footer { order: 330; }   /* authored footer.html */
@supports not (display: contents) {
  header { display: block; order: 100; }
  main   { display: block; order: 200; }
  footer { display: block; order: 300; }
}

/* --- Base (the only intentionally unscoped rules) ------------------- */
*, *::before, *::after { box-sizing: border-box; }
html {
  font-family: var(--font-body);
  font-size: 100%;                 /* honour the reader's default size */
  line-height: var(--leading);
  -webkit-text-size-adjust: 100%;
}
body {
  /* --measure is the CONTENT width; the horizontal padding is added outside it
     so the readable column is a true 66ch (tracks --space-3 if you change it). */
  max-width: calc(var(--measure) + 2 * var(--space-3));
  margin: 0 auto;
  padding: var(--space-5) var(--space-3);
  color: var(--ink);
  background: var(--bg);
}
img, picture > * { max-width: 100%; height: auto; }
/* Bare images that fall DIRECTLY into a region (the .logo, an image-as-
   index landing, any top-level authored <img>) dissolve into the body
   column-flex (header/main/footer are display:contents), where the
   default align-items:stretch would pull a width:auto image to full width
   and squash it against a height cap. Pin them to their intrinsic ratio.
   Images nested inside .page-body are normal block flow, so unaffected. */
header > img, main > img, footer > img { align-self: flex-start; }
:focus-visible { outline: 0.125rem solid var(--accent); outline-offset: 0.125rem; }
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* --- Header chrome ------------------------------------------------------- */
/* Themed rules keep the one-class budget: scope AND state go in :where(...)
   (zero specificity) so a custom.css rule always wins. */
:where(header) .site-title {
  font-family: var(--font-chrome);
  font-size: var(--text-xl);
  line-height: var(--leading-tight);
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  margin-bottom: var(--space-1);
}
:where(header) .site-title:where(:hover) { color: var(--accent-ink); }
:where(header) .logo { max-height: 2.25rem; width: auto; margin-bottom: var(--space-2); }

:where(header) .navigation {
  font-family: var(--font-chrome);
  font-size: var(--text-sm);
  margin-bottom: var(--space-4);
}
:where(header .navigation) .section {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1) var(--space-4);
  padding: 0;
  margin: var(--space-1) 0 0;
}
/* Tier 2 = the SECOND .section (only when present) — lighter/smaller.
   `+ .section` (not :last-child) so a lone tier-1 nav — e.g. the home
   page, where tier 2 is suppressed — keeps the full tier-1 size. */
:where(header .navigation .section) + .section {
  font-size: var(--text-sm);
  padding-top: var(--space-1);
}
:where(header .navigation) .link {
  color: var(--muted);
  text-decoration: none;
  padding-bottom: 0.125rem;
  border-bottom: 0.125rem solid transparent;   /* reserved slot; transparent = no colour, not a palette value */
}
:where(header .navigation) .link:where(:hover) { color: var(--ink); }
:where(header .navigation) .active {
  color: var(--accent);
  font-weight: 600;
  border-bottom-color: var(--accent);
}
:where(header .navigation .up)::before { content: "\2191\00a0"; color: var(--muted); } /* ↑ */
/* (no .folder affordance in the nav: every tier-1 item is a section, so a
   marker there is just noise; the .contents listing marks folders instead.) */

:where(header) .language-switcher {
  font-family: var(--font-chrome);
  font-size: var(--text-sm);
  color: var(--muted);
  margin-bottom: var(--space-4);
}
:where(header .language-switcher) .link { color: var(--accent); text-decoration: none; }
/* :not(.active) — the current-language .link is a non-interactive <span>. */
:where(header .language-switcher) .link:where(:not(.active):hover) { text-decoration: underline; }
:where(header .language-switcher .link) + .link { margin-left: var(--space-2); }
:where(header .language-switcher) .active { color: var(--muted); font-weight: 600; }
:where(header .language-switcher .active) + .link { margin-left: var(--space-2); }

:where(header) .custom-header { margin-bottom: var(--space-4); }

/* --- Content region (<main>) --------------------------------------------- */
/* Top-level content blocks are bare single classes (0,1,0) — see the header
   comment: they must out-rank the browser's own element defaults; custom.css
   still wins them by loading after this sheet. */
.page-title {
  font-size: var(--text-2xl);
  line-height: var(--leading-tight);
  font-weight: 700;
  margin: 0 0 var(--space-1);
}
.page-date { color: var(--muted); font-size: var(--text-sm); margin: 0 0 var(--space-4); }

.page-body { line-height: var(--leading); }
:where(.page-body) > :first-child { margin-top: 0; }
:where(.page-body) a { color: var(--accent); text-decoration: underline; text-underline-offset: 0.125rem; }
:where(.page-body) a:where(:hover) { color: var(--accent-ink); }
/* Every heading level is on the scale + rhythm (authored HTML bodies may carry
   any of h1-h6; engine-rendered pages use .page-title for the h1). */
:where(.page-body) h1 { font-size: var(--text-2xl); line-height: var(--leading-tight); font-weight: 700; margin: var(--space-5) 0 var(--space-2); }
:where(.page-body) h2 { font-size: var(--text-xl); line-height: var(--leading-tight); margin: var(--space-5) 0 var(--space-2); }
:where(.page-body) h3 { font-size: var(--text-lg); line-height: var(--leading-tight); margin: var(--space-4) 0 var(--space-1); }
:where(.page-body) h4, :where(.page-body) h5, :where(.page-body) h6 {
  font-size: var(--text-base); line-height: var(--leading-tight); font-weight: 700;
  margin: var(--space-4) 0 var(--space-1);
}
:where(.page-body) p { margin: 0 0 var(--space-3); }
:where(.page-body) ul, :where(.page-body) ol { margin: 0 0 var(--space-3); padding-left: var(--space-4); }
:where(.page-body) li { margin: var(--space-1) 0; }
:where(.page-body) blockquote {
  margin: var(--space-4) 0;
  padding: var(--space-1) 0 var(--space-1) var(--space-3);
  border-left: 0.1875rem solid var(--rule);
  color: var(--muted);
}
/* A .txt file's body (and any bare authored <pre>) is the site's PRIMARY
   READING content, NOT code — the engine wraps it in <pre> only to keep the
   author's line breaks. So it reads as PROSE: the body face, no box, wrapped.
   .txt is a first-class citizen (compass convention-promotion). ACTUAL code
   (`<pre><code>`, Markdown fences, inline <code>) is the exception below. The
   default <pre> is prose so that on browsers without :has() it degrades in
   favour of .txt — the format that matters most. */
:where(.page-body) pre {
  font-family: var(--font-body);
  white-space: pre-wrap;              /* honour the author's line breaks; wrap long lines */
  margin: 0 0 var(--space-3);
  line-height: var(--leading);
}
/* Real code: monospace, distinguished by the face alone (no box). --code-bg
   stays a reserved knob for a theme that wants a code surface. */
:where(.page-body) code { font-family: var(--font-mono); font-size: 0.9em; }
:where(.page-body) pre:has(code) {
  white-space: pre;                   /* code does not wrap — scroll instead */
  overflow-x: auto;
}
:where(.page-body) hr { border: 0; border-top: 0.0625rem solid var(--rule); margin: var(--space-5) 0; }
:where(.page-body) table { border-collapse: collapse; width: 100%; margin: var(--space-4) 0; }
:where(.page-body) th, :where(.page-body) td {
  text-align: left;
  padding: var(--space-1) var(--space-2);
  border-bottom: 0.0625rem solid var(--rule);
}
:where(.page-body) figure { margin: var(--space-4) 0; }
:where(.page-body) figcaption { color: var(--muted); font-size: var(--text-sm); margin-top: var(--space-1); }

/* --- .contents child listing --------------------------------------------- */
.contents { list-style: none; padding: 0; margin: var(--space-3) 0 0; }
:where(.contents) .entry {
  padding: var(--space-2) 0;
  border-bottom: 0.0625rem solid var(--rule);
}
:where(.contents) .link { color: var(--accent); text-decoration: none; }
:where(.contents) .link:where(:hover) { color: var(--accent-ink); text-decoration: underline; }
:where(.contents .folder) > .link::after { content: "\00a0/"; color: var(--muted); }

/* --- Cross-language links (ADR-0052) ------------------------------------- */
/* A work with no translation into THIS language is still listed — in the
   language it has — rather than vanishing from the edition; silently dropping
   an author's content is the one outcome a reader can never undo. The engine
   marks it (.untranslated + lang/hreflang) and the theme SAYS SO, naming the
   language by its own CODE via attr(lang) — never an invented word, because
   the engine does not presume to know what language this site speaks.
   To hide them instead: `.untranslated { display: none }` in custom.css. */
:where(.contents, .navigation) .link:where(.untranslated)::after {
  content: "\00a0(" attr(lang) ")";
  color: var(--muted);
}
/* …and when that link is ALSO a folder, keep the folder marker as well. */
:where(.contents .folder) > .link:where(.untranslated)::after {
  content: "\00a0/\00a0(" attr(lang) ")";
}

/* --- Image / gallery blocks ---------------------------------------------- */
:where(.page-body) .gallery-grid {
  list-style: none;
  padding: 0;
  margin: var(--space-4) 0;
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
  gap: var(--space-2);
}
:where(.page-body) .gallery-grid img { width: 100%; border-radius: 0.25rem; }
:where(.page-body) .gallery-nav {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin: var(--space-4) 0;
  font-size: var(--text-sm);
}
/* Status hooks: shown, not hidden — muted but legible (ADR-0051 R4). */
:where(.page-body) :is(.gallery-page-failed, .gallery-decode-errors,
                       .image-failed, .image-animated-unavailable) {
  color: var(--muted);
  font-size: var(--text-sm);
}

/* --- Footer -------------------------------------------------------------- */
:where(footer) .custom-footer {
  font-family: var(--font-chrome);
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 0.0625rem solid var(--rule);
  color: var(--muted);
  font-size: var(--text-sm);
}
:where(footer .custom-footer) a { color: var(--accent); }

/* --- .recent feed (Epoch 24.8) ------------------------------------------- */
/* The newest items from a section's whole subtree, rendered in the <footer>
   (root landing = whole site). Shares the .contents entry/link/folder/
   untranslated vocabulary above; adds a per-item .date. A footer block like
   .custom-footer: muted, chrome type, set off by a top rule. Hide it with
   `.recent { display: none }`; reorder with `order:`. */
:where(footer) .recent {
  list-style: none;
  padding: 0;
  margin: 0;
  margin-top: var(--space-5);
  padding-top: var(--space-3);
  border-top: 0.0625rem solid var(--rule);
  font-family: var(--font-chrome);
  font-size: var(--text-sm);
}
:where(footer .recent) .entry { padding: var(--space-1) 0; }
:where(footer .recent) .link { color: var(--accent); text-decoration: none; }
:where(footer .recent) .link:where(:hover) {
  color: var(--accent-ink);
  text-decoration: underline;
}
:where(footer .recent) .date { color: var(--muted); margin-left: var(--space-2); }
/* Subsection items get the folder marker; untranslated items name their
   language — the same conventions .contents uses, scoped under .recent. */
:where(footer .recent .folder) > .link::after { content: "\00a0/"; color: var(--muted); }
:where(footer .recent) .link:where(.untranslated)::after {
  content: "\00a0(" attr(lang) ")";
  color: var(--muted);
}
:where(footer .recent .folder) > .link:where(.untranslated)::after {
  content: "\00a0/\00a0(" attr(lang) ")";
}

/* --- Bundled search / smart-404 UI --------------------------------------- */
:where([data-search], [data-smart-404]) form label {
  display: block;
  margin-bottom: var(--space-1);
  font-weight: 600;
}
:where([data-search]) input[type="search"] {
  width: 100%;
  padding: var(--space-2) var(--space-2);
  font: inherit;
  color: var(--ink);
  background: var(--bg);
  border: 0.0625rem solid var(--rule);
  border-radius: 0.375rem;
}
/* Result / 404 links (hardcoded in 404.html, injected by search.js). */
:where([data-search], [data-smart-404]) a {
  color: var(--accent);
  text-decoration: underline;
  text-underline-offset: 0.125rem;
}
:where([data-search], [data-smart-404]) a:where(:hover) { color: var(--accent-ink); }
/* .snippet is injected client-side by search.js into the result lists. */
:where([data-search], [data-smart-404]) .snippet {
  color: var(--muted); font-size: var(--text-sm); margin: var(--space-1) 0 0 var(--space-4);
}
