/* Astrella — cosmic theme
   Deep indigo/violet base, warm gold accents, soft glassmorphism cards. */

:root {
  --bg-0: #0a0620;
  --bg-1: #140c30;
  --bg-2: #1b1140;
  --violet: #6d3fc9;
  --magenta: #c9439f;
  --gold: #f6c76b;
  --gold-soft: #ffe9b3;
  --ink: #f4ecff;
  --ink-dim: rgba(244, 236, 255, 0.72);
  --ink-faint: rgba(244, 236, 255, 0.48);
  --card-bg: rgba(255, 255, 255, 0.06);
  --card-border: rgba(255, 255, 255, 0.12);
  --card-bg-strong: rgba(255, 255, 255, 0.1);
  --success: #7fe0b8;
  --radius-lg: 22px;
  --radius-md: 16px;
  --radius-sm: 10px;
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-top: env(safe-area-inset-top, 0px);
  color-scheme: dark;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  height: 100%;
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Inter", "Helvetica Neue", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  overscroll-behavior-y: none;
}
/* `background` intentionally lives on `html` only, not `body` (real bug
   found & fixed in the same visual-design pass that added the cosmic
   photo to #bg-layer below): with BOTH html and body painting an opaque
   background, body's own opaque paint sits in front of any negative-
   z-index descendant of the root stacking context (per the CSS painting-
   order spec, a non-positioned box's own background always paints above
   z-index:-1 content, since body itself never becomes a stacking context
   here) -- so `#bg-layer` was rendering, completely correctly, entirely
   hidden behind body's own solid fill. Confirmed empirically: hiding
   every element except #bg-layer and blanking html/body's inline
   background showed the intended photo perfectly; restoring them made it
   vanish again. Keeping the color on `html` alone still gives an instant
   solid-color paint before any CSS/image loads (via the standard
   canvas-background-propagation rule) with no visible behavior change
   for that fallback case, while finally letting #bg-layer's own
   background show through body's now-transparent box. */
html { background: var(--bg-0); }

