/* ==========================================================================
   Math Memory — account screens
   Everything here runs on the purple app gradient. NO white cards and no
   light panels: a child meets this screen before they meet the game, so it
   has to look like the game rather than like a form in front of it.

   Colour carries meaning, not just cheer — the kid's door and the kid's panel
   are teal, the parent's door is pink, and the play code is gold because it
   is the one thing on the page worth writing down.
   ========================================================================== */

/* ---- Shared panel ------------------------------------------------------- */

.screen--auth,
.screen--welcome {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  padding: var(--s5) var(--s4) var(--s6);
  max-width: 520px;
  margin: 0 auto;
  width: 100%;
}

.auth__head {
  display: flex;
  align-items: center;
  gap: var(--s3);
}

.auth__title,
.welcome__title {
  font: 700 clamp(22px, 5.5vw, 29px)/1.2 Fredoka, sans-serif;
  color: #fff;
  margin: 0;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .35);
}

.welcome__title { text-align: center; }

.auth__panel {
  /* A lit panel rather than a pale one: violet lifted off the backdrop, with
     a hairline of light along the top edge so it reads as raised. */
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0) 42%),
    linear-gradient(165deg, var(--indigo), #2d1566);
  border: 2px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-card);
  padding: var(--s5) var(--s4) var(--s4);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
  box-shadow: 0 16px 44px rgba(0, 0, 0, .38);
}

/* The child's panel wears the same teal as their door, so the two screens
   read as one path. */
.auth__panel--kid {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .18), rgba(255, 255, 255, 0) 42%),
    linear-gradient(165deg, var(--teal-deep), #123f6e);
  border-color: rgba(79, 227, 208, .4);
  box-shadow: 0 16px 44px rgba(0, 0, 0, .38), 0 0 0 6px rgba(52, 209, 192, .1);
}

.auth__lede {
  font: 700 16px/1.55 Nunito, sans-serif;
  color: #fff;
  margin: 0 0 var(--s2);
}

.auth__label {
  font: 800 12px/1 Nunito, sans-serif;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--gold);
  margin-top: var(--s2);
}

.auth__row { display: flex; gap: var(--s2); }

/* ---- Inputs ------------------------------------------------------------- */

.auth__input,
.auth__select {
  font: 700 17px/1 Nunito, sans-serif;
  color: #fff;
  background: rgba(0, 0, 0, .3);
  border: 2px solid rgba(255, 255, 255, .22);
  border-radius: var(--r-chip);
  padding: 14px var(--s3);
  width: 100%;
  /* 17px or larger stops iOS Safari zooming the page on focus. */
  min-height: 50px;
}

.auth__input::placeholder { color: rgba(255, 255, 255, .42); }

.auth__input:focus-visible,
.auth__select:focus-visible {
  outline: none;
  border-color: var(--gold);
  background: rgba(0, 0, 0, .42);
  box-shadow: 0 0 0 4px rgba(255, 215, 106, .22);
}

/* A <select> paints its own list with the OS palette, so the option text has
   to stay legible against whatever that is — not against this panel. */
