/* ══════════════════════════════════════════════════════════════════════════
   SPLENT theme engine — public shell base stylesheet.
   Brand-agnostic: every colour/font comes from --brand-* custom properties set
   by the product's design tokens (see tokens.py). Skins change tokens, not this.
   ══════════════════════════════════════════════════════════════════════════ */

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

body.cms-public {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--brand-bg);
    color: var(--brand-text);
    font-family: var(--brand-font-body);
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}
.site-main { flex: 1 0 auto; }   /* push the footer to the bottom */

h1, h2, h3, h4 {
    font-family: var(--brand-font-heading);
    color: var(--brand-heading);
    line-height: 1.15;
    margin: 0 0 .5em;
}

a { color: var(--brand-primary); text-decoration: none; }
a:hover { text-decoration: underline; }

.container {
    width: 100%;
    max-width: var(--brand-container);
    margin-inline: auto;
    padding-inline: 1.25rem;
}

.section { padding-block: 3.5rem; }

/* ── Header / nav ──────────────────────────────────────────────────────── */
.site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    background: color-mix(in srgb, var(--brand-bg) 88%, transparent);
    backdrop-filter: saturate(1.4) blur(8px);
    border-bottom: 1px solid var(--brand-border);
}
.site-header__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    min-height: 64px;
    padding-block: 1rem;
}
.site-brand {
    display: flex;
    align-items: center;
    gap: .6rem;
    font-family: var(--brand-font-display);
    font-weight: 700;
    font-size: 1.25rem;
    color: var(--brand-heading);
}
.site-brand__logo { height: 40px; width: auto; display: block; }
.site-nav { display: flex; gap: 1.25rem; align-items: center; }
.site-nav a { color: var(--brand-text); font-weight: 500; }
.site-nav a:hover { color: var(--brand-primary); text-decoration: none; }
/* Active page (and its sub-views). 3 classes so it beats the skins' 2-class
   `.cms-public .site-nav a`; token-driven, works for both products. */
.cms-public .site-nav a.is-active { color: var(--brand-primary); font-weight: 700; }

/* ── Mobile nav: hamburger toggle ───────────────────────────────────────── */
.site-nav-toggle { display: none; }

@media (max-width: 820px) {
    .site-header__inner { position: relative; flex-wrap: wrap; }
    .site-nav-toggle {
        display: inline-flex;
        flex-direction: column;
        justify-content: center;
        gap: 5px;
        width: 42px;
        height: 42px;
        padding: 9px;
        background: none;
        border: 1px solid var(--brand-border);
        border-radius: 8px;
        cursor: pointer;
    }
    .site-nav-toggle span {
        display: block;
        width: 100%;
        height: 2px;
        background: var(--brand-heading);
        border-radius: 2px;
    }
    .site-nav {
        display: none;
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        flex-direction: column;
        align-items: flex-start;
        gap: 1rem;
        margin: 0;
        padding: 1rem 1.25rem 1.25rem;
        background: var(--brand-bg);
        border-bottom: 1px solid var(--brand-border);
        box-shadow: 0 14px 28px rgba(0, 0, 0, .1);
    }
    .site-nav.is-open { display: flex; }
}
.lang-switch { display: inline-flex; gap: .25rem; margin-left: .35rem; }
.lang-switch__opt { font-size: .78rem; font-weight: 700; padding: .15rem .4rem; border-radius: 6px; color: var(--brand-muted); }
.lang-switch__opt.is-active { color: var(--brand-primary); background: color-mix(in srgb, var(--brand-primary) 12%, transparent); }

/* ── Breadcrumb ─────────────────────────────────────────────────────────────
   Rendered by the shell right under the header for any page that passes a
   trail. It stays a line of text on the page background instead of a band of
   its own: a hero or a section usually follows immediately, each with its own
   surface and its own bottom border, and a second edge above them reads as a
   rule that lost its table. ─────────────────────────────────────────────── */
