/* The look comes from the table prototype: a phone screen, card colour carrying the suit colour. */
/* The whole app is drawn in the Uno deck's colours: the four suits, the Wild's ink and the paper. Nothing else
   gets a colour of its own; every other tone below is one of those six mixed with another. */
:root{
  color-scheme:light;
  --u-coral:#f4565c;
  --u-sun:#ee9b22;
  --u-leaf:#2e9e6b;
  --u-sea:#3b78dc;
  --ink:#27242a;
  --paper:#ffffff;
  --coral:var(--u-coral);
  --coral-deep:color-mix(in oklab,var(--u-coral),var(--ink) 22%);
  --coral-light:color-mix(in oklab,var(--u-coral),var(--paper) 22%);
  --coral-wash:color-mix(in oklab,var(--u-coral) 14%,var(--paper));
  --coral-on-wash:color-mix(in oklab,var(--u-coral),var(--ink) 36%);
  --sea-deep:color-mix(in oklab,var(--u-sea),var(--ink) 24%);
  --sea-light:color-mix(in oklab,var(--u-sea),var(--paper) 22%);
  --leaf-deep:color-mix(in oklab,var(--u-leaf),var(--ink) 26%);
  --leaf-light:color-mix(in oklab,var(--u-leaf),var(--paper) 20%);
  --ink-deep:var(--ink);
  --ink-light:color-mix(in oklab,var(--ink),var(--paper) 14%);
  --table:color-mix(in oklab,var(--ink) 6%,var(--paper));
  --line:color-mix(in oklab,var(--ink) 14%,var(--paper));
  --muted:color-mix(in oklab,var(--ink) 62%,var(--paper));
  --outside:color-mix(in oklab,var(--ink) 9%,var(--paper));
  --online:var(--u-leaf);
  --display:"Rubik",system-ui,-apple-system,"Segoe UI",sans-serif;
  --body:"Karla",system-ui,-apple-system,"Segoe UI",sans-serif;
}
*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}
[hidden]{display:none!important}
html,body{height:100%;margin:0}
/* The page is a sheet the size of the screen, as in an app: it never scrolls, bounces or zooms. Panning stays
   allowed so lists inside it still scroll; pinching and double-tapping are not. Text is only selectable in a field.
   The body must not be position:fixed: Safari reads a fixed element at the top edge to colour the status bar. */
html{overflow:hidden;overscroll-behavior:none;touch-action:pan-x pan-y;-webkit-text-size-adjust:100%;text-size-adjust:100%}
body{overscroll-behavior:none;-webkit-touch-callout:none;-webkit-user-select:none;user-select:none;background:var(--outside);color:var(--ink);font:400 15px/1.35 var(--body);display:flex;align-items:center;justify-content:center;overflow:hidden;overflow:clip}
input{-webkit-touch-callout:default;-webkit-user-select:text;user-select:text}
button{font:inherit;color:inherit;background:none;border:0;padding:0;cursor:pointer}
button:focus-visible,input:focus-visible{outline:3px solid var(--ink);outline-offset:2px}
.caps{font:700 11px/1.2 var(--display);letter-spacing:.14em;text-transform:uppercase}

