/* ==========================================================================
   The window frame and its body types.
   ========================================================================== */

.hxp-windows {
    position: absolute;
    top: 0;
    bottom: var(--taskbar-h);
    left: var(--canvas-gutter);
    right: var(--canvas-gutter);
    z-index: 10;

    /* This layer spans the whole desktop and sits above the icons, so left
       solid it swallows every click aimed at them. Only the windows
       themselves should take the pointer. */
    pointer-events: none;
}

.hxp-win {
    pointer-events: auto;
}

/* --------------------------------------------------------------------------
   Frame
   -------------------------------------------------------------------------- */

.hxp-win {
    position: absolute;
    /* Placement is a fraction of the free space, so a window authored flush
       against an edge stays flush against it at any canvas width. */
    left: calc(var(--fx) * (100% - var(--w) * var(--u)));
    top: calc(var(--fy) * (100% - var(--h) * var(--u)));
    width: calc(var(--w) * var(--u));
    height: calc(var(--h) * var(--u));
    z-index: var(--z);

    display: flex;
    flex-direction: column;

    /* The window sizes its own contents. Everything inside lays itself out
       from this width rather than from whether the window happens to be
       maximised - so dragging a widget wide by hand gives you the expanded
       design, separators, padding and alignment included. Safe to contain:
       the width is set explicitly, never derived from the contents. */
    container-type: inline-size;
    container-name: win;

    background: var(--glass);
    border: 1px solid var(--glass-edge);
    border-radius: var(--win-radius);
    backdrop-filter: blur(12px);
    box-shadow: 0 18px 50px -20px rgba(0, 0, 0, 0.6);
    overflow: hidden;

    /* Drag writes these; they stay at 0 the rest of the time. */
    translate: calc(var(--dx, 0) * 1px) calc(var(--dy, 0) * 1px);

    opacity: 1;
    visibility: visible;

    /* Expanding is the same widget growing, not a different window opening. */
    transition:
        left 0.3s var(--ease),
        top 0.3s var(--ease),
        width 0.3s var(--ease),
        height 0.3s var(--ease),
        opacity 0.22s var(--ease),
        visibility 0s;
}

/* A gesture must track the pointer exactly, with nothing easing behind it. */
.hxp-win.is-dragging,
.hxp-win.is-resizing {
    transition: none;
}

@media (prefers-reduced-motion: reduce) {
    .hxp-win {
        transition: none;
    }
}

/* Putting a window away fades it. display:none cannot be transitioned, so a
   minimised window would vanish and reappear with a pop - which is what made
   the desktop look like it was jumping around during navigation. */
.hxp-win[data-state="min"],
.hxp-win[data-state="closed"] {
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition:
        opacity 0.22s var(--ease),
        visibility 0s linear 0.22s;
}

.hxp-win.is-dragging {
    cursor: grabbing;
    box-shadow: 0 30px 70px -20px rgba(0, 0, 0, 0.7);
    user-select: none;
}

.hxp-win[data-state="max"] {
    left: calc(9 * var(--u));
    top: calc(93 * var(--u));
    width: calc(100% - 18 * var(--u));
    height: calc(100% - 102 * var(--u));

    /* Deliberately NOT a fixed z-index. Pinning it at 50 put an expanded
       window *underneath* any widget the visitor had raised past that, so
       opening one could leave it buried. Whatever opens is focused, and
       focusing is what puts a window on top. */
    z-index: var(--z);
}

/* --------------------------------------------------------------------------
   Title bar
   -------------------------------------------------------------------------- */

.hxp-win__bar {
    flex-shrink: 0;
    height: calc(var(--win-bar-h) * var(--u));
    padding-inline: calc(var(--win-pad) * var(--u));

    display: flex;
    align-items: center;
    gap: calc(12 * var(--u));

    border-bottom: 1px solid var(--glass-rule);
    cursor: grab;
    touch-action: none;
}

.hxp-win[data-state="max"] .hxp-win__bar {
    cursor: default;
}