.block-breadcrumb {
    /* A visible strip of orientation chrome under the header: the header
       keeps its bottom border, this band adds a surface and its own lower
       edge, and together they read as a toolbar rather than a stray rule. */
    background: var(--brand-surface);
    border-bottom: 1px solid var(--brand-border);
    padding-block: .7rem;
    font-size: .875rem;
    color: var(--brand-muted);
}
.breadcrumb-trail {
    display: flex;
    align-items: center;
    /* Never wrap. Three levels of course titles become three stacked lines on
       a phone and push the page title off the screen, which costs more than
       the end of a label the reader can already guess. */
    flex-wrap: nowrap;
    gap: .45rem;
    margin: 0;
    padding: 0;
    list-style: none;
    overflow: hidden;
    /* The clipping above would cut the focus ring off the first and the last
       link, which sit flush against the edges of the row. Two pixels of room
       inside, taken straight back outside, so nothing moves. */
    padding-inline: 2px;
    margin-inline: -2px;
}
/* A level of the hierarchy, not an "item": `.breadcrumb-item` is Bootstrap's,
   and the admin shell restyles it with `content: '\203A' !important`, which
   would put a typed separator back into a block whose whole point is not to
   have one. The public shell loads no Bootstrap today; the block travels. */
.breadcrumb-level {
    display: flex;
    align-items: center;
    gap: .45rem;
    /* A flex item refuses to shrink past its own text unless it is allowed to,
       and the row would overflow instead of truncating. */
    min-width: 0;
}
/* The reader is already here and the same words are the page title just
   below, so this is the label that gives up room first. The ancestors are the
   part of the trail that is worth reading, and they stay legible. */
.breadcrumb-level:last-child { flex-shrink: 3; }
.breadcrumb-level > * {
    min-width: 0;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
}
/* Two classes, so this beats the skins' `.cms-public a` and the ancestors
   stay quiet instead of taking the link colour. */
.cms-public .breadcrumb-link {
    color: var(--brand-muted);
    text-decoration: none;
}
.cms-public .breadcrumb-link:hover {
    color: var(--brand-primary);
    text-decoration: underline;
}
.breadcrumb-current {
    color: var(--brand-heading);
    font-weight: 600;
}
.breadcrumb-home-icon {
    flex: 0 0 auto;
    width: .95em;
    height: .95em;
    margin-right: .1rem;
    vertical-align: -.1em;
}
/* The separator is drawn, not written. A "/" in `content:` is announced by
   VoiceOver and NVDA, so the trail is read as "Courses slash EGC slash Tema
   1"; a slanted hairline says the same thing to the eye and nothing at all to
   a screen reader. */
.breadcrumb-level + .breadcrumb-level::before {
    /* The separator is drawn, not written, so screen readers stay silent.
       A chevron reads as "path" at a glance where a hairline disappears. */
    content: "";
    flex: 0 0 auto;
    width: .45em;
    height: .45em;
    border-top: 2px solid color-mix(in srgb, var(--brand-muted) 70%, transparent);
    border-right: 2px solid color-mix(in srgb, var(--brand-muted) 70%, transparent);
    transform: rotate(45deg);
    margin-right: .1rem;
}

@media (max-width: 820px) {
    .block-breadcrumb { padding-block: .6rem; font-size: .8rem; }
}

/* ── Buttons ───────────────────────────────────────────────────────────── */
.btn {
    display: inline-block;
    padding: .7rem 1.4rem;
    border-radius: var(--brand-radius);
    font-weight: 600;
    border: 1px solid transparent;
    cursor: pointer;
    transition: transform .12s ease, box-shadow .12s ease;
}
.btn:hover { transform: translateY(-1px); text-decoration: none; }
.btn-primary {
    background: var(--brand-primary);
    color: var(--brand-primary-contrast);
    box-shadow: 0 6px 18px color-mix(in srgb, var(--brand-primary) 30%, transparent);
}

/* ── Hero block ────────────────────────────────────────────────────────── */
.block-hero {
    padding-block: 5rem;
    text-align: center;
    background:
        radial-gradient(60% 120% at 50% 0%, color-mix(in srgb, var(--brand-primary) 12%, transparent), transparent),
        var(--brand-surface);
    border-bottom: 1px solid var(--brand-border);
}
.hero-eyebrow {
    text-transform: uppercase;
    letter-spacing: .12em;
    font-size: .8rem;
    font-weight: 700;
    color: var(--brand-accent);
    margin: 0 0 .75rem;
}
.hero-title {
    font-family: var(--brand-font-display);
    font-size: clamp(2.2rem, 5vw, 3.6rem);
}
.hero-subtitle {
    max-width: 42rem;
    margin: 1rem auto 1.75rem;
    color: var(--brand-muted);
    font-size: 1.15rem;
}

