/* 1. Use a more intuitive box-sizing model */
*, *::before, *::after {
    box-sizing: border-box;
}

/* 3. Allow percentage-based heights in the application */
html, body {
    height: 100%;
    font-size: 16px;
    margin: 0;
    padding: 0;
}

html {
    scroll-behavior: smooth;
}

/* 4. Improve text rendering and set a baseline line-height */
body {
    line-height: 1.5;
    -webkit-font-smoothing: antialiased;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
}

/* 5. Improve media defaults */
img, picture, video, canvas, svg {
    display: block;
    max-width: 100%;
    height: auto;
}

/* 6. Remove built-in form typography inherits */
input, button, textarea, select {
    font: inherit;
}

/* 7. Avoid text overflows */
p, h1, h2, h3, h4, h5, h6 {
    overflow-wrap: break-word;
}

p {
    margin: 0;
    padding: 0;
    padding-bottom: 1em;
}

p:last-child {
    padding-bottom: 0;
}

/* 8. Improve accessibility by keeping focus states visible but clean */
:focus-visible {
    outline: 3px solid currentColor;
    outline-offset: 2px;
}

:root {
    /* common */
    --gst-card-radius: 1rem;
    /* nested radius: outer radius minus the gap it sits inside, so corners stay concentric */
    --gst-card-radius-inner: 0.625rem;
    --gst-card-padding: 2rem;
    --gst-card-padding-mobile: 1rem;
    --gst-navcard-outline-thickness: 3px;
    --gst-button-padding: 1rem;

    /* motion: a decelerating curve reads as settling rather than sliding */
    --gst-ease: cubic-bezier(0.22, 1, 0.36, 1);
    --gst-card-speed: 220ms;
}

:root {
    /* defaults applied across this display */
    --gst-container-highlight: #6366f1;

    /* defaults */
    --gst-container-bg: #0f172a;
    --gst-container-color: #f8fafc;

    /*
     * Elevation is layered: a tight contact shadow, a mid diffusion and a wide ambient
     * pool. One large blur alone reads as a smudge; three stacked reads as height.
     * The inset hairline is the top-edge catch-light that gives a dark card its edge.
     */
    --gst-elev-1: 0 1px 2px rgba(0, 0, 0, 0.32),
                  0 4px 10px -3px rgba(0, 0, 0, 0.36),
                  0 14px 28px -12px rgba(0, 0, 0, 0.46);
    --gst-elev-2: 0 2px 4px rgba(0, 0, 0, 0.34),
                  0 10px 22px -6px rgba(0, 0, 0, 0.44),
                  0 28px 52px -20px rgba(0, 0, 0, 0.58);
    --gst-card-ring: inset 0 1px 0 0 rgba(255, 255, 255, 0.06);

    --gst-card-shadow: var(--gst-card-ring), var(--gst-elev-1);
    --gst-card-shadow-hover: var(--gst-card-ring), var(--gst-elev-2);
    --gst-section-title: #f8fafc;
    --gst-leader-color: #f8fafc;

    /* contrast becomes lighter */
    --gst-contrast-rgb: 255, 255, 255;

    /* php code theming */
    --gst-php-code-bg: #090d16;
    --gst-php-code-text: #e2e8f0;
    --gst-php-code-border: #1e293b;
    --gst-php-code-keyword: #818cf8;
    --gst-php-code-string: #34d399;
    --gst-php-code-comment: #94a3b8;
    --gst-php-code-variable: #f472b6;
    --gst-php-code-function: #fbbf24;
    --gst-php-code-number: #38bdf8;

    & .gst-theme-header, & .gst-theme-footer {
        /* dedicated block style for header */
        --gst-container-bg: #090d16;
        --gst-container-color: #f1f5f9;
        --gst-container-border: #1e293b;
        --gst-container-highlight: #818cf8;
        --gst-container-bg-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath d='M 10,0 L 10,10 L 0,10' fill='none' stroke='%23e2e8f005' stroke-width='1'/%3E%3C/svg%3E");
    }

    & .gst-theme-primary {
        /* spec: main content area, solid background */
        --gst-container-bg: #0f172a;
        --gst-container-color: #f8fafc;
        --gst-container-border: #1e293b;
        /*--gst-container-bg-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath d='M 10,0 L 10,10 L 0,10' fill='none' stroke='%23e2e8f007' stroke-width='1'/%3E%3C/svg%3E");*/
    }

    & .gst-theme-primary .gst-default-card,
    & .gst-primary-card {
        --gst-container-bg: #1e293b;
        --gst-container-color: #f8fafc;
        --gst-container-border: #334155;
        --gst-container-bg-image: none;
    }

    & .gst-theme-secondary {
        /* spec: secondary content area, allows background to show through, not for main text */
        --gst-container-bg: transparent;
        --gst-container-color: #f8fafc;
        --gst-container-bg-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'%3E%3Cpath d='M 10,0 L 10,10 L 0,10' fill='none' stroke='%23e2e8f002' stroke-width='1'/%3E%3C/svg%3E");
    }

    & .gst-theme-secondary .gst-default-card,
    & .gst-secondary-card {
        --gst-container-bg: #1e293b;
        --gst-container-color: #f8fafc;
        --gst-container-border: #334155;
        --gst-container-highlight: #818cf8;
        --gst-container-bg-image: none;
    }

    & .gst-theme-inverted {
        --gst-container-bg: #6366f1;
        --gst-container-color: #ffffff;
        --gst-container-border: #4f46e5;
        --gst-contrast-rgb: 0, 0, 0;
        --gst-container-bg-image: none;
    }
}

