/* Smart Keys Drop — marketing mini-game
   Self-contained, mobile-first, embeddable in an iOS WKWebView. */

:root {
    --bg: #0b1020;
    --bg-2: #121a33;
    --panel: rgba(255, 255, 255, 0.05);
    --panel-border: rgba(255, 255, 255, 0.10);
    --text: #ffffff;
    --muted: rgba(255, 255, 255, 0.55);
    --accent: #037AFF;          /* Smart Keys brand blue */
    --accent-soft: rgba(3, 122, 255, 0.18);
    --good: #2fd27a;
    --bad: #ff5c5c;
    --key-w: 34px;              /* recomputed in JS for fit */
    --key-h: 41px;              /* a bit taller than wide (iOS look); recomputed in JS */
    --safe-top: env(safe-area-inset-top, 0px);
    --safe-bottom: env(safe-area-inset-bottom, 0px);
}

* {
    box-sizing: border-box;
    -webkit-tap-highlight-color: transparent;
    user-select: none;
    -webkit-user-select: none;
    margin: 0;
    padding: 0;
}

html, body {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
    touch-action: none;
}

body {
    background:
        radial-gradient(120% 80% at 50% -10%, var(--bg-2) 0%, var(--bg) 55%);
    color: var(--text);
    font-family: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;            /* center the phone-shaped app on desktop */
}

a { color: var(--accent); text-decoration: none; }

.app {
    position: relative;
    width: 100%;
    max-width: 560px;
    height: 100%;
    max-height: 950px;              /* keep a phone shape on tall/desktop windows */
    display: flex;
    flex-direction: column;
}
/* On mobile, drop the bottom gap so the playfield reaches the edge (keep the safe-area
   inset for the home indicator). */
@media (pointer: coarse) {
    .app { padding-bottom: var(--safe-bottom); }
}
/* Quick jolt on a bomb blast. */
.app.shake { animation: screen-shake .45s cubic-bezier(.36, .07, .19, .97) both; }
@keyframes screen-shake {
    10%, 90% { transform: translate3d(-2px, 1px, 0); }
    20%, 80% { transform: translate3d(4px, -2px, 0); }
    30%, 50%, 70% { transform: translate3d(-6px, 3px, 0); }
    40%, 60% { transform: translate3d(6px, -3px, 0); }
}
/* ---------- HUD ---------- */
/* Overlaid on the top of the board (not a stacked header band), so the well reaches
   nearly full height. Floats in the corners over the empty top of the well; only the
   buttons capture taps, so a drag can still begin anywhere across the board's top. */
.hud {
    position: absolute;
    top: 0; left: 0; right: 0;
    z-index: 12;                     /* above falling tiles, below countdown/overlays */
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 12px 0;
    pointer-events: none;            /* let drags fall through to the board... */
}
.hud .icon-btn { pointer-events: auto; }   /* ...but keep the mute button tappable */

.brand { display: flex; flex-direction: column; align-items: center; gap: 4px; }
/* Header wordmark: the staggered QWERTYS keyboard logo, scaled way down. The #id wins
   the --ik over .kbd-logo (which is declared later). Lights blue as letters are placed. */
#brand-keys { --ik: 18px; --ik-gap: 2px; }
#brand-keys .kk {
    font-size: calc(var(--ik) * 0.62);
    border-radius: 3px;
    border-bottom-width: 2px;
    transition: background .25s, color .25s, border-bottom-color .25s;
}
#brand-keys.brand-win { animation: brand-win .7s ease-out; }
@keyframes brand-win {
    0%, 100% { transform: scale(1); filter: none; }
    35%      { transform: scale(1.12); filter: drop-shadow(0 0 10px rgba(67,192,255,0.9)); }
}
.brand .brand-text { display: flex; flex-direction: column; line-height: 1.1; }
.brand .brand-name { font-weight: 600; font-size: 1.05rem; letter-spacing: 0.2px; }
.brand .brand-sub {
    font-size: 0.75rem; color: var(--muted); letter-spacing: 0.4px;
    cursor: pointer; width: fit-content;
    text-decoration: underline; text-decoration-color: rgba(255,255,255,0.22); text-underline-offset: 2px;
}
.brand a.brand-sub:active { color: var(--text); }

.hud-right { display: flex; align-items: flex-start; gap: 10px; }
/* Score column: the combo streak stacks on top of the number (no SCORE label). */
.stat { display: flex; flex-direction: column; align-items: flex-end; gap: 4px; line-height: 1; }
.stat #score { font-size: 1.4rem; font-weight: 700; font-variant-numeric: tabular-nums; }