#bg-layer {
  position: fixed;
  inset: 0;
  z-index: -1;
  /* Visual-design pass (2026-09-12), art swapped 2026-09-13: a real
     nebula photo sits under the existing violet/magenta glow gradients
     and the dark vertical fade -- the gradients are kept (not replaced)
     so body text and cards still read cleanly against the photo's
     bright patches, per this project's "never let art fight legibility"
     rule. `background-attachment: fixed` keeps the photo stable while
     `.app`'s content scrolls over it.
     `cosmic-bg-zodiac.jpg` (2026-09-13, user-supplied, generated to
     match this file's own --violet/--magenta/--gold tokens) replaced
     the original `cosmic-bg-1.jpg` -- a portrait-oriented nebula with a
     faint glowing zodiac-wheel motif dissolving into the clouds,
     picked over the older landscape photo specifically because its
     native portrait aspect (941x1672) needs far less cropping on the
     phone-width viewports this app is mostly used at. `cosmic-bg-1.jpg`
     and `cosmic-bg-2.jpg` are left in img/brand/ as earlier candidates,
     unreferenced but not deleted. */
  background:
    radial-gradient(560px 420px at 82% 8%, rgba(109, 63, 201, 0.28), transparent 60%),
    radial-gradient(520px 460px at 12% 85%, rgba(201, 67, 159, 0.18), transparent 60%),
    linear-gradient(180deg, rgba(20, 12, 48, 0.4) 0%, rgba(10, 6, 32, 0.55) 55%, rgba(6, 4, 18, 0.82) 100%),
    url("img/brand/cosmic-bg-zodiac.jpg");
  background-size: auto, auto, auto, cover;
  /* 72%/24% keeps the photo's brightest cluster (its glowing wheel/star
     core) inside a narrow portrait viewport instead of `center`, which
     on this image crops slightly into the dimmer lower-left corner --
     checked by rendering the actual crop at 390px and 1024px-wide
     viewports (apps/web's own e2e run), not just picking a position by
     eye. Cards themselves layer their own translucent blur (`.card`'s
     backdrop-filter) on top, so text stays legible even where the photo
     is bright; this overlay only needs to keep the *gaps* between cards
     from looking washed out, which is why it's lighter than the first
     version of this background. */
  background-position: center, center, center, 72% 24%;
  background-repeat: no-repeat;
  background-attachment: fixed;
}
#bg-layer::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(1.6px 1.6px at 10% 12%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 24% 30%, #fff, transparent),
    radial-gradient(1.8px 1.8px at 60% 8%, #fff, transparent),
    radial-gradient(1.3px 1.3px at 78% 22%, #fff, transparent),
    radial-gradient(1.6px 1.6px at 92% 45%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 6% 60%, #fff, transparent),
    radial-gradient(1.7px 1.7px at 38% 72%, #fff, transparent),
    radial-gradient(1.3px 1.3px at 55% 90%, #fff, transparent),
    radial-gradient(1.6px 1.6px at 88% 82%, #fff, transparent),
    radial-gradient(1.4px 1.4px at 70% 60%, #fff, transparent);
  opacity: 0.5;
}

.app {
  max-width: 560px;
  margin: 0 auto;
  min-height: 100%;
  padding: calc(20px + var(--safe-top)) 18px calc(96px + var(--safe-bottom));
}

[dir="rtl"] .app { direction: rtl; }

/* ---------------- Typography ---------------- */
h1, h2, h3 { margin: 0 0 6px; font-weight: 700; letter-spacing: -0.01em; }
h1 { font-size: 26px; }
h2 { font-size: 20px; }
h3 { font-size: 16px; }
p { margin: 0 0 10px; line-height: 1.55; color: var(--ink-dim); }
.muted { color: var(--ink-faint); font-size: 13px; }
.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.12em;
  font-size: 11px;
  color: var(--gold);
  font-weight: 700;
  margin-bottom: 4px;
}

/* ---------------- Header ---------------- */
.topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 18px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  font-size: 19px;
  letter-spacing: -0.01em;
}
.brand img { width: 32px; height: 32px; border-radius: 9px; }
.icon-btn {
  width: 40px; height: 40px;
  display: flex; align-items: center; justify-content: center;
  border-radius: 12px;
  background: var(--card-bg);
  border: 1px solid var(--card-border);
  color: var(--ink);
  cursor: pointer;
  font-size: 18px;
}
.icon-btn:active { transform: scale(0.95); }

/* ---------------- Cards ---------------- */
.card {
  background: linear-gradient(155deg, var(--card-bg-strong), var(--card-bg));
  border: 1px solid var(--card-border);
  border-radius: var(--radius-lg);
  padding: 20px;
  margin-bottom: 16px;
  backdrop-filter: blur(18px);
  -webkit-backdrop-filter: blur(18px);
  box-shadow: 0 10px 30px rgba(0,0,0,0.25);
  position: relative;
  overflow: hidden;
}
.card.hero {
  background: linear-gradient(160deg, rgba(109,63,201,0.35), rgba(201,67,159,0.12));
}
.card.tight { padding: 14px 16px; }

/* New/Full Moon "special day" treatment on the Today's Sky card (see
   renderTodaysSky() -- only the two exact phases get this, never the 6
   in-between names). Deliberately just a warmer border + a gently
   pulsing glow (box-shadow only, same technique as the sign-badge glow
   above) rather than swapping the card's own background gradient --
   keeps every existing text color's contrast against .card's normal
   dark background untouched, so this reads as "a genuine occasion"
   without risking readability. */
.today-sky--special {
  border-color: rgba(246,199,107,0.4);
  animation: sky-special-glow 4.5s ease-in-out infinite;
}
.eyebrow--special { color: var(--gold-soft); }
@keyframes sky-special-glow {
  0%, 100% { box-shadow: 0 10px 30px rgba(0,0,0,0.25), 0 0 0 1px rgba(246,199,107,0.16), 0 0 16px rgba(246,199,107,0.14); }
  50% { box-shadow: 0 10px 30px rgba(0,0,0,0.25), 0 0 0 1px rgba(246,199,107,0.32), 0 0 30px rgba(246,199,107,0.3); }
}
@media (prefers-reduced-motion: reduce) {
  .today-sky--special {
    animation: none;
    box-shadow: 0 10px 30px rgba(0,0,0,0.25), 0 0 0 1px rgba(246,199,107,0.24), 0 0 22px rgba(246,199,107,0.2);
  }
}

/* Illustrated header banner (real user-supplied art, one per reading
   screen -- see img/headers/ and renderCardBanner() in main.ts). Bleeds
   to the card's own edges via negative margins equal to `.card`'s own
   padding; `.card`'s `overflow: hidden` clips it to the card's rounded
   top corners for free, so this needs no border-radius of its own. A
   bottom fade blends it into the card body so the headline text right
   below it never fights the photo for contrast. */
.card-banner {
  display: block;
  width: calc(100% + 40px);
  height: 132px;
  object-fit: cover;
  margin: -20px -20px 16px -20px;
  -webkit-mask-image: linear-gradient(180deg, #000 65%, transparent 100%);
  mask-image: linear-gradient(180deg, #000 65%, transparent 100%);
}

/* Share row (2026-09-12, "this app has to live"): a compact row of icon
   pills under a reading's content, letting someone send that exact
   reading to a friend/partner. `.share-btn--primary` (native share sheet)
   only appears in markup at all when the browser actually supports it. */
.share-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 14px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.08);
}
.share-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.06);
  border: 1px solid var(--card-border);
  color: var(--ink-dim);
  font-size: 12.5px;
  font-weight: 600;
  text-decoration: none;
  cursor: pointer;
  line-height: 1;
}
.share-btn:active { transform: scale(0.96); }
.share-btn--primary {
  background: linear-gradient(135deg, var(--gold), var(--gold-soft));
  border-color: transparent;
  color: #241a02;
}
.card-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}
.card-row.selectable {
  cursor: pointer;
  padding: 10px 4px;
  border-radius: var(--radius-sm);
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.card-row.selectable:last-of-type { border-bottom: none; }
.card-row.selectable:hover, .card-row.selectable:focus-visible {
  background: rgba(255,255,255,0.05);
  outline: none;
}
/* `.btn` defaults to `width: 100%` (meant for a full-width button on its
   own, or one of several in a `.btn-row`). Nested directly in a
   `.card-row` flex container instead, that 100% flex-basis makes it
   balloon to consume most of the row's width -- and because `.btn-ghost`
   is transparent, that oversized hit target is invisible: tapping what
   looks like empty space next to a saved person's name silently hits
   "Remove" instead of selecting them. Size it to its own content here. */
.card-row .btn {
  width: auto;
  flex: 0 0 auto;
}

/* A circular, gently-glowing badge for a single zodiac glyph -- e.g. the
   Daily screen's sun-sign badge (see `renderSignBadge()` in main.ts). Sits
   on a radial gold-into-violet fill with a soft outer glow ring, ready to
   hold a real illustrated badge image later in place of the Unicode glyph
   without any markup/layout change (a future asset would just replace the
   `<span>` content or become a background-image on this same element). */
.sign-badge {
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  flex-shrink: 0;
  background: radial-gradient(circle at 35% 28%, rgba(255,233,179,0.55), rgba(109,63,201,0.35) 70%);
  border: 1px solid rgba(246,199,107,0.45);
  box-shadow: 0 0 0 1px rgba(246,199,107,0.12), 0 0 22px rgba(246,199,107,0.28), inset 0 0 14px rgba(0,0,0,0.25);
}
.sign-badge span { line-height: 1; }
.sign-badge--md { width: 52px; height: 52px; font-size: 26px; }
.sign-badge--lg { width: 68px; height: 68px; font-size: 34px; }
/* Visual-design pass (2026-09-12, expanded 2026-09-13): once real
   illustrated medallion art exists for a sign (see SIGN_ILLUSTRATIONS in
   main.ts -- 8 of 12 signs so far: aries, taurus, gemini, cancer, virgo,
   scorpio, capricorn, pisces; leo/libra/sagittarius/aquarius still use an
   older collage-derived crop pending higher-quality source art),
   `renderSignBadge` swaps the `<span>` glyph for an `<img>` and adds this
   modifier; the ring/glow styling above still applies, this just makes
   the photo fill the circle and crop cleanly to it. */
.sign-badge--art { background: #000; }
.sign-badge--art img {
  width: 100%; height: 100%;
  border-radius: 50%;
  object-fit: cover;
}

/* A small inline planet glyph (renderPlanetIcon) shown next to a planet's
   localized name in a pill or list -- the SVGs already carry their own
   dark circular backdrop + gold glow, so no extra badge wrapper needed. */
.planet-icon { width: 18px; height: 18px; flex-shrink: 0; vertical-align: middle; }

/* ---------------- Buttons & forms ---------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  border: none;
  border-radius: 14px;
  padding: 14px 20px;
  font-size: 15px;
  font-weight: 700;
  cursor: pointer;
  width: 100%;
  transition: transform 0.12s ease, opacity 0.12s ease;
}
.btn:active { transform: scale(0.98); }
.btn-primary {
  background: linear-gradient(120deg, var(--gold-soft), var(--gold));
  color: #241454;
}
.btn-secondary {
  background: var(--card-bg);
  color: var(--ink);
  border: 1px solid var(--card-border);
}
.btn-ghost {
  background: transparent;
  color: var(--ink-dim);
  border: 1px solid transparent;
}
.btn-row { display: flex; gap: 10px; }
.btn-row .btn { width: auto; flex: 1; }

label { display: block; font-size: 13px; color: var(--ink-dim); margin: 14px 0 6px; }
input, select {
  width: 100%;
  padding: 13px 14px;
  border-radius: 12px;
  border: 1px solid var(--card-border);
  background: rgba(255,255,255,0.05);
  color: var(--ink);
  font-size: 15px;
  outline: none;
}
input:focus, select:focus { border-color: var(--gold); }
.field-row { display: flex; gap: 10px; }
.field-row > div { flex: 1; }
.checkbox-row {
  display: flex; align-items: center; gap: 10px;
  margin-top: 14px; font-size: 14px; color: var(--ink-dim);
}
.checkbox-row input { width: auto; }

/* ---------------- Tab bar ---------------- */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  display: flex;
  justify-content: center;
  padding: 10px 12px calc(10px + var(--safe-bottom));
  background: linear-gradient(0deg, rgba(10,6,32,0.96) 60%, rgba(10,6,32,0.75));
  backdrop-filter: blur(14px);
  border-top: 1px solid rgba(255,255,255,0.08);
  z-index: 20;
}
.tabbar-inner {
  display: flex;
  gap: 4px;
  max-width: 560px;
  width: 100%;
  justify-content: space-between;
}
.tab-btn {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  background: none;
  border: none;
  color: var(--ink-faint);
  font-size: 10.5px;
  padding: 6px 2px;
  border-radius: 12px;
  cursor: pointer;
  font-weight: 600;
}
.tab-btn .tab-icon { font-size: 19px; line-height: 1; }
.tab-btn.active { color: var(--gold); background: rgba(246,199,107,0.1); }

/* ---------------- Launch gate ---------------- */
/* The app's real first screen (see main.ts's `renderLaunchGate`): a
   continuously-animated chart-wheel emblem, the brand wordmark, and a
   terms/privacy acceptance card, all entering on a short stagger via
   `.fade-in`'s existing keyframe plus a per-element inline
   `animation-delay` rather than a second bespoke animation. The emblem
   reuses `.unlock-reveal`'s `le-*` counterparts below -- same visual
   language (a gold chart-wheel arc, a pulsing core) as the "your
   horoscope was just calculated" moment elsewhere in the app, but
   looping continuously here instead of drawing once, since this is a
   standing brand moment, not a one-shot calculation. */
.launch-gate { text-align: center; padding: 34px 6px 10px; }

.launch-emblem { width: 148px; height: 148px; margin: 0 auto 22px; }
.launch-emblem svg { width: 100%; height: 100%; overflow: visible; }

.le-track { fill: none; stroke: rgba(244, 236, 255, 0.12); stroke-width: 1.4; }

.le-ring-spin { transform-origin: 60px 60px; animation: le-spin 26s linear infinite; }
.le-draw {
  fill: none;
  stroke: var(--gold);
  stroke-width: 1.8;
  stroke-linecap: round;
  stroke-dasharray: 314.2;
  stroke-dashoffset: 314.2;
  filter: drop-shadow(0 0 7px rgba(246, 199, 107, 0.5));
  animation: le-draw-once 2.6s cubic-bezier(0.65, 0, 0.35, 1) forwards;
}

.le-orbit { transform-origin: 60px 60px; animation: le-spin 7s linear infinite; }
.le-orbit-ring { fill: none; stroke: rgba(201, 67, 159, 0.28); stroke-width: 1; stroke-dasharray: 2 4; }
.le-planet { fill: var(--magenta); filter: drop-shadow(0 0 4px rgba(201, 67, 159, 0.7)); }

.le-core { fill: var(--gold-soft); animation: le-core-pulse 2.4s ease-in-out infinite; }

.le-star { fill: #fff; animation: le-star-twinkle 3.2s ease-in-out infinite; }
.le-star:nth-of-type(1) { animation-delay: 0.1s; }
.le-star:nth-of-type(2) { animation-delay: 0.9s; }
.le-star:nth-of-type(3) { animation-delay: 1.6s; }
.le-star:nth-of-type(4) { animation-delay: 0.4s; }
.le-star:nth-of-type(5) { animation-delay: 2.1s; }

@keyframes le-spin { to { transform: rotate(360deg); } }
@keyframes le-draw-once {
  0% { stroke-dashoffset: 314.2; opacity: 0.25; }
  12% { opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 1; }
}
@keyframes le-core-pulse {
  0%, 100% { r: 4; opacity: 0.6; }
  50% { r: 5.5; opacity: 1; }
}
@keyframes le-star-twinkle {
  0%, 100% { opacity: 0.25; }
  50% { opacity: 1; }
}

.launch-brand {
  justify-content: center;
  font-size: 32px;
  font-weight: 800;
  letter-spacing: 0.01em;
  margin-bottom: 6px;
  color: var(--gold-soft);
}
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .launch-brand {
    background: linear-gradient(135deg, var(--gold-soft), var(--gold) 55%, var(--magenta));
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }
}

.launch-tagline { max-width: 320px; margin: 0 auto 26px; }

.launch-terms-card { text-align: center; max-width: 420px; margin: 0 auto; }
.launch-terms-card .eyebrow { text-align: center; }
.launch-terms-links {
  display: flex;
  justify-content: center;
  gap: 8px 16px;
  flex-wrap: wrap;
  margin: 4px 0 16px;
}
.launch-terms-link { color: var(--gold); font-size: 13.5px; font-weight: 600; text-decoration: none; }
.launch-terms-link:hover, .launch-terms-link:focus-visible { text-decoration: underline; }
.launch-terms-card .btn { max-width: 320px; margin: 4px auto 10px; }
.launch-terms-fineprint { margin: 0; }

@media (prefers-reduced-motion: reduce) {
  .le-ring-spin, .le-orbit, .le-draw, .le-core, .le-star {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
  }
  .le-draw { stroke-dashoffset: 0; opacity: 1; }
}

/* ---------------- Onboarding ---------------- */
.onboard-hero {
  text-align: center;
  padding: 30px 10px 10px;
}
.onboard-hero .glyph-badge {
  width: 84px; height: 84px; border-radius: 24px; font-size: 40px;
  margin: 0 auto 18px;
}
.onboard-hero h1 { font-size: 28px; margin-bottom: 10px; }
.onboard-hero p { max-width: 340px; margin: 0 auto 8px; }

.lang-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  gap: 8px;
  margin: 14px 0 4px;
}
.lang-chip {
  padding: 9px 6px;
  text-align: center;
  border-radius: 12px;
  border: 1px solid var(--card-border);
  background: var(--card-bg);
  font-size: 13px;
  cursor: pointer;
  color: var(--ink-dim);
}
.lang-chip.active {
  border-color: var(--gold);
  color: var(--gold);
  background: rgba(246,199,107,0.12);
}

/* ---------------- Content blocks ---------------- */
.headline { font-size: 19px; font-weight: 700; margin-bottom: 8px; line-height: 1.4; }
.body-text { font-size: 15px; color: var(--ink-dim); line-height: 1.65; margin-bottom: 6px; }
.pill-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 12px; }
.pill {
  padding: 6px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.07);
  border: 1px solid var(--card-border);
  font-size: 12.5px;
  color: var(--ink-dim);
  display: flex; align-items: center; gap: 6px;
}

