/*
 * Showcase page styles.
 *
 * Loaded only by /showcase/. The device frames, the slot machinery, and the
 * page's motion are used nowhere else, so none of this belongs in site.css,
 * which every week page and every published exercise loads.
 *
 * The page is not bound by the slide theme's contract, but it is bound to look
 * like the rest of the site: everything here is built from the tokens site.css
 * already defines. See docs/showcase.md.
 */

.showcase-page {
    padding-block: var(--it230-space-7);
}

/* Hero */
.showcase-hero {
    padding-bottom: var(--it230-space-5);
}

.showcase-hero h1 {
    max-width: none;
    font-size: clamp(2.5rem, 5vw, 3.75rem);
    font-weight: 700;
    text-wrap: wrap;
}

.showcase-hero-intro {
    margin-bottom: var(--it230-space-7);
}

.showcase-hero .lede {
    max-width: none;
    margin-top: var(--it230-space-4);
    font-size: 1.2rem;
}

.showcase-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--it230-space-3);
    margin-bottom: var(--it230-space-6);
}

.showcase-actions .secondary-action,
.showcase-document .secondary-action {
    display: inline-block;
    padding: 0.65rem 1rem;
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-sm);
    background: var(--it230-color-surface);
    color: var(--it230-color-accent-text);
    font-size: 0.94rem;
    font-weight: 700;
    text-decoration: none;
}

.showcase-actions .secondary-action:hover,
.showcase-document .secondary-action:hover {
    border-color: var(--it230-color-accent-fill);
}

/*
 * A slot is one example: a figure holding one or two device frames, a caption,
 * and its controls. The whole figure is a single stop for a reader moving
 * through the page.
 */
.showcase-slot {
    margin: 0 0 var(--it230-space-6);
}

/*
 * A device pair is one composition rather than two pictures side by side: the
 * laptop is the base and the phone sits in front of its lower corner, the way
 * the two would actually sit on a desk. Overlapping also buys the laptop real
 * width, which matters because its whole job is to be legible.
 */
.showcase-devices {
    position: relative;
    padding-bottom: var(--it230-space-5);
}

.device-laptop {
    width: 86%;
}

.device-laptop:only-child {
    width: 100%;
}

.device-phone {
    position: absolute;
    right: 0;
    bottom: 0;
    z-index: 2;
    width: 31%;
    max-width: 21rem;
    /*
     * A faint rim and a deeper shadow, because the phone now sits on a bezel
     * its own color. A shadow tuned for a light background disappears against
     * a dark one and the two devices merge into a single shape.
     */
    filter: drop-shadow(0 0 0.07rem rgb(255 255 255 / 30%))
        drop-shadow(0 0.4rem 0.8rem rgb(0 0 6 / 22%));
}

.showcase-slot figcaption {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--it230-space-3) var(--it230-space-5);
    padding-top: var(--it230-space-4);
    margin-top: var(--it230-space-4);
    color: var(--it230-color-muted);
    font-size: 0.9rem;
    text-align: center;
}

.showcase-caption-text {
    min-width: 0;
}

/*
 * The recording pair keeps its recording controls apart from the exercise
 * link so a narrow screen can put each beneath its own device. On a wide
 * screen they wrap back into one centered row beneath the progress line.
 */
.showcase-mixed {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    column-gap: var(--it230-space-3);
}

.showcase-mixed .showcase-devices,
.showcase-mixed .showcase-progress {
    flex-basis: 100%;
}

/* A frame lays out at full device width, so it must not size its flex item. */
.showcase-mixed .showcase-devices {
    min-width: 0;
}

.showcase-mixed .showcase-progress {
    margin-bottom: var(--it230-space-3);
    text-align: center;
}

.showcase-pair-controls {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: var(--it230-space-3);
}

.showcase-slot .showcase-pair-caption {
    padding-top: 0;
    margin-top: 0;
}

