/* ------------------------------------------------------------------ type */
@font-face { font-family: 'Selecta'; src: url('../fonts/Selecta-Regular.otf') format('opentype'); font-weight: 400; font-display: swap; }
@font-face { font-family: 'Selecta'; src: url('../fonts/Selecta-Medium.otf') format('opentype'); font-weight: 500; font-display: swap; }
@font-face { font-family: 'Kalice'; src: url('../fonts/Kalice-Regular.woff2') format('woff2'); font-weight: 400; font-display: swap; }

/* ------------------------------------------------------------------ ground */
:root {
  --ink: #f2f4f8;
  --dim: rgba(242,244,248,.58);
  --faint: rgba(242,244,248,.34);
  --void: #05070d;

  /* One glass material, declared once. Every panel in the app is this and
     nothing else; a second glass is how an interface starts looking assembled. */
  --glass-bg: rgba(255,255,255,.085);
  /* The dark variant, for the two panels that float over the PLANET rather than
     over the sky. A white-tinted glass borrows whatever is behind it, and behind
     these it may be the Sahara at noon — at which point the panel is a pale slab
     with pale text on it. Tinting the base dark keeps the glass character (the
     blur and the saturation still show the colour through) and guarantees the
     ink has a ground. */
  --glass-dark: rgba(11,14,22,.56);
  --glass-line: rgba(255,255,255,.16);
  --glass-blur: blur(26px) saturate(1.5);
  --glass-shadow: 0 1px 0 rgba(255,255,255,.14) inset, 0 -1px 0 rgba(0,0,0,.22) inset, 0 18px 44px rgba(0,0,0,.45);

  --warm: #ffd08a;   /* the answer */
  --cool: #7fd4ff;   /* you */
  --hot:  #ff8f6b;

  --r: 18px;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
html, body {
  margin: 0; height: 100%; background: var(--void); color: var(--ink);
  font-family: 'Selecta', ui-sans-serif, system-ui, sans-serif;
  font-weight: 400; overscroll-behavior: none;
  -webkit-font-smoothing: antialiased;
}
body { display: grid; place-items: center; user-select: none; }

/* The phone. On a desktop the app is shown inside a device because it is a phone
   app and pretending otherwise would let the layout drift somewhere a phone can
   never go. #stage is the app's whole world, and every length inside it is in
   container units, so the framed view and a real phone get the same layout. */
#device {
  position: relative; width: 100%; height: 100%;
  display: grid; place-items: center;
}
#stage {
  position: relative; width: 100%; height: 100%; overflow: hidden;
  container-type: size; container-name: app;
  background: var(--void);
}
body.framed #device { padding: 20px; }
body.framed #stage {
  width: 402px; height: 874px; border-radius: 54px;
  box-shadow: 0 0 0 11px #121418, 0 0 0 13px #2b2f38, 0 44px 90px rgba(0,0,0,.7);
  /* Scaled, never resized. A 1280x720 laptop is 154px shorter than the phone,
     and the first version simply overflowed — with the one button on the title
     screen off the bottom of the window. Scaling is the right fix rather than
     shrinking the box, because #stage is the container-query root: a transform
     does not touch the content box, so every cqw and cqh inside still resolves
     against 402x874 and the framed view keeps the SAME layout a real phone gets,
     just drawn smaller. --fit is set by fitFrame() in main.js; CSS cannot divide
     a viewport length by a number and get a scale factor. */
  /* Centred on the VIEWPORT rather than by the grid. A transform does not change
     the layout box, so a grid centring the still-874px-tall box in a 680px area
     overflows it and the visual result lands off-centre. Positioning against the
     viewport and translating by half sidesteps the layout box entirely. */
  position: fixed; left: 50%; top: 50%;
  transform: translate(-50%, -50%) scale(var(--fit, 1));
}

#globe { position: absolute; inset: 0; width: 100%; height: 100%; display: block; touch-action: none; }
#ui { position: absolute; inset: 0; pointer-events: none; }
#ui > * { pointer-events: auto; }

/* ------------------------------------------------------------------ glass */
.glass {
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-shadow);
  border-radius: var(--r);
}

