/* =====================================================================
   express.css -- the express lane (js/express.js), Sep 2026.
   Full bleed like the old journey: no header, no bottom nav. Warm paper,
   Cormorant titles, Quicksand UI, big thumb-friendly targets, 360px safe.
   Tokens only (css/theme.css).

   CENTRED ON THE COUPLE (Sep 2026, owner: "the design to be centralized
   with the Orange Mushroom and Violetta there"). Top to bottom, every
   step: the slim top bar (brand, pips, the Hi / Table / Not you? pill),
   THE COUPLE STAGE (.xl-couple, ~140px), a centred title, then the step's
   content in one centred column.
   ===================================================================== */

body[data-page="express"] #app-nav,
body[data-page="express"] #cam-pop,
body[data-page="express"] #jy-banner,
body[data-page="express"] #jy-retry { display: none; }
/* #app clips with overflow:hidden, which makes it the sticky containing
   scroller and would un-pin .xl-top. clip does not (visible is the fallback
   for engines without clip; body already hides horizontal overflow). */
body[data-page="express"] #app { overflow: visible; overflow: clip; }
body[data-page="express"] #app-content {
    padding: 0 var(--page-pad) calc(var(--space-lg) + env(safe-area-inset-bottom, 0));
}

.xl { max-width: 420px; margin: 0 auto; }
/* CENTRED ON THE SCREEN (owner, 26 Sep): the lane fills the viewport as a
   column; the top bar stays pinned first, and the couple stage + the step sit
   in the middle of the space left (auto margins), so a short step like E1 is
   not stranded at the top of an empty page. With the keyboard up (.xl--kbd)
   the column stays top-aligned so the name field stays in view. */
.xl {
    display: flex; flex-direction: column;
    min-height: calc(100vh - var(--space-lg) - env(safe-area-inset-bottom, 0px));
    min-height: calc(100dvh - var(--space-lg) - env(safe-area-inset-bottom, 0px));
}
.xl > .xl-couple, .xl > .xl-body, .xl > .xl-splash { width: 100%; }
.xl:not(.xl--kbd) > .xl-couple { margin-top: auto; }
.xl:not(.xl--kbd) > .xl-body { margin-bottom: auto; }
.xl--splash > .xl-splash { margin-bottom: auto; }
.xl .spin {
    display: inline-block; width: 1em; height: 1em; vertical-align: -2px; margin-right: 8px;
    border: 2px solid currentColor; border-top-color: transparent; border-radius: 50%;
    animation: btnspin .7s linear infinite;
}

/* ---- top: brand, progress pips, and the pinned Hi / Table / Not you? ---- */
.xl-top {
    position: sticky; top: 0; z-index: 20;
    margin: 0 calc(-1 * var(--page-pad));
    padding: calc(12px + env(safe-area-inset-top, 0)) var(--page-pad) 10px;
    background: color-mix(in srgb, var(--paper) 92%, transparent);
    -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px);
    border-bottom: var(--bw) solid var(--line);
}
.xl-bar {
    display: flex; align-items: center; justify-content: space-between; gap: var(--space-sm);
    max-width: 380px; margin: 0 auto;
}
.xl-brand {
    font-family: var(--display); font-weight: 600; font-size: var(--text-lg);
    color: var(--ink); line-height: 1; white-space: nowrap;
}
.xl-brand .amp { font-style: italic; color: var(--accent); }
.xl-dots { display: inline-flex; align-items: center; gap: 6px; }
.xl-dots i {
    display: block; width: 8px; height: 8px; border-radius: var(--radius-pill);
    background: var(--line); transition: width var(--dur-med), background var(--dur-med);
}
.xl-dots i.on { background: var(--accent-soft); }
.xl-dots i.cur { background: var(--accent); width: 22px; }

/* one centred pill: Hi, Name | Table 7 | Not you? */
.xl-who {
    display: flex; align-items: center; justify-content: center; gap: 8px;
    width: fit-content; max-width: 100%;
    margin: 10px auto 0; padding: 3px 3px 3px 14px;
    background: var(--card);
    border: var(--bw) solid var(--line); border-radius: var(--radius-pill);
    box-shadow: var(--shadow-sm);
}
.xl-hi {
    min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-size: var(--text-sm); color: var(--ink-soft);
}
.xl-hi b { color: var(--ink); font-weight: 600; }
.xl-table {
    flex: none; display: inline-flex; align-items: center;
    font-weight: 700; font-size: var(--px-sm); line-height: 1;
    color: var(--card);
    /* the primary-fill rose (css/theme.css --rose-deep): the table chip is
       the same call-out as Home's, and white on it reads ~5.7:1 */
    background: var(--rose-deep);
    border-radius: var(--radius-pill); padding: 7px 12px;
}
/* a 44px tap target that does not fatten the pill: the negative block
   margin gives back the 8px the min-height adds (it lays out at 36px) */
