.home-sky {
  width: min(420px, calc(100% - 24px));
  margin: 0 auto;
}

.home-constellation {
  display: block;
  width: 100%;
  height: auto;
  max-height: 46vh;
  color: var(--text);
  overflow: visible;
}

/* A star is a link: it brightens on hover and shows a ring on keyboard focus, so it is plainly
   pressable without a label saying so. */
.nav-star {
  cursor: pointer;
  outline: none;
  /* The labels stand on the sky, not on a panel, so they use the strongest text colour — not the
     link colour, which on the dawn sky is 4.3:1. Hovering turns them to the link colour: that is
     an interaction state, and it is only ever seen while a finger or pointer is on the star. */
  color: var(--text);
  text-decoration: none;
}

.nav-star:hover text,
.nav-star:focus-visible text {
  fill: var(--accent-strong);
}

.nav-star .nav-halo {
  transition: opacity 0.2s;
}

.nav-star:hover .nav-halo,
.nav-star:focus-visible .nav-halo {
  opacity: 1;
  filter: brightness(1.25);
}

.nav-star:focus-visible .nav-hit {
  stroke: var(--accent-strong);
  stroke-width: 2;
}

.nav-star text {
  paint-order: stroke;
}

/* The one moving thing on the front page, and it moves slowly: the training star breathes, to say
   «start here». Anyone who has asked their device for less motion gets it still. */
@keyframes nav-breathe {
  0%, 100% { opacity: 0.8; }
  50% { opacity: 1; }
}

.nav-pulse {
  animation: nav-breathe 4.5s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
  .nav-pulse {
    animation: none;
  }
}

.constellation {
  display: block;
  width: 100%;
  max-width: 380px;
  margin: 8px auto 14px;
  color: var(--text);
}

/* The training app draws every screen inside #app, so #app is the glass sheet — the same one
   the reading pages have. Nothing the app shows ever sits directly on the sky. Empty until the
   app starts (and until the boot guard fills it), so an unstarted page shows no blank panel. */
#app {
  width: min(640px, calc(100% - 24px));
  margin: 12px auto 0;
  background: var(--surface-glass);
  border: 0.5px solid var(--surface-glass-border);
  border-radius: 24px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

#app:empty {
  display: none;
}

/* Inside the sheet a card is just its contents: a second frame round text that already sits on
   glass reads as a box in a box. */
#app .card-glass {
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.card-glass {
  background: var(--surface-glass);
  border: 0.5px solid var(--surface-glass-border);
  border-radius: 20px;
  padding: 16px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.btn-primary {
  background: var(--accent-gradient);
  color: var(--accent-text);
  border: none;
  border-radius: 999px;
  padding: 12px 22px;
  font-size: 16px;
  font-weight: 500;
  font-family: inherit;
  cursor: pointer;
  /* The one place the sky is allowed to glow: the thing to press. */
  box-shadow: var(--glow);
}

.btn-primary:hover {
  filter: brightness(1.08);
}

/* Pressed is a dimming, not a colour change: the old rule swapped the fill for the link
   colour, which is now cyan and would have put white text on it. */
.btn-primary:active {
  filter: brightness(0.92);
}

.pill-warm {
  display: inline-block;
  background: var(--warm);
  color: var(--warm-text);
  border-radius: 999px;
  padding: 3px 10px;
  font-size: 12px;
}

/* The training app's footer. It lives in index.html, which loads this file and palette.css
   but not content.css — so the link colouring the server-rendered pages get from
   `.site-foot a` never reached it, and every link there came out in the browser's default
   blue and purple, next to a warm grey page. */
.app-foot {
  /* On a glass panel, not on the sky: loose text at the bottom of the page sits on the lowest,
     lightest part of the twilight, where white text measures 3.5:1. */
  width: min(640px, calc(100% - 24px));
  margin: 24px auto 0;
  padding: 20px 24px;
  background: var(--surface-glass);
  border: 0.5px solid var(--surface-glass-border);
  border-radius: 20px;
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1.6;
}

.app-foot a {
  color: var(--text);
}

/* The one control that changes the whole site: which sky. Sits at the end of the header, so
   it is where a person looks for settings and never covers what they came to read. */
.sky-toggle {
  margin-left: auto;
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 0.5px solid var(--surface-glass-border);
  background: var(--surface-glass);
  color: var(--text);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
}

.sky-toggle:hover {
  box-shadow: var(--glow);
}

/* The header, on every page — reading pages, the static pages, the training app. It is the one
   thing that sits on the bare sky, so it takes the strongest text colour (not the muted one) and
   a test measures it against the top of both skies, where the sky is darkest. */
.site-head {
  display: flex;
  align-items: center;
  gap: 14px;
  width: min(42rem, calc(100% - 24px));
  margin: 0 auto;
  padding: 14px 4px;
  color: var(--text);
  font-size: 15px;
}

.site-head a {
  color: inherit;
}

/* The mark is a link home, so it needs a hit area a thumb can find; the picture itself is
   smaller than the area around it. */
.site-mark {
  display: inline-flex;
  flex: 0 0 auto;
  padding: 4px;
  margin: -4px;
}

.site-mark img {
  display: block;
  width: 50px;
  height: 40px;
}

/* The links wrap under themselves rather than under the mark. */
.site-nav {
  min-width: 0;
  line-height: 1.5;
}

/* The native look of a control is a light grey box; on the sky it is a hole. Every button that
   is not styled by a class of its own takes the panel look and the text colour. */
button {
  color: var(--text);
}

/* Windows High Contrast (forced colours) drops gradients and shadows, so a button that is only a
   gradient with no border would lose its edge and vanish. Give the shapes a real border there. */
@media (forced-colors: active) {
  .btn-primary,
  .kids-btn,
  .kids-cell,
  .kids-tile,
  .sky-toggle,
  #app,
  .reading,
  .site-foot,
  .app-foot,
  .card-glass {
    border: 1px solid CanvasText;
  }
}

/* The spatial-memory exercise. Cells are big enough for a thumb (at 5×5 on a 320px phone the
   panel leaves them about 44px), and «lit» is the accent so it reads on both skies. */
.spatial-grid {
  display: grid;
  gap: 8px;
  max-width: 320px;
  margin: 12px auto 0;
}

.spatial-cell {
  aspect-ratio: 1 / 1;
  min-height: 44px;
  border: 1px solid var(--surface-glass-border);
  border-radius: 12px;
  background: var(--surface-glass);
  cursor: pointer;
}

.spatial-cell:disabled {
  cursor: default;
}

.spatial-cell.lit {
  background: var(--accent);
  border-color: var(--accent);
  box-shadow: var(--glow);
}

/* Chosen, before the answer is shown: a filled outline, not the answer's colour. */
.spatial-cell.picked {
  border: 3px solid var(--accent-strong);
}

/* A tap on a place that was never lit: dashed, so it is told apart without relying on colour. */
.spatial-cell.wrong {
  border: 2px dashed var(--text);
  opacity: 0.7;
}

@media (forced-colors: active) {
  .spatial-cell.lit {
    background: Highlight;
  }
}

/* In forced-colours mode the page's colours are replaced, so the reaction square would never turn
   green or red. Keep its colour, and give it an outline so it is a visible shape either way. */
@media (forced-colors: active) {
  #reaction-box {
    forced-color-adjust: none;
    border: 2px solid CanvasText;
  }
}

/* The labels of the front-page constellation carry a halo in the sky's own colour: a star's
   line that runs to or past a label goes under the word instead of striking it through. */
.home-constellation text {
  paint-order: stroke;
  stroke: var(--bg);
  stroke-width: 4px;
  stroke-linejoin: round;
}
