/* styles.css — Lunar Card demo app.
   Adapted from skycard/styles.css: same card, search row, chips, day strip
   and skeleton, retuned from Skycard's dusk-violet to a deeper night blue.
   Like Skycard, this page deliberately does NOT load ../shared.css — that
   stylesheet claims :root, the universal selector and body, and would
   fight this one — so the CSS for every shared component used here
   (MoonDisc, LunarWheel) is restated at the bottom of this file rather
   than linked. */

:root {
  --page-bg: #0a0d18;
  --page-bg-2: #141a2e;
  --card-w: 380px;
  --card-radius: 24px;
  --card-grad-1: #131c33;
  --card-grad-2: #1b2748;
  --card-grad-3: #26355e;
  --text-hero: #eef2fb;
  --text-soft: #c3cde6;
  --text-dim: #97a4c4;
  --chip-bg: rgba(255, 255, 255, 0.07);
  --chip-border: rgba(255, 255, 255, 0.13);
  --strip-bg: rgba(8, 12, 26, 0.36);
  --pill-bg: rgba(255, 255, 255, 0.16);
  --accent: #ffd35c;
  --shadow-color: rgba(10, 14, 34, 0.6);
  --font-sans: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Consolas, monospace;

  /* MoonDisc / LunarWheel tokens (the components read these; in the gallery
     pages they come from ../shared.css instead). */
  --moon-lit: #dfe7f7;
  --moon-lit-hi: #ffffff;
  --moon-dark: #161e34;
  --moon-mare: #9db0d2;
  --moon-rim: rgba(255, 255, 255, 0.22);
  --moon-glow: #b9cdff;
  --lw-today: #ffd35c;
  --lw-guide: rgba(255, 255, 255, 0.10);
}

* {
  box-sizing: border-box;
}

html {
  /* min-height, not height (2026-09-06): with html/body at height:100% the
     body's radial gradient tiled at exactly one viewport height, so a tall
     page showed a hard horizontal seam where the second tile began. Let the
     root grow with the content, paint the gradient once, and back it with
     the gradient's own end colour so nothing can ever show a seam. */
  min-height: 100%;
  background: var(--page-bg);
}

body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  /* Column flex + auto main-axis margins on .card (2026-09-06): a flex-
     centred child taller than the viewport overflows ABOVE the top edge
     where it can't be scrolled to (the Lunar card's search row + hero were
     clipped under the topbar on load). Main-axis auto margins centre the
     card when there is room and pin it to the top when there isn't. They
     must be MAIN-axis margins: cross-axis auto margins do nothing here
     because a min-height body has no definite cross size. */
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 32px 16px;
  font-family: var(--font-sans);
  background: radial-gradient(circle at 70% 8%, var(--page-bg-2), var(--page-bg) 62%);
  background-repeat: no-repeat;
  color: var(--text-hero);
}

.page-wrap {
  /* The flex item of the column-flex body (2026-09-06): main-axis auto
     margins centre the card when it fits the viewport and pin it to the
     top (below the fixed topbar) when it is taller, instead of
     align-items:center pushing its top off-screen. */
  margin-top: auto;
  margin-bottom: auto;
  width: 100%;
  max-width: var(--card-w);
  display: flex;
  flex-direction: column;
  gap: 10px;
}

#app {
  width: 100%;
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------- */
/* Card                                                                    */
/* ---------------------------------------------------------------------- */

.card {
  position: relative;
  /* Its own stacking context (2026-09-06 topbar-bleed fix): keeps every
     effect the card draws — the hero moon's glow (filter: drop-shadow on
     .md-full), gradients, the starfield — unambiguously below the fixed
     .topbar's z-index:30. overflow:hidden below already clips the glow to
     the card's own box (confirmed: it never paints past the card's edge);
     the bar's own background opacity (index.html's inline <style>) is what
     stops it showing THROUGH the bar once the card scrolls behind it. */
  isolation: isolate;
  width: 100%;
  min-height: 560px;
  border-radius: var(--card-radius);
  overflow: hidden;
  padding: 20px 20px 16px;
  display: flex;
  flex-direction: column;
  background:
    linear-gradient(165deg, var(--card-grad-3) 0%, var(--card-grad-2) 46%, var(--card-grad-1) 100%);
  box-shadow:
    0 24px 60px -12px var(--shadow-color),
    0 8px 24px -8px rgba(6, 9, 22, 0.55);
  animation: cardEnter 0.4s ease-out both;
}