button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: .5em;
  padding: 15px 22px; border-radius: 999px; font-weight: 500;
  letter-spacing: .01em; font-size: 15px; line-height: 1;
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: 1px solid var(--glass-line);
  box-shadow: var(--glass-shadow);
  transition: transform .18s cubic-bezier(.2,.9,.3,1), background .18s, opacity .18s;
}
.btn:active { transform: scale(.97); }
.btn[disabled] { opacity: .35; pointer-events: none; }
.btn.primary {
  /* A DECLARED divergence from the house glass button.
     wabi.ai's button is built for #f0f0f0 paper: white highlights, near-black
     text, and a backdrop it can borrow light from. Over Pin's near-black sky
     that same recipe resolves to a mid-grey slab with dark grey text on it —
     the exact failure the light-glass-over-dark-content note is about. So the
     structure is kept (a lit top edge, a shaded bottom, a travelling shine, the
     same radius and weight) and the values are inverted: on a dark app the one
     bright object should be the one thing you are meant to press. */
  background: linear-gradient(180deg, #ffffff 0%, #e6e9ef 100%);
  color: #06080e;
  border: 0;
  -webkit-backdrop-filter: none; backdrop-filter: none;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,.95),
    inset 0 -2px 3px rgba(0,0,0,.10),
    0 0 0 1px rgba(255,255,255,.16),
    0 12px 30px rgba(0,0,0,.55);
  overflow: hidden;
}
.btn.primary::after {
  /* The travelling shine, from the production button. */
  content: ''; position: absolute; inset: 0; border-radius: inherit;
  background: linear-gradient(-70deg, rgba(255,255,255,0) 38%, rgba(255,255,255,.75) 48% 52%, rgba(255,255,255,0) 62%);
  background-size: 240% 100%; background-position: 120% 50%;
  mix-blend-mode: overlay; pointer-events: none;
  transition: background-position 900ms cubic-bezier(.25,1,.5,1);
}
.btn.primary:hover::after { background-position: -30% 50%; }
.btn { position: relative; }
.btn.primary:active { transform: scale(.975); }

/* ------------------------------------------------------------------ layout
   Every length below is in container units against #stage, so the framed
   desktop view and a real phone lay out identically — there is one design, not
   a phone one and a desktop one that drift. */
#arc { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }

.off { display: none !important; }

.nogl {
  position: absolute; inset: 0; display: grid; place-items: center;
  padding: 10cqw; text-align: center; color: var(--dim); font-size: 15px; line-height: 1.5;
}

/* ---- top bar ---- */
/* The scrim is the bar's OWN background, not a z-index:-1 pseudo-element.
   `.bar` does not create a stacking context, so a negative z-index child of it
   is pushed behind the nearest ancestor that does — which is #stage, and #stage
   paints an opaque background. The scrim was therefore drawn perfectly and
   hidden behind the app. A gradient on the element cannot fail that way.

   It is needed because the globe is bright and it MOVES: a bar with no ground
   is legible over the ocean and gone over the Sahara, and the score is the one
   thing that must never be hard to read. */
.bar {
  position: absolute; left: 0; right: 0; top: 0; z-index: 1;
  display: flex; align-items: center; gap: 3cqw;
  padding: calc(env(safe-area-inset-top, 0px) + 4.2cqh) 5cqw 5cqh;
  background: linear-gradient(180deg, rgba(5,7,13,.92) 0%, rgba(5,7,13,.70) 38%, rgba(5,7,13,0) 100%);
  font-size: 12px; letter-spacing: .10em; text-transform: uppercase;
  color: var(--faint);
}
.puzzle { font-weight: 500; color: rgba(242,244,248,.52); }
.dots { flex: 1; display: flex; justify-content: center; gap: 6px; }
.dot {
  width: 7px; height: 7px; border-radius: 999px;
  background: rgba(255,255,255,.22);
  box-shadow: 0 1px 3px rgba(0,0,0,.5); transition: background .3s, transform .3s;
}
.dot.now { background: rgba(255,255,255,.55); transform: scale(1.25); }
.dot.done { background: var(--dim); }
.score { font-weight: 500; color: var(--ink); font-variant-numeric: tabular-nums; letter-spacing: .04em; }
.icon {
  width: 34px; height: 34px; display: grid; place-items: center; border-radius: 999px;
  color: var(--faint); transition: color .2s, background .2s;
}
.icon.on { color: var(--ink); background: rgba(255,255,255,.10); }