/* Present for assistive technology, which cannot see the hidden frames. */
.showcase-caption-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

.showcase-slot figcaption a {
    color: var(--it230-color-accent-text);
}

/*
 * Device frames.
 *
 * Drawn here rather than loaded as artwork: an image would be fixed in color
 * while the page recolors, and would tie the page to a license and to a
 * particular manufacturer's hardware. These are deliberately generic outlines.
 */
/*
 * Both devices wear a dark bezel. Fixed values rather than theme tokens: the
 * site has no dark surface token and a device bezel is not a site surface.
 * The dark surround also absorbs the letterbox bars the deck itself draws when
 * a slide is shown narrower than its aspect ratio, which against a light frame
 * read as a rendering fault rather than as part of the device.
 */
.device {
    --device-edge: #101014;
    --device-shell: #1b1b20;
    --device-detail: #3a3a42;

    flex: 0 0 auto;
}

.device-screen {
    position: relative;
    overflow: hidden;
    background: var(--it230-color-surface);
}

/*
 * The embedded deck is laid out at a real viewport size and scaled down, so it
 * renders exactly as it would on that device. Sizing the frame to the
 * container instead would show the deck a tablet-sized viewport and prove
 * nothing about either device.
 */
.device-screen iframe {
    display: block;
    width: var(--frame-width);
    height: var(--frame-height);
    border: 0;
    transform: scale(var(--frame-scale, 1));
    transform-origin: top left;
}

.device-screen[data-loaded="false"] {
    background: linear-gradient(
        180deg,
        var(--it230-color-raised),
        var(--it230-color-surface)
    );
}

/* Laptop */
/*
 * The lid is inset so the base can flare wider than it, the way a laptop
 * actually looks, without the base pushing past the column and scrolling the
 * page sideways on a narrow screen.
 */
.device-laptop .device-shell {
    width: 94%;
    margin-inline: auto;
    padding: 0.45rem 0.45rem 0.6rem;
    border: 1px solid var(--device-edge);
    border-radius: 0.8rem 0.8rem 0.35rem 0.35rem;
    background: var(--device-shell);
}

.device-laptop .device-screen {
    aspect-ratio: 16 / 9;
    border: 1px solid var(--device-edge);
    border-radius: 0.25rem;
}

/* A shallow base and central recess suggest a laptop without a drawn keyboard. */
.device-laptop .device-base {
    position: relative;
    width: 100%;
    height: 0.9rem;
    border-radius: 0 0 50% 50% / 0 0 80% 80%;
    background: linear-gradient(
        180deg,
        var(--device-detail),
        var(--device-shell)
    );
}

.device-laptop .device-base::after {
    position: absolute;
    top: 0;
    left: 42%;
    width: 16%;
    height: 0.25rem;
    border-radius: 0 0 0.25rem 0.25rem;
    background: var(--device-edge);
    content: "";
}

/* Neutral phone chrome; landscape for slides, portrait for written steps. */
.device-phone .device-shell {
    padding: 0.45rem 0.8rem;
    border: 1px solid var(--device-edge);
    border-radius: 1.1rem;
    background: var(--device-shell);
}

.device-phone .device-screen {
    aspect-ratio: 844 / 390;
    border-radius: 0.3rem;
}

/* Slot controls: the toggle and the links beside it share one button shape. */
.showcase-control {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 2.75rem;
    min-width: 5.5rem;
    padding: 0.5rem 1rem;
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-sm);
    background: var(--it230-color-surface);
    color: var(--it230-color-accent-text);
    font: inherit;
    font-size: 0.9rem;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
}

.showcase-control:hover {
    border-color: var(--it230-color-accent-fill);
}

/*
 * The toggle is filled with the accent text colour rather than the fill: at
 * this size white text needs 4.5:1, which most accent fills do not reach.
 * This is the same pairing the site's primary action uses.
 */
.showcase-control[data-toggle] {
    border-color: var(--it230-color-accent-text);
    background: var(--it230-color-accent-text);
    color: white;
}