.card.no-enter {
  animation: none;
}

/* A fixed, hand-placed star field — the night-sky counterpart to Skycard's
   .cloud-silhouette. Deterministic (no randomness), so the card looks the
   same on every load and in every screenshot. */
.starfield {
  position: absolute;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    radial-gradient(1.6px 1.6px at 12% 9%, rgba(255,255,255,.55), transparent 60%),
    radial-gradient(1.2px 1.2px at 28% 17%, rgba(255,255,255,.38), transparent 60%),
    radial-gradient(1.8px 1.8px at 46% 6%, rgba(255,255,255,.5), transparent 60%),
    radial-gradient(1.2px 1.2px at 68% 13%, rgba(255,255,255,.34), transparent 60%),
    radial-gradient(1.5px 1.5px at 86% 8%, rgba(255,255,255,.46), transparent 60%),
    radial-gradient(1.2px 1.2px at 8% 34%, rgba(255,255,255,.3), transparent 60%),
    radial-gradient(1.4px 1.4px at 92% 30%, rgba(255,255,255,.36), transparent 60%),
    radial-gradient(1.2px 1.2px at 18% 62%, rgba(255,255,255,.26), transparent 60%),
    radial-gradient(1.5px 1.5px at 78% 71%, rgba(255,255,255,.3), transparent 60%),
    radial-gradient(ellipse 320px 160px at 50% 100%, rgba(8, 12, 26, .5), transparent 72%);
}

.card > * {
  position: relative;
  z-index: 1;
}

@keyframes cardEnter {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}

.section-title {
  margin: 0 0 8px;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-dim);
}

/* ---------------------------------------------------------------------- */
/* Search row                                                              */
/* ---------------------------------------------------------------------- */

.search-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  /* Must sit above the hero (a later sibling): `.card > *` gives every
     child z-index:1, so without this the dropdown is trapped under the
     hero disc and clicks land on the SVG (the bug Skycard hit 2026-09-05). */
  z-index: 5;
}

.search-field {
  position: relative;
  flex: 1;
  min-width: 0;
}

.search-icon {
  position: absolute;
  left: 14px;
  top: 50%;
  transform: translateY(-50%);
  color: var(--text-dim);
  display: flex;
  pointer-events: none;
}

.search-input {
  width: 100%;
  height: 44px;
  border-radius: 22px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-hero);
  padding: 0 16px 0 42px;
  font-size: 14px;
  font-family: inherit;
  outline: none;
  transition: background 0.15s ease, border-color 0.15s ease;
}

.search-input::placeholder {
  color: var(--text-dim);
}

.search-input:focus {
  background: rgba(255, 255, 255, 0.13);
  border-color: rgba(255, 255, 255, 0.28);
}

.locate-btn {
  flex: 0 0 auto;
  width: 44px;
  height: 44px;
  border-radius: 14px;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(255, 255, 255, 0.08);
  color: var(--text-hero);
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  transition: background 0.15s ease, transform 0.1s ease;
}

.locate-btn:hover {
  background: rgba(255, 255, 255, 0.15);
}

.locate-btn:active {
  transform: scale(0.94);
}

.locate-btn.is-locating svg {
  animation: spin 1s linear infinite;
}

@keyframes spin {
  to { transform: rotate(360deg); }
}

.city-dropdown {
  position: absolute;
  top: calc(100% + 8px);
  left: 0;
  right: 0;
  margin: 0;
  padding: 6px;
  list-style: none;
  background: rgba(22, 30, 55, 0.98);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 16px;
  box-shadow: 0 16px 40px -8px rgba(5, 8, 20, 0.65);
  max-height: 260px;
  overflow-y: auto;
  z-index: 20;
}

