/* Grapevine Learning 2026 — the skin.
 *
 * Loaded AFTER the plugin's gvl-lms.css (the dependency is declared in
 * inc/enqueue.php, so the order is guaranteed rather than incidental).
 *
 * This file is the whole reskin, and it has exactly two jobs:
 *   1. override the plugin's design tokens
 *   2. style the chrome the plugin does not render — top bar, footer, and the
 *      indent that keeps them clear of the fixed course rail
 *
 * It deliberately contains no rules for .gvl-modrow, .gvl-lessoncard,
 * .gvl-player or any other LMS component. If a component needs changing, the
 * change belongs in a token — and if no token fits, the plugin is missing one.
 */

/* ── 1. Tokens ──────────────────────────────────────────────────────────────
 * PLACEHOLDER PALETTE. Derived from the green (#62cb31) in the legacy theme,
 * darkened to #3c8526 so it clears 4.5:1 on white for body-sized text. Swap
 * these six values for the real brand palette; nothing else needs to change. */
:root {
    --gvl-primary:       #3c8526;
    --gvl-primary-dark:  #2a5e1a;
    --gvl-primary-light: #9dd487;
    --gvl-primary-wash:  #eff8ea;
    --gvl-accent:        #0b7f8f;   /* progress / completion, distinct from primary */

    /* A modal floats on a 93%-white, blurred backdrop, so the ordinary rule
       colours — #f1f2f3 and #e7e8e9 — leave it with no visible edge at all.
       This is deliberately darker than any line used on the page itself. */
    --gvl-modal-edge:    #d2d5d9;

    --gvl-radius-lg:     0.75rem;

    /* Chrome measurements the plugin's rail also reads. */
    --gvl-sidebar-w:     300px;
    --gvl-topbar-h:      90px;
}

/* The vendored eDocs base used to hardcode its own blue behind !important in
 * 173 places. Rather than override each one, the two vendored files now
 * reference these tokens directly (see the header comment in style.css), so
 * setting the variables above is genuinely all a reskin has to do.
 */


/* ── 2. Top bar ─────────────────────────────────────────────────────────────
 * The eDocs template positions its top-bar nav absolutely and leaves the bar
 * position:relative, so it scrolls away. Rebuilt as a sticky flex row, which
 * also lets the brand, the page context and the nav sit on one baseline
 * without magic offsets. */
.top-page-header {
    position: sticky;
    top: 0;
    z-index: 900;
    display: flex;
    align-items: center;
    gap: 28px;
    height: var(--gvl-topbar-h);
    padding: 0 40px;
    background-color: var(--gvl-surface);
    border-bottom: 1px solid var(--gvl-line);
}

.gvl-topbar-brand {
    flex: 0 0 auto;
    display: flex;
    align-items: center;
}

.gvl-topbar-brand img,
.gvl-wordmark {
    display: inline-flex;
    align-items: center;
    gap: 12px;
    font-family: var(--gvl-font);
    font-size: 18px;
    font-weight: 600;
    color: var(--gvl-title);
    text-decoration: none;
}

.gvl-pagenav {
    display: inline-flex;
    align-items: center;
}

.gvl-pagenav__toggle {
    padding: 4px 6px;
    margin-left: 5px;
    margin-right: 10px;
    font-size: 10px;
    line-height: 1;
    color: var(--gvl-muted);
    background: none;
    border: 0;
    cursor: pointer;
}

.gvl-pagenav__toggle:hover { color: var(--gvl-primary); }

/* The children open under the page they belong to.
 *
 * The wrapper starts at the page's name and the caret is at its right end, so
 * aligning to the wrapper puts the menu under the name — which is the thing
 * these items are children OF. Anchored to the caret, the list appeared to
 * belong to the page after it. */
.gvl-pagenav .dropdown-menu {
    left: 0;
    right: auto;
    margin-top: 10px;
}

/* ── The pages on a narrow bar ───────────────────────────────────────────────
   Below the breakpoint the inline links are hidden and this takes their place.
   Both are in the markup; CSS decides which is on screen, because the server
   cannot know the width and a breakpoint guessed from a user agent is the
   oldest wrong answer in the trade. */
.gvl-pagenav__burger {
    display: none;
    padding: 8px 10px;
    font-size: 16px;
    line-height: 1;
    color: var(--gvl-title);
    background: none;
    border: 0;
    border-radius: var(--gvl-radius);
    cursor: pointer;
}

.gvl-pagenav__burger:hover,
.gvl-pagenav__burger[aria-expanded="true"] {
    color: var(--gvl-primary);
    background-color: var(--gvl-primary-wash);
}

/* Anchored to the bar rather than to the button: the panel is the width of the
   screen's edge-to-edge content, not of the control that opened it. */
.gvl-pagenav__panel {
    position: absolute;
    top: var(--gvl-topbar-h);
    left: 0;
    right: 0;
    z-index: 950;
    display: flex;
    flex-direction: column;
    padding: 8px 0;
    background-color: var(--gvl-surface);
    border-bottom: 1px solid var(--gvl-line);
    box-shadow: 0 8px 20px rgba(0, 0, 0, .08);
}