.xl-notme {
    flex: none; min-height: 44px; margin: -4px 0; padding: 0 10px;
    background: none; border: 0; cursor: pointer;
    font: inherit; font-size: var(--text-xs); color: var(--dim);
    text-decoration: underline; text-underline-offset: 3px;
}
/* no "Not you?" and no table (E5, unseated): keep the right edge as soft as the left */
.xl-who > .xl-hi:last-child { padding-right: 11px; }

/* =====================================================================
   THE COUPLE STAGE
   Jiahao (the Orange Mushroom) left, Yi Fang (Violetta) right, the guest
   between them from E2 on. The boxes are the Home stage's (css/quest.css
   .hs-sprbox): each sized to its own frame sheet's aspect, the mushroom at
   .65 of her height and mirrored to face her. --xl-trio is mirrored in
   js/express.js TRIO (the guest's art is sized in px there).
   The band has a MIN-height, never a fixed one: a line that wraps to two
   (360px, large text) grows the stage downward instead of spilling up
   under the sticky top bar. Only the folded strips below (keyboard, short
   screens) are a fixed height, and they hide the line.
   ===================================================================== */
.xl-couple {
    --xl-trio: clamp(72px, 22vw, 88px);
    position: relative;
    min-height: 150px; max-width: 380px; margin: 8px auto 0;
    display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
    padding-bottom: 6px;
}
/* the soft ground: a blush wash and a warm oval under their feet */
.xl-floor {
    position: absolute; left: 6%; right: 6%; bottom: 0; height: 34px;
    pointer-events: none;
    background:
        radial-gradient(50% 38% at 50% 62%, color-mix(in srgb, var(--card-warm) 92%, transparent), transparent 100%),
        radial-gradient(60% 100% at 50% 100%, color-mix(in srgb, var(--blush) 50%, transparent), transparent 72%);
}

/* the one line: a small speech bubble, nudged toward the speaker, whose
   tail points at them (--tail: the speaker's offset from centre) */
.xl-say {
    position: relative; z-index: 1;
    left: calc(var(--tail) * .4);
    display: inline-flex; align-items: center; gap: 6px;
    max-width: min(270px, 76%);      /* 76% + the .4 tail nudge stays inside the band at 360px */
    margin: 0 auto 10px; padding: 6px 14px;
    font-size: var(--text-sm); font-weight: 500; line-height: 1.3; color: var(--ink);
    background: var(--card);
    border: var(--bw) solid color-mix(in srgb, var(--accent) 28%, var(--line));
    border-radius: 14px;
    box-shadow: var(--shadow-sm);
    animation: xlSay var(--ease-bounce) both;
    --tail: -40px;
}
.xl-say::after {
    content: '';
    position: absolute; bottom: -6px; margin-left: -5px;
    left: clamp(18px, calc(50% + var(--tail) * .6), calc(100% - 18px));
    width: 10px; height: 10px;
    background: var(--card);
    border-right: var(--bw) solid color-mix(in srgb, var(--accent) 28%, var(--line));
    border-bottom: var(--bw) solid color-mix(in srgb, var(--accent) 28%, var(--line));
    transform: rotate(45deg);
}
.xl-say[data-who="vio"] { --tail: 36px; }
.xl-couple[data-cast="3"] .xl-say[data-who="mush"] { --tail: -84px; }
.xl-couple[data-cast="3"] .xl-say[data-who="vio"]  { --tail: 80px; }
.xl-say-i { flex: none; display: inline-grid; place-items: center; color: var(--accent-deep); }
.xl-say-i svg { width: 16px; height: 16px; }
@keyframes xlSay { from { opacity: 0; transform: translateY(6px) scale(.94); } }

