/* ==========================================================================
   Baamboozle Classroom — theme styles
   Styled with Baamboozle brand color (#FFC700 / #754FF0). Headings use the
   real brand font, Obviously (Semibold, self-hosted below); body copy uses
   the real brand font, Brevia (self-hosted below, 4 weights × upright/italic).
   ========================================================================== */

@font-face {
    font-family: "Obviously";
    src: url("../fonts/Obviously-Semibold.otf") format("opentype");
    /* Only the Semibold weight is available — claim the full weight range so
       browsers render every font-weight using these outlines instead of
       synthesizing a faux-bold/faux-thin version of them. */
    font-weight: 100 900;
    font-style: normal;
    font-display: swap;
}

/* Brevia — real weight files, so each face declares its own specific
   font-weight/font-style instead of a range, so the browser loads the
   matching real outlines per requested weight rather than synthesizing. */
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Light.ttf") format("truetype");
    font-weight: 300;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Regular.ttf") format("truetype");
    font-weight: 400;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Medium.ttf") format("truetype");
    font-weight: 500;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-MediumItalic.ttf") format("truetype");
    font-weight: 500;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Semibold.ttf") format("truetype");
    font-weight: 600;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-SemiboldItalic.ttf") format("truetype");
    font-weight: 600;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Bold.ttf") format("truetype");
    font-weight: 700;
    font-style: normal;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-BoldItalic.ttf") format("truetype");
    font-weight: 700;
    font-style: italic;
    font-display: swap;
}
@font-face {
    font-family: "Brevia";
    src: url("../fonts/Brevia-Black.ttf") format("truetype");
    font-weight: 800;
    font-style: normal;
    font-display: swap;
}

:root {
    /* Baamboozle brand palette — see Brand Guidelines 2022 */
    --color-yellow: #FFC700;
    --color-yellow-soft: #FFF3CC;
    --color-purple: #754FF0;
    --color-purple-dark: #5D38D6;
    /* Measured from baamboozle.com's own white-on-purple pop-text (their
       "shadow-dark-purple" variant) — a darker, monochromatic self-shadow
       rather than a contrasting color. Used on .closing-cta-heading. */
    --color-purple-shadow: #461BD0;
    --color-purple-soft: #EFE9FE;
    --color-coral: #FF6F91;
    --color-orange: #FF9F43;
    --color-ink: #150E28;
    --color-ink-soft: #5F5872;
    /* ~10% lighter than --color-ink-soft (blended toward white), for long
       stretches of article body copy where --color-ink-soft on its own
       still read as too dark next to the title. */
    --color-ink-softer: #6F6980;
    --color-border: #ECE6FB;
    --color-white: #FFFFFF;
    /* Neutral grey for the featured-post panel. */
    --color-bg-soft: #FAFAFA;
    /* Tint behind the pinned/featured post panel: #F1EDFD at 60% opacity. */
    --color-pinned-tint: rgba(241, 237, 253, 0.6);

    /* var(--gh-font-heading)/var(--gh-font-body) are injected by Ghost when an
       editor picks a custom font in Settings > Design & branding > Fonts;
       otherwise these Baamboozle-brand defaults are used. */
    --font-display: var(--gh-font-heading, "Obviously", ui-rounded, "Segoe UI", sans-serif);
    --font-body: var(--gh-font-body, "Brevia", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif);

    --radius-lg: 28px;
    --radius-md: 18px;
    --radius-sm: 12px;
    --radius-pill: 999px;

    --shadow-card: 0 6px 0 rgba(36, 28, 51, 0.06), 0 12px 24px rgba(36, 28, 51, 0.06);
    --max-width: 1160px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    font-family: var(--font-body);
    font-weight: 500;
    color: var(--color-ink);
    background: var(--color-white);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; height: auto; display: block; }

a { color: inherit; text-decoration: none; }

.site-wrap { display: flex; flex-direction: column; min-height: 100vh; }

.eyebrow {
    display: inline-block;
    font-family: var(--font-body);
    font-weight: 700;
    font-size: 13px;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--color-purple);
    margin-bottom: 10px;
}

/* Hero-only variant: a soft purple pill instead of plain uppercase text —
   matches the same pill language as the active category filter
   (background: purple-soft, text: purple) so it reads as a tag/badge next
   to the big hero title instead of a small label easy to miss. The plain
   .eyebrow on post cards is intentionally left as flat text. */
.eyebrow--hero {
    display: inline-flex;
    align-items: center;
    font-size: 13px;
    padding: 7px 16px;
    border-radius: var(--radius-pill);
    background: var(--color-purple-soft);
}

/* Post-card category: matches the pinned post's pill (.eyebrow--hero) —
   same soft-purple fill, purple text, and pill shape — instead of the flat
   uppercase label it used before. margin reset so it sits centred in the
   card's head row. */
.eyebrow--card {
    display: inline-flex;
    align-items: center;
    font-size: 13px;
    padding: 7px 16px;
    border-radius: var(--radius-pill);
    background: var(--color-purple-soft);
    color: var(--color-purple);
    margin: 0;
}

/* ---------- Buttons ---------- */

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-family: var(--font-body);
    font-weight: 700;
    border: none;
    border-radius: var(--radius-pill);
    cursor: pointer;
    text-align: center;
    white-space: nowrap;
    transition: transform .12s ease, opacity .12s ease;
}

.btn:hover { transform: translateY(-2px); opacity: .92; }
.btn:active { transform: translateY(0); opacity: 1; }

.btn-purple { background: var(--color-purple); color: var(--color-white); }
.btn-purple:hover { background: var(--color-purple-dark); }

/* Header "Play games" button only -- turns yellow with purple text on
   hover, rather than the default .btn-purple:hover (which just darkens
   the purple and keeps white text). Scoped to the header so the other
   .btn-purple use on this theme (the 404 page's "Back to blog" button)
   keeps the standard hover. */
