/* Pre-rendered document pages under /cours/ (scripts/prerenderDocs.js).
   Mirrors the in-app viewer (page.css) and the logged-out header
   (.public-mode-header in main.css) as a normal scrolling page, without the
   viewer's fixed-position sheet, swipe handling, or toolbar. */

:root {
    --ui-font: 'IBM Plex Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

    /* The key surface, in literal values. These rules were written against
       landing.css's tokens — --card, --key-shadow, --text, --accent — on a
       page that does not load landing.css, so every one resolved to nothing:
       no background, no shadow, and three header buttons rendering as blue
       underlined links. A stylesheet may only use tokens it can see. */
    --sd-accent: #a0da00;
    --sd-accent-hi: #b4f000;
    --sd-card: rgba(255, 255, 255, 0.06);
    --sd-card-hi: rgba(255, 255, 255, 0.1);
    --sd-key-shadow: 0 4px 0 rgba(0, 0, 0, 0.25),
                     0 0 32px inset rgba(255, 255, 255, 0.05),
                     0 0 3px inset rgba(255, 255, 255, 0.1);
    --sd-key-shadow-down: 0 1px 0 rgba(0, 0, 0, 0.25),
                          0 0 32px inset rgba(255, 255, 255, 0.05),
                          0 0 3px inset rgba(255, 255, 255, 0.1);
}

html {
    background: #1a1a24;
}

/* The starfield the application runs behind its subject views, reused as the
   page's own ground. It hooks #graph-view by id and inserts a WebGL canvas
   into it, so the page gives it that container as a fixed layer and paints
   the gradient here — the body's flat colour would otherwise sit on top of it.
   Everything that has to be read keeps its own surface above this. */