.xl-cast {
    position: relative; z-index: 1;
    display: flex; align-items: flex-end; justify-content: center;
    gap: clamp(6px, 3vw, 14px);
    transform-origin: bottom center;
    transition: transform var(--dur-med) ease;
}
.xl-cw {
    position: relative;
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    transform-origin: bottom center;
    transition: transform var(--dur-slow) ease;
}
.xl-spr { display: block; position: relative; animation: xlBob 5s ease-in-out infinite; }
.xl-cw--mush .xl-spr {
    height: calc(var(--xl-trio) * .65);
    width: calc(var(--xl-trio) * .65 * 1.125);
}
.xl-cw--vio .xl-spr {
    height: var(--xl-trio);
    width: calc(var(--xl-trio) * .886);
    animation-duration: 5.6s;
}
/* --xl-pk / --xl-pdy: a pose's calibration (js/express.js POSE_CAL), set
   on the <img> as it switches, so a frame sheet of another size draws at
   the idle art's size with its feet on the same floor line */
.xl-spr img {
    position: absolute; inset: 0; width: 100%; height: 100%;
    object-fit: contain; object-position: bottom center;
    image-rendering: pixelated;      /* SPRITES keep their pixels */
    pointer-events: none;
    transform: translateY(var(--xl-pdy, 0%)) scale(var(--xl-pk, 1));
    transform-origin: bottom center;
}
.xl-cw--mush .xl-spr img {
    transform: translateY(var(--xl-pdy, 0%)) scale(calc(-1 * var(--xl-pk, 1)), var(--xl-pk, 1));
}
.xl-gbox { display: block; animation: xlBob 5.2s ease-in-out infinite; }
.xl-gbox img, .xl-gbox .mbox { display: block; }
/* pixel art only: a real photo (photo, the photo_char head) stays smooth */
.xl-gbox[data-art="sprite"] img, .xl-gbox[data-art="maple"] img, .xl-gbox .mbox { image-rendering: pixelated; }
.xl-tag {
    max-width: 11ch; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
    font-family: var(--sans); font-weight: 600; font-size: var(--px-sm); letter-spacing: .04em;
    line-height: 1.2; color: var(--ink-soft);
}
.xl-cw--you .xl-tag { color: var(--accent-deep); }
@keyframes xlBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-4px); } }

/* E2: the guest pops in as a preset is tapped */
.xl-cw--you.is-pop { animation: xlPop .36s cubic-bezier(.34, 1.4, .64, 1) both; }
@keyframes xlPop { from { transform: translateY(6px) scale(.8); opacity: .4; } }

/* E3: they squeeze in for the photo */
.xl-couple[data-mood="selfie"] .xl-cw--mush { transform: translateX(6px); }
.xl-couple[data-mood="selfie"] .xl-cw--vio  { transform: translateX(-6px); }
/* E4: listening, leaning in toward the middle */
.xl-couple[data-mood="wish"] .xl-cw--mush { transform: rotate(4deg); }
.xl-couple[data-mood="wish"] .xl-cw--vio  { transform: rotate(-4deg); }
/* E5: a little celebratory hop, all three, left to right */
.xl-couple.is-hop .xl-cw { animation: xlHop .5s ease-out 2; }
.xl-couple.is-hop .xl-cw--you { animation-delay: .08s; }
.xl-couple.is-hop .xl-cw--vio { animation-delay: .16s; }
@keyframes xlHop {
    0%, 100% { transform: translateY(0); }
    40%      { transform: translateY(-14px); }
    70%      { transform: translateY(-3px); }
}

/* THE KEYBOARD (js/express.js _kbd): a field is focused and the viewport
   lost ~a keyboard of height. The stage folds to a strip, so the field
   stays in view; the line and the tags step out. A short viewport with no
   JS signal (a landscape phone) gets the same strip. */
.xl--kbd .xl-couple { height: 62px; min-height: 0; margin-top: 4px; }
.xl--kbd .xl-say, .xl--kbd .xl-tag { display: none; }
.xl--kbd .xl-cast { transform: scale(.6); }
.xl--kbd.xl--name .xl-sub { display: none; }
@media (max-height: 460px) {
    .xl-couple { height: 62px; min-height: 0; margin-top: 4px; }
    .xl-say, .xl-tag { display: none; }
    .xl-cast { transform: scale(.6); }
}

/* ---- body: one centred column ---- */
.xl-body {
    max-width: 380px; margin: 0 auto;
    padding: 12px 0 var(--space-sm);
    text-align: center;
    animation: xlIn var(--dur-slow) ease both;
}
@keyframes xlIn { from { opacity: 0; transform: translateY(6px); } }
.xl-title {
    font-family: var(--display); font-weight: 600;
    font-size: var(--text-2xl); line-height: 1.1;
    color: var(--ink); margin-bottom: 6px;
}
/* the step title takes the focus on a new step (for a screen reader); it is
   not a control, so no focus box around it (it showed after every camera
   return, QA 12 Oct) */