.hxp-win__title {
    margin: 0;
    font-size: calc(var(--t-title) * var(--u));
    font-weight: 600;
    line-height: 1;
    text-transform: capitalize;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.hxp-win__title-link {
    text-decoration: none;
    color: inherit;
}

.hxp-win__title-link:hover {
    text-decoration: underline;
    text-decoration-thickness: 1px;
    text-underline-offset: calc(3 * var(--u));
}

.hxp-win__tools {
    margin-left: auto;
    display: flex;
    align-items: center;
    gap: calc(10 * var(--u));
    flex-shrink: 0;
}

/* --- progress readout --------------------------------------------------- */

/* The readout belongs to the scattered window. Maximised, every card is on
   screen at once, so counting them says nothing - the design leaves it off. */
.hxp-win__progress {
    display: flex;
    align-items: center;
    gap: calc(10 * var(--u));
}

.hxp-win__progress-label {
    font-size: calc(var(--t-micro) * var(--u));
    color: var(--ink-muted);
    white-space: nowrap;
}

.hxp-win__progress-pill {
    position: relative;
    display: grid;
    place-items: center;
    width: calc(66 * var(--u));
    height: calc(13 * var(--u));
    border-radius: 100px;
    background: linear-gradient(90deg, var(--pill-from), var(--pill-to));
    overflow: hidden;
}

.hxp-win__progress-fill {
    position: absolute;
    inset: 0 auto 0 0;
    width: var(--fill, 0%);
    background: rgba(249, 243, 83, 0.32);
    transition: width 0.12s linear;
}

.hxp-win__progress-num {
    position: relative;
    font-size: calc(var(--t-micro) * var(--u));
    font-weight: 300;
    line-height: 1;
    white-space: nowrap;
}

/* Wide enough to be the expanded design, and the readout is widget chrome.
   This has to sit after the rules above: @container adds no specificity, so a
   later plain rule would simply win. */
@container win (min-width: 740px) {
    .hxp-win__progress {
        display: none;
    }
}

/* --- traffic lights ----------------------------------------------------- */

/* Only the maximised pages carry these in the design. On the scattered desktop
   a row of macOS dots on an XP window reads as the wrong operating system. */
.hxp-win:not([data-state="max"]) .hxp-lights {
    display: none;
}

.hxp-lights {
    display: flex;
    align-items: center;
    gap: calc(8 * var(--u));
}

.hxp-light {
    width: calc(13 * var(--u));
    height: calc(13 * var(--u));
    border-radius: 50%;
    box-shadow: inset 0 -1px 2px rgba(0, 0, 0, 0.28);
    transition: filter 0.15s var(--ease);
}

.hxp-light:hover {
    filter: brightness(1.2);
}

.hxp-light--close { background: var(--light-close); }
.hxp-light--min   { background: var(--light-min); }
.hxp-light--max   { background: var(--light-max); }

/* --------------------------------------------------------------------------
   Body

   Text is never scaled to fit - it stays at the size it was designed at and
   scrolls when there is more of it than the frame holds. Structure still fits:
   grids and media divide the frame between them.
   -------------------------------------------------------------------------- */

.hxp-win__body {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    padding: calc(var(--win-pad) * var(--u));
    overflow: hidden;
}

.hxp-win__scroll {
    flex: 1 1 auto;
    min-height: 0;
    display: flex;
    flex-direction: column;
    overflow-y: auto;
    overflow-x: hidden;
    overscroll-behavior: contain;

    /* The native bar is hidden in favour of the design's own indicator below.
       On macOS the native one is an overlay: it takes no space and fades out,
       leaving the cut edge as the only cue that there is more to read. */
    scrollbar-width: none;
}

.hxp-win__scroll::-webkit-scrollbar {
    display: none;
}

.hxp-win__scroll > * {
    flex: 1 1 auto;
    min-height: 0;
}

/* --- scroll indicator ---------------------------------------------------
   The slim yellow bar from the design. Always visible while the window has
   more to show, unlike the platform's overlay scrollbar.
   ---------------------------------------------------------------------- */

.hxp-scrollbar {
    position: absolute;
    top: calc(var(--win-pad) * var(--u));
    bottom: calc(var(--win-pad) * var(--u));
    right: calc(var(--win-pad) * var(--u));
    width: calc(8 * var(--u));
    border-radius: 100px;
    background: var(--glass-inset);
    pointer-events: none;
    opacity: 0;
    transition: opacity 0.2s var(--ease);
}

.hxp-win__body.is-scrollable .hxp-scrollbar {
    opacity: 1;
}

.hxp-win__body.is-scrollable .hxp-win__scroll {
    padding-right: calc(20 * var(--u));
}

.hxp-scrollbar__thumb {
    position: absolute;
    left: 0;
    right: 0;
    top: 0;
    height: 20%;
    border-radius: 100px;
    background: var(--harry-yellow);
    box-shadow: 0 calc(4 * var(--u)) calc(4 * var(--u)) rgba(0, 0, 0, 0.25);
}

/* --------------------------------------------------------------------------
   Cards

   A window with a segmented bar slides through its cards. Snapping is
   "proximity", not "mandatory", so a card with more text than the frame holds
   can still be read through rather than fighting the scroll back to its top.
   -------------------------------------------------------------------------- */

.hxp-cards {
    display: flex;
    flex-direction: column;
    min-height: 0;
}

.hxp-win--slides[data-state="open"] .hxp-win__scroll {
    scroll-snap-type: y proximity;
    scroll-behavior: smooth;
}

.hxp-win[data-state="open"] .hxp-card-slide,
.hxp-win[data-state="open"] .hxp-project,
.hxp-win[data-state="open"] .hxp-card {
    scroll-snap-align: start;
}

@media (prefers-reduced-motion: reduce) {
    .hxp-win__scroll {
        scroll-behavior: auto;
    }
}

/* --- resize grip -------------------------------------------------------- */

.hxp-win__resize {
    position: absolute;
    right: 0;
    bottom: 0;
    width: calc(18 * var(--u));
    height: calc(18 * var(--u));
    display: grid;
    place-items: center;
    color: var(--ink);
    cursor: nwse-resize;
    touch-action: none;
    opacity: 0.5;
    transition: opacity 0.15s var(--ease);
}

.hxp-win__resize:hover,
.hxp-win__resize:focus-visible,
.hxp-win.is-resizing .hxp-win__resize {
    opacity: 1;
}

.hxp-win__resize svg {
    width: calc(11 * var(--u));
    height: calc(11 * var(--u));
}

/* A maximised window fills the frame; there is nothing to resize. */
.hxp-win[data-state="max"] .hxp-win__resize {
    display: none;
}

.hxp-win.is-resizing {
    user-select: none;
}

/* --- footer segments ---------------------------------------------------- */

.hxp-win__segments {
    flex-shrink: 0;
    display: flex;
    gap: calc(12 * var(--u));
    padding: 0 calc(var(--win-pad) * var(--u)) calc(var(--win-pad) * var(--u));
}

.hxp-seg {
    flex: 1 1 0;
    height: calc(8 * var(--u));
    border-radius: 100px;
    background: var(--glass-inset);
    transition: background 0.2s var(--ease);
}

@container win (min-width: 740px) {
    .hxp-win__segments { display: none; }
}

.hxp-seg.is-on {
    background: var(--harry-yellow);
    box-shadow: 0 4px 4px rgba(0, 0, 0, 0.25);
}

/* ==========================================================================
   Shared body primitives
   ========================================================================== */

.hxp-eyebrow {
    margin: 0 0 calc(4 * var(--u));
    font-size: calc(var(--t-eyebrow) * var(--u));
    font-weight: 400;
    line-height: 1.2;
    color: var(--ink-muted);
}

.hxp-lead {
    margin: 0 0 calc(14 * var(--u));
    font-size: calc(var(--t-lead) * var(--u));
    font-weight: 600;
    line-height: 1.2;
}

.hxp-prose {
    font-size: calc(var(--t-body) * var(--u));
    line-height: 1.42;
}

.hxp-prose > :first-child { margin-top: 0; }
.hxp-prose > :last-child  { margin-bottom: 0; }
.hxp-prose p { margin: 0 0 1em; }

.hxp-empty {
    margin: 0;
    color: var(--ink-muted);
    font-size: calc(var(--t-body) * var(--u));
}

/* --- buttons ------------------------------------------------------------ */

.hxp-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 100px;
    text-decoration: none;
    white-space: nowrap;
    transition: filter 0.15s var(--ease);
}

