/* -------------------------------------------------------------------------- */
/*                                 Root Setup                                 */
/* -------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   Fonts - self-hosted, so this archive works with no network at all.

   This file used to open with

     @import url('https://fonts.googleapis.com/css2?family=Gabriela&family=Lato:wght@300;400;700&display=swap');

   which was two defects rather than the one Gemini_Code_Audit.md section 3.6
   reports.

   1. It BLOCKED FIRST PAINT. An @import is discovered only after style.css
      itself has been fetched and parsed, so the browser then opens a second
      connection - DNS, TCP and TLS to a host it has never spoken to - before
      it can paint anything. Measured in headless Chrome on 5 September 2026,
      Chrome's own PerformanceResourceTiming reported it as
      renderBlockingStatus: "blocking", finishing at 49-65 ms on a LAN and
      600 ms behind 150 ms of emulated latency. On a machine with no route to
      the internet it blocks until the connection fails.

   2. THREE QUARTERS OF WHAT IT FETCHED WAS NEVER USED. It asked for Lato in
      300, 400 and 700, and no rule in this stylesheet names Lato - `body` is
      set in the system stack. Grepping the whole corpus for "Lato" finds line
      4 of this file and then only the words "Latona" and "Latourette" in
      article prose. Only Gabriela is real, and only at weight 400, on h1-h6.

   So Lato is gone rather than self-hosted, and Gabriela is served from
   fonts/. Four subsets, 37 KB in total, each kept behind the unicode-range
   Google publishes for it, so a Latin page downloads 12,796 bytes and nothing
   else. Cyrillic is kept because russian/ is a real section of this archive.

   The files are the exact bytes fonts.gstatic.com serves, verified as woff2
   by their wOF2 magic number. Gabriela is Eduardo Tunni's, licensed under the
   SIL Open Font License 1.1, which permits redistribution; fonts/OFL.txt is
   the licence as it is published with the font, and it must travel with these
   files. Read from the upstream metadata, not assumed.

   `font-display: swap` matches what the removed URL asked for with
   `&display=swap`: headings paint immediately in the fallback serif and
   re-render when the face arrives, rather than sitting invisible.
   --------------------------------------------------------------------------- */