.xl-title[tabindex="-1"]:focus, .xl-title[tabindex="-1"]:focus-visible { outline: none; }
.xl-sub { font-size: var(--text-sm); color: var(--ink-soft); margin: 0 auto 16px; max-width: 36ch; }
.xl-label { font-size: var(--text-xs); font-weight: 600; color: var(--dim); margin: 14px 2px 6px; }
.xl-note, .xl-hint { font-size: var(--text-sm); color: var(--ink-soft); padding: 6px 2px; }
.xl-note { color: var(--accent-deep); }
.xl-err { font-size: var(--text-sm); color: var(--accent-deep); min-height: 0; margin-top: 8px; }
.xl-err:empty { display: none; }
.xl-up { font-size: var(--text-xs); color: var(--ink-soft); text-align: center; margin-top: 10px; }
.xl-up:empty { display: none; }
.xl-splash { padding-top: var(--space-lg); text-align: center; color: var(--ink-soft); font-size: var(--text-sm); }
.xl--splash { padding-top: 14vh; }

/* ---- E1 name ---- */
.xl-input.field {
    font-size: var(--text-base);          /* 16px: iOS never zooms the page */
    min-height: 56px; padding: 14px 16px;
    text-align: left;
    border-radius: var(--radius);
    background: var(--card);
}
.xl-list { display: flex; flex-direction: column; gap: var(--space-sm); margin-top: 12px; }
.xl-row {
    display: flex; align-items: center; gap: 12px;
    width: 100%; min-height: 60px; padding: 10px 14px;
    font: inherit; color: var(--ink); text-align: left; cursor: pointer;
    background: var(--card);
    border: var(--bw) solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    transition: transform var(--dur-fast), border-color var(--dur-med);
}
.xl-row:active { transform: scale(var(--tap-scale)); }
.xl-row:focus-visible, .xl-tile:focus-visible, .xl-card:focus-visible, .xl-bigcard:focus-visible, .xl-chip:focus-visible {
    outline: 2px solid var(--accent); outline-offset: 2px;
}
.xl-row[disabled] { cursor: default; }
.xl-row[disabled]:not(.is-busy) { opacity: .55; }
.xl-row.is-busy { border-color: var(--accent); }
.xl-row--new { border-style: dashed; background: var(--paper-2); box-shadow: none; }
.xl-ph {
    flex: 0 0 auto; width: 40px; height: 40px; border-radius: 50%;
    display: grid; place-items: center;
    background: color-mix(in srgb, var(--accent-soft) 34%, var(--card));
    color: var(--accent-deep);
    font-family: var(--display); font-weight: 600; font-size: var(--text-lg);
}
.xl-ph .spin { margin: 0; }
.xl-ph--plus { font-family: var(--sans); background: var(--card); border: var(--bw) solid var(--line); }
.xl-rt { min-width: 0; }
.xl-rn { display: block; font-family: var(--display); font-weight: 600; font-size: var(--text-lg); line-height: 1.2; }
.xl-row--new .xl-rn { font-family: var(--sans); font-size: var(--text-base); color: var(--accent-deep); }
.xl-row.is-busy .xl-rn { font-family: var(--sans); font-size: var(--text-base); color: var(--accent-deep); }
.xl-rs { display: block; font-size: var(--text-xs); color: var(--dim); margin-top: 2px; }

/* ---- E1 safe floor: the reception line and the outage final state ---- */
.xl-safe-t {
    font-size: var(--text-sm); line-height: 1.4; color: var(--ink-soft);
    text-align: center; padding: 4px 8px 0;
}
.xl-safe {
    display: flex; flex-direction: column; gap: var(--space-sm);
    padding: 16px 14px;
    background: var(--paper-2);
    border: var(--bw) solid var(--line); border-radius: var(--radius);
    text-align: center;
}
.xl-safe-h {
    font-family: var(--display); font-weight: 600;
    font-size: var(--text-lg); line-height: 1.3; color: var(--ink);
    max-width: 30ch; margin: 0 auto 4px;
}
.xl-safe .xl-link { margin-top: 0; }
/* the outage final state (register failed too): a touch warmer edge so it
   reads as "the answer for now", not as another loading panel */
.xl-safe--final { border-color: var(--accent-soft); }