.site-header-actions .btn-purple:hover {
    background: var(--color-yellow);
    color: var(--color-purple);
}

.btn-white { background: var(--color-white); color: var(--color-purple); }
.btn-white:hover { background: var(--color-yellow); color: var(--color-ink); }
.btn-yellow {
    background: var(--color-yellow);
    color: var(--color-purple);
    /* Letter-spacing measured off the real footer CTA button's
       Computed panel. */
    letter-spacing: .02em;
    /* Real button has a purple ring drawn as an inset box-shadow
       (measured: inset 0 0 0 2px #754ff0, i.e. --color-purple). */
    box-shadow: inset 0 0 0 2px var(--color-purple);
}
.btn-yellow:hover { background: var(--color-purple); color: var(--color-white); }

/* Sized to match baamboozle.com's own buttons: flat pills, no drop-shadow,
   generous padding relative to their height. */
.btn-large {
    padding: 18px 40px;
    font-size: 20px;
    /* On the real site, font-weight: 800 is set on their "big" size
       modifier class itself (not on a color variant), so it applies
       to every big button regardless of color — hero "Read more" and
       the footer "Join for free" are both btn-large, so both get the
       real Brevia Black face (self-hosted above at font-weight: 800)
       instead of a synthesized/faux-bold 700. */
    font-weight: 800;
}
.btn-small { padding: 13px 18px; font-size: 16px; }

/* ---------- Header ---------- */

.site-header {
    border-bottom: 1px solid var(--color-border);
    background: var(--color-white);
    position: sticky;
    top: 0;
    z-index: 20;
}

.site-header-inner {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 18px 24px;
    display: flex;
    align-items: center;
    gap: 24px;
}

.site-logo { display: flex; align-items: center; margin-right: auto; }
.site-logo img { height: 36px; width: auto; }
.site-logo-text {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 26px;
    color: var(--color-purple);
    -webkit-text-stroke: 1.5px var(--color-ink);
    letter-spacing: .01em;
}

.site-header-actions { display: flex; align-items: center; gap: 14px; }

/* ---------- Homepage banner ---------- */

/* Admin-swappable photo banner (Design & branding → homepage_banner_image).
   Sits below the header and above the featured post on the true homepage
   only; hidden entirely until an image is uploaded. Contained to the site's
   normal max-width like everything else, with rounded corners matching the
   featured-post image and the rest of the site's card language — 21:9 reads
   as a proper wide banner without duplicating the 16:9 ratio already used
   by the featured-post hero image below it. Mobile is treated differently
   on purpose: below 900px it goes full-bleed edge-to-edge with square
   corners, flush against the header, since the rounded/contained version
   read as cramped at narrow widths (see the mobile override further down —
   it drops the max-width/side padding and squares the corners back off). */
.homepage-banner {
    max-width: var(--max-width);
    /* Top margin matches .hero-inner's top margin (40px) below, so the
       header-to-photo gap equals the photo-to-pinned-post gap. */
    margin: 40px auto 32px;
    padding: 0 24px;
}
.homepage-banner-inner {
    aspect-ratio: 21/9;
    background: var(--color-purple-soft);
    /* Matches .hero-inner (the pinned post panel) below it -- both are
       big, full-bleed-ish hero elements that read as one continuous
       block at the top of the page, so they share the same 48px radius
       rather than each using a different value. */
    border-radius: 48px;
    overflow: hidden;
}
.homepage-banner-inner img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}

/* ---------- Closing CTA ---------- */

.closing-cta {
    position: relative;
    overflow: hidden;
    background: var(--color-purple-soft);
}

/* Wave sits at the very top of the section, stretched edge-to-edge.
   White rather than the brand purple: on baamboozle.com this wave caps
   off a solid-purple section above it, but here the section above is
   the plain white post list, so a white wave reads as the natural
   continuation of that white ground dipping into the lavender CTA --
   not a jarring purple slab. z-index:0 (and z-index:1 on
   .closing-cta-inner below) keeps it behind the heading and button --
   position:absolute elements paint above normal-flow content by default
   regardless of DOM order, which is what let it cover the text before
   this fix. Always visible (not tied to .is-visible like the dots below)
   -- it's the section's boundary shape, not a decoration, so it
   shouldn't fade out and leave a flat seam when scrolling past it. */
.closing-cta-wave {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
    height: clamp(40px, 6vw, 90px);
    display: block;
    z-index: 0;
}

.closing-cta-deco {
    position: absolute;
    inset: 0;
    overflow: hidden;
    pointer-events: none;
    z-index: 0;
}

/* Each shape starts hidden/shrunk and fades+scales in as the section
   scrolls into view, then back out again if it scrolls out of view (see
   the IntersectionObserver in main.js) -- a two-way toggle rather than a
   one-shot reveal or a continuous float/bounce loop. */
.cta-deco {
    position: absolute;
    left: var(--x);
    top: var(--y);
    width: var(--size);
    height: var(--size);
    opacity: 0;
    transform: scale(.4) scaleX(var(--flip, 1));
    transition: opacity .5s ease, transform .5s ease;
    transition-delay: var(--delay, 0s);
}
.closing-cta.is-visible .cta-deco {
    opacity: 1;
    transform: scale(1) scaleX(var(--flip, 1));
}

/* Character doodles (actual illustrated assets, not simple shapes): let
   height follow each image's own aspect ratio instead of forcing a
   square box like the plain dots/squiggles above. */
.cta-deco--img {
    height: auto;
    display: block;
}