@font-face {
    font-family: 'Gabriela';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/gabriela-cyrillic-ext.woff2') format('woff2');
    unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

@font-face {
    font-family: 'Gabriela';
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url('fonts/gabriela-cyrillic.woff2') format('woff2');
    unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

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

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

:root {
    /* Font Scaling Root Variable */
    --font-base: 16px;
    --font-scale: 1;

    /* Transition Speeds */
    --trans-speed: 0.3s;
    --trans-speed-slow: 0.5s;

    /* Global Spacing */
    --gap-standard: 1rem;
    --border-radius: 16px;
    /* Slightly more rounded for modern look */

    /* Layout */
    --max-width: 1100px;
    --header-height: 70px;
}

/* -------------------------------------------------------------------------- */
/*                                    Reset                                   */
/* -------------------------------------------------------------------------- */
* {
    box-sizing: border-box;
    margin: 0;
    padding: 0;
    -webkit-tap-highlight-color: transparent;
}

html {
    font-size: calc(var(--font-base) * var(--font-scale));
    scroll-behavior: smooth;
    height: 100%;
}

body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
    line-height: 1.7;
    /* Improved readability */
    min-height: 100vh;
    transition: background-color 0.5s ease, color 0.5s ease;
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
}

/* -------------------------------------------------------------------------- */
/*                                Typography                                  */
/* -------------------------------------------------------------------------- */
h1,
h2,
h3,
h4,
h5,
h6 {
    font-family: 'Gabriela', serif;
    margin-bottom: 0.8rem;
    line-height: 1.2;
    letter-spacing: -0.02em;
}

h1 {
    font-size: 2.8rem;
    font-weight: 700;
}

h2 {
    font-size: 2.2rem;
}

h3 {
    font-size: 1.6rem;
}

p {
    font-size: 1.05rem;
    margin-bottom: 1.2rem;
}

a {
    /* `inherit`, not a fixed 1rem: legacy pages put links inside headings and
       small print, and a hard size flattened all of them to body size. */
    font-size: inherit;
    text-decoration: none;
    transition: color var(--trans-speed), background-color var(--trans-speed);
    position: relative;
}

/* -------------------------------------------------------------------------- */
/*                                   Themes                                   */
/* -------------------------------------------------------------------------- */

/* These eight blocks were `body.theme-N` until 5 September 2026, and the move
   to `html.theme-N` is what lets the theme be right at the FIRST paint rather
   than shortly after it.

   The reader's choice lives in localStorage, so only the browser can know it,
   and only a blocking script in <head> runs early enough to act on it. Such a
   script cannot touch <body>, which does not exist yet - so the class it sets
   has to go on <html>. Custom properties inherit, so `body { background:
   var(--bg-gradient) }` below reads them exactly as before and no other rule
   in this file changes.

   Gemini_Code_Audit.md section 3.4 proposed the <head> script WITHOUT this
   move. Its snippet sets `document.documentElement.className = 'theme-' + n`
   while every theme rule was still `body.theme-N`, so `html.theme-4` matched
   nothing at all: the page would have carried a class that selected no
   declaration and painted the default theme anyway. It is the second
   remediation in that document that fails silently while looking like a fix.

   Anything reading these variables must therefore not assume the class is on
   <body>: Script.js's apply_theme() sets it on document.documentElement, and
   check_contrast.py reads `html.theme-N` blocks out of this file. */

html.theme-0 {
    --bg-color: #121212;
    --bg-gradient: linear-gradient(135deg, #1a1a2e 0%, #16213e 100%);
    --text-color: #f5f5f7;
    --text-color-secondary: #a1a1a6;
    --accent-color: #1f4068;
    --highlight-color: #4db8ff;
    --card-bg: rgba(22, 33, 62, 0.7);
    --header-bg: rgba(26, 26, 46, 0.85);
    --button-text: #fff;
    --shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    --border-color: rgba(255, 255, 255, 0.1);
}

html.theme-1 {
    --bg-color: #2D033B;
    --bg-gradient: linear-gradient(135deg, #2D033B 0%, #410756 100%);
    --text-color: #E5B8F4;
    --text-color-secondary: #cfa0e0;
    --accent-color: #810CA8;
    --highlight-color: #ce6dee;   /* was #C147E9: 3.85:1 as link text on the card */
    --card-bg: rgba(65, 7, 86, 0.7);
    --header-bg: rgba(45, 3, 59, 0.85);
    --button-text: #fff;
    --shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    --border-color: rgba(255, 255, 255, 0.1);
}

html.theme-2 {
    --bg-color: #0c2d1c;
    --bg-gradient: linear-gradient(135deg, #0c2d1c 0%, #13422a 100%);
    --text-color: #d1e8d6;
    --text-color-secondary: #a3c2a9;
    --accent-color: #1b5e20;
    --highlight-color: #66ff99;
    --card-bg: rgba(19, 66, 42, 0.7);
    --header-bg: rgba(12, 45, 28, 0.85);
    --button-text: #fff;
    --shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    --border-color: rgba(255, 255, 255, 0.1);
}

html.theme-3 {
    --bg-color: #202124;
    --bg-gradient: linear-gradient(135deg, #202124 0%, #303134 100%);
    --text-color: #e8eaed;
    --text-color-secondary: #a8aeb3;   /* was #9aa0a6: 3.83:1 on a notice tint */
    --accent-color: #3c4043;
    --highlight-color: #fdd663;
    --card-bg: rgba(48, 49, 52, 0.7);
    --header-bg: rgba(32, 33, 36, 0.85);
    --button-text: #fff;
    --shadow: 0 8px 32px rgba(0, 0, 0, 0.3);
    --border-color: rgba(255, 255, 255, 0.1);
}

/* Light Themes */
html.theme-4 {
    --bg-color: #f5f5f7;
    --bg-gradient: linear-gradient(135deg, #f5f5f7 0%, #ffffff 100%);
    --text-color: #1d1d1f;
    --text-color-secondary: #6a6a6f;   /* was #86868b: 3.33:1 on the header */
    /* Was #007aff for both. It is 3.69:1 as link text on this near-white page
       and 4.02:1 under white as a button fill, so it failed in both of its
       jobs at once. One blue still does both, three steps darker. */
    --accent-color: #0069dc;
    --highlight-color: #0069dc;
    --card-bg: rgba(255, 255, 255, 0.7);
    --header-bg: rgba(245, 245, 247, 0.85);
    --button-text: #fff;
    --shadow: 0 10px 40px rgba(0, 0, 0, 0.1);
    --border-color: rgba(0, 0, 0, 0.05);
}

html.theme-5 {
    --bg-color: #fff9f0;
    --bg-gradient: linear-gradient(135deg, #fff9f0 0%, #fff0e0 100%);
    --text-color: #5c4a3f;
    --text-color-secondary: #71635a;   /* was #8d7b70: 3.61:1 on the card */
    /* An orange link on cream cannot be both vivid and readable: #ef6c00 is
       2.76:1 against this page and #ff6f00 is 2.79:1 under white. Both had to
       come down. The theme's warmth lives in --bg-gradient, which is unchanged. */
    --accent-color: #c45500;
    --highlight-color: #a94c00;
    --card-bg: rgba(255, 240, 224, 0.7);
    --header-bg: rgba(255, 249, 240, 0.85);
    --button-text: #fff;
    --shadow: 0 10px 40px rgba(92, 74, 63, 0.1);
    --border-color: rgba(92, 74, 63, 0.1);
}

html.theme-6 {
    --bg-color: #e0f7fa;
    --bg-gradient: linear-gradient(135deg, #e0f7fa 0%, #b2ebf2 100%);
    --text-color: #006064;
    /* Solving this in cyan landed on #006f7a, one step from the link colour
       below - passing, but leaving links and secondary text the same colour.
       Desaturated instead, so the saturated one is still the link. */
    --text-color-secondary: #4a6367;   /* was #00838f: 3.46:1 on the page */
    --accent-color: #008293;           /* was #00bcd4: 2.30:1 under white */
    --highlight-color: #006f7b;        /* was #0097a7: 2.68:1 as link text */
    --card-bg: rgba(255, 255, 255, 0.6);
    --header-bg: rgba(224, 247, 250, 0.85);
    --button-text: #fff;
    --shadow: 0 10px 40px rgba(0, 96, 100, 0.1);
    --border-color: rgba(0, 96, 100, 0.1);
}

html.theme-7 {
    --bg-color: #f3e5f5;
    --bg-gradient: linear-gradient(135deg, #f3e5f5 0%, #e1bee7 100%);
    --text-color: #4a148c;
    --text-color-secondary: #7b1fa2;
    --accent-color: #ab47bc;
    --highlight-color: #8823a3;   /* was #8e24aa: 4.26:1 off the card */
    --card-bg: rgba(255, 255, 255, 0.6);
    --header-bg: rgba(243, 229, 245, 0.85);
    --button-text: #fff;
    --shadow: 0 10px 40px rgba(74, 20, 140, 0.1);
    --border-color: rgba(74, 20, 140, 0.1);
}

body {
    background: var(--bg-gradient);
    background-attachment: fixed;
    /* Parallax-like effect */
    color: var(--text-color);
}

a {
    color: var(--highlight-color);
}

a:hover {
    color: var(--highlight-color);
    filter: brightness(1.2);
}

a.bible-link {
    font-weight: 600;
    color: var(--highlight-color);
    border-bottom: 2px dotted var(--highlight-color);
    text-decoration: none;
    padding: 0 2px;
    border-radius: 4px;
    transition: background-color 0.2s;
}

a.bible-link:hover {
    background-color: rgba(255, 255, 255, 0.1);
    text-decoration: none;
}

/* -------------------------------------------------------------------------- */
/*                                   Layout                                   */
/* -------------------------------------------------------------------------- */
.main-container {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 2rem 1rem;
    width: 100%;
    flex: 1;
    display: flex;
    flex-direction: column;
}

#banner-section {
    width: 100%;
    overflow: hidden;
    margin-bottom: 2rem;
    display: none;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    transition: transform 0.5s ease;
}

#banner-section:hover {
    transform: scale(1.01);
}

#banner-img {
    width: 100%;
    height: auto;
    max-height: 120px;
    object-fit: cover;
    display: block;
}

/* Sticky Glass Header */
header {
    background: var(--header-bg);
    backdrop-filter: blur(12px);
    -webkit-backdrop-filter: blur(12px);
    border-bottom: 1px solid var(--border-color);
    position: sticky;
    top: 0;
    z-index: 1000;
    padding: 1rem 0;
    margin-bottom: 2rem;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
    transition: background 0.3s;
}

.title-area {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 0 1rem;
}

.title-area h1 {
    margin: 0;
    font-size: 1.8rem;
    background: linear-gradient(90deg, var(--text-color), var(--highlight-color));
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
}

.title-buttons {
    display: flex;
    gap: 0.8rem;
    align-items: center;
}

.control-btn {
    background-color: var(--card-bg);
    /* Glassy button */
    color: var(--text-color);
    border: 1px solid var(--border-color);
    border-radius: 50%;
    width: 3rem;
    height: 3rem;
    font-size: 1.2rem;
    cursor: pointer;
    display: flex;
    justify-content: center;
    align-items: center;
    transition: all 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275);
    box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
}

.control-btn:hover {
    transform: translateY(-2px);
    background-color: var(--accent-color);
    color: var(--button-text);
    border-color: var(--accent-color);
}

.control-btn:active {
    transform: scale(0.95);
}

/* -------------------------------------------------------------------------- */
/*                               Content Grids                                */
/* -------------------------------------------------------------------------- */
.grid-menu {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 2rem;
    margin-bottom: 4rem;
}

.menu-card {
    background-color: var(--card-bg);
    backdrop-filter: blur(10px);
    padding: 2rem;
    border-radius: var(--border-radius);
    text-align: center;
    box-shadow: var(--shadow);
    transition: all 0.4s cubic-bezier(0.165, 0.84, 0.44, 1);
    border: 1px solid var(--border-color);
    display: flex;
    flex-direction: column;
    align-items: center;
    height: 100%;
}

.menu-card:hover {
    transform: translateY(-8px);
    box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2);
    border-color: var(--highlight-color);
}

.menu-card img {
    margin-bottom: 1.5rem;
    max-height: 60px;
    width: auto;
    transition: transform 0.3s;
}

.menu-card:hover img {
    transform: scale(1.1) rotate(2deg);
}

.menu-card h3 {
    margin-bottom: 0.8rem;
    color: var(--text-color);
    font-size: 1.4rem;
}

.menu-card p {
    font-size: 0.95rem;
    color: var(--text-color-secondary);
    margin: 0;
    text-align: center;
}

.menu-card p:empty {
    display: none;
}

.section-divider {
    border: 0;
    height: 1px;
    background-image: linear-gradient(to right, rgba(0, 0, 0, 0), var(--accent-color), rgba(0, 0, 0, 0));
    margin: 3rem 0;
}

/* -------------------------------------------------------------------------- */
/*                              Article List                                  */
/* -------------------------------------------------------------------------- */
.articles-list {
    display: grid;
    grid-template-columns: 1fr;
    gap: 2rem;
}

.article-item p {
    text-align: justify;
    color: var(--text-color-secondary);
}

.article-item {
    background-color: var(--card-bg);
    backdrop-filter: blur(5px);
    padding: 2rem;
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    border: 1px solid var(--border-color);
    border-left: 6px solid var(--highlight-color);
    transition: transform 0.3s;
}

.article-item:hover {
    transform: translateX(5px);
}

/* --accent-color, not a gradient from --highlight-color, and --button-text,
   not a hard-coded white. --highlight-color is the LINK colour: on the four
   dark themes it has to be light enough to read against a near-black page,
   which is exactly what makes white unreadable on top of it. The gradient's
   highlight end measured 2.18:1 on theme 0 and 1.29:1 on theme 2, against a
   4.5:1 requirement. See docs/tools/check_contrast.py. */
.read-more-btn {
    display: inline-block;
    margin-top: 1rem;
    padding: 0.6rem 2rem;
    background: var(--accent-color);
    color: var(--button-text) !important;
    border-radius: 50px;
    font-weight: 600;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    transition: all 0.3s;
    text-transform: uppercase;
    font-size: 0.85rem;
    letter-spacing: 0.5px;
}

.read-more-btn:hover {
    transform: translateY(-2px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.3);
}

/* -------------------------------------------------------------------------- */
/*                                Languages                                   */
/* -------------------------------------------------------------------------- */
.languages-grid {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin-top: 1rem;
}

.lang-link {
    font-size: 0.95rem;
    padding: 0.5rem 1.2rem;
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: 20px;
    color: var(--text-color);
    transition: all 0.2s;
}

/* Same correction as .read-more-btn: --accent-color is the palette's fill
   behind --button-text, and --highlight-color is not. */
.lang-link:hover {
    background-color: var(--accent-color);
    color: var(--button-text);
    border-color: var(--accent-color);
    transform: scale(1.05);
    text-decoration: none;
    filter: none;
}

/* -------------------------------------------------------------------------- */
/*                                Mobile specific                             */
/* -------------------------------------------------------------------------- */
@media (max-width: 768px) {
    :root {
        --font-base: 15px;
    }

    .main-container {
        padding: 1rem;
    }

    header {
        padding: 0.8rem 0;
    }

    .title-area {
        flex-direction: column;
        gap: 1rem;
        text-align: center;
    }

    .title-area h1 {
        font-size: 2rem;
    }

    .grid-menu {
        grid-template-columns: 1fr;
        gap: 1.5rem;
    }

    .control-btn {
        width: 2.8rem;
        height: 2.8rem;
    }
}

/* ========================================================================== */
/*                                                                            */
/*                       LEGACY CONTENT COMPATIBILITY LAYER                   */
/*                                                                            */
/*  Everything below styles the ~12,400 imported article pages. Those pages    */
/*  are 1997-2010 era HTML: <font color>, bgcolor attributes, layout tables,   */
/*  <center>, and TYPO3 class names. header.php wraps all of it in             */
/*  <article class="content-body">, so this section is what turns that raw     */
/*  markup into something readable inside the themed shell.                    */
/*                                                                            */
/*  Design rule: legacy colours are NEUTRALISED, not preserved. Hard-coded     */
/*  black text and pastel table backgrounds are unreadable on the dark         */
/*  themes, and there is no way to keep both them and a working theme          */
/*  switcher. Add class "legacy-colors" to <body> to opt a page back out.      */
/*  See docs/07-STYLE-AND-THEMING.md.                                          */
/* ========================================================================== */

/* -------------------------------------------------------------------------- */
/*                          Chrome added by header/footer                     */
/* -------------------------------------------------------------------------- */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    z-index: 1100;
    padding: 0.75rem 1.25rem;
    background: var(--accent-color);
    color: var(--button-text);
    border-radius: 0 0 var(--border-radius) 0;
}

.skip-link:focus {
    left: 0;
}

.site-title-link,
.site-title-link:hover {
    color: inherit;
    filter: none;
}

.site-tagline {
    text-align: center;
    margin: 0.4rem 0 0;
    font-size: 0.95rem;
    color: var(--text-color-secondary);
}

.breadcrumb {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    font-size: 0.9rem;
    margin-bottom: 1.25rem;
    padding: 0 0.25rem;
    color: var(--text-color-secondary);
}

/* AI-010. The trail runs Home / Section / every directory down to this page,
   so a crumb is now one of three things: a link, the page itself, or a folder
   with no index.php to open (554 of the 817 intermediate directories). They are
   all the same colour, so the link needs a cue that is not colour — the rule
   .retired-link already establishes for this archive. Underlined here means
   clickable; the other two are plain. No new colour is introduced, so
   check_contrast.py's 112 pairs are untouched. */
.breadcrumb a {
    color: var(--text-color-secondary);
    text-decoration: underline;
    text-underline-offset: 0.15em;
    text-decoration-thickness: 1px;
}

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

.breadcrumb-plain {
    cursor: default;
}

.site-footer {
    text-align: center;
    padding: 2rem 1rem 1rem;
    margin-top: 3rem;
    border-top: 1px solid var(--border-color);
    font-size: 0.9rem;
    color: var(--text-color-secondary);
}

.footer-nav {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.5rem 1.25rem;
    margin-bottom: 0.75rem;
}

.footer-note {
    margin: 0;
    opacity: 0.75;
    font-size: 0.85rem;
}

.debug-badge {
    position: fixed;
    bottom: 0;
    left: 0;
    width: 100%;
    padding: 4px 8px;
    background: #b00020;
    color: #fff;
    font: 12px/1.4 monospace;
    text-align: center;
    z-index: 1100;
}

/* -------------------------------------------------------------------------- */
/*                        The reading surface itself                          */
/* -------------------------------------------------------------------------- */
.content-body {
    background-color: var(--card-bg);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    padding: clamp(1.25rem, 4vw, 3rem);
    color: var(--text-color);
    overflow-wrap: break-word;
    word-wrap: break-word;
}

/* Pages that build their own card grid (the hand-made section landing pages)
   should not sit inside a second card. */
.content-body:has(> .language-content),
.content-body:has(> .grid-menu) {
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    padding: 0;
}

.content-body > :first-child {
    margin-top: 0;
}

.content-body > :last-child {
    margin-bottom: 0;
}

/* -------------------------------------------------------------------------- */
/*                          Legacy colour neutralisation                      */
/* -------------------------------------------------------------------------- */
body:not(.legacy-colors) .content-body font[color],
body:not(.legacy-colors) .content-body [text],
body:not(.legacy-colors) .content-body [link],
body:not(.legacy-colors) .content-body [vlink],
body:not(.legacy-colors) .content-body [alink] {
    color: inherit !important;
}

body:not(.legacy-colors) .content-body [bgcolor],
body:not(.legacy-colors) .content-body [background] {
    background-color: transparent !important;
    background-image: none !important;
}

body:not(.legacy-colors) .content-body font[face] {
    font-family: inherit !important;
}

/* Legacy <font size> values map onto the fluid type scale rather than the
   browser absolute 1-7 ladder, which ignores the font-size control. */
.content-body font[size="1"] {
    font-size: 0.78em;
}

.content-body font[size="2"] {
    font-size: 0.9em;
}

.content-body font[size="3"] {
    font-size: 1em;
}

.content-body font[size="4"] {
    font-size: 1.15em;
}

.content-body font[size="5"] {
    font-size: 1.35em;
}

.content-body font[size="6"] {
    font-size: 1.6em;
}

.content-body font[size="7"] {
    font-size: 1.9em;
}

/* -------------------------------------------------------------------------- */
/*                              Legacy typography                             */
/* -------------------------------------------------------------------------- */
.content-body p,
.content-body li,
.content-body dd,
.content-body td,
.content-body th {
    color: inherit;
    text-align: start;
}

.content-body p {
    margin: 0 0 1.1rem;
}

/* Imported pages use <P> as a line separator, so hundreds of them are empty. */
.content-body p:empty {
    margin: 0 0 0.6rem;
}

.content-body h1,
.content-body h2,
.content-body h3,
.content-body h4,
.content-body h5,
.content-body h6 {
    color: var(--text-color);
    margin-top: 2rem;
}

.content-body h1 {
    font-size: 2rem;
}

.content-body h2 {
    font-size: 1.6rem;
}

.content-body h3 {
    font-size: 1.3rem;
}

.content-body a {
    color: var(--highlight-color);
    text-decoration: underline;
    text-underline-offset: 0.15em;
    text-decoration-thickness: 1px;
}

/* 8%, not 18%. This wash is the ONE colour guaranteed to reduce the link's
   own contrast, because it moves the ground toward the text. At 18% it cost
   about a quarter of the ratio, so every theme's link colour would have had to
   darken to pay for a hover effect. 8% is still visible and costs ~0.1. */
.content-body a:hover {
    background-color: color-mix(in srgb, var(--highlight-color) 8%, transparent);
    border-radius: 3px;
}

/* A citation whose target is gone from the live web AND from the Internet
   Archive (AI-017, AI-024). `retire_external_links.py` turns the <a> into this
   span, keeping the editors' wording character for character and the dead
   address in the `title`.

   It INHERITS its colour deliberately, so it introduces no new foreground /
   background pair and check_contrast.py's 112 stay 112. The cue is the dotted
   underline alone: a retired citation must not look like a working link, and
   must not look like ordinary prose either - 409 of these went in on
   8 September 2026 with labels as short as "here" and "1", which without a
   cue simply read as words and hide the fact that a citation was ever there. */
.content-body .retired-link {
    text-decoration: underline dotted;
    text-underline-offset: 0.15em;
    text-decoration-thickness: 1px;
    cursor: help;
}

.content-body ul,
.content-body ol,
.content-body dir,
.content-body menu {
    margin: 0 0 1.1rem;
    padding-inline-start: 1.6rem;
}

.content-body li {
    margin-bottom: 0.4rem;
}

/* Imported pages routinely open <LI> outside any list. */
.content-body > li {
    list-style-position: inside;
    margin-inline-start: 1rem;
}

.content-body blockquote {
    margin: 1.5rem 0;
    padding: 0.75rem 1.25rem;
    border-inline-start: 3px solid var(--highlight-color);
    background-color: color-mix(in srgb, var(--highlight-color) 8%, transparent);
    border-radius: 0 8px 8px 0;
}

.content-body hr {
    border: 0;
    height: 1px;
    background-image: linear-gradient(to right, transparent, var(--border-color), transparent);
    margin: 2rem 0;
}

.content-body pre {
    overflow-x: auto;
    padding: 1rem;
    border-radius: 8px;
    background-color: color-mix(in srgb, var(--text-color) 8%, transparent);
    font-size: 0.9em;
}

.content-body code,
.content-body tt {
    font-size: 0.92em;
}

.content-body sup,
.content-body sub {
    line-height: 0;
}

.content-body center {
    display: block;
    text-align: center;
}

/* TYPO3 leftovers from the 2010 CMS export. */
.content-body .bodytext {
    margin-bottom: 1.1rem;
}

.content-body .csc-textpic-imagewrap,
.content-body .csc-textpic-clear {
    max-width: 100%;
}

.content-body .align-center,
.content-body .csc-textpic-center {
    text-align: center;
}

.content-body .news-list-container {
    list-style: none;
    padding: 0;
}

.content-body .news-list-item {
    padding: 1.25rem 0;
    border-bottom: 1px solid var(--border-color);
}

/* -------------------------------------------------------------------------- */
/*                       Legacy images and layout tables                      */
/* -------------------------------------------------------------------------- */
.content-body img {
    max-width: 100%;
    height: auto;
    border-radius: 4px;
}

/* Spacer GIFs should not pick up the rounded-corner treatment. */
.content-body img[src$="clear.gif"] {
    border-radius: 0;
}

.content-body table {
    max-width: 100%;
    border-collapse: collapse;
    margin: 0 0 1.25rem;
}

.content-body table[border="0"],
.content-body table:not([border]) {
    border: 0;
}

.content-body td,
.content-body th {
    padding: 0.4rem 0.6rem;
    vertical-align: top;
}

/* Tables that actually carry a border are treated as data tables. */
.content-body table[border]:not([border="0"]) {
    border: 1px solid var(--border-color);
}

.content-body table[border]:not([border="0"]) td,
.content-body table[border]:not([border="0"]) th {
    border: 1px solid var(--border-color);
}

/* Script.js wraps every top-level table so wide 1990s layout tables scroll
   instead of forcing the whole page sideways on a phone. */
.table-scroll {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    margin: 0 0 1.25rem;
    max-width: 100%;
}

.table-scroll > table {
    margin-bottom: 0;
}

.content-body iframe,
.content-body embed,
.content-body object,
.content-body video {
    max-width: 100%;
}

/* -------------------------------------------------------------------------- */
/*                             Right-to-left support                          */
/* -------------------------------------------------------------------------- */
/* Headings are 'Gabriela', serif at line-height 1.2 everywhere else, and
   Gabriela is a Latin-only display face — so an Arabic heading fell through to
   whatever the browser's generic serif happens to be. Measured before adding
   this: arabic/ carries 117,475 Arabic combining marks over 2,883,362 Arabic
   characters (4.07%), across 282 pages and 166 headings, so the tashkeel that
   1.2 crowds really are there. farsi/ and urdu/ are dir="rtl" too and hold
   ZERO Arabic characters between them — three pages of English listings — so
   they are unaffected either way.

   System faces only. This archive is meant to work from a USB key, and a
   webfont for one section would be a second network dependency on top of the
   one style.css already has. */
[dir="rtl"] h1,
[dir="rtl"] h2,
[dir="rtl"] h3,
[dir="rtl"] h4,
[dir="rtl"] h5,
[dir="rtl"] h6 {
    font-family: "Segoe UI", "Traditional Arabic", "Simplified Arabic",
        "Geeza Pro", "Noto Naskh Arabic", "Amiri", serif;
    line-height: 1.6;
    letter-spacing: normal;
}

[dir="rtl"] .content-body {
    text-align: right;
}

[dir="rtl"] .content-body p,
[dir="rtl"] .content-body li,
[dir="rtl"] .content-body td {
    text-align: right;
}

[dir="rtl"] .breadcrumb {
    flex-direction: row-reverse;
    justify-content: flex-end;
}

/* -------------------------------------------------------------------------- */
/*                            Landing-page helpers                            */
/* -------------------------------------------------------------------------- */
.language-content h1 {
    text-align: center;
    margin-bottom: 2rem;
}

.section-intro {
    max-width: 60ch;
    margin: 0 auto 2.5rem;
    text-align: center;
    color: var(--text-color-secondary);
}

/* The imported 2010 page kept underneath a rebuilt landing grid (AI-003).
   .content-body drops its panel when a page builds its own cards, so the
   preserved content needs the panel back — otherwise the section's own welcome
   text floats on the page background with no card behind it. */
.section-legacy {
    background-color: var(--card-bg);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    box-shadow: var(--shadow);
    padding: clamp(1.25rem, 4vw, 3rem);
    margin-top: 1rem;
}

.section-legacy > :first-child {
    margin-top: 0;
}

.section-legacy-label {
    margin: 0 0 1.5rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.95rem;
    color: var(--text-color-secondary);
}

/* -------------------------------------------------------------------------- */
/*                        Language rail (AI-009)                              */
/* -------------------------------------------------------------------------- */
/* render_language_rail() in functions.php. Deliberately a small strip and not a
   card grid: it is the same twenty links on every landing page, so it must not
   compete with the page's own content the way twenty .menu-cards did. */
.language-rail {
    margin: 3rem 0 0;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border-color);
}

.language-rail-title {
    font-size: 1rem;
    margin: 0 0 0.75rem;
    color: var(--text-color-secondary);
    font-weight: 600;
}

.language-rail ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem 0.75rem;
}

.language-rail li {
    margin: 0;
    font-size: 0.95rem;
}

.language-rail a {
    text-decoration: none;
    border-bottom: 1px solid transparent;
}

.language-rail a:hover,
.language-rail a:focus-visible {
    border-bottom-color: currentColor;
}

.language-rail-current {
    color: var(--text-color-secondary);
    font-weight: 600;
}

/* -------------------------------------------------------------------------- */
/*                     Generated directory index (AI-019)                     */
/* -------------------------------------------------------------------------- */
/* render_directory_index() in functions.php. Used on pages whose own link text
   was destroyed by the encoding bug, so it has to look like what it is: a
   listing the site generated, not the page the reader was expecting. */
.dir-index-note {
    color: var(--text-color-secondary);
    font-size: 0.95rem;
    max-width: 70ch;
}

.dir-index-list {
    list-style: none;
    padding: 0;
    margin: 1.5rem 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    gap: 0.5rem;
}

.dir-index-list li {
    margin: 0;
}

.dir-index-list a {
    display: block;
    padding: 0.7rem 0.9rem;
    border: 1px solid var(--border-color);
    border-radius: 10px;
    text-decoration: none;
    transition: border-color 0.2s, background-color 0.2s;
}

.dir-index-list a:hover,
.dir-index-list a:focus-visible {
    border-color: var(--highlight-color);
    background-color: color-mix(in srgb, var(--highlight-color) 8%, transparent);
}

.dir-index-list .dir-index-dir a::after {
    content: " \2192";
}

/* A file name is shown only where the page's title did not survive. It is
   deliberately styled as a file name so it never reads as a title. */
.dir-index-file {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.9em;
    color: var(--text-color-secondary);
    word-break: break-all;
}

.dir-index-back {
    margin-bottom: 0;
    font-size: 0.95rem;
}

/* Group heading in the deep listing used by chinese/project/*_index.php. The
   folder name is all the label there is: those topic folders never had a
   readable name, so nothing is claimed about what a topic contains. */
.dir-index-group {
    margin: 2rem 0 0.5rem;
    font-size: 1.05rem;
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    color: var(--text-color-secondary);
    border-bottom: 1px solid var(--border-color);
    padding-bottom: 0.4rem;
}

.dir-index-count {
    font-family: inherit;
    font-weight: normal;
    opacity: 0.7;
}

/* -------------------------------------------------------------------------- */
/*                                   Print                                    */
/* -------------------------------------------------------------------------- */
@media print {

    header,
    .breadcrumb,
    .site-footer,
    .title-buttons,
    #back-to-top,
    #reading-progress-bar,
    #banner-section,
    .noprint {
        display: none !important;
    }

    body {
        background: #fff !important;
        color: #000 !important;
    }

    .content-body {
        background: none !important;
        border: 0 !important;
        box-shadow: none !important;
        padding: 0 !important;
        color: #000 !important;
    }

    .content-body a {
        color: #000 !important;
    }
}

/* -------------------------------------------------------------------------- */
/*                              Motion preferences                            */
/* -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {

    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* -------------------------------------------------------------------------- */
/*                          Mobile: legacy content                            */
/* -------------------------------------------------------------------------- */
@media (max-width: 768px) {
    .content-body {
        padding: 1.1rem;
        border-radius: 12px;
    }

    .content-body h1 {
        font-size: 1.6rem;
    }

    .content-body h2 {
        font-size: 1.35rem;
    }

    .footer-nav {
        gap: 0.4rem 0.9rem;
    }
}

/* The home page and the hand-built language landing pages lay out their own
   card grids, so they opt out of the reading-surface panel. */
body.page-home .content-body {
    background: none;
    border: 0;
    box-shadow: none;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    padding: 0;
}

/* -------------------------------------------------------------------------- */
/*                       Missing-content notice (AI-004)                      */
/* -------------------------------------------------------------------------- */
/* Shown by render_missing_content() on the 72 pages whose text did not survive
   the import. Deliberately looks like a notice, not like an article, so nobody
   mistakes it for the page's real content. */
.missing-content {
    border: 1px dashed var(--border-color);
    border-inline-start: 4px solid var(--highlight-color);
    border-radius: 10px;
    padding: 1.5rem clamp(1rem, 3vw, 2rem);
    background-color: color-mix(in srgb, var(--highlight-color) 6%, transparent);
}

.missing-content h2 {
    margin-top: 0;
    font-size: 1.35rem;
}

.missing-content p {
    color: var(--text-color-secondary);
}

.missing-content ul {
    margin-bottom: 0;
}

/* Shown by render_archived_notice() on the nine pages that ARE the obsolete
   thing (AI-024 §3.2-3.3): the CD order forms, the CD update zipfiles, the
   BitTorrent links, the 1996 internet-forums list. The preserved page follows
   it in the same panel, so this must read as a banner over that page and not
   as another article. Solid border where .missing-content is dashed: the two
   notices mean different things - "the text was lost" versus "the text is
   intact and no longer true" - and should not be mistaken for each other. */
.archived-notice {
    border: 1px solid var(--border-color);
    border-inline-start: 4px solid var(--highlight-color);
    border-radius: 10px;
    padding: 1.5rem clamp(1rem, 3vw, 2rem);
    margin-bottom: 2rem;
    background-color: color-mix(in srgb, var(--highlight-color) 10%, transparent);
}

.archived-notice h2 {
    margin-top: 0;
    font-size: 1.3rem;
}

.archived-notice p {
    color: var(--text-color-secondary);
}

.archived-notice ul {
    margin-bottom: 0;
}

/* Separates the banner from the page it is about. */
.archived-notice-label {
    margin: 0 0 1.5rem;
    padding-bottom: 0.75rem;
    border-bottom: 1px solid var(--border-color);
    font-size: 0.95rem;
    color: var(--text-color-secondary);
}

/* -------------------------------------------------------------------------- */
/*                            Search page (AI-008)                            */
/* -------------------------------------------------------------------------- */
/* search.php only. It is a hand-built page, not imported markup, so nothing
   here needs the .content-body scoping the legacy layer uses. No colour is
   hard-coded: every one comes from the active theme block. */

.search-heading {
    margin-top: 0;
}

.search-form {
    margin-bottom: 2rem;
}

/* The visible <label> would only repeat the heading above it, but a search
   field still needs a name for a screen reader. */
.search-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.search-row {
    display: flex;
    gap: 0.75rem;
    flex-wrap: wrap;
}

.search-row input[type="search"] {
    flex: 1 1 18rem;
    min-inline-size: 0;
    padding: 0.75rem 1rem;
    font-size: 1.05rem;
    font-family: inherit;
    color: var(--text-color);
    background-color: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    transition: border-color var(--trans-speed);
}

.search-row input[type="search"]:focus {
    outline: none;
    border-color: var(--highlight-color);
}

.search-row button {
    padding: 0.75rem 1.75rem;
    font-size: 1.05rem;
    font-family: inherit;
    color: var(--button-text);
    background-color: var(--accent-color);
    border: 1px solid var(--border-color);
    border-radius: var(--border-radius);
    cursor: pointer;
    transition: background-color var(--trans-speed);
}

/* The hover state used to swap the fill to --highlight-color while keeping
   --button-text on top, which fails AA on seven of the eight themes for the
   reason given at .read-more-btn. A ring says "hover" without disturbing the
   one text/background pair on this button that is measured to pass. */
.search-row button:hover {
    border-color: var(--highlight-color);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--highlight-color) 30%, transparent);
}

