/* Page shell, cards, slots, win splash.
 *
 * Art direction: a lit table in a dark room. Two variable groups carry it, both
 * overridden by ui.css from the equipped pair — --table-* for the surface,
 * --back-* for the card backs.
 *
 * Card sizing belongs to klondike.js, which sets width, height and `font-size`
 * per card in pixels. The font size IS the card width, so everything inside a
 * card is expressed in `em` and scales with it. No media queries are needed to
 * keep a rank legible on a phone. */

:root {
  /* ui.css swaps these for the table the player has equipped. */
  --table-1: #2c3564;
  --table-2: #191f3c;
  --table-3: #0d1024;

  /* Card ink. deck3d.js carries the same two for the WebGL table — change one,
     change the other, or the same card reads differently on the two. */
  --ink: #131829;
  --ink-soft: #6b7386;
  --red: #d61f3c;
  --key: #ffc247;        /* the one accent: primary buttons, the XP ring, a hint */
  --key-deep: #4a3200;
  --edge: rgba(255, 255, 255, .09);
  --glass: rgba(16, 20, 38, .62);
  --radius: .085em;      /* card corners, in card widths */
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

html, body {
  margin: 0;
  height: 100%;
  overflow: hidden;
  overscroll-behavior: none;
  font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  color: #eef1f8;
  background: var(--table-3);
}

/* The lit table: a pool of light at the top, falling off to the room. The second
   layer is a faint weave, which is what stops a large flat gradient from banding
   on a cheap panel. */
body {
  display: flex;
  flex-direction: column;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .014) 0 2px, transparent 2px 4px),
    radial-gradient(120% 78% at 50% -12%, var(--table-1), var(--table-2) 58%, var(--table-3) 100%);
}

/* ---------- the two floating bars ---------- */

/* Neither bar spans the window. They are panels laid on the table with table
   visible around them, which is what keeps this from reading as a page with a
   header and a footer. */
.hud, .dock {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 9px 10px;
  padding: 7px 10px;
  border: 1px solid var(--edge);
  border-radius: 15px;
  background: var(--glass);
  backdrop-filter: blur(14px) saturate(1.3);
  -webkit-backdrop-filter: blur(14px) saturate(1.3);
  box-shadow: 0 6px 22px rgba(0, 0, 0, .3);
}

/* The indie.fun SDK pins its sign-in pill to the top right, over this bar.
   session.js publishes its width as --acct-w; it stays 0 when there is none. */
.hud { margin-right: calc(10px + var(--acct-w, 0px)); }
.dock { margin-bottom: calc(9px + env(safe-area-inset-bottom)); }

/* ---------- board ---------- */

.board {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  touch-action: none;
  user-select: none;
}

/* Empty piles are outlines only. A filled rectangle reads as a blank card. */
.slot {
  position: absolute;
  top: 0; left: 0;
  border-radius: var(--radius);
  border: 1.5px dashed rgba(255, 255, 255, .18);
  background: rgba(0, 0, 0, .16);
  display: flex;
  align-items: center;
  justify-content: center;
  color: rgba(255, 255, 255, .26);
  font-size: .9em;
  transition: transform .22s ease, width .22s ease, height .22s ease, font-size .22s ease,
              border-color .2s ease, box-shadow .2s ease;
}
.slot.recycle::after { content: "↻"; font-size: .46em; line-height: 1; }
.slot.foundation::after { content: attr(data-suit); font-size: .5em; line-height: 1; }

.card {
  position: absolute;
  top: 0; left: 0;
  border-radius: var(--radius);
  transition: transform .2s cubic-bezier(.22, .78, .3, 1),
              width .22s ease, height .22s ease, font-size .22s ease;
  will-change: transform;
  cursor: pointer;
}
.card.no-anim { transition: none; }
.card.dragging { transition: none; cursor: grabbing; }
.card.down { cursor: default; }