.auth__select { flex: 0 0 42%; min-width: 0; }
.auth__select option { color: #1a1430; background: #fff; }

.auth__input--phone { flex: 1 1 auto; min-width: 0; }
.auth__input--age   { max-width: 150px; }

.auth__input--code {
  font: 700 26px/1 'IBM Plex Mono', monospace;
  letter-spacing: .3em;
  text-align: center;
  padding-left: calc(var(--s3) + .3em);   /* re-centres against the tracking */
  color: var(--gold);
}

.auth__input--big {
  font-size: clamp(24px, 7vw, 31px);
  min-height: 62px;
  letter-spacing: .18em;
  padding-left: calc(var(--s3) + .18em);
}

/* ---- Buttons ------------------------------------------------------------ */

.auth__go {
  margin-top: var(--s3);
  font: 800 17px/1.25 Nunito, sans-serif;
  padding: 16px var(--s4);
  border-radius: var(--r-pill);
  letter-spacing: 0;
}

.auth__go[disabled] { opacity: .55; cursor: default; transform: none; }

.auth__quiet {
  background: none;
  border: 0;
  color: rgba(255, 255, 255, .72);
  font: 700 14px/1.4 Nunito, sans-serif;
  padding: var(--s3);
  cursor: pointer;
  border-radius: var(--r-chip);
  text-align: center;
}

.auth__quiet:hover:not([disabled]) { color: #fff; background: rgba(255, 255, 255, .1); }
.auth__quiet[disabled] { opacity: .45; cursor: default; }

/* ---- Messages ----------------------------------------------------------- */

.auth__note {
  font: 700 14px/1.5 Nunito, sans-serif;
  color: rgba(255, 255, 255, .8);
  margin: var(--s2) 0 0;
  min-height: 1.5em;                       /* no jump when a message appears */
}

/* Salmon, not red: this screen is read by children, and a hard red on a wrong
   code reads as "you are in trouble" rather than "try again". */
.auth__note--error { color: #ff9ab3; }

.auth__fine {
  font: 600 13px/1.6 Nunito, sans-serif;
  color: rgba(255, 255, 255, .58);
  margin: var(--s2) 0 0;
}

.auth__check {
  display: flex;
  align-items: flex-start;
  gap: var(--s2);
  font: 700 14px/1.5 Nunito, sans-serif;
  color: rgba(255, 255, 255, .85);
  margin-top: var(--s3);
  cursor: pointer;
}

.auth__check input { margin-top: 3px; width: 19px; height: 19px; flex: none; }

/* ---- The play code ------------------------------------------------------ */

.codecard {
  font: 700 clamp(28px, 9vw, 40px)/1.1 'IBM Plex Mono', monospace;
  letter-spacing: .12em;
  text-align: center;
  color: var(--ink-2);
  background: linear-gradient(180deg, var(--gold), var(--amber));
  border-radius: var(--r-tile);
  padding: var(--s4) var(--s2);
  margin: var(--s3) 0;
  box-shadow: 0 8px 0 #d98e12, 0 18px 30px rgba(255, 160, 0, .3);
  /* Long enough to matter and short enough to read aloud — let it be selected
     so a parent can copy rather than transcribe. */
  user-select: all;
}

/* ---- Welcome doors ------------------------------------------------------ */

.welcome__duck { align-self: center; }

.doors {
  display: flex;
  flex-direction: column;
  gap: var(--s4);
}

.door {
  display: flex;
  align-items: center;
  gap: var(--s4);
  text-align: left;
  border: 2px solid rgba(255, 255, 255, .18);
  border-radius: var(--r-tile);
  padding: var(--s4);
  cursor: pointer;
  color: #fff;
  transition: transform .16s ease, box-shadow .16s ease, border-color .16s ease;
}

.door:hover, .door:focus-visible {
  transform: translateY(-3px);
  border-color: rgba(255, 255, 255, .5);
  outline: none;
}

.door:active { transform: translateY(1px); }

/* The child's door is the loud one — they are the one who came to play. The
   parent's is calmer: they are here to set something up, not to play. */
.door--kid {
  background: linear-gradient(150deg, var(--teal-2), var(--teal-3));
  box-shadow: 0 8px 0 var(--teal-deep), 0 18px 34px rgba(31, 181, 164, .34);
  color: #06302c;
}

.door--kid:hover { box-shadow: 0 10px 0 var(--teal-deep), 0 22px 40px rgba(31, 181, 164, .42); }

.door--parent {
  background: linear-gradient(150deg, var(--pink-soft), var(--pink));
  box-shadow: 0 8px 0 var(--pink-deep), 0 18px 34px rgba(255, 133, 185, .3);
  color: #4a1030;
}

.door--parent:hover { box-shadow: 0 10px 0 var(--pink-deep), 0 22px 40px rgba(255, 133, 185, .38); }

.door__icon { font-size: 46px; line-height: 1; flex: none; }
.door__text { display: flex; flex-direction: column; gap: 2px; }
.door__title { font: 700 clamp(18px, 5vw, 22px)/1.15 Fredoka, sans-serif; }
.door__sub { font: 700 13.5px/1.35 Nunito, sans-serif; opacity: .72; }

/* ---- Who's playing ------------------------------------------------------ */

.screen--who {
  display: flex;
  flex-direction: column;
  gap: var(--s5);
  padding: var(--s6) var(--s4);
  max-width: 620px;
  margin: 0 auto;
  width: 100%;
}

.who__title {
  font: 700 clamp(23px, 6vw, 31px)/1.2 Fredoka, sans-serif;
  color: #fff;
  text-align: center;
  margin: 0;
  text-shadow: 0 2px 12px rgba(0, 0, 0, .35);
}

.who__grid {
  display: grid;
  /* Cards find their own column count rather than being told one, so the
     picker works from a phone up to a wide tablet without breakpoints. */
  grid-template-columns: repeat(auto-fit, minmax(124px, 1fr));
  gap: var(--s4);
  justify-content: center;
}

.who__card {
  background: linear-gradient(165deg, rgba(255, 255, 255, .18), rgba(255, 255, 255, .06));
  border: 2px solid rgba(255, 255, 255, .2);
  border-radius: var(--r-tile);
  padding: var(--s4) var(--s2);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--s2);
  cursor: pointer;
  color: #fff;
  transition: transform .16s ease, background .16s ease, border-color .16s ease;
}

.who__card:hover:not([disabled]),
.who__card:focus-visible {
  background: linear-gradient(165deg, rgba(255, 215, 106, .3), rgba(255, 182, 46, .14));
  border-color: var(--gold);
  transform: translateY(-3px);
  outline: none;
}

.who__card[disabled] { cursor: default; }
.who__card.is-loading { opacity: .55; }

.who__face {
  font-size: 46px;
  line-height: 1;
  filter: drop-shadow(0 4px 10px rgba(0, 0, 0, .35));
}

.who__name { font: 700 15px/1.2 Nunito, sans-serif; text-align: center; overflow-wrap: anywhere; }

.who__card--add { background: transparent; border-style: dashed; }
.who__card--add .who__face { font-size: 38px; opacity: .8; }

.who__loading {
  grid-column: 1 / -1;
  text-align: center;
  color: rgba(255, 255, 255, .7);
  font: 700 15px/1.5 Nunito, sans-serif;
}

.who__faces { display: flex; flex-wrap: wrap; gap: var(--s2); }

.who__face-pick {
  font-size: 27px;
  line-height: 1;
  background: rgba(0, 0, 0, .26);
  border: 2px solid rgba(255, 255, 255, .16);
  border-radius: var(--r-chip);
  padding: var(--s2) var(--s3);
  cursor: pointer;
}

.who__face-pick.is-on {
  border-color: var(--gold);
  background: rgba(255, 215, 106, .22);
}

.who__foot { display: flex; flex-direction: column; align-items: center; gap: var(--s1); }

.screen--who .auth__note { text-align: center; }

@media (prefers-reduced-motion: reduce) {
  .door, .who__card { transition: none; }
  .door:hover, .who__card:hover:not([disabled]) { transform: none; }
}

/* The signed-in parent's name on the picker. Quiet on purpose — it is
   reassurance, not a heading. */
.who__whoami {
  font: 700 13px/1.4 Nunito, sans-serif;
  color: rgba(255, 255, 255, .52);
  text-align: center;
  margin: 0 0 var(--s1);
}

/* Who is playing, in the game's own top bar and on the board. Gold so it is
   findable at a glance on a shared tablet, without competing with the score. */
.pill--who { background: rgba(255, 215, 106, .2); color: var(--gold); }
.chip--who { background: rgba(255, 215, 106, .2); color: var(--gold); font-weight: 800; }

/* The child's play code on their card. Monospace and quiet — a parent needs
   to read it back accurately, not be drawn to it before the child's name. */
.who__code {
  font: 500 11.5px/1 'IBM Plex Mono', monospace;
  letter-spacing: .06em;
  color: rgba(255, 255, 255, .58);
  background: rgba(0, 0, 0, .26);
  border-radius: var(--r-pill);
  padding: 4px 9px;
  user-select: all;
}

/* The "create one" link, once a sign-in has failed with no such account.
   Brought forward rather than redirecting: the same failure covers a typo. */
.auth__quiet--loud {
  color: var(--gold);
  background: rgba(255, 215, 106, .12);
}

/* ---- The child's own profile card, at the top of Settings ---------------- */

.kidcard {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--s3) var(--s4);
  align-items: center;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .16), rgba(255, 255, 255, 0) 46%),
    linear-gradient(165deg, var(--teal-deep), #123f6e);
  border: 2px solid rgba(79, 227, 208, .34);
  border-radius: var(--r-card);
  padding: var(--s4);
}