/* ── Cards / grid ──────────────────────────────────────────────────────── */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 1.25rem;
}
.card {
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius);
    padding: 1.5rem;
    transition: transform .14s ease, box-shadow .14s ease;
}
.card:hover {
    transform: translateY(-3px);
    box-shadow: 0 14px 30px color-mix(in srgb, var(--brand-heading) 10%, transparent);
}
.card__title { font-size: 1.15rem; }
.card__text { color: var(--brand-muted); margin: 0; }
.card__img { width: 100%; border-radius: var(--brand-radius); margin-bottom: .75rem; object-fit: cover; }
.card__meta { color: var(--brand-muted); font-size: .85rem; margin: .5rem 0 0; }
.badge {
    display: inline-block;
    font-size: .7rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .05em;
    padding: .15rem .55rem;
    border-radius: 999px;
    background: color-mix(in srgb, var(--brand-primary) 14%, transparent);
    color: var(--brand-primary);
    margin-bottom: .5rem;
}

.section-title { font-size: 1.5rem; margin: 2.5rem 0 1.25rem; color: var(--brand-heading); }
.person__photo { width: 88px; height: 88px; border-radius: 50%; object-fit: cover; margin-bottom: .5rem; }

/* ── Footer ────────────────────────────────────────────────────────────── */
.site-footer {
    padding-block: 2.5rem 1.5rem;
    background: var(--brand-surface);
    border-top: 1px solid var(--brand-border);
}
.site-footer__inner {
    display: flex;
    flex-wrap: wrap;
    gap: 1.5rem;
    align-items: flex-start;
    justify-content: space-between;
}
.site-footer__brand { display: flex; flex-direction: column; gap: .3rem; max-width: 32rem; }
.site-footer__name { font-family: var(--brand-font-display); font-weight: 700; font-size: 1.15rem; color: var(--brand-heading); }
.site-footer__tagline { color: var(--brand-muted); font-size: .9rem; }
/* Admin-managed footer links (Menus editor): a discreet muted row that wraps,
   sitting before the social list and quieter than it. */
.site-footer-nav { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem 1.1rem; padding: 0; margin: 0; }
.site-footer-nav a { color: var(--brand-muted); font-size: .9rem; }
.site-footer-nav a:hover { color: var(--brand-primary); text-decoration: none; }
.site-social { list-style: none; display: flex; flex-wrap: wrap; gap: .4rem 1.1rem; padding: 0; margin: 0; }
.site-social a { color: var(--brand-text); font-weight: 600; font-size: .9rem; }
.site-social a:hover { color: var(--brand-primary); text-decoration: none; }
/* margin-block-start, not the margin shorthand: this element is also a
   .container, which centres itself with margin-inline: auto, and the
   shorthand resets that to zero. The row then hugged the left edge of the
   window while the row above it stayed centred, so on a wide screen the
   copyright sat in the far corner and "Made with SPLENT", pushed to the
   right edge of a box starting at zero, landed in the middle of nowhere. */
.site-footer__legal { color: var(--brand-muted); margin-block-start: 1.25rem; font-size: .85rem; display: flex; justify-content: space-between; align-items: center; gap: 1rem; flex-wrap: wrap; }
.site-footer__madewith a { color: var(--brand-primary); font-weight: 700; }
.site-footer__madewith a:hover { text-decoration: underline; }

/* ── Home / landing components ──────────────────────────────────────────── */
.hero-actions { display: flex; gap: .75rem; justify-content: center; flex-wrap: wrap; }
.btn-ghost {
    background: transparent;
    border: 1px solid var(--brand-border);
    color: var(--brand-heading);
}
.btn-ghost:hover { border-color: var(--brand-primary); color: var(--brand-primary); }

.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    gap: 1.25rem;
}
.feature {
    text-align: center;
    padding: 1.75rem 1.25rem;
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius);
}
.feature__icon { font-size: 2.4rem; display: block; margin-bottom: .6rem; }
.feature h3 { font-size: 1.1rem; margin-bottom: .35rem; }
.feature p { color: var(--brand-muted); margin: 0; font-size: .92rem; }