.closing-cta-inner {
    position: relative;
    z-index: 1;
    max-width: 640px;
    margin: 0 auto;
    /* Top padding clears the wave (max 90px tall) with extra room so the
       heading sits comfortably below it. Bottom padding clears the heart
       and cloud doodles anchored near the bottom (see .cta-deco images). */
    padding: 160px 24px 200px;
    display: flex;
    flex-direction: column;
    align-items: center;
    /* Room for the heading's pop-shadow trailing edge before the next
       element. */
    gap: 24px;
    text-align: center;
}
.closing-cta-heading {
    font-family: var(--font-display);
    /* Real-measured shadow geometry (see the hero headline's original
       treatment), scaled to this heading's own font-size via em. Recolored to
       match the real site's light-purple footer treatment: yellow text with a
       purple pop-shadow. Line-height opened up
       the same way to give the diagonal trail clearance. */
    font-weight: 600;
    font-size: 38px;
    line-height: 1.55;
    letter-spacing: .06em;
    color: var(--color-yellow);
    text-shadow:
        -0.059em -0.059em var(--color-purple),
        -0.059em -0.029em var(--color-purple),
        -0.059em 0 var(--color-purple),
        0.059em -0.029em var(--color-purple),
        0 -0.059em var(--color-purple),
        0.029em -0.059em var(--color-purple),
        0.059em -0.059em var(--color-purple),
        0.029em 0.059em var(--color-purple),
        -0.059em 0.029em var(--color-purple),
        -0.059em 0.059em var(--color-purple),
        0.059em 0.059em var(--color-purple),
        0.059em 0 var(--color-purple),
        0.059em 0.029em var(--color-purple),
        -0.059em 0.088em 0.029em var(--color-purple),
        -0.029em 0.088em 0.029em var(--color-purple),
        -0.029em 0.118em 0.029em var(--color-purple),
        0 0.118em 0.029em var(--color-purple),
        0.029em 0.118em 0.029em var(--color-purple),
        0 0.147em 0.029em var(--color-purple),
        0.029em 0.147em 0.029em var(--color-purple),
        0.029em 0.176em 0.029em var(--color-purple),
        0.059em 0.206em 0.029em var(--color-purple),
        0.088em 0.206em 0.029em var(--color-purple),
        0.088em 0.235em 0.029em var(--color-purple),
        0.118em 0.265em 0.029em var(--color-purple),
        0.176em 0.265em 0.029em var(--color-purple),
        0.088em -0.029em 0.029em var(--color-purple),
        0.088em 0 0.029em var(--color-purple),
        0.118em 0 0.029em var(--color-purple),
        0.118em 0.029em 0.029em var(--color-purple),
        0.147em 0.029em 0.029em var(--color-purple),
        0.147em 0.059em 0.029em var(--color-purple),
        0.176em 0.059em 0.029em var(--color-purple),
        0.206em 0.088em 0.029em var(--color-purple),
        0.235em 0.118em 0.029em var(--color-purple),
        0.235em 0.147em 0.029em var(--color-purple),
        0.235em 0.176em 0.029em var(--color-purple),
        0.235em 0.206em 0.029em var(--color-purple),
        0.235em 0.235em 0.029em var(--color-purple),
        0.235em 0.265em 0.029em var(--color-purple);
    margin: 0;
    text-wrap: balance;
}

/* ---------- Hero ---------- */

.hero {
    background: var(--color-white);
}

.hero-inner {
    /* Positioning context for the title link's stretched-link overlay
       below, matching the post cards -- click anywhere on this panel to
       open the post. */
    position: relative;
    /* Matches .homepage-banner-inner's effective width above: that banner
       is inset 24px per side via padding on its own max-width box, so its
       visible image is (--max-width - 48px). This panel's own padding
       doesn't shrink its background the same way (padding insets content,
       not the box's own background), so without this adjustment its
       background renders 48px wider than the header image above it. */
    max-width: calc(var(--max-width) - 48px);
    /* Vertical margin instead of the old border-bottom — the grey panel
       itself now separates the hero from the header above and the grid
       below, so a divider line would be redundant. */
    margin: 40px auto 56px;
    padding: 48px 40px;
    background: var(--color-pinned-tint);
    /* 48px, not the shared --radius-md token the blog cards use — this
       panel is meant to read as a bigger, standalone hero element. */
    border-radius: 48px;
    display: grid;
    grid-template-columns: 0.92fr 1.08fr;
    /* Named areas instead of two plain items so the heading and the rest of
       the copy (excerpt/meta/button) can be split apart on mobile, with the
       image sandwiched between them — see the mobile override below. On
       desktop "media" spans both rows, reproducing the original simple
       two-column layout exactly. */
    grid-template-areas:
        "heading media"
        "copy    media";
    column-gap: 48px;
    row-gap: 0;
    align-items: center;
    /* Lift + shadow on hover, matching the post cards below -- without
       this the featured post (the biggest, most prominent thing on the
       page) gave no hover feedback at all. The title itself doesn't also
       turn purple on hover (unlike the small cards) -- with a headline
       this large, adding that on top of the lift/shadow plus "Read
       more"'s own color change read as too much purple competing for
       attention at once; the lift/shadow alone is signal enough. */
    transition: transform .15s ease, box-shadow .15s ease;
}

.hero-inner:hover {
    transform: translateY(-4px);
    box-shadow: var(--shadow-card);
}

/* Feature image zooms in slightly on hover (clipped by .hero-media's own
   rounded corners, set above). "Read more" also gets its hover color +
   arrow-slide from anywhere on the card, not just when hovering the CTA
   text directly -- consistent with the rest of the panel now reacting
   as one clickable unit rather than the CTA being its own separate
   little island. */
.hero-inner:hover .hero-media img {
    transform: scale(1.05);
}
.hero-inner:hover .hero-cta {
    color: var(--color-purple);
}
.hero-inner:hover .hero-cta-arrow {
    transform: translateX(4px);
}

