/* Reveal — the Dreamlight palette.
   Concept C's night sky with Concept A's square slots: the board shows where
   every piece will land before any of them arrive, so a child can see how much
   of the picture is still out there. */

:root{
  --void:#070818; --deep:#12132f; --panel:#1a1b40; --panel-2:#141535;
  --ink:#eef0ff; --dim:#9b9ac9; --faint:#6b6a99;
  --violet:#a78bfa; --aqua:#7dd3fc; --rose:#f9a8d4; --star:#fef3c7;
  --good:#86efac; --miss:#fca5a5;
  --line:rgba(167,139,250,.28);
  --r-sm:10px; --r-md:16px; --r-lg:22px;
}

*{box-sizing:border-box;margin:0;padding:0;-webkit-tap-highlight-color:transparent}
[hidden]{display:none!important}
html,body{height:100%;overflow-x:clip}
body{
  background:var(--void);color:var(--ink);
  font-family:Quicksand,system-ui,-apple-system,sans-serif;
  font-weight:600;
  overscroll-behavior-y:none;
  -webkit-font-smoothing:antialiased;
  background-image:
    radial-gradient(100% 55% at 20% 6%,rgba(167,139,250,.26) 0%,transparent 58%),
    radial-gradient(90% 50% at 82% 20%,rgba(125,211,252,.18) 0%,transparent 56%),
    radial-gradient(85% 45% at 50% 100%,rgba(249,168,212,.14) 0%,transparent 60%),
    linear-gradient(180deg,#12132f 0%,#0a0b20 58%,#060714 100%);
  background-attachment:fixed;
}
/* Starfield, drawn as one repeating tile rather than hundreds of elements. */
body::before{
  content:"";position:fixed;inset:0;pointer-events:none;z-index:0;opacity:.8;
  background-image:
    radial-gradient(1.4px 1.4px at 18% 24%,rgba(255,255,255,.9),transparent),
    radial-gradient(1px 1px at 62% 12%,rgba(255,255,255,.6),transparent),
    radial-gradient(1.6px 1.6px at 84% 58%,rgba(254,243,199,.85),transparent),
    radial-gradient(1px 1px at 34% 72%,rgba(255,255,255,.5),transparent),
    radial-gradient(1.2px 1.2px at 8% 88%,rgba(125,211,252,.7),transparent),
    radial-gradient(1px 1px at 74% 90%,rgba(255,255,255,.5),transparent);
  background-size:340px 300px;
  animation:drift 120s linear infinite;
}
@keyframes drift{to{background-position:340px 300px,-340px 300px,340px -300px,-340px -300px,340px 300px,-340px 300px}}

/* ---------------------------------------------------------------- screens */
.screen{
  position:relative;z-index:1;min-height:100dvh;
  max-width:820px;margin:0 auto;
  padding:max(14px,env(safe-area-inset-top)) 15px max(18px,env(safe-area-inset-bottom));
  display:flex;flex-direction:column;gap:13px;
}
.screen[hidden]{display:none!important}
.fill{flex:1 1 auto;min-height:0;display:flex;flex-direction:column;justify-content:center;gap:16px}

h1,h2,h3{font-family:'Cormorant Garamond',Georgia,serif;font-weight:400;line-height:1.05}
em{font-style:italic;color:var(--aqua)}
.kick{font-size:9.5px;letter-spacing:.3em;color:var(--violet);font-weight:700;text-transform:uppercase}
.muted{color:var(--dim);font-weight:600}

/* ---------------------------------------------------------------- buttons */
.btn{
  font-family:Quicksand,sans-serif;font-weight:700;font-size:16px;color:#0d0e22;
  background:linear-gradient(135deg,var(--star),var(--rose));border:none;border-radius:99px;
  padding:15px 34px;cursor:pointer;box-shadow:0 10px 30px -12px rgba(254,243,199,.8);
  transition:transform .2s,box-shadow .2s;
}
.btn:hover{transform:translateY(-2px);box-shadow:0 16px 34px -12px rgba(254,243,199,.9)}
.btn:active{transform:translateY(0)}
.btn:focus-visible{outline:2px solid var(--star);outline-offset:4px}
.btn.ghost{background:transparent;color:var(--aqua);border:1px solid rgba(125,211,252,.45);box-shadow:none}
.btn.ghost:hover{background:rgba(125,211,252,.1);transform:none}
.btn.small{font-size:14px;padding:11px 22px}
.icon-btn{
  width:44px;height:44px;flex:0 0 auto;border:1px solid var(--line);border-radius:14px;
  background:transparent;color:var(--dim);cursor:pointer;display:grid;place-items:center;transition:.2s;
}
.icon-btn:hover{color:var(--aqua);border-color:var(--aqua)}
.icon-btn:focus-visible{outline:2px solid var(--aqua);outline-offset:2px}
.icon-btn svg{width:19px;height:19px}
.icon-btn.off{color:var(--miss);border-color:rgba(252,165,165,.5)}

/* ---------------------------------------------------------------- topbar */
.topbar{display:flex;align-items:center;gap:11px;flex:0 0 auto}
.topbar .who{flex:1;min-width:0}
.topbar h2{font-size:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sparkcount{display:flex;align-items:center;gap:5px;font-weight:700;font-size:15px;color:var(--star);
  font-variant-numeric:tabular-nums}
.sparkcount svg{width:15px;height:15px}

/* ---------------------------------------------------------------- the board */
.board-wrap{flex:0 1 auto;width:100%;min-height:0;display:flex;justify-content:center}
.board{
  position:relative;width:100%;max-width:560px;aspect-ratio:4/3;border-radius:var(--r-lg);
  background:radial-gradient(circle at 50% 50%,rgba(167,139,250,.12),rgba(7,8,24,.5) 74%);
  box-shadow:0 0 70px -20px rgba(167,139,250,.5),inset 0 0 40px rgba(7,8,24,.55);
  padding:7px;
}
/* Empty slots. The outline is the whole point of this hybrid: the shape of the
   finished picture is legible from the first second, so a half-built board reads
   as "four still out there" rather than as an accident. */
.slots{position:absolute;inset:7px;display:grid;gap:3px;border-radius:var(--r-md);overflow:hidden}
.slot{
  border:1px solid rgba(167,139,250,.26);border-radius:3px;
  background:linear-gradient(150deg,rgba(167,139,250,.07),rgba(7,8,24,.16));
  transition:opacity .5s ease,border-color .5s ease;
}
.slot.filled{opacity:0;border-color:transparent}
.pieces{position:absolute;inset:7px;border-radius:var(--r-md);overflow:hidden}
.pc{position:absolute;background-repeat:no-repeat;opacity:0;will-change:transform,opacity,filter}
.pc.here{animation:arrive .82s cubic-bezier(.16,.84,.32,1) forwards}
@keyframes arrive{
  0%{opacity:0;transform:translate(var(--fx),var(--fy)) rotate(var(--fr)) scale(.4);filter:brightness(2.4) blur(7px)}
  55%{opacity:1;filter:brightness(1.4) blur(1px)}
  /* Settles a whisker over 1:1. A 5x3 grid lands on fractional pixels and the
     rounding leaves a visible hairline between finished neighbours; 1.006 was
     under half a device pixel of overlap and some seams still showed at 2x.
     The image scales with the transform, so this closes them without knocking
     anything measurably out of alignment. */
  100%{opacity:1;transform:scale(1.016);filter:none}
}
.spark{position:absolute;width:9px;height:9px;border-radius:50%;pointer-events:none;z-index:3;
  background:radial-gradient(circle,#fff,var(--star) 40%,transparent 70%);
  animation:trail .85s ease-out forwards}
@keyframes trail{from{opacity:1;transform:scale(1.6)}to{opacity:0;transform:scale(.2)}}
.board-hint{
  position:absolute;inset:0;display:grid;place-items:center;pointer-events:none;padding:20px;
  font-family:'Cormorant Garamond',serif;font-style:italic;font-size:16px;
  color:rgba(178,176,224,.72);text-align:center;transition:opacity .6s;
  /* Sits directly over the slot outlines, which cut through the letterforms. */
  text-shadow:0 1px 10px rgba(7,8,24,.98),0 0 22px rgba(7,8,24,.95);
}
.board-hint.gone{opacity:0}

/* ---------------------------------------------------------------- progress */
.dots{display:flex;gap:4px;flex-wrap:wrap;justify-content:flex-end}
/* In the play header the dots sit under the hall name and read left to right
   with it, rather than being right-aligned into a wrap. */
.topbar .who .dots{justify-content:flex-start;margin-top:6px}
.dot{width:6.5px;height:6.5px;border-radius:50%;background:rgba(167,139,250,.24);transition:.45s}
.dot.on{background:var(--star);box-shadow:0 0 9px var(--star)}
.dot.miss{background:rgba(252,165,165,.45)}

/* ---------------------------------------------------------------- quiz */
.panel{flex:0 0 auto;display:flex;flex-direction:column;gap:11px}
.qline{min-height:58px;display:flex;align-items:center;justify-content:center;text-align:center}
.qline p{
  font-family:'Cormorant Garamond',serif;font-weight:600;font-size:clamp(20px,5.3vw,28px);
  line-height:1.2;opacity:0;transform:translateY(8px);transition:.48s ease;
}
.qline p.in{opacity:1;transform:none}
.qline p.narr{font-weight:400;font-style:italic;color:var(--dim);font-size:clamp(16px,4.2vw,20px)}

.choices{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.choice{
  font-family:Quicksand,sans-serif;font-weight:600;font-size:clamp(15px,4.1vw,17.5px);color:var(--ink);
  background:rgba(167,139,250,.1);border:1px solid var(--line);border-radius:var(--r-md);
  padding:15px 11px;min-height:60px;cursor:pointer;backdrop-filter:blur(6px);
  opacity:0;transform:translateY(9px);
  transition:opacity .38s,transform .2s,background .25s,border-color .25s,box-shadow .25s;
}
.choice.in{opacity:1;transform:none}
.choice.reading{border-color:var(--aqua);background:rgba(125,211,252,.17);
  box-shadow:0 0 26px -4px rgba(125,211,252,.6)}
.choice:focus-visible{outline:2px solid var(--aqua);outline-offset:3px}
@media (hover:hover){.choice:not(.locked):hover{background:rgba(167,139,250,.21);border-color:var(--violet)}}
.choice:active:not(.locked){transform:scale(.97)}
.choice.right{background:rgba(134,239,172,.22);border-color:var(--good);
  box-shadow:0 0 30px -4px rgba(134,239,172,.6)}
.choice.wrong{background:rgba(252,165,165,.17);border-color:var(--miss)}
.choice.locked{cursor:default}
.choice.dimmed{opacity:.3}

.tray{display:flex;gap:10px}
.guess{
  flex:1;font-family:'Cormorant Garamond',serif;font-style:italic;font-size:16.5px;color:var(--star);
  background:transparent;border:1px solid rgba(254,243,199,.35);border-radius:var(--r-md);
  padding:12px;cursor:pointer;transition:.22s;
}
.guess:hover{background:rgba(254,243,199,.09);border-color:var(--star)}
.guess:focus-visible{outline:2px solid var(--star);outline-offset:2px}
.guess:disabled{opacity:.35;cursor:default}

.fact{max-height:0;opacity:0;overflow:hidden;text-align:center;font-size:13.5px;line-height:1.55;
  color:var(--dim);transition:max-height .42s ease,opacity .42s ease,padding .42s ease}
.fact.show{max-height:82px;opacity:1;padding-top:2px}
.fact b{color:var(--aqua);font-weight:700}

/* ---------------------------------------------------------------- result */
.result{align-items:center;animation:rise .55s cubic-bezier(.2,.8,.3,1) both}
@keyframes rise{from{opacity:0;transform:translateY(18px)}to{opacity:1;transform:none}}
.title-out{font-family:'Cormorant Garamond',serif;font-size:clamp(23px,6.2vw,31px);text-align:center;
  margin-bottom:11px}
.stars{display:flex;justify-content:center;gap:10px;margin-bottom:14px}
.stars svg{width:34px;height:34px;fill:rgba(254,243,199,.14);stroke:rgba(254,243,199,.38);stroke-width:1.2}
.stars svg.on{fill:var(--star);stroke:#fff;filter:drop-shadow(0 0 14px rgba(254,243,199,.85));
  animation:pop .5s cubic-bezier(.2,1.5,.4,1) both}
@keyframes pop{from{transform:scale(0) rotate(-40deg)}to{transform:scale(1) rotate(0)}}
.tally{display:flex;justify-content:center;gap:24px;margin-bottom:20px;font-size:10.5px;color:var(--dim);
  text-transform:uppercase;letter-spacing:.11em;font-weight:700;text-align:center}
.tally b{display:block;font-family:'Cormorant Garamond',serif;font-size:27px;color:var(--star);
  letter-spacing:0;text-transform:none;font-variant-numeric:tabular-nums;font-weight:600}
.result-actions{display:flex;gap:10px;justify-content:center;flex-wrap:wrap}

/* ---------------------------------------------------------------- hall map */
.halls{display:grid;grid-template-columns:repeat(auto-fill,minmax(148px,1fr));gap:12px;
  padding-bottom:6px}
.hall{
  --hue:#a78bfa;
  position:relative;text-align:left;border:1px solid color-mix(in srgb,var(--hue) 30%,transparent);
  border-radius:var(--r-md);
  background:linear-gradient(165deg,rgba(26,27,64,.9),rgba(16,17,44,.9));overflow:hidden;
  cursor:pointer;transition:transform .2s,border-color .2s,box-shadow .2s;padding:0;
  font-family:inherit;color:inherit;display:block;width:100%;
}
.hall:hover{transform:translateY(-3px);border-color:var(--hue);
  box-shadow:0 16px 34px -16px color-mix(in srgb,var(--hue) 80%,transparent)}
.hall:focus-visible{outline:2px solid var(--aqua);outline-offset:3px}
.hall .thumb{
  position:relative;aspect-ratio:4/3;overflow:hidden;display:grid;place-items:center;
  background:
    radial-gradient(90% 80% at 50% 40%,color-mix(in srgb,var(--hue) 16%,transparent),transparent 70%),
    #0b0c22;
}
.hall .thumb img{width:100%;height:100%;object-fit:cover;display:block}
/* An unearned hall shows the slot grid it will fill, never the picture -- plus
   its own colour and glyph, so the map is scannable by a child who is still
   learning to read the labels. */
.hall .thumb .locked-grid{position:absolute;inset:6px;display:grid;gap:2px;
  grid-template-columns:repeat(5,1fr);grid-template-rows:repeat(3,1fr)}
.hall .thumb .locked-grid i{
  border:1px solid color-mix(in srgb,var(--hue) 26%,transparent);border-radius:2px;
  background:color-mix(in srgb,var(--hue) 6%,transparent);
}
.hall .thumb .glyph{
  position:relative;width:44%;max-width:76px;aspect-ratio:1;color:var(--hue);opacity:.9;
  filter:drop-shadow(0 0 16px color-mix(in srgb,var(--hue) 55%,transparent));
}
.hall.lit .meta h3{color:var(--hue)}
.hall .meta{padding:11px 12px 13px}
.hall .meta h3{font-size:17px;margin-bottom:2px}
.hall .meta .sub{font-size:11px;color:var(--faint);font-weight:600}
.hall .ribbon{
  position:absolute;top:8px;right:8px;display:flex;gap:2px;background:rgba(7,8,24,.78);
  padding:4px 7px;border-radius:99px;border:1px solid rgba(254,243,199,.3);
}
.hall .ribbon svg{width:11px;height:11px;fill:var(--star)}
.hall .ribbon svg.off{fill:rgba(254,243,199,.22)}

/* ---------------------------------------------------------------- gallery */
.gallery{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}
.frame{
  position:relative;aspect-ratio:4/3;border-radius:var(--r-sm);overflow:hidden;cursor:pointer;
  border:1px solid var(--line);background:#0b0c22;padding:0;display:block;width:100%;
  transition:transform .2s,box-shadow .2s;
  /* A button inherits neither of these, so the caption was rendering in the
     UA's default black over a sunlit picture. */
  color:var(--ink);font-family:inherit;
}
.frame:hover{transform:translateY(-3px);box-shadow:0 16px 30px -16px rgba(167,139,250,.8)}
.frame:focus-visible{outline:2px solid var(--aqua);outline-offset:3px}
.frame img{width:100%;height:100%;object-fit:cover;display:block}
.frame .cap{
  position:absolute;left:0;right:0;bottom:0;padding:16px 9px 7px;font-size:11px;font-weight:700;
  background:linear-gradient(180deg,transparent,rgba(7,8,24,.92));text-align:left;
}
.frame.empty{display:grid;place-items:center;color:var(--dim);font-size:12.5px;text-align:center;
  padding:10px;cursor:default;line-height:1.9}
.frame.empty:hover{transform:none;box-shadow:none}
.frame.empty .faint{color:var(--faint);font-size:11px}

/* ---------------------------------------------------------------- overlays */
.veil{
  position:fixed;inset:0;z-index:60;display:grid;place-items:center;padding:24px;text-align:center;
  background:radial-gradient(circle at 50% 38%,rgba(18,19,47,.94),rgba(6,7,20,.98));
  backdrop-filter:blur(8px);transition:opacity .4s;overflow-y:auto;
}
.veil[hidden]{display:none!important}
.veil .card{max-width:440px;width:100%;animation:rise .55s cubic-bezier(.2,.8,.3,1) both;
  margin:auto;padding:8px 0}
.veil h2{font-size:clamp(32px,8.5vw,46px);margin-bottom:14px}
.veil p{font-size:14.5px;line-height:1.7;color:var(--dim);margin-bottom:24px}
.veil .kick{margin-bottom:13px}
.gopts{display:grid;gap:10px;margin-bottom:18px}
.gopt{
  font-family:Quicksand;font-weight:600;font-size:16px;color:var(--ink);background:rgba(167,139,250,.12);
  border:1px solid var(--line);border-radius:var(--r-md);padding:14px;cursor:pointer;transition:.2s;
}
.gopt:hover{border-color:var(--aqua);background:rgba(125,211,252,.16)}
.gopt:focus-visible{outline:2px solid var(--aqua);outline-offset:2px}
.gopt.no{border-color:var(--miss);animation:shake .38s}
@keyframes shake{25%{transform:translateX(-6px)}75%{transform:translateX(6px)}}

.code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:clamp(17px,5vw,23px);
  letter-spacing:.1em;color:var(--star);background:rgba(254,243,199,.08);
  border:1px dashed rgba(254,243,199,.4);border-radius:var(--r-sm);padding:14px 10px;
  margin-bottom:14px;user-select:all;word-break:break-all;
}
.field{
  width:100%;font-family:ui-monospace,monospace;font-size:16px;letter-spacing:.08em;text-align:center;
  color:var(--ink);background:rgba(167,139,250,.1);border:1px solid var(--line);
  border-radius:var(--r-sm);padding:14px;margin-bottom:12px;text-transform:uppercase;
}
.field:focus{outline:2px solid var(--aqua);outline-offset:1px}
.status{font-size:12.5px;min-height:18px;margin-bottom:12px;color:var(--dim)}
.status.bad{color:var(--miss)}
.status.good{color:var(--good)}

.badge{
  position:fixed;left:50%;top:16px;transform:translateX(-50%);z-index:80;
  background:rgba(6,7,20,.92);border:1px solid var(--violet);color:var(--ink);font-size:12.5px;
  font-weight:700;padding:9px 17px;border-radius:99px;opacity:0;transition:.3s;pointer-events:none;
}
.badge.show{opacity:1;transform:translateX(-50%) translateY(4px)}

/* ---------------------------------------------------------------- responsive */
@media (max-width:380px){
  .choice{padding:13px 8px;min-height:54px}
  .choices{gap:8px}
  .halls{grid-template-columns:repeat(auto-fill,minmax(132px,1fr));gap:10px}
}
@media (prefers-reduced-motion:reduce){
  *{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important}
}

/* Build stamp, tucked under the story. Faint on purpose: it is for whoever is
   deploying, not for the eight-year-old reading the story above it. */
.build-stamp{
  margin:22px 0 0!important;font-size:10.5px;letter-spacing:.1em;color:var(--faint);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;opacity:.75;
}

/* Cloud-sync status. A coloured dot and a sentence, because a spinner tells a
   parent nothing about whether the pictures are safe. */
.sync{display:flex;align-items:center;justify-content:center;gap:8px;font-size:12.5px;
  color:var(--dim);margin-bottom:16px;min-height:20px}
.sync-dot{width:8px;height:8px;border-radius:50%;background:var(--faint);flex:0 0 auto;transition:.3s}
.sync.saving .sync-dot{background:var(--aqua);animation:pulse 1.1s ease-in-out infinite}
.sync.saved  .sync-dot{background:var(--good);box-shadow:0 0 9px rgba(134,239,172,.8)}
.sync.offline .sync-dot,.sync.retrying .sync-dot{background:var(--star)}
.sync.error  .sync-dot{background:var(--miss)}
.sync.saved{color:var(--good)}
.sync.error{color:var(--miss)}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.35}}