.search-scope,
.search-note,
.search-summary {
    margin-top: 0.75rem;
    color: var(--text-color-secondary);
    font-size: 0.95rem;
}

.search-notice {
    border: 1px dashed var(--border-color);
    border-inline-start: 4px solid var(--highlight-color);
    border-radius: 10px;
    padding: 1.25rem clamp(1rem, 3vw, 1.75rem);
    background-color: color-mix(in srgb, var(--highlight-color) 6%, transparent);
}

.search-notice h3 {
    margin-top: 0;
}

.search-notice pre {
    overflow-x: auto;
}

/* Results are an <ol> so the numbering is real: it survives paging, and a
   screen reader announces "3 of 10" without any ARIA. */
.search-results {
    padding-inline-start: 2.5rem;
    margin: 1.5rem 0;
}

.search-result {
    margin-bottom: 1.75rem;
}

.search-result h3 {
    margin: 0 0 0.35rem;
    font-size: 1.2rem;
    line-height: 1.35;
}

.search-snippet {
    margin: 0 0 0.35rem;
    color: var(--text-color-secondary);
}

/* 25%, not 35%. Same self-defeating shape as the link hover, and deeper: at
   35% a marked term measured 3.56:1 on theme 2, 4.39 on theme 3 and 4.49 on
   theme 6 - the search hit was the least readable text on the results page.
   Fixing it in the palette instead would have meant moving four themes' BODY
   text colour to suit one highlighter, which is the tail wagging the dog. */