.hero-heading { grid-area: heading; }
.hero-media { grid-area: media; }
.hero-copy { grid-area: copy; }

.hero .eyebrow--hero { color: var(--color-purple); }

.hero-title {
    font-family: var(--font-display);
    /* Was 40px; tested against real post titles and found that size
       pushed a title like "Mom-umental Mother's Day Games for English
       Class" to 4 lines, splitting "English Class" across two of them
       and stranding a lone word on the last line. 34px (already used on
       the error page's reused .hero-title, coincidentally) brings it to
       3 lines that group into sensible phrases instead, with no real
       loss of visual weight -- still far larger than anything else on
       the page. */
    font-size: 34px;
    line-height: 1.12;
    font-weight: 800;
    margin: 0 0 18px;
    color: var(--color-ink);
}

.hero-title a { color: inherit; }

.hero-excerpt {
    font-size: 18px;
    color: rgba(36,28,51,.75);
    margin: 0 0 20px;
    max-width: 46ch;
}

.hero .post-meta { margin-bottom: 26px; }

.hero-media {
    /* Wrapper (not the img itself) owns the rounded corners + clipping,
       so the zoom-on-hover transform below (applied to the img) gets
       clipped to this shape instead of spilling past it. */
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.hero-media img,
.hero-media-placeholder {
    background: var(--color-purple-soft);
    /* Matches the real aspect ratio of Baamboozle's own blog feature images
       (measured 1140x641, i.e. 16:9) so every post's hero image reads as a
       wide "banner" crop instead of the boxier 4:3 placeholder shape. */
    aspect-ratio: 16 / 9;
}

.hero-media img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    transition: transform .3s ease;
}

.hero-media-placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 64px;
}

/* Hero's "Read more" — a plain text link with a trailing arrow instead of a
   filled pill button, so the hero card (already a bold grey/purple/photo
   block) doesn't also need a heavy CTA button competing for attention.
   The footer's "Join for free" keeps the filled btn-yellow treatment —
   that's the one true button/conversion action on the page. */
.hero-cta {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-body);
    font-weight: 800;
    font-size: 18px;
    color: var(--color-ink);
    transition: color .15s ease;
}

.hero-cta-arrow {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    transition: transform .15s ease;
}

/* Hover (desktop) and active/tap (mobile, no hover capability) both read as
   "engaged" the same way: text and arrow switch to brand purple together. */
.hero-cta:hover,
.hero-cta:active {
    color: var(--color-purple);
}

.hero-cta:hover .hero-cta-arrow,
.hero-cta:active .hero-cta-arrow {
    transform: translateX(4px);
}

/* Same stretched-link pattern as the post cards: an invisible overlay on
   the title link, sized to the whole panel via .hero-inner's
   position:relative above, so a click anywhere on the featured post --
   image, excerpt, whitespace -- opens it. The category pill and "Read
   more" link both stay independently elevated above the overlay: the
   pill because it goes to a different destination (the tag archive, not
   the post) and would otherwise be swallowed by one giant link; the CTA
   because it's a real link with its own hover animation (color shift +
   arrow slide) that would stop firing if the invisible overlay sat on
   top of it and caught the hover instead. Both are inline/content-sized
   elements, not full-width rows, so elevating them doesn't create a
   dead-click zone the way elevating a full-width row would (see the
   post-card fix for exactly that mistake). */
.hero-title a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}
.eyebrow--hero, .hero-cta {
    position: relative;
    z-index: 2;
}

/* ---------- Post meta ---------- */

.post-meta {
    font-family: var(--font-body);
    font-weight: 600;
    font-size: 14px;
    color: var(--color-ink);
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
}

.post-meta-dot { color: var(--color-orange); }

.post-meta--card { font-size: 13px; color: var(--color-ink-soft); margin-top: auto; }

/* ---------- Search bar ---------- */

/* Triggers Ghost's built-in search (data-ghost-search) — no custom search
   index to build or keep in sync, and it already covers every post/tag on
   the site. Styled as a pill "input" so it reads as a real search field even
   though it's actually a button that opens Ghost's search modal on click.
   Lives in the categories sidebar (index.hbs) as its own card, stacked above
   the categories list — search and category browsing are both ways to find
   a post, so they read as one "find something" module instead of search
   being a separate full-width section up top. */
.search-bar {
    width: 100%;
    margin: 0 0 16px;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 16px;
    background: var(--color-white);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-card);
    font-family: var(--font-body);
    text-align: left;
    cursor: pointer;
    transition: border-color .15s ease, background .15s ease;
}

.search-bar:hover {
    border-color: var(--color-purple);
    background: var(--color-purple-soft);
}

.search-bar:focus-visible {
    outline: none;
    border-color: var(--color-purple);
}

.search-bar-icon {
    width: 20px;
    height: 20px;
    flex-shrink: 0;
    color: var(--color-purple);
}

.search-bar-text {
    font-weight: 600;
    font-size: 15px;
    color: var(--color-ink-soft);
}

/* ---------- Listing layout ---------- */

.listing-inner {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 48px 24px 80px;
    display: grid;
    grid-template-columns: 1fr 240px;
    gap: 44px;
    align-items: start;
}

/* Sidebar sits second in the grid template (right column) while staying
   first in the HTML — order flips its visual position without touching
   markup or its DOM/tab order relative to the post grid. */
.categories-rail { position: sticky; top: 92px; order: 2; }
.post-grid-wrap { order: 1; }

.categories-card { }

/* No heading above the list anymore — a top border stands in for it, so
   the pills still read as one contained group instead of floating loose
   next to the post grid. */
.categories-list {
    list-style: none;
    margin: 0;
    padding: 14px 0 0;
    border-top: 1px solid var(--color-border);
    display: flex;
    flex-direction: column;
    gap: 6px;
}