.energy-bar {
  height: 8px;
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  overflow: hidden;
  margin-top: 8px;
}
.energy-bar-fill {
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--violet), var(--gold));
}

/* ---------------- Daily header + stat tiles ---------------- */
.daily-header { display: flex; align-items: center; gap: 14px; margin-bottom: 12px; }
.daily-header-text { min-width: 0; }
.daily-header-text .headline { margin-bottom: 2px; }

/* Settings profile row (2026-09-14): the same illustrated sign-badge
   language used on Daily/Compatibility, extended to Settings -- see
   renderSettingsProfileBadge() in main.ts. Same flex layout as
   .daily-header, just with a smaller bottom margin since it sits right
   above the "Start over" button rather than a full reading. */
.settings-profile-row { display: flex; align-items: center; gap: 14px; margin-bottom: 14px; }

.stat-row {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(84px, 1fr));
  gap: 10px;
  margin: 14px 0;
}
.stat-tile {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 2px;
  text-align: center;
  padding: 12px 8px;
  border-radius: var(--radius-md);
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--card-border);
}
.stat-icon { font-size: 15px; color: var(--gold); }
.stat-value { font-size: 20px; font-weight: 800; color: var(--ink); }
.stat-value small { font-size: 12px; font-weight: 600; color: var(--ink-faint); }
.stat-value--sm { font-size: 14px; font-weight: 700; text-transform: capitalize; }
.stat-label { font-size: 11px; color: var(--ink-faint); text-transform: uppercase; letter-spacing: 0.04em; }