.showcase-control[data-toggle]:hover {
    filter: brightness(0.92);
}

.showcase-control[aria-disabled="true"] {
    cursor: default;
    filter: none;
    opacity: 0.6;
}

.showcase-progress {
    color: var(--it230-color-muted);
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
}

/*
 * Groups.
 *
 * A group heading is a signpost, not a chapter opener: it says which stage of
 * the course the sections beneath it belong to and then gets out of the way.
 * Prominent labels make each phase easy to find while the smaller gloss
 * explains it. Every section below still reads correctly on its own.
 */
.showcase-group {
    margin-top: var(--it230-space-7);
    scroll-margin-top: 5rem;
}

.showcase-group-heading {
    position: relative;
    padding-top: var(--it230-space-4);
    padding-left: calc(var(--it230-space-4) + 0.375rem);
    border-top: 0.125rem solid var(--it230-color-line);
    margin-bottom: var(--it230-space-6);
}

.showcase-group-heading::before {
    position: absolute;
    top: var(--it230-space-4);
    bottom: 0;
    left: 0;
    width: 0.375rem;
    border-radius: 999px;
    background: var(--it230-color-accent-fill);
    content: "";
}

.showcase-group-heading h2 {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 0 var(--it230-space-3);
    margin-bottom: var(--it230-space-2);
}

.showcase-group-label {
    color: var(--it230-color-accent-text);
    font-size: clamp(1.6rem, 3vw, 2rem);
    font-weight: 700;
}

.showcase-group-gloss {
    color: var(--it230-color-muted);
    font-size: 1.15rem;
    font-weight: 400;
}

.showcase-group-heading > p {
    margin: 0;
    color: var(--it230-color-muted);
}

/* Sections */
.showcase-section {
    padding: clamp(1rem, 3vw, 2rem);
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-lg);
    background: var(--it230-color-surface);
    box-shadow: var(--it230-shadow-raised);
    margin-bottom: var(--it230-space-7);
    scroll-margin-top: 5rem;
}

.showcase-section > h3 {
    padding-bottom: var(--it230-space-4);
    border-bottom: 1px solid var(--it230-color-line);
}

.showcase-slot .showcase-card-actions {
    flex-wrap: wrap;
    gap: var(--it230-space-3);
    padding-top: 0;
    margin-top: 0;
}

.showcase-card-actions .showcase-progress {
    flex-basis: 100%;
}

.showcase-section h3 {
    margin-bottom: var(--it230-space-4);
    font-size: clamp(1.5rem, 3vw, 1.85rem);
    font-weight: 700;
    line-height: 1.2;
    text-wrap: wrap;
    scroll-margin-top: 5rem;
}

.showcase-section > p {
    margin-block: 0 var(--it230-space-5);
    line-height: 1.65;
}

.showcase-section > :last-child {
    margin-bottom: 0;
}

.showcase-section p,
.showcase-list {
    max-width: none;
}

.showcase-list {
    margin: 0 0 var(--it230-space-5);
    padding-left: var(--it230-space-5);
}

.showcase-list li {
    margin-bottom: var(--it230-space-2);
}

.showcase-list li::marker {
    color: var(--it230-color-accent-fill);
}

.showcase-evidence {
    padding-left: var(--it230-space-4);
    border-left: 0.125rem solid var(--it230-color-line);
    color: var(--it230-color-muted);
    font-size: 0.95rem;
}

/*
 * The note states what the page does not claim. It carries a visible title so
 * its meaning does not depend on the border beside it.
 */
.showcase-note {
    max-width: 46rem;
    padding: var(--it230-space-4);
    border: 1px solid var(--it230-color-line);
    border-left: 0.25rem solid var(--it230-color-accent-fill);
    border-radius: var(--it230-radius-md);
    margin-bottom: var(--it230-space-5);
    background: var(--it230-color-surface);
}