.hxp-btn:hover {
    filter: brightness(1.1);
}

.hxp-btn--pill {
    height: calc(19 * var(--u));
    padding-inline: calc(12 * var(--u));
    background: var(--harry-yellow);
    color: var(--mono-black);
    font-size: calc(var(--t-micro) * var(--u));
    font-weight: 600;
}

.hxp-btn--solid {
    height: calc(19 * var(--u));
    padding-inline: calc(16 * var(--u));
    background: var(--harry-yellow);
    color: var(--mono-black);
    font-size: calc(11 * var(--u));
    font-weight: 600;
}

/* --- progress bars ------------------------------------------------------ */

.hxp-bar {
    display: block;
    height: calc(8 * var(--u));
    border-radius: 100px;
    background: var(--glass-inset);
    overflow: hidden;
}

.hxp-bar__fill {
    display: block;
    height: 100%;
    width: var(--fill, 0%);
    border-radius: 100px;
    background: var(--harry-yellow);
}

/* --- media facade ------------------------------------------------------- */

.hxp-media {
    position: relative;
    display: block;
    width: 100%;
    min-height: 0;
    border-radius: calc(4 * var(--u));
    overflow: hidden;
    background: rgba(255, 255, 255, 0.06);
}

/* Direct child only. The play mark is an <img> too, and this rule was
   stretching it to fill the plate with object-fit: cover. */