.category-pill {
    display: block;
    padding: 10px 14px;
    border-radius: var(--radius-sm);
    font-weight: 700;
    font-size: 14.5px;
    color: var(--color-ink);
    border: 1.5px solid transparent;
    /* Without this, mobile browsers draw their own tap-highlight rectangle
       over a link on touch — a flat, square-cornered box that ignores the
       pill's border-radius. Turning it off lets our own rounded states
       (hover fill below, focus ring) be the only highlight shown. */
    -webkit-tap-highlight-color: transparent;
}

.category-pill:hover { background: #F1EDFD; }

/* Keyboard/touch focus ring — box-shadow (not outline) so it always follows
   the pill's rounded corners instead of drawing a sharp-edged rectangle. */
.category-pill:focus-visible {
    outline: none;
    box-shadow: 0 0 0 2px var(--color-purple);
}

.category-pill.is-active {
    background: var(--color-purple-soft);
    border-color: var(--color-purple);
    color: var(--color-purple);
}

.listing-kicker {
    font-family: var(--font-display);
    text-transform: uppercase;
    letter-spacing: .05em;
    font-size: 13px;
    color: var(--color-ink-soft);
    margin: 0;
}

.listing-heading {
    font-family: var(--font-display);
    font-size: 32px;
    margin: 4px 0 28px;
}

.post-grid {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 28px;
}

.post-grid-empty { color: var(--color-ink-soft); }

/* ---------- Post card ---------- */

.post-card {
    border: 1.5px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--color-white);
    transition: transform .15s ease, box-shadow .15s ease;
    display: flex;
    flex-direction: column;
    /* Positioning context for the title link's stretched-link overlay
       below, so clicking anywhere on the card opens the post. */
    position: relative;
}

.post-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-card); }

.post-card-image-link { display: block; }

.post-card-image {
    width: 100%;
    aspect-ratio: 16 / 10;
    object-fit: cover;
    background: var(--color-yellow-soft);
}

.post-card-image--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 40px;
}

.post-card-body { padding: 20px 22px 24px; display: flex; flex-direction: column; gap: 8px; flex: 1; }

/* Top row of the card: category pill. */
.post-card-head {
    display: flex;
    align-items: center;
    gap: 12px;
}