.sd-starfield {
    position: fixed;
    inset: 0;
    z-index: 0;
    pointer-events: none;
    background: linear-gradient(160deg, #0a0a12 0%, #12121f 40%, #1a1a28 70%, #0d1117 100%);
}

body.static-doc {
    margin: 0;
    min-height: 100vh;
    background: #1a1a24;
    color: rgba(255, 255, 255, 0.9);
    font-family: CMSerif, 'Times New Roman', serif;
    -webkit-font-smoothing: antialiased;
}

/* ---- header ----------------------------------------------------------- */

.sd-header {
    position: sticky;
    top: 0;
    z-index: 50;
    min-height: 56px;
    box-sizing: border-box;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: env(safe-area-inset-top, 0px) 20px 0;
    background: linear-gradient(165deg, rgba(38, 38, 52, 0.95) 0%, rgba(28, 28, 40, 0.95) 100%);
    backdrop-filter: blur(16px);
    -webkit-backdrop-filter: blur(16px);
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.sd-logo {
    display: flex;
    align-items: center;
    gap: 14px;
    color: rgba(255, 255, 255, 0.9);
    text-decoration: none;
}

.sd-logo img {
    width: 26px;
    height: 26px;
    filter: invert(1) brightness(2);
}

/* The wordmark is set in Computer Modern, as on the landing page
   (.brand-name in landing.css). CMSerif.css is loaded on every /cours/ page;
   the sans --ui-font is not, so the wordmark used to fall back to the
   system font. */
.sd-logo span {
    font-family: CMSerif, 'Latin Modern Roman', 'Times New Roman', serif;
    font-weight: bold;
    font-size: 16px;
    letter-spacing: 0.34em;
}

.sd-actions {
    display: flex;
    align-items: center;
    gap: 10px;
}





/* static-doc.js adds .sd-logged-in when a session exists */

body.sd-logged-in .sd-btn.sd-login,
body.sd-logged-in .sd-btn.sd-register {
    display: none;
}

body.sd-logged-in .sd-btn.sd-app {
    display: inline-flex;
}

/* ---- page ------------------------------------------------------------- */

.sd-main {
    max-width: 860px;
    margin: 0 auto;
    padding: 16px 20px 56px;
    box-sizing: border-box;
}




.sd-page {
    background: rgba(30, 30, 30, 0.85);
    border: 1px solid rgba(255, 255, 255, 0.1);
    border-radius: 16px;
    box-shadow: 0 0 4px inset rgba(100, 100, 100, 0.2), 0 0 56px inset rgba(100, 100, 100, 0.1);
    padding: 32px 40px;
    /* Section numbering (document.css) increments this counter from a
       ::before pseudo-element, so it needs a declaring ancestor — in the app
       that's .page-wrapper > .page (page.css). Without it every sous-section
       reads "0.1". */
    counter-reset: section;
}

.sd-page-header {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 12px 16px;
    margin-bottom: 1.5rem;
    padding-bottom: 1rem;
    border-bottom: 1px solid rgba(255, 255, 255, 0.1);
}

.sd-page-header-title {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 16px;
    min-width: 0;
}

.sd-page-title {
    font-size: 1.8em;
    font-weight: bold;
    margin: 0;
    color: white;
}

/* same as .page .doc-type-tag */
.sd-doc-type-tag {
    font-family: CMSerif, 'Times New Roman', serif;
    display: inline-block;
    font-size: 0.7rem;
    font-variant: small-caps;
    letter-spacing: 0.1em;
    color: rgba(160, 218, 0, 0.9);
    border-radius: 10px;
    padding: 4px 12px;
    white-space: nowrap;
    background: rgba(22, 131, 0, 0.337);
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    box-shadow: 0 0 32px inset rgba(255, 255, 255, 0.05), 0 0 3px inset rgba(255, 255, 255, 0.1);
}

.sd-open-link {
    font-family: var(--ui-font);
    font-size: 13px;
    color: rgba(160, 218, 0, 0.9);
    text-decoration: none;
    white-space: nowrap;
}

.sd-open-link:hover {
    text-decoration: underline;
}

.sd-subtitle {
    margin: -0.75rem 0 1.25rem;
    font-size: 1.1em;
    color: rgba(255, 255, 255, 0.6);
}

.sd-page .parser-output {
    line-height: 1.6;
    font-size: 16px;
}

/* same as .page .sketch-placeholder */
.sd-page .sketch-placeholder {
    position: relative;
    width: 100%;
    background: transparent;
    border-radius: 12px;
    margin: 1.5em 0;
}

.sd-page .sketch-placeholder canvas {
    display: block;
    position: relative;
    z-index: 1;
    pointer-events: auto;
}

.sd-page .sketch-placeholder .sketch-loading {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    color: rgba(255, 255, 255, 0.5);
    font-size: 14px;
}

.sd-page .sketch-error {
    font-family: var(--ui-font);
    font-size: 13px;
    color: rgba(255, 255, 255, 0.45);
}

/* @reponse(...) fallback (static-doc.js) */
.sd-page .sd-answer-in-app {
    margin: 0.5rem 0 0;
    font-family: var(--ui-font);
    font-size: 13px;
    color: rgba(255, 255, 255, 0.55);
}

.sd-page .sd-answer-in-app a {
    color: rgba(160, 218, 0, 0.9);
}

/* ---- end-of-preview call to action ----------------------------------- */

/* ---- the gate ----------------------------------------------------------
   Not a card sitting on the page: the page itself, torn across and continued
   in another colour. A bordered box reads as an advertisement dropped into
   the document — something to scroll past. A change of paper reads as the
   document stopping, which is what has actually happened.

   So it breaks out of the page's padding to the full width, is separated by
   one hairline rather than a border, and runs to the bottom: there is nothing
   after it, and it should not pretend there is. */

.sd-gate {
    position: relative;
    margin: 2.5rem -24px -24px;          /* out through the page's padding */
    padding: 40px 24px 56px;
    text-align: center;
    background: rgba(160, 218, 0, 0.06);
    border-top: 1px solid rgba(160, 218, 0, 0.16);
    border-radius: 0 0 15px 15px;        /* follows the page's own corners */
    flex: 1 1 auto;                      /* fills whatever height is left */
}

/* The gate is a panel laid over the document, and it casts a shadow upward
   onto the last lines. It used to be a gradient toward the page's own colour,
   which reads as the text dissolving — as though the document were damaged
   rather than merely continuing behind something. A shadow says the opposite:
   the content is intact, there is simply a wall in front of it.

   Being a shadow, it is black in both themes and only the strength changes;
   the old ramp had to be rewritten per theme because it was impersonating a
   background. */
.sd-gate {
    box-shadow: 0 -16px 28px -12px rgba(0, 0, 0, 0.5);
}

.theme-light .sd-gate {
    box-shadow: 0 -16px 28px -14px rgba(0, 0, 0, 0.22);
}

/* Nothing was hidden, so nothing needs fading into. */
/* Nothing was hidden, so there is nothing to cast a shadow onto. */
.sd-gate.sd-gate-only { box-shadow: none; }

/* Both gates wear the house colour. It was blue for the subscriber one at
   first, on the argument that lime means « free » here — but lime is the
   brand before it is a signal, and two different-coloured walls read as two
   different products rather than as one. The wording carries the difference
   instead. */

.sd-gate h2 {
    margin: 0 0 10px;
    font-size: 1.3rem;
}

.sd-gate p {
    margin: 0 auto 22px;
    max-width: 44ch;
    color: var(--dim, rgba(255, 255, 255, 0.6));
    line-height: 1.6;
}

/* The page is a column so the tear can claim the space below the text. */
.static-doc .page-wrapper > .page {
    display: flex;
    flex-direction: column;
}

.static-doc .page > .parser-output { flex: 0 0 auto; }

@media (max-width: 600px) {
    .sd-gate {
        margin-left: -16px;
        margin-right: -16px;
        margin-bottom: 0;
        border-radius: 0;
    }

    /* page.css reserves 100px of bottom padding here — « extra scroll room »
       for the sheet, above the application's bottom bar. There is no bottom
       bar on a static page, and the room is already provided by the wrapper,
       which is sized to the footer. Left in, it showed as a hundred pixels of
       blank page hanging below the gate: the tear stopped, and the sheet
       carried on underneath it. */
    .static-doc .page-wrapper > .page { padding-bottom: 0; }
}

/* ---- other documents of the chapter ---------------------------------- */

.sd-siblings {
    margin-top: 2rem;
    padding-top: 1.25rem;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
    font-family: var(--ui-font);
}

.sd-siblings h2 {
    margin: 0 0 10px;
    font-size: 12px;
    font-weight: 500;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: rgba(255, 255, 255, 0.45);
}

.sd-siblings ul {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.sd-siblings li {
    margin: 0;
}

.sd-siblings a {
    display: inline-block;
    padding: 6px 12px;
    border-radius: 8px;
    font-size: 14px;
    background: rgba(255, 255, 255, 0.06);
    color: rgba(255, 255, 255, 0.85);
    text-decoration: none;
}

.sd-siblings a:hover {
    background: rgba(255, 255, 255, 0.1);
}

.sd-siblings a[aria-current="page"] {
    background: rgba(160, 218, 0, 0.14);
    color: rgba(160, 218, 0, 0.95);
}

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

.sd-footer {
    max-width: 860px;
    margin: 0 auto;
    padding: 0 20px calc(40px + env(safe-area-inset-bottom, 0px));
    box-sizing: border-box;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 8px 18px;
    font-family: var(--ui-font);
    font-size: 13px;
}

.sd-footer a {
    color: rgba(255, 255, 255, 0.5);
    text-decoration: none;
}

.sd-footer a:hover {
    color: rgba(255, 255, 255, 0.85);
}

/* ---- narrow screens --------------------------------------------------- */

@media (max-width: 600px) {
    .sd-header {
        padding-left: 12px;
        padding-right: 12px;
    }

    .sd-btn {
        padding: 6px 10px;
        font-size: 12px;
    }

    /* one account button in the header on a phone; the gate keeps both */
    .sd-header .sd-btn.sd-login {
        display: none;
    }

    .sd-main {
        padding: 10px 10px 40px;
    }

    .sd-page {
        padding: 20px 16px;
        border-radius: 14px;
    }

    .sd-page-title {
        font-size: 1.45em;
    }

    /* same tightening as page.css at this width (excludes the padding-less
       text blocks and headings, which document.css keeps at 0) */
    .sd-page .block:not(.texte.block, .section.block, .sous-section.block, .sous-sous-section) {
        padding: 15px;
    }

    .sd-logo {
        gap: 11px;
    }

    .sd-logo img {
        width: 22px;
        height: 22px;
    }

    .sd-logo span {
        font-size: 14px;
        letter-spacing: 0.28em;
    }
}

/* ==== /cours/ index ======================================================
   Follows the landing page (landing.css): its tokens, Hanken Grotesk, key
   surfaces. Kept after the narrow-screen block above so these rules win over
   the document-page sizes there. Tokens are copied, not imported: landing.css
   also lays out the whole landing page. */

html:has(> body.sd-hub-page) {
    background: #151515;
}

body.sd-hub-page {
    --bg: #151515;
    --card: rgba(255, 255, 255, 0.05);
    --card-hi: rgba(255, 255, 255, 0.08);
    --text: rgba(255, 255, 255, 0.9);
    --muted: rgba(255, 255, 255, 0.55);
    --faint: rgba(255, 255, 255, 0.34);
    --hair: rgba(255, 255, 255, 0.1);
    --accent: #a0da00;
    --accent-hi: color-mix(in oklab, #a0da00 82%, #ffffff);
    --key-shadow: 0 4px 0 rgba(0, 0, 0, 0.25), 0 0 32px inset rgba(255, 255, 255, 0.05), 0 0 3px inset rgba(255, 255, 255, 0.1);
    --key-shadow-down: 0 2px 0 rgba(0, 0, 0, 0.25), 0 0 32px inset rgba(255, 255, 255, 0.05), 0 0 3px inset rgba(255, 255, 255, 0.1);
    --ui-font: 'Hanken Grotesk', system-ui, -apple-system, sans-serif;
    --wrap: 1120px;
    --gutter: max(20px, calc((100% - var(--wrap)) / 2 + 40px));
    background: var(--bg);
    color: var(--text);
    font-family: var(--ui-font);
}

/* ---- header: landing bar and key buttons ---- */

.sd-hub-page .sd-header {
    min-height: 64px;
    padding-left: var(--gutter);
    padding-right: var(--gutter);
    background: rgba(10, 10, 10, 0.72);
    backdrop-filter: blur(20px) saturate(1.2);
    -webkit-backdrop-filter: blur(20px) saturate(1.2);
    border-bottom-color: var(--hair);
}

.sd-header .sd-btn,
.sd-header .fold-button,
.sd-hub-page .sd-btn {
    display: inline-flex;
    align-items: center;
    padding: 8px 16px;
    margin: 0;
    border-radius: var(--border-radius, 8px);
    font-family: var(--ui-font);
    font-size: 0.92rem;
    text-decoration: none;          /* these are links wearing a button */
    color: rgba(255, 255, 255, 0.85);
    background: var(--sd-card);
    border: 0;
    border-top: 1px solid rgba(255, 255, 255, 0.15);
    box-shadow: var(--sd-key-shadow);
    transition: transform 0.1s ease, box-shadow 0.1s ease, background 0.15s ease;
}

.sd-header .sd-btn:hover,
.sd-header .fold-button:hover,
.sd-hub-page .sd-btn:hover {
    background: var(--sd-card-hi);
    color: #fff;
}

.sd-header .sd-btn:active,
.sd-header .fold-button:active,
.sd-hub-page .sd-btn:active {
    transform: translateY(3px);
    box-shadow: var(--sd-key-shadow-down);
}

.sd-header .sd-btn-primary,
.sd-hub-page .sd-btn.sd-register {
    color: #10160a;
    font-weight: 500;
    background: var(--sd-accent);
    border-top-color: rgba(255, 255, 255, 0.35);
    box-shadow: 0 4px 0 rgba(58, 80, 0, 0.55),
                0 0 32px inset rgba(255, 255, 255, 0.12),
                0 0 3px inset rgba(255, 255, 255, 0.18);
}

.sd-header .sd-btn-primary:hover {
    background: var(--sd-accent-hi);
    color: #10160a;
}

.sd-hub-page .sd-btn.sd-register:hover {
    background: var(--sd-accent-hi);
    opacity: 1;
}

/* ---- page ---- */

.sd-hub-page .sd-main {
    max-width: var(--wrap);
    padding: 72px 40px 0;
}

.sd-page.sd-hub {
    padding: 0;
    background: none;
    border: 0;
    border-radius: 0;
    box-shadow: none;
}

.sd-hub-head {
    max-width: 700px;
}

.sd-kicker {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 18px;
    font-size: 0.8rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--sd-accent);
}

.sd-kicker::before {
    content: '';
    width: 22px;
    height: 1px;
    background: var(--sd-accent);
}

.sd-hub .sd-page-title {
    margin: 0 0 18px;
    font-family: var(--ui-font);
    font-size: clamp(2.1rem, 4.4vw, 3rem);
    font-weight: 700;
    line-height: 1.1;
    letter-spacing: -0.015em;
    color: #fff;
    text-wrap: balance;
}

.sd-hub-intro {
    margin: 0;
    font-size: 1.15rem;
    line-height: 1.65;
    color: var(--muted);
}

.sd-hub-legend {
    display: grid;
    gap: 10px;
    margin: 26px 0 0;
    padding: 0;
    list-style: none;
    font-size: 0.98rem;
    color: var(--muted);
}

.sd-hub-legend li {
    display: grid;
    grid-template-columns: 7.5rem 1fr;
    align-items: baseline;
}

.sd-hub-legend b {
    font-weight: 600;
    color: var(--text);
}

.sd-jumps {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
    margin-top: 30px;
}

.sd-jump {
    display: inline-flex;
    align-items: baseline;
    gap: 10px;
    padding: 7px 14px;
    border-radius: 999px;
    font-size: 0.92rem;
    color: var(--text);
    text-decoration: none;
    background: rgba(255, 255, 255, 0.05);
    border-top: 1px solid rgba(255, 255, 255, 0.12);
    transition: background 0.15s ease, transform 0.1s ease;
}

.sd-jump span {
    color: var(--faint);
    font-variant-numeric: tabular-nums;
}

.sd-jump:hover {
    background: rgba(255, 255, 255, 0.1);
    transform: translateY(-1px);
}

/* ---- subjects and chapter cards ---- */

.sd-subject {
    margin-top: 72px;
    scroll-margin-top: 96px;
}

.sd-subject-head {
    display: flex;
    align-items: baseline;
    gap: 14px;
    margin-bottom: 22px;
    padding-bottom: 14px;
    border-bottom: 1px solid var(--hair);
}

.sd-subject-head h2 {
    margin: 0;
    font-family: var(--ui-font);
    font-size: 1.65rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: #fff;
}

.sd-subject-count {
    font-size: 0.95rem;
    color: var(--faint);
}

.sd-card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    gap: 18px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.sd-card {
    display: flex;
    flex-direction: column;
    gap: 14px;
    margin: 0;
    padding: 20px 18px 16px;
    border-radius: 14px;
    background: var(--sd-card);
    border-top: 1px solid rgba(255, 255, 255, 0.13);
    box-shadow: var(--sd-key-shadow);
}

.sd-card-open {
    border-top-color: rgba(160, 218, 0, 0.4);
}

.sd-card-wide {
    grid-column: 1 / -1;
}

.sd-card-title {
    margin: 0 2px;
    font-family: var(--ui-font);
    font-size: 1.18rem;
    font-weight: 600;
    line-height: 1.3;
    color: #fff;
}

.sd-doc-list {
    display: grid;
    gap: 6px;
    margin: 0;
    padding: 0;
    list-style: none;
}

.sd-card-wide .sd-doc-list {
    grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
    column-gap: 18px;
}

.sd-doc-list li {
    margin: 0;
}

.sd-doc {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 9px 12px;
    border-radius: 8px;
    font-size: 0.98rem;
    line-height: 1.35;
    color: var(--text);
    text-decoration: none;
    background: rgba(255, 255, 255, 0.03);
    transition: background 0.15s ease, color 0.15s ease;
}

.sd-doc::after {
    content: '→';
    color: var(--faint);
    transition: transform 0.2s ease, color 0.15s ease;
}

.sd-doc:hover {
    color: #fff;
    background: rgba(255, 255, 255, 0.08);
}

.sd-doc:hover::after {
    color: var(--sd-accent);
    transform: translateX(3px);
}

.sd-doc-name {
    flex: 1;
    min-width: 0;
}

/* tier badges: only "Accès libre" is lit, the preview state stays quiet */
.sd-tier {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    flex: none;
    font-size: 0.8rem;
    font-variant: small-caps;
    letter-spacing: 0.04em;
    white-space: nowrap;
}

.sd-tier::before {
    content: '';
    width: 6px;
    height: 6px;
    border-radius: 50%;
    flex: none;
}

.sd-tier-public {
    color: var(--sd-accent);
}

.sd-tier-public::before {
    background: var(--sd-accent);
    box-shadow: 0 0 7px rgba(160, 218, 0, 0.7);
}

.sd-tier-registered {
    color: var(--faint);
}

.sd-tier-registered::before {
    box-shadow: inset 0 0 0 1px var(--faint);
}

/* Quieter still than the preview badge. The subscriber documents are the bulk
   of the catalogue, so a lit badge on each would make the hub read as a price
   list rather than as a table of contents. */
.sd-tier-paid {
    color: var(--faint);
    opacity: 0.72;
}

.sd-tier-paid::before {
    box-shadow: inset 0 0 0 1px var(--faint);
    opacity: 0.6;
}

/* ---- closing call to action ---- */

.sd-hub-cta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 24px 40px;
    margin-top: 80px;
    padding: 32px 36px;
    border-radius: 16px;
    background: linear-gradient(135deg, rgba(160, 218, 0, 0.09) 0%, rgba(160, 218, 0, 0.02) 100%);
    border: 1px solid rgba(160, 218, 0, 0.2);
}

.sd-hub-cta h2 {
    margin: 0 0 8px;
    font-family: var(--ui-font);
    font-size: 1.45rem;
    font-weight: 700;
    color: #fff;
}

.sd-hub-cta p {
    max-width: 56ch;
    margin: 0;
    line-height: 1.6;
    color: var(--muted);
}

.sd-hub-cta-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px 22px;
}

.sd-hub-cta .sd-btn {
    padding: 12px 22px;
    font-size: 1rem;
}

.sd-hub-cta-link {
    font-size: 0.98rem;
    color: var(--text);
    text-decoration: none;
}

.sd-hub-cta-link:hover {
    color: var(--sd-accent);
}

/* ---- footer: the landing's ---- */

.sd-hub-page .sd-footer {
    max-width: none;
    margin-top: 96px;
    padding: 48px var(--gutter) calc(48px + env(safe-area-inset-bottom, 0px));
    align-items: center;
    justify-content: space-between;
    gap: 28px 40px;
    background: #0b0b0b;
    border-top: 1px solid var(--hair);
}

.sd-footer-brand {
    display: flex;
    align-items: center;
    gap: 14px;
}

.sd-footer-brand img {
    width: 34px;
    height: 34px;
    filter: invert(1) brightness(2);
}

.sd-footer-name {
    font-family: CMSerif, 'Latin Modern Roman', 'Times New Roman', serif;
    font-size: 15px;
    font-weight: bold;
    letter-spacing: 0.3em;
    color: var(--text);
}

.sd-footer-motto {
    font-size: 0.9rem;
    font-style: italic;
    color: var(--muted);
}

.sd-footer-links {
    display: flex;
    flex-wrap: wrap;
    gap: 8px 22px;
}

.sd-hub-page .sd-footer a {
    font-size: 0.9rem;
    color: var(--faint);
}

.sd-hub-page .sd-footer a:hover {
    color: var(--muted);
}

/* ---- focus and motion ---- */

.sd-hub-page a:focus-visible {
    outline: 2px solid var(--sd-accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    .sd-hub-page .sd-btn,
    .sd-jump,
    .sd-doc,
    .sd-doc::after {
        transition: none;
    }

    .sd-hub-page .sd-btn:active,
    .sd-jump:hover,
    .sd-doc:hover::after {
        transform: none;
    }
}

/* ---- narrow screens ---- */

@media (max-width: 700px) {
    .sd-hub-page .sd-btn {
        padding: 7px 12px;
        font-size: 0.85rem;
    }

    .sd-hub-page .sd-main {
        padding: 40px 16px 0;
    }

    .sd-hub .sd-page-title {
        font-size: 2rem;
    }

    .sd-hub-intro {
        font-size: 1.05rem;
    }

    .sd-hub-legend li {
        grid-template-columns: 1fr;
        gap: 2px;
    }

    .sd-subject {
        margin-top: 52px;
    }

    .sd-card-grid,
    .sd-card-wide .sd-doc-list {
        grid-template-columns: 1fr;
    }

    .sd-card-grid {
        gap: 14px;
    }

    .sd-card {
        padding: 16px 12px 12px;
    }

    .sd-hub-cta {
        margin-top: 56px;
        padding: 24px 20px;
    }

    .sd-hub-page .sd-footer {
        flex-direction: column;
        align-items: flex-start;
        margin-top: 64px;
        padding-left: 20px;
        padding-right: 20px;
    }
}


/* ---- the static shell ------------------------------------------------- */
/* The page is built from the application's own CSS: main.css for the sidebars,
   page.css for the document column. What remains here is only what a page with
   no session needs — the panels pinned open, and anchors where the app has
   click handlers. */

/* In the app these list items are <li> with a JS handler, so they carry all
   the styling and there is no <a> to fight with. A static page needs real
   links, and a real link arrives blue and underlined: neutralise it and let
   the item's own rules show through. */
.sd-static-sidebar .sidebar-nav a,
.sd-static-chapter .document-list a,
.sd-static-chapter .sections-list a {
    color: inherit;
    text-decoration: none;
    display: block;
    width: 100%;
}

/* The whole row is the target, not the words in it: the padding moves from
   the item to the link so there is no dead border around the text. */
.sd-static-sidebar .sidebar-nav li,
.sd-static-chapter .document-list li {
    padding: 0;
}

.sd-static-sidebar .sidebar-nav a,
.sd-static-sidebar .sidebar-nav li.sd-locked-nav {
    padding: 12px 20px;
    /* The application's items are <li> with the icon and label side by side.
       Wrapping them in a link made the anchor a block and stacked the two, so
       « Se connecter » wore its icon like a hat. */
    display: flex;
    align-items: center;
}
.sd-static-chapter .document-list a { padding: 12px 16px; }

.sd-static-sidebar .sidebar-logo { text-decoration: none; }

/* Where the visitor already is, in both panels. */
.sd-static-chapter .document-list li.active {
    background: rgba(160, 218, 0, 0.1);
    color: var(--accent, #a0da00);
}

/* The two ways in sit at the bottom, away from the subjects. */
.sd-static-sidebar .sidebar-bottom {
    margin-top: auto;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.07);
}

.sd-static-sidebar .nav-register a { color: var(--accent, #a0da00); }

/* ---- the table of contents -------------------------------------------- */

.sd-toc li { padding: 0; }

.sd-toc a,
.sd-toc .is-locked > span {
    padding: 7px 10px;
    border-radius: 8px;
    line-height: 1.4;
}

.sd-toc a:hover { background: rgba(255, 255, 255, 0.05); }

/* Depth by indent alone. A second colour here would compete with the one
   thing in the panel that should be lit — the locked rows. */
.sd-toc .lvl-2 > a, .sd-toc .lvl-2 > span { padding-left: 24px; font-size: 0.94em; }
.sd-toc .lvl-3 > a, .sd-toc .lvl-3 > span { padding-left: 38px; font-size: 0.9em; opacity: 0.85; }

/* A locked section is named but not reachable: dimmed, not a link, with the
   padlock inline so the reason is visible rather than merely implied. */
.sd-toc .is-locked > span {
    display: flex;
    align-items: baseline;
    gap: 8px;
    color: rgba(255, 255, 255, 0.42);
    cursor: default;
}

.sd-toc .sd-lock { flex: none; opacity: 0.7; transform: translateY(1px); }

.sd-locked-note {
    margin: 6px 0 0;
    padding: 0 10px;
    font-size: 0.82em;
    line-height: 1.45;
    color: rgba(255, 255, 255, 0.42);
}

/* ---- how the shell narrows ---------------------------------------------
   The application retracts its left nav first, because inside the app that
   nav is the only way to anywhere. A static page is not the app: its reader
   arrived from a search result, wants the document, and has the same links in
   the footer. So the order is reversed, and the rule is what each panel is
   worth to a stranger.

     > 1400   document, both panels
     > 1080   the table of contents goes first — it is a convenience, and the
              headings are in the text anyway
     ≤ 1080   the nav goes too, and simply disappears: no bottom bar, no
              hamburger, nothing to dismiss. The footer carries the links.

   These override the application's own breakpoints, which assume a session. */

@media (max-width: 1400px) {
    .sd-static-chapter.chapter-sidebar { display: none; }
    .static-doc .page-wrapper.with-right-sidebar { right: 20px; }
}

@media (max-width: 1080px) {
    /* display:none, not the app's translate-and-fade: there is no state here
       to bring it back, so leaving it in the layout serves nobody. */
    .static-doc .floating-sidebar,
    .static-doc .floating-sidebar.navbar,
    .static-doc .floating-sidebar.navbar-hidden { display: none; }
    .static-doc .page-wrapper { left: 20px; right: 20px; }
}


/* ---- centring, once the panels are gone --------------------------------
   page.css sets « margin: 20px 0 » below 1200px, which is right inside the
   application: the page is flanked by a nav and a chapter panel, so it is
   already where it should be. Here the panels have gone, and « 0 » beats the
   « auto » it replaced — an 800px column pinned to the left edge of a 1110px
   wrapper, with three hundred pixels of nothing beside it. */
@media (max-width: 1200px) {
    .static-doc .page-wrapper > .page { margin: 20px auto; }
}

/* No bottom margin: the page must reach the footer, not stop short of it and
   leave a band of ground showing between the two. */
.static-doc .page-wrapper > .page { margin-bottom: 0; }

/* ---- phones ------------------------------------------------------------
   No card, no gutter, no rounded corners: the document is the page. The
   framing belongs to an application the reader is not in, and on a 390px
   screen it costs 40px of line width to say so. */
@media (max-width: 600px) {
    /* .with-right-sidebar is carried in the markup at every width, and the
       rule that neutralises it above is one class more specific than a plain
       .page-wrapper — so it has to be named here too, or the gutter it sets
       survives into the phone layout on the right-hand side only. */
    .static-doc .page-wrapper,
    .static-doc .page-wrapper.with-right-sidebar { left: 0; right: 0; }

    .static-doc .page-wrapper > .page {
        margin: 0;
        border-radius: 0;
        border-left: 0;
        border-right: 0;
        border-top: 0;
        min-height: 100vh;
    }
}

/* ---- what the application draws for itself ------------------------------
   Two things page.css adds below 600px make no sense on a static page, and
   one of them is expensive. */
@media (max-width: 600px) {
    /* A swipe-to-dismiss handle, for a sheet that can be dismissed. This one
       cannot: it is the page. The header keeps the padding that was reserved
       for it, less the room the handle occupied. */
    .static-doc .page-wrapper > .page::before { display: none; }
    .static-doc .page .page-header { padding-top: 16px; }

    /* In the application this block holds the theme toggle and the edit
       button, and hiding it on a phone is right. Here it holds the one link
       that leads into the product — on the devices most search traffic
       arrives from. */
    .static-doc .page-header-actions { display: flex; }
}

/* ---- the footer, under the document ------------------------------------
   It does not scroll. It sits in its final place from the start, behind the
   page, and the document slides up off it — the page is a sheet lying on the
   site, and reaching the end of the sheet is what shows you the site beneath.

   Three things have to line up for that:

   - the footer is fixed, so it never moves;
   - the page paints over it, so it is hidden until the page has gone by;
   - the scroll area is longer than the page by exactly the footer's height,
     so the scroll ends the moment the footer is fully uncovered and not a
     pixel later.

   Its text sits 20px off the bottom, level with the foot of the left panel,
   and takes the same 20px above — so the band it occupies is symmetrical. */

.static-doc {
    /* A desktop-shaped fallback. static-doc.js measures the footer and
       overrides the wrapper's padding, because the links wrap differently at
       every width and no constant is right for all of them. */
    --sd-footer-text: 22px;
    --sd-footer-gap: 20px;    /* matches .floating-sidebar's bottom offset */
}

.static-doc .page-wrapper > .sd-footer {
    position: fixed;
    bottom: var(--sd-footer-gap);
    /* Inside the document's own column, not across the viewport: full width
       ran the links under the left panel, which clipped « Cours en accès
       libre » to « en accès libre ». These track the same breakpoints the
       wrapper uses. */
    left: 280px;
    right: 380px;
    z-index: 0;
    /* The base rule caps the footer at 860px and centres it with auto
       margins; once it is fixed with left/right offsets those margins are
       zeroed, so the cap anchored it to the left edge of the region and it
       sat 40–70px left of the document it belongs to. */
    margin: 0;
    max-width: none;
    padding: var(--sd-footer-gap) 24px 0;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px 22px;
    font-size: 0.9rem;
    line-height: var(--sd-footer-text);
}

/* The page rides over it. .page-wrapper is already a stacking context, so
   this only has to beat the footer. */
.static-doc .page-wrapper > .page {
    position: relative;
    z-index: 1;
}

/* The scroll runs exactly as far past the page as the footer is tall: its
   text, the gap above it, and the gap below. */
.static-doc .page-wrapper {
    padding-bottom: calc(var(--sd-footer-text) + var(--sd-footer-gap) * 2);
}

.static-doc .page-wrapper > .sd-footer a {
    color: var(--faint, rgba(255, 255, 255, 0.42));
    text-decoration: none;
    transition: color 0.12s;
}

.static-doc .page-wrapper > .sd-footer a:hover { color: var(--dim, rgba(255, 255, 255, 0.7)); }

/* The panels leave, and the footer widens to follow the document. */
@media (max-width: 1400px) {
    .static-doc .page-wrapper > .sd-footer { right: 20px; }
}

@media (max-width: 1080px) {
    .static-doc .page-wrapper > .sd-footer { left: 20px; }
}

/* Narrow enough and the links take two lines; the scroll allowance follows. */
@media (max-width: 640px) {
    .static-doc { --sd-footer-text: 54px; }
    .static-doc .page-wrapper > .sd-footer {
        left: 0;
        right: 0;
        padding-left: 16px;
        padding-right: 16px;
    }
}

/* ---- the hub scrolls like a page, not like an app ----------------------
   main.css locks html and body to the viewport with overflow:hidden. Inside
   the application that is correct — the scrolling happens in .page-wrapper,
   and the shell itself must never move. The document pages inherit that
   safely for the same reason.

   /cours/ is not a shell. It is an ordinary long page, and with the lock
   applied it simply could not be scrolled. Body becomes the scroller. */
html:has(> body.sd-hub-page) {
    overflow: auto;
    height: auto;
}

body.sd-hub-page {
    height: auto;
    min-height: 100%;
    overflow-y: auto;
    overflow-x: hidden;
    -webkit-overflow-scrolling: touch;
}

/* ---- buttons -----------------------------------------------------------
   The gate uses .fold-button — the same control the documents themselves use
   for « Solution » and « Démonstration ». It is the house button, so the gate
   is built from the page's own vocabulary rather than from a second one
   invented for it. These links only need what an <a> lacks. */
.sd-gate .fold-button {
    display: inline-flex;
    align-items: center;
    text-decoration: none;
    margin: 0.5rem 0.25rem 0;
    font-family: var(--ui-font);
    /* The key surface, as document.css gives it to the folds: flat face, a lit
       top edge, and a hard drop shadow standing in for the key's side. */
    background: rgba(255, 255, 255, 0.06);
    border: none;
    border-top: 1px solid rgba(255, 255, 255, 0.16);
    box-shadow: 0 4px 0 rgba(0, 0, 0, 0.22),
                0 0 32px inset rgba(255, 255, 255, 0.05),
                0 0 3px inset rgba(255, 255, 255, 0.1);
    color: rgba(255, 255, 255, 0.82);
    transform: translateY(0);
    transition: transform 0.1s ease, box-shadow 0.1s ease,
                background 0.15s ease, color 0.15s ease;
}

.sd-gate .fold-button:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }

/* Pressed: it travels into its own shadow, like every other key. */
.sd-gate .fold-button:active {
    transform: translateY(3px);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.22),
                0 0 32px inset rgba(255, 255, 255, 0.05),
                0 0 3px inset rgba(255, 255, 255, 0.1);
}

/* The accent key, as the landing uses it: the brand colour filled, dark text
   on top, the top edge lit a little brighter because the face is lighter. */
.sd-gate .sd-btn-primary {
    background: var(--accent, #a0da00);
    border-top: 1px solid rgba(255, 255, 255, 0.35);
    box-shadow: 0 4px 0 rgba(58, 80, 0, 0.55),
                0 0 32px inset rgba(255, 255, 255, 0.12),
                0 0 3px inset rgba(255, 255, 255, 0.18);
    color: #10160a;
    font-weight: 500;
}

.sd-gate .sd-btn-primary:hover { background: #b4f000; color: #10160a; }

.sd-gate .sd-btn-primary:active {
    transform: translateY(3px);
    box-shadow: 0 1px 0 rgba(58, 80, 0, 0.55),
                0 0 32px inset rgba(255, 255, 255, 0.12),
                0 0 3px inset rgba(255, 255, 255, 0.18);
}

/* On a light page the same key is built from black instead of white: a 6%
   white face is invisible over the pale wall, and its shadow has to be
   softer or it reads as a hole rather than a button. */
.theme-light .sd-gate .fold-button {
    background: rgba(255, 255, 255, 0.75);
    border-top: 1px solid rgba(255, 255, 255, 0.9);
    box-shadow: 0 3px 0 rgba(0, 0, 0, 0.14),
                0 0 24px inset rgba(0, 0, 0, 0.03);
    color: rgba(0, 0, 0, 0.72);
}

.theme-light .sd-gate .fold-button:hover { background: #fff; color: rgba(0, 0, 0, 0.88); }

.theme-light .sd-gate .fold-button:active {
    transform: translateY(2px);
    box-shadow: 0 1px 0 rgba(0, 0, 0, 0.14), 0 0 24px inset rgba(0, 0, 0, 0.03);
}

/* The accent holds its own against the pale wall because it is the same hue
   at full strength — the wall is that lime at 9%. */
.theme-light .sd-gate .sd-btn-primary {
    background: var(--accent, #a0da00);
    border-top: 1px solid rgba(255, 255, 255, 0.6);
    box-shadow: 0 3px 0 rgba(80, 110, 0, 0.5),
                0 0 24px inset rgba(255, 255, 255, 0.2);
    color: #10160a;
}

.theme-light .sd-gate .sd-btn-primary:hover { background: #aee800; color: #10160a; }

.theme-light .sd-gate .sd-btn-primary:active {
    transform: translateY(2px);
    box-shadow: 0 1px 0 rgba(80, 110, 0, 0.5), 0 0 24px inset rgba(255, 255, 255, 0.2);
}

.sd-gate-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0;
}

/* ---- where the text stops ----------------------------------------------
   A vertical ellipsis between the last visible block and the gate. It is the
   only mark in the page that means « continues » without words, and it lands
   before the wall so the reader meets a boundary rather than an ending. */
.sd-cut {
    margin: 1.6rem 0 0;
    text-align: center;
    font-size: 3.2rem;
    line-height: 0.7;
    letter-spacing: 0;
    color: rgba(255, 255, 255, 0.22);
    user-select: none;
}

/* The wall and its text on a light page: the same lime at 6% over white
   reads far stronger than over near-black, and the body copy inherits a
   light --dim that is invisible on it. */
.theme-light .sd-gate {
    background: rgb(224 255 140 / 23%);
    border-top-color: rgb(164 177 127 / 39%);
}
.theme-light .sd-gate p { color: rgba(0, 0, 0, 0.6); }
.theme-light .sd-gate h2 { color: rgba(0, 0, 0, 0.88); }

/* page.css gives .theme-btn display:flex, which beats the [hidden]
   attribute — the same trap that once showed every tab at once. A class at
   matching specificity, with !important, is what actually hides it. */
.static-doc .theme-btn.sd-hidden { display: none !important; }

/* A sentence needs room; « Connexion requise » does not. */
.sd-nav-pane { max-width: 340px; }
.sd-nav-pane-title { line-height: 1.45; }

.theme-light .sd-cut { color: rgba(0, 0, 0, 0.25); }
.theme-light .sd-footer a { color: rgba(0, 0, 0, 0.55); }
.theme-light .sd-footer a:hover { color: rgba(0, 0, 0, 0.85); }

/* ---- the locked sidebar items ------------------------------------------
   Search, dashboard, notifications and settings are shown rather than hidden:
   a visitor who cannot see that they exist does not know what an account is
   for. They look exactly like the live ones and say what they need when
   clicked. */
/* The items that need a session are still items: same padding, same icon
   column, same row height as the subjects. They carry no <a>, so the padding
   the anchors get had to be given to them directly — without it their icons
   sat 20px left of every other row. */
.sd-static-sidebar .sd-locked-nav { cursor: pointer; }

.sd-static-sidebar .nav-svg {
    width: 20px;
    height: 20px;
    display: block;
}

.sd-static-sidebar .sidebar-spacer { flex: 1 1 auto; }

/* The starfield goes behind everything instead of everything being lifted
   above it: .page-wrapper is position:fixed with z-index 50 and the rails
   have their own, and overriding those to `relative` moved the document and
   dropped the table of contents off screen. */

/* The message a locked item raises. It replaces the item's own label for a
   few seconds rather than opening a dialog: a modal for « you are not signed
   in » is a heavier answer than the question deserves. */
/* What a locked item answers with: a statement and two ways in, nothing
   else. It replaced a toast that explained what a dashboard was for, which
   read as an advertisement standing where the UI should be. Neutral border,
   not lime — the panel is not the thing being sold. */
.sd-nav-pane {
    position: fixed;
    /* Beside the sidebar, not over it: at left:20px it covered the items
       above and below the one it was answering for. */
    left: 280px;
    padding: 16px 18px;
    border-radius: 12px;
    background: rgba(28, 28, 40, 0.97);
    border: 1px solid rgba(255, 255, 255, 0.12);
    z-index: 200;
    box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.16s, transform 0.16s;
    pointer-events: none;
}

.sd-nav-pane.on { opacity: 1; transform: translateY(0); pointer-events: auto; }

.sd-nav-pane-title {
    margin: 0 0 12px;
    color: var(--text, #fff);
    font-size: 0.95rem;
}

.sd-nav-pane-actions { display: flex; gap: 10px; }

/* The house button, as the fold buttons use it. --fill-color-1 resolves
   light inside this panel, so the secondary one states its own dark surface
   rather than inheriting one it cannot be read on. */
/* Controls take the interface face; the document face is for the document. */
.sd-nav-pane-title,
.search-overlay .search-placeholder p,
.search-overlay .fold-button { font-family: var(--ui-font); }

/* The search results pane borrows the nav pane's buttons. */
.search-overlay .sd-nav-pane-actions .fold-button {
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.88);
    text-decoration: none;
}
.search-overlay .sd-nav-pane-actions .fold-button.sd-primary {
    background: var(--accent, #a0da00);
    border-color: var(--accent, #a0da00);
    color: #0a0b0c;
}

.sd-nav-pane-actions .fold-button {
    font-family: var(--ui-font);
    margin: 0;
    text-decoration: none;
    white-space: nowrap;
    background: rgba(255, 255, 255, 0.08);
    border-color: rgba(255, 255, 255, 0.16);
    color: rgba(255, 255, 255, 0.88);
}
.sd-nav-pane-actions .fold-button:hover { background: rgba(255, 255, 255, 0.14); opacity: 1; }
.sd-nav-pane-actions .fold-button.sd-primary {
    background: var(--accent, #a0da00);
    border-color: var(--accent, #a0da00);
    color: #0a0b0c;
}

/* ---- the search panel ---------------------------------------------------
   It opens, it focuses, it takes typing. It does not search. Showing the
   panel is the point: it is one of the better parts of the application, and
   a reader who has seen it knows what the account is worth. */
.sd-search-panel {
    position: fixed;
    top: 20px;
    left: 280px;
    width: min(560px, calc(100vw - 320px));
    padding: 18px;
    border-radius: 16px;
    background: linear-gradient(165deg, rgba(38, 38, 52, 0.98) 0%, rgba(28, 28, 40, 0.98) 100%);
    border: 1px solid rgba(255, 255, 255, 0.1);
    box-shadow: 0 24px 70px rgba(0, 0, 0, 0.6);
    z-index: 210;
}

.sd-search-box {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    border-radius: 10px;
    background: rgba(0, 0, 0, 0.3);
    border: 1px solid rgba(255, 255, 255, 0.09);
}

.sd-search-icon { display: flex; color: var(--faint, rgba(255, 255, 255, 0.42)); }
.sd-search-icon .nav-svg { width: 18px; height: 18px; }

.sd-search-box input {
    flex: 1;
    min-width: 0;
    background: none;
    border: 0;
    outline: none;
    color: var(--ink, #f4f5f2);
    font: inherit;
    font-size: 0.95rem;
}

.sd-search-close {
    background: none;
    border: 0;
    color: var(--faint, rgba(255, 255, 255, 0.42));
    font-size: 1.4rem;
    line-height: 1;
    cursor: pointer;
    padding: 0 2px;
}

.sd-search-close:hover { color: var(--ink, #f4f5f2); }

.sd-search-note {
    margin: 14px 2px 0;
    font-size: 0.88rem;
    line-height: 1.55;
    color: var(--dim, rgba(255, 255, 255, 0.6));
}

.sd-search-actions { display: flex; flex-wrap: wrap; gap: 0; margin-top: 4px; }
.sd-search-actions .fold-button { text-decoration: none; color: inherit; display: inline-flex; }

@media (max-width: 1080px) {
    .sd-search-panel { left: 20px; width: calc(100vw - 40px); }
    .sd-nav-toast { left: 20px; width: min(280px, calc(100vw - 40px)); }
}