@media (prefers-color-scheme: light) {
    :root {
        background-color: #f8fafc;
        background-repeat: repeat;
        --gst-container-border: 1px solid #e2e8f0;

        /* defaults */
        --gst-container-bg: #ffffff;
        --gst-container-color: #0f172a;

        /*
         * Light elevation is tinted with the slate hue rather than neutral black —
         * a pure-black shadow over a warmless background reads as dirt, not depth.
         */
        --gst-elev-1: 0 1px 2px rgba(15, 23, 42, 0.06),
                      0 4px 10px -3px rgba(15, 23, 42, 0.07),
                      0 14px 28px -12px rgba(15, 23, 42, 0.10);
        --gst-elev-2: 0 2px 4px rgba(15, 23, 42, 0.07),
                      0 10px 22px -6px rgba(15, 23, 42, 0.10),
                      0 28px 52px -20px rgba(15, 23, 42, 0.16);
        --gst-card-ring: inset 0 1px 0 0 rgba(255, 255, 255, 0.9);

        --gst-card-shadow: var(--gst-card-ring), var(--gst-elev-1);
        --gst-card-shadow-hover: var(--gst-card-ring), var(--gst-elev-2);

        /* php code theming */
        --gst-php-code-bg: #f8fafc;
        --gst-php-code-text: #0f172a;
        --gst-php-code-border: #e2e8f0;
        --gst-php-code-keyword: #4f46e5; /* e.g., function, return, if */
        --gst-php-code-string: #047857; /* e.g., "hello world" */
        --gst-php-code-comment: #64748b; /* e.g., // comment */
        --gst-php-code-variable: #db2777; /* e.g., $my_var */
        --gst-php-code-function: #7c3aed; /* e.g., array_map() */
        --gst-php-code-number: #0284c7; /* e.g., 42, 3.14 */

        & .gst-theme-header, & .gst-theme-footer {
            /* dedicated block style for header */
            --gst-container-bg: #ffffff;
            --gst-container-color: #0f172a;
            --gst-container-border: #e2e8f0;
            --gst-container-bg-image: none;
        }

        & .gst-theme-primary {
            --gst-container-bg: #ffffff;
            --gst-container-color: #0f172a;
            --gst-container-border: #e2e8f0;
            --gst-container-bg-image: none;
        }

        & .gst-theme-primary .gst-default-card,
        & .gst-primary-card {
            --gst-container-bg: #ffffff;
            --gst-container-color: #0f172a;
            --gst-container-border: #e2e8f0;
            --gst-container-highlight: #6366f1;
            --gst-container-bg-image: none;
        }

        & .gst-theme-secondary {
            /* SECONDARY content area */
            --gst-container-bg: #f1f5f9;
            --gst-container-color: #0f172a;
            --gst-container-bg-image: none;
        }

        & .gst-theme-secondary .gst-default-card,
        & .gst-secondary-card {
            --gst-container-bg: #ffffff;
            --gst-container-color: #0f172a;
            --gst-container-border: #e2e8f0;
            --gst-container-highlight: #6366f1;
            --gst-container-bg-image: none;
        }

        & .gst-inverted-card {
            --gst-container-bg: #0f172a;
            --gst-container-color: #ffffff;
            --gst-container-border: #334155;
            --gst-contrast-rgb: 255, 255, 255;
            --gst-container-bg-image: none;

            /*
             * A dark card on a light page needs a heavier shadow than its white
             * neighbours, or it reads as pasted on rather than sitting above.
             */
            --gst-elev-1: 0 1px 2px rgba(15, 23, 42, 0.14),
                          0 6px 14px -4px rgba(15, 23, 42, 0.18),
                          0 18px 34px -14px rgba(15, 23, 42, 0.26);
            --gst-elev-2: 0 2px 4px rgba(15, 23, 42, 0.18),
                          0 12px 24px -6px rgba(15, 23, 42, 0.24),
                          0 32px 56px -22px rgba(15, 23, 42, 0.34);
            --gst-card-ring: inset 0 1px 0 0 rgba(255, 255, 255, 0.08);
            --gst-card-shadow: var(--gst-card-ring), var(--gst-elev-1);
            --gst-card-shadow-hover: var(--gst-card-ring), var(--gst-elev-2);
        }

        --gst-section-title: #0f172a;
        --gst-leader-color: #0f172a;

        /* contrast becomes darker */
        --gst-contrast-rgb: 0, 0, 0;
    }
}