.gvl-pagenav__panel-item {
    padding: 12px 20px;
    font-size: 15px;
    font-weight: 500;
    color: var(--gvl-title);
}

.gvl-pagenav__panel-item:hover {
    color: var(--gvl-primary);
    background-color: var(--gvl-surface-sunk);
}

/* Nesting shown by indent and a rule, the same way the Pages list shows it. */
.gvl-pagenav__panel-item--child {
    padding-left: 38px;
    font-weight: 400;
    color: var(--gvl-text);
}

.gvl-wordmark:hover {
    color: var(--gvl-primary);
}

/* The bar is a fixed height, so the logo is constrained by HEIGHT and lets its
   width fall where it may — a wordmark and a square badge are both common, and
   sizing by width would make one of them tiny and the other enormous. The cap on
   width is a backstop against a very wide image pushing the name off screen.

   51px inside a 90px bar: large enough to carry the identity, with ~19px of air
   above and below so the bar still reads as a bar rather than as a frame around
   the logo. The width cap moves with the height — leaving it at 180px would mean
   a wide wordmark hit the cap first and never actually got bigger. */
.gvl-wordmark__logo {
    display: block;
    height: 51px;
    width: auto;
    max-width: 270px;
    object-fit: contain;
}

/* A rule between the two, so a logo that already contains words does not read as
   running into the site name. */
.gvl-wordmark--has-logo .gvl-wordmark__name {
    padding-left: 12px;
    border-left: 1px solid var(--gvl-line);
}

@media (max-width: 575px) {

    /* On a narrow bar the logo is the thing that identifies the site at a
       glance, and the name is what runs out of room first. */
    .gvl-wordmark__logo { height: 36px; max-width: 120px; }

    /* The name is not cut.
     *
     * It used to be capped at 9ch with an ellipsis, which on a narrow phone
     * rendered "Grapevi…" — a site identifying itself by half a word. The room
     * is bought by shrinking the logo and the type instead, because a smaller
     * title still says who you are and a truncated one does not. */
    .gvl-wordmark {
        font-size: 16px;
        gap: 8px;
    }

    .gvl-wordmark--has-logo .gvl-wordmark__name {
        padding-left: 8px;
        white-space: nowrap;
    }
}

/* Undo the template's absolute positioning; the flex row handles placement. */
.top-page-header .top-header-nav {
    position: static;
    flex: 0 0 auto;
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: 26px;
    height: auto;
    line-height: 1;
}

.top-page-header .top-nav-item {
    margin: 0;
    line-height: 1;
    font-size: 15px;
    color: var(--gvl-title);
}

.top-page-header .top-nav-item:hover,
.top-page-header .top-nav-item.is-current {
    color: var(--gvl-primary);
}

.top-page-header .top-page-button {
    margin-left: 4px;
    padding: 12px 26px !important;
}


/* ── The account menu ────────────────────────────────────────────────────────
 * Who is signed in, and the few things they can do. Signing out used to be the
 * only control up here, which made the most destructive action in the bar the
 * easiest one to hit by accident.
 *
 * Quiet on purpose: this is wayfinding, not a call to action, and a solid
 * button competed with the one the page is actually asking you to press. */
.gvl-account { margin-left: 4px; }

.gvl-account__toggle {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 6px 10px 6px 6px;
    font-size: 15px;
    line-height: 1;
    color: var(--gvl-title);
    background: none;
    border: 1px solid transparent;
    border-radius: 999px;
    cursor: pointer;
}

.gvl-account__toggle:hover,
.gvl-account__toggle[aria-expanded="true"] {
    border-color: var(--gvl-line);
    background-color: var(--gvl-surface-sunk);
}

/* The icon sits underneath and the Gravatar is requested with d=blank, so a
   person with no Gravatar gets a transparent image and the icon shows through.
   See gvl_2026_account_menu() — it saves asking Gravatar, over the network, on
   every page render, just to decide which of the two to draw. */