.post-card-title {
    font-family: var(--font-display);
    font-size: 20px;
    /* 1.35, not a tighter 1.2-ish value — Obviously's descenders (g, y) sit
       low enough that a tighter box gets sliced flat by the overflow:hidden
       clamp below, chopping the curl off any descender in the title. */
    line-height: 1.35;
    margin: 0;
    /* Single-line title, truncated with an ellipsis when it doesn't fit.
       Line-based clamp so it stays exactly one line at any card width. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 1;
    line-clamp: 1;
    overflow: hidden;
}

.post-card-title a:hover { color: var(--color-purple); }

/* "Stretched link": an invisible overlay on the title link, sized to the
   whole card via the position:relative ancestor above, so a click
   anywhere on the card -- image, excerpt, whitespace -- opens the post.
   This is the standard pattern for a clickable card that also contains
   a second, differently-targeted link (the category pill below opens
   the tag archive, not the post): wrapping the *entire* card in one
   giant <a> would either swallow that second link or produce invalid
   nested <a> tags. A single stretched overlay keeps one real link (the
   title's, for assistive tech) while the pill stays independently
   clickable via z-index above it. */
.post-card-title a::after {
    content: "";
    position: absolute;
    inset: 0;
    z-index: 1;
}
/* Only the pill itself sits above the overlay (not the whole
   .post-card-head row it's in) -- that row is a full-width flex
   container, and the pill doesn't stretch to fill it, so elevating the
   row would lift the empty space beside the pill too: clicks would land
   above the stretched overlay there but hit no actual link, going dead
   instead of opening the post like the rest of the card. */
.eyebrow--card, .post-card-image-link {
    position: relative;
    z-index: 2;
}

.post-card-excerpt {
    color: var(--color-ink-soft);
    font-size: 14.5px;
    line-height: 1.5;
    margin: 0;
    /* Line-based clamp, not a fixed pixel height — it always caps at 2 lines
       of wrapped text no matter how the card's width changes (window resize,
       breakpoint, zoom), rather than cutting off at a fixed px cap that could
       show more or less than 2 lines depending on width. */
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    /* Hard backstop at exactly 2 lines' worth of height. flex:1 previously
       stretched this element to fill leftover card space, which could make
       -webkit-line-clamp mis-measure "2 lines" against a taller flexed box
       and let a 3rd line of long excerpts slip through uncapped. The meta
       row below is pinned to the bottom via margin-top: auto instead, so
       card layout stays even without stretching the excerpt itself. */
    max-height: calc(1.5em * 2);
}

/* ---------- Pagination ---------- */

/* Pagination is wayfinding, not a call to action, so it stays in the
   UI/body face (Brevia) at a moderate weight and reads as text links
   rather than buttons -- keeps it visually quieter than the real CTAs
   ("Read more" / "Join for free"), which are the only things on the
   page set in Obviously. */
.pagination {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-top: 48px;
    padding-top: 28px;
    border-top: 1px solid var(--color-border);
    font-family: var(--font-body);
    font-size: 15px;
    font-weight: 600;
}

.pagination .older-posts,
.pagination .newer-posts {
    color: var(--color-ink);
    text-decoration: none;
    padding-bottom: 2px;
    border-bottom: 1.5px solid transparent;
}

.pagination .older-posts:hover,
.pagination .newer-posts:hover {
    color: var(--color-purple);
    border-bottom-color: var(--color-purple);
}

.pagination .page-number {
    color: var(--color-ink-soft);
    font-weight: 500;
}

/* ---------- Single post ---------- */

/* Default padding-top (48px) covers page.hbs, which still puts the back
   link and title inside .post-full-header directly with nothing above
   it. post.hbs (below) puts a .post-full-nav strip and/or the full-bleed
   .post-full-media--top banner before .post-full instead, and those two
   sibling rules -- more specific than the plain class alone -- override
   this default so the header doesn't end up with doubled-up spacing. */
.post-full { max-width: 760px; margin: 0 auto; padding: 48px 24px 20px; }

.post-full-nav { max-width: 760px; margin: 0 auto; padding: 28px 24px 0; }

.post-full-nav + .post-full { padding-top: 32px; }
.post-full-media--top + .post-full { padding-top: 40px; }

.post-back-link {
    display: inline-block;
    font-weight: 700;
    font-size: 14px;
    color: var(--color-ink-soft);
    margin-bottom: 22px;
}
.post-back-link:hover { color: var(--color-purple); }

.post-full-title {
    font-family: var(--font-display);
    font-size: 40px;
    line-height: 1.12;
    /* Generous gap below the title so the tag/date line reads as a
       distinct, secondary line rather than crowding the headline. */
    margin: 0 0 28px;
    text-align: center;
}

/* Gap down to the body copy is double the title-to-meta gap above (56px
   vs 28px), so the meta line reads as closing out the header instead of
   sitting right on top of the article text. Lighter than the title: the
   meta line is supporting info, not part of the headline's hierarchy. */
.post-meta--full { justify-content: center; margin-bottom: 56px; color: var(--color-ink-soft); }

.post-meta-tag { color: var(--color-purple); font-weight: 700; text-decoration: none; }
.post-meta-tag:hover { text-decoration: underline; }

.post-full-media {
    max-width: 960px;
    margin: 32px auto;
    padding: 0 24px;
}
.post-full-media img { border-radius: var(--radius-lg); }
.post-full-media figcaption { text-align: center; color: var(--color-ink-soft); font-size: 13px; margin-top: 10px; }

/* Modifier for the post's own feature image at the very top of the page
   (post.hbs) -- same boxed, rounded-corner treatment as the base
   .post-full-media class above (a full-bleed edge-to-edge version was
   tried and felt oversized/inconsistent with the rest of the theme's
   rounded-card language, so this keeps the original contained look and
   only adjusts the spacing now that the image sits above the title
   instead of below it). */
.post-full-media--top {
    margin: 20px auto 32px;
}
.post-full-media--top + .post-full { padding-top: 0; }

.post-full-body {
    font-size: 18px;
    line-height: 1.75;
    /* Softer than the title, same idea as the meta line above -- keeps
       the headline as the one strong-black element on the page instead
       of everything competing at full ink contrast. One step lighter
       than --color-ink-soft since that alone still read too dark over
       this much running text. */
    color: var(--color-ink-softer);
}

.post-full-body h2, .post-full-body h3, .post-full-body h4 {
    font-family: var(--font-display);
    line-height: 1.3;
    /* Subheadings stay full-strength ink (not the softer body color) so
       they still read as structural signposts within the article. */
    color: var(--color-ink);
}

.post-full-body a { color: var(--color-purple); text-decoration: underline; text-decoration-color: var(--color-yellow); text-decoration-thickness: 2px; }

.post-full-body blockquote {
    margin: 28px 0;
    padding: 4px 0 4px 22px;
    border-left: 4px solid var(--color-yellow);
    font-style: italic;
    color: var(--color-ink-soft);
}

.post-full-body img { border-radius: var(--radius-md); }

/* Per-game showcase blurbs ("Students read the clue...", "Helps with:",
   "Best for:") are pasted into these posts as raw HTML with an inline
   font-size:1.25rem — noticeably bigger than the rest of the article's
   18px body copy. Overriding back to the article's own type scale so
   these blocks read as part of the same article, not a separate size.
   !important is required here since it's beating an inline style we
   don't control at the source. */
.post-full-body p[style*="font-size:1.25rem"] {
    font-size: 18px !important;
    line-height: 1.75 !important;
}

/* Numbered-game badges ("1", "2", "9"...) in the same per-game showcase
   blocks: pasted in as a pill (48x28px, border-radius:999px). Changed to
   a circle at 2x the pill's height (56x56px) with a 28px centered
   number. !important again since these are inline styles baked into the
   post content, not theme markup. */
.post-full-body div[style*="width:48px"][style*="height:28px"][style*="border-radius:999px"] {
    width: 56px !important;
    height: 56px !important;
    border-radius: 50% !important;
    font-size: 28px !important;
    display: flex !important;
    align-items: center !important;
    justify-content: center !important;
    text-align: center !important;
}

/* The badge's own row uses align-items:baseline, which aligns it to the
   title's baseline only -- the byline sits in a second line the row
   never accounts for. Centering against the row instead centers the
   badge against the full title+byline block. */
.post-full-body div[style*="align-items:baseline"][style*="gap:12px"] {
    align-items: center !important;
}

.post-full-body .kg-width-wide {
    width: 100%;
    max-width: 1040px;
    margin-left: 50%;
    transform: translateX(-50%);
}

.post-full-body .kg-width-full {
    width: 100vw;
    max-width: 1200px;
    margin-left: 50%;
    transform: translateX(-50%);
}
.post-full-body .kg-width-full img,
.post-full-body .kg-width-wide img { border-radius: var(--radius-md); width: 100%; }

.post-full-body code { background: var(--color-yellow-soft); padding: 2px 6px; border-radius: 6px; font-size: .9em; }
.post-full-body pre { background: var(--color-ink); color: var(--color-white); padding: 18px; border-radius: var(--radius-md); overflow-x: auto; }
.post-full-body pre code { background: none; padding: 0; }

.post-full-footer {
    max-width: 760px;
    margin: 40px auto 0;
    padding: 28px 24px 0;
    border-top: 1px solid var(--color-border);
}

.post-tags { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 28px; }

/* ---------- Related ---------- */

.related { background: var(--color-purple-soft); }
.related-inner { max-width: var(--max-width); margin: 0 auto; padding: 56px 24px; }

.related-header {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 16px;
    margin-bottom: 26px;
}
.related-title { font-family: var(--font-display); font-size: 26px; margin: 0; }
.related-view-all {
    flex-shrink: 0;
    font-weight: 700;
    font-size: 15px;
    color: var(--color-purple);
    text-decoration: underline;
    text-underline-offset: 3px;
}
.related-view-all:hover { color: var(--color-purple-dark); }

/* Always at least 3 related posts (see post.hbs get limit="3"), laid out in
   one horizontal row on desktop; steps down to 2, then 1 column as the
   viewport narrows so cards stay readable on tablet/mobile. */
.related-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 28px;
}

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