/* ---- E2 character: THE PICKER (Oct 2026) ------------------------------
   The hero is the guest's character between the couple on the stage above
   (bigger on this step, js/express.js HERO_K, on a soft shadow). Below the
   title: the NAME PLATE (name + one line of personality, it follows the
   pick), then twenty ROUND PORTRAIT BADGES in four rows of five, each the
   1x idle (AvatarKit.spriteHtml fitBody: every character's body the same
   size, centred, clipped to the disc so a glow never spills onto a
   neighbour). Sprites are pixel art; the chrome around them stays quiet. */
.xl-gbox { position: relative; }
.xl-couple[data-mood="character"] .xl-gbox::after {
    content: ''; position: absolute; z-index: -1;
    left: 50%; bottom: -3px; width: 64%; height: 10px; transform: translateX(-50%);
    border-radius: 50%;
    background: radial-gradient(closest-side, color-mix(in srgb, var(--ink) 16%, transparent), transparent);
    pointer-events: none;
}
.xl-plate {
    display: flex; flex-direction: column; align-items: center; gap: 2px;
    width: fit-content; max-width: 100%;
    margin: 2px auto 14px; padding: 7px 18px 8px;
    background: var(--card);
    border: var(--bw) solid color-mix(in srgb, var(--accent) 26%, var(--line));
    border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    animation: xlIn var(--dur-med) ease both;
}
.xl-pn { font-family: var(--display); font-weight: 600; font-size: var(--text-lg); line-height: 1.15; color: var(--accent-deep); }
.xl-pl { font-size: var(--text-xs); line-height: 1.35; color: var(--ink-soft); }
.xl-sub--after { font-size: var(--text-xs); color: var(--dim); margin: 2px auto 10px; }

.xl-grid {
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 10px 6px; margin: 0 auto 10px; max-width: 360px;
}
.xl-tile {
    position: relative;
    display: grid; place-items: center;
    /* min-height 0: the art must never stretch the circle into an oval */
    width: 100%; aspect-ratio: 1; min-width: 0; min-height: 0; align-self: start; padding: 0;
    font: inherit; cursor: pointer;
    overflow: visible;
    background: radial-gradient(circle at 50% 38%, var(--card) 0 42%, color-mix(in srgb, var(--blush) 26%, var(--card-warm)) 100%);
    border: var(--bw) solid var(--line); border-radius: 50%;
    box-shadow: var(--shadow-sm);
    -webkit-tap-highlight-color: transparent;
    transition: border-color var(--dur-med), background var(--dur-med), transform var(--dur-fast), box-shadow var(--dur-med);
}
.xl-tile:active { transform: scale(.94); }
.xl-tile.on {
    border-color: var(--accent);
    background: radial-gradient(circle at 50% 38%, var(--card) 0 36%, color-mix(in srgb, var(--blush) 62%, var(--card)) 100%);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent), var(--shadow-sm);
}
/* the art fills the disc, centred and clipped to it */
.xl-tart { display: block; line-height: 0; }
.xl-tile:not(.xl-tile--keep) .xl-tart {
    position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
    display: grid; place-items: center;
}
.xl-tile .ak-spr { display: block; }
.xl-tile .xl-vh { position: absolute; }
.xl-tl { font-size: var(--text-xs); font-weight: 600; color: var(--ink-soft); line-height: 1.2; text-align: center; }
.xl-tile.on .xl-tl { color: var(--accent-deep); }
/* a badge whose art did not load (js/express.js _tileFallback): its name instead */
.xl-tile.is-noart .xl-tart { display: none; }
.xl-tile.is-noart .xl-tl { position: static; padding: 0 4px; -webkit-hyphens: auto; hyphens: auto; overflow-wrap: anywhere; }
/* the guest's own art on the stage did not load: no broken-image glyph (_heroFallback) */
.xl-gbox.is-noart img { visibility: hidden; }
/* "Keep my character": the look the guest came with (a pre-baked Maple
   character, a photo character, a retired roster friend) leads the
   badges as a pill on a row of its own */
.xl-tile--keep {
    grid-column: 1 / -1; aspect-ratio: auto;
    display: flex; flex-direction: row; align-items: center; justify-content: center; gap: 12px;
    min-height: 60px; padding: 4px 18px 4px 10px; overflow: visible;
    border-radius: var(--radius-pill);
    background: var(--card);
}
.xl-tile--keep.on { background: color-mix(in srgb, var(--blush) 24%, var(--card)); }
.xl-tile--keep .xl-tart {
    margin: 0; height: 50px; width: 50px; flex: none;
    display: grid; place-items: end center; border-radius: 50%;
    background: radial-gradient(circle at 50% 38%, var(--card) 0 40%, color-mix(in srgb, var(--blush) 40%, var(--card-warm)) 100%);
}
.xl-tile--keep .xl-tl { font-size: var(--text-sm); }
/* "Make me from a selfie" (owner, 11 Oct 2026): a full-width pill just above
   the grid, like Keep, but NOT a radio: it sits outside the radiogroup element
   (no xl-tile class, so wireGrid leaves it alone) and opens the photo panel
   (js/photochar.js) with its own handler. Same width and gap as the grid. */