body {
    background-color: var(--gst-container-bg);
}


@media (max-width: 600px) {
    :root {
        --gst-card-padding: 1rem;
    }
}

/*
 * Top Navigation
 */

.gst-top {
    background: #3a3a52;
    color: white;
    padding: 1em;
    width: 100%;
}

/*
 * Global Theming
 */

.gst-header-block {
    border-bottom: var(--gst-container-border);
}

.gst-footer-block {
    border-top: var(--gst-container-border);
}


/**
 * The container is responsible for setting the styling beneath the container to be
 * whatever the previously defined variables are, but doesn't actually apply them
 */
.gst-container,
.gst-card {
    background-color: var(--gst-container-bg);
    background-image: var(--gst-container-bg-image);
    background-repeat: repeat;
    color: var(--gst-container-color);

    & h1, & h2, & h3, & h4, & h5,  & h6 {
        color: var(--gst-container-color);
    }

    /*
     * Controls that carry their own foreground must opt out: this selector is (0,2,1)
     * and a component class like .gst-btn-primary is (0,1,0), so without the exclusion
     * the container repaints their labels in the container's text colour.
     */
    & :is(a:not(.plaina, .gst-btn, .gst-pagination-link), .gst-linkcolor) {
        color: var(--gst-container-color);
    }

    & .gst-accent {
        color: var(--gst-container-highlight);
    }
}

.gst-card {
    margin: 0;
}

.gst-chunky-btn {
    all: unset;
    background-color: color-mix(in srgb, var(--gst-container-color) 100%, var(--gst-container-bg));
    color: var(--gst-container-bg);
    border-radius: var(--gst-card-radius);
    cursor: pointer;
    font-weight: 500;
    text-align: center;
    transition: all 0.2s ease-in-out;
    padding: var(--gst-button-padding);
    display: flex;
    align-items: center;
    justify-content: center;

    &:hover {
        background-color: color-mix(in srgb, var(--gst-container-color) 70%, var(--gst-container-bg));
    }

    &:focus {
        background-color: var(--gst-container-bg);
        outline: var(--gst-navcard-outline-thickness) solid var(--gst-container-highlight);
        color: var(--gst-container-highlight);
    }
}

.gst-content, .gst-content-p-normal {
    width: min(1220px, 100%);
    margin: 0 auto;
    box-sizing: border-box;
}

.gst-content-wide, .gst-content-p-wide {
    width: min(1440px, 100%);
    margin: 0 auto;
    box-sizing: border-box;
}

.gst-content-p-thin {
    width: min(800px, 100%);
    margin: 0 auto;
    box-sizing: border-box;
}

.gst-content-p-wide, .gst-content-p, .gst-content-p-normal, .gst-content-p-thin {
    padding: 3em 1em;
}

/*
 * Responsive Header
 */

.gst-header-desktop {
    display: flex;
    flex: 1 1;
    gap: 2em;
    font-size: larger;
    flex-wrap: wrap;
}

.gst-header-mobile-toggle {
    display: none;
    cursor: pointer;
    font-size: 2rem;
    background: none;
    border: none;
    color: var(--gst-container-color);
}

.gst-header-mobile-nav {
    display: none;
    position: fixed;
    top: 0;
    right: -100%;
    width: 250px;
    height: 100vh;
    background-color: var(--gst-container-bg);
    z-index: 1000;
    transition: right 0.3s ease-in-out;
    padding: 2em;
    box-shadow: -2px 0 5px rgba(0,0,0,0.5);
    flex-direction: column;
    gap: 1.5em;
}

.gst-header-mobile-nav.open {
    display: flex;
    right: 0;
}

.gst-header-mobile-nav-overlay {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    background: rgba(0, 0, 0, 0.5);
    z-index: 999;
}

.gst-header-mobile-nav-overlay.open {
    display: block;
}

.gst-header-mobile-nav a {
    text-decoration: none;
    font-size: 1.2rem;
    color: var(--gst-container-color);
}

.gst-header-mobile-close {
    align-self: flex-end;
    font-size: 1.5rem;
    cursor: pointer;
    margin-bottom: 1em;
}

@media (max-width: 500px) {
    .gst-header-desktop {
        display: none !important;
    }

    .gst-header-mobile-toggle {
        display: block !important;
        margin-left: auto;
    }
}

.gst-readable {
    width: min(800px, 100%);
    margin-left: auto;
    margin-right: auto;
    line-height: 1.5;
}

/*
 * Optional in-page nav, main column, optional panel. Source order is nav → main →
 * sidebar, so the single-column stack puts the in-page nav above what it navigates.
 * Between the two, the panels wrap off one at a time rather than all at once.
 */
.gst-sbc {
    display: flex;
    flex-direction: row;
    gap: 2em;
    flex-wrap: wrap;
}

@media (max-width: 600px) {
    .gst-sbc {
        flex-direction: column;
    }
}