.error-page {
    max-width: 640px;
    margin: 0 auto;
    padding: 100px 24px;
    text-align: center;
}
.error-page .hero-excerpt { margin-left: auto; margin-right: auto; }

/* ---------- Footer ---------- */

/* Same light-purple ground as .closing-cta above it, on purpose — the real
   site runs its CTA and footer as one continuous panel with no visible seam
   between them, so this reuses the same token rather than a separate color. */
.site-footer { margin-top: auto; background: var(--color-purple-soft); color: var(--color-ink); position: relative; overflow: hidden; }

/* Sits flush at the bottom-left like a little plant growing up from the
   footer's edge -- no clipping risk since it's anchored from the bottom,
   not a percentage from the top. Fades/scales in and out on scroll the
   same way the closing-cta doodles do (see main.js + .site-footer.is-visible
   below), for consistency with the rest of the doodles on the page. */
.site-footer-doodle {
    position: absolute;
    left: 4%;
    bottom: 0;
    width: 90px;
    height: auto;
    pointer-events: none;
    opacity: 0;
    transform: scale(.4);
    transform-origin: bottom center;
    transition: opacity .5s ease, transform .5s ease;
}
.site-footer.is-visible .site-footer-doodle {
    opacity: 1;
    transform: scale(1);
}

.site-footer-inner {
    max-width: var(--max-width);
    margin: 0 auto;
    padding: 52px 24px 32px;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 28px;
}

.site-footer-brand { max-width: 320px; display: flex; flex-direction: column; align-items: center; }
.site-footer-logo { display: inline-flex; align-items: center; }
.site-footer-logo img { height: 60px; width: auto; }
.site-footer-logo-text {
    font-family: var(--font-display);
    font-weight: 800;
    font-size: 22px;
    color: var(--color-yellow);
    -webkit-text-stroke: 1.2px var(--color-purple);
}
.site-footer-brand p { color: var(--color-purple); font-weight: 600; font-size: 14.5px; margin-top: 10px; }

.site-footer-bottom {
    text-align: center;
    font-size: 13px;
    color: var(--color-purple);
    padding: 18px 24px 28px;
}

/* ---------- Responsive ---------- */

@media (max-width: 900px) {
    /* Full-bleed edge-to-edge on mobile, unlike the rounded/contained
       desktop version — drop the max-width and side padding so it spans
       the viewport, and square the corners back off since a rounded edge
       reads oddly once the banner touches both sides of the screen. */
    .homepage-banner {
        max-width: none;
        margin: 0 0 32px;
        padding: 0;
    }
    .homepage-banner-inner { border-radius: 0; }
    .hero-inner {
        grid-template-columns: 1fr;
        /* Heading first, then the photo, then the excerpt/meta/button —
           not photo-first (that stacked two photos back-to-back under the
           homepage banner with nothing breaking them up) and not photo-last
           either (landing the image after the "Read more" button read as
           misplaced). This puts the image right under the title, which is
           where readers expect it. */
        grid-template-areas:
            "heading"
            "media"
            "copy";
        row-gap: 20px;
        /* Side margin so the grey panel still reads as a floating card on
           narrower screens instead of stretching edge-to-edge. */
        margin: 32px 16px 40px;
        padding: 32px 24px;
    }
    .search-bar {
        margin: 0 0 20px;
        padding: 14px 18px;
    }
    .listing-inner { grid-template-columns: 1fr; }
    /* The right-column "order" that moves the sidebar next to the post
       grid on desktop is a purely visual desktop trick — on a single
       stacked column it would otherwise push the category list below
       every post card. Reset order here so categories go back to their
       natural place in the markup: before the post grid. */
    .categories-rail { position: static; order: 0; }
    .post-grid-wrap { order: 0; }
    /* Wrapped pill chips read as cramped/busy at phone widths — switched to
       a plain stacked list instead: a flat list of rows with only the
       active category boxed. Assumes a
       short category list (kept to ~4), so a full-height list needs no
       collapse/accordion behavior. */
    .categories-list { flex-direction: column; gap: 2px; padding-top: 12px; }
    .category-pill {
        /* Thinner than the heading's Bold, so the two read as distinct
           levels of a hierarchy rather than one undifferentiated block of
           bold text. */
        font-weight: 500;
        padding: 14px 4px;
        border: none;
        /* Flat rows at rest (no border/background, so this radius is
           invisible until hover/focus draws a fill) — kept rounded so the
           hover/tap highlight and focus ring are soft-cornered like the
           active pill's purple box below, not a sharp rectangle. */
        border-radius: var(--radius-sm);
    }
    .category-pill.is-active {
        font-weight: 600;
        padding: 12px 16px;
        border: 1.5px solid var(--color-purple);
        border-radius: var(--radius-sm);
    }
    .related-grid { grid-template-columns: repeat(2, 1fr); }

    /* ---------- Closing CTA (mobile) ---------- */

    /* 2/3 of full viewport height rather than 100vh -- the full-height
       version (with doodles filling the extra space) read as too long
       and empty once the doodles below were removed. Still flex-centers
       the heading+button group within that shorter height. */
    .closing-cta {
        min-height: 66.67vh;
        display: flex;
        flex-direction: column;
        justify-content: center;
    }
    .closing-cta-inner {
        /* Top padding clears the wave; bottom padding is half of the
           desktop-derived 60px, halving the gap down to the footer
           below (paired with .site-footer-inner's halved top padding). */
        padding: 100px 24px 30px;
    }

    /* Only three doodles kept on mobile -- flower and star-burst tucked
       into the top corners (below the wave, above the centered heading),
       heart anchored to the very bottom (safely below the button/logo
       area, and bottom-anchored so it can't get clipped regardless of
       exact section height). Blue-creature and the cloud are dropped
       entirely -- five doodles crammed into this much shorter section
       is what caused the crowding/overlap before. */
    .closing-cta-deco img[src*="blue-creature.svg"],
    .closing-cta-deco img[src*="cloud-rainbow.svg"] {
        display: none !important;
    }
    /* Small red dot (one of the original background dots, untouched by
       the mobile doodle layout above) was landing right on top of the
       repositioned flower at this width -- hidden here rather than
       hunting for another free spot in an already-tight layout. */
    .closing-cta-deco svg[style*="--y:22%"] {
        display: none !important;
    }
    .closing-cta-deco img[src*="flower.svg"] {
        left: 8% !important;
        top: 12% !important;
    }
    .closing-cta-deco img[src*="star-burst.svg"] {
        left: 76% !important;
        top: 12% !important;
    }
    .closing-cta-deco img[src*="heart.svg"] {
        left: 55% !important;
        top: auto !important;
        bottom: 16px !important;
        width: 90px !important;
        margin-left: 0 !important;
    }

    /* ---------- Footer (mobile) ---------- */

    /* Top padding halved to match .closing-cta-inner's halved bottom
       padding above -- together they halve the visual gap between the
       "Play games" button and the Baamboozle logo below it. */
    .site-footer-inner { padding-top: 26px; }

    /* Tree doodle removed along with the rest of the doodles above. */
    .site-footer-doodle { display: none !important; }
}