.hxp-media > img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hxp-media__empty {
    display: block;
    height: 100%;
    min-height: calc(40 * var(--u));
}

.hxp-media__play {
    position: absolute;
    inset: 0;
    display: grid;
    place-items: center;
    pointer-events: none;
}

.hxp-media__play img,
.hxp-media__play svg {
    width: calc(86 * var(--u));
    height: auto;
    filter: drop-shadow(0 2px 8px rgba(0, 0, 0, 0.35));
    transition: transform 0.2s var(--ease);
}

.hxp-media--video:hover .hxp-media__play img,
.hxp-media--video:hover .hxp-media__play svg {
    transform: scale(1.06);
}

.hxp-media video,
.hxp-media iframe {
    width: 100%;
    height: 100%;
    border: 0;
    aspect-ratio: 16 / 9;
}

/* ==========================================================================
   Type: image
   ========================================================================== */

.hxp-figure {
    margin: 0;
    height: 100%;
    border-radius: calc(4 * var(--u));
    overflow: hidden;
}

.hxp-figure img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* ==========================================================================
   Type: project-list (Track Record)
   ========================================================================== */

.hxp-projects {
    margin: 0;
    padding: 0;
    list-style: none;
    display: flex;
    flex-direction: column;
    gap: calc(14 * var(--u));
    min-height: 0;
}

.hxp-project {
    display: grid;
    grid-template-columns: 1fr calc(214 * var(--u));
    gap: calc(24 * var(--u));
    align-items: stretch;
    min-height: 0;
    padding-bottom: calc(14 * var(--u));
    border-bottom: 1px solid var(--glass-rule);
}

.hxp-project:last-child {
    border-bottom: 0;
    padding-bottom: 0;
}

/* Narrow: rows keep their designed proportions and the window scrolls through
   them - the progress readout counts those rows. */
@container win (max-width: 739.98px) {
    .hxp-project {
        flex: 0 0 auto;
    }

    .hxp-project__media .hxp-media {
        aspect-ratio: 214 / 156;
        flex: 0 0 auto;
    }

    .hxp-project__text {
        min-height: 0;
    }

    .hxp-project__description {
        display: none;   /* not in the design's compact window either */
    }
}

.hxp-project__title {
    margin: 0 0 calc(12 * var(--u));
    font-size: calc(var(--t-lead) * var(--u));
    font-weight: 600;
    line-height: 1.2;
}

.hxp-project__detail-label {
    margin-top: calc(12 * var(--u));
}

.hxp-project__subtitle,
.hxp-project__description {
    margin: 0;
    font-size: calc(var(--t-body) * var(--u));
    line-height: 1.35;
}

.hxp-project__description {
    color: var(--ink-muted);
    margin-top: calc(6 * var(--u));
}

.hxp-project__media {
    display: flex;
    flex-direction: column;
    gap: calc(8 * var(--u));
    min-height: 0;
}

.hxp-project__media .hxp-media {
    flex: 1 1 auto;
    min-height: 0;
}

/* Wide: the list becomes the three-column grid from the Figma. */
@container win (min-width: 740px) {
    .hxp-projects {
        display: grid;
        grid-template-columns: repeat(auto-fill, minmax(calc(360 * var(--u)), 1fr));
        grid-auto-rows: auto;
        gap: calc(24 * var(--u)) calc(43 * var(--u));
        align-items: start;
    }

    .hxp-project {
        grid-template-columns: 1fr;
        gap: calc(12 * var(--u));
        border-top: 1px solid var(--glass-rule);
        border-bottom: 0;
        padding-top: calc(12 * var(--u));
        padding-bottom: 0;
    }

    .hxp-project__media {
        width: 100%;
    }

    .hxp-project__media .hxp-media {
        flex: 0 0 auto;
        aspect-ratio: 405 / 248;
    }
}