.gst-sbc-main {
    /* outgrows both panels so they sit at their basis; min-width lets an
       overlong code block scroll instead of stretching the row */
    flex: 999999 0 300px;
    min-width: 0;
}

.gst-sbc-nav {
    flex: 1 0 320px;
}

.gst-sbc-sidebar {
    flex: 1 0 320px;
}

/*
 * The dividing rule belongs to the column rather than to the rail inside it. A flex item
 * stretches to the tallest item in its row, so the rule runs the height of the article
 * instead of stopping wherever the nav happens to end. :has() keeps it off a column that
 * has no rail — an article with no headings should not leave a rule beside a blank gutter.
 */
.gst-sbc-nav:has(> .gst-rail) {
    border-right: 1px solid var(--gst-container-border);
    padding-right: 1.5rem;
}

.gst-sbc-sidebar:has(> .gst-rail) {
    border-left: 1px solid var(--gst-container-border);
    padding-left: 1.5rem;
}

/*
 * The columns have to stay stretched for their rules, so the rails are what stick.
 *
 * Deliberately no max-height and no inner scroller. Clamping to the viewport is only
 * correct once the panel is pinned — before that its top sits some 430px down, below the
 * masthead, so the box claimed a viewport of height from there and ran its last few
 * hundred pixels past the fold, with its own scrollbar reporting the list as finished.
 * At its natural height the panel is always consistent with what it shows.
 *
 * The trade is that a panel taller than the viewport keeps its tail off-screen while
 * pinned. Making one both persistent and fully reachable means sizing it from its live
 * position on every scroll, which is script, not CSS.
 */
.gst-sbc-nav > .gst-rail,
.gst-sbc-sidebar > .gst-rail {
    position: sticky;
    top: 1em;
}

@media (max-width: 600px) {
    /* stacked, the rails are just blocks in the page — pinning them would cover the content */
    .gst-sbc-nav > .gst-rail,
    .gst-sbc-sidebar > .gst-rail {
        position: static;
    }

    /* and there is no gutter left for a vertical rule to sit in, so it separates above instead */
    .gst-sbc-nav:has(> .gst-rail),
    .gst-sbc-sidebar:has(> .gst-rail) {
        border-right: 0;
        border-left: 0;
        border-top: 1px solid var(--gst-container-border);
        padding: 1.5rem 0 0;
    }
}

/*
 * Nav lists step in by one bullet's width per level, not the browser default 40px —
 * an outline three headings deep otherwise spends most of the panel on indent.
 */
.gst-nav-items {
    padding-inline-start: 24px;
}

/*
 * A nav entry with nothing to link to — the label for the group under it. It takes the
 * rail link's box so the rows keep one rhythm, and full contrast so it reads as the
 * heading of that group rather than a link that has stopped working.
 */
.gst-nav-section {
    display: block;
    padding: 0.25rem 0;
    font-weight: 650;
    color: var(--gst-container-color);
}

/*
 * Rail
 *
 * A sidebar panel that is deliberately not a card. A card's fill, border, shadow and
 * 2rem padding make it an object in its own right, which is what you want for one
 * amongst several; in three columns it leaves the article outnumbered two to one by
 * its own furniture. A rail is typography and nothing else — the dividing rule is the
 * column's, above — so it marks where the panel is and then gets out of the way. Every
 * colour comes from the container tokens, so light and dark follow with no second palette.
 */
.gst-rail {
    font-size: 0.9375rem;
    line-height: 1.5;
    /* a step back from body copy — legible, but not competing for the first read */
    color: color-mix(in srgb, var(--gst-container-color) 72%, var(--gst-container-bg));
}

/*
 * A panel heading, not an article heading. Left alone an <h3> here inherits the article's
 * scale and reads as a page title dropped into the gutter; full contrast against the muted
 * list below is enough to mark it as the head of the panel.
 */
.gst-rail :is(h2, h3, h4) {
    margin: 0 0 0.75rem;
    font-size: 0.9375rem;
    font-weight: 650;
    color: var(--gst-container-color);
}

.gst-rail ul {
    /* flush at the top level wherever the markup puts it — a partial may wrap its list in <nav> */
    list-style: none;
    padding-inline-start: 0;
    margin: 0;
}

.gst-rail ul ul {
    /* the indent alone carries the nesting; markers three levels deep read as clutter */
    padding-inline-start: 24px;
}

.gst-rail a {
    /* the whole row is the target, not just the word */
    display: block;
    padding: 0.25rem 0;
    color: inherit;
    text-decoration: none;
}

.gst-rail a:hover,
.gst-rail a:focus-visible {
    color: var(--gst-container-highlight);
}

@media (max-width: 600px) {
    .gst-content-p-wide {
        padding: 1em 1em;
    }
}

/*
 * Section Titles
 */