/* Stage: paper, then the felt that opens over it, then the cards that never leave, then the screen */
#frame{position:relative;width:390px;height:min(844px,calc(100% - 32px));background:var(--paper);border-radius:34px;overflow:hidden;box-shadow:0 24px 60px color-mix(in srgb,var(--ink) 20%,transparent);flex:none}
#felt{position:absolute;inset:0;background:var(--table);clip-path:circle(0 at 50% 40%);overflow:hidden}
#orbit{position:absolute;inset:0;overflow:hidden;pointer-events:none}
#screen{position:absolute;inset:0;overflow:hidden}
.layer{position:absolute;inset:0}
.layer.leaving{pointer-events:none}
#fx{position:absolute;inset:0;pointer-events:none;z-index:20;overflow:hidden}
@media (max-width:759px){
  /* The frame, and so everything placed on it, starts below the status bar, where iOS draws its own fade.
     Only the felt reaches up under the bar, so the table still runs to the top of the screen. */
  :root{--bar:calc(env(safe-area-inset-top,0px) + 24px)}
  body{--page:var(--paper);align-items:stretch;background:var(--page);padding-top:var(--bar);transition:background-color .48s cubic-bezier(.3,.7,.2,1)}
  /* Safari tints the status bar from the page background, not from the felt under it, so the page takes the table's colour too */
  body:has(#felt[data-open="true"]){--page:var(--table)}
  /* An open sheet's scrim dims the page, and so the status bar, as much as it dims the frame, in step with its fade */
  body:has(.scrim){transition-duration:.2s}
  body:has(.scrim:not(.closing)){background:color-mix(in srgb,var(--ink) 28%,var(--page))}
  #frame .scrim{top:calc(-1 * var(--bar))}
  #frame{width:100%;height:auto;flex:1;min-height:0;border-radius:0;box-shadow:none;overflow:visible}
  #felt{top:calc(-1 * var(--bar))}
  /* The orbiting cards reach up under the bar too, or the paper screens show them sliced along the frame's top edge */
  #orbit{overflow:visible;clip-path:inset(calc(-1 * var(--bar)) 0 0 0)}
  /* The game picker's colour runs up under the bar as well; its content stays where it was on the frame */
  #screen{overflow:visible;clip-path:inset(calc(-1 * var(--bar)) 0 0 0)}
}
#bar{display:none}
/* In a Safari tab the bar blurs well below the safe area, unless a fixed element holds the top edge: then Safari
   draws the bar flat in that element's colour, so a strip the page's colour keeps the frame close under it */
@media (max-width:759px) and (display-mode:browser){
  :root{--bar:calc(env(safe-area-inset-top,0px) + 12px)}
  #bar{display:block;position:fixed;left:0;right:0;top:0;height:var(--bar);background:inherit;z-index:30;pointer-events:none}
}

/* Cards. --w is a real length, so a hand that changes card size can animate it */
@property --w{syntax:"<length>";inherits:true;initial-value:60px}
.flight{position:absolute;left:0;top:0;width:var(--w);height:calc(var(--w)*1.4)}
.flight .card{position:absolute;left:0;top:0}
.card{position:relative;width:var(--w,60px);height:calc(var(--w,60px)*1.4);border-radius:calc(var(--w,60px)*.15);color:#fff;overflow:hidden;flex:none;box-shadow:0 1px 3px color-mix(in srgb,var(--ink) 22%,transparent);user-select:none}
.card.red{background:var(--coral)}
.card.ink{background:var(--ink)}
.card .ix{position:absolute;left:9%;top:6%;display:flex;flex-direction:column;align-items:center;font:800 calc(var(--w,60px)*.25)/1 var(--display);letter-spacing:-.04em}
.card .ix svg{width:calc(var(--w,60px)*.17);height:calc(var(--w,60px)*.17);margin-top:calc(var(--w,60px)*.03);fill:currentColor}
.card .big{position:absolute;right:-9%;bottom:-7%;width:70%;height:50%;fill:currentColor}
.card.mini{border-radius:calc(var(--w)*.17)}
.card.mini .big{display:none}
.card.mini .ix{left:5%;top:5%;font-size:calc(var(--w)*.46)}
.card.mini .ix svg{width:calc(var(--w)*.36);height:calc(var(--w)*.36);margin-top:1px}
/* Rummy's back: coral, with deep pinstripes running edge to edge */
.card.back{background:repeating-linear-gradient(-45deg,var(--coral-deep) 0 calc(var(--w,60px)*.045),var(--coral) 0 calc(var(--w,60px)*.1))}
/* Uno's back: the card cut into the four colours from the middle, an ink dot where they meet */
.card.back.uno-back{background:radial-gradient(circle,var(--ink) 0 calc(var(--w,60px)*.16),#fff 0 calc(var(--w,60px)*.2),transparent 0),conic-gradient(var(--u-coral) 0 25%,var(--u-sun) 0 50%,var(--u-leaf) 0 75%,var(--u-sea) 0)}
/* A Joker is the one card in sun, so it never passes for a heart or a spade at any size */
.card.joker{background:var(--u-sun)}
/* Uno cards: flat colour like the Rummy cards, the number is its own big symbol, Wilds are the ink card */
.card.uno{background:var(--c);--bg:var(--c)}
.card.uno.u-coral{--c:var(--u-coral)}
.card.uno.u-sun{--c:var(--u-sun)}
.card.uno.u-leaf{--c:var(--u-leaf)}
.card.uno.u-sea{--c:var(--u-sea)}
.card.uno.u-wild{--c:var(--ink)}
.card.uno .ix{z-index:1}
.card.uno .num{position:absolute;right:-5%;bottom:-20%;font:900 calc(var(--w,60px)*1.08)/1 var(--display);letter-spacing:-.07em}
.card.uno.mini .num{display:none}
.card .wildmark{position:absolute;right:6%;top:5%;width:calc(var(--w)*.3);height:calc(var(--w)*.3);fill:currentColor}
.flying{position:absolute;left:0;top:0;will-change:transform;z-index:2}
.orbit-card{position:absolute;left:0;top:0;will-change:transform}

/* Icons draw themselves in, then each has its own move when its button is pressed */
.ic{width:var(--ic,22px);height:var(--ic,22px);display:block;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;overflow:visible}
.ic *{transform-box:fill-box;transform-origin:center;animation:ic-draw .45s cubic-bezier(.3,.7,.2,1) .12s backwards}
.ic .dot{fill:currentColor;stroke:none}
.ic .soft{fill:currentColor;fill-opacity:.22}
@keyframes ic-draw{from{stroke-dasharray:1;stroke-dashoffset:1;opacity:0}to{stroke-dasharray:1;stroke-dashoffset:0;opacity:1}}
.ic-back.play .m{animation:ic-nudge .36s cubic-bezier(.3,.7,.2,1)}
.ic-go.play .m{animation:ic-slide-r .36s cubic-bezier(.3,.7,.2,1)}
.ic-undo.play .m{animation:ic-swing .42s cubic-bezier(.3,.7,.2,1)}
.ic-sort.play .up{animation:ic-rise .42s cubic-bezier(.3,.7,.2,1)}
.ic-sort.play .down{animation:ic-fall .42s cubic-bezier(.3,.7,.2,1)}
.ic-chevron .m{transition:transform .25s cubic-bezier(.3,.7,.2,1)}
[aria-expanded="true"] > .ic-chevron .m{transform:rotate(180deg)}
.ic-leave.play .m{animation:ic-slide-r .36s cubic-bezier(.3,.7,.2,1)}
.ic-finish{transform-origin:25% 90%}
.ic-finish.play .m{animation:ic-wobble .5s ease-out}
.ic-sound .waves,.ic-sound .mute{transition:opacity .2s}
.ic-sound .mute,.off > .ic-sound .waves{opacity:0}
.off > .ic-sound .mute{opacity:1}
.ic-sound.play .waves{animation:ic-pop .34s cubic-bezier(.3,1.3,.5,1)}
.ic-rules.play .a{animation:ic-slide-l .42s cubic-bezier(.3,.7,.2,1)}
.ic-rules.play .b{animation:ic-slide-r .42s cubic-bezier(.3,.7,.2,1)}
.ic-stats.play .t{animation:ic-rise .42s cubic-bezier(.3,.7,.2,1)}
.ic-stats.play .s{animation:ic-fall .42s cubic-bezier(.3,.7,.2,1)}
.ic-react .eyes{animation:ic-blink 4.5s ease-in-out infinite}
.ic-react.play .m{animation:ic-wobble .5s ease-out}
.ic-kick.play .m{animation:ic-wobble .5s ease-out}
.ic-watch.play .m{animation:ic-wink .36s cubic-bezier(.3,.7,.2,1)}
.ic-play .m{fill:currentColor}
.ic-play.play .m{animation:ic-slide-r .36s cubic-bezier(.3,.7,.2,1)}
.ic-guide.play .glass{animation:ic-pop .34s cubic-bezier(.3,1.3,.5,1)}
.ic-guide .rays{animation:none;opacity:0;transition:opacity .2s}
[data-level="1"] .ic-guide .glass,[data-level="2"] .ic-guide .glass{fill:currentColor;fill-opacity:.3;transition:fill-opacity .2s}
[data-level="2"] .ic-guide .rays{opacity:1;animation:ic-glow 1.6s ease-in-out infinite}
.ic-laugh .loop{animation:ic-laugh .9s ease-in-out infinite}
.ic-flame .loop{transform-origin:50% 100%;animation:ic-flicker .7s ease-in-out infinite}
.ic-flame .inner{transform-origin:50% 100%;animation:ic-flicker .5s ease-in-out infinite reverse}
.ic-shock .loop{animation:ic-tremble .4s linear infinite}
.ic-shock .o{animation:ic-pop 1s ease-in-out infinite}
.ic-clap .l{transform-origin:100% 100%;animation:ic-clap-l .6s ease-in-out infinite}
.ic-clap .r{transform-origin:0 100%;animation:ic-clap-r .6s ease-in-out infinite}
.ic-clap .sparks{animation:ic-spark .6s ease-out infinite}
.ic-eyeroll .pupils{animation:ic-roll 1.6s linear infinite}
.ic-joker .loop{animation:ic-twinkle 2s ease-in-out infinite}
@keyframes ic-wink{50%{transform:scaleY(.1)}}
@keyframes ic-nudge{50%{transform:translateX(-4px)}}
@keyframes ic-slide-l{50%{transform:translateX(-6px)}}
@keyframes ic-slide-r{50%{transform:translateX(6px)}}
@keyframes ic-swing{50%{transform:rotate(-36deg)}}
@keyframes ic-rise{50%{transform:translateY(-3px)}}
@keyframes ic-fall{50%{transform:translateY(3px)}}
@keyframes ic-blink{0%,92%,100%{transform:scaleY(1)}96%{transform:scaleY(.1)}}
@keyframes ic-wobble{25%{transform:rotate(-14deg)}60%{transform:rotate(10deg)}}
@keyframes ic-pop{50%{transform:scale(1.2)}}
@keyframes ic-glow{50%{opacity:.35}}
@keyframes ic-laugh{25%{transform:translateY(-2px) rotate(-7deg)}75%{transform:translateY(-2px) rotate(7deg)}}
@keyframes ic-flicker{33%{transform:scale(.94,1.08) skewX(-3deg)}66%{transform:scale(1.04,.95) skewX(3deg)}}
@keyframes ic-tremble{25%{transform:translateX(-.6px)}75%{transform:translateX(.6px)}}
@keyframes ic-clap-l{0%,100%{transform:rotate(-16deg)}50%{transform:rotate(0)}}
@keyframes ic-clap-r{0%,100%{transform:rotate(16deg)}50%{transform:rotate(0)}}
@keyframes ic-spark{0%,40%{opacity:0;transform:scale(.7)}60%{opacity:1;transform:scale(1)}100%{opacity:0;transform:scale(1.1)}}
@keyframes ic-roll{0%,100%{transform:translate(0,-1.3px)}25%{transform:translate(1.3px,0)}50%{transform:translate(0,1.3px)}75%{transform:translate(-1.3px,0)}}
@keyframes ic-twinkle{50%{transform:rotate(36deg) scale(.86)}}

/* Pills and home */
.centre{position:absolute;left:0;right:0;display:flex;flex-direction:column;align-items:center;text-align:center;z-index:2}
.pins{position:absolute;left:0;right:0;bottom:24px;display:flex;flex-direction:column;align-items:center;gap:10px;padding-inline:24px;z-index:3}
.pill{min-width:210px;padding:14px 26px;border-radius:999px;font:800 17px/1 var(--display);letter-spacing:.05em;text-transform:uppercase;text-align:center;transition:transform .12s}
.pill:active{transform:scale(.96)}
.pill.solid{background:var(--coral);color:#fff}
.pill.plain{background:var(--coral-wash);color:var(--coral-on-wash)}
.pill.small{min-width:0;padding:10px 18px;font-size:13px}
.pill[disabled]{background:var(--line);color:var(--muted);cursor:default}
.pair{display:flex;gap:8px;justify-content:center}
.logo-top{font:800 21px/1 var(--display);letter-spacing:.42em;margin-right:-.42em}
.logo-num{font:900 118px/.95 var(--display);color:var(--coral);letter-spacing:-.04em;font-variant-numeric:tabular-nums}
.tag{font:600 14px/1.3 var(--body);color:var(--muted);max-width:230px;margin-top:8px}
/* Home: a near-white page with a soft warm falloff, so the orbiting cards carry the colour and the buttons are black
   and white. The tone sits on the frame itself, under the cards, and fades in and out as the page comes and goes. */
#frame::before{content:"";position:absolute;inset:0;background:radial-gradient(120% 70% at 50% 40%,#fff 0,#fbf9f5 55%,#f1ece3 100%);opacity:0;transition:opacity .48s cubic-bezier(.3,.7,.2,1);pointer-events:none}
body[data-page="home"] #frame::before{opacity:1}
.orbit-card{transition:box-shadow .48s}
body[data-page="home"] .orbit-card{box-shadow:0 8px 18px color-mix(in srgb,var(--ink) 18%,transparent)}
.home-logo{color:var(--ink)}
.hl-fan{position:relative;width:0;height:66px;margin-bottom:14px}
.hl-fan .card{position:absolute;left:-20px;top:0;transform-origin:50% 120%;box-shadow:0 10px 22px color-mix(in srgb,var(--ink) 22%,transparent);animation:gp-deal .8s cubic-bezier(.2,1.35,.4,1) backwards,gp-bob 3.2s ease-in-out infinite}
.hl-fan .card:nth-child(1){rotate:-16deg;margin:6px 0 0 -26px;animation-delay:.1s,0s}
.hl-fan .card:nth-child(2){z-index:1;animation-delay:.18s,-1.1s}
.hl-fan .card:nth-child(3){rotate:16deg;margin:6px 0 0 26px;animation-delay:.26s,-2.2s}
.hl-word{margin:0;font:900 clamp(64px,20vw,88px)/.9 var(--display);letter-spacing:-.04em}
.back-btn.home-btn{background:#fff;color:var(--ink)}
/* The name bar is the page's big white button, edged so it holds up on the white: your character, your name, and go */
.namebar{display:flex;align-items:center;width:100%;max-width:320px;padding:6px;border-radius:999px;background:#fff;box-shadow:0 0 0 2px color-mix(in srgb,var(--ink) 8%,transparent),0 10px 26px color-mix(in srgb,var(--ink) 12%,transparent);transition:box-shadow .15s}
.namebar:has(.name:focus){box-shadow:0 0 0 2px var(--ink),0 10px 26px color-mix(in srgb,var(--ink) 12%,transparent)}
.name{flex:1;min-width:0;padding:0 8px;border:0;outline:0;background:none;text-align:center;font:800 18px/1 var(--display);color:var(--ink);caret-color:var(--ink)}
.name:focus-visible{outline:0}
.name::placeholder{color:var(--ink);opacity:.4}
.charpick{display:flex;flex-direction:column;align-items:center;gap:18px}
.chargrid{display:grid;grid-template-columns:repeat(4,64px);gap:16px}
.chargrid .av{position:static;width:64px;height:64px}
.chargrid .av:active{transform:scale(.92)}
.chargrid .av[aria-pressed="true"]{box-shadow:0 0 0 3px #fff,0 0 0 6px var(--ink)}
.namebar.solo .name{padding-left:52px}
/* Once you have a name: Play as the big white pill, your character round beside it, as Leave sits by the lobby's */
.pill.home-play{flex:1;padding:17px 20px;background:#fff;color:var(--ink);font-size:18px;letter-spacing:0;text-transform:none;box-shadow:0 10px 26px color-mix(in srgb,var(--ink) 18%,transparent)}
.av.home-av{position:static;flex:none;width:53px;height:53px;box-shadow:0 6px 16px color-mix(in srgb,var(--ink) 14%,transparent);transition:transform .12s}
.av.home-av:active{transform:scale(.92)}
.hl-name{font:inherit;color:var(--ink);font-weight:800;text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px;text-decoration-color:color-mix(in srgb,var(--ink) 40%,transparent)}
.go{flex:none;width:44px;height:44px;border-radius:50%;display:grid;place-items:center;background:var(--ink);color:#fff;transition:background .15s,color .15s,transform .12s}
.go:active{transform:scale(.92)}
.go[disabled]{background:color-mix(in srgb,var(--ink) 10%,#fff);color:var(--muted);cursor:default;transform:none}

/* Who's online, and other paper screens */
.head{position:absolute;left:0;right:0;top:0;padding:26px 22px 0;text-align:center;z-index:2}
.head h1{margin:0;font:800 26px/1.05 var(--display);text-wrap:balance}
.head p{margin:6px 0 0;color:var(--muted);font-weight:600}
.back-btn{position:absolute;left:14px;top:20px;width:36px;height:36px;border-radius:50%;background:var(--table);display:grid;place-items:center;z-index:3}
.rules-btn{left:auto;right:14px}
/* The lobby: a full colour page like the game picker, in the one deck colour no game has. Your table floats in
   with whoever is online, as one group, with the big button under them in reach. */
.lobby{position:absolute;inset:0;display:flex;flex-direction:column;z-index:2;color:#fff;text-align:center;overflow:hidden}
.lobby::before{content:"";position:absolute;inset:0;z-index:-1;background:radial-gradient(120% 70% at 50% 30%,var(--sea-light) 0,var(--u-sea) 55%,var(--sea-deep) 100%)}
.others{flex:1;min-height:0;overflow-y:auto;padding:76px 12px 8px;scrollbar-width:none;display:flex;flex-direction:column}
.list{position:relative;flex:1;display:flex;flex-wrap:wrap;align-content:center;justify-content:center;gap:14px 10px}
/* Each bubble bobs on its own clock and height. The name hangs off the face like a balloon's string: it bobs too,
   a beat behind and not quite as far, so the two never move as one. */
.person{flex:none;width:104px;display:flex;flex-direction:column;align-items:center;gap:4px;translate:0 var(--y,0)}
.person.group{width:136px}
.person .faces{animation:lb-float 4s ease-in-out var(--d,0s) infinite}
.person b,.person small{animation:lb-trail 4s ease-in-out infinite}
.person b{animation-delay:calc(var(--d,0s) - 3.7s)}
.person small{animation-delay:calc(var(--d,0s) - 3.6s)}
@keyframes lb-float{0%,100%{transform:translateY(0) rotate(-1.5deg)}50%{transform:translateY(-12px) rotate(1.5deg)}}
@keyframes lb-trail{0%,100%{transform:translateY(0) rotate(-.8deg)}50%{transform:translateY(-8px) rotate(.8deg)}}
/* Someone leaving is lifted out of the flow while they pop; then the scraps they burst into, and a face flying to a seat */
.popping{pointer-events:none;z-index:1}
.shard{position:absolute;width:8px;height:5px;margin:-2.5px 0 0 -4px;border-radius:2px;pointer-events:none;z-index:6}
.flyer{position:absolute;z-index:6;pointer-events:none}
.flyer .av{position:static;width:100%;height:100%;box-shadow:0 0 0 3px #fff,0 14px 26px color-mix(in srgb,var(--ink) 30%,transparent);transition:none}
.person .faces{display:flex;justify-content:center;margin-bottom:4px}
.person .av{position:static;width:64px;height:64px;box-shadow:0 0 0 3px #fff,0 10px 22px color-mix(in srgb,var(--ink) 30%,transparent);transition:none}
.person.group .av{width:52px;height:52px}
.person.group .av+.av{margin-left:-18px}
.person b{max-width:100%;font:800 15px/1.1 var(--display);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.person small{display:flex;align-items:center;justify-content:center;gap:5px;max-width:100%;font:600 12px/1.2 var(--body);opacity:.85;overflow:hidden;white-space:nowrap}
.person small:empty{display:none}
.person.tap{cursor:pointer;outline:none}
.person.tap .faces{position:relative}
.person.tap .av{transition:box-shadow .15s,scale .12s}
.person.tap:focus-visible .av{box-shadow:0 0 0 3px #fff,0 0 0 7px rgba(255,255,255,.35),0 10px 22px color-mix(in srgb,var(--ink) 30%,transparent)}
.person.tap:active:not(.off) .av{scale:.92}
.person.tap.off{cursor:default}
/* An invite out: a ring pulses out from the avatar until it is answered or taken back */
.person.waiting .faces::after{content:"";position:absolute;inset:0;box-sizing:border-box;border-radius:50%;border:3px solid #fff;pointer-events:none;animation:lb-wait 1.6s ease-out infinite}
@keyframes lb-wait{from{scale:1;opacity:.9}to{scale:1.55;opacity:0}}
@media (prefers-reduced-motion:reduce){.person.waiting .faces::after{animation:none;scale:1.15;opacity:.7}}
/* What you can do at your table */
.tcard{flex:none;max-height:62%;overflow-y:auto;scrollbar-width:none;display:flex;flex-direction:column;align-items:center;gap:14px;padding:6px 22px 30px}
/* Your table, up in the air with everyone else: drawn like any other table's float, but each face bobs for itself.
   Faces overlap, so someone away or a bot is washed out rather than see-through. */
.person.mine{width:max-content;max-width:100%}
.person .chips{position:relative;animation:none}
.chip{flex:none;animation:lb-float var(--t,4s) ease-in-out var(--d,0s) infinite}
.chip+.chip{margin-left:-18px}
.chip.popping{margin-left:0}
.chip.away .av{filter:saturate(.6) brightness(1.08)}
.chip.invited .av{filter:saturate(.6) brightness(1.08);box-shadow:none;outline:2px dashed #fff;outline-offset:2px}
/* Away from the keyboard: the same badge as anyone, with the character in grey, and AFK on top in a darker grey */
.lobby :is(.av.afk,.chip.afk .av){--cf:#8f8f8f;position:relative;left:0;top:0}
.lobby :is(.av.afk,.chip.afk .av) .char{filter:grayscale(1)}
.lobby :is(.av.afk,.chip.afk .av) .char .body{opacity:.4}
.lobby :is(.av.afk,.chip.afk .av)::after{content:"AFK";position:absolute;inset:0;display:grid;place-items:center;font:800 18px/1 var(--display);letter-spacing:.04em;color:#5a5a5a;pointer-events:none}
.lobby .person.group :is(.av.afk,.chip.afk .av)::after{font-size:15px}
/* Faces in a group overlap, so the one after moves over enough to leave the word readable */
.lobby .person.group .av.afk+.av,.lobby .chip.afk+.chip{margin-left:-8px}
.tc-hint{margin:-4px 0 0;max-width:300px;font:600 13px/1.3 var(--body);opacity:.85;text-wrap:pretty}
.tc-hint:empty{display:none}
.tc-pins{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;margin-top:4px}
.tc-go{display:flex;align-items:center;justify-content:center;gap:10px;width:100%;max-width:320px}
.lobby .combo{flex:1}
.lobby .pill.solid{width:100%;padding:17px 20px;background:#fff;color:var(--sea-deep);font-size:18px;letter-spacing:0;text-transform:none}
.lobby .pill[disabled]{background:rgba(255,255,255,.2);color:#fff}
.leave-btn{flex:none;width:53px;height:53px;border-radius:50%;background:rgba(255,255,255,.2);color:#fff;display:grid;place-items:center;transition:transform .12s}
.leave-btn:active{transform:scale(.92)}
@media (max-width:759px){
  .lobby{top:calc(-1 * var(--bar))}
  .others{padding-top:calc(76px + var(--bar))}
  body[data-page="lobby"]{--page:var(--u-sea)}
  /* The tone the home page's falloff has reached at the top edge, so the status bar runs on from it */
  body[data-page="home"]{--page:#fbf9f5}
  #frame::before{top:calc(-1 * var(--bar))}
}

/* Picking bots, while nobody sits at your table: − and + inside the big button */
.combo{display:flex;align-items:center}
.combo.bots{gap:2px;min-width:210px;padding:5px;border-radius:999px;background:#fff}
.lobby .combo.bots .pill{flex:1;min-width:0;padding:12px 8px;background:none;box-shadow:none;white-space:nowrap;font-variant-numeric:tabular-nums}
.step{width:40px;height:40px;flex:none;border-radius:50%;display:grid;place-items:center;background:color-mix(in oklab,var(--u-sea) 14%,#fff);color:var(--sea-deep);font:800 20px/1 var(--display);transition:transform .12s,opacity .15s}
.step[hidden]{display:none}
.step:active{transform:scale(.88)}
.step[disabled]{opacity:.35;cursor:default;transform:none}

/* Picking a game: one big tile each, its own cards fanned on it */
.gamepick{position:absolute;inset:0;overflow:hidden;container-type:size;touch-action:pan-y;user-select:none;-webkit-user-select:none;z-index:2;background:var(--ink-deep)}
.gp-track{position:absolute;inset:0;isolation:isolate}
.gp-slide{--off:0;--a:0;position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:flex-end;gap:22px;padding:0 26px 56px;color:#fff;text-align:center;overflow:hidden}
.gp-slide::before{content:"";position:absolute;inset:0;z-index:-1;opacity:var(--bg,1);background:var(--grad)}
.gp-slide.g-rummy{--grad:radial-gradient(120% 70% at 50% 34%,var(--coral-light) 0,var(--coral) 55%,var(--coral-deep) 100%)}
.gp-slide.g-uno{--grad:radial-gradient(120% 70% at 50% 34%,var(--ink-light) 0,var(--ink) 60%,var(--ink-deep) 100%)}
/* The covered game sinks into the dark as the next one opens over it */
.gp-fan{position:absolute;left:50%;top:40%;width:0;height:0;opacity:calc((.88 - var(--a)) * 5);transform:translateX(calc(var(--off) * 18cqw)) scale(calc(1 - var(--a) * .25))}
/* Each card flies its own distance and spin, the outer ones furthest, so the fan breaks apart and lands back together */
.gp-c{--fx:-50%;--fy:-62%;--fr:0deg;--k:1;position:absolute;left:0;top:0;transform:translate(calc(var(--off) * var(--k) * 62cqw),calc(var(--a) * var(--a) * var(--k) * -14cqh)) translate(var(--fx),var(--fy)) rotate(calc(var(--fr) * (1 - var(--a)) + var(--off) * var(--k) * 38deg))}
.gp-c:nth-child(1){--fx:-118%;--fy:-46%;--fr:-17deg;--k:.8}
.gp-c:nth-child(2){--k:1.15}
.gp-c:nth-child(3){--fx:18%;--fy:-46%;--fr:17deg;--k:1.5}
.gp-c .card{position:relative;box-shadow:0 0 0 3px rgba(255,255,255,.95),0 12px 28px color-mix(in srgb,var(--ink) 34%,transparent);animation:gp-deal .8s cubic-bezier(.2,1.35,.4,1) backwards,gp-bob 3.2s ease-in-out infinite}
.gp-c:nth-child(1) .card{animation-delay:.1s,0s}
.gp-c:nth-child(2) .card{animation-delay:.18s,-1.1s}
.gp-c:nth-child(3) .card{animation-delay:.26s,-2.2s}
@keyframes gp-deal{from{scale:.3;rotate:-40deg;opacity:0}}
@keyframes gp-bob{0%,100%{translate:0 0}50%{translate:0 -10px}}
.gp-text{display:flex;flex-direction:column;align-items:center;gap:8px}
.gp-text b{font:900 clamp(48px,15cqw,72px)/.95 var(--display);letter-spacing:-.03em;text-wrap:balance;transform:translateX(calc(var(--off) * 40cqw)) skewX(calc(var(--off) * -8deg));opacity:calc(1 - var(--a) * 1.4)}
.gp-text span{font:600 16px/1.3 var(--body);transform:translateX(calc(var(--off) * 26cqw));opacity:calc(.9 - var(--a) * 1.8)}
.gp-play{width:100%;max-width:320px;padding:17px 20px;border-radius:999px;background:#fff;font:800 18px/1 var(--display);translate:0 calc(var(--a) * 60px);opacity:calc(1 - var(--a) * 2);transition:transform .12s}
.g-rummy .gp-play{color:var(--coral-deep)}
.g-uno .gp-play{color:var(--ink)}
.gp-play:active{transform:scale(.96)}
/* Arrows on both edges say there are more games either way; they drift outwards now and then as a hint */
.gp-arrow{position:absolute;top:40%;z-index:3;display:grid;place-items:center;width:44px;height:44px;margin-top:-22px;color:#fff;opacity:.85;transition:opacity .2s,transform .12s}
.gp-arrow.prev{left:10px}
.gp-arrow.next{right:10px}
.gp-arrow svg{width:30px;height:30px;filter:drop-shadow(0 1px 3px color-mix(in srgb,var(--ink) 25%,transparent))}
.gp-arrow.prev svg{rotate:-90deg}
.gp-arrow.next svg{rotate:90deg}
.gp-arrow:active{transform:scale(.9);opacity:1}
.gp-back{background:rgba(255,255,255,.2);color:#fff}
@media (max-width:759px){
  .gamepick{top:calc(-1 * var(--bar))}
  .gp-fan,.gp-arrow{top:calc(40% + var(--bar) * .6)}
  body[data-page="rummy"]{--page:var(--coral)}
  body[data-page="uno"]{--page:var(--ink)}
}

/* The vote: who picked which game, the time left, and the winner's cards jumping for joy */
.gp-votes{display:flex;justify-content:center;gap:6px;min-height:34px;transform:translateX(calc(var(--off) * 26cqw));opacity:calc(1 - var(--a) * 1.8)}
.gp-voter.av{position:static;width:34px;height:34px;font-size:15px;box-shadow:0 0 0 2.5px #fff;transition:none;animation:gp-vote .32s cubic-bezier(.3,1.4,.5,1)}
@keyframes gp-vote{from{scale:0}}
.gp-play.picked{background:rgba(255,255,255,.22);color:#fff;box-shadow:inset 0 0 0 2px #fff}
.gp-play[disabled]{cursor:default}
/* Lets the pointer through, so a swipe that starts on it still turns the picker */
.gp-play.soon{background:rgba(255,255,255,.14);color:#fff;pointer-events:none}
.gp-slide.won .gp-fan{animation:gp-won .6s cubic-bezier(.3,1.5,.5,1)}
@keyframes gp-won{40%{scale:1.18}}
/* A picked game's cards, lifted off the picker on their way to the stock */
.carried{position:absolute;z-index:1;width:var(--w);height:calc(var(--w)*1.4)}
.carried .card{position:absolute;left:0;top:0;margin:0;box-shadow:0 0 0 3px rgba(255,255,255,.95),0 12px 28px color-mix(in srgb,var(--ink) 34%,transparent)}

/* An invite coming in */
.hero-av.av{position:static;width:136px;height:136px;font-size:64px;transition:none}
.invite{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px}
.invite .hero-av.av{width:96px;height:96px;font-size:44px;margin-bottom:8px}
.sheet .invite h3{font-size:26px;line-height:1.1;overflow-wrap:anywhere}
.invite .pair{width:100%;margin-top:12px}
.invite .pill{flex:1;min-width:0}
/* It comes from the lobby, so its accents wear the lobby's blue on the white sheet */
.sheet .invite .av{--cb:color-mix(in oklab,var(--u-sea) 12%,#fff);--cf:var(--u-sea)}
.invite .pill.solid{background:var(--u-sea);color:#fff}
.invite .pill.plain{background:color-mix(in oklab,var(--u-sea) 12%,#fff);color:var(--sea-deep)}

/* Leaving a game, and the table deciding whether to end it: the invite's layout, in the table's own coral */
.ask{display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px}
.ask .hero-av.av{width:96px;height:96px;font-size:44px;margin-bottom:8px}
.sheet .ask h3{font-size:26px;line-height:1.1;overflow-wrap:anywhere;text-wrap:balance}
.ask .pair{width:100%;margin-top:12px}
.ask .pair .pill{flex:1;min-width:0}
.ask>.pill{width:100%;margin-top:4px}
.opts{display:flex;flex-direction:column;gap:8px;width:100%;margin-top:12px}
.opt{display:flex;align-items:center;gap:12px;width:100%;padding:12px 14px;border-radius:18px;border:1.5px solid var(--line);color:var(--ink);text-align:left;transition:transform .12s}
.opt:active{transform:scale(.97)}
.opt-ic{flex:none;width:42px;height:42px;border-radius:50%;background:var(--coral-wash);color:var(--coral-deep);display:grid;place-items:center}
.opt b{display:block;font:800 16px/1.15 var(--display)}
.opt small{display:block;margin-top:3px;font:600 13px/1.25 var(--body);color:var(--muted);text-wrap:pretty}
/* Leaving stays neutral: outlined choices in ink, with staying as the one filled button */
.leave-ask .pill.plain{background:var(--ink);color:#fff}
/* A player's sheet: the same layout, with what they have on the table and something to throw at them */
.seat-ask .sub{margin-top:0}
.seat-ask .sub:empty{display:none}
.seat-ask .mset{justify-content:center;width:100%;margin-top:12px}
.seat-ask .reacts{width:100%;margin-top:12px}
.hero-wrap{position:relative}
.hero-wrap .cnt{left:auto;right:-4px;top:-2px;min-width:28px;height:28px;padding:0 7px;border-radius:14px;font-size:14px;line-height:28px}
.seat-kick{position:absolute;right:14px;top:14px;width:36px;height:36px;border-radius:50%;background:var(--coral-wash);color:var(--coral-on-wash);display:grid;place-items:center;--ic:20px;transition:transform .12s}
.seat-kick:active{transform:scale(.9)}
.ask-faces{display:flex;flex-wrap:wrap;justify-content:center;gap:12px;margin-bottom:10px}
.ask-face{position:relative;width:60px;height:60px}
.ask-face .av{position:static;width:100%;height:100%;font-size:26px;transition:opacity .2s}
.ask-face[data-state="no"] .av{opacity:.35}
/* Yet to answer: the ring an invite pulses with. Answered: a mark on the badge */
.ask-face[data-state="wait"]::after{content:"";position:absolute;inset:0;box-sizing:border-box;border-radius:50%;border:3px solid var(--coral);pointer-events:none;animation:lb-wait 1.6s ease-out infinite}
.ask-mark{--ic:14px;position:absolute;right:-3px;bottom:-3px;width:24px;height:24px;border-radius:50%;display:grid;place-items:center;color:#fff;box-shadow:0 0 0 2.5px #fff}
.ask-mark:empty{display:none}
.ask-mark .ic{stroke-width:3}
.ask-face[data-state="yes"] .ask-mark{background:var(--u-leaf)}
.ask-face[data-state="no"] .ask-mark{background:var(--muted)}
.ask-count{margin-top:10px;color:var(--coral-deep)}
.ask-clock{width:100%;height:6px;margin-top:4px;border-radius:999px;background:var(--table);overflow:hidden}
.ask-clock i{display:block;height:100%;border-radius:inherit;background:var(--coral);transform-origin:left}
@media (prefers-reduced-motion:reduce){.ask-face[data-state="wait"]::after{animation:none;scale:1.1;opacity:.7}}

/* Round table seats */
.seat{position:absolute;left:0;top:0;width:0;height:0;z-index:3;transition:transform .25s}
.seat.active{z-index:4}
.av{--cb:var(--ink);position:absolute;left:-20px;top:-20px;width:40px;height:40px;border-radius:50%;display:grid;place-items:center;font:800 16px/1 var(--display);color:#fff;background:var(--cb);transition:transform .25s}
.av.c1{--cb:var(--coral)}
/* In Uno every character has a suit colour of its own (--suit), so the first four seats get all four. On the light
   table and scores it sits in full on a pale wash of itself; on the picker's ink the badge goes white */
:is(.g-uno,.pal-uno) .av.ch-chip{--suit:var(--u-sea)}
:is(.g-uno,.pal-uno) .av.ch-dice{--suit:var(--u-sun)}
:is(.g-uno,.pal-uno) .av.ch-cheeky{--suit:var(--u-leaf)}
:is(.g-uno,.pal-uno) .av.ch-deck{--suit:var(--u-coral)}
:is(.g-uno,.pal-uno) .av.ch-sweetie{--suit:var(--u-leaf)}
:is(.g-uno,.pal-uno) .av.ch-sly{--suit:var(--u-sun)}
:is(.g-uno,.pal-uno) .av.ch-sleepy{--suit:var(--u-sea)}
:is(.g-uno,.pal-uno) .av.ch-shades{--suit:var(--u-coral)}
:is(.g-uno,.pal-uno) .av.ch-robot{--suit:var(--u-sea)}
:is(.g-uno,.pal-uno) .av{--cf:var(--suit);--cb:color-mix(in oklab,var(--suit) 16%,var(--paper))}
.g-uno .av{--cb:var(--paper)}
.pal-uno .tring circle{stroke:var(--ink)}
/* On a coloured background (the coral name bar and Rummy slide, the blue lobby) the badge goes white and the
   character takes the background's colour */
.g-rummy .av{--cb:var(--paper);--cf:var(--coral)}
/* On the white name bar the character wears coral on white */
.av.home-av{--cb:#fff;--cf:var(--coral)}
.lobby .av{--cb:var(--paper);--cf:var(--u-sea)}
/* The player characters from avatars.js fill the badge and blink now and then */
.av .char{display:block;width:100%;height:100%;overflow:visible}
.char .eyes{transform-box:fill-box;transform-origin:center;animation:ic-blink 4.5s ease-in-out infinite}
.char .zz{animation:char-zz 2.4s ease-in-out infinite}
@keyframes char-zz{0%,100%{opacity:0;transform:translate(-2px,2px)}50%{opacity:1;transform:none}}
/* The face a character pulls when a reaction hits it, alongside its morph in morphs.js. The badge behind it stays still */
.char .body{transform-box:view-box;transform-origin:center}
.av[class*="hit-"] .char .eyes{animation:none;transition:transform .15s}
.av.hit-laugh .char .eyes,.av.hit-clap .char .eyes{transform:scaleY(.25)}
.av.hit-flame .char .eyes{transform:scale(1.1,.45)}
.av.hit-shock .char .eyes{transform:scale(1.45)}
.av.hit-eyeroll .char .eyes{transform:translateY(-2.5px)}
.av.hit-joker .char .eyes{animation:char-dizzy .45s linear 2}
.char .mouth{transform-box:fill-box;transform-origin:center;transition:transform .15s}
.av.hit-laugh .char .mouth{transform:scale(1.5)}
.av.hit-shock .char .mouth{transform:scale(1.4)}
.av.hit-clap .char .mouth{transform:scale(1.25)}
.av.hit-eyeroll .char .mouth{transform:scaleX(.7)}
.seat:has(.av[class*="hit-"]){z-index:6}
@keyframes char-dizzy{to{transform:rotate(360deg)}}
.seat.active .av{transform:scale(1.14)}
.tring{position:absolute;left:-27px;top:-27px;width:54px;height:54px;transform:rotate(-90deg);pointer-events:none;overflow:visible}
.tring circle{fill:none;stroke:var(--coral);stroke-width:4;stroke-linecap:round;stroke-dasharray:151;stroke-dashoffset:151}
.av.c1 ~ .tring circle{stroke:var(--ink)}
.seat.warn .tring circle{stroke:var(--coral-deep);stroke-width:6}
.lab{position:absolute;left:-28px;width:56px;text-align:center;font:700 11px/1.15 var(--display);white-space:nowrap;pointer-events:none;overflow:hidden;text-overflow:ellipsis}
.lab small{display:block;font:500 11px/1.15 var(--display);color:var(--muted);font-variant-numeric:tabular-nums}
.lab.below{top:33px}
/* Beside the avatar the label centres on it, so a name with no place under it yet still lines up */
.lab.beside{left:34px;top:0;transform:translateY(-50%);width:60px;text-align:left}
.seat.me .lab{left:29px;top:0;transform:translateY(-50%);width:66px;text-align:left}
.seat.me .lab small{font:800 18px/1.05 var(--display);color:var(--coral)}
.cnt{position:absolute;left:9px;top:-25px;min-width:19px;height:19px;padding:0 5px;border-radius:10px;background:#fff;color:var(--ink);font:800 11px/19px var(--display);text-align:center;box-shadow:0 1px 4px color-mix(in srgb,var(--ink) 30%,transparent);pointer-events:none}
.seat.last .cnt,.cnt.last{background:var(--coral);color:#fff;animation:pulse 1s infinite}
.seat.last .av{animation:alarm 1s infinite}
@keyframes pulse{50%{transform:scale(1.28)}}
@keyframes alarm{50%{box-shadow:0 0 0 8px color-mix(in srgb,var(--u-coral) 28%,transparent)}}
.fan{position:absolute;left:0;top:0;width:0;height:0;transition:transform .25s}
.fan .card{position:absolute;left:-8.5px;top:-24px;transform-origin:50% 100%;transform:rotate(var(--r)) translateY(var(--y,0px));transition:transform .25s;box-shadow:0 0 0 .5px #fff}
.seat.thinking .fan .card{animation:shuffle 1.1s ease-in-out var(--d) infinite}
@keyframes shuffle{50%{transform:rotate(var(--r)) translateY(-5px)}}

/* The felt's fixtures */
.spot{position:absolute;left:0;top:0;width:200px;height:200px;border-radius:50%;background:radial-gradient(closest-side,#fff 0%,#fff 40%,rgba(255,255,255,.9) 62%,rgba(255,255,255,0) 100%);transition:transform .45s cubic-bezier(.3,.7,.2,1);pointer-events:none}

/* Melds */
.meld{position:absolute;left:0;top:0;display:flex;border-radius:6px;padding:0}
.meld .card{margin-left:calc(var(--w)*-.35);transform-origin:0 0}
.meld .card:first-child{margin-left:0}
.meld.fits{box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--coral);border-radius:7px}
.meld .who{position:absolute;left:-7px;top:-9px;width:14px;height:14px;border-radius:50%;display:grid;place-items:center;font:800 8px/1 var(--display);background:#fff;color:var(--ink);box-shadow:0 0 0 1px var(--line);z-index:1}

/* Stock and pile */
.mid{position:absolute;left:50%;transform:translate(-50%,-50%);display:flex;align-items:center;gap:12px;z-index:2}
.stock{position:relative;display:block;border-radius:6px}
.stock .card:nth-child(1){position:absolute;left:2px;top:-2px}
.stock .card:nth-child(2){position:relative}
/* Tapping counts here: a ring pulses round the shape the cards make. A filter can follow their tilt where a box-shadow can't, and each pair of offsets spreads it one way. It sits on a copy of the cards that only fades, as iOS Safari can leave an animated filter unpainted */
.stock .cards{display:block;position:relative}
.ring{--ring-c:color-mix(in srgb,var(--u-coral) 60%,#fff);--card-ring:drop-shadow(1px 0 #fff) drop-shadow(-1px 0 #fff) drop-shadow(0 1px #fff) drop-shadow(0 -1px #fff) drop-shadow(1.5px 0 var(--ring-c)) drop-shadow(-1.5px 0 var(--ring-c)) drop-shadow(0 1.5px var(--ring-c)) drop-shadow(0 -1.5px var(--ring-c))}
.ring{display:none;position:absolute;left:0;top:0;width:100%;height:100%;z-index:-1;pointer-events:none;opacity:0;filter:var(--card-ring)}
.hot>.ring{display:block;animation:hot-ring 1.8s ease-in-out infinite}
@keyframes hot-ring{50%{opacity:1}}
.stock .n{position:absolute;left:50%;bottom:-7px;transform:translateX(-50%);min-width:22px;padding:0 5px;height:16px;border-radius:9px;background:#fff;color:var(--ink);font:800 10px/16px var(--display);box-shadow:0 1px 3px color-mix(in srgb,var(--ink) 25%,transparent);z-index:1}
@keyframes hot{50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--u-coral) 32%,transparent)}}
.pile{position:relative;height:59px;width:86px;display:block;border-radius:6px}
.pile .pc{position:absolute;top:0;transition:left .22s cubic-bezier(.3,.7,.2,1)}
.pile .cards{position:absolute;left:0;top:0;width:100%;height:100%;display:block}
/* No cards to ring when the pile is empty, so a card-sized space pulses where the discard will land */
.pile.hot .cards:empty{width:42px;height:59px;border-radius:7px;animation:hot 1.8s ease-in-out infinite}
.pile .n{position:absolute;right:-6px;bottom:-7px;min-width:22px;padding:0 5px;height:16px;border-radius:9px;background:#fff;color:var(--ink);font:800 10px/16px var(--display);box-shadow:0 1px 3px color-mix(in srgb,var(--ink) 25%,transparent);z-index:6}

/* Uno: the colour in play rings the top card, an arrow by the stock shows which way play goes */
.unotable .pile .pc:last-of-type .card{box-shadow:0 0 0 2.5px #fff,0 0 0 5.5px var(--now,transparent);transition:box-shadow .2s}
.dirmark{position:absolute;left:50%;width:26px;height:26px;margin:-13px 0 0 -112px;color:var(--coral);opacity:.55;z-index:2;pointer-events:none}
.dirmark svg{width:100%;height:100%;display:block;transition:transform .3s}
.dirmark.ccw svg{transform:scaleX(-1)}
.unotable .hc .card{transition:--w .24s cubic-bezier(.3,.7,.2,1),box-shadow .14s,translate .2s,filter .2s}
.unotable .hc.dim .card{translate:0 12px;filter:saturate(.55) brightness(.92)}
.shout{position:absolute;left:0;top:0;font:900 24px/1 var(--display);letter-spacing:-.02em;color:var(--coral);-webkit-text-stroke:4px #fff;paint-order:stroke fill;white-space:nowrap;z-index:4}
.colours{display:grid;grid-template-columns:1fr 1fr;gap:10px;width:100%;margin-top:12px}
.colour{display:flex;flex-direction:column;align-items:flex-start;gap:2px;padding:16px 14px;border-radius:16px;background:var(--c);color:#fff;text-align:left;transition:transform .12s}
.colour:active{transform:scale(.95)}
.colour.advised{box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--online)}
.colour b{font:800 18px/1 var(--display)}
.colour small{font:600 12px/1.2 var(--body);opacity:.85}

/* Your side */
/* Bottom-aligned, so the dock grows up from where the sort button sits when its drawer opens */
.row{position:absolute;left:100px;right:12px;height:52px;padding-bottom:3px;display:flex;align-items:flex-end;justify-content:flex-end;gap:6px;z-index:6}
/* Nothing on screen spells out your move; this line is only read out by screen readers */
.say{position:absolute;width:1px;height:1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;pointer-events:none}
/* The line under the piles, for passing messages. Two lines fit above your melds. */
.note{position:absolute;left:50%;width:220px;margin-left:-110px;text-align:center;white-space:pre-line;font:700 13px/1.25 var(--display);color:var(--ink);text-wrap:balance;z-index:2;pointer-events:none}
.dock{display:flex;flex-direction:column;align-items:center;padding:4px;border-radius:999px;background:#fff}
.tool{width:38px;height:38px;flex:none;border-radius:50%;display:grid;place-items:center;color:var(--ink);transition:background .15s,color .15s,transform .12s}
.tool:active{transform:scale(.88)}
@media (hover:hover){.tool:hover{background:var(--table)}}
.tool.on{background:var(--ink);color:#fff}
.tool.off{color:var(--muted)}
.tool.solo{width:46px;height:46px;background:#fff}
/* The dock's drawer opens upward over the felt into the tools used less often */
.drawer{display:grid;grid-template-rows:0fr;transition:grid-template-rows .25s cubic-bezier(.3,.7,.2,1)}
.drawer.open{grid-template-rows:1fr}
.drawer > div{overflow:hidden;display:flex;flex-direction:column;gap:2px}
.drawer.open > div{padding-bottom:2px}
.hand{position:absolute;left:0;right:0;bottom:0;z-index:5;touch-action:none}
.hand.catching{z-index:7}
.hand .flying{pointer-events:none}
.hc{display:block;position:absolute;left:50%;bottom:-6px;transform-origin:50% 100%;transition:transform .24s cubic-bezier(.3,.7,.2,1);border-radius:10px}
.hc .card{transition:--w .24s cubic-bezier(.3,.7,.2,1),box-shadow .14s,translate .2s}
.hc.arriving{visibility:hidden;transition:none}
.hc.sel .card{box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--ink)}
.hc.must .card{box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--coral-deep)}
.hc.hint .card{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--online)}
.hc.sel.melds .card{box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--online)}
.hc.advised .card{translate:0 -10px;box-shadow:0 0 0 2.5px #fff,0 0 0 5px var(--online)}
.tool.hot{animation:hot 1s infinite}
.hc.dragging{visibility:hidden}
.float{position:absolute;left:0;top:0;font:900 26px/1 var(--display);color:var(--coral);-webkit-text-stroke:3px #fff;paint-order:stroke fill;z-index:3}
.shock{position:absolute;left:0;top:0;width:40px;height:40px;margin:-20px;border-radius:50%;border:3px solid var(--coral)}
.toast{position:absolute;left:0;right:0;top:var(--toast,48px);width:fit-content;max-width:92%;margin-inline:auto;background:var(--ink);color:#fff;padding:8px 14px;border-radius:999px;font:700 12px/1.2 var(--display);text-align:center;z-index:15;pointer-events:none}
.toss{position:absolute;left:0;top:0;width:48px;height:48px;z-index:12;pointer-events:none}
.toss-b{position:absolute;inset:0;display:grid;place-items:center;color:var(--coral-deep);filter:drop-shadow(0 3px 4px color-mix(in srgb,var(--ink) 25%,transparent));--ic:44px}
/* The pieces that burst off a thrown icon as it reacts, set off from ui.js */
.hitbit{position:absolute;z-index:5;overflow:visible;pointer-events:none;opacity:0}
.out{position:absolute;inset:0;z-index:25;display:grid;place-items:center;text-align:center;background:rgba(255,255,255,.86)}
.out b{display:block;font:900 110px/.9 var(--display);color:var(--coral);letter-spacing:-.03em}
.out span{font:600 15px var(--body)}

/* Sheets */
.scrim{position:absolute;inset:0;background:color-mix(in srgb,var(--ink) 28%,transparent);z-index:30}
.sheet{position:absolute;left:0;right:0;bottom:0;z-index:31;background:#fff;border-radius:24px 24px 0 0;padding:20px 20px 26px;display:flex;flex-direction:column;gap:14px;max-height:82%;overflow-y:auto;scrollbar-width:none}
.sheet h3{margin:0;font:800 20px/1 var(--display)}
.sheet .sub{color:var(--muted);font-size:14px;margin-top:4px}
.sheet .mset{display:flex;flex-wrap:wrap;gap:12px}
.sheet .bigmeld{display:flex}
.sheet .bigmeld .card + .card{margin-left:-20px}
.reacts{display:flex;justify-content:space-between;gap:4px}
.reacts button{width:46px;height:46px;border-radius:50%;background:var(--coral-wash);color:var(--coral-on-wash);display:grid;place-items:center;flex:none;--ic:28px;transition:transform .12s}
.reacts button:active{transform:scale(.88)}
/* The pile's sheet and the table's questions: the invite's layout again, with the cards or the answers where the choices would be */
:is(.pile-ask,.pick-ask) .sub{margin-top:0;text-wrap:pretty}
.pilegrid{display:flex;flex-wrap:wrap;justify-content:center;gap:6px;width:100%;margin:12px 0}
.pilegrid button{border-radius:8px;position:relative;transition:transform .14s cubic-bezier(.3,.7,.2,1)}
.pilegrid button.taking{transform:translateY(-5px)}
.pilegrid button.chosen .card{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--ink)}
.pilegrid button.dead .card{opacity:.38}
.pilegrid button.advised:not(.chosen) .card{box-shadow:0 0 0 2px #fff,0 0 0 4px var(--online)}
.choice{display:flex;align-items:center;gap:12px;padding:12px 14px;border-radius:18px;background:var(--table);font:800 16px/1.15 var(--display);text-align:left;width:100%;transition:transform .12s}
.choice:active{transform:scale(.97)}
.choice .fanned{display:flex;flex:none}
.choice .fanned .card + .card{margin-left:-10px}
.seg{display:flex;background:var(--coral-wash);border-radius:999px;padding:3px;flex:none}
.seg button{padding:7px 10px;border-radius:999px;font:700 12px/1 var(--display);color:var(--coral-on-wash);white-space:nowrap;transition:background .15s,color .15s}
.seg button[aria-pressed="true"]{background:var(--coral);color:#fff}

/* Table rules: the invite's layout, with a tab for everything global and one for each game, each tab in its own page's colour */
.sheet:has(>.rt){overflow:hidden;max-height:90%}
/* The tab's colours are real colours to the browser, so the sheet's own parts can fade from one tab's to the next. Each panel wears its own tab's, so one leaving keeps them on its way out. */
@property --acc{syntax:"<color>";inherits:true;initial-value:#000}
@property --acc-wash{syntax:"<color>";inherits:true;initial-value:#fff}
@property --acc-on{syntax:"<color>";inherits:true;initial-value:#000}
:is(.rt,.rt-panel){--acc:var(--u-sea);--acc-wash:color-mix(in oklab,var(--u-sea) 12%,#fff);--acc-on:var(--sea-deep)}
.rt{display:flex;flex-direction:column;gap:14px;min-height:0;transition:--acc .3s,--acc-wash .3s,--acc-on .3s}
:is(.rt,.rt-panel)[data-tab="rummy"]{--acc:var(--coral);--acc-wash:var(--coral-wash);--acc-on:var(--coral-on-wash)}
:is(.rt,.rt-panel)[data-tab="uno"]{--acc:var(--ink);--acc-wash:color-mix(in oklab,var(--ink) 8%,#fff);--acc-on:var(--ink)}
.rt-head{flex:none;display:flex;align-items:center;justify-content:center;gap:12px}
.sheet .rt-head h3{font-size:22px;line-height:1.1}
.rt-hero{position:relative;display:grid;place-items:center}
.rt-hero>.leaving{position:absolute;left:50%;top:50%;translate:-50% -50%;pointer-events:none}
.rt-disc{width:38px;height:38px;border-radius:50%;background:var(--acc-wash);color:var(--acc);display:grid;place-items:center;--ic:20px}
.rt-hero-fan{display:flex}
.rt-hero-fan .card{margin:0 -3px}
.rt-hero-fan .card:first-child{rotate:-10deg;translate:0 2px}
.rt-hero-fan .card:last-child{rotate:10deg;translate:0 2px}
.rt-hero-fan .card:nth-child(2){z-index:1}
.seg.rt-tabs{flex:none;display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);position:relative;background:var(--acc-wash)}
.rt-tabs button{position:relative;display:flex;align-items:center;justify-content:center;gap:6px;padding:8px 4px;font-size:14px;color:var(--acc-on);--ic:18px;transition:color .2s}
.rt-tabs button[aria-pressed="true"]{background:none;color:#fff}
/* The one marker behind the tabs, which runs to whichever is picked */
.rt-thumb{position:absolute;left:3px;top:3px;bottom:3px;width:calc((100% - 6px)/var(--n));border-radius:999px;background:var(--acc);translate:calc(var(--i,0)*100%) 0;transition:translate .34s cubic-bezier(.3,1.15,.5,1)}
/* A little Wild for the Uno tab, and the same colours on it whichever tab is showing */
.rt-wheel{flex:none;width:16px;height:16px;border-radius:50%;box-shadow:0 0 0 1.5px #fff;background:conic-gradient(var(--u-coral) 0 25%,var(--u-sun) 0 50%,var(--u-leaf) 0 75%,var(--u-sea) 0)}
.rt-stage{position:relative;flex:0 1 auto;min-height:0;display:flex;overflow:hidden;margin:0 -20px}
.rt-panel{flex:1;min-width:0;display:flex;flex-direction:column;gap:14px;padding:4px 20px 24px;overflow:hidden auto;scrollbar-width:none;overscroll-behavior:contain}
.rt-panel.leaving{position:absolute;left:0;right:0;top:0;bottom:0;pointer-events:none}
/* A soft edge where the list runs on below the sheet */
.rt-stage::after{content:"";position:absolute;left:0;right:0;bottom:0;height:22px;background:linear-gradient(transparent,#fff);pointer-events:none}
/* Most rows read the same way: their picture, their name, their control. Space alone marks where a new group starts. */
.rt-row{flex:none;display:grid;grid-template-columns:48px minmax(0,1fr) auto;column-gap:12px;align-items:center;min-height:46px}
.rt-apart{margin-top:14px}
.rt-row>b{font:800 16px/1.2 var(--display);text-wrap:balance}
.rt-art{display:grid;place-items:center}
.rt-row>.rt-art{height:44px;color:var(--acc)}
.rt-tiles{position:relative;display:grid;grid-auto-flow:column;grid-auto-columns:auto;padding:3px;border-radius:999px;background:var(--acc-wash)}
.rt-tile{position:relative;display:flex;justify-content:center;align-items:center;height:36px;min-width:38px;padding:0 10px;border-radius:999px;color:var(--acc-on);font:800 14px/1 var(--display);white-space:nowrap;transition:background .15s,color .15s,transform .12s}
.rt-tile:active{transform:scale(.97)}
.rt-tile[aria-pressed="true"]{background:var(--acc);color:#fff}
/* In a row of small choices the colour travels between them, on this marker, instead of fading */
.rt-row:not(.rt-cards) .rt-tile{transition:color .15s,transform .12s}
.rt-tile.rt-sliding[aria-pressed="true"]{background:none}
.rt-tile-thumb{position:absolute;border-radius:999px;background:var(--acc)}
/* Cards and toggles: big enough to see what a choice does. The picture sits on white, so a card reads the same whether its tile is picked or not. */
.rt-row.rt-cards{grid-template-columns:minmax(0,1fr);row-gap:10px}
.rt-cards>.rt-tiles{grid-auto-columns:minmax(0,1fr);gap:10px;padding:0;border-radius:0;background:none}
.rt-cards .rt-tile,.rt-toggle{flex-direction:column;align-items:stretch;gap:8px;height:auto;min-width:0;padding:6px 6px 11px;border-radius:18px;background:var(--acc-wash)}
.rt-cards .rt-tile[aria-pressed="true"]{background:var(--acc)}
.rt-cards .rt-art,.rt-toggle .rt-art{height:66px;border-radius:13px;background:#fff;overflow:hidden;color:var(--acc);--ic:34px}
.rt-pair{flex:none;display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:10px}
.rt-toggle[aria-checked="true"]{background:var(--acc);color:#fff}
.rt-foot{display:flex;align-items:center;justify-content:space-between;gap:6px;padding:0 6px 0 8px}
.rt-mini{position:relative;flex:none;width:30px;height:18px;border-radius:999px;background:color-mix(in oklab,var(--acc) 22%,#fff);transition:background .15s}
.rt-mini::after{content:"";position:absolute;left:2px;top:2px;width:14px;height:14px;border-radius:50%;background:#fff;transition:translate .16s cubic-bezier(.3,1.3,.5,1)}
.rt-toggle[aria-checked="true"] .rt-mini{background:#fff}
.rt-toggle[aria-checked="true"] .rt-mini::after{background:var(--acc);translate:12px 0}
.rt-flip{position:relative;width:44px;height:26px;border-radius:999px;background:color-mix(in oklab,var(--acc) 22%,#fff);transition:background .15s,transform .12s}
.rt-flip:active{transform:scale(.96)}
.rt-flip i{position:absolute;left:3px;top:3px;width:20px;height:20px;border-radius:50%;background:#fff;box-shadow:0 1px 2px color-mix(in srgb,var(--ink) 30%,transparent);transition:translate .16s cubic-bezier(.3,1.3,.5,1)}
.rt-flip[aria-checked="true"]{background:var(--acc)}
.rt-flip[aria-checked="true"] i{translate:18px 0}
.rt-fan{display:flex}
.rt-fan .card{box-shadow:0 0 0 1.5px #fff}
.rt-fan .card + .card{margin-left:calc(var(--w)*-.45)}
.rt-tight .card + .card{margin-left:calc(var(--w)*-.62)}
.rt-dim{opacity:.38}
.rt-struck{position:relative}
.rt-struck::after{content:"";position:absolute;left:-4px;right:-4px;top:50%;height:2.5px;border-radius:2px;background:var(--ink);rotate:-35deg}
.rt-fan .card.rt-lit{box-shadow:0 0 0 1.5px #fff,0 0 0 3.5px var(--online)}
.rt-lifted{translate:0 2px}
.rt-lifted .card.rt-lit{translate:0 -4px}
.rt-ring{width:30px;height:30px;fill:none;stroke-linecap:round;stroke-width:6}
.rt-ring .band{stroke:color-mix(in oklab,var(--acc) 20%,#fff)}
.rt-ring :is(.fill,.wedge,.rim){stroke:var(--acc)}
.rt-ring .wedge{stroke-linecap:butt;stroke-width:18}
.rt-ring .rim{stroke-width:4}
.rt-ring.rt-dim{opacity:.5}
.rt-ace{display:flex;align-items:center;gap:5px}
.rt-pips{display:grid;grid-template-columns:repeat(3,5px);gap:2px}
.rt-pips i{height:5px;border-radius:50%;background:var(--acc)}
.rt-star{position:relative}
.rt-star svg{position:absolute;right:-9px;top:-7px;width:18px;height:18px;fill:var(--u-sun)}
.rt-icon{--ic:26px}
.rt-icon.off{opacity:.5}
/* Bars that climb with the bonus, the ones it has reached filled in */
.rt-bars{display:flex;align-items:flex-end;gap:3px;height:28px}
.rt-bars i{width:8px;border-radius:3px;background:color-mix(in oklab,var(--acc) 20%,#fff)}
.rt-bars i.on{background:var(--acc)}
.rt-bars i:nth-child(1){height:10px}
.rt-bars i:nth-child(2){height:19px}
.rt-bars i:nth-child(3){height:28px}
/* What the last choice means, only once there is one. Its room is kept, so the sheet doesn't move. */
.rt-hint{flex:none;min-height:16px;margin-block:-8px -2px;font:600 12.5px/16px var(--body);color:var(--muted);text-align:center;text-wrap:balance}
.rt>.pill{flex:none;align-self:stretch;background:var(--acc);color:#fff;transition:transform .12s}
@media (prefers-reduced-motion:reduce){.rt,.rt-thumb,.rt-tabs button,.rt-tile,.rt-row:not(.rt-cards) .rt-tile,.rt>.pill,.rt-flip,.rt-flip i,.rt-mini,.rt-mini::after{transition:none}}

/* Stats: a full colour page like the lobby, in the one deck colour no other screen wears. Your numbers sit
   straight on it; lists and the podium are white. */
:root{--sun-deep:color-mix(in oklab,var(--u-sun),var(--ink) 24%);--sun-light:color-mix(in oklab,var(--u-sun),var(--paper) 22%);--sun-wash:color-mix(in oklab,var(--u-sun) 14%,var(--paper))}
@property --p{syntax:"<number>";inherits:true;initial-value:0}
.stats{position:absolute;inset:0;display:flex;flex-direction:column;z-index:2;color:#fff;overflow:hidden;touch-action:pan-y;-webkit-user-select:none;user-select:none}
.stats::before{content:"";position:absolute;inset:0;z-index:-1;background:radial-gradient(120% 70% at 50% 30%,var(--sun-light) 0,var(--u-sun) 55%,var(--sun-deep) 100%)}
.stats .av{--cb:var(--paper);--cf:var(--u-sun)}
.st-head{flex:none;display:flex;flex-direction:column;align-items:center;gap:12px;padding:24px 16px 12px}
.st-head h1{margin:0;text-align:center;font:900 26px/1 var(--display);letter-spacing:-.02em}
/* Faint arrows at the sides: there is another game to swipe to */
.st-arrow{position:absolute;top:50%;margin-top:-32px;display:grid;place-items:center;width:24px;height:64px;color:#fff;opacity:.55;transition:opacity .2s,transform .12s}
.st-arrow svg{width:20px;height:20px}
.st-arrow.prev{left:2px}
.st-arrow.next{right:2px}
.st-arrow.prev svg{rotate:-90deg}
.st-arrow.next svg{rotate:90deg}
.st-arrow:active{transform:scale(.9);opacity:1}
.st-tabs{background:rgba(255,255,255,.2)}
.st-tabs button{padding:9px 22px;font-size:14px;color:#fff}
.st-tabs button[aria-pressed="true"]{background:#fff;color:var(--sun-deep)}
.st-body{container-type:inline-size;position:relative;flex:1;min-height:0;overflow-x:hidden;overflow-y:auto;padding:0 0 calc(28px + env(safe-area-inset-bottom));scrollbar-width:none;mask:linear-gradient(#000 calc(100% - 28px),transparent)}
.st-page{display:flex;flex-direction:column;gap:12px;width:min(460px,100% - 48px);min-height:100%;margin:0 auto;padding-top:6px}
.st-status{position:absolute;left:50%;bottom:calc(16px + env(safe-area-inset-bottom));transform:translateX(-50%);max-width:90%;padding:8px 14px;border-radius:999px;background:var(--ink);color:#fff;font:700 12px/1.2 var(--display);text-align:center;white-space:nowrap}
.st-status:empty{display:none}

/* You: your character inside a ring that fills to your win rate */
.st-hero{display:flex;flex-direction:column;align-items:center;gap:8px;text-align:center;padding-top:4px}
.st-ring{width:136px;height:136px;padding:10px;border-radius:50%;background:conic-gradient(#fff calc(var(--p) * 1%),rgba(255,255,255,.24) 0);animation:st-ring 1s cubic-bezier(.3,.7,.2,1) .2s backwards,lb-float 4s ease-in-out 1.2s infinite}
@keyframes st-ring{from{--p:0}}
.st-ring .av.st-me{position:static;width:100%;height:100%;box-shadow:0 0 0 4px var(--u-sun),0 10px 22px color-mix(in srgb,var(--sun-deep) 45%,transparent);transition:none}
.st-hero h2{margin:4px 0 0;max-width:100%;font:900 26px/1.05 var(--display);letter-spacing:-.02em;overflow-wrap:anywhere}
.ic-link.play .a{animation:ic-slide-r .42s cubic-bezier(.3,.7,.2,1)}
.ic-link.play .b{animation:ic-slide-l .42s cubic-bezier(.3,.7,.2,1)}
/* Your numbers sit straight on the colour */
.st-big{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));padding:14px 4px 18px}
.st-big>div{display:flex;flex-direction:column;align-items:center;gap:6px;text-align:center}
.st-big b{font:900 40px/1 var(--display);letter-spacing:-.03em;font-variant-numeric:tabular-nums;text-shadow:0 2px 12px color-mix(in srgb,var(--sun-deep) 50%,transparent)}
.st-big span{font:700 12px/1.2 var(--body);opacity:.9}
/* The smaller numbers: three to a row, each with a picture of what it counts */
.st-tiles{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:18px 8px;padding:18px 4px 6px}
.st-tile{display:flex;flex-direction:column;align-items:center;gap:5px;text-align:center}
.st-tic{--ic:20px;display:grid;place-items:center;width:40px;height:40px;margin-bottom:2px;border-radius:50%;background:rgba(255,255,255,.2)}
.st-tile b{font:900 20px/1 var(--display);font-variant-numeric:tabular-nums;white-space:nowrap}
.st-tile b small{font:800 11px/1 var(--display)}
.st-tile span{font:700 11px/1.2 var(--body);opacity:.85}
/* Meters: a white bar filling across a faint one, straight on the colour */
.st-meters{display:flex;flex-direction:column;gap:14px;padding:16px 4px 18px}
.st-meter{display:flex;flex-direction:column;gap:6px}
.st-mlab{display:flex;justify-content:space-between;align-items:baseline;font:800 14px/1 var(--display)}
.st-mlab b{font:900 18px/1 var(--display);font-variant-numeric:tabular-nums}
.st-bar{height:10px;border-radius:999px;background:rgba(255,255,255,.24);overflow:hidden}
.st-bar i{display:block;height:100%;width:calc(var(--p) * 1%);border-radius:inherit;background:#fff;transform-origin:left;animation:st-grow-x .9s cubic-bezier(.3,.7,.2,1) .25s backwards}
.st-meter small{font:700 11px/1.2 var(--body);opacity:.85}
@keyframes st-grow-x{from{transform:scaleX(0)}}
/* Form: a bar for each recent game, as high as you got towards the target */
.st-form{padding:16px 4px 18px}
.st-fhead{display:flex;align-items:baseline;gap:6px;margin-bottom:12px}
.st-fhead b{font:900 20px/1 var(--display)}
.st-fhead span{font:700 12px/1.2 var(--body);opacity:.85}
.st-bars{display:grid;grid-auto-flow:column;grid-auto-columns:minmax(0,1fr);gap:5px;height:132px}
.st-col{display:flex;flex-direction:column;align-items:center;gap:4px;min-width:0}
.st-col small{font:800 9px/1 var(--display);opacity:.85;font-variant-numeric:tabular-nums;white-space:nowrap}
.st-track{position:relative;flex:1;width:100%;max-width:22px;border-radius:6px;background:rgba(255,255,255,.2);overflow:hidden}
.st-track i{position:absolute;left:0;right:0;bottom:0;height:calc(var(--h) * 1%);border-radius:6px;background:rgba(255,255,255,.45);transform-origin:bottom;animation:st-grow-y .7s cubic-bezier(.3,.7,.2,1) calc(.2s + var(--i) * 40ms) backwards}
.st-col.won .st-track i{background:#fff}
.st-col em{font:900 10px/1 var(--display);font-style:normal;opacity:.6}
.st-col.won em,.st-col.won small{opacity:1}
@keyframes st-grow-y{from{transform:scaleY(0)}}
/* Leaderboard rows: wins against the leader's */
.st-share{display:block;height:4px;margin-top:3px;border-radius:999px;background:var(--table);overflow:hidden}
.st-share i{display:block;height:100%;width:calc(var(--p) * 1%);border-radius:inherit;background:var(--u-sun);transform-origin:left;animation:st-grow-x .8s cubic-bezier(.3,.7,.2,1) .3s backwards}
.st-empty{padding:28px 20px;text-align:center;font:700 15px/1.35 var(--body);opacity:.92;text-wrap:balance}
.st-empty.small{padding:10px 20px;font-size:14px}
.st-wait{display:flex;justify-content:center;gap:8px;padding:80px 0}
.st-wait span{width:10px;height:10px;border-radius:50%;background:#fff;animation:st-wait 1s ease-in-out infinite}
.st-wait span:nth-child(2){animation-delay:.15s}
.st-wait span:nth-child(3){animation-delay:.3s}
@keyframes st-wait{50%{transform:translateY(-10px);opacity:.5}}

/* Lists: one white sheet from edge to edge and down to the bottom of the page, a row a game or a player. The rows keep to the page's column. */
.st-body:has(.st-list){padding-bottom:0;mask:none}
.st-list{--gut:max(24px,calc(50cqw - 230px));flex:1 0 auto;display:flex;flex-direction:column;width:100cqw;margin-left:calc(50% - 50cqw);padding:0 0 calc(20px + env(safe-area-inset-bottom));border-radius:24px 24px 0 0;background:#fff;color:var(--ink);overflow:clip;box-shadow:0 -10px 30px color-mix(in srgb,var(--sun-deep) 34%,transparent)}
/* The list scrolls with the page, so once the sheet reaches the top this edge stays behind: the rows pass under it and its corners, painted in the page colour, keep the sheet looking rounded */
.st-list::before{content:"";position:sticky;top:0;z-index:1;flex:none;height:24px;margin-bottom:-10px;background:radial-gradient(circle at 100% 100%,#fff 23.5px,var(--u-sun) 24px) 0 0/24px 24px no-repeat,radial-gradient(circle at 0 100%,#fff 23.5px,var(--u-sun) 24px) 100% 0/24px 24px no-repeat,#fff}
.st-what{min-width:0;display:flex;flex-direction:column;gap:3px}
.st-what b{font:800 14px/1.15 var(--display);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-what small{font:600 12px/1.2 var(--body);color:var(--muted);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-game{display:grid;grid-template-columns:26px minmax(0,1fr) auto auto;align-items:center;gap:10px;padding:11px var(--gut)}
.st-kind{width:26px;height:36px;border-radius:6px;display:grid;place-items:center;background:var(--coral);color:#fff;font:900 14px/1 var(--display);rotate:-6deg;box-shadow:0 3px 8px color-mix(in srgb,var(--ink) 18%,transparent)}
.st-kind.uno{background:var(--ink);rotate:6deg}
.st-faces{display:flex}
.st-faces .av{position:static;width:24px;height:24px;box-shadow:0 0 0 2px #fff;transition:none;--cb:var(--sun-wash);--cf:var(--u-sun)}
.st-faces .av+.av{margin-left:-8px}
.st-game em{min-width:44px;padding:5px 8px;border-radius:999px;background:var(--table);color:var(--muted);font:800 11px/1 var(--display);font-style:normal;letter-spacing:.06em;text-transform:uppercase;text-align:center}
.st-game.won em{background:var(--u-leaf);color:#fff}

/* Everyone: the top three on a podium, bobbing like the lobby's bubbles, then the rest in a list */
.st-podium{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));align-items:end;gap:8px;padding-top:10px}
.st-step{display:flex;flex-direction:column;align-items:center;min-width:0;text-align:center}
.st-float{display:flex;flex-direction:column;align-items:center;gap:3px;max-width:100%;padding-bottom:10px;animation:lb-float 4s ease-in-out var(--d,0s) infinite}
.st-step .av{position:static;width:60px;height:60px;margin-bottom:4px;box-shadow:0 0 0 3px #fff,0 10px 22px color-mix(in srgb,var(--sun-deep) 55%,transparent);transition:none}
.st-step.p1 .av{width:78px;height:78px}
.st-step b{max-width:100%;font:800 14px/1.1 var(--display);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.st-step small{font:700 12px/1.2 var(--body);opacity:.9}
.st-block{align-self:stretch;display:grid;justify-items:center;padding-top:10px;border-radius:16px 16px 6px 6px;background:#fff;color:var(--sun-deep);font:900 30px/1 var(--display);height:54px;box-shadow:0 14px 30px color-mix(in srgb,var(--sun-deep) 34%,transparent)}
.st-step.p1 .st-block{height:86px;font-size:36px}
.st-step.p2 .st-block{height:68px}
.st-step.me b{text-decoration:underline;text-decoration-thickness:2px;text-underline-offset:3px}
.st-row{display:grid;grid-template-columns:22px 36px minmax(0,1fr) auto;align-items:center;gap:10px;padding:10px var(--gut)}
.st-row .st-rank{font:800 14px/1 var(--display);color:var(--muted);text-align:center;font-variant-numeric:tabular-nums}
.st-row .av{position:static;width:36px;height:36px;transition:none;--cb:var(--sun-wash);--cf:var(--u-sun)}
.st-row strong{display:flex;flex-direction:column;align-items:flex-end;font:900 20px/1 var(--display);font-variant-numeric:tabular-nums}
.st-row strong span{font:700 10px/1.2 var(--body);color:var(--muted)}
.st-row.me{background:var(--sun-wash)}

/* Linking devices, on the white sheet in the page's colour */
.linksheet{display:flex;flex-direction:column;gap:14px}
.ls-code{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:14px 14px 14px 18px;border-radius:18px;background:var(--sun-wash)}
.ls-code b{font:900 30px/1 var(--display);letter-spacing:.08em;font-variant-numeric:tabular-nums}
.linksheet .pill.plain{background:var(--sun-wash);color:var(--sun-deep)}
.ls-code .pill.plain{background:#fff}
.namebar.ls-bar{max-width:none}
.ls-bar .name{padding-left:52px;letter-spacing:.12em;text-transform:uppercase}
.ls-bar .name::placeholder{letter-spacing:0;text-transform:none}
.ls-msg{margin:-4px 0 0;font:600 14px/1.3 var(--body);color:var(--coral-deep);text-align:center}
.ls-msg.good{color:var(--leaf-deep)}
.ls-msg:empty{display:none}
.ls-unlink{display:flex;align-items:center;justify-content:space-between;gap:10px;font:600 14px/1.2 var(--body);color:var(--muted)}
.ls-unlink:empty{display:none}
@media (max-width:759px){
  .stats{top:calc(-1 * var(--bar))}
  .st-head{padding-top:calc(24px + var(--bar))}
  body[data-page="stats"]{--page:var(--u-sun)}
}
@media (prefers-reduced-motion:reduce){.st-ring,.st-float,.st-wait span,.st-bar i,.st-track i,.st-share i{animation:none}}

/* Round score: a circular race to the target, then each player's cards turn over */
#scorescreen{--acc:var(--coral);--acc-wash:var(--coral-wash);--acc-on:var(--coral-on-wash);position:absolute;inset:0;display:flex;flex-direction:column}
#scorescreen.pal-uno{--acc:var(--ink);--acc-wash:color-mix(in oklab,var(--ink) 8%,#fff);--acc-on:var(--ink)}
.hero{position:relative;flex:none;overflow:hidden}
.race{position:absolute;left:50%;z-index:1}
.race svg{position:absolute;inset:0;overflow:visible}
.race .band{fill:none;stroke:var(--table);stroke-width:46}
.race .tick{stroke:#fff;stroke-width:2}
.race .flag{stroke:var(--ink);stroke-width:3}
.race .sarc{fill:none;stroke-width:6}
.flaglab{position:absolute;left:50%;top:-20px;transform:translateX(-50%);font:800 12px/1 var(--display);letter-spacing:.06em;color:var(--ink)}
.rav{left:50%;top:50%;width:24px;height:24px;margin:-12px;font-size:11px;box-shadow:0 0 0 2px #fff;transition:none}
.rav.now{z-index:2;box-shadow:0 0 0 2px #fff,0 0 0 4px var(--ink)}
.rc{position:absolute;left:50%;top:50%;transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;text-align:center;white-space:nowrap}
.rc .num{font-weight:900;font-family:var(--display);line-height:1;letter-spacing:-.04em;color:var(--acc);font-variant-numeric:tabular-nums;transition:color .15s}
.rc .num.down{color:var(--ink)}
.rc .sub{font:600 12px/1.2 var(--body);color:var(--muted);margin-top:3px;min-height:14px}
/* The sheet: the same white sheet as the stats lists, one player's row over a strip of everyone, in the game's own colour */
.scoresheet{position:relative;z-index:2;flex:none;margin-top:auto;display:flex;flex-direction:column;background:var(--paper);border-radius:24px 24px 0 0;box-shadow:0 -10px 30px color-mix(in srgb,var(--ink) 14%,transparent)}
.spotlight{position:relative;flex:none;height:68px;margin:8px 8px 0;overflow:hidden}
.srow{position:absolute;inset:0;display:grid;grid-template-columns:44px minmax(0,1fr) auto;column-gap:10px;align-items:center;padding:0 6px;transform:translateX(105%)}
.srow.shown{transform:none}
.srow .av{position:static;width:44px;height:44px;font-size:18px;transition:none}
/* Everyone in order, with the one marker behind whoever is being counted */
.strip{position:relative;flex:none;display:flex;justify-content:center;margin:4px 8px 0}
.strip-mark{position:absolute;left:0;top:0;bottom:0;border-radius:16px;background:var(--acc-wash);transition:transform .46s cubic-bezier(.3,.7,.2,1)}
.sface{position:relative;flex:1 1 0;min-width:0;max-width:76px;display:flex;flex-direction:column;align-items:center;gap:4px;padding:8px 0 6px;border-radius:16px}
.sface[disabled]{cursor:default}
.sface.lift{z-index:2}
.sface .av{position:static;width:34px;height:34px;font-size:14px;transition:none}
.sface .tot{font:900 15px/1 var(--display);letter-spacing:-.02em;font-variant-numeric:tabular-nums;transition:color .2s}
.sface.lead .tot{color:var(--acc)}
.sface .dl{min-height:12px;font:800 11px/12px var(--display);color:var(--acc-on);font-variant-numeric:tabular-nums}
.sface .dl.neg{color:var(--muted)}
/* On the white sheet a character sits on a wash of the colour it runs the ring in. Uno's already do, in their suit. */
#scorescreen:not(.pal-uno) .scoresheet .av.c0{--cb:color-mix(in oklab,var(--ink) 8%,#fff);--cf:var(--ink)}
#scorescreen:not(.pal-uno) .scoresheet .av.c1{--cb:var(--coral-wash);--cf:var(--coral)}
.srow .who{min-width:0}
.srow .nm{font:800 14px/1.1 var(--display);margin-bottom:3px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.cs{display:flex;align-items:center;gap:6px;height:34px;overflow:hidden}
.cs .grp{display:flex;flex:none}
.cs .grp .card + .card{margin-left:calc(-1 * var(--tuck,9px))}
.cs .card{visibility:hidden}
.cs .card.on{visibility:visible}
.cs .minus{font:800 14px/1 var(--display);color:var(--muted);visibility:hidden}
.cs .minus.on{visibility:visible}
.cs .wentout{padding:5px 9px;border-radius:999px;background:var(--acc-wash);color:var(--acc-on);font:800 12px/1 var(--display);visibility:hidden;white-space:nowrap}
.cs .wentout.on{visibility:visible}
.cs .wentout:empty{display:none}
.nums{display:flex;flex-direction:column;align-items:flex-end;gap:4px;min-width:50px}
.nums .tot{font:900 24px/1 var(--display);letter-spacing:-.02em;font-variant-numeric:tabular-nums;transition:color .2s}
.nums .tot{position:relative;z-index:1;transform-origin:100% 50%}
.nums .dl{min-height:18px;padding:2px 7px;border-radius:999px;background:var(--acc-wash);color:var(--acc-on);font:800 11px/14px var(--display);font-variant-numeric:tabular-nums}
.nums .dl.neg{background:var(--table);color:var(--muted)}
.nums .dl:empty{visibility:hidden}
.srow.lead .tot{color:var(--acc)}
.scorefoot{flex:none;padding:10px 24px calc(20px + env(safe-area-inset-bottom));display:flex;justify-content:center}
.scorefoot .pill{width:100%;max-width:320px;padding:17px 20px;font-size:18px;letter-spacing:0;text-transform:none;transition:background .25s,color .25s,transform .12s}
.scorefoot .pill.solid{background:var(--acc);color:#fff}
.scorefoot .pill.plain{background:var(--acc-wash);color:var(--acc-on)}
.scorefoot .pill[disabled]{background:var(--line);color:var(--muted)}

/* Winner: the result in the space the sheet leaves, with the final order and every way out together on the sheet */
.winscreen{--acc:var(--coral);--acc-wash:var(--coral-wash);--acc-on:var(--coral-on-wash);position:absolute;inset:0;display:flex;flex-direction:column}
.winscreen.pal-uno{--acc:var(--ink);--acc-wash:color-mix(in oklab,var(--ink) 8%,#fff);--acc-on:var(--ink)}
.win-hero{flex:1;min-height:0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding-inline:24px;text-align:center}
.win-hero .caps{font-size:13px;color:var(--ink)}
.win-hero .logo-num{margin-top:6px;color:var(--acc)}
.win-hero .tag{max-width:260px}
.win-sheet{flex:none;position:relative;z-index:2;background:var(--paper);border-radius:24px 24px 0 0;box-shadow:0 -10px 30px color-mix(in srgb,var(--ink) 14%,transparent);padding-top:10px}
.win-list{list-style:none;margin:0;padding:0 16px;overflow-y:auto;scrollbar-width:none}
.win-row{display:flex;align-items:center;gap:12px;height:48px;padding-inline:8px;border-radius:14px}
.win-row.won{background:var(--acc-wash)}
.win-row .av{position:static;flex:none;width:34px;height:34px;font-size:16px;transition:none}
.win-name{flex:1;min-width:0;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;font:700 15px/1.2 var(--display);color:var(--ink)}
.win-total{flex:none;font:800 17px/1 var(--display);color:var(--ink);font-variant-numeric:tabular-nums}
.win-row.won .win-total{color:var(--acc-on)}
.win-foot{display:grid;grid-template-columns:1fr 1fr;gap:8px;padding:12px 24px calc(20px + env(safe-area-inset-bottom))}
.win-foot .pill{min-width:0;font-size:15px;letter-spacing:0;text-transform:none;padding:13px 12px}
.win-foot .pill.solid{grid-column:1/-1;padding:17px 20px;font-size:18px;background:var(--acc);color:#fff}
.win-foot .pill.plain{background:var(--acc-wash);color:var(--acc-on)}

@media (prefers-reduced-motion:reduce){
  .seat.thinking .fan .card,.seat.last .cnt,.cnt.last,.seat.last .av,.tool.hot{animation:none}
  .hot>.ring{animation:none;opacity:1}
  .pile.hot .cards:empty,.tool.hot{box-shadow:0 0 0 5px color-mix(in srgb,var(--u-coral) 32%,transparent)}
  .seat,.hc,.hc .card,.spot,.strip-mark,.pile .pc{transition:none}
  .ic *,.char *{animation:none!important}
  .gp-c .card,.gp-voter.av,.gp-slide.won .gp-fan{animation:none}
  .person>*,.chip{animation:none!important}
}

/* Watching a table: no moves, and the hand of whoever is followed. The dock stays open on what's left to do, until they join */
.watch-dock #sort,.watch-dock #react,.watch-dock #guide,.watch-dock #expand{display:none}
.watch-dock .drawer{grid-template-rows:1fr}
.watch-dock .drawer > div{padding-bottom:0}
.tool[disabled]{opacity:.35;cursor:default}
.tool.join{background:var(--coral);color:#fff}
.watching .seat{transition:transform .45s cubic-bezier(.3,.7,.2,1)}
.watching .seat.me .fan,.watching .seat.me .cnt{display:none}
.watching .seat.me .lab{width:120px}