.cta-banner {
    margin-top: 3.5rem;
    padding-block: 3.5rem;
    text-align: center;
    background: var(--brand-primary);
    color: var(--brand-primary-contrast);
}
.cta-banner h2 { color: var(--brand-primary-contrast); }
.cta-banner p { opacity: .92; margin-bottom: 1.5rem; }
.cta-banner .btn-primary { background: var(--brand-bg); color: var(--brand-heading); }

/* ── Countdown ──────────────────────────────────────────────────────────── */
.countdown { display: flex; gap: .75rem; justify-content: center; flex-wrap: wrap; margin: 1.75rem 0; }
.countdown__unit {
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius);
    padding: .6rem 1rem;
    min-width: 76px;
}
.countdown__num { display: block; font-family: var(--brand-font-display); font-size: 2rem; font-weight: 700; color: var(--brand-heading); line-height: 1; }
.countdown__label { font-size: .7rem; text-transform: uppercase; letter-spacing: .08em; color: var(--brand-muted); }

/* ── Logo wall (sponsors) ───────────────────────────────────────────────── */
.logo-wall { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 1rem; }
.logo-wall__item {
    display: flex; align-items: center; justify-content: center; text-align: center;
    padding: 1.25rem; min-height: 84px;
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius);
    font-weight: 700; color: var(--brand-muted);
}

/* ── Gallery ────────────────────────────────────────────────────────────── */
.gallery-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: .75rem; }
.gallery-grid__item {
    display: block; aspect-ratio: 4 / 3; overflow: hidden;
    border-radius: var(--brand-radius); border: 1px solid var(--brand-border);
}
.gallery-grid__item img { width: 100%; height: 100%; object-fit: cover; transition: transform .35s ease; }
.gallery-grid__item:hover img { transform: scale(1.06); }

/* ── Code highlighting ──────────────────────────────────────────────────────
   The token classes splent_framework.markdown emits, all prefixed `tok-` so
   they cannot collide with whatever classes a migrated body arrived carrying.

   Every colour goes through a variable rather than being written into the
   rule, because the two things a skin decides about a code block are its
   background and how dark it is, and a palette that reads on a pale panel is
   unreadable on a dark one. The defaults below are for a pale panel, which is
   what a skin gets if it says nothing; a skin with a dark panel overrides the
   eight variables in one block.

   Only what carries meaning is coloured. Punctuation, plain names and
   whitespace inherit, because a block where everything is a different colour
   reads as decoration and stops helping anyone find the line they wanted. */
.cms-public {
    /* The panel itself, so a code block is one decision in one place
       instead of each skin inventing its own and none of them following
       the reader's colour scheme. */
    --code-bg:      #f6f7f9;
    --code-fg:      #24292f;
    --code-border:  #e2e4e8;

    --code-comment: #646b74;
    --code-keyword: #b5187f;
    --code-string:  #1a7f37;
    --code-number:  #b5541c;
    --code-name:    #6f42c1;
    --code-builtin: #0550ae;
    --code-added:   #1a7f37;
    --code-removed: #b31d28;
}

/* The dark palette. Not the light one dimmed: those hues are chosen to hold
   4.5:1 against a near-black panel, which the light ones do not, and a
   reader who set their system to dark and then got a white slab in the
   middle of a page has been handed a torch. */
@media (prefers-color-scheme: dark) {
    .cms-public {
        --code-bg:      #16181d;
        --code-fg:      #e3e6eb;
        --code-border:  #2f333b;

        --code-comment: #7c8797;
        --code-keyword: #ff7bbf;
        --code-string:  #8ddb8d;
        --code-number:  #ffb86c;
        --code-name:    #c9a6ff;
        --code-builtin: #79c0ff;
        --code-added:   #8ddb8d;
        --code-removed: #ff8080;
    }
}

/* Comments: quieter than the code, and italic so a long licence header at the
   top of a file is skimmed past rather than read. */
.cms-public .tok-c, .cms-public .tok-c1, .cms-public .tok-cm,
.cms-public .tok-ch, .cms-public .tok-cs, .cms-public .tok-cp,
.cms-public .tok-cpf { color: var(--code-comment); font-style: italic; }