/* A visually distinct callout for the day's single-line "tip" text --
   the mood-board reference's "Rada od gwiazd" quote card -- rather than
   letting it blend into the surrounding paragraphs at the same weight. */
.advice-card {
  border-left: 2px solid var(--gold);
  background: rgba(246,199,107,0.08);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  padding: 10px 14px;
  margin: 10px 0;
}
.advice-card .body-text { margin-bottom: 0; color: var(--ink); }

/* ---------------- Moon phase visual (renderMoonGlyph in main.ts) -------- */
.sky-row { display: flex; align-items: center; gap: 14px; margin-bottom: 10px; }
.sky-row-text { min-width: 0; }
.sky-row-text .headline { margin-bottom: 2px; }
.moon-visual { flex-shrink: 0; filter: drop-shadow(0 0 14px rgba(246,199,107,0.35)); }

.month-row {
  display: flex;
  gap: 12px;
  padding: 12px 0;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.month-row:last-child { border-bottom: none; }
.month-name { width: 74px; flex-shrink: 0; font-weight: 700; font-size: 13px; color: var(--gold-soft); }

.section-title {
  display: flex; align-items: center; gap: 8px;
  margin: 22px 0 10px;
}
.section-title .line { flex: 1; height: 1px; background: rgba(255,255,255,0.1); }

/* ---------------- Compatibility ---------------- */
.compat-score-ring {
  width: 108px; height: 108px;
  border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  margin: 6px auto 14px;
  background: conic-gradient(var(--gold) calc(var(--pct, 70) * 1%), rgba(255,255,255,0.08) 0);
  position: relative;
}
.compat-score-ring::before {
  content: "";
  position: absolute; inset: 8px;
  border-radius: 50%;
  background: var(--bg-1);
}
.compat-score-num { position: relative; font-size: 26px; font-weight: 800; }
.vs-row { display: flex; align-items: center; justify-content: center; gap: 14px; margin-bottom: 6px; }
.vs-side { display: flex; flex-direction: column; align-items: center; gap: 6px; }
.vs-sign { text-align: center; font-size: 13px; color: var(--ink-dim); }
.vs-label { font-size: 12px; color: var(--ink-faint); }

/* ---------------- Ad slot ---------------- */
.ad-slot {
  border-radius: var(--radius-md);
  border: 1px dashed rgba(246,199,107,0.35);
  background: rgba(255,255,255,0.03);
  padding: 14px;
  text-align: center;
  margin: 18px 0;
  font-size: 12px;
  color: var(--ink-faint);
  min-height: 90px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
}
.ad-slot .ad-tag {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--ink-faint);
  opacity: 0.7;
}