.showcase-note p {
    margin: 0;
}

.showcase-note-title {
    margin-bottom: var(--it230-space-2) !important;
    font-weight: 700;
}

/* Figures */
.showcase-stats {
    display: flex;
    flex-wrap: wrap;
    gap: var(--it230-space-5);
    margin: 0 0 var(--it230-space-5);
    padding: 0;
    list-style: none;
}

.showcase-stats li {
    display: flex;
    flex-direction: column;
    min-width: 7rem;
}

.showcase-stat-value {
    color: var(--it230-color-accent-text);
    font-size: 2.4rem;
    font-weight: 700;
    line-height: 1.1;
}

.showcase-stat-label {
    color: var(--it230-color-muted);
    font-size: 0.95rem;
}

.showcase-text-action {
    align-self: center;
    font-weight: 700;
}

.showcase-closing {
    padding: var(--it230-space-5);
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-lg);
    margin-top: var(--it230-space-7);
    background: var(--it230-color-surface);
    box-shadow: var(--it230-shadow-raised);
}

.showcase-closing h2 {
    margin-bottom: var(--it230-space-4);
}

.showcase-closing .showcase-evidence {
    margin-bottom: 0;
}

/*
 * On narrow screens, center the phone below the laptop so both remain visible
 * without covering each other's content.
 */
@media (max-width: 40rem) {
    .showcase-slot figcaption {
        flex-wrap: wrap;
    }

    .showcase-devices .device-phone {
        position: static;
        width: 85%;
        margin: var(--it230-space-5) auto 0;
    }

    .showcase-devices .device-phone[data-orientation="portrait"] {
        width: 80%;
    }

    .device-laptop {
        width: 100%;
    }

    .showcase-devices {
        padding-bottom: 0;
    }

    /*
     * Unwrap the devices so the recording controls can sit between the
     * laptop and the phone. The wrapper is a plain div, so nothing is lost
     * to assistive technology, and the phone holds nothing focusable, so
     * reordering it leaves the tab order matching what is seen.
     */
    .showcase-mixed {
        flex-flow: column nowrap;
        align-items: center;
    }

    .showcase-mixed .showcase-devices {
        display: contents;
    }

    .showcase-mixed .device-laptop {
        order: 1;
    }

    .showcase-mixed .showcase-progress {
        order: 2;
        margin-top: var(--it230-space-4);
    }

    .showcase-pair-controls {
        order: 3;
    }

    .showcase-mixed .device-phone {
        order: 4;
    }

    .showcase-slot .showcase-pair-caption {
        order: 5;
        margin-top: var(--it230-space-4);
    }
}

/*
 * Page cards.
 *
 * The weekly overview, summarised from the catalog rather than framed. It
 * shows every phase in full, so this is a complete card rather than a
 * fragment: no clipped height and no faded edge, because nothing is being cut
 * off for the reader to wonder about.
 */
.showcase-excerpt {
    margin: 0 0 var(--it230-space-6);
}

.page-card {
    position: relative;
    overflow: hidden;
    max-width: 38rem;
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-md);
    background: var(--it230-color-surface);
    box-shadow: var(--it230-shadow-raised);
}

.page-card-inner {
    padding: var(--it230-space-5);
}

.showcase-excerpt figcaption {
    margin-top: var(--it230-space-3);
    font-size: 0.95rem;
    text-align: center;
}