.xl-selfie {
    box-sizing: border-box; width: 100%; max-width: 360px; margin: 0 auto 10px;
    display: flex; align-items: center; justify-content: center; gap: 10px;
    min-height: 52px; padding: 6px 18px;
    font: inherit; font-weight: 600; font-size: var(--text-sm); color: var(--accent-deep);
    background: color-mix(in srgb, var(--blush) 22%, var(--card));
    border: var(--bw) dashed color-mix(in srgb, var(--accent) 55%, var(--line));
    border-radius: var(--radius-pill);
    box-shadow: var(--shadow-sm);
    cursor: pointer;
    -webkit-tap-highlight-color: transparent;
    transition: transform var(--dur-fast), background var(--dur-med);
}
.xl-selfie:active { transform: scale(.97); }
.xl-selfie-i { font-size: var(--px-xl); line-height: 1; }
/* the sheet between "Use this character" and the save (js/photochar.js) */
.pcg-body { display: flex; flex-direction: column; align-items: center; gap: 12px; text-align: center; }
.pcg-still { height: 120px; width: auto; max-width: 100%; object-fit: contain; image-rendering: pixelated; }
.pcg-t { margin: 0; color: var(--ink); font-size: var(--text-base); line-height: 1.4; }
.pcg-spin {
    display: inline-block; width: 18px; height: 18px; margin-right: 8px; vertical-align: -3px;
    border: 3px solid var(--blush); border-top-color: var(--rose-deep); border-radius: 50%;
    animation: pcgSpin .8s linear infinite;
}
@keyframes pcgSpin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) { .pcg-spin { animation: none; } }

.xl-cta { min-height: 56px; margin-top: 4px; }
/* THE MAIN BUTTON STAYS IN REACH (audit, Oct 2026): on a short phone
   (an iPhone SE in Safari shows ~553px) every step's button sat below the
   fold with no hint to scroll. It now rides the bottom edge until its own
   place scrolls into view (#app clips with overflow:clip on this page, so
   sticky works). With the keyboard up it stays in the flow: pinned over a
   short visible area it would cover the caret. */
.xl-cta {
    position: sticky; bottom: calc(8px + env(safe-area-inset-bottom, 0px)); z-index: 5;
    box-shadow: var(--shadow);
}
.xl--kbd .xl-cta { position: static; }

/* ---- E3 selfie ---- */
.xl-bigcard {
    display: flex; flex-direction: column; align-items: center; gap: 6px;
    width: 100%; padding: 22px 18px 20px; cursor: pointer; font: inherit; color: var(--ink);
    background: linear-gradient(color-mix(in srgb, var(--blush) 34%, var(--card)), var(--card));
    border: var(--bw) solid color-mix(in srgb, var(--accent) 35%, var(--line));
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    transition: transform var(--dur-fast);
}
.xl-bigcard:active { transform: scale(var(--tap-scale)); }
/* storage blocked: the file picker is the main card (a label around a hidden input) */
.xl-bigcard--file { position: relative; }
.xl-bigcard--file:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.xl-bigico {
    width: 60px; height: 60px; border-radius: 50%; display: grid; place-items: center;
    color: var(--card); background: var(--rose-deep);
    box-shadow: var(--shadow); margin-bottom: 4px;
}
.xl-bigico svg { width: 28px; height: 28px; }
.xl-bigt { font-family: var(--display); font-weight: 600; font-size: var(--text-xl); line-height: 1.1; }
.xl-bigs { font-size: var(--text-sm); color: var(--ink-soft); }

.xl-link {
    display: block; margin: 10px auto 0; min-height: 44px; padding: 0 12px;
    background: none; border: 0; cursor: pointer; font: inherit;
    font-size: var(--text-sm); color: var(--ink-soft);
    text-decoration: underline; text-underline-offset: 3px; text-align: center;
}
.xl-link--in { display: inline; margin: 0; min-height: 0; padding: 0; color: var(--accent-deep); }
.xl-file { display: flex; align-items: center; justify-content: center; position: relative; }
/* visually hidden but still activatable through its label: iOS Safari has
   refused to open a display:none file input from a label in the past */