.inner {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  transform-style: preserve-3d;
  transition: transform .18s ease;
  box-shadow: 0 .5px 1px rgba(0, 0, 0, .34), 0 .04em .09em rgba(0, 0, 0, .22);
}
.card.down .inner { transform: rotateY(180deg); }
.card.dragging .inner { box-shadow: 0 .12em .3em rgba(0, 0, 0, .5); }

.face, .back {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  overflow: hidden;
}

.face {
  background: linear-gradient(168deg, #fff 0%, #fdfdff 46%, #eef0f7 100%);
  color: var(--ink);
  border: 1px solid rgba(20, 28, 50, .16);
}
.card.red .face { color: var(--red); }

/* Single index across the top: rank hard left, suit hard right, with a large
   suit watermark below. A tableau fan only exposes the top strip of a card, so a
   second index in the bottom corner occupies the one region nobody sees.
   Dropping it is what buys room for an index large enough to read at a glance.

   Side by side rather than stacked, because a deep pile compresses that strip
   until it is a few pixels tall: stacked, the suit was the half that fell off
   the bottom, and a column read as ranks in two colours with no way to tell a
   heart from a diamond. deck3d.js lays the same two out the same way. */
.corner {
  position: absolute;
  display: flex;
  align-items: center;
  justify-content: space-between;
  line-height: 1;
  font-weight: 800;
  letter-spacing: -.01em;
}
.corner .r { font-size: .27em; }
.corner .s { font-size: .235em; }
.corner.tl { top: .05em; left: .07em; right: .07em; }
.corner.br { display: none; }

.pip {
  position: absolute;
  right: .05em;
  bottom: -.02em;
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  font-size: .62em;
  line-height: .82;
  opacity: .26;
}

/* ---------- backs ---------- */

/* ui.css sets both from the equipped back. These are the fallbacks. */
.back {
  transform: rotateY(180deg);
  background: var(--back-bg,
    repeating-linear-gradient(45deg, rgba(255, 255, 255, .07) 0 .05em, transparent .05em .1em),
    linear-gradient(155deg, #4a5578, #232a48));
  border: 1px solid rgba(0, 0, 0, .3);
}
/* Shared inset frame, so the whole set reads as one deck. */
.back::after {
  content: "";
  position: absolute;
  inset: 7%;
  border-radius: 3%;
  border: 1px solid var(--back-line, rgba(255, 255, 255, .28));
}

/* Hints light the card from inside. An outline on a card in a tight fan draws
   four lines, three of them underneath other cards. */
.card.hint .face { box-shadow: inset 0 0 0 .03em var(--key), inset 0 0 .2em rgba(255, 194, 71, .55); }
.slot.hint { border-color: var(--key); border-style: solid; box-shadow: inset 0 0 0 .03em rgba(255, 194, 71, .45); }

/* ---------- the WebGL table ---------- */

/* `table3d.js` draws the cards, the slots and the surface on a canvas behind the
   page, lit and with thickness. Everything above this line still exists and
   still runs — the divs are laid out, dragged and dropped exactly as before.
   They just stop being the thing you look at.

   Transparent and not hidden, deliberately: `visibility: hidden` and
   `display: none` take the pointer events with them, and those divs are the
   whole input layer. Nothing here changes what the game does; remove the canvas
   and the 2D table is still underneath, which is what the fallback relies on. */

#stage3d {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  /* Above the page background, below every element in flow, so the two bars and
     their backdrop blur sit over the table exactly as they did. */
  z-index: -1;
  pointer-events: none;
}

/* The canvas paints above the page background and below everything in flow —
   but `body`'s own background is in flow, and would cover it. The surface is on
   the canvas now; `html` keeps the same flat colour underneath as the base the
   fallback and the overscroll gutter need. */
[data-gl="on"] body,
[data-gl="ready"] body { background: none; }

[data-gl="on"] .card,
[data-gl="ready"] .card,
[data-gl="on"] .slot,
[data-gl="ready"] .slot {
  opacity: 0;
  /* The canvas runs its own springs off these positions. Leaving the CSS
     transition on would hand it the destination a fifth of a second late. */
  transition: none;
  box-shadow: none;
}
[data-gl="on"] .card .inner,
[data-gl="ready"] .card .inner { transition: none; box-shadow: none; }

/* ---------- win splash ---------- */

.win[hidden] { display: none; }

.win {
  position: fixed;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
  background: rgba(6, 8, 18, .66);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
  z-index: 500;
  animation: fade .3s ease both;
}
@keyframes fade { from { opacity: 0 } to { opacity: 1 } }

.win-card {
  position: relative;
  overflow: hidden;
  text-align: center;
  width: min(340px, 100%);
  padding: 26px 26px 22px;
  border-radius: 22px;
  background: linear-gradient(170deg, #232b52, #141936 70%);
  border: 1px solid rgba(255, 255, 255, .12);
  box-shadow: 0 24px 60px rgba(0, 0, 0, .55);
  animation: rise .42s cubic-bezier(.2, .9, .3, 1.25) both;
}
@keyframes rise {
  from { opacity: 0; transform: translateY(24px) scale(.94) }
  to { opacity: 1; transform: none }
}
.win-card > * { position: relative; }

/* A soft glow behind the total. The number is the subject; rays compete. */
.halo {
  position: absolute;
  left: 50%;
  top: 26%;
  width: 320px; height: 320px;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(255, 194, 71, .28), transparent 62%);
  pointer-events: none;
  animation: breathe 5s ease-in-out infinite;
}
@keyframes breathe { 50% { opacity: .55; transform: translate(-50%, -50%) scale(1.12) } }

.eyebrow {
  margin: 0 0 2px;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: .24em;
  text-transform: uppercase;
  opacity: .5;
}
.win-card h1 { margin: 0 0 14px; font-size: 27px; font-weight: 700; letter-spacing: -.01em; }
.win-card p { margin: 0 0 16px; opacity: .62; font-size: 13px; }

.total { line-height: 1; margin-bottom: 10px; }
.total b {
  display: block;
  font-size: 62px;
  font-weight: 800;
  letter-spacing: -.035em;
  color: var(--key);
  font-variant-numeric: tabular-nums;
  text-shadow: 0 0 34px rgba(255, 194, 71, .5);
}
.total span {
  display: block;
  margin-top: 4px;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .2em;
  opacity: .5;
}

.badge {
  display: inline-block;
  margin-bottom: 12px;
  padding: 4px 12px;
  border-radius: 999px;
  font-size: 10px;
  font-weight: 800;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--key-deep);
  background: var(--key);
}
.badge[hidden] { display: none; }

.breakdown {
  list-style: none;
  margin: 0 0 16px;
  padding: 0;
  display: grid;
  gap: 8px;
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}
.breakdown li { display: flex; justify-content: space-between; gap: 24px; }
.breakdown span { opacity: .6; }
.breakdown .rule {
  margin-top: 4px;
  padding-top: 9px;
  border-top: 1px solid rgba(255, 255, 255, .12);
}

.win-actions { display: grid; gap: 8px; }

/* ---------- the game's own toast ---------- */

/* Reports what happened to the saved game on sign-in and sign-out, the one time
   the table changes without the player touching it. This is klondike.js's single
   toast and sits at the bottom; ui.js has its own stack at the top (ui.css). */
.toast {
  position: fixed;
  left: 50%;
  bottom: 84px;
  z-index: 600;
  max-width: min(420px, calc(100vw - 32px));
  padding: 10px 16px;
  border-radius: 12px;
  font-size: 13px;
  line-height: 1.4;
  text-align: center;
  background: rgba(12, 16, 32, .94);
  border: 1px solid var(--edge);
  box-shadow: 0 12px 30px rgba(0, 0, 0, .45);
  opacity: 0;
  pointer-events: none;
  transform: translate(-50%, 12px);
  transition: opacity .25s ease, transform .25s ease;
}
.toast.show { opacity: 1; transform: translate(-50%, 0); }