.gst-section-title {
    padding-top: 5em;
    padding-bottom: 3em;
    text-align: center;

    & h2 {
        all: unset;
        font-size: 300%;
        line-height: 1.2;
        margin: 0;
        padding: 0;
    }

    & h2:after {
        content: "";
        all: unset;
    }

    & p {
        margin: 0.75em 0 0;
        font-size: 130%;
        font-weight: 500;
    }
}


.gst-section-title:first-child {
    padding-top: 0;
}

.gst-content-p-wide .gst-section-title:first-child {
    padding-top: 0;
}

/*
 * Sidebar
 */

/* maintain compatibility with previous versions by only knocking out padding if we have a card in it */
aside.tips:has(.gst-card) {
    padding: 0 !important;
}

/*
 * Clickable Navigation Card
 */

.gst-navcard {
    position: relative;
    outline: var(--gst-navcard-outline-thickness) solid transparent;
    outline-offset: 0;
    /*
     * Named properties, not `all`. `all` animates the border-width and padding the
     * hover state never meant to touch, which is what makes the lift feel rubbery.
     */
    transition: transform var(--gst-card-speed) var(--gst-ease),
                box-shadow var(--gst-card-speed) var(--gst-ease),
                background-color var(--gst-card-speed) var(--gst-ease),
                border-color var(--gst-card-speed) var(--gst-ease),
                outline-color 120ms linear;
}

.gst-navcard:hover {
    /* a short lift plus real elevation, rather than a long lift with a flat shadow */
    transform: translateY(-3px);
    border-color: var(--gst-container-highlight);
    /* 6% tint, not a 20% grey wash — the surface should warm, not go muddy */
    background-color: color-mix(in srgb, var(--gst-container-highlight) 6%, var(--gst-container-bg));
    box-shadow: var(--gst-card-shadow-hover),
                0 0 0 1px color-mix(in srgb, var(--gst-container-highlight) 45%, transparent);
}

.gst-navcard:active {
    transform: translateY(-1px);
    transition-duration: 90ms;
}

/* keyboard focus keeps the hard ring; pointer hover no longer needs it */
.gst-navcard:focus-within {
    outline-color: var(--gst-container-highlight);
    box-shadow: var(--gst-card-shadow-hover);
}

.gst-navcard-title-link {
    all: unset;
    color: var(--gst-container-color);
    /* size comes from .gst-navcard-title-text so the two do not compound */
    font: inherit;
    text-decoration: none;
    transition: color var(--gst-card-speed) var(--gst-ease);
}

.gst-navcard:hover .gst-navcard-title-link {
    color: var(--gst-container-highlight);
}

.gst-navcard-title-link:after {
    content: "";
    position: absolute;
    inset: 0;
    cursor: pointer;
}

.gst-navcard-indicator {
    width: 28px;
    height: 28px;
    fill: rgba(var(--gst-contrast-rgb), 0.22);
    transition: fill var(--gst-card-speed) var(--gst-ease),
                transform var(--gst-card-speed) var(--gst-ease);
}

.gst-navcard:hover .gst-navcard-indicator {
    fill: var(--gst-container-highlight);
    /* nudges along its own diagonal, so the glyph and the gesture agree */
    transform: translate(2px, -2px);
}

@media (prefers-reduced-motion: reduce) {
    .gst-navcard,
    .gst-navcard-indicator,
    .gst-navcard-title-link {
        transition-duration: 1ms;
    }

    .gst-navcard:hover,
    .gst-navcard:active,
    .gst-navcard:hover .gst-navcard-indicator {
        transform: none;
    }
}

.gst-navcard-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 100%;
    box-sizing: border-box;

    /* "Chunk" styling: chunky padding and thick borders */
    padding: 14px 32px;
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
    font-size: 1.1rem;
    font-weight: 700;
    text-decoration: none;
    text-align: center;
    letter-spacing: 0.5px;
    cursor: pointer;

    /* Colors & Border */
    color: #111111 !important;
    background-color: #ffffff;
    border: 2px solid #111111;
    border-radius: 0.5em;

    /* Smooth transitions for hover/active states */
    transition: all 0.2s ease-in-out;
}

@media (max-width: 600px) {
    .gst-navcard-btn {
        padding: 4px 16px !important;
    }
}

/*
 * Basic Card
 */

.gst-card {
    border-radius: var(--gst-card-radius);
    position: relative;
    display: flex;
    flex-direction: column;
    flex-grow: 1;
    overflow: hidden;

    border: 1px solid var(--gst-container-border);
    box-shadow: var(--gst-card-shadow);

    /* keeps the inset ring and any child blend modes from leaking onto the page */
    isolation: isolate;
}

.gst-card-title {
    flex: 0 0 fit-content;
    padding: var(--gst-card-padding);
    padding-bottom: 0.5em;
    display: flex;
    gap: 1em;
    flex-wrap: wrap;
    align-items: center;
}

.gst-card-title-text,
.gst-navcard-title-text {
    flex: 99999 0 180px;
    font-size: clamp(1.0625rem, 0.98rem + 0.4vw, 1.25rem);
    font-weight: 650;
    /* large text needs negative tracking and tighter leading or it reads loose */
    letter-spacing: -0.011em;
    line-height: 1.25;
    text-wrap: balance;
}