/* ==========================================================================
   Type: video-grid (Content)
   ========================================================================== */

.hxp-grid {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(calc(340 * var(--u)), 1fr));
    grid-auto-rows: 1fr;          /* rows share the frame instead of overrunning it */
    gap: calc(24 * var(--u)) calc(43 * var(--u));
    align-items: stretch;
    min-height: 0;
}

/* Wide: cards take their natural height and the media keeps the aspect the
   Figma draws it at. Sharing the frame between rows stretched the artwork to
   whatever height was left over. */
@container win (min-width: 740px) {
    .hxp-grid {
        grid-auto-rows: auto;
        align-items: start;
        row-gap: calc(34 * var(--u));
    }

    .hxp-card .hxp-media {
        flex: 0 0 auto;
        aspect-ratio: 405 / 248;
    }
}

/* "See more" points at the page you are already on. */
@container win (min-width: 740px) {
    .hxp-win__tools .hxp-btn--pill { display: none; }
}

.hxp-card .hxp-media {
    flex: 1 1 auto;
    min-height: 0;
}

.hxp-card {
    display: flex;
    flex-direction: column;
    gap: calc(6 * var(--u));
    padding-top: calc(14 * var(--u));
    border-top: 1px solid var(--glass-rule);

    /* Grid items default to min-height:auto, which floors them at their
       content height - the card could not shrink below its image's intrinsic
       size and overran the row. */
    min-height: 0;
    min-width: 0;
}

.hxp-card__title {
    margin: 0;
    font-size: calc(var(--t-lead) * var(--u));
    font-weight: 600;
    line-height: 1.2;
}

.hxp-card__description {
    margin: 0 0 calc(8 * var(--u));
    font-size: calc(var(--t-body) * var(--u));
    color: var(--ink-muted);
}

/* Narrow: the Content window shows one card filling the frame. */
@container win (max-width: 739.98px) {
    .hxp-grid {
        grid-template-columns: 1fr;
    }

    .hxp-card:nth-child(n + 2) {
        display: none;
    }

    .hxp-card {
        border-top: 0;
        padding-top: 0;
    }

    .hxp-card .hxp-eyebrow,
    .hxp-card .hxp-card__title,
    .hxp-card .hxp-card__description,
    .hxp-card .hxp-bar {
        display: none;
    }
}

/* ==========================================================================
   Type: services
   ========================================================================== */

.hxp-services__intro {
    flex: 0 0 auto;
    padding-bottom: calc(18 * var(--u));
    border-bottom: 1px solid var(--glass-rule);
}

/* Constrain the copy, not the block: max-width on the block dragged its rule
   in with it, so the separator stopped where the text stopped instead of
   running the full width of the window as the design has it. */
@container win (min-width: 1100px) {
    .hxp-services__intro > * {
        max-width: calc(600 * var(--u));
    }
}



/* Natural height, never a share of the frame. `flex: 1 1 0` let short windows
   crush these rows below their own content, so consecutive rows drew on top of
   each other - the window scrolls instead. */
.hxp-service {
    flex: 0 0 auto;
    display: grid;
    grid-template-columns: calc(150 * var(--u)) minmax(0, calc(390 * var(--u))) minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas: "mark title body bullets";
    gap: calc(28 * var(--u));
    align-items: start;
    padding: calc(24 * var(--u)) 0;
    border-bottom: 1px solid var(--glass-rule);
}

.hxp-service:last-child {
    border-bottom: 0;
}

.hxp-service__mark {
    grid-area: mark;
    display: flex;
    flex-direction: column;
    gap: calc(8 * var(--u));
}

.hxp-service__num {
    font-size: calc(30 * var(--u));
    font-weight: 600;
    line-height: 1;
    color: var(--ink-faint);
    font-variant-numeric: tabular-nums;
}

.hxp-service__icon {
    width: calc(35 * var(--u));
    height: calc(35 * var(--u));
    object-fit: contain;
}