.search-snippet mark,
.search-result h3 mark {
    color: var(--text-color);
    background-color: color-mix(in srgb, var(--highlight-color) 25%, transparent);
    border-radius: 3px;
    padding: 0 2px;
}

.search-path {
    margin: 0;
    font-size: 0.85rem;
    color: var(--text-color-secondary);
}

.search-section {
    color: var(--highlight-color);
}

.search-section::after {
    content: " · ";
    color: var(--text-color-secondary);
}

.search-file {
    /* Paths are read character by character, so they need a monospace face and
       must be able to wrap: some are 80 characters long. */
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    overflow-wrap: anywhere;
}

.search-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1.5rem;
    margin: 2rem 0;
}

.search-pager-off {
    color: var(--text-color-secondary);
    opacity: 0.5;
}

.search-elsewhere {
    margin-top: 3rem;
    padding-top: 1.5rem;
    border-top: 1px solid var(--border-color);
    font-size: 0.95rem;
    color: var(--text-color-secondary);
}

/* -------------------------------------------------------------------------- */
/*                                 UI Widgets                                 */
/* -------------------------------------------------------------------------- */
/* The reading progress bar and the back-to-top button. Script.js creates both
   elements, but their appearance belongs here.

   These rules lived inside create_scroll_widgets() as a 45-line template
   literal appended to document.head on every page load. Moving them is
   Gemini_Code_Audit.md section 3.5, and its stated reason - a Content Security
   Policy would refuse the injected <style> - is not a live problem: measured on
   5 September 2026 no CSP is served by the live host, none is set in .htaccess
   and none is emitted by any PHP file. It is worth doing anyway for the reason
   the same section gives second: this is stylesheet content, so it belongs in
   the cached stylesheet rather than being rebuilt from a string on each of
   12,474 pages. */

#reading-progress-bar {
    position: fixed;
    top: 0;
    left: 0;
    height: 4px;
    background: var(--highlight-color);
    width: 0%;
    z-index: 1002;
    transition: width 0.1s;
}

#back-to-top {
    position: fixed;
    bottom: 30px;
    inset-inline-end: 30px;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    background: var(--accent-color);
    color: var(--button-text);
    border: none;
    font-size: 1.5rem;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
    cursor: pointer;
    opacity: 0;
    visibility: hidden;
    transform: translateY(20px);
    transition: all 0.3s;
    z-index: 1001;
    display: flex;
    align-items: center;
    justify-content: center;
}

#back-to-top.visible {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
}

#back-to-top:hover {
    transform: scale(1.1);
    filter: brightness(1.2);
}