.gst-card-title-icon {
    width: 56px;
    height: 56px;
    border-radius: var(--gst-card-radius-inner);
    object-fit: contain;
    /* a hairline keeps transparent logos from floating unanchored on the card */
    box-shadow: inset 0 0 0 1px rgba(var(--gst-contrast-rgb), 0.08);
    background-color: rgba(var(--gst-contrast-rgb), 0.03);
}

.gst-card-content {
    flex: 1 1;
    padding: var(--gst-card-padding);
    display: flex;
    flex-direction: column;

    /*
     * Body copy sits a step back from the title. The heading and link rules on
     * .gst-container are more specific, so those stay at full contrast.
     */
    color: color-mix(in srgb, var(--gst-container-color) 78%, var(--gst-container-bg));
    text-wrap: pretty;
}

.gst-card-footer {
    padding: var(--gst-card-padding);
    flex: 0 0 fit-content;
    font-size: 0.9375rem;
    font-weight: 600;
    letter-spacing: 0.005em;
}

.gst-card-title + .gst-card-content {
    padding-top: calc(var(--gst-card-padding) / 2);
}

.gst-card-content:has(+.gst-card-footer) {
    padding-bottom: calc(var(--gst-card-padding) / 2);
}

.gst-card-content + .gst-card-footer {
    padding-top: 0;
}

/*
 * CGRID
 *
 * Displays in an auto-repeating grid, however, when the space is too small, it significantly collapses
 * the gap and changes the separation from such large padding, into a vertical list
 */

.gst-cgrid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(340px, 100%), 1fr));
    gap: 1.5em;
    margin: 0;
    padding: 0;
    list-style-type: none;
}

.gst-cgrid-card {
    border-radius: var(--gst-card-radius);
    overflow: hidden;
}

@media (max-width: 700px) {
    .gst-cgrid {
        gap: 0;
        overflow: hidden;
        border-radius: var(--gst-card-radius);
        /* the stack reads as one slab, so the elevation belongs to the list, not each row */
        box-shadow: var(--gst-card-shadow);
    }

    .gst-cgrid-card {
        border-radius: 0 !important;
        overflow: hidden;
        border-width: 0;
        box-shadow: none;
    }

    .gst-cgrid-card + .gst-cgrid-card {
        /* a hairline rule, rather than a 3px gutter showing the page through the slab */
        border-top: 1px solid rgba(var(--gst-contrast-rgb), 0.12);
    }

    /* lifting one row out of a merged stack just tears a hole in it */
    .gst-cgrid .gst-navcard:hover {
        transform: none;
        box-shadow: none;
    }
}

/*
 * Banners
 */

.gst-warning {
    border-radius: var(--gst-card-radius);
    padding: 1em;
    background: #5d3b3b;
    border: 1px solid #442c2c;
    color: white;
}

.gst-tip {
    border-radius: var(--gst-card-radius);
    padding: 1em;
    background: #5c5d3b;
    border: 1px solid #44442c;
    color: white;
}

/*
 * Pagination
 */

.gst-pagination {
    /*
     * 2.5rem is the WCAG 2.5.8 target size. A bare "7" text link was roughly an
     * 8px hit area, which is the main reason the old bar felt unfinished.
     */
    --gst-pagination-size: 2.5rem;

    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.75em;
    padding: 2em 1em;
}

.gst-pagination-list {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    align-items: center;
    gap: 0.375rem;
    margin: 0;
    padding: 0;
    list-style: none;
}

.gst-pagination-item {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* the jump controls sit slightly apart from the run of numbers */
.gst-pagination-item-previous {
    margin-right: 0.4rem;
}

.gst-pagination-item-next {
    margin-left: 0.4rem;
}

.gst-pagination-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.3em;

    min-width: var(--gst-pagination-size);
    height: var(--gst-pagination-size);
    padding: 0 0.7em;
    box-sizing: border-box;

    border: 1px solid transparent;
    border-radius: var(--gst-button-radius, 0.5rem);
    color: var(--gst-container-color);
    text-decoration: none;
    font-weight: 500;
    line-height: 1;
    /* digits share a width, so the row does not twitch between 8 and 11 */
    font-variant-numeric: tabular-nums;

    transition: background-color 140ms var(--gst-ease),
                border-color 140ms var(--gst-ease),
                color 140ms var(--gst-ease),
                box-shadow 140ms var(--gst-ease);
}

a.gst-pagination-link:hover {
    background-color: color-mix(in srgb, var(--gst-container-color) 8%, transparent);
    border-color: color-mix(in srgb, var(--gst-container-color) 18%, transparent);
}

a.gst-pagination-link:active {
    background-color: color-mix(in srgb, var(--gst-container-color) 14%, transparent);
}

a.gst-pagination-link:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gst-container-highlight) 45%, transparent);
}