.hxp-service__title {
    grid-area: title;
    margin: 0;
    font-size: calc(38 * var(--u));
    font-weight: 600;
    line-height: 1.06;
    letter-spacing: -0.02em;
    text-wrap: balance;
}

.hxp-service__body {
    grid-area: body;
    margin: 0;
    font-size: calc(var(--t-body) * var(--u));
    line-height: 1.4;
}

.hxp-service__bullets {
    grid-area: bullets;
    margin: 0;
    padding-left: calc(16 * var(--u));
    font-size: calc(var(--t-body) * var(--u));
    line-height: 1.5;
}

.hxp-service__bullets li::marker {
    color: var(--ink-faint);
}

/* Between the two: wide enough for the expanded design, not wide enough for
   four columns of it. Four would leave the body copy setting three words to a
   line. The title takes the full width and the two text columns sit under it. */
@container win (min-width: 740px) and (max-width: 1099.98px) {
    .hxp-service {
        grid-template-columns: calc(120 * var(--u)) minmax(0, 1fr) minmax(0, 1fr);
        grid-template-areas:
            "mark  title   title"
            "mark  body    bullets";
        gap: calc(10 * var(--u)) calc(24 * var(--u));
    }

    .hxp-service__title {
        font-size: calc(30 * var(--u));
    }
}

/* Narrow: each card gets the frame to itself - one column, full width, and
   only as tall as its own content. The separators and the run of the rows are
   the same either way; only the column count and the type sizes change. */
@container win (max-width: 739.98px) {
    .hxp-card-slide {
        flex: 0 0 auto;
        padding-block: calc(4 * var(--u)) calc(16 * var(--u));
    }

    .hxp-services__intro {
        padding-bottom: calc(14 * var(--u));
    }

    .hxp-service {
        /* The areas have to go too: a four-cell template keeps four columns
           however grid-template-columns is set, so the rows stayed in four
           squeezed columns instead of stacking. */
        grid-template-areas: none;
        grid-template-columns: 1fr;
        gap: calc(8 * var(--u));
    }

    /* And so do the item placements. With no matching area, `grid-area: mark`
       is read as a line name instead, and grid invents implicit zero-width
       tracks for lines that do not exist - which is what stacked the parts of
       a row on top of each other. */
    .hxp-service > * {
        grid-area: auto;
    }

    .hxp-service__mark {
        flex-direction: row;
        align-items: center;
        gap: calc(10 * var(--u));
    }

    .hxp-service__num {
        font-size: calc(20 * var(--u));
    }

    .hxp-service__title {
        font-size: calc(22 * var(--u));
    }
}

/* ==========================================================================
   Type: media-player
   ========================================================================== */

.hxp-player {
    display: flex;
    flex-direction: column;
    gap: calc(12 * var(--u));
    height: 100%;
}

/* The transport sits in the title bar, where the design puts it. */
.hxp-player__transport {
    display: flex;
    align-items: center;
    gap: calc(10 * var(--u));
}

.hxp-win--media-player .hxp-win__tools {
    display: none;
}

.hxp-player__btn {
    display: grid;
    place-items: center;
    width: calc(20 * var(--u));
    height: calc(20 * var(--u));
    color: var(--ink);
}

.hxp-player__btn svg {
    width: calc(15 * var(--u));
    height: calc(15 * var(--u));
}

.hxp-player__stage {
    flex: 1 1 auto;
    min-height: 0;
    border-radius: calc(4 * var(--u));
    overflow: hidden;
    background: rgba(255, 255, 255, 0.06);
}