/* ---- the prompt ---- */
.prompt, .sheet { background: var(--glass-dark); }
.prompt {
  position: absolute; left: 5cqw; right: 5cqw;
  top: calc(env(safe-area-inset-top, 0px) + 11cqh);
  padding: 4cqw 5cqw 4.4cqw;
  animation: rise .5s cubic-bezier(.2,.9,.3,1) both;
}
.tier {
  font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 2cqw;
}
.placename {
  /* Smaller than it wants to be. The headline is the shortest thing on the
     screen and the globe is the thing you have to aim at, so every point the
     name gives back is a point of clear sky. */
  margin: 0 0 1.6cqw; font-family: 'Kalice', Georgia, serif; font-weight: 400;
  font-size: clamp(21px, 6.4cqw, 29px); line-height: 1.06; letter-spacing: -.005em;
}
.clue { margin: 0; font-size: 13.5px; line-height: 1.42; color: var(--dim); }

/* ---- hint + action ---- */
.actwrap {
  position: absolute; left: 5cqw; right: 5cqw;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 4.5cqh);
  display: flex; flex-direction: column; align-items: center; gap: 3cqw;
}
.hint { font-size: 12.5px; color: var(--faint); letter-spacing: .01em; text-align: center; }
.act { min-width: 58cqw; }
.wide { width: 100%; }

/* ---- the sheet ---- */
.sheet {
  position: absolute; left: 2.6cqw; right: 2.6cqw;
  bottom: calc(env(safe-area-inset-bottom, 0px) + 2.4cqh);
  padding: 2.4cqw 6cqw 6cqw;
  border-radius: 26px;
  animation: sheetUp .55s cubic-bezier(.18,.9,.28,1) both;
  max-height: 74cqh; overflow-y: auto; overscroll-behavior: contain;
}
.sheet.tall { max-height: 86cqh; }
.grab {
  width: 34px; height: 4px; border-radius: 99px; margin: 0 auto 4.5cqw;
  background: rgba(255,255,255,.22);
}
.verdict {
  margin: 0 0 3.6cqw; font-family: 'Kalice', Georgia, serif; font-weight: 400;
  font-size: clamp(24px, 7.6cqw, 36px); line-height: 1.06;
}
.stats { display: flex; gap: 3cqw; margin-bottom: 4.4cqw; }
.stat {
  flex: 1; padding: 3.4cqw 3.6cqw; border-radius: 14px;
  background: rgba(255,255,255,.055); border: 1px solid rgba(255,255,255,.10);
}
.stat .v {
  font-size: clamp(17px, 5.4cqw, 24px); font-weight: 500;
  font-variant-numeric: tabular-nums; letter-spacing: -.01em;
}
.stat .l { margin-top: .5cqw; font-size: 10.5px; letter-spacing: .12em; text-transform: uppercase; color: var(--faint); }

/* The points tile takes the colour of the band, so how you did is legible
   before a single word has been read. */