/*
 * The current page was bold and one size larger, which reflowed the whole row as
 * you paged. A filled tile marks it without changing any metrics.
 */
.gst-pagination-current {
    background-color: var(--gst-container-highlight);
    border-color: var(--gst-container-highlight);
    color: #ffffff;
    font-weight: 650;
    cursor: default;
}

/*
 * Chevrons are decoration. Every link carries an explicit aria-label, which wins
 * the accessible-name computation outright, so generated content cannot leak in.
 */
.gst-pagination-item-first .gst-pagination-link::before {
    content: "\00ab";
}

.gst-pagination-item-previous .gst-pagination-link::before {
    content: "\2039";
}

.gst-pagination-item-next .gst-pagination-link::after {
    content: "\203a";
}

.gst-pagination-item-last .gst-pagination-link::after {
    content: "\00bb";
}

.gst-pagination-item-first .gst-pagination-link::before,
.gst-pagination-item-previous .gst-pagination-link::before,
.gst-pagination-item-next .gst-pagination-link::after,
.gst-pagination-item-last .gst-pagination-link::after {
    font-size: 1.2em;
    line-height: 0;
}

.gst-pagination-status {
    margin: 0;
    padding: 0;
    font-size: 0.875rem;
    font-variant-numeric: tabular-nums;
    color: color-mix(in srgb, var(--gst-container-color) 62%, var(--gst-container-bg));
}

@media (max-width: 600px) {
    .gst-pagination {
        /* a touch target wants more than the pointer minimum */
        --gst-pagination-size: 2.75rem;
        padding: 1.5em 0.5em;
    }

    .gst-pagination-link {
        padding: 0 0.5em;
    }

    /* the jump controls fall back to their chevrons */
    .gst-pagination-item-first .gst-pagination-label,
    .gst-pagination-item-previous .gst-pagination-label,
    .gst-pagination-item-next .gst-pagination-label,
    .gst-pagination-item-last .gst-pagination-label {
        display: none;
    }
}

@media (max-width: 460px) {
    /*
     * Eight numbered tiles plus four jumps cannot fit, and wrapping them to three
     * rows reads worse than dropping them. The status line below already says
     * which page you are on, so keep only the current tile for orientation.
     */
    .gst-pagination-item-page {
        display: none;
    }

    .gst-pagination-item-page:has(.gst-pagination-current) {
        display: block;
    }
}

/*
 * Utility
 */

.gst-no-transition * {
    transition: none !important;
}

ul.gst-clean-list {
    list-style: none;
    margin: 0;
    padding: 0;

    & > li {
        margin: 0;
        padding: 0;
    }
}

.gst-divided-list {
    & > * {
        padding: 3em 1em !important;
    }

    & > *:not(:last-child) {
        border-bottom: 1px dotted rgba(var(--gst-contrast-rgb), 0.2);
    }
}

.gst-divided-list-compact {
    & > * {
        padding: 1em 1em !important;
    }
}


/* completely hides it but is detectable by screen readers */
.gst-sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.gst-hide-empty:empty {
    display: none;
}

/*
 * Code blocks
 */


.gst-md-code-block-other {
    background-color: var(--gst-php-code-bg);
    color: var(--gst-php-code-text);
    border: 1px solid var(--gst-php-code-border);
    padding: 1rem;
    border-radius: 6px;
    font-family: 'Courier New', Courier, monospace;
    overflow-x: auto;
    margin-bottom: 1em;
    white-space: pre-wrap;
}

.gst-code-block-php {
    background-color: var(--gst-php-code-bg);
    color: var(--gst-php-code-text);
    border: 1px solid var(--gst-php-code-border);
    padding: 1rem;
    border-radius: 6px;
    font-family: 'Courier New', Courier, monospace;
    overflow-x: auto;
    margin-bottom: 1em;
}

.gst-code-php {
    font-family: 'Courier New', Courier, monospace;
    /*overflow-x: auto;*/

    & .keyword {
        color: var(--gst-php-code-keyword);
        font-weight: bold;
    }

    & .string {
        color: var(--gst-php-code-string);
    }

    & .comment {
        color: var(--gst-php-code-comment);
        font-style: italic;
    }

    & .variable {
        color: var(--gst-php-code-variable);
    }

    & .function {
        color: var(--gst-php-code-function);
    }

    & .number {
        color: var(--gst-php-code-number);
    }
}

/*
 * Buttons!
 */

/* Custom property fallback if not defined globally */
:root {
    /* sits a step inside --gst-card-radius so a button in a card reads as nested */
    --gst-button-radius: 0.5rem;
}

/* ==========================================
   Base Button Style

   Every variant supplies three tokens and nothing else. State is derived from
   them, so there are no hand-picked hover and active shades to keep in sync:

     --gst-btn-bg    the fill
     --gst-btn-fg    the label, always set explicitly so no ancestor can repaint it
     --gst-btn-ring  the focus ring, normally the fill

   The border and the state shades fall out of those.
   ========================================== */