/* Keywords and operators that are words (and, not, in). */
.cms-public .tok-k, .cms-public .tok-kc, .cms-public .tok-kd,
.cms-public .tok-kn, .cms-public .tok-kp, .cms-public .tok-kr,
.cms-public .tok-kt, .cms-public .tok-ow { color: var(--code-keyword); font-weight: 600; }

/* Strings, including the quotes and the escapes inside them. */
.cms-public .tok-s, .cms-public .tok-s1, .cms-public .tok-s2,
.cms-public .tok-sb, .cms-public .tok-sc, .cms-public .tok-sd,
.cms-public .tok-se, .cms-public .tok-sh, .cms-public .tok-si,
.cms-public .tok-sx, .cms-public .tok-sr, .cms-public .tok-ss,
.cms-public .tok-sa, .cms-public .tok-dl,
/* A YAML scalar is a literal rather than a quoted string, and it is the
   right-hand side of every line in a compose file. */
.cms-public .tok-l { color: var(--code-string); }

.cms-public .tok-m, .cms-public .tok-mi, .cms-public .tok-mf,
.cms-public .tok-mh, .cms-public .tok-mo, .cms-public .tok-mb { color: var(--code-number); }

/* Things that were declared here: a function, a class, a tag, a variable. */
.cms-public .tok-nf, .cms-public .tok-nc, .cms-public .tok-nt,
.cms-public .tok-nd, .cms-public .tok-ne, .cms-public .tok-fm { color: var(--code-name); }

/* Things that came with the language or the shell: builtins, constants,
   attribute names. Three quarters of this corpus is bash, where this is the
   class that does the work. */
.cms-public .tok-nb, .cms-public .tok-bp, .cms-public .tok-no,
.cms-public .tok-na, .cms-public .tok-nv, .cms-public .tok-vg,
.cms-public .tok-vi, .cms-public .tok-vc, .cms-public .tok-vm { color: var(--code-builtin); }

/* Diffs and terminal transcripts, which is what a practical is full of. */
.cms-public .tok-gi { color: var(--code-added); }
.cms-public .tok-gd { color: var(--code-removed); }
.cms-public .tok-gp { color: var(--code-comment); user-select: none; }
.cms-public .tok-gh, .cms-public .tok-gu { color: var(--code-name); font-weight: 600; }
.cms-public .tok-ge { font-style: italic; }
.cms-public .tok-gs { font-weight: 700; }

/* A lexer that could not make sense of a character still shows it. Marking it
   red would tell a reader their own page is broken, which it is not. */
.cms-public .tok-err { color: inherit; }


/* ── The code block itself ──────────────────────────────────────────────────
   A figure around the <pre>, added by JavaScript at load: the language it is
   written in, and a button that copies it. Both belong here rather than in
   the markdown the server renders, because both are about reading a page
   rather than about what the page says, and a stored body should not carry
   chrome that a redesign would have to migrate out of it again. */

.cms-public .code-block {
    position: relative;
    margin: 1.6rem 0;
    background: var(--code-bg);
    border: 1px solid var(--code-border);
    border-radius: var(--brand-radius);
    overflow: hidden;
}

.cms-public .code-block__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: .35rem .5rem .35rem .9rem;
    border-bottom: 1px solid var(--code-border);
    /* A shade off the panel, so the bar reads as chrome and the code below
       keeps the whole of the reader's attention. */
    background: color-mix(in srgb, var(--code-fg) 6%, var(--code-bg));
}

/* What the block is written in. Taken from the language- class the renderer
   already puts there, so it says bash because the author wrote bash. */
.cms-public .code-block__lang {
    font-family: var(--brand-font-display, ui-monospace, monospace);
    font-size: .7rem;
    font-weight: 600;
    letter-spacing: .08em;
    text-transform: uppercase;
    color: color-mix(in srgb, var(--code-fg) 55%, transparent);
}

.cms-public .code-block__copy {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .2rem .55rem;
    font: inherit;
    font-size: .72rem;
    font-weight: 600;
    color: color-mix(in srgb, var(--code-fg) 70%, transparent);
    background: none;
    border: 1px solid var(--code-border);
    border-radius: calc(var(--brand-radius) * .6);
    cursor: pointer;
    transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}