.city-option {
  width: 100%;
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 8px;
  background: none;
  border: none;
  color: var(--text-hero);
  padding: 9px 10px;
  border-radius: 10px;
  font-size: 13.5px;
  cursor: pointer;
  text-align: left;
  font-family: inherit;
}

.city-option:hover,
.city-option:focus-visible {
  background: rgba(255, 255, 255, 0.1);
}

.city-name {
  font-weight: 600;
}

.city-country {
  color: var(--text-dim);
  font-size: 12px;
}

/* ---------------------------------------------------------------------- */
/* Hero                                                                     */
/* ---------------------------------------------------------------------- */

.hero {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 14px 0 4px;
  animation: heroFade 0.2s ease-out both;
}

@keyframes heroFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

.hero-disc {
  width: 200px;
  height: 200px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.hero-phase {
  margin-top: 12px;
  font-size: 30px;
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--text-hero);
}

.hero-illum {
  margin-top: 5px;
  font-size: 14.5px;
  color: var(--text-soft);
}

.hero-age {
  margin-top: 3px;
  font-size: 12.5px;
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

.hero-city {
  margin-top: 8px;
  font-size: 12.5px;
  color: var(--text-dim);
  letter-spacing: 0.02em;
}

/* ---------------------------------------------------------------------- */
/* Chips                                                                    */
/* ---------------------------------------------------------------------- */

.chip-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 18px;
  width: 100%;
}

.chip {
  background: var(--chip-bg);
  border: 1px solid var(--chip-border);
  border-radius: 14px;
  padding: 8px 6px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  min-width: 0;
}

.chip-label {
  font-size: 10.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text-dim);
  text-align: center;
}

.chip-value {
  font-family: var(--font-mono);
  font-size: 14px;
  font-variant-numeric: tabular-nums;
  color: var(--text-hero);
  white-space: nowrap;
}

.chip-note {
  font-size: 10px;
  color: var(--text-dim);
}

/* Below 390 px the second "next phase" chip is dropped — the soonest one
   is always the one that survives (app.js sorts them). */
.chip-secondary {
  display: none;
}

@media (min-width: 390px) {
  .chip-secondary {
    display: flex;
  }
}

/* ---------------------------------------------------------------------- */
/* Week strip                                                              */
/* ---------------------------------------------------------------------- */

.week {
  margin-top: 22px;
}

.week-strip {
  display: flex;
  background: var(--strip-bg);
  border-radius: 18px;
  padding: 10px 6px;
  gap: 2px;
}

.day-col {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 5px;
  color: var(--text-soft);
  padding: 8px 2px;
  border-radius: 14px;
}

.day-col.is-today {
  background: var(--pill-bg);
  box-shadow: inset 0 0 0 1px rgba(255, 211, 92, 0.45);
}

.day-name {
  font-size: 11px;
  font-weight: 600;
  color: var(--text-soft);
}

.day-col.is-today .day-name {
  color: var(--accent);
}

.day-disc {
  width: 34px;
  height: 34px;
  display: flex;
  align-items: center;
  justify-content: center;
}

.day-illum {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-variant-numeric: tabular-nums;
  color: var(--text-dim);
}

/* ---------------------------------------------------------------------- */
/* Wheel                                                                   */
/* ---------------------------------------------------------------------- */

.wheel {
  margin-top: 24px;
}

/* ---------------------------------------------------------------------- */
/* Footer                                                                   */
/* ---------------------------------------------------------------------- */

.card-footer {
  margin-top: auto;
  padding-top: 16px;
  text-align: center;
  font-size: 10.5px;
  color: var(--text-dim);
  display: flex;
  justify-content: center;
  gap: 6px;
  flex-wrap: wrap;
}

.card-footer .footer-line {
  flex-basis: 100%;
  font-family: var(--font-mono);
  opacity: 0.75;
}

/* ---------------------------------------------------------------------- */
/* Error card                                                              */
/* ---------------------------------------------------------------------- */

.error-card {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  gap: 12px;
  padding: 40px 12px;
}

.error-icon {
  font-size: 36px;
  color: var(--text-soft);
}

.error-message {
  color: var(--text-soft);
  font-size: 14px;
  max-width: 260px;
  margin: 0;
}