@media (max-width: 640px) {
    /* The header nav's "Join for free" pill was wrapping onto two lines
       here (logo + button no longer fit on one row at phone widths),
       which blew the pill out into a tall, chunky oval instead of a
       normal button. .btn now has white-space: nowrap so it can't wrap
       at all, so the header also needs to shrink to make room: a
       smaller wordmark, tighter gaps, and a smaller button size. */
    .site-header-inner { padding: 14px 16px; gap: 12px; }
    .site-logo img { height: 28px; }
    .site-logo-text { font-size: 20px; }
    .site-header-actions .btn-small { padding: 9px 14px; font-size: 14px; }

    .hero-title { font-size: 24px; }
    /* Sized to match the title's proportion to .post-card-excerpt's 20px
       title, rather than matching the excerpt's raw pixel value -- at
       24px the title is bigger than a card's, so pairing it with the
       cards' exact 14.5px excerpt made the preview text look small and
       cramped relative to its own headline. */
    .hero-excerpt { font-size: 17px; }
    /* text-shadow on .closing-cta-heading is in em, so it stays correctly
       proportioned automatically at these smaller mobile font-sizes — no
       separate shadow override needed here any more. */
    .closing-cta-heading { font-size: 28px; }
    /* btn-large is sized to match baamboozle.com's real desktop buttons —
       generous padding, 20px/800-weight text. Next to the header's compact
       btn-small "Join for free" on a phone screen that reads as oversized.
       Scaled down here, but kept a clear step above btn-small so "Read
       more" and the footer CTA still read as the primary action, not a
       secondary nav link. */
    .btn-large { padding: 14px 28px; font-size: 17px; }
    .homepage-banner-inner { aspect-ratio: 16/9; }
    .post-grid { grid-template-columns: 1fr; }
    .post-full-title { font-size: 30px; }
    .related-header { flex-direction: column; align-items: flex-start; gap: 6px; }
    .related-grid { grid-template-columns: 1fr; }
}

/* ---------- Back to top ---------- */
/* Circular scroll-to-top control fixed to the bottom-right. Inactive: white
   circle with a purple border (stroke) and purple arrow. Hover/active: fills
   purple with a white arrow. Toggled visible by JS (main.js) past a scroll
   threshold via the [hidden] attribute + .is-visible fade. */
.back-to-top {
    position: fixed;
    right: 24px;
    bottom: 24px;
    z-index: 50;
    width: 52px;
    height: 52px;
    display: grid;
    place-items: center;
    padding: 0;
    border-radius: var(--radius-pill);
    background: var(--color-white);
    border: 2px solid var(--color-purple);
    color: var(--color-purple);
    cursor: pointer;
    box-shadow: var(--shadow-card);
    opacity: 0;
    transform: translateY(8px);
    transition: opacity 0.2s ease, transform 0.2s ease,
                background-color 0.2s ease, color 0.2s ease, border-color 0.2s ease;
}

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

.back-to-top:hover,
.back-to-top:active {
    background: var(--color-purple);
    border-color: var(--color-purple);
    color: var(--color-white);
}

.back-to-top:focus-visible {
    outline: 3px solid var(--color-purple-soft);
    outline-offset: 2px;
}

.back-to-top svg {
    display: block;
}

@media (max-width: 640px) {
    .back-to-top {
        right: 16px;
        bottom: 16px;
        width: 46px;
        height: 46px;
    }
}