.cms-public .code-block__copy:hover {
    color: var(--code-fg);
    border-color: color-mix(in srgb, var(--code-fg) 35%, transparent);
    background: color-mix(in srgb, var(--code-fg) 8%, transparent);
}

.cms-public .code-block__copy:focus-visible {
    outline: 2px solid var(--brand-primary);
    outline-offset: 1px;
}

/* Said in words as well as in colour, and announced to a screen reader by
   the script, because "it went green" is not feedback everyone receives. */
.cms-public .code-block__copy.is-done {
    color: var(--code-added);
    border-color: color-mix(in srgb, var(--code-added) 45%, transparent);
}

.cms-public .code-block pre {
    margin: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    color: var(--code-fg);
    padding: .9rem 1.1rem;
    overflow-x: auto;
    tab-size: 4;
}

/* A block with no language gets no bar, so an unlabelled snippet does not
   grow an empty strip above it. The copy button moves inside instead. */
.cms-public .code-block--bare .code-block__bar {
    position: absolute;
    inset-block-start: .4rem;
    inset-inline-end: .4rem;
    padding: 0;
    border: 0;
    background: none;
    opacity: 0;
    transition: opacity .15s ease;
}

.cms-public .code-block--bare:hover .code-block__bar,
.cms-public .code-block--bare:focus-within .code-block__bar {
    opacity: 1;
}

/* ── Forms ────────────────────────────────────────────────────────────────
   Shared features render WTForms with Bootstrap-named classes (.form-label,
   .form-control), so the public shell styles those names and a feature's
   form looks native here without carrying its own stylesheet. */
.form-label {
    display: block;
    margin-bottom: .4rem;
    font-weight: 600;
    color: var(--brand-heading);
}
.form-control {
    display: block;
    width: 100%;
    padding: .55rem .8rem;
    font: inherit;
    color: var(--brand-text);
    background: var(--brand-surface);
    border: 1px solid var(--brand-border);
    border-radius: var(--brand-radius);
}
.form-control::placeholder { color: var(--brand-muted); }
.form-control:focus {
    outline: none;
    border-color: var(--brand-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--brand-primary) 20%, transparent);
}
.form-field { margin-bottom: 1.15rem; }
.form-check-input { accent-color: var(--brand-primary); }
.form-check-label { margin-left: .4rem; }
.form-error { color: var(--brand-danger, #b3261e); font-size: .9rem; margin: .35rem 0 0; }
.alert {
    padding: .7rem 1rem;
    margin-bottom: 1rem;
    border: 1px solid var(--brand-border);
    border-left: 4px solid var(--brand-primary);
    border-radius: var(--brand-radius);
    background: var(--brand-surface);
}
/* The narrow column a lone public form (log in, contact) sits in. */
.form-page { max-width: 26rem; }

/* On paper the chrome is noise: a button nobody can press and a language
   the code already shows. */
@media print {
    .cms-public .code-block__bar { display: none; }
    .cms-public .code-block {
        background: #ffffff;
        border-color: #999999;
    }
    .cms-public .code-block pre { color: #000000; }
}

/* ── Lightbox ──────────────────────────────────────────────────────────── */
/* Rich-text images and anything marked data-lightbox open full-screen
 * (lightbox.js). The cursor tells the reader the image is expandable. */
.prose img,
img[data-lightbox],
[data-lightbox] img {
    cursor: zoom-in;
}

.lightbox {
    position: fixed;
    inset: 0;
    z-index: 200;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem;
    background: rgba(0, 0, 0, 0.86);
    cursor: zoom-out;
}

.lightbox__img {
    max-width: 100%;
    max-height: 100%;
    border-radius: var(--brand-radius);
    box-shadow: 0 12px 48px rgba(0, 0, 0, 0.5);
}

.lightbox__close {
    position: absolute;
    top: 1rem;
    right: 1.25rem;
    border: 0;
    background: none;
    color: #fff;
    font-size: 2.25rem;
    line-height: 1;
    cursor: pointer;
    opacity: 0.8;
}

.lightbox__close:hover {
    opacity: 1;
}