.xl-vh { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; clip: rect(0 0 0 0); pointer-events: none; }
.xl-pair { margin-top: 10px; }

.xl-polaroid {
    width: 190px; margin: 0 auto 18px; padding: 10px 10px 32px;
    background: var(--card); border-radius: 4px;
    box-shadow: var(--pop-shadow);
    transform: rotate(-2deg);
}
.xl-polaroid img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; background: var(--paper-2); }
.xl-polaroid--lg { width: min(220px, 62vw); }

/* ---- E4 wish ---- */
.xl-chips { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin-bottom: 12px; }
.xl-chip {
    min-height: 44px; padding: 8px 14px;
    font: inherit; font-size: var(--text-xs); line-height: 1.3; text-align: center; white-space: normal;
    color: var(--ink-soft); cursor: pointer;
    background: var(--card); border: var(--bw) solid var(--line); border-radius: var(--radius-pill);
}
.xl-chip:active { transform: scale(.97); }
.xl-wish.field {
    min-height: 120px; font-size: var(--text-base); text-align: left;
    border-radius: var(--radius); background: var(--card);
}
.xl-count { text-align: right; font-size: var(--text-xs); color: var(--dim); margin: 4px 2px 10px; }

/* ---- E5 sent ---- */
.xl-sent { text-align: center; }
.xl-sent .eyebrow { margin-bottom: 8px; }
/* the Just Dated pair (two mushrooms, hearts above them) between the
   eyebrow and the title; pixel art, so it is never smoothed */
.xl-jd { display: flex; justify-content: center; margin: -6px 0 2px; line-height: 0; }
.xl-jd img { display: block; image-rendering: pixelated; }
.xl-shot { display: flex; justify-content: center; margin: 12px 0 4px; }
.xl-shot .xl-polaroid { width: 132px; padding: 8px 8px 24px; margin-bottom: 6px; }
.xl-quote {
    font-family: var(--display); font-style: italic; font-size: var(--text-lg); line-height: 1.35;
    color: var(--ink); margin: 8px auto 18px; max-width: 32ch; overflow-wrap: anywhere;
}
/* "Save my polaroid": the quiet second button under Enter */
.xl-savepol { min-height: 48px; margin-top: 10px; }
.xl-cards { display: grid; gap: var(--space-sm); margin: 6px 0 14px; }
.xl-card {
    display: flex; align-items: center; justify-content: space-between; gap: 12px;
    width: 100%; min-height: 56px; padding: 12px 16px;
    font: inherit; color: var(--ink); text-align: left;
    background: var(--card);
    border: var(--bw) solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
}
.xl-card--table {
    border-color: color-mix(in srgb, var(--accent) 40%, var(--line));
    background: color-mix(in srgb, var(--blush) 18%, var(--card));
}
.xl-card--go { cursor: pointer; }
.xl-card--go:active { transform: scale(var(--tap-scale)); }
.xl-ck { flex: 0 0 auto; font-size: var(--text-xs); font-weight: 600; color: var(--dim); }
.xl-cv { font-weight: 600; text-align: right; }
.xl-cv b { color: var(--accent-deep); font-weight: 700; }
.xl-card--table .xl-cv { font-family: var(--display); font-size: var(--text-xl); color: var(--accent-deep); }
.xl-card--table .xl-cv--soft { font-family: var(--sans); font-size: var(--text-sm); font-weight: 500; color: var(--ink-soft); }

.xl-toast { font-size: var(--px-sm); }

/* #/home: "Your polaroid did not upload." (Express.paintBanner). Pinned at the
   top, above the nav clearance, dismissible; never on any other page. */
.xl-banner {
    position: fixed; z-index: 70;
    top: calc(var(--space-sm) + env(safe-area-inset-top));
    left: 50%; transform: translateX(-50%);
    width: calc(100% - 2 * var(--space-md)); max-width: var(--content-max);
    display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-xs) var(--space-sm);
    padding: 10px 44px 10px 14px;
    font-size: var(--text-sm); color: var(--ink);
    background: var(--card);
    border: var(--bw) solid color-mix(in srgb, var(--accent) 40%, var(--line));
    border-radius: var(--radius); box-shadow: var(--pop-shadow);
}
.xl-banner .xl-link--in { min-height: 32px; display: inline-flex; align-items: center; }
/* storage blocked: "Retake" is a file picker (a label around a hidden input) */
.xl-banner-file { position: relative; cursor: pointer; }
.xl-banner-file:focus-within { outline: 2px solid var(--accent); outline-offset: 2px; }
.xl-banner-x {
    position: absolute; top: 50%; right: 4px; transform: translateY(-50%);
    width: 40px; height: 40px; border: 0; background: none; cursor: pointer;
    font: inherit; font-size: var(--text-lg); line-height: 1; color: var(--dim);
}