.gvl-account__avatar {
    position: relative;
    display: block;
    width: 28px;
    height: 28px;
    flex: 0 0 auto;
    border-radius: 50%;
    overflow: hidden;
    background-color: var(--gvl-surface-sunk);
    color: var(--gvl-muted, #6c757d);
}

.gvl-account__avatar .fas {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
}

.gvl-account__avatar img {
    position: relative;
    display: block;
    width: 100%;
    height: 100%;
    border-radius: 50%;
    object-fit: cover;
}

.gvl-account__name {
    max-width: 14ch;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.gvl-account__caret {
    font-size: 10px;
    color: var(--gvl-muted, #6c757d);
}

/* Right-aligned in CSS, not by Popper.
 *
 * The markup asks for this with Bootstrap's .dropdown-menu-end, and in the
 * vendored 5.0.0-beta3 that class sets one custom property — --bs-position:end
 * — which is acted on by a rule keyed to [data-bs-popper], an attribute
 * Bootstrap's JavaScript adds when it positions the menu. That JavaScript is
 * gone; gvl-ui.js replaced it and only toggles .show. So the class was inert,
 * the menu hung from the toggle's LEFT edge, and because the toggle sits at the
 * right end of the bar a 200px menu ran past the screen — widening the document
 * itself on a phone, which is why the page could be scrolled sideways. */
.gvl-account__menu {
    right: 0;
    left: auto;
    min-width: 200px;
    margin-top: 8px;
    padding: 6px;
    border: 1px solid var(--gvl-line);
    border-radius: 10px;
    box-shadow: 0 8px 24px rgba(0, 0, 0, .1);
}

.gvl-account__menu .dropdown-item {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 9px 12px;
    border-radius: 6px;
    font-size: 15px;
}

/* A fixed box, so the labels line up whatever width each glyph happens to be. */
.gvl-account__menu .dropdown-item > .fas,
.gvl-account__menu .dropdown-item > .fab {
    width: 16px;
    flex: 0 0 auto;
    text-align: center;
    font-size: 14px;
    color: var(--gvl-muted, #6c757d);
}

.gvl-account__menu .dropdown-item:hover > .fas,
.gvl-account__menu .dropdown-item:hover > .fab { color: inherit; }

/* Last, and visibly a different kind of thing from the navigation above it. */
.gvl-account__signout,
.gvl-account__signout > .fas { color: var(--gvl-danger, #b3261e); }

.gvl-account__signout:hover,
.gvl-account__signout:focus {
    color: var(--gvl-danger, #b3261e);
    background-color: rgba(179, 38, 30, .08);
}


/* ── Modals ──────────────────────────────────────────────────────────────────
 * The vendored base gives .modal-content `border: none` and a 5%-opacity
 * shadow. That is a reasonable choice over a dark backdrop — and this backdrop
 * is white at 93% with a 20px blur, so the result was a white card on a white
 * ground with nothing to say where one ended and the other began.
 *
 * The backdrop is left alone: the pale, blurred page behind is the look this
 * theme wants. What the card needed was an edge of its own.
 *
 * Two shadows rather than one. The wide, soft one lifts the card off the page;
 * the tight, darker one does the work the border does on a screen where shadows
 * are turned down. Neither alone reads as "floating above" on white.
 */
.modal-content {
    border: 1px solid var(--gvl-modal-edge);
    box-shadow:
        0 24px 64px rgba(17, 20, 24, .16),
        0 4px 12px rgba(17, 20, 24, .07);
}

/* The header and footer rails sit against that edge, so they take a line with a
   little more presence than the ones used inside the body. */
.modal-content .modal-header { border-bottom-color: var(--gvl-line-strong); }
.modal-content .modal-footer { border-top-color: var(--gvl-line-strong); }

/* ── 4. Footer ──────────────────────────────────────────────────────────────
 * Selector is `footer.gvl-footer`, not `.gvl-footer`, deliberately. The
 * vendored base carries `.doc-body footer { padding-left: 380px;
 * padding-right: 80px }` — sized for its fixed 300px sidebar, which this page
 * no longer has — and that out-specifies a single class. The result was a
 * footer indented 380px on the left and 80px on the right, holding a gap for
 * a rail that is not there. */
footer.gvl-footer {
    background-color: var(--gvl-surface-sunk);
    border-top: 1px solid var(--gvl-line);
    padding: 28px 40px;
}

.gvl-footer__inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    flex-wrap: wrap;
}

/* Hard right, with or without a footer menu beside it.
   margin-left:auto rather than text-align, because the credit is the only
   child when no menu is assigned and there is nothing for space-between to
   push it away from — it would simply sit on the left. The order swap keeps
   the menu on the left when there is one. */
.gvl-footer__credit {
    order: 2;
    margin: 0 0 0 auto;
    font-size: 13px;
    text-align: right;
    color: var(--gvl-muted);
}

.gvl-footer__nav { order: 1; }

.gvl-footer__nav {
    display: flex;
    gap: 22px;
    flex-wrap: wrap;
}

.gvl-footer__nav a {
    font-size: 13px;
    color: var(--gvl-muted);
}

.gvl-footer__nav a:hover {
    color: var(--gvl-primary);
}


/* ── 5. Ordinary pages ──────────────────────────────────────────────────────
 * Everything that is not a course: posts, pages, search, 404. The course page
 * gets its layout from the plugin. */
.gvl-page {
    max-width: 820px;
    margin: 0 auto;
    padding: 56px 24px 80px;
}

.gvl-page__title {
    font-family: var(--gvl-font);
    font-size: 34px;
    font-weight: 600;
    color: var(--gvl-title);
    line-height: 1.2;
    margin: 0 0 8px;
}

.gvl-page__meta {
    font-size: 13px;
    color: var(--gvl-muted);
    margin: 0 0 32px;
}

.gvl-page__body {
    font-size: 16px;
    line-height: 1.8;
    color: var(--gvl-text);
}

.gvl-page__body ul,
.gvl-page__body ol {
    padding-left: 1.3em;
    margin: 0 0 1em;
}

.gvl-page__body ul { list-style: disc; }
.gvl-page__body ol { list-style: decimal; }


/* ── 6. Course listing ──────────────────────────────────────────────────────
 * A grid of course cards. Reuses the plugin's card tokens so the listing and
 * the course page read as one system. */
.gvl-courses {
    max-width: 1180px;
    margin: 0 auto;
    padding: 56px 40px 80px;
}

.gvl-courses__title {
    font-family: var(--gvl-font);
    font-size: 32px;
    font-weight: 600;
    color: var(--gvl-title);
    margin: 0 0 34px;
}

.gvl-courses__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 26px;
}

.gvl-coursecard {
    display: flex;
    flex-direction: column;
    background-color: var(--gvl-surface);
    border: 1px solid var(--gvl-line);
    border-radius: var(--gvl-radius-lg);
    box-shadow: var(--gvl-shadow);
    overflow: hidden;
    text-decoration: none;
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
}

.gvl-coursecard:hover {
    transform: translateY(-4px);
    border-color: var(--gvl-primary-light);
    box-shadow: var(--gvl-shadow-lift);
}

.gvl-coursecard__media {
    aspect-ratio: 16 / 9;
    background-color: var(--gvl-primary-wash);
    background-size: cover;
    background-position: center;
}

.gvl-coursecard__body {
    padding: 20px 22px 24px;
    display: flex;
    flex-direction: column;
    gap: 8px;
    flex: 1 1 auto;
}

.gvl-coursecard__title {
    font-size: 17px;
    font-weight: 600;
    color: var(--gvl-title);
    line-height: 1.35;
    margin: 0;
}

.gvl-coursecard__excerpt {
    font-size: 14px;
    color: var(--gvl-text);
    line-height: 1.65;
    margin: 0;
}

.gvl-coursecard__meta {
    font-size: 12px;
    color: var(--gvl-muted);
    margin: 4px 0 0;
}


/* ── 7. Accessibility ───────────────────────────────────────────────────── */
.screen-reader-text {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.gvl-skip:focus {
    position: fixed;
    top: 12px;
    left: 12px;
    z-index: 100000;
    width: auto;
    height: auto;
    clip: auto;
    margin: 0;
    padding: 12px 20px;
    background-color: var(--gvl-surface);
    color: var(--gvl-primary);
    border-radius: var(--gvl-radius);
    box-shadow: var(--gvl-shadow-lift);
}

:focus-visible {
    outline: 2px solid var(--gvl-primary);
    outline-offset: 2px;
}


/* ── 8. Responsive ──────────────────────────────────────────────────────── */
@media (max-width: 991px) {

    .top-page-header {
        padding: 0 20px;
        gap: 16px;
    }

    .top-page-header .top-header-nav {
        gap: 16px;
    }

    footer.gvl-footer {
        padding: 24px 20px;
    }

    .gvl-courses {
        padding: 36px 20px 60px;
    }
}

@media (max-width: 575px) {

    .top-page-header .top-nav-item {
        display: none;   /* the account button stays */
    }

    /* The pages do not disappear with them — they move behind the hamburger.
       Before this they were simply gone on a phone, which made a page somebody
       had written unreachable from the device most likely to be reading it. */
    .gvl-pagenav__burger { display: inline-flex; }

    /* Everything the hamburger stands in for: the inline links, the wrappers
       that hold them, and the carets that opened their children.
       
       These sat in the 400px block for a while — a stray brace when that block
       was added closed this one early, and between 401px and 575px the bar
       showed a hamburger AND a caret. Hiding the wrapper is what matters: the
       caret is its child, and hiding only the links leaves the button behind
       with nothing beside it. */
    .gvl-pagenav-set .gvl-pagenav,
    .gvl-pagenav-set .gvl-pagenav__toggle,
    .gvl-pagenav-set > .top-nav-item { display: none !important; }

    /* The bar did not fit. Measured at 390px: the brand and the nav came to
       360px, plus 40px of padding and a 16px gap, against a 390px viewport —
       so the home page scrolled sideways on a phone, and had been doing so
       before the hamburger was added to it.

       Three changes, in order of how much they buy: the signed-in name goes
       (the avatar still says who you are, and it is the widest thing in the
       bar), then the padding, then the gap. */
    .gvl-account__name { display: none; }

    .top-page-header {
        padding: 0 12px;
        gap: 8px;
    }

    /* Lets the brand give way rather than forcing the row wider than the
       screen; its name already truncates. */
    .gvl-topbar-brand { min-width: 0; }

    /* And the signed-OUT bar, which has a different widest thing in it: the
       Sign In button carries .btn's 9.25rem minimum and 38px of side padding,
       which overflowed a 320px screen by 61px. Nothing else on the bar needs
       it to be that wide. */
    .top-page-header .top-page-button {
        min-width: 0;
        padding: 12px 18px !important;
    }
}

/* Smaller again. At 320px the logo and the site name cannot share the row with
   a Sign In button, and something has to give: the name goes, because a site
   that has uploaded a logo has already said who it is and the logo is the half
   that survives being small. A site with no logo keeps its name. */
@media (max-width: 400px) {

    /* Smaller still, and still the whole name. */
    .gvl-wordmark { font-size: 14px; gap: 6px; }

    .gvl-wordmark--has-logo .gvl-wordmark__name { padding-left: 6px; }

    .gvl-wordmark__logo { height: 30px; max-width: 90px; }

    .top-page-header {
        padding: 0 8px;
        gap: 6px;
    }

    /* The Sign In button becomes its icon.
     *
     * Keeping the site's name whole costs room, and this is where it comes
     * from: a person-shaped icon in the top right corner is the most
     * universally understood control on the web, and the word beside it was
     * the widest thing competing with the title. */
    .top-page-header .top-page-button span { display: none; }

    .top-page-header .top-page-button {
        padding: 12px 14px !important;
    }

    .top-page-header .top-page-button .mr-5 { margin-right: 0 !important; }
}

/* Above the breakpoint the panel never opens, whatever its hidden state. */
@media (min-width: 576px) {
    .gvl-pagenav__panel { display: none !important; }
}


/* ── Admin bar ──────────────────────────────────────────────────────────────
 * A sticky top:0 sits under WordPress's fixed admin bar for signed-in staff. */
.admin-bar .top-page-header {
    top: 32px;
}

@media screen and (max-width: 782px) {
    .admin-bar .top-page-header {
        top: 46px;
    }
}


/* ── Home page ──────────────────────────────────────────────────────────────
 * Modelled on the eDocs help-center layout: a hero with a search, then the
 * "Knowledgebase" promo-box cards repurposed as course cards.
 *
 * The card classes below are the theme's, not the plugin's — a course card in
 * a listing is chrome, not an LMS component, and nothing in the player depends
 * on it. */
.gvl-hero {
    position: relative;
    padding: 64px 24px 68px;
    text-align: center;
    background-color: var(--gvl-primary-wash);
    background-size: cover;
    background-position: center;
    border-bottom: 1px solid var(--gvl-line);
}

/* A featured image behind the hero would otherwise swallow the text. */
.gvl-hero--image::before {
    content: "";
    position: absolute;
    inset: 0;
    background: linear-gradient(to bottom, rgba(255, 255, 255, .92), rgba(255, 255, 255, .82));
}

.gvl-hero__inner {
    position: relative;
    max-width: 760px;
    margin: 0 auto;
}

.gvl-hero__title {
    font-family: var(--gvl-font);
    font-size: clamp(30px, 5vw, 46px);
    font-weight: 600;
    line-height: 1.15;
    color: var(--gvl-title);
    margin: 0 0 16px;
}

.gvl-hero__lede {
    font-size: 17px;
    line-height: 1.7;
    color: var(--gvl-text);
    margin: 0 0 12px;
}

.gvl-hero__meta {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    flex-wrap: wrap;
    margin: 14px 0 0;
    font-size: 13px;
    color: var(--gvl-muted);
}



/* ── Course cards ───────────────────────────────────────────────────────── */
/* Less air at the top than when a heading sat here: the hero ends and the
   courses begin. */
.gvl-section {
    padding: 32px 0 88px;
}

.gvl-section__title {
    font-family: var(--gvl-font);
    font-size: 28px;
    font-weight: 600;
    color: var(--gvl-title);
    text-align: center;
    margin: 0 0 12px;
}

.gvl-section__lede {
    text-align: center;
    color: var(--gvl-muted);
    font-size: 15px;
    margin: 0 0 42px;
}

.gvl-coursebox {
    /* The containing block for .stretched-link's overlay — without it the
       overlay escapes to whatever is positioned further up and the "card" that
       is clickable is the whole column, or the whole page. */
    position: relative;

    /* The card's own padding, declared here rather than inherited from the
       vendored .promo-box, because the course image bleeds through it to the
       card's edges and has to know by how much. Two rules sharing one number is
       how a full-bleed image ends up with a hairline of background down one
       side after somebody retunes a template nobody reads. */
    --gvl-card-pad-y: 40px;
    --gvl-card-pad-x: 32px;
    padding: var(--gvl-card-pad-y) var(--gvl-card-pad-x);
    display: flex;
    flex-direction: column;
    height: 100%;
    margin-bottom: 0;
    border: 1px solid var(--gvl-line);
    border-radius: var(--gvl-radius-lg);
    transition: transform .2s ease, box-shadow .2s ease, border-color .2s ease;
    cursor: pointer;
}

/* Keyboard users land on the title link, whose focus ring sits on the text. The
   card takes the ring instead, because the card is what activating it opens. */
.gvl-coursebox:focus-within {
    border-color: var(--gvl-primary);
    box-shadow: 0 0 0 3px var(--gvl-primary-wash);
}

.gvl-coursebox__title .stretched-link:focus-visible { outline: none; }

/* The call to action is inert — the pointer is over the stretched link's overlay,
   never over this — so the CARD's hover drives it.
   
   Styled here rather than borrowing .btn-outline-primary, which the vendored base
   pins with `background-color: transparent !important`. Matching that would mean
   !important on every line of the hover state, and an !important war over a
   decorative element is a poor trade for three declarations. */
.gvl-coursebox__cta {
    display: inline-flex;
    align-items: center;
    padding: .375rem .875rem;
    font-size: .875rem;
    font-weight: 600;
    line-height: 1.5;
    color: var(--gvl-primary);
    background-color: transparent;
    border: 1px solid var(--gvl-primary);
    border-radius: var(--gvl-radius);
    pointer-events: none;
    transition: color .2s ease, background-color .2s ease;
}

.gvl-coursebox:hover .gvl-coursebox__cta,
.gvl-coursebox:focus-within .gvl-coursebox__cta {
    color: #fff;
    background-color: var(--gvl-primary);
}

.gvl-coursebox:hover {
    transform: translateY(-4px);
    border-color: var(--gvl-primary-light);
    box-shadow: var(--gvl-shadow-lift);
}

.gvl-coursebox__icon {
    color: var(--gvl-primary);
}

/* Sized to the icon's footprint so a course with art and one without produce
   identical card geometry — a grid of two different card shapes reads as a
   mistake. */
/* A course's own picture, filling the top of the card edge to edge.
   Full width and 16:9 rather than an icon-sized square: a photograph shrunk to
   54px is a smudge, and the point of letting somebody upload one is that it
   says something an icon cannot. The same shape the Course image control
   previews, so what they choose is what they get.
   Pulled out through the card's padding on three sides so it meets the border
   with no gap, and rounded to match it — one pixel tighter than the card's own
   radius, which is the border's width, or a sliver of card shows at each
   corner. */
.gvl-coursebox__thumb {
    display: block;
    width: auto;
    aspect-ratio: 16 / 9;
    margin: calc(var(--gvl-card-pad-y) * -1) calc(var(--gvl-card-pad-x) * -1) 24px;
    border-radius: calc(var(--gvl-radius-lg) - 1px) calc(var(--gvl-radius-lg) - 1px) 0 0;
    background-color: var(--gvl-primary-wash);
    background-size: cover;
    background-position: center;
}

.gvl-coursebox__title {
    font-family: var(--gvl-font);
    line-height: 1.35;
    margin: 0 0 12px;
}

.gvl-coursebox__title a {
    color: var(--gvl-title);
    text-decoration: none;
}

.gvl-coursebox__title a:hover {
    color: var(--gvl-primary);
}

.gvl-coursebox__excerpt {
    font-size: 14px;
    line-height: 1.65;
    color: var(--gvl-text);
    margin: 0 0 20px;
}

.gvl-coursebox__modules {
    margin: 0 0 24px;
    padding: 0;
}

.gvl-coursebox__modules li {
    display: flex;
    align-items: baseline;
    gap: 10px;
    font-size: 14px;
    line-height: 1.5;
    color: var(--gvl-text);
    margin-bottom: 10px;
}

.gvl-coursebox__modules li:last-child {
    margin-bottom: 0;
}

.gvl-coursebox__modules i {
    flex: 0 0 auto;
    font-size: 11px;
    color: var(--gvl-primary-light);
}

.gvl-coursebox__more {
    font-size: 13px;
    color: var(--gvl-muted);
    padding-left: 21px;
}

/* Pushed to the bottom so every card's button sits on the same line, whatever
   the excerpt and module count above it. */
.gvl-coursebox__foot {
    margin-top: auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    flex-wrap: wrap;
}

.gvl-coursebox__count {
    font-size: 12px;
    color: var(--gvl-muted);
}

.gvl-empty-courses {
    text-align: center;
    color: var(--gvl-muted);
    padding: 40px 0;
}


/* ── Course facts ───────────────────────────────────────────────────────────
 * The label/value rows the live CCI catalogue shows on each card: enrollment,
 * price, dates. Rendered as a <dl> because that is what a list of label/value
 * pairs is, and laid out as a grid so the labels line up across cards. */
.gvl-coursefacts {
    display: flex;
    flex-wrap: wrap;
    gap: 14px 26px;
    margin: 0 0 22px;
    padding: 16px 0;
    border-top: 1px solid var(--gvl-line);
    border-bottom: 1px solid var(--gvl-line);
}

.gvl-coursefacts__row {
    min-width: 0;
}

.gvl-coursefacts dt {
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--gvl-muted);
    margin: 0 0 4px;
}

.gvl-coursefacts dd {
    font-size: 14px;
    font-weight: 500;
    color: var(--gvl-title);
    margin: 0;
    line-height: 1.3;
}

/* A course outside its availability window still lists, but says so rather
   than letting someone click in and find a locked door. */
.gvl-coursebox--closed {
    opacity: .72;
}

.gvl-coursebox__badge {
    display: inline-block;
    font-size: 11px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--gvl-muted);
    background-color: var(--gvl-surface-sunk);
    border: 1px solid var(--gvl-line-strong);
    padding: 3px 10px;
    border-radius: 100px;
}


/* ── Management affordances ─────────────────────────────────────────────────
 * Shown only to people who can author courses. They no longer link into
 * wp-admin — that is closed to anyone without manage_options now — so creating
 * and copying both happen in modals on the front end. */
/* It stands where the lede would be, so it sits the same way the lede does:
   centred, with the same gap under it before the cards begin. It used to be a
   dashed box above the heading captioned "You can manage courses", which spent a
   banner telling somebody something they already knew about themselves. */
.gvl-newcourse-control {
    display: block;
    text-align: center;
    margin: 0;
}

.gvl-coursebox__status {
    display: inline-block;
    font-size: 10px;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--gvl-primary-dark);
    background-color: var(--gvl-primary-wash);
    padding: 3px 9px;
    border-radius: 100px;
    margin: 0 0 12px;
    text-align: center;

    /* letter-spacing adds its space AFTER the last letter too, so the text in
       a pill sized to its own content sits one notch left of centre. Pulling
       the box in by the same amount puts it back; without this the badge reads
       as slightly misaligned and nothing on the page explains why. */
    text-indent: .1em;
}

.gvl-coursebox__actions {
    display: inline-flex;
    align-items: center;
    gap: 14px;
}

.gvl-coursebox__edit {
    font-size: 13px;
    color: var(--gvl-muted);
    white-space: nowrap;
}

.gvl-coursebox__edit:hover {
    color: var(--gvl-primary);
}


/* ── Copy a Course ──────────────────────────────────────────────────────── */
.gvl-copymodal {
    border: 0;
    border-radius: var(--gvl-radius-lg);
}

/* The vendored base sets .modal-header to display:block with 2.5rem padding,
 * which drops Bootstrap's close button below the title instead of beside it.
 * Restore the flex row for this modal only — other modals on the site are the
 * base's business. */
.gvl-copymodal .modal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 22px 24px 16px;
    border-bottom: 1px solid var(--gvl-line);
}

.gvl-copymodal .modal-body {
    padding: 20px 24px 24px;
}

.gvl-copymodal .modal-title {
    font-family: var(--gvl-font);
    font-size: 18px;
    font-weight: 600;
    color: var(--gvl-title);
}

.gvl-copymodal__lede {
    font-size: 13px;
    line-height: 1.6;
    color: var(--gvl-muted);
    margin: 0 0 18px;
}

/* Where a copy is going, above the list of what to copy. Only drawn when there
   is more than one answer. */
.gvl-copydest {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 8px 12px;
    margin: 0 0 16px;
}

.gvl-copydest label {
    font-size: 13px;
    font-weight: 600;
    margin: 0;
    white-space: nowrap;
}

/* The filter, when the list is long enough to need one, sits above the select
   and spans both columns so the label stays beside the thing it names. */
.gvl-copydest__filter {
    grid-column: 2;
    width: 100%;
}

/* Who keeps the money, under the destination it depends on.
 *
 * Left-aligned against the modal's centred text, because a checkbox whose label
 * is centred sits a long way from its own box — and the two have to read as one
 * control for the tick to mean anything. */
.gvl-copyterms {
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: start;
    gap: 2px 8px;
    text-align: left;
    margin: 0 0 16px;
}

.gvl-copyterms[hidden] { display: none; }

.gvl-copyterms input { margin-top: 3px; }

.gvl-copyterms label {
    font-size: 13px;
    font-weight: 600;
    margin: 0;
}

.gvl-copyterms .gvl-form__hint {
    grid-column: 2;
    font-size: 12px;
    line-height: 1.5;
    color: var(--gvl-muted);
}

.gvl-copylist {
    list-style: none;
    margin: 0;
    padding: 0;
}

.gvl-copylist li + li {
    margin-top: 8px;
}

.gvl-copyrow {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    width: 100%;
    text-align: left;
    background-color: var(--gvl-surface);
    border: 1px solid var(--gvl-line-strong);
    border-radius: var(--gvl-radius);
    padding: 14px 16px;
    font-family: var(--gvl-font);
    cursor: pointer;
    transition: border-color .15s ease, background-color .15s ease;
}

.gvl-copyrow:hover {
    border-color: var(--gvl-primary);
    background-color: var(--gvl-primary-wash);
}

.gvl-copyrow__title {
    display: block;
    font-size: 15px;
    font-weight: 600;
    color: var(--gvl-title);
    line-height: 1.35;
}

.gvl-copyrow__meta {
    display: block;
    font-size: 12px;
    color: var(--gvl-muted);
    margin-top: 3px;
}

.gvl-copyrow__action {
    flex: 0 0 auto;
    font-size: 13px;
    font-weight: 600;
    color: var(--gvl-primary);
    white-space: nowrap;
}

.gvl-copyrow__action i {
    font-size: 11px;
    margin-left: 4px;
}


/* ── Copy a Course: search ──────────────────────────────────────────────── */
.gvl-copysearch {
    position: relative;
    margin-bottom: 14px;
}

.gvl-copysearch i {
    position: absolute;
    left: 14px;
    top: 50%;
    transform: translateY(-50%);
    font-size: 12px;
    color: var(--gvl-muted);
    pointer-events: none;
}

.gvl-copysearch input {
    width: 100%;
    height: 42px;
    padding: 0 14px 0 36px;
    font-family: var(--gvl-font);
    font-size: 14px;
    color: var(--gvl-text);
    background-color: var(--gvl-surface);
    border: 1px solid var(--gvl-line-strong);
    border-radius: var(--gvl-radius);
}

.gvl-copysearch input:focus {
    outline: none;
    border-color: var(--gvl-primary-light);
    box-shadow: 0 0 0 3px var(--gvl-primary-wash);
}

.gvl-copylist__empty {
    font-size: 14px;
    color: var(--gvl-muted);
    text-align: center;
    padding: 20px 0;
    margin: 0;
}

.gvl-copylist__empty[hidden] {
    display: none;
}

/* [hidden] must win over the flex/list display the rows otherwise take. */
.gvl-copylist [data-gvl-copy-item][hidden] {
    display: none !important;
}


@media (max-width: 575px) {
    /* A long display name must not put the menu back off the edge. */
    .gvl-account__menu {
        max-width: calc(100vw - 1.5rem);
    }
}

/* ── Course search and paging on the home page ──────────────────────────────
   The home page is the catalogue now, so it needs the two things a catalogue
   needs: a way to look for something, and a way through the rest of it. */

.gvl-coursesearch {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 0 0 28px;
}

/* The field and its icon, as one object. The icon is positioned against this
   rather than against the form: absolute with no `top` resolves to "where a
   flex item would have sat", so when the form wrapped, the icon wrapped too and
   appeared beside the button on the second row. Centred on its own wrapper it
   tracks the input's height, with no measurement here to keep in step with the
   input's padding. */
.gvl-coursesearch__field {
    position: relative;
    display: flex;
    /* Basis 0, not auto. With flex-wrap on, a line is broken using each item's
       HYPOTHETICAL size — its basis — and only then do the items on that line
       shrink. An `auto` basis is the field's content width, so the field and
       its button were measured as too wide together and the button was pushed
       to a second row before any shrinking was considered. A zero basis lets
       both sit on one line, and the field then grows into whatever the button
       leaves. */
    flex: 1 1 0;
    min-width: 0;
    /* Matched to the button's height rather than set to a number: the button
       takes its height from the button padding, and the two are now side by
       side at every width, where before they were stacked on small screens and
       a few pixels of difference did not show. */
    align-self: stretch;
}

.gvl-coursesearch__icon {
    position: absolute;
    left: 16px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gvl-muted, #6c757d);
    font-size: 14px;
    pointer-events: none;
}

.gvl-coursesearch input[type="search"] {
    flex: 1 1 auto;
    min-width: 0;
    padding: 12px 16px 12px 42px;
    border: 1px solid var(--gvl-rule, #e7ecf1);
    border-radius: var(--gvl-radius, 6px);
    background: var(--gvl-card, #fff);
    font-family: inherit;
    font-size: .9375rem;
}

.gvl-coursesearch input[type="search"]:focus {
    outline: none;
    border-color: var(--gvl-primary, #0b50d8);
    box-shadow: 0 0 0 3px var(--gvl-primary-wash, rgba(11, 80, 216, .12));
}

.gvl-coursesearch .btn { flex: 0 0 auto; }

.gvl-coursesearch__clear {
    flex: 0 0 auto;
    font-size: .875rem;
    color: var(--gvl-muted, #6c757d);
}

/* Previous / Next. The page count sits between them so the two controls are
   not a pair of buttons with nothing saying where you are. */
.gvl-coursepager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 16px;
    margin-top: 32px;
}

.gvl-coursepager__count {
    font-size: .875rem;
    color: var(--gvl-muted, #6c757d);
    font-variant-numeric: tabular-nums;
}

/* A disabled end of the range stays in place rather than disappearing, so the
   controls do not shuffle sideways as you page. */
.gvl-coursepager .is-disabled {
    opacity: .45;
    cursor: default;
    pointer-events: none;
}

@media (max-width: 575px) {
    /* The field and its button stay on one line. Giving the input 100% used to
       push the button onto a row of its own, which reads as two unrelated
       controls and costs a whole line to say nothing — the button is three
       words wide and the field can simply be narrower.

       Only the Clear link wraps: it is the one part that is not needed to run
       a search, and it appears only after one has been run. */
    .gvl-coursesearch { flex-wrap: wrap; gap: 8px; }
    .gvl-coursesearch .btn { padding-left: 14px; padding-right: 14px; }
    .gvl-coursesearch__clear { flex: 1 0 100%; }
    .gvl-coursepager { gap: 10px; }
}


/* ── Show / hide inactive courses ───────────────────────────────────────────
   Rendered only for someone who has inactive courses to reveal, so it is never
   a control that does nothing. Quiet by default and marked when it is on —
   a listing showing unpublished work should say so. */

.gvl-inactive-toggle {
    margin: -12px 0 22px;
    font-size: .875rem;
}

.gvl-inactive-toggle__link {
    display: inline-flex;
    align-items: center;
    gap: 7px;
    color: var(--gvl-muted, #6c757d);
    text-decoration: none;
}

.gvl-inactive-toggle__link:hover {
    color: var(--gvl-primary, #0b50d8);
    text-decoration: underline;
}

.gvl-inactive-toggle__link.is-on {
    color: var(--gvl-primary, #0b50d8);
    font-weight: 600;
}

.gvl-inactive-toggle__link i { font-size: 12px; }