.kidcard__face {
  font-size: 48px;
  line-height: 1;
  background: rgba(0, 0, 0, .24);
  border: 2px solid rgba(255, 255, 255, .2);
  border-radius: 50%;
  width: 78px;
  height: 78px;
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: transform .16s ease, border-color .16s ease;
}
.kidcard__face:hover, .kidcard__face:focus-visible {
  transform: scale(1.05);
  border-color: var(--gold);
  outline: none;
}

.kidcard__who { display: flex; flex-direction: column; gap: 5px; min-width: 0; }
.kidcard__name {
  font: 700 21px/1.15 Fredoka, sans-serif;
  color: #fff;
  overflow-wrap: anywhere;
}

.kidcard__code {
  font: 500 12px/1 'IBM Plex Mono', monospace;
  letter-spacing: .08em;
  color: var(--gold);
  background: rgba(0, 0, 0, .3);
  border: 1px solid rgba(255, 215, 106, .28);
  border-radius: var(--r-pill);
  padding: 6px 11px;
  cursor: pointer;
  align-self: flex-start;
  max-width: 100%;
}
.kidcard__code:hover { background: rgba(0, 0, 0, .42); }

.kidcard__hint { font: 600 11px/1.4 Nunito, sans-serif; color: rgba(255, 255, 255, .5); }