/* ---------------- Chart wheel ---------------- */
.wheel-wrap { display: flex; justify-content: center; margin: 6px 0 10px; }
.chart-list { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
.chart-list-item {
  display: flex; align-items: center; gap: 8px;
  padding: 10px 12px;
  border-radius: 12px;
  background: rgba(255,255,255,0.05);
  border: 1px solid var(--card-border);
  font-size: 13px;
}
.chart-list-item .g { font-size: 17px; }
/* The "no match in our offline city list -- continue anyway" option
   (main.ts's wireCitySearch, added 2026-09-14). Reuses .chart-list-item's
   base look but spans both grid columns (it's one long sentence, not a
   short city name) and is visually distinct -- dashed border, no solid
   fill -- so it never reads as a real, precise city match. */
.chart-list-item--freeform {
  grid-column: 1 / -1;
  cursor: pointer;
  background: transparent;
  border-style: dashed;
  color: var(--ink-dim, inherit);
}
.chart-list-item--freeform:hover,
.chart-list-item--freeform:focus-visible { background: rgba(255,255,255,0.05); }

/* ---------------- Unlock reveal (Astrella Premium) ----------------
   The one-time "you just unlocked this" ceremony shown by
   `renderUnlockReveal` in main.ts, in place of Yearly/Love/Compatibility's
   real content, for exactly the first paid tab opened right after a
   fresh checkout or restore actually unlocks Premium in this session.
   Plays a brief, real-feeling "calculating" beat (a slow single pass of
   the same zodiac-wheel motif used elsewhere for "your personal chart is
   being worked out") then swaps to a credibility statement and a reveal
   button -- see wireUnlockReveal for the timing. */
.unlock-reveal { text-align: center; }

.unlock-reveal-stage {
  width: 88px;
  height: 88px;
  margin: 4px auto 18px;
}

.urw-track { fill: none; stroke: rgba(244, 236, 255, 0.14); stroke-width: 2; }

.urw-draw {
  fill: none;
  stroke: var(--gold);
  stroke-width: 2.5;
  stroke-linecap: round;
  transform-origin: 50% 50%;
  transform: rotate(-90deg);
  stroke-dasharray: 251.2;
  stroke-dashoffset: 251.2;
  animation: urw-draw-once 2.4s cubic-bezier(0.65, 0, 0.35, 1) forwards;
  filter: drop-shadow(0 0 6px rgba(246, 199, 107, 0.55));
}

.urw-core {
  fill: var(--gold-soft);
  animation: urw-core-pulse 1.2s ease-in-out infinite;
}

@keyframes urw-draw-once {
  0% { stroke-dashoffset: 251.2; opacity: 0.3; }
  10% { opacity: 1; }
  100% { stroke-dashoffset: 0; opacity: 1; }
}

@keyframes urw-core-pulse {
  0%, 100% { r: 3; opacity: 0.55; }
  50% { r: 4.5; opacity: 1; }
}

.unlock-reveal-status { color: var(--ink-dim); min-height: 1.4em; }

.unlock-reveal-result .body-text { margin-bottom: 16px; }
.unlock-reveal-result .btn { max-width: 320px; margin: 0 auto; }

@media (prefers-reduced-motion: reduce) {
  .urw-draw, .urw-core {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
  }
}

/* ---------------- Settings ---------------- */
.settings-row {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 0;
  border-bottom: 1px solid rgba(255,255,255,0.06);
}
.settings-row:last-child { border-bottom: none; }

/* ---------------- Misc ---------------- */
.fade-in { animation: fadeIn 0.35s ease both; }
@keyframes fadeIn {
  from { opacity: 0; transform: translateY(6px); }
  to { opacity: 1; transform: translateY(0); }
}

.skeleton {
  background: linear-gradient(90deg, rgba(255,255,255,0.04) 25%, rgba(255,255,255,0.09) 37%, rgba(255,255,255,0.04) 63%);
  background-size: 400% 100%;
  animation: shimmer 1.4s ease infinite;
  border-radius: 10px;
  height: 14px;
  margin-bottom: 8px;
}
@keyframes shimmer { 0% { background-position: 100% 50%; } 100% { background-position: 0 50%; } }

::selection { background: rgba(246,199,107,0.35); }

a { color: var(--gold-soft); }

@media (min-width: 640px) {
  .tabbar-inner { gap: 8px; }
}

/* -------------------------------------------------------------------------
   WordPress seamless embed mode (0.3.3)
   The app remains isolated in its iframe, but visually becomes part of the
   Horoscop.space theme instead of painting a second full-screen website.
   Enabled only with ?embed=seamless, so standalone/PWA behaviour is unchanged.
   ------------------------------------------------------------------------- */
html[data-embed-mode="seamless"] {
  background: transparent;
}
html[data-embed-mode="seamless"] body {
  min-height: 0;
  height: auto;
  overflow: visible;
  background: transparent;
  display: flex;
  flex-direction: column;
}
html[data-embed-mode="seamless"] #bg-layer {
  display: none;
}
html[data-embed-mode="seamless"] .app {
  order: 2;
  width: 100%;
  max-width: 720px;
  min-height: 0;
  margin: 0 auto;
  padding: 4px 14px 22px;
}
html[data-embed-mode="seamless"] .tabbar {
  order: 1;
  position: static;
  width: min(720px, calc(100% - 28px));
  margin: 0 auto 14px;
  padding: 8px;
  border: 1px solid rgba(255,255,255,0.10);
  border-radius: 18px;
  background: rgba(20,12,48,0.84);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: 0 12px 32px rgba(0,0,0,0.18);
}
html[data-embed-mode="seamless"] .tabbar:empty {
  display: none;
}
html[data-embed-mode="seamless"] .tabbar-inner {
  max-width: none;
}
html[data-embed-mode="seamless"] .topbar {
  margin: 0 0 14px;
  padding: 2px 2px 0;
}
html[data-embed-mode="seamless"] .card {
  background: linear-gradient(155deg, rgba(255,255,255,0.085), rgba(255,255,255,0.045));
  border-color: rgba(255,255,255,0.11);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  box-shadow: 0 12px 32px rgba(0,0,0,0.20);
}
html[data-embed-mode="seamless"] .launch-gate {
  padding-top: 16px;
}
@media (max-width: 560px) {
  html[data-embed-mode="seamless"] .app {
    padding-inline: 8px;
  }
  html[data-embed-mode="seamless"] .tabbar {
    width: calc(100% - 16px);
    border-radius: 14px;
  }
}