/* Weekly overview excerpt */
.excerpt-kicker {
    margin: 0 0 var(--it230-space-1) !important;
    color: var(--it230-color-accent-text);
    font-size: 0.75rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.excerpt-title {
    margin: 0 0 var(--it230-space-4) !important;
    font-size: 1.35rem;
    font-weight: 700;
    line-height: 1.25;
}

.excerpt-phases {
    margin: 0;
    padding: 0;
    list-style: none;
}

.excerpt-phase {
    display: block;
    padding-left: var(--it230-space-3);
    border-left: 0.2rem solid var(--it230-color-accent-fill);
    margin-bottom: var(--it230-space-4);
}

.excerpt-phase-label {
    display: block;
    color: var(--it230-color-accent-text);
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

.excerpt-phase-title {
    display: block;
    font-weight: 700;
}

.excerpt-phase-body {
    display: block;
    color: var(--it230-color-muted);
    font-size: 0.9rem;
}

/*
 * A phone showing a page is portrait. A slide has to be landscape because it
 * is 16:9; a page does not.
 */
.device-phone[data-orientation="portrait"] {
    width: 30%;
    max-width: 15rem;
}

.device-phone[data-orientation="portrait"] .device-screen {
    aspect-ratio: 390 / 780;
}

/*
 * The exercise preview and its destination share one card. The frame fills
 * the card edge to edge, so the card's own border is the only one around it.
 */
.showcase-document {
    overflow: hidden;
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-lg);
    margin: 0 0 var(--it230-space-6);
    background: var(--it230-color-surface);
    box-shadow: var(--it230-shadow-raised);
}

.doc-frame {
    min-width: 0;
}

.doc-screen {
    position: relative;
    overflow: hidden;
    width: 100%;
    aspect-ratio: 1280 / 900;
}

.doc-screen iframe {
    display: block;
    width: var(--frame-width);
    height: var(--frame-height);
    border: 0;
    transform: scale(var(--frame-scale, 1));
    transform-origin: top left;
}

.showcase-document figcaption {
    display: flex;
    justify-content: center;
    padding: var(--it230-space-4) var(--it230-space-5);
    border-top: 1px solid var(--it230-color-line);
}

.device-phone[data-orientation="portrait"] .device-screen iframe {
    width: var(--frame-width);
    height: var(--frame-height);
    transform: scale(var(--frame-scale, 1));
    transform-origin: top left;
}

/*
 * Accent picker.
 *
 * Selection is carried by a ring and by `aria-checked`, never by the swatch
 * colour alone: the control is a row of colours, so colour is the one cue it
 * cannot rely on to say which is chosen.
 */
.accent-picker {
    padding: var(--it230-space-5);
    border: 1px solid var(--it230-color-line);
    border-radius: var(--it230-radius-lg);
    margin-bottom: var(--it230-space-7);
    background: var(--it230-color-surface);
}

.accent-picker-label {
    margin: 0 0 var(--it230-space-2);
    font-weight: 700;
}

.accent-swatches {
    display: flex;
    flex-wrap: wrap;
    gap: var(--it230-space-2);
}

.accent-swatch {
    display: inline-flex;
    align-items: center;
    gap: var(--it230-space-2);
    min-height: 2.75rem;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--it230-color-line);
    border-radius: 999px;
    background: var(--it230-color-surface);
    color: var(--it230-color-text);
    font: inherit;
    font-size: 0.85rem;
    cursor: pointer;
}

.accent-swatch:hover {
    border-color: var(--swatch);
}

.accent-swatch[aria-checked="true"] {
    border-color: var(--swatch);
    box-shadow: inset 0 0 0 0.12rem var(--swatch);
    font-weight: 700;
}

.accent-dot {
    width: 0.85rem;
    height: 0.85rem;
    border: 1px solid rgb(0 0 6 / 18%);
    border-radius: 999px;
    background: var(--swatch);
}

.accent-picker-note {
    margin: var(--it230-space-4) 0 0;
    color: var(--it230-color-muted);
    font-size: 0.85rem;
}

/* The overview uses columns where the evidence stays readable. */
@media (min-width: 56rem) {
    .showcase-section-overview {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: var(--it230-space-7);
        align-items: start;
    }

    .showcase-section-overview > :not(.showcase-excerpt) {
        grid-column: 1;
    }

    .showcase-section-overview > .showcase-excerpt {
        grid-column: 2;
        grid-row: 1 / span 4;
        margin-bottom: 0;
    }
}