@media (max-width: 370px) {
    .xl-grid { gap: 8px 4px; }
    .xl-selfie { margin-bottom: 8px; }
    .xl-title { font-size: var(--text-xl); }
}
/* narrow AND tall enough for the full stage (a short screen keeps its strip) */
@media (max-width: 370px) and (min-height: 461px) {
    .xl-couple { min-height: 142px; }
}
/* a short phone (461-640px tall) gives the step a little more of the screen */
@media (min-height: 461px) and (max-height: 640px) {
    .xl-couple { min-height: 112px; }
}
@media (prefers-reduced-motion: reduce) {
    .xl-body, .xl-say, .xl-spr, .xl-gbox, .xl-cw--you.is-pop, .xl-couple.is-hop .xl-cw, .xl-plate { animation: none; }
    .xl-tile { transition: none; }
    .xl-cw, .xl-cast { transition: none; }
    .xl .spin { animation: none; }
    .xl-polaroid { transform: none; }
}

/* THE ONE SELFIE (owner, 12 Oct 2026): E4 "This is you in Maple!", the five
   Maple characters made from the selfie as rounded tiles (a radiogroup like the
   badges), the "making" wait, and the small "or choose an avatar here!" link */
.xl-mgrid {
    display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
    gap: 8px; margin: 4px auto 6px; max-width: 360px;
}
.xl-mtile {
    position: relative; display: grid; place-items: end center;
    width: 100%; aspect-ratio: 3 / 4; min-width: 0; padding: 4px 2px; overflow: hidden;
    font: inherit; cursor: pointer;
    background: radial-gradient(circle at 50% 40%, var(--card) 0 40%, color-mix(in srgb, var(--blush) 26%, var(--card-warm)) 100%);
    border: var(--bw) solid var(--line); border-radius: var(--radius);
    box-shadow: var(--shadow-sm);
    -webkit-tap-highlight-color: transparent;
    transition: border-color var(--dur-med), transform var(--dur-fast), box-shadow var(--dur-med);
}
.xl-mtile:active { transform: scale(.94); }
.xl-mtile.on {
    border-color: var(--accent);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent), var(--shadow-sm);
}
.xl-mtile:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.xl-mtile img { display: block; max-width: 100%; max-height: 100%; width: auto; height: auto;
    object-fit: contain; image-rendering: pixelated; }
.xl-pcimg { display: block; width: auto; max-width: 100%; image-rendering: pixelated; }
.xl-making { display: flex; justify-content: center; align-items: center; gap: 8px; min-height: 64px;
    color: var(--ink-soft); font-size: var(--text-sm); }
.xl-mk { font-size: var(--text-xs); color: var(--ink-soft); text-align: center; min-height: 1.2em; margin: 4px 0 0; }
.xl-avatar { font-size: var(--text-xs); color: var(--dim); }
.xl-note { color: var(--accent-deep); }
@media (prefers-reduced-motion: reduce) { .xl-mtile { transition: none; } .xl-mtile:active { transform: none; } }

/* ---- E2 review, a gallery photo: He / She and a skin tone for the Maple twin (owner, 26 Oct 2026) ---- */
.xl-twin { margin: 4px 0 12px; }
.xl-twin-q { margin: 0 0 6px; }
.xl-twin .xl-chips { margin-bottom: 8px; }
.xl-twin .xl-chip { min-width: 84px; font-size: var(--text-sm); }
.xl-chip.on { color: var(--rose-deep); border-color: var(--rose-deep); background: var(--card); font-weight: 700; }
.xl-skins { display: flex; justify-content: center; gap: 10px; }
.xl-skin { -webkit-appearance: none; appearance: none; width: 30px; height: 30px; padding: 0; border-radius: 50%;
    border: 2px solid var(--card); box-shadow: 0 0 0 1px var(--line); cursor: pointer; }
.xl-skin.on { box-shadow: 0 0 0 3px var(--rose-deep); }
.xl-refile { position: relative; }
