  :root{
    --bg:#1F120E;
    --bg-2:#2A1913;
    --card-face:#F3E7D3;
    --cream:#F1E6D4;
    --cream-dim:#C6BEE0;
    --wine:#FF2F92;
    --wine-deep:#7A1252;
    --amber:#2FE0FF;
    --amber-soft:#1B9DB8;
    --purple-neon:#C850FF; /* matches the .app edge-highlight glow */
    --logo-img:url("../images/logo-img-v2.jpg");
    --line:rgba(200,120,255,.28);
    --serif:"Bodoni 72","Didot","Songti SC","Noto Serif SC",Georgia,serif;
    --hand:"Bradley Hand","Chalkboard SE","Segoe Print","Comic Sans MS","Kaiti SC","STKaiti",cursive;
    --sans:-apple-system,BlinkMacSystemFont,"PingFang SC","Hiragino Sans GB","Microsoft YaHei",sans-serif;
    --card-back:url("../images/card-back.jpg");
    --bg-photo:url("../images/bg-photo.jpg");
    --cw:140px;   /* fan card width; the true value is set on .fan-area by updateLayout() in JS,
                     since .fan-card's containing block (.fan) has no intrinsic width for % to use */
    --ch:calc(var(--cw) * 1.5);
  }
  *{margin:0;padding:0;box-sizing:border-box;-webkit-tap-highlight-color:transparent}
  .sr-only{
    position:absolute;width:1px;height:1px;padding:0;margin:-1px;
    overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0;
  }
  html,body{height:100%}
  body{
    background:var(--bg-photo) center/cover no-repeat, var(--bg);
    color:var(--cream);
    font-family:var(--sans);
    display:flex;justify-content:center;
    min-height:100dvh;
    overflow:hidden;
    overscroll-behavior:none;
  }
  /* dark scrim over the night-street photo, plus a little warm lamp glow */
  .lamp{
    position:fixed;inset:0;pointer-events:none;z-index:0;
    background:
      linear-gradient(180deg, rgba(8,5,4,.62) 0%, rgba(8,5,4,.32) 32%, rgba(8,5,4,.4) 62%, rgba(8,5,4,.78) 100%),
      radial-gradient(60vw 40vh at 50% -6%, rgba(214,160,94,.14), transparent 70%),
      radial-gradient(70vw 45vh at 10% 85%, rgba(214,160,94,.06), transparent 70%);
  }

  /* ---------- floating corner controls (no header bar) ---------- */
  .deck-count{
    position:absolute;z-index:20;
    top:calc(env(safe-area-inset-top) + 14px);left:50%;transform:translateX(-50%);
    min-height:40px;display:inline-flex;align-items:center;justify-content:center;
    white-space:nowrap;font-size:12px;letter-spacing:.08em;color:var(--cream-dim);
    background:rgba(10,6,14,.45);border:1px solid var(--line);border-radius:999px;
    padding:7px 12px;
  }
  .deck-count b{color:var(--purple-neon);font-weight:600;text-shadow:0 0 10px rgba(200,80,255,.5)}
  .shuffle-btn{
    position:absolute;z-index:20;
    top:calc(env(safe-area-inset-top) + 14px);right:16px;
  }
  .lobby-link{
    position:absolute;z-index:21;
    top:calc(env(safe-area-inset-top) + 14px);left:16px;
    min-width:72px;min-height:40px;padding:0 12px;display:inline-flex;align-items:center;justify-content:center;
    white-space:nowrap;border:1px solid rgba(255,255,255,.14);border-radius:999px;
    background:rgba(20,8,38,.72);color:var(--amber);font-size:12px;font-weight:850;
    letter-spacing:.02em;text-decoration:none;
    box-shadow:inset 0 0 18px rgba(150,44,255,.12),0 0 18px rgba(150,44,255,.12);
    backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);
    transition:transform .12s ease,background .2s ease;
  }
  .lobby-link:active{transform:scale(.96)}
  .lobby-link:focus-visible{outline:2px solid var(--amber);outline-offset:3px}

  /* ---------- stage ---------- */
  /* ---------- phone-shaped app frame ---------- */
  /* Design baseline is a 9:16 portrait phone. Real phones are usually taller
     (e.g. 9:19.5) so 100% width already fits under this cap and the frame
     simply fills the device edge-to-edge. On wide/landscape/desktop viewports
     this caps the app to a phone-shaped column instead of stretching full-bleed,
     with the same background photo showing through as a natural side border. */
  .app{
    position:relative;z-index:1;
    width:100%;max-width:calc(100dvh * 9 / 16);
    height:100dvh;
    display:flex;flex-direction:column;
    overflow:hidden;
    border-left:1px solid rgba(255,255,255,.22);
    border-right:1px solid rgba(255,255,255,.22);
    box-shadow:
      0 0 0 1px rgba(255,45,146,.35),
      0 0 26px rgba(200,80,255,.3),
      0 0 60px rgba(255,45,146,.16);
  }
  .fx-overlay{
    position:absolute;
    inset:0;
    z-index:60;
    background:#050611;
    opacity:0;
    visibility:hidden;
    pointer-events:none;
    overflow:hidden;
    contain:layout paint style;
    transition:opacity .18s ease, visibility .18s ease;
  }
  .fx-overlay.show{
    opacity:1;
    visibility:visible;
    pointer-events:auto;
  }
  .fx-overlay video{
    position:absolute;
    inset:0;
    display:block;
    width:100%;
    height:100%;
    background:#050611;
    object-fit:contain;
    opacity:0;
    visibility:hidden;
    pointer-events:none;
    transform:translateZ(0);
  }
  .fx-overlay video.active{
    opacity:1;
    visibility:visible;
  }
  .app.fx-running .deck-count,
  .app.fx-running .shuffle-btn,
  .app.fx-running .stage{
    visibility:hidden;
  }
  .stage{
    position:relative;z-index:1;flex:1 1 auto;
    display:flex;flex-direction:column;min-height:0;
    padding-bottom:env(safe-area-inset-bottom);
  }

  /* ---------- sliding card spread ---------- */
  .fan-area{
    position:relative;z-index:1;flex:0 0 auto;
    /* the explicit z-index (rather than the default auto) seals the ring's
       per-card z-index values (up to 1000, for front-to-back ordering)
       inside fan-area's own stacking context, so they can't leak out and
       out-rank .table-area (z-index:2) when the reveal card overlaps it */
    width:min(94%,860px);margin:0 auto;
    height:clamp(300px, 50dvh, 480px);
    overflow:hidden;
    touch-action:none;
    cursor:grab;
    -webkit-user-select:none;user-select:none;
    contain:layout paint style;
  }
  .fan-area:active{cursor:grabbing}
  .fan{
    position:absolute;left:50%;bottom:0;
    width:0;height:0;
  }
  .fan-card{
    position:absolute;
    left:calc(var(--cw) / -2);
    top:calc(var(--ch) / -2);
    width:var(--cw);height:var(--ch);
    backface-visibility:hidden;
    -webkit-backface-visibility:hidden;
    cursor:pointer;
    transition:transform .28s cubic-bezier(.22,1,.36,1), opacity .22s ease;
    contain:layout paint style;
  }
  .fan.dragging .fan-card{
    transition:none;
    will-change:transform;
  }
  /* hold-and-slide-up gesture: the held card flips in place, tracking the
     finger 1:1 (with the same light damping) until release; other cards
     keep their normal transition */
  .fan-card.pulling{transition:none;will-change:transform;z-index:5}
  .fan-card:focus-visible .cover{outline:2px solid var(--amber);outline-offset:2px}
  .fan-card .cover{
    position:absolute;inset:0;border-radius:12px;overflow:hidden;
    background-image:var(--card-back);
    background-size:cover;background-position:center;
    box-shadow:0 10px 24px rgba(0,0,0,.5), 0 0 0 1px rgba(214,160,94,.22);
  }
  .fan.dragging .fan-card .cover{
    box-shadow:0 4px 10px rgba(0,0,0,.38), 0 0 0 1px rgba(214,160,94,.16);
  }

  /* ---------- table / reveal slot ---------- */
  .table-area{
    position:relative;z-index:2;flex:1 1 auto;min-height:0;
    /* anchored to the top (not centered) so the card sits just below the
       corner buttons and is free to overlap down into the ring — it stays
       uncropped (table-area has no overflow:hidden) and, thanks to the
       z-index above beating .fan-area's sealed stacking context, entirely
       on top of the ring rather than being squeezed to avoid it */
    display:flex;align-items:flex-start;justify-content:center;
    padding:calc(env(safe-area-inset-top) + 90px) 20px 4px;
    /* only the revealed card itself should catch the pointer; everywhere
       else in this box (including the dead space where it overlaps the
       ring below) must fall through so the ring can be dragged from there */
    pointer-events:none;
  }
  .slot{
    position:relative;
    width:min(82%, 340px);
    aspect-ratio:2/3;
    perspective:1200px;
  }
  .placeholder{
    position:absolute;inset:0;
    /* top-anchored (not centered) so the logo sits right below the corner
       buttons, matching where the reveal card itself starts */
    display:flex;align-items:flex-start;justify-content:center;
    text-align:center;
    font-size:11px;letter-spacing:.22em;color:rgba(255,255,255,.5);
    padding:20px;line-height:2;
  }
  .logo-mark{
    /* deliberately smaller than the slot/big-card box (which is allowed to
       overlap the ring below) so the idle logo itself never touches or
       clashes with the deck; once a card is revealed, .big-card fills that
       whole box and, being strictly bigger than this mark, fully covers it */
    width:min(72%, 270px);
    aspect-ratio:4/5;
    background-image:var(--logo-img);
    background-size:contain;background-position:center;background-repeat:no-repeat;
    filter:drop-shadow(0 0 18px rgba(200,80,255,.25));
  }
  .big-card{
    position:absolute;inset:0;
    transform-style:preserve-3d;
    display:none;
    cursor:pointer;
    pointer-events:auto;
  }
  .big-card.in{display:block;animation:deal .7s cubic-bezier(.2,.8,.25,1) both}
  @keyframes deal{
    0%{transform:translateY(46dvh) scale(.42) rotateY(180deg);opacity:.4}
    55%{opacity:1}
    100%{transform:translateY(0) scale(1) rotateY(360deg);opacity:1}
  }
  .bface{
    position:absolute;inset:0;border-radius:16px;overflow:hidden;
    backface-visibility:hidden;-webkit-backface-visibility:hidden;
    box-shadow:0 16px 40px rgba(0,0,0,.55), 0 0 0 1px rgba(214,160,94,.2);
  }
  .bface.bback{
    background-image:var(--card-back);
    background-size:cover;background-position:center;
    transform:rotateY(180deg);
  }
  .bface.bfront{
    background:#0A0A0A;
    overflow:hidden;
  }
  .bart{
    position:absolute;inset:0;width:100%;height:100%;
    object-fit:cover;object-position:center;
  }
  .big-card.glow{filter:drop-shadow(0 0 30px rgba(214,160,94,.35))}

  /* ---------- buttons ---------- */
  .btn{
    font-family:var(--sans);font-size:13px;letter-spacing:.06em;
    border-radius:999px;padding:10px 20px;min-height:44px;cursor:pointer;border:none;
  }
  .btn-ghost{
    background:rgba(15,8,20,.5);color:var(--purple-neon);border:1px solid var(--line);
    transition:background .2s, box-shadow .2s;
  }
  .btn-ghost:active{background:rgba(200,80,255,.16);box-shadow:0 0 14px rgba(200,80,255,.3)}
  .btn:active{transform:translateY(1px)}

  @media (max-width:360px){
    .lobby-link{left:10px;min-width:68px;padding:0 10px}
    .deck-count{padding:7px 9px;font-size:10px;letter-spacing:.04em}
    .shuffle-btn{right:10px;min-height:40px;padding:8px 12px;font-size:11px}
  }

  @media (prefers-reduced-motion:reduce){
    *{animation:none!important;transition:none!important}
  }

  @media (hover:none) and (pointer:coarse){
    .app{
      box-shadow:
        0 0 0 1px rgba(255,45,146,.28),
        0 0 24px rgba(255,45,146,.12);
    }
    .fan-card .cover{
      box-shadow:0 6px 14px rgba(0,0,0,.42), 0 0 0 1px rgba(214,160,94,.18);
    }
    .logo-mark,
    .big-card.glow{
      filter:none;
    }
    .bface{
      box-shadow:0 10px 24px rgba(0,0,0,.48), 0 0 0 1px rgba(214,160,94,.18);
    }
  }

  @media (hover:none) and (pointer:coarse) and (min-width:700px){
    .app{
      max-width:min(100vw, 840px);
      border-left:1px solid rgba(255,255,255,.16);
      border-right:1px solid rgba(255,255,255,.16);
    }
    .lobby-link{
      left:24px;
      top:calc(env(safe-area-inset-top) + 20px);
    }
    .deck-count{
      left:50%;
      top:calc(env(safe-area-inset-top) + 20px);
      font-size:13px;
    }
    .shuffle-btn{
      right:24px;
      top:calc(env(safe-area-inset-top) + 20px);
    }
    .table-area{
      padding-top:calc(env(safe-area-inset-top) + 96px);
    }
    .slot{
      width:min(58%, 430px);
    }
    .fan-area{
      width:min(96%, 900px);
      height:clamp(360px, 45dvh, 520px);
    }
  }

  @media (hover:none) and (pointer:coarse) and (min-width:900px) and (orientation:landscape){
    .app{
      max-width:min(100vw, 980px);
    }
    .slot{
      width:min(42%, 400px);
    }
    .fan-area{
      height:clamp(300px, 43dvh, 460px);
    }
  }