.gst-btn {
    --gst-btn-bg: transparent;
    --gst-btn-fg: var(--gst-container-color);
    --gst-btn-border: var(--gst-btn-bg);
    --gst-btn-ring: var(--gst-container-highlight);

    /* inline-flex so a button with an icon centres it without inline styles */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4em;

    font-weight: 500;
    line-height: 1.5;
    text-align: center;
    text-decoration: none;
    vertical-align: middle;
    cursor: pointer;
    user-select: none;
    padding: 0.5rem 1rem;
    font-size: 1rem;

    color: var(--gst-btn-fg);
    background-color: var(--gst-btn-bg);
    border: 1px solid var(--gst-btn-border);
    border-radius: var(--gst-button-radius, 0.5rem);

    transition: color 140ms var(--gst-ease),
                background-color 140ms var(--gst-ease),
                border-color 140ms var(--gst-ease),
                box-shadow 140ms var(--gst-ease),
                transform 140ms var(--gst-ease);
}

/*
 * Mixing the fill toward its own label is correct for every variant in both
 * schemes: a dark-on-light button darkens, a light-on-dark button lightens.
 */
.gst-btn:hover {
    background-color: color-mix(in srgb, var(--gst-btn-bg) 88%, var(--gst-btn-fg));
    border-color: color-mix(in srgb, var(--gst-btn-border) 88%, var(--gst-btn-fg));
}

.gst-btn:active, .gst-btn.active {
    background-color: color-mix(in srgb, var(--gst-btn-bg) 78%, var(--gst-btn-fg));
    border-color: color-mix(in srgb, var(--gst-btn-border) 78%, var(--gst-btn-fg));
    transform: translateY(1px);
    transition-duration: 60ms;
}

/*
 * Accessibility focus ring. The old rule set `outline: 0` on the base and restored
 * a ring only per variant, so a bare .gst-btn had no focus indicator at all. The
 * transparent outline is what forced-colors mode paints over.
 */
.gst-btn:focus-visible {
    outline: 2px solid transparent;
    outline-offset: 2px;
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--gst-btn-ring) 45%, transparent);
}

/* Disabled State */
.gst-btn:disabled, .gst-btn.disabled {
    pointer-events: none;
    opacity: 0.65;
    box-shadow: none;
    transform: none;
}

@media (prefers-reduced-motion: reduce) {
    .gst-btn {
        transition-duration: 1ms;
    }

    .gst-btn:active, .gst-btn.active {
        transform: none;
    }
}

/*
 * Variants. Palette retuned from Bootstrap's defaults to this site's slate/indigo
 * language, and to clear 4.5:1 against its own label — Bootstrap's #0d6efd/#fff is
 * 3.6:1 and #0dcaf0 with black is worse.
 */

/* Primary (Indigo) — 6.3:1 on white */
.gst-btn-primary {
    --gst-btn-bg: #4f46e5;
    --gst-btn-fg: #ffffff;
    --gst-btn-ring: #4f46e5;
}

/*
 * Secondary — derived from the container rather than a fixed grey, so it stays
 * legible on a #1e293b card and on a white one without a per-scheme override.
 */
.gst-btn-secondary {
    --gst-btn-bg: color-mix(in srgb, var(--gst-container-color) 10%, transparent);
    --gst-btn-fg: var(--gst-container-color);
    --gst-btn-border: color-mix(in srgb, var(--gst-container-color) 22%, transparent);
    --gst-btn-ring: var(--gst-container-highlight);
}

/* Success (Green) — 5.0:1 on white */
.gst-btn-success {
    --gst-btn-bg: #15803d;
    --gst-btn-fg: #ffffff;
    --gst-btn-ring: #15803d;
}

/* Danger (Red) — 4.8:1 on white */
.gst-btn-danger {
    --gst-btn-bg: #dc2626;
    --gst-btn-fg: #ffffff;
    --gst-btn-ring: #dc2626;
}

/* Warning (Amber) — 7.7:1 on near-black; the label must not follow the scheme */
.gst-btn-warning {
    --gst-btn-bg: #f59e0b;
    --gst-btn-fg: #1c1917;
    --gst-btn-ring: #f59e0b;
}

/* Info (Cyan) — 5.4:1 on white */
.gst-btn-info {
    --gst-btn-bg: #0e7490;
    --gst-btn-fg: #ffffff;
    --gst-btn-ring: #0e7490;
}

/* Light (Off-White) — fixed by name, so it does not follow the scheme */
.gst-btn-light {
    --gst-btn-bg: #f1f5f9;
    --gst-btn-fg: #0f172a;
    --gst-btn-border: #cbd5e1;
    --gst-btn-ring: var(--gst-container-highlight);
}

/* Dark (Slate) — likewise fixed by name */
.gst-btn-dark {
    --gst-btn-bg: #1e293b;
    --gst-btn-fg: #f8fafc;
    --gst-btn-ring: #1e293b;
}