/* combo / streak chip — shows from a streak of 2, "hot" (flame) past COMBO_FIRE_AT */
.combo {
    display: flex; align-items: center; gap: 3px;
    padding: 4px 9px; border-radius: 999px;
    background: var(--accent-soft);
    color: #7fc0ff;
    font-weight: 700; font-size: 0.9rem; line-height: 1;
}
.combo.hidden { display: none; }
.combo .combo-fire { display: none; font-size: 0.85rem; }
.combo b { font-variant-numeric: tabular-nums; }
.combo b::after { content: '×'; opacity: 0.6; font-weight: 600; margin-left: 1px; }
.combo.hot { background: rgba(255, 120, 40, 0.2); color: #ffb061; box-shadow: 0 0 12px rgba(255, 120, 40, 0.4); }
.combo.hot .combo-fire { display: inline; }
.combo.bump { animation: combo-bump .25s ease-out; }
@keyframes combo-bump { 0% { transform: scale(1); } 45% { transform: scale(1.28); } 100% { transform: scale(1); } }

.lives { display: flex; gap: 3px; font-size: 0.95rem; }
.lives .life { transition: transform .2s, opacity .2s; }
.lives .life.lost { opacity: 0.25; transform: scale(0.8); filter: grayscale(1); }

.icon-btn {
    background: var(--panel);
    border: 1px solid var(--panel-border);
    color: var(--text);
    width: 34px; height: 34px;
    border-radius: 9px;
    font-size: 0.95rem;
    cursor: pointer;
}

/* ---------- level label ---------- */
/* Sits just under the QWERTYS wordmark in the overlaid HUD (the progress bar + n/26
   counter are gone — the keyboard filling in is the progress indicator). */
.level-badge {
    font-size: 0.74rem; font-weight: 600; letter-spacing: 0.3px;
    color: rgba(255, 255, 255, 0.72);
}

/* ---------- Playfield ---------- */
.playfield {
    position: relative;
    flex: 1 1 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
}

/* Next-piece preview: a mini layout mirroring the upcoming piece, centered up top. */
.next-pill {
    position: absolute; top: 6px; left: 50%; transform: translateX(-50%);
    z-index: 3;                       /* behind the falling tile */
    transition: opacity .35s ease;    /* fades in once the current piece drops clear */
}
.next-shape { position: relative; }
.next-pill b {
    position: absolute;
    display: grid; place-items: center;
    border-radius: 7px;
    background: rgba(255,255,255,0.07);
    border: 1px solid rgba(255,255,255,0.1);
    color: #9fc4ee; font-weight: 600; font-style: normal;
}
/* "—" fallback + bomb/flag emoji previews */
.next-pill > b:only-child, .next-pill b.pill-emoji {
    position: static; width: calc(var(--key-w) * 0.7); height: calc(var(--key-w) * 0.7);
    font-size: calc(var(--key-w) * 0.45); background: transparent; border: none; color: var(--muted);
}

.drop-zone {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    border-radius: 0;                /* full-bleed playfield, edge to edge */
    background:
        linear-gradient(180deg, rgba(255,255,255,0.03), rgba(255,255,255,0.0)),
        repeating-linear-gradient(0deg, transparent 0 38px, rgba(255,255,255,0.03) 38px 39px);
    border: 1px solid var(--panel-border);
}


@media (pointer: coarse) {
    .drop-zone {
        border: none;
    }
}

/* The keyboard tray fills the play area; cells are absolutely positioned by JS. */
.keyboard { position: absolute; inset: 0; }

.guide-line {
    position: absolute; top: 0; bottom: 0; width: 2px;
    background: linear-gradient(180deg, transparent, var(--accent-soft) 30%, var(--accent));
    transform: translateX(-50%);
    opacity: 0;
    /* Boost ramps in gradually: width, glow (and the fire overlay below) ease over ~.5s. */
    transition: opacity .2s, width .5s ease, box-shadow .55s ease;
    pointer-events: none;
    z-index: 0;                       /* behind the keyboard keys (set below) */
}
/* Fire-coloured overlay cross-faded in on boost (gradient backgrounds can't transition,
   so we fade this layer instead of swapping the base gradient). */
.guide-line::after {
    content: '';
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(255,210,58,0) 0%, rgba(255,160,40,0.5) 28%, #ff8a1e 68%, #ff3b1e 100%);
    opacity: 0;
    transition: opacity .55s ease;
}
.guide-line.show { opacity: 0.5; }
/* While the player speeds the key down, the guide flares: wider, fire-coloured, and
   glowing — easing in over ~.5s so it's a gradual ignite, not a snap. */
.guide-line.boost {
    width: 7px;
    opacity: 0.95;
    box-shadow: 0 0 14px rgba(255,120,30,0.82);
}
.guide-line.boost::after { opacity: 1; }

/* ---------- First-key tutorial hint ---------- */
.tutorial {
    position: absolute; inset: 0; z-index: 8;
    display: grid; place-items: center;
    pointer-events: none;             /* taps pass through to dismiss it */
    text-align: center;
}
.tutorial.hidden { display: none; }
.tut-block.hidden { display: none; }
.tut-block { display: flex; flex-direction: column; align-items: center; }
.tutorial p { color: var(--text); font-weight: 600; font-size: 0.95rem; opacity: 0.9; margin-top: 14px; }

/* The tutorial shows a touch visual (finger gesture over a key) on touch devices
   and a keys visual (arrows inside a key) on desktop — toggled from JS. */
.tut-visual { display: none; }
.tutorial.is-touch .tut-visual.touch { display: flex; justify-content: center; }
.tutorial.is-keys  .tut-visual.keys  { display: flex; justify-content: center; }
.tut-finger {
    display: inline-block;
    font-size: 3.4rem; line-height: 1;
    filter: drop-shadow(0 3px 7px rgba(0, 0, 0, 0.55));
    pointer-events: none;
}
.tut-finger.swipe-x { animation: tut-swipe-x 1.5s ease-in-out infinite; }
.tut-finger.swipe-y { animation: tut-swipe-y .9s ease-in-out infinite alternate; }
@keyframes tut-swipe-x {
    0%, 100% { transform: translateX(-26px) rotate(-10deg); }
    50%      { transform: translateX(26px) rotate(10deg); }
}
@keyframes tut-swipe-y {
    from { transform: translateY(-10px); }
    to   { transform: translateY(26px); }
}
/* A mock key with the arrows inside it, gently pulsing; the arrows animate in
   the gesture's direction (← → for move, ⌄ for speed-down). */
.tut-key {
    position: relative;
    width: 78px; height: 78px;
    border-radius: 18px;
    display: flex; align-items: center; justify-content: center; gap: 2px;
    background: linear-gradient(160deg, #2aa9ff, var(--accent));
    box-shadow: 0 10px 26px rgba(3,122,255,0.5), inset 0 1px 0 rgba(255,255,255,0.4);
    color: #fff;
    animation: tut-key-pulse 1.3s ease-in-out infinite;
}
@keyframes tut-key-pulse {
    0%, 100% { transform: scale(1);    box-shadow: 0 10px 26px rgba(3,122,255,0.45), inset 0 1px 0 rgba(255,255,255,0.4); }
    50%      { transform: scale(1.07); box-shadow: 0 14px 34px rgba(3,122,255,0.75), inset 0 1px 0 rgba(255,255,255,0.4); }
}
.tut-arrow { font-size: 2.4rem; font-weight: 800; line-height: 1; }
.tut-arrow.left  { animation: tut-arr-left 1.3s ease-in-out infinite; }
.tut-arrow.right { animation: tut-arr-right 1.3s ease-in-out infinite; }
.tut-arrow.down  { font-size: 3rem; animation: tut-arr-down .9s ease-in-out infinite alternate; }
@keyframes tut-arr-left  { 0%,100% { transform: translateX(2px);  opacity: .55; } 50% { transform: translateX(-5px); opacity: 1; } }
@keyframes tut-arr-right { 0%,100% { transform: translateX(-2px); opacity: .55; } 50% { transform: translateX(5px);  opacity: 1; } }
@keyframes tut-arr-down  { from { transform: translateY(-5px); opacity: .55; } to { transform: translateY(6px); opacity: 1; } }

/* falling tile */
.tile {
    position: absolute;
    top: 0; left: 0;
    width: var(--key-w); height: var(--key-h);
    display: grid; place-items: center;
    font-weight: 700; font-size: calc(var(--key-w) * 0.54);
    color: #fff; text-shadow: 0 1px 1px rgba(0,40,90,0.35);
    background: linear-gradient(180deg, #3db0ff, #037AFF);
    border-radius: calc(var(--key-w) * 0.2);   /* ~7px at default size; scales with resolution */
    border-bottom: 3px solid #0257ad;   /* keycap base edge */
    will-change: transform;
    transform: translate(-50%, 0);  /* x is center */
    z-index: 4;
    pointer-events: none;   /* drag is on the drop-zone, slot-taps on the keyboard;
                               tiles must let clicks fall through to the slot beneath */
}
/* a key that settled in the wrong slot — gray junk to be bombed away */
.tile.obstacle {
    background: linear-gradient(180deg, #616a78, #3b424d);
    border-bottom-color: #2b313a;
    color: rgba(255,255,255,0.55); text-shadow: none;
    z-index: 3;
}
/* translucent landing preview of the falling piece */
.tile.ghost {
    background: transparent;
    border: 2px solid rgba(255,255,255,0.3);
    box-shadow: none;
    color: rgba(255,255,255,0.22);
    z-index: 2;
}
/* falling bomb / flag special pieces */
.tile.bomb-tile, .tile.flag-tile {
    background: rgba(8,12,24,0.7);
    border: 1px solid rgba(255,255,255,0.16);
    box-shadow: 0 4px 14px rgba(0,0,0,0.45);
    font-size: calc(var(--key-w) * 0.62);
}
.tile.bomb-tile { box-shadow: 0 0 16px rgba(255,120,40,0.5); }
.tile.boom { animation: tile-boom .3s ease-out forwards; }
/* The key a falling bomb is about to destroy — red pulse so you can see the target.
   !important so it wins over a filled key's pop-in animation (declared later). */
.tile.doomed, .key.doomed {
    z-index: 6;
    animation: doomed-pulse .55s ease-in-out infinite !important;
}
@keyframes doomed-pulse {
    0%, 100% { box-shadow: 0 0 0 2px rgba(255,80,40,0.8), 0 0 10px rgba(255,90,40,0.55); }
    50%      { box-shadow: 0 0 0 3px rgba(255,130,50,1), 0 0 20px rgba(255,90,40,0.95); }
}
.tile.miss { animation: tile-shake .3s; background: linear-gradient(160deg, #ff7a7a, var(--bad)); box-shadow: 0 6px 16px rgba(255,92,92,0.5); }
@keyframes tile-shake {
    0%,100% { transform: translate(-50%, 0) rotate(0); }
    25% { transform: translate(calc(-50% - 6px), 0) rotate(-6deg); }
    75% { transform: translate(calc(-50% + 6px), 0) rotate(6deg); }
}
/* caught in a bomb blast */
.tile.tile-boom {
    animation: tile-boom .3s ease-out forwards;
    background: linear-gradient(160deg, #ffb24a, var(--bad));
    box-shadow: 0 0 22px rgba(255, 90, 30, 0.9);
}
@keyframes tile-boom {
    0%   { transform: translate(-50%, 0) scale(1) rotate(0);        opacity: 1; }
    100% { transform: translate(-50%, -4px) scale(1.7) rotate(8deg); opacity: 0; }
}
/* while the player speeds the key down (hold / down-arrow / tap-a-slot): orange
   glow + a pure-CSS flame rising above the key. The glow is a static box-shadow
   (never an animation) so it can't fight the tile's own transform animations
   (miss/boom); the two gradient plumes on ::before/::after do the flickering. */
.tile.on-fire {
    box-shadow: 0 0 18px rgba(255, 110, 30, 0.95), 0 6px 16px rgba(255, 90, 30, 0.55), inset 0 1px 0 rgba(255,255,255,0.4);
    animation: fire-glow-in .55s ease-out;   /* glow ramps in (rather than snapping on) */
}
@keyframes fire-glow-in {
    from { box-shadow: 0 0 0 rgba(255, 110, 30, 0), 0 0 0 rgba(255, 90, 30, 0), inset 0 0 0 rgba(255,255,255,0); }
}
.tile.on-fire::before,
.tile.on-fire::after {
    content: '';
    position: absolute;
    left: 50%; bottom: 100%;          /* sit just above the key */
    transform: translateX(-50%);
    transform-origin: 50% 100%;
    pointer-events: none;
    border-radius: 50% 50% 48% 48% / 65% 65% 35% 35%;
    filter: blur(2px);
}
/* outer (orange→red) plume — fire-ignite fades it in (opacity) over .5s while
   flame-flicker (transform only) keeps it alive, so the two don't fight. */
.tile.on-fire::before {
    width: 78%; height: 105%;
    background: radial-gradient(ellipse at 50% 100%,
        #ffd23a 0%, #ff8a1e 32%, #ff3b1e 62%, rgba(255,59,30,0) 80%);
    animation: fire-ignite .5s ease-out, flame-flicker .42s ease-in-out infinite alternate;
}
/* inner (yellow) core, flickers faster */
.tile.on-fire::after {
    width: 46%; height: 72%;
    background: radial-gradient(ellipse at 50% 100%,
        #fff3b0 0%, #ffd23a 42%, #ff8a1e 78%, rgba(255,138,30,0) 92%);
    filter: blur(1px);
    animation: fire-ignite .5s ease-out, flame-flicker .29s ease-in-out infinite alternate;
}
@keyframes fire-ignite { from { opacity: 0; } }   /* flame grows in gradually */
@keyframes flame-flicker {
    0%   { transform: translateX(-50%) scaleY(0.88) scaleX(1.02); }
    100% { transform: translateX(-50%) scaleY(1.16) scaleX(0.9); }
}

/* floating score popups + shards */
.float {
    position: absolute; z-index: 6; pointer-events: none;
    font-weight: 800; font-size: 1rem;
    transform: translate(-50%, -30px);
    animation: float-up .8s ease-out forwards;
}
.float.good { color: var(--good); }
.float.bad { color: var(--bad); }
@keyframes float-up {
    from { opacity: 1; }
    to { opacity: 0; transform: translate(-50%, -60px); }
}

/* ---------- Collectible heart (last-life rescue) ---------- */
.heart-collectible {
    position: absolute;
    z-index: 3;                       /* sits behind the falling tile */
    transform: translate(-50%, -50%);
    font-size: calc(var(--key-w) * 0.92);
    line-height: 1;
    pointer-events: none;             /* it's a fly-through target, not a button */
    filter: drop-shadow(0 0 10px rgba(255, 92, 92, 0.85));
    animation: heart-bob 1.1s ease-in-out infinite;
}
@keyframes heart-bob {
    0%, 100% { transform: translate(-50%, -50%) scale(1); }
    50%      { transform: translate(-50%, -50%) scale(1.2); }
}

/* ---------- Bomb hazard ---------- */
.bomb-collectible {
    position: absolute;
    z-index: 3;                       /* sits behind the falling tile */
    transform: translate(-50%, -50%);
    font-size: calc(var(--key-w) * 0.9);
    line-height: 1;
    pointer-events: none;             /* a fly-through hazard, not a button */
    filter: drop-shadow(0 0 9px rgba(255, 140, 40, 0.7));
    animation: heart-bob 1.1s ease-in-out infinite;
}
.bomb-collectible.boom {
    animation: bomb-boom .26s ease-out forwards;
    filter: drop-shadow(0 0 18px rgba(255, 90, 30, 0.95));
}
@keyframes bomb-boom {
    0%   { transform: translate(-50%, -50%) scale(1);   opacity: 1; }
    100% { transform: translate(-50%, -50%) scale(1.9); opacity: 0; }
}

/* ---------- AZERTY status badge (bottom-left, with countdown ring) ---------- */
.azerty-badge {
    position: absolute;
    left: 8px; bottom: 8px;          /* bottom-left, inside the keyboard panel */
    z-index: 10;
    width: 40px; height: 40px;
}
.azerty-badge.hidden { display: none; }
/* dark disc behind the flag for legibility over the playfield */
.azerty-badge::before {
    content: '';
    position: absolute; inset: 4px;
    border-radius: 50%;
    background: rgba(8, 12, 24, 0.72);
}
/* the depleting ring, driven by --ab-progress (1 → 0) set from JS each frame */
.ab-ring {
    position: absolute; inset: 0;
    border-radius: 50%;
    background: conic-gradient(var(--accent) calc(var(--ab-progress, 1) * 360deg), rgba(255,255,255,0.16) 0deg);
    -webkit-mask: radial-gradient(circle, transparent 58%, #000 59%);
            mask: radial-gradient(circle, transparent 58%, #000 59%);
}
.ab-flag {
    position: absolute; inset: 0;
    display: grid; place-items: center;
    font-size: 18px;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.5));
}

/* ---------- Timed power-up badges (bottom-right stack: speed, reveal) ---------- */
.fx-stack {
    position: absolute;
    right: 8px; bottom: 8px;
    z-index: 10;
    display: flex; flex-direction: column-reverse; gap: 6px; align-items: center;
}
.fx-badge { position: relative; width: 40px; height: 40px; }
.fx-badge.hidden { display: none; }
.fx-badge::before {
    content: '';
    position: absolute; inset: 4px;
    border-radius: 50%;
    background: rgba(8, 12, 24, 0.72);
}
/* ring driven by --fx-progress (1 → 0); colour (--fx-color) set per badge in JS */
.fx-ring {
    position: absolute; inset: 0;
    border-radius: 50%;
    background: conic-gradient(var(--fx-color, var(--accent)) calc(var(--fx-progress, 1) * 360deg), rgba(255,255,255,0.16) 0deg);
    -webkit-mask: radial-gradient(circle, transparent 58%, #000 59%);
            mask: radial-gradient(circle, transparent 58%, #000 59%);
}
.fx-emoji {
    position: absolute; inset: 0;
    display: grid; place-items: center;
    font-size: 18px;
    filter: drop-shadow(0 1px 3px rgba(0, 0, 0, 0.5));
}

/* ---------- Speed emoji (slow / fast) ---------- */
.speed-collectible {
    position: absolute;
    z-index: 3;                       /* sits behind the falling tile */
    transform: translate(-50%, -50%);
    font-size: calc(var(--key-w) * 0.92);
    line-height: 1;
    pointer-events: none;             /* a fly-through collectible, not a button */
    animation: heart-bob 1.1s ease-in-out infinite;
}
.speed-collectible.slow { filter: drop-shadow(0 0 9px rgba(80, 220, 140, 0.85)); }
.speed-collectible.fast { filter: drop-shadow(0 0 9px rgba(120, 180, 255, 0.9)); }

/* ---------- Reveal emoji (lights up the keyboard) ---------- */
.reveal-collectible {
    position: absolute;
    z-index: 3;                       /* sits behind the falling tile */
    transform: translate(-50%, -50%);
    font-size: calc(var(--key-w) * 0.92);
    line-height: 1;
    pointer-events: none;             /* a fly-through collectible, not a button */
    filter: drop-shadow(0 0 10px rgba(255, 210, 74, 0.9));
    animation: heart-bob 1.1s ease-in-out infinite;
}

/* ---------- French flag (AZERTY switch) ---------- */
.flag-collectible {
    position: absolute;
    z-index: 3;                       /* sits behind the falling tile */
    transform: translate(-50%, -50%);
    font-size: calc(var(--key-w) * 0.92);
    line-height: 1;
    pointer-events: none;             /* a fly-through item, not a button */
    filter: drop-shadow(0 0 9px rgba(120, 170, 255, 0.7));
    animation: heart-bob 1.1s ease-in-out infinite;
}
/* An uncollected collectible expired — fade + shrink it out instead of vanishing. */
.speed-collectible.fade-out, .reveal-collectible.fade-out, .flag-collectible.fade-out {
    animation: none;
    opacity: 0;
    transform: translate(-50%, -50%) scale(0.6);
    transition: opacity .36s ease, transform .36s ease;
}

/* ---------- Keyboard tray (absolute cells, placed by JS) ---------- */
.keyboard { position: absolute; inset: 0; --reveal: 0; }

.key {
    position: absolute;          /* left/top set by JS from the grid */
    z-index: 1;                  /* above the guide lines, below the falling tile/ghost */
    width: var(--key-w); height: var(--key-h);
    display: grid; place-items: center;
    font-weight: 700; font-size: calc(var(--key-w) * 0.52);
    border-radius: calc(var(--key-w) * 0.2);   /* ~7px at default size; scales with resolution */
    background: rgba(255,255,255,0.06);
    border-bottom: 3px solid rgba(0,0,0,0.3);   /* keycap base edge */
    /* Slot labels stay hidden until the falling piece nears the keyboard (--reveal). */
    color: rgba(255,255,255, calc(0.4 * var(--reveal, 0)));
    transition: background .2s, color .2s;
}
.key:active { transform: scale(0.92); }
/* Ñ/Ç on Spanish/Portuguese: a yellow BONUS key — never a target; tap it as
   often as you like for points (a tempting distraction). */
.key.deco {
    color: #4a3300; text-shadow: 0 1px 0 rgba(255,255,255,0.3);
    background: linear-gradient(180deg, #ffd860, #ffb12e);
    border-bottom: 3px solid #d98a1e;   /* keycap base edge */
    cursor: pointer;
    animation: deco-glow 1.5s ease-in-out infinite;
}
@keyframes deco-glow {   /* a single soft glow so the bonus key invites taps */
    0%, 100% { box-shadow: 0 0 6px rgba(255, 200, 60, 0.45); }
    50%      { box-shadow: 0 0 16px rgba(255, 205, 70, 0.9); }
}
.key.deco:active { transform: scale(0.9); }
.key.deco-pop { animation: deco-pop .22s ease-out; }
@keyframes deco-pop {
    0% { transform: scale(1); } 45% { transform: scale(1.28); } 100% { transform: scale(1); }
}
/* Home slot of the current falling piece — its glow + label fade in with
   --reveal (only as the piece nears the keyboard), not before. */
.key.target { color: rgba(255,255,255, calc(0.85 * var(--reveal, 0))); }
.key.target::after {
    content: '';
    position: absolute; inset: -1px;
    border-radius: 10px;
    box-shadow: 0 0 0 1px var(--accent), 0 0 18px var(--accent-soft);
    opacity: var(--reveal, 0);
    pointer-events: none;
    animation: target-pulse 1.1s ease-in-out infinite;
}
@keyframes target-pulse {
    0%,100% { box-shadow: 0 0 0 1px var(--accent), 0 0 10px var(--accent-soft); }
    50% { box-shadow: 0 0 0 1px var(--accent), 0 0 22px var(--accent); }
}
.key.filled {
    color: #fff; text-shadow: 0 1px 1px rgba(0,40,90,0.35);
    background: linear-gradient(180deg, #3db0ff, #037AFF);
    border-bottom: 3px solid #0257ad;   /* keycap base edge */
    animation: pop-in .28s ease-out;
}
@keyframes pop-in {
    0% { transform: scale(0.5); }
    60% { transform: scale(1.18); }
    100% { transform: scale(1); }
}
/* Tetris-style full-row clear: a gold flash sweeping across the row (staggered
   per key via --rc-delay), then back to the filled blue. */
.key.row-clear {
    z-index: 2;
    animation: row-clear-flash .9s ease-out;
    animation-delay: var(--rc-delay, 0ms);
}
@keyframes row-clear-flash {
    0%   { transform: scale(1); }
    35%  {
        transform: scale(1.24) translateY(-5px);
        background: linear-gradient(160deg, #fff0a8, #ffba2e);
        color: #3a2a00;
        box-shadow: 0 0 26px rgba(255, 196, 46, 0.95), inset 0 1px 0 rgba(255,255,255,0.6);
    }
    100% { transform: scale(1); }
}

/* Level-start teaser: a transient blue keycap that lifts off and fades, so the
   not-yet-placed letters "fly up" out of the keyboard before the countdown. */
.key.key-fly {
    z-index: 5;
    pointer-events: none;
    animation: key-fly-up .5s ease-in forwards;
}
@keyframes key-fly-up {
    0%   { opacity: 1; transform: translateY(0) scale(1); }
    100% { opacity: 0; transform: translateY(calc(var(--key-h, 41px) * -1.15)) scale(0.84); }
}
/* ---------- Level-up banner (non-blocking) ---------- */
.level-banner {
    position: absolute;
    top: 22%; left: 50%;             /* upper area, clear of the falling key's path */
    transform: translate(-50%, -50%) scale(0.82);
    z-index: 40;
    text-align: center;
    padding: 18px 28px;
    border-radius: 18px;
    background: rgba(8, 12, 24, 0.8);
    border: 1px solid var(--panel-border);
    backdrop-filter: blur(10px);
    -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 12px 34px rgba(3, 122, 255, 0.4);
    pointer-events: none;
    opacity: 0;
    transition: opacity .25s ease, transform .25s ease;
}
.level-banner.show { opacity: 1; transform: translate(-50%, -50%) scale(1); }
.level-banner .lb-emoji { font-size: 2rem; display: block; margin-bottom: 6px; }
.level-banner .lb-title { font-size: 1.3rem; font-weight: 700; }
.level-banner .lb-sub { color: var(--muted); font-size: 0.86rem; margin-top: 4px; }

/* 3-2-1 countdown over the visible board (no backdrop, so the player can read the
   layout). Each tick pops in. */
.countdown {
    position: absolute;
    top: 40%; left: 50%;
    transform: translate(-50%, -50%);
    z-index: 40;
    pointer-events: none;
    font-weight: 800; font-size: 5.5rem; line-height: 1;
    color: #fff;
    text-shadow: 0 4px 24px rgba(3, 122, 255, 0.7), 0 2px 6px rgba(0, 0, 0, 0.5);
}
.countdown.hidden { display: none; }
.countdown.go { color: #43c0ff; font-size: 4rem; }
.countdown.tick { animation: count-pop .5s cubic-bezier(.2, .9, .3, 1); }
@keyframes count-pop {
    0%   { opacity: 0; transform: translate(-50%, -50%) scale(1.5); }
    30%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    80%  { opacity: 1; transform: translate(-50%, -50%) scale(1); }
    100% { opacity: 0.15; transform: translate(-50%, -50%) scale(0.85); }
}
/* ---------- Overlays ---------- */
/* ---------- Intro animation ---------- */
.intro {
    position: absolute; inset: 0; z-index: 60;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 22px; cursor: pointer;
    background: radial-gradient(120% 80% at 50% 38%, var(--bg-2), var(--bg) 72%);
    transition: opacity .48s ease;
}
.intro.hidden { display: none; }
.intro.fade { opacity: 0; }

/* Keyboard wordmark (Q W E R / T Y S = "QWERTYS"), shared by the intro and the
   welcome screen. Grey keys; the Q/W/T that drop in during the intro stay blue. */
.kbd-logo {
    position: relative;
    --ik: 56px; --ik-gap: 8px; --ik-step: calc(var(--ik) + var(--ik-gap));
    width: calc(3 * var(--ik-step) + var(--ik));     /* widest row = 4 keys */
    height: calc(var(--ik-step) + var(--ik) * 1.18);
}
.kbd-logo .kk {
    position: absolute;
    left: calc(var(--x) * var(--ik-step));
    top: calc(var(--y) * var(--ik-step));
    width: var(--ik); height: calc(var(--ik) * 1.18);
    display: grid; place-items: center;
    font-weight: 800; font-size: calc(var(--ik) * 0.5);
    border-radius: calc(var(--ik) * 0.18);
    color: rgba(255,255,255,0.5);
    background: rgba(255,255,255,0.06);
    border-bottom: 3px solid rgba(0,0,0,0.3);
}
.kbd-logo .kk.lit {
    color: #fff;
    background: linear-gradient(180deg, #3db0ff, #037AFF);
    border-bottom-color: #0257ad;
    text-shadow: 0 1px 1px rgba(0,40,90,0.35);
}
/* Intro animation: keys start hidden, fade in, then Q/W/T drop in slowly. */
.intro .kk { opacity: 0; transform: translateY(8px) scale(0.92); }
.intro .kk.in { animation: ik-in .42s ease-out forwards; }
@keyframes ik-in { to { opacity: 1; transform: none; } }
/* Like positioning a real piece — NO opacity fade (the keys arrive from off-screen,
   fully opaque): drop in from the top at screen centre, snap right, slide left to align
   over the slots, then drop in with gravity (accelerating, no ease-out). The +64px is
   the QWT group's offset from the centred logo's centre, so the start sits screen-centre.
   Per-segment timing functions. */
.intro .kk.drop { opacity: 1; animation: ik-drop 1.7s linear forwards; }
@keyframes ik-drop {
    0%   { transform: translate(64px, -500px);  animation-timing-function: cubic-bezier(.3, .5, .5, 1); }   /* off-screen top, screen-centre x */
    28%  { transform: translate(64px, -160px);  animation-timing-function: cubic-bezier(.2, .8, .3, 1); }   /* dropped into view, hovering at centre */
    44%  { transform: translate(128px, -160px); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }   /* snap right */
    72%  { transform: translate(0, -160px);     animation-timing-function: cubic-bezier(.42, 0, 1, 1); }    /* slide left, align over the slot */
    100% { transform: translate(0, 0); }   /* drop in (gravity, no ease-out) */
}
.intro-sub {
    font-size: 1rem; color: var(--muted); letter-spacing: 1.4px;
    opacity: 0; transform: translateY(8px);
}
.intro-sub.in { animation: ik-in .5s ease-out forwards; }
/* The welcome screen reuses the wordmark, a touch smaller, as its title. */
.start-logo { margin: 4px auto 14px; --ik: 48px; }

/* ---------- QWERTYS-complete celebration ---------- */
/* When the player spells QWERTYS, the wordmark blooms big and centered over the
   board, its letters flip blue→gold one at a time (like a row clear), and the bonus
   points sit below. (Declared after .kbd-logo .kk.lit so .gold wins the cascade.) */
.brand-celebrate {
    position: absolute; inset: 0; z-index: 46;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 16px;
    pointer-events: none;
    opacity: 0;
    transition: opacity .3s ease;
}
.brand-celebrate.hidden { display: none; }
.brand-celebrate.show { opacity: 1; }
.brand-celebrate .bc-logo { --ik: 52px; filter: drop-shadow(0 8px 26px rgba(3, 122, 255, 0.5)); }
.brand-celebrate .bc-points {
    font-size: 2.4rem; font-weight: 800; color: #ffd23a;
    text-shadow: 0 4px 18px rgba(255, 196, 46, 0.7), 0 2px 6px rgba(0, 0, 0, 0.5);
}
/* resting gold once a letter has flipped (stays yellow until the overlay fades) */
.brand-celebrate .kk.gold {
    color: #3a2a00; text-shadow: 0 1px 0 rgba(255, 255, 255, 0.3);
    background: linear-gradient(160deg, #ffd23a, #ffb12e);
    border-bottom-color: #d98a1e;
}
.brand-celebrate .kk.flip { animation: bc-flip .55s ease-out; }
@keyframes bc-flip {
    0%   { transform: scale(0.92); }
    55%  { transform: scale(1.26) translateY(-6px); box-shadow: 0 0 28px rgba(255, 196, 46, 0.95); }
    100% { transform: scale(1); }
}
.overlay {
    position: absolute; inset: 0; z-index: 50;
    display: flex; flex-direction: column;
    align-items: center; justify-content: center;
    text-align: center;
    padding: 28px 24px;
    background: rgba(8, 12, 24, 0.82);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    /* Whole-overlay fade; children stagger in on top (see below). */
    opacity: 0;
    transition: opacity .35s ease;
}
.overlay.show { opacity: 1; }
.overlay.hidden { display: none; }
/* Sequenced entrance for each overlay's children. `backwards` holds the start
   state during the per-child delay; we deliberately don't fill forwards so the
   resting transform stays in the cascade (buttons keep their :active press). */
.overlay.show > * { animation: overlay-rise .5s cubic-bezier(.2, .8, .2, 1) backwards; }
@keyframes overlay-rise {
    from { opacity: 0; transform: translateY(16px); }
    to   { opacity: 1; transform: none; }
}
.overlay.show > *:nth-child(1) { animation-delay: .05s; }
.overlay.show > *:nth-child(2) { animation-delay: .12s; }
.overlay.show > *:nth-child(3) { animation-delay: .19s; }
.overlay.show > *:nth-child(4) { animation-delay: .26s; }
.overlay.show > *:nth-child(5) { animation-delay: .33s; }
.overlay.show > *:nth-child(6) { animation-delay: .40s; }
.overlay.show > *:nth-child(7) { animation-delay: .47s; }
.overlay.show > *:nth-child(8) { animation-delay: .54s; }
.overlay .logo-big {
    width: 64px; height: 64px; border-radius: 16px;
    display: grid; place-items: center; font-size: 34px;
    background: linear-gradient(160deg, var(--accent), #2aa9ff);
    box-shadow: 0 10px 30px rgba(3,122,255,0.5);
    margin-bottom: 16px;
}
/* End screen is content-heavy (score + buttons + promo video); always allow scroll
   so nothing is clipped. On phones (touch) it's tighter, so drop the icon and pull
   the content up; desktop keeps the icon and centered layout. */
#over-overlay { overflow-y: auto; }
@media (pointer: coarse) {
    #over-overlay { justify-content: flex-start; padding-top: 16px; padding-bottom: 22px; }
    #over-overlay #over-logo { display: none; }
    #over-overlay h2 { margin-top: 4px; }
}
.overlay h1 { font-size: 1.7rem; font-weight: 600; margin-bottom: 6px; }
.overlay h2 { font-size: 1.5rem; font-weight: 600; margin-bottom: 6px; }
.overlay p { color: var(--muted); line-height: 1.5; max-width: 320px; margin-bottom: 8px; }
.overlay .how { text-align: left; max-width: 300px; margin: 8px 0 20px; }
.overlay .how li { color: var(--muted); margin: 8px 0; line-height: 1.4; list-style: none; padding-left: 26px; position: relative; }
.overlay .how li::before { content: attr(data-emoji); position: absolute; left: 0; top: -1px; }

.big-score { font-size: 2.6rem; font-weight: 700; color: var(--accent); margin: 4px 0 2px; font-variant-numeric: tabular-nums; }
.score-caption { color: var(--muted); margin-bottom: 18px; }

.btn {
    appearance: none; border: none; cursor: pointer;
    font-family: inherit; font-weight: 600; font-size: 1.05rem;
    color: #fff;
    background: linear-gradient(160deg, #2aa9ff, var(--accent));
    padding: 14px 30px; border-radius: 14px;
    box-shadow: 0 8px 22px rgba(3,122,255,0.45);
    width: 100%; max-width: 300px;
    transition: transform .1s;
}
.btn:active { transform: scale(0.97); }
.btn.secondary {
    background: var(--panel); border: 1px solid var(--panel-border);
    box-shadow: none; margin-top: 10px; font-weight: 500;
}
.store-link { display: block; margin-top: 16px; font-size: 0.85rem; color: var(--muted); }
.store-link b { color: var(--text); }
.footer-note { margin-top: 22px; font-size: 0.75rem; color: var(--muted); }

/* Best-score row on the end screen (shown when this run isn't a new high). */
.best-row {
    margin: 12px 0 2px;
    font-size: 0.95rem; font-weight: 600; color: var(--muted);
}
.best-row.hidden { display: none; }
.best-row b { color: var(--text); font-variant-numeric: tabular-nums; }

/* New-high celebration accents on the game-over overlay. */
.overlay.newhigh #over-title { color: #ffd23a; }
.overlay.newhigh .big-score { color: #ffd23a; }
.overlay.newhigh #over-logo {
    background: linear-gradient(160deg, #ffd23a, #ff9e2e);
    box-shadow: 0 10px 30px rgba(255, 180, 40, 0.55);
}

/* Squared Smart Keys promo card on the end screen: a looping screencast as the
   background, a dark→clear gradient, and the logo + rotating headline pinned to
   the bottom-left. (min-height is a fallback if aspect-ratio is unsupported.) */
.sk-card {
    position: relative;
    display: block;
    width: 100%; max-width: 300px;
    margin: 16px auto 2px;
    aspect-ratio: 4 / 5;             /* taller — the screencast is portrait */
    min-height: 300px;
    border-radius: 16px;
    overflow: hidden;
    text-align: left;
    color: var(--text);
    background: #0a1326;
    border: 1px solid rgba(3, 122, 255, 0.45);
    box-shadow: 0 10px 28px rgba(0, 0, 0, 0.45);
    transition: transform .18s ease, box-shadow .22s ease, border-color .22s ease;
}
/* Desktop hover: lift the card with a brand-blue glow (no-op on touch). */
.sk-card:hover {
    transform: translateY(-3px);
    border-color: rgba(3, 122, 255, 0.85);
    box-shadow: 0 16px 38px rgba(3, 122, 255, 0.36), 0 10px 28px rgba(0, 0, 0, 0.5);
}
.sk-card:active { transform: scale(0.98); }
/* The screencast fills the card; object-position keeps the keyboard in frame
   (the source is portrait, so it's cropped top/bottom on this landscape card). */
.sk-card-video {
    position: absolute; inset: 0;
    width: 100%; height: 100%;
    object-fit: cover;
    object-position: center top; /* keep the text + AI suggestion chips in frame */
    transition: transform .4s ease;
}
.sk-card:hover .sk-card-video { transform: scale(1.06); } /* gentle zoom on hover */
.sk-card::before {
    content: '';
    position: absolute; inset: 0; z-index: 1;
    background: linear-gradient(to top, rgba(3,6,16,0.96) 0%, rgba(3,6,16,0.65) 30%, rgba(3,6,16,0) 62%);
}
.sk-card-foot {
    position: absolute; left: 0; right: 0; bottom: 0; z-index: 2;
    padding: 13px 15px;
    display: flex; align-items: center; gap: 11px;
}
.sk-card-logo {
    flex: 0 0 auto; width: 40px; height: 40px; border-radius: 10px;
    object-fit: cover;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.5);
}
.sk-card-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sk-card-text > b { font-size: 1.02rem; font-weight: 700; text-shadow: 0 1px 8px rgba(0,0,0,0.7); }
.sk-card .sk-sub { font-size: 0.76rem; color: rgba(255,255,255,0.82); }
.sk-card .sk-arrow { color: #6cc0ff; font-weight: 700; display: inline-block; transition: transform .2s ease; }
.sk-card:hover .sk-arrow { transform: translateX(4px); }

/* small screens */
@media (max-height: 680px) {
    .overlay .how { margin: 4px 0 14px; }
    .overlay h1 { font-size: 1.5rem; }
    .sk-card { aspect-ratio: 1 / 1; min-height: 120px; }
}


/* ---------- Game-over count-up (blur board → skull → race score → results) ---------- */
.go-fx {
    position: absolute; inset: 0; z-index: 48;
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 12px;
    background: rgba(8, 12, 24, 0.55);
    backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px);
    opacity: 0; transition: opacity .3s ease;
    pointer-events: none;
}
.go-fx.show { opacity: 1; }
.go-fx.hidden { display: none; }
.go-skull {
    font-size: 4.4rem; line-height: 1;
    filter: drop-shadow(0 8px 22px rgba(0, 0, 0, 0.6));
}
.go-skull.drop { animation: go-skull-drop .5s cubic-bezier(.2, .9, .3, 1.2) backwards; }
@keyframes go-skull-drop {
    0%   { opacity: 0; transform: translateY(-44px) scale(0.4) rotate(-12deg); }
    70%  { opacity: 1; transform: translateY(4px) scale(1.12) rotate(4deg); }
    100% { transform: translateY(0) scale(1) rotate(0); }
}
.go-score {
    font-size: 2.7rem; font-weight: 800; letter-spacing: 0.5px;
    color: #fff; text-shadow: 0 2px 14px rgba(3, 122, 255, 0.55);
    font-variant-numeric: tabular-nums;
}


/* ---------- Flag intro popup (one-time, tap Continue) ---------- */
.flag-intro {
    position: absolute; inset: 0; z-index: 42;
    display: flex; align-items: flex-start; justify-content: center;
    pointer-events: none;             /* board stays inert (it's paused); only the card is live */
}
.flag-intro.hidden { display: none; }
.flag-intro-card {
    margin-top: 16%;
    pointer-events: auto;
    text-align: center;
    max-width: 78%;
    padding: 18px 22px;
    border-radius: 18px;
    background: rgba(8, 12, 24, 0.92);
    border: 1px solid var(--panel-border);
    backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
    box-shadow: 0 16px 40px rgba(3, 122, 255, 0.4);
    opacity: 0; transform: translateY(-10px) scale(0.94);
    transition: opacity .26s ease, transform .26s ease;
}
.flag-intro.show .flag-intro-card { opacity: 1; transform: none; }
.fi-emoji { font-size: 2.5rem; line-height: 1; display: block; }
.fi-title { font-size: 1.25rem; font-weight: 800; margin-top: 8px; }
.fi-text { color: var(--muted); font-size: 0.92rem; line-height: 1.4; margin-top: 6px; }
.fi-btn { margin-top: 16px; }