.stat.b-bullseye .v { color: #d5b6ff; } .stat.b-bullseye { background: rgba(120,84,190,.20); border-color: rgba(190,150,255,.36); }
.stat.b-pinpoint .v, .stat.b-close .v { color: #8ff0b6; }
.stat.b-good .v, .stat.b-fair .v { color: #ffe08a; }
.stat.b-poor .v { color: #ffab7a; }
.stat.b-lost .v { color: #ff8f8f; }
.dot.b-bullseye { background: #c9a6ff; }
.dot.b-pinpoint, .dot.b-close { background: #7fe3a8; }
.dot.b-good, .dot.b-fair { background: #ffd97a; }
.dot.b-poor { background: #ff9d6a; }
.dot.b-lost { background: #ff7f7f; }

.line { margin: 0 0 3.4cqw; font-size: 15px; line-height: 1.42; }
.hook {
  margin: 0 0 5cqw; font-size: 13px; line-height: 1.5; color: var(--dim);
  padding-left: 3.6cqw; border-left: 1px solid rgba(255,255,255,.18);
}
.hook:empty { display: none; }
.note {
  font-size: 11.5px; letter-spacing: .04em; color: var(--warm);
  margin-bottom: 4cqw; opacity: .85;
}
.extra:empty { display: none; }

/* ---- leaderboard ---- */
.board { margin-bottom: 5cqw; }
.board-head {
  font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 3cqw;
}
.board-form { display: flex; gap: 2.4cqw; margin-bottom: 3.6cqw; }
.board-form input {
  flex: 1; min-width: 0; font: inherit; font-size: 14px; color: var(--ink);
  background: rgba(255,255,255,.07); border: 1px solid var(--glass-line);
  border-radius: 999px; padding: 12px 16px; outline: none;
}
.board-form input:focus { border-color: rgba(255,255,255,.34); background: rgba(255,255,255,.10); }
.board-form .btn { padding: 12px 16px; font-size: 13px; white-space: nowrap; }
.board-list { list-style: none; margin: 0 0 2.4cqw; padding: 0; }
.board-list li {
  display: grid; grid-template-columns: 22px minmax(0,1fr) auto; gap: 3cqw;
  align-items: baseline; padding: 7px 0; font-size: 14px;
  border-bottom: 1px solid rgba(255,255,255,.06);
}
.board-list li.me { color: var(--warm); }
.br { color: var(--faint); font-size: 12px; font-variant-numeric: tabular-nums; }
.bn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.bp { font-weight: 500; font-variant-numeric: tabular-nums; }
.board-status { font-size: 12.5px; color: var(--faint); }

/* ---- title ---- */
.title {
  position: absolute; inset: 0; display: grid; align-items: end;
  padding: 0 7cqw calc(env(safe-area-inset-bottom, 0px) + 8cqh);
  background: linear-gradient(180deg, rgba(5,7,13,0) 34%, rgba(5,7,13,.72) 66%, rgba(5,7,13,.94) 100%);
  animation: fade .8s ease both;
}
.title-in { display: flex; flex-direction: column; align-items: flex-start; }
.mark {
  font-family: 'Kalice', Georgia, serif; font-size: clamp(56px, 20cqw, 96px);
  line-height: .9; letter-spacing: -.03em; margin-bottom: 3.4cqw;
}
.sub { margin: 0 0 3cqw; font-size: 15px; line-height: 1.45; max-width: 30ch; }
.meta { margin: 0 0 7cqw; font-size: 12.5px; line-height: 1.45; color: var(--faint); max-width: 34ch; }
.title .btn { width: 100%; padding: 17px 22px; font-size: 16px; }
.note-title, .title .note { margin: 3.4cqw 0 0; font-size: 11.5px; color: var(--faint); letter-spacing: .04em; }

@keyframes rise { from { opacity: 0; transform: translateY(-10px); } to { opacity: 1; transform: none; } }
@keyframes sheetUp { from { opacity: 0; transform: translateY(26px); } to { opacity: 1; transform: none; } }
@keyframes fade { from { opacity: 0; } to { opacity: 1; } }

@media (prefers-reduced-motion: reduce) {
  .prompt, .sheet, .title { animation: none; }
}

.sheetname {
  font-size: 10.5px; letter-spacing: .13em; text-transform: uppercase;
  color: var(--faint); margin-bottom: 2.4cqw;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* ---- the day's five ---- */
.recap { list-style: none; margin: 0 0 5cqw; padding: 0; }
.recap li {
  display: grid; grid-template-columns: minmax(0,1fr) auto 34px; gap: 3cqw;
  align-items: baseline; padding: 8px 0 8px 10px; font-size: 14px;
  border-bottom: 1px solid rgba(255,255,255,.06);
  border-left: 2px solid rgba(255,255,255,.14);
}
.rn { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.rd { font-size: 12px; color: var(--faint); font-variant-numeric: tabular-nums; }
.rp { text-align: right; font-weight: 500; font-variant-numeric: tabular-nums; }
.recap li.b-bullseye { border-left-color: #c9a6ff; }
.recap li.b-pinpoint, .recap li.b-close { border-left-color: #7fe3a8; }
.recap li.b-good, .recap li.b-fair { border-left-color: #ffd97a; }
.recap li.b-poor { border-left-color: #ff9d6a; }
.recap li.b-lost { border-left-color: #ff7f7f; }

/* ?cover — the shelf card and the share image. The app with nothing said. */
body.cover #ui { display: none; }
body.cover #device { padding: 0; }

.nextin { font-size: 12px; color: var(--faint); letter-spacing: .02em; margin-bottom: 4.5cqw; }

/* The confirm button before there is anything to confirm: invisible, inert, and
   still occupying its row — see the note in goRound(). */
.act.waiting { visibility: hidden; pointer-events: none; }