.hxp-player__stage img,
.hxp-player__stage video {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.hxp-player__bar {
    flex-shrink: 0;
}

/* The player's bar is a gradient that runs out rather than a hard-edged
   progress fill - it reads as playback, not as a percentage. */
.hxp-player__bar .hxp-bar__fill {
    width: 100%;
    background: linear-gradient(
        90deg,
        var(--harry-yellow) 0%,
        rgba(237, 255, 0, 0.88) 16%,
        rgba(213, 226, 0, 0.55) 42%,
        rgba(160, 170, 0, 0.22) 68%,
        rgba(237, 255, 0, 0) 88%
    );
}

/* ==========================================================================
   Type: gimmick — the big buttons (blue: blue screen, red: detonate)
   ========================================================================== */

.hxp-gimmick {
    display: grid;
    place-items: center;
    height: 100%;
    min-height: 0;
    overflow: hidden;
}

.hxp-bigred {
    display: block;
    aspect-ratio: 1;
    block-size: min(calc(83 * var(--u)), 100%);
    inline-size: auto;
    max-inline-size: 100%;
    transition: transform 0.09s var(--ease);
}

.hxp-bigred img {
    width: 100%;
    height: 100%;
    object-fit: contain;
}

.hxp-bigred:active {
    transform: translateY(calc(2 * var(--u))) scale(0.97);
}

/* The red artwork carries its own drop shadow and the blue does not, so the
   blue one is given a matching shadow here rather than sitting flatter than
   its twin. Only on the blue, or the red would get two. */
.hxp-bigred--blue img {
    filter: drop-shadow(0 3px 4px rgba(0, 0, 0, 0.4));
}

/* Once it has been pressed there is nothing left to press. */
.hxp-bigred:disabled {
    cursor: default;
}

/* ==========================================================================
   Type: contact — Clippy
   ========================================================================== */

.hxp-clippy {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: calc(12 * var(--u));
    height: 100%;
    text-align: center;
}

.hxp-clippy__img {
    flex: 1 1 auto;
    min-height: 0;
    width: 100%;
    display: grid;
    place-items: center;
}

/* Bound on both axes and let the intrinsic ratio pick the size, so the
   artwork scales down to fit rather than being cropped by its box. */
.hxp-clippy__img img {
    width: auto;
    height: auto;
    max-width: min(calc(119 * var(--u)), 100%);
    max-height: 100%;
    object-fit: contain;
}

.hxp-clippy .hxp-btn {
    width: 100%;
}

/* --------------------------------------------------------------------------
   Narrow windows — the gimmick frame is 117 units wide and Clippy 156. At the
   standard 18 units of padding and a 16-unit title there is nothing left to
   set the title in, so both tighten and the title wraps rather than truncates.
   -------------------------------------------------------------------------- */

.hxp-win--narrow {
    --win-pad: 13;
}

.hxp-win--narrow .hxp-win__bar {
    height: auto;
    min-height: calc(34 * var(--u));
    align-items: flex-start;
    padding-block: calc(10 * var(--u)) calc(8 * var(--u));
}

.hxp-win--gimmick {
    --win-pad: 9;
}

.hxp-win--gimmick .hxp-win__title {
    font-size: calc(13 * var(--u));
}

/* Clippy and the red button are fixed-size widgets, and their titles read as
   labels for the thing underneath - so they centre.

   The title has to span the bar for that: .hxp-win__tools carries
   margin-left:auto, which eats the free space and pins the title left however
   the bar is justified. Neither window renders any tools, so it goes. */
.hxp-win--contact .hxp-win__tools,
.hxp-win--gimmick .hxp-win__tools {
    display: none;
}

.hxp-win--contact .hxp-win__title,
.hxp-win--gimmick .hxp-win__title {
    flex: 1 1 auto;
    text-align: center;
}

.hxp-win--narrow .hxp-win__title {
    font-size: calc(14 * var(--u));
    line-height: 1.18;
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
    text-wrap: balance;
}

/* ==========================================================================
   Type: connect — the contact details panel
   ========================================================================== */

.hxp-connect {
    display: flex;
    flex-direction: column;
    gap: calc(8 * var(--u));
}

.hxp-connect__lead {
    margin: 0 0 calc(4 * var(--u));
    font-size: calc(var(--t-body) * var(--u));
    line-height: 1.35;
    color: var(--ink-muted);
}

.hxp-connect__link {
    width: 100%;
    height: calc(26 * var(--u));
    font-size: calc(13 * var(--u));
}

.hxp-connect__socials {
    display: flex;
    gap: calc(8 * var(--u));
}

.hxp-connect__social {
    flex: 1 1 0;
    height: calc(26 * var(--u));
}

.hxp-connect__social svg {
    width: calc(15 * var(--u));
    height: calc(15 * var(--u));
}

.hxp-scrim {
    position: absolute;
    inset: 0 0 var(--taskbar-h) 0;
    z-index: 800;
    background: rgba(6, 10, 18, 0.5);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.25s var(--ease), visibility 0s linear 0.25s;
}

.hxp-desktop.has-modal .hxp-scrim {
    opacity: 1;
    visibility: visible;
    transition: opacity 0.25s var(--ease), visibility 0s;
}