/* The picker spans both columns so eight faces get the full width rather than
   wrapping into the narrow one beside the avatar. */
.kidcard__faces {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--s2);
  padding-top: var(--s1);
}

.kidcard__pick {
  font-size: 26px;
  line-height: 1;
  background: rgba(0, 0, 0, .26);
  border: 2px solid transparent;
  border-radius: var(--r-chip);
  padding: 7px 10px;
  cursor: pointer;
}
.kidcard__pick.is-on { border-color: var(--gold); background: rgba(255, 215, 106, .22); }
.kidcard__pick[disabled] { opacity: .5; cursor: default; }

.kidcard__msg {
  grid-column: 1 / -1;
  margin: 0;
  font: 600 12.5px/1.5 Nunito, sans-serif;
  color: rgba(255, 255, 255, .7);
}
.kidcard__msg--error { color: #ff9ab3; }

@media (prefers-reduced-motion: reduce) {
  .kidcard__face { transition: none; }
  .kidcard__face:hover { transform: none; }
}

/* The chevron on a tile that opens another screen, as opposed to one that
   toggles or acts in place. */
.link-tile__chev {
  margin-left: auto;
  font: 700 18px/1 Nunito, sans-serif;
  color: rgba(255, 255, 255, .4);
}

/* ---- Dashboard: where the child has got to ------------------------------ */

.p-here__now {
  font: 700 19px/1.25 Fredoka, sans-serif;
  color: #fff;
  margin-bottom: 10px;
}

.p-here__meta {
  font: 600 11.5px/1.5 Nunito, sans-serif;
  color: rgba(255, 255, 255, .55);
  margin-top: 8px;
}

.p-map {
  display: flex;
  flex-direction: column;
  gap: 5px;
  margin-top: var(--s4);
}

.p-maprow {
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: 4px 7px;
  border-radius: 9px;
}

/* The table they are on, marked so a parent's eye lands there first. */
.p-maprow.is-here {
  background: rgba(255, 215, 106, .12);
  box-shadow: inset 0 0 0 1px rgba(255, 215, 106, .3);
}

.p-maprow__name {
  font: 700 12px/1 'IBM Plex Mono', monospace;
  color: rgba(255, 255, 255, .7);
  width: 30px;
  flex: none;
  text-align: right;
}
.p-maprow.is-here .p-maprow__name { color: var(--gold); }

.p-maprow__dots { display: flex; gap: 5px; flex: 1; }

.p-node {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  flex: none;
  display: grid;
  place-items: center;
  font-size: 8px;
  line-height: 1;
}

/* The test that closes a table is a square, not a circle — it is a different
   kind of step and should not be miscounted as a fourth lesson. */
.p-node--test { border-radius: 5px; width: 17px; }

.p-node--done    { background: var(--teal); color: #06302c; }
.p-node--current { background: var(--gold); color: #5b2c00; box-shadow: 0 0 0 3px rgba(255, 215, 106, .25); }
.p-node--locked  { background: rgba(255, 255, 255, .12); color: transparent; }

.p-legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--s4);
  margin-top: var(--s3);
  font: 600 10.5px/1 Nunito, sans-serif;
  color: rgba(255, 255, 255, .5);
}
.p-legend__item { display: inline-flex; align-items: center; gap: 6px; }
.p-legend .p-node { width: 11px; height: 11px; }

/* ---- Prizes: the parent's card on the report ----------------------------- */

.prz-list { display: flex; flex-direction: column; gap: 8px; margin-top: 10px; }

.prz-row {
  display: flex;
  align-items: center;
  gap: var(--s3);
  background: rgba(0, 0, 0, .2);
  border: 1px solid rgba(255, 255, 255, .1);
  border-radius: var(--r-chip);
  padding: 8px 10px;
}
.prz-row.is-earned { border-color: rgba(255, 215, 106, .45); background: rgba(255, 215, 106, .1); }

.prz-thumb {
  width: 40px; height: 40px; flex: none;
  border-radius: 10px;
  background: rgba(0, 0, 0, .3) center/cover no-repeat;
  display: grid; place-items: center;
  font-size: 20px;
}

.prz-row__text { display: flex; flex-direction: column; gap: 2px; min-width: 0; flex: 1; }
.prz-row__title { font: 700 14px/1.25 Nunito, sans-serif; color: #fff; overflow-wrap: anywhere; }
.prz-row__meta { font: 600 11px/1.3 Nunito, sans-serif; color: rgba(255, 255, 255, .55); }

.prz-del {
  background: none; border: 0; cursor: pointer; flex: none;
  color: rgba(255, 255, 255, .45);
  font: 700 20px/1 Nunito, sans-serif;
  padding: 4px 8px; border-radius: 8px;
}
.prz-del:hover { color: #ff9ab3; background: rgba(255, 133, 185, .14); }

.prz-form { display: flex; flex-direction: column; gap: var(--s4); margin-top: var(--s4); }
.prz-form__row { display: flex; gap: 8px; flex-wrap: wrap; }
.prz-level { width: 100%; }
.prz-amount { width: 100%; }

/* --------------------------------------------------------------------------
   A labelled field

   Each one says what it is above the control and what it is FOR below it.
   The form used to be four bare controls with placeholder text doing the work
   of labels — which vanishes the moment anyone types, and never explained
   where the value ended up.
   -------------------------------------------------------------------------- */
.prz-field { display: flex; flex-direction: column; gap: 6px; }
.prz-field__label {
  font: 800 12px var(--font-ui);
  color: rgba(255, 255, 255, .85);
  letter-spacing: .02em;
}
.prz-field__hint {
  font: 600 11.5px/1.5 var(--font-ui);
  color: rgba(255, 255, 255, .5);
}

/* --------------------------------------------------------------------------
   The photo row

   The native file input is pulled out of the layout and driven by a real
   button. Browsers draw that control as [Choose File][no file selected], the
   text half is not styleable, and at phone width it truncated to
   "no fi...ected" — which read as an error message about a broken file.
   -------------------------------------------------------------------------- */
.prz-file {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px; border: 0;
  overflow: hidden; clip-path: inset(50%);
  white-space: nowrap;
}
/* The hidden input can still take focus from the keyboard, so the button that
   stands in for it carries the ring. */
.prz-photo__btn:focus-visible,
.prz-photo__clear:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }

.prz-photo {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap;
  background: rgba(0, 0, 0, .26);
  border: 2px dashed rgba(255, 255, 255, .2);
  border-radius: var(--r-chip);
  padding: 10px;
}
.prz-photo__img {
  width: 46px; height: 46px; flex: none;
  border-radius: 10px;
  background: rgba(0, 0, 0, .35) center/cover no-repeat;
  display: grid; place-items: center;
}
.prz-photo__img.has-photo { border: 1px solid rgba(255, 215, 106, .5); }
/* The filename can be a 40-character camera timestamp; it takes what room is
   left and gives up the rest rather than pushing the buttons off the row. */
.prz-photo__name {
  flex: 1 1 90px;
  min-width: 0;
  font: 600 11.5px/1.35 var(--font-ui);
  color: rgba(255, 255, 255, .62);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.prz-photo__btn, .prz-photo__clear {
  flex: none;
  min-height: 40px;
  padding: 9px 14px;
  border-radius: var(--r-chip);
  font: 800 12px var(--font-ui);
}
.prz-photo__btn {
  background: rgba(255, 255, 255, .16);
  border: 1.5px solid rgba(255, 255, 255, .26);
  color: #fff;
}
.prz-photo__btn:hover { background: rgba(255, 255, 255, .24); }
.prz-photo__clear {
  background: none;
  border: 1.5px solid rgba(255, 140, 170, .4);
  color: #ffc3d6;
}
.prz-photo__clear:hover { background: rgba(255, 90, 140, .16); }

/* At the narrowest widths the two buttons take the row to themselves rather
   than squeezing the filename to nothing. */
@media (max-width: 380px) {
  .prz-photo__name { flex: 1 1 100%; order: 3; }
}

/* --------------------------------------------------------------------------
   The preview

   A small copy of the card the child is shown when they pass the table, kept
   in step with every keystroke. A prize is a promise made to a person, and it
   should be possible to read it before making it.
   -------------------------------------------------------------------------- */
.prz-pv { margin: 0; }
.prz-pv__cap {
  font: 800 11px var(--font-ui);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, .45);
  margin-bottom: 7px;
}
.prz-pv__card {
  display: flex; flex-direction: column; align-items: center; gap: 7px;
  text-align: center;
  background: linear-gradient(180deg, rgba(139, 61, 255, .22), rgba(30, 143, 255, .14));
  border: 1.5px solid rgba(255, 215, 106, .3);
  border-radius: var(--r-tile);
  padding: 16px 14px;
}
.prz-pv__ribbon {
  font: 800 10px var(--font-ui);
  letter-spacing: .12em;
  color: var(--ink-2);
  background: linear-gradient(140deg, var(--gold), var(--amber));
  border-radius: var(--r-pill);
  padding: 4px 12px;
}
.prz-pv__art {
  width: 76px; height: 76px;
  border-radius: 18px;
  background: rgba(0, 0, 0, .3) center/cover no-repeat;
  border: 2px solid rgba(255, 215, 106, .4);
  display: grid; place-items: center;
  font-size: 38px; line-height: 1;
}
.prz-pv__art.has-photo { font-size: 0; }
.prz-pv__name {
  font: 700 17px/1.25 var(--font-display);
  color: #fff;
  overflow-wrap: anywhere;
}
.prz-pv__name.is-placeholder { color: rgba(255, 255, 255, .35); font-style: italic; }
.prz-pv__amount {
  font: 800 17px/1 'IBM Plex Mono', monospace;
  color: var(--gold);
}
.prz-pv__ask {
  font: 800 11.5px var(--font-ui);
  color: var(--ink-2);
  background: linear-gradient(140deg, #ffd76a, #ff8a2b);
  border-radius: var(--r-pill);
  padding: 7px 13px;
  margin-top: 2px;
}
.prz-pv__when {
  font: 600 11px/1.4 var(--font-ui);
  color: rgba(255, 255, 255, .5);
}

.prz-save { margin-top: 2px; }
.prz-msg { margin: 8px 0 0; font: 600 12px/1.5 Nunito, sans-serif; color: rgba(255, 255, 255, .7); }

.prz-won { display: flex; flex-direction: column; gap: 8px; }

/* ---------------------------------------------------------------------------
   [hidden] is a User Agent rule (`display: none`), so ANY author rule that
   sets `display` overrides it — including the `flex` and `grid` on the blocks
   below. Every one of these starts hidden and is revealed once its data
   arrives, and without this they render as empty boxes in the meantime: a
   dashed prize ribbon on every table that has no prize, an empty teal profile
   card for a parent, and so on.
   --------------------------------------------------------------------------- */
.prz-won[hidden],
.kidcard[hidden],
.auth__check[hidden],
.kidcard__faces[hidden] { display: none; }

/* ---- The gift at the top of a table's climb ------------------------------ */

.path__slot--prize {
  /* Sits above the test node, so it needs no lean of its own. */
  --shift: 0px;
}

.path__slot--prize[hidden] { display: none; }

.gift {
  width: 74px;
  height: 74px;
  border-radius: 22px;
  font-size: 38px;
  line-height: 1;
  display: grid;
  place-items: center;
  cursor: pointer;
  border: 3px dashed rgba(255, 215, 106, .55);
  background: rgba(255, 215, 106, .14);
  transition: transform .18s cubic-bezier(.2, 1.2, .4, 1), box-shadow .18s ease;
}

.gift:hover, .gift:focus-visible { transform: scale(1.08) rotate(-4deg); outline: none; }
.gift:active { transform: scale(.96); }

/* Won: solid, gold, and lifted. The dashes were the "not yet". */
.gift.is-won {
  border-style: solid;
  border-color: transparent;
  background: linear-gradient(180deg, var(--gold), var(--amber));
  box-shadow: 0 8px 0 #d98e12, 0 16px 30px rgba(255, 160, 0, .45);
  animation: giftwiggle 2.6s ease-in-out infinite;
}

@keyframes giftwiggle {
  0%, 88%, 100% { transform: rotate(0deg); }
  91% { transform: rotate(-7deg); }
  94% { transform: rotate(6deg); }
  97% { transform: rotate(-3deg); }
}

.gift__tag {
  display: block;
  margin-top: 6px;
  max-inline-size: 120px;
  margin-inline: auto;
  font: 700 13px/1.15 Fredoka, sans-serif;
  color: rgba(255, 215, 106, .9);
  text-align: center;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.gift__tag.is-won { color: var(--gold); }

/* ---- The sheet the gift opens ------------------------------------------- */

/* The game's own .sheet is a cream card. This one is dark like the rest of the
   app, because a child meets the purple everywhere else and a pale card here
   would read as a different program. */
.przs {
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .14), rgba(255, 255, 255, 0) 40%),
    linear-gradient(165deg, var(--indigo), #2d1566);
  border: 2px solid rgba(255, 215, 106, .4);
  color: #fff;
  max-width: 360px;
}

.przs__ribbon {
  display: inline-block;
  font: 800 11px/1 Nunito, sans-serif;
  letter-spacing: .14em;
  color: var(--ink-2);
  background: linear-gradient(180deg, var(--gold), var(--amber));
  border-radius: var(--r-pill);
  padding: 7px 14px;
  margin-bottom: var(--s4);
}

.przs__art {
  width: 132px;
  height: 132px;
  margin: 0 auto var(--s4);
  border-radius: 26px;
  background: rgba(0, 0, 0, .28) center/cover no-repeat;
  border: 2px solid rgba(255, 255, 255, .16);
  display: grid;
  place-items: center;
  font-size: 62px;
  line-height: 1;
}
/* A real photo needs no emoji behind it and no inner glow fighting it. */
.przs__art.has-photo { border-color: rgba(255, 215, 106, .5); }
.przs__art.is-won { box-shadow: 0 0 0 6px rgba(255, 215, 106, .18); }

.przs__title {
  font: 700 25px/1.2 Fredoka, sans-serif;
  color: #fff;
  margin: 0 0 6px;
  overflow-wrap: anywhere;
}

.przs__amount {
  font: 800 30px/1 'IBM Plex Mono', monospace;
  color: var(--gold);
  margin-bottom: 10px;
}

.przs__note {
  font: 600 14px/1.55 Nunito, sans-serif;
  color: rgba(255, 255, 255, .72);
  margin: 0 0 var(--s5);
}

.przs__close { width: 100%; min-height: 56px; font: 800 17px/1 Nunito, sans-serif; padding: 15px; }

@media (prefers-reduced-motion: reduce) {
  .gift, .gift.is-won { transition: none; animation: none; }
  .gift:hover, .gift:focus-visible { transform: none; }
}

/* A prize still to win: shown, but in purple, clearly "not yet" against the
   gold of one that has been won. */
.przs--todo { border-color: rgba(255, 255, 255, .22); }
.przs--todo .przs__ribbon {
  background: rgba(255, 255, 255, .16);
  color: #fff;
}
.przs--todo .przs__title { color: rgba(255, 255, 255, .9); }

/* A won certificate: the card is the picture, so the sheet makes room. */
.przs--cert { max-width: 400px; }
.przs__cert { position: relative; z-index: 1; max-inline-size: 300px; margin-block-end: 26px; }

/* ---- Walking from one node to the next ---------------------------------- */

/* Lifted above the path while travelling so he passes in front of the nodes
   he crosses rather than disappearing behind them. */
.map__duck--walking {
  z-index: 6;
  position: relative;
  pointer-events: none;
}

/* The node just cleared, settling as he leaves it. */
.node.is-justdone {
  animation: nodesettle .6s cubic-bezier(.2, 1.2, .4, 1) both;
}

@keyframes nodesettle {
  0%   { transform: scale(1); }
  45%  { transform: scale(1.16); }
  100% { transform: scale(1); }
}

/* The stars the board earned, landing on the node that earned them. */
.node__pop {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 3px;
  pointer-events: none;
  z-index: 7;
}

.node__pop i {
  font-style: normal;
  font-size: 26px;
  color: var(--gold);
  opacity: 0;
  text-shadow: 0 3px 10px rgba(0, 0, 0, .45);
  animation: starfly 1.5s cubic-bezier(.2, 1.2, .4, 1) forwards;
}

@keyframes starfly {
  0%   { opacity: 0; transform: translateY(6px) scale(.4); }
  25%  { opacity: 1; transform: translateY(-14px) scale(1.25); }
  70%  { opacity: 1; transform: translateY(-26px) scale(1); }
  100% { opacity: 0; transform: translateY(-44px) scale(.85); }
}

/* Calm mode and reduced-motion skip the journey: the duck is simply already
   there, which runWalk() handles by returning before it measures anything. */
@media (prefers-reduced-motion: reduce) {
  .map__duck--walking { transition: none !important; }
  .node.is-justdone, .node__pop i { animation: none; }
  .node__pop { display: none; }
}

/* ---- The prize arriving on its own --------------------------------------- */

/* A tapped prize uses the sheet's normal pop. A REVEAL has not been asked for,
   so it announces itself: the card swings in from small and slightly turned,
   and the gift inside lands a beat later. */
.przs--reveal {
  animation: przsreveal .72s cubic-bezier(.18, 1.3, .35, 1) both;
}

@keyframes przsreveal {
  0%   { opacity: 0; transform: scale(.55) rotate(-6deg) translateY(30px); }
  55%  { opacity: 1; transform: scale(1.06) rotate(1.5deg) translateY(0); }
  75%  { transform: scale(.98) rotate(-.5deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

.przs--reveal .przs__art {
  animation: przsart .8s cubic-bezier(.2, 1.4, .35, 1) .3s both;
}

@keyframes przsart {
  0%   { opacity: 0; transform: scale(.3) rotate(-14deg); }
  60%  { opacity: 1; transform: scale(1.14) rotate(5deg); }
  100% { opacity: 1; transform: scale(1) rotate(0deg); }
}

.przs--reveal .przs__ribbon {
  animation: przsribbon .5s cubic-bezier(.2, 1.4, .35, 1) .55s both;
}

@keyframes przsribbon {
  0%   { opacity: 0; transform: translateY(-10px) scale(.8); }
  100% { opacity: 1; transform: translateY(0) scale(1); }
}

/* The glow behind the card, so the reveal reads as a moment rather than a
   dialog that happened to appear. */
.overlay--prize.overlay--reveal {
  animation: revealglow .9s ease-out both;
}

@keyframes revealglow {
  0%   { background-color: rgba(12, 6, 32, 0); }
  100% { background-color: rgba(12, 6, 32, .72); }
}

/* ---- The reveal's own furniture ------------------------------------------
   Light behind the gift and Quackers on the corner of the card. Both exist
   only on a reveal — a prize the child tapped is a thing on a shelf, one that
   arrives is an event, and this is most of what separates them. */

.przs { position: relative; }

.przs__rays {
  position: absolute;
  top: 34px;
  left: 50%;
  width: 260px;
  height: 260px;
  margin-left: -130px;
  z-index: 0;
  pointer-events: none;
  opacity: .5;
  background: conic-gradient(
    from 0deg,
    rgba(255, 215, 106, .5) 0deg 12deg, transparent 12deg 30deg,
    rgba(255, 215, 106, .5) 30deg 42deg, transparent 42deg 60deg,
    rgba(255, 215, 106, .5) 60deg 72deg, transparent 72deg 90deg,
    rgba(255, 215, 106, .5) 90deg 102deg, transparent 102deg 120deg,
    rgba(255, 215, 106, .5) 120deg 132deg, transparent 132deg 150deg,
    rgba(255, 215, 106, .5) 150deg 162deg, transparent 162deg 180deg,
    rgba(255, 215, 106, .5) 180deg 192deg, transparent 192deg 210deg,
    rgba(255, 215, 106, .5) 210deg 222deg, transparent 222deg 240deg,
    rgba(255, 215, 106, .5) 240deg 252deg, transparent 252deg 270deg,
    rgba(255, 215, 106, .5) 270deg 282deg, transparent 282deg 300deg,
    rgba(255, 215, 106, .5) 300deg 312deg, transparent 312deg 330deg,
    rgba(255, 215, 106, .5) 330deg 342deg, transparent 342deg 360deg);
  /* Faded out at both ends so it is light around the gift rather than a wheel
     drawn on the card. */
  -webkit-mask-image: radial-gradient(circle, transparent 22%, #000 38%, transparent 72%);
  mask-image: radial-gradient(circle, transparent 22%, #000 38%, transparent 72%);
  animation: przsrays 14s linear infinite, przsraysin .9s ease-out both;
}

@keyframes przsrays { to { transform: rotate(360deg); } }
@keyframes przsraysin { from { opacity: 0; } to { opacity: .5; } }

/* Everything else on the card sits in front of the light. */
.przs__ribbon,
.przs__art,
.przs__title,
.przs__amount,
.przs__note,
.przs__close { position: relative; z-index: 1; }

.przs__duck {
  position: absolute;
  top: -34px;
  right: -6px;
  z-index: 2;
  pointer-events: none;
  animation: przsduck .5s cubic-bezier(.2, 1.5, .4, 1) .45s both;
}

@keyframes przsduck {
  0%   { opacity: 0; transform: translateY(26px) scale(.6) rotate(-12deg); }
  100% { opacity: 1; transform: translateY(0) scale(1) rotate(-6deg); }
}

/* On a small phone the card is close to the edge of the screen, so he tucks
   in rather than hanging off it. A transform here would be overwritten by the
   entrance animation's own, so this moves him with offsets only. */
@media (max-width: 380px) {
  .przs__duck { top: -24px; right: 2px; }
  .przs__rays { width: 220px; height: 220px; margin-left: -110px; }
}

@media (prefers-reduced-motion: reduce) {
  .przs--reveal,
  .przs--reveal .przs__art,
  .przs--reveal .przs__ribbon,
  .przs__duck,
  .overlay--prize.overlay--reveal { animation: none; }
  /* The light stays — it is the moment — but it stops turning. */
  .przs__rays { animation: none; }
}