.btn-retry {
  background: var(--pill-bg);
  border: 1px solid rgba(255, 255, 255, 0.2);
  color: var(--text-hero);
  padding: 10px 22px;
  border-radius: 20px;
  font-size: 13.5px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}

.btn-retry:hover {
  background: rgba(255, 255, 255, 0.22);
}

/* ---------------------------------------------------------------------- */
/* Skeleton                                                                 */
/* ---------------------------------------------------------------------- */

.skeleton {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding-top: 24px;
}

.skel-bar,
.skel-chip,
.skel-day {
  border-radius: 12px;
  background: linear-gradient(90deg, rgba(255,255,255,0.05) 25%, rgba(255,255,255,0.13) 37%, rgba(255,255,255,0.05) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
}

.skel-disc {
  width: 180px;
  height: 180px;
  border-radius: 50%;
}

.skel-phase {
  width: 160px;
  height: 30px;
  margin-top: 16px;
}

.skel-label {
  width: 120px;
  height: 15px;
  margin-top: 10px;
}

.skel-row {
  display: flex;
  gap: 10px;
  width: 100%;
  margin-top: 20px;
}

.skel-chip {
  flex: 1;
  height: 46px;
  border-radius: 14px;
}

.skel-strip {
  display: flex;
  gap: 6px;
  width: 100%;
  margin-top: 22px;
}

.skel-day {
  flex: 1;
  height: 74px;
  border-radius: 14px;
}

.skel-wheel {
  width: 100%;
  height: 260px;
  margin-top: 22px;
  border-radius: 20px;
}

@keyframes shimmer {
  0% { background-position: 100% 0; }
  100% { background-position: -100% 0; }
}

/* ---------------------------------------------------------------------- */
/* Shared components restated (this page does not load ../shared.css)      */
/* MoonDisc — demo/mould/components/MoonDisc.js                            */
/* ---------------------------------------------------------------------- */

.md {
  display: block;
  overflow: visible;
}

.md-full {
  filter: drop-shadow(0 6px 18px rgba(120, 160, 255, 0.18));
}

/* ---------------------------------------------------------------------- */
/* LunarWheel — demo/mould/components/LunarWheel.js                        */
/* ---------------------------------------------------------------------- */

.lw {
  margin: 0;
}

.lw-svg {
  display: block;
  width: 100%;
  height: auto;
}

/* The wheel draws at ~320-380 px wide on every breakpoint (the card that
   holds it is a fixed column), so the rim words are sized once here rather
   than nudged up by a media query the way RingDial's are. 8.5px was too
   small to read on a 390 px phone; the quarter words are anchored inward
   (see wheel-geometry.js), so growing them cannot push them off-canvas. */
.lw-label {
  font-family: var(--font-sans);
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.09em;
  fill: var(--text-dim);
}

.lw-label-principal {
  fill: var(--text-soft);
}

.lw-label-half {
  font-size: 8.8px;
  letter-spacing: 0.14em;
  fill: var(--text-dim);
  opacity: 0.8;
}

.lw-disc.is-estimated {
  opacity: 0.42;
}

.lw-caption,
.lw-note {
  margin: 8px 0 0;
  font-size: 11.5px;
  line-height: 1.45;
  color: var(--text-dim);
  text-align: center;
}

.lw-note {
  margin-top: 4px;
  font-style: italic;
}

.lw-empty {
  padding: 24px;
  text-align: center;
  font-size: 13px;
  color: var(--text-dim);
}

.lw-sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
}

/* ---------------------------------------------------------------------- */
/* Reduced motion                                                          */
/* ---------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .card,
  .hero,
  .skel-bar,
  .skel-chip,
  .skel-day,
  .locate-btn.is-locating svg {
    animation: none !important;
  }
}

/* ---------------------------------------------------------------------- */
/* Small screens                                                           */
/* ---------------------------------------------------------------------- */

@media (max-width: 400px) {
  :root {
    --card-w: 100%;
  }
  .hero-disc {
    width: 168px;
    height: 168px;
  }
  .hero-disc .md {
    width: 168px;
    height: 168px;
  }
  .hero-phase {
    font-size: 26px;
  }
}
