/* ═══ cosmic-silver tokens (spec §1) ═══ */
:root {
  /* ground = 星空藍 (user direction 2026-09-16): the old midnight-black
     (#0C0C0C → #10141F) read as 夜空黑; the site now sits in deep blue.
     Same two-stop 135deg body gradient, only the hue moves — the near
     stop stays darkest (night zenith), the far stop lifts to starlit blue.
     AA floor = the GLASS COMPOSITE, not bare ground (spec §1 rule); the
     star-blue far stop is ~2× the old luminance, so two values moved to
     keep the floors (2026-09-16): --silver-faint #8a919c → #9aa3b2 and
     the lg mirror band #6f7787 → #7b8494. Worst real surfaces on the far
     stop: card glass ≈#202d53 → text 10.4, heading 10.6, silver-dim 6.2,
     faint 5.3, rose 5.0, mirror band 3.6. card:hover's brightness(1.12)
     scales the element's whole rendered output — plate and glyph together —
     so the ratio RISES (band 3.57 → 4.04); it is not a floor case.
     Real faint floor is input::placeholder (glass .05 over the card plate,
     ≈#2b385c) at 4.55:1, not ocean-dim's 4.70:1 — both pass, but the
     tighter one is what to sample next time. */
  --void: #0a1733;        /* deep 星空藍 — body gradient near stop */
  --deep-space: #14224a;  /* lighter horizon blue — far stop  */
  --galaxy-y-offset: clamp(40px, 9vh, 96px); /* keep the Milky-Way band below the hero/nav overlap */
  --heading: #e5e4e2;
  --text: #dde2ec;
  --silver-dim: #a9b0bc;
  --silver-faint: #9aa3b2;  /* muted — same value as --metal-lo; lifted off #8a919c (3.8:1 worst) for AA on the 星空藍 glass */
  --starlight: #f5f7fa;
  --rose: #fb7185;   /* the ONLY hue on the site: transformation stars + errors */
  --glass-bg: rgba(255, 255, 255, 0.05);
  --glass-bg-strong: rgba(10, 23, 51, 0.72);
  --glass-border: rgba(255, 255, 255, 0.1);

  /* mirror chrome gradients — single source of truth: the base heading rules
     and the animated glint overlay (@supports block below) MUST be the same
     two mirrors, so both reference these tokens */
  --chrome-mirror-lg: linear-gradient(
    180deg,
    #ffffff 0%,
    #eef2f8 16%,
    #c8d0dc 34%,
    #8e97a6 45%,
    #7b8494 49%,  /* lifted off #6f7787 (2.99:1 on 星空藍 card glass) to hold the 3.0 large-text floor */
    #dfe6ee 53%,
    #f8fafc 78%,
    #ffffff 100%
  );
  --chrome-mirror-sm: linear-gradient(
    180deg,
    #fdfeff 0%,
    #ccd4df 40%,
    #939da9 70%,
    #b9c2cf 100%
  );

  /* metallic silver sheen — the entire interaction language is chrome now:
     states are expressed by luminance (edge → brighter edge → inverted
     chrome plate), never by hue (user direction: no blue-violet) */
  --metal-hi: #f8fafc;        /* hover/focus highlight          12.9:1 on card glass */
  --metal-mid: #c8d0dc;       /* interactive text base           8.7:1 on card glass */
  --metal-lo: #9aa3b2;        /* control edges                    5.3:1 on card glass */
  --metal-deep: #6f7787;      /* dark edge floor (decor); NOT the mirror band — band lifted to #7b8494; 3.4:1 bare far stop — large text / decor only */
  --metal-deep-small: #8a93a5; /* small text on dark — AA-safe replacement for #6f7787 */
  --ink-on-chrome: #10141f;   /* text on a chrome plate          >=6.2:1 */
  /* WCAG AA contrast tokens (spec § contrast) */
  --text-muted-on-dark: #9aa3b2;  /* secondary on var(--deep-space) — was #6b7280 (fails) */
  --text-muted-on-light: #4b5563; /* secondary on white/#fdf2f8 — was #9ca3af (fails) */
  --error-on-light: #b91c1c;      /* error on #fff — was #ef4444 (fails) */
  --error-on-dark: #fb7185;       /* error on var(--deep-space) — was #ef4444 */
  --gen-title: #f5f3ff;           /* generation title on subtle purple — was #6d28d9 (1.62:1) */
  --metal-line: rgba(200, 208, 220, 0.22);
  /* moving glint layer for the mirror chrome (user direction 2026-09-13/14):
     one diagonal light band crossing the glyphs, silver-white, no hue.
     45deg（使用者指定，最好辨認）；純白核心在已白的鏡面上不可見，故帶一段
     淡暗前導邊（墨色低透明）造出反光邊界的對比 — 亮區暗區都看得到移動。 */
  --chrome-glint: linear-gradient(
    45deg,
    transparent 0%,
    transparent 30%,
    rgba(10, 23, 51, 0.32) 36%,
    rgba(248, 250, 252, 0.95) 42%,
    rgba(248, 250, 252, 0.95) 50%,
    rgba(255, 255, 255, 0.15) 58%,
    transparent 64%,
    transparent 100%
  );
  --metal-edge: linear-gradient(
    135deg,
    rgba(255, 255, 255, 0.55),
    rgba(154, 163, 178, 0.18) 35%,
    rgba(240, 244, 250, 0.4) 60%,
    rgba(154, 163, 178, 0.15)
  );
}

/* ═══ deep-space ground (spec §3 layer 1) ═══ */
body {
  background:
    radial-gradient(120vw 90vh at 15% 8%, rgba(198, 220, 255, 0.07), transparent 60%),
    radial-gradient(90vw 70vh at 85% 92%, rgba(120, 160, 230, 0.06), transparent 55%),
    linear-gradient(135deg, var(--void), var(--deep-space));
  background-attachment: fixed;
  color: var(--text);
}

/* ═══ starfield: fixed decorative layers (spec §3) ═══ */
.sky-nebula,
.sky-stars-a,
.sky-stars-b {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: -3;
}
.sky-nebula { z-index: -4; }

/* galaxy particle layer (spec §3 layer 4) — above CSS stars, below content */
#galaxy-canvas {
  position: fixed;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  z-index: -2;
  transform: translateY(var(--galaxy-y-offset));
}

/* band haze — same -18deg axis as the canvas particles (spec §4) */
.sky-nebula::before {
  content: '';
  position: absolute;
  left: -40%;
  right: -40%;
  top: calc(50% + var(--galaxy-y-offset));
  height: 130vmax;
  transform: translateY(-50%) rotate(-18deg);
  background:
    radial-gradient(42% 10% at 50% 50%, rgba(214, 230, 255, 0.13), transparent 72%),
    radial-gradient(70% 18% at 50% 50%, rgba(214, 230, 255, 0.075), transparent 78%),
    radial-gradient(55% 15% at 50% 50%, rgba(126, 165, 232, 0.07), transparent 72%);
}

/* static star field — generated by scripts/gen-stars.js, do not edit */
.sky-stars-a,
.sky-stars-b {
  border-radius: 50%;
  animation: twinkleA 3.5s ease-in-out infinite alternate;
}
.sky-stars-a { width: 1px; height: 1px; box-shadow:
  55.19vw 3.32vh 0 0 rgba(229,228,226,0.98),
  46.89vw 31.78vh 0 0 rgba(229,228,226,0.86),
  75.65vw 28.64vh 0 0 rgba(229,228,226,0.96),
  96.80vw 84.94vh 0 0 rgba(229,228,226,0.86),
  29.60vw 33.54vh 0 0 rgba(229,228,226,0.87),
  14.68vw 88.25vh 0 0 rgba(229,228,226,0.95),
  40.94vw 86.19vh 0 0 rgba(229,228,226,0.94),
  17.79vw 84.05vh 0 0 rgba(229,228,226,0.96),
  5.17vw 55.80vh 0 0 rgba(229,228,226,0.91),
  66.08vw 93.42vh 0 0 rgba(229,228,226,0.90),
  20.59vw 41.67vh 0 0 rgba(229,228,226,0.95),
  86.61vw 98.40vh 0 0 rgba(229,228,226,0.87),
  11.32vw 67.12vh 0 0 rgba(229,228,226,0.92),
  2.22vw 13.68vh 0 0 rgba(229,228,226,0.90); }
.sky-stars-b {
  width: 2px; height: 2px;
  animation-name: twinkleB;
  animation-duration: 7s;
  animation-delay: -2.2s;
  box-shadow: 86.52vw 79.11vh 0 0 rgba(229,228,226,0.83),
  5.51vw 54.68vh 0 0 rgba(229,228,226,0.92),
  0.23vw 98.23vh 0 0 rgba(229,228,226,0.79),
  17.64vw 56.39vh 0 0 rgba(229,228,226,0.94),
  68.62vw 74.67vh 0 0 rgba(229,228,226,0.78),
  37.49vw 18.99vh 0 0 rgba(229,228,226,0.92),
  48.98vw 95.72vh 0 0 rgba(229,228,226,0.72),
  17.63vw 95.93vh 0 0 rgba(229,228,226,0.92),
  17.94vw 69.18vh 0 0 rgba(229,228,226,0.86),
  78.25vw 13.85vh 0 0 rgba(229,228,226,0.95);
}
/* 2026-09-17 使用者指示：星星少但亮 — 閃爍暗段地板拉高，最暗相仍清楚可見 */
@keyframes twinkleA { from { opacity: 1; } to { opacity: 0.55; } }
@keyframes twinkleB { from { opacity: 0.85; } to { opacity: 0.5; } }

/* serif headings (spec §2) — Latin/digits via Playfair, CJK via Noto Serif TC.
   Mirror chrome (user-requested): a STATIC vertical reflection gradient —
   sky highlight, a sharp horizon break, then the ground reflection — like
   polished chrome plating. No sweeping animation; a mirror does not marquee.
   Falls back to solid --heading where background-clip: text is unsupported. */
h1, h2, h3, h4, h5, h6,
.nav-brand {
  font-family: 'Playfair Display', 'Noto Serif TC', serif;
  color: var(--heading);
  background: var(--chrome-mirror-lg);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  filter: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.55)) drop-shadow(0 0 10px rgba(214, 224, 240, 0.28));
}
/* small headings can't carry the full mirror's dark horizon band (it melts
   into the card glass at 1.25rem) — light silver only, AA-safe throughout.
   background-image (not the shorthand) so background-clip: text survives. */
h3, h4, h5, h6 {
  background-image: var(--chrome-mirror-sm);
}

/* mirror chrome glint (user direction 2026-09-13, supersedes "no sweeping
   animation"): a light pass ACROSS the static mirror — the mirror
   gradient itself never moves; an oversized clipped sheen layer slides
   over it. The long rest between passes IS the effect: the eye is caught
   by change and habituates to constant motion. Both levels share the
   120s period (2026-09-17) and are phase-offset (small headings +60s),
   so they never pulse together. Sweeping band is fully off-text at both
   keyframe ends, so the loop seam is invisible. Only inside @supports:
   without background-clip: text the sheen would paint as a moving block. */
@supports (-webkit-background-clip: text) or (background-clip: text) {
  h1, h2, .nav-brand {
    background-image: var(--chrome-glint), var(--chrome-mirror-lg);
    background-size: 240% 100%, 100% 100%;
    background-position: 130% 0, 0 0;
    background-repeat: no-repeat;
    animation: chrome-glint 120s ease-in-out infinite;
  }
  h3, h4, h5, h6 {
    background-image: var(--chrome-glint), var(--chrome-mirror-sm);
    background-size: 240% 100%, 100% 100%;
    background-position: 130% 0, 0 0;
    background-repeat: no-repeat;
    animation: chrome-glint 120s ease-in-out 60s infinite;
  }
}
/* band center at position p: x = 1.2C − 1.4C·p/100 → p=130% fully off the
   left edge, p=−30% fully off the right; the pass runs left→right（閱讀方向）.
   2026-09-17 使用者指示（issue#1，取代 09-14 的慢掃回饋）：掃過速度加快
   （~2s，1.7% of cycle）、每 2 分鐘閃一次；小標延遲 60s 錯相，不齊發。 */
@keyframes chrome-glint {
  0%   { background-position: 130% 0, 0 0; }
  1.7% { background-position: -30% 0, 0 0; }
  100% { background-position: -30% 0, 0 0; }
}

/* ═══ reduced motion: freeze to a static sky (spec §4) ═══ */
@media (prefers-reduced-motion: reduce) {
  .sky-stars-a,
  .sky-stars-b {
    animation: none;
    opacity: 0.7;
  }
  h1, h2, h3, h4, h5, h6, .nav-brand {
    animation: none;  /* glint off — static mirror */
  }
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
  line-height: 1.6;
}

/* links: "clickable" is carried by the underline and luminance, not hue */
a {
  color: #cfd6e0;
  text-decoration: underline;
  text-decoration-color: rgba(200, 208, 220, 0.4);
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
  transition: color 0.18s ease, text-decoration-color 0.18s ease;
}
a:hover {
  color: var(--metal-hi);
  text-decoration-color: var(--metal-hi);
  text-shadow: 0 0 10px rgba(248, 250, 252, 0.35);
}

button {
  font-family: inherit;
  cursor: pointer;
}

button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

input, select {
  font-family: inherit;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  border-radius: 4px;
  color: var(--text);
}

select option {
  background: var(--deep-space);
  color: var(--text);
}

select option:checked,
select option:hover,
select option:focus {
  background: var(--metal-mid);
  color: var(--ink-on-chrome);
}

input::placeholder { color: var(--silver-faint); }

input:focus, select:focus {
  outline: 2px solid var(--starlight);
  outline-offset: 1px;
  border-color: var(--metal-lo);
}

@media (max-width: 768px) {
  body {
    font-size: 14px;
  }
}

/* ── layout ── */
.app { min-height: 100vh; display: flex; flex-direction: column; }
.nav {
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  border-bottom: 1px solid var(--metal-line);
  color: var(--text);
  padding: 1rem 2rem;
  display: flex; justify-content: space-between; align-items: center;
  flex-wrap: wrap; gap: 1rem;
}
.nav a { color: var(--silver-dim); }
.nav a:hover { color: var(--starlight); }
.nav-brand { color: var(--heading); font-size: 1.25rem; font-weight: bold; text-decoration: none; }
.nav-links { display: flex; gap: 1rem; align-items: center; }
.nav-logout {
  background: transparent; border: 1px solid var(--glass-border); color: var(--silver-dim);
  padding: 0.25rem 0.75rem; border-radius: 4px;
}
.nav-logout:hover { border-color: var(--silver-dim); color: var(--starlight); }
main { flex: 1; }
.footer { padding: 1rem; text-align: center; font-size: 0.875rem; color: var(--silver-faint); }

/* ── shared ── */
.card {
  position: relative;
  border: 1px solid transparent;
  background:
    linear-gradient(var(--glass-bg), var(--glass-bg)) padding-box,
    var(--metal-edge) border-box;
  -webkit-backdrop-filter: blur(20px);
  backdrop-filter: blur(20px);
  padding: 1.5rem; border-radius: 18px 6px 18px 6px;  /* tailfin cut */
  margin-bottom: 1.5rem;
}
/* one line of skylight along the card's top edge */
.card::before {
  content: '';
  position: absolute; inset: 0 0 auto 0; height: 1px;
  border-radius: inherit; pointer-events: none;
  background: linear-gradient(90deg, transparent, rgba(248, 250, 252, 0.55), transparent);
}
.card,
.feature {
  transition: filter 0.4s ease;
}
.card:hover,
.feature:hover {
  filter: brightness(1.12);
}

.page { padding: 1.5rem; max-width: 800px; margin: 0 auto; }
.page-narrow { padding: 1.5rem; max-width: 600px; margin: 0 auto; }
.center-note { padding: 2rem; text-align: center; }
.error { color: var(--rose); margin-bottom: 1rem; font-size: 0.875rem; }
.muted { color: var(--silver-faint); }
/* primary CTA = chrome plate: on a dark site a bright plate with dark ink
   IS the strongest call-to-action signal (no hue needed). Bullet-nose
   silhouette + top reflection line = Jet Age streamline. */
.cta,
.btn-primary {
  position: relative; overflow: hidden;
  border: 1px solid transparent;
  border-radius: 999px;
  background:
    linear-gradient(180deg,
      #f8fafc 0%, #dbe2eb 34%, #aab3c1 50%,
      #8e97a6 56%, #c4ccd8 82%, #eef2f7 100%) padding-box,
    linear-gradient(160deg,
      rgba(255, 255, 255, 0.75), rgba(154, 163, 178, 0.35) 40%,
      rgba(248, 250, 252, 0.6) 65%, rgba(154, 163, 178, 0.3)) border-box;
  color: var(--ink-on-chrome);
}
.btn-primary {
  padding: 0.75rem 1.5rem; cursor: pointer; font-size: 1rem;
  font-weight: 500; text-decoration: none;
}
.cta { padding: 0.75rem 2rem; font-weight: 500; }
.cta::before,
.btn-primary::before {
  content: '';
  position: absolute; left: 6%; right: 6%; top: 2px; height: 42%;
  border-radius: 999px 999px 50% 50% / 999px 999px 100% 100%;
  background: linear-gradient(180deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0));
  pointer-events: none;
}
.btn-primary:hover,
.cta:hover {
  filter: brightness(1.06);
  box-shadow: 0 0 18px rgba(248, 250, 252, 0.32);
}
.btn-primary:active,
.cta:active { filter: brightness(0.95); transform: translateY(1px); }
/* disabled = 處理中/已鎖定（Google 登入 debounce、magic-link 送信中） */
.btn-primary:disabled { opacity: 0.65; cursor: not-allowed; filter: none; }
.auth-submit { display: inline-flex; align-items: center; justify-content: center; gap: 0.5rem; }
.button-spinner {
  display: inline-block;
  width: 0.9rem;
  height: 0.9rem;
  flex: 0 0 auto;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: button-spin 0.7s linear infinite;
}
@keyframes button-spin { to { transform: rotate(360deg); } }
.btn-block { width: 100%; padding: 1rem 1.5rem; border-radius: 8px; border: none; font-size: 1rem; }
.btn-link, .back-link { background: none; border: none; color: #cfd6e0; cursor: pointer; }
.back-link { margin-bottom: 1rem; }
.prose { white-space: pre-wrap; line-height: 1.8; }

/* ── home ── */
.hero { padding: 3rem 2rem; max-width: 1200px; margin: 0 auto; }
/* Jet Age speed lines removed (issue#1 評論 2026-09-17): 右上三條橫線被
   測試者當成來路不明的雜線 — 這裡不留替代裝飾 */
.hero-head { text-align: center; margin-bottom: 3rem; }
.hero-head h1 { font-size: 2.5rem; margin-bottom: 1rem; color: var(--heading); }
.hero-sub { font-size: 1.25rem; color: var(--silver-dim); margin-bottom: 2rem; }
.hero-actions { display: flex; gap: 1rem; justify-content: center; flex-wrap: wrap; }
.cta-alt {
  color: #cfd6e0; padding: 0.75rem 2rem;
  border-radius: 999px; text-decoration: none; font-weight: 500;
  border: 1px solid var(--metal-lo);
  background: rgba(255, 255, 255, 0.04);
}
.cta-alt:hover {
  color: var(--metal-hi);
  border-color: var(--metal-hi);
  background: rgba(255, 255, 255, 0.08);
}
.feature-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem; margin-top: 3rem;
}
.feature {
  border: 1px solid transparent;
  /* 2026-09-17 issue#1：方框內漸層加深（deep-space 往 void 壓深），凸顯白字 —
     銀河玻璃白 0.05 換成深藍縱向漸層；silver-dim 對比 6.2 → 8.4:1 */
  background:
    linear-gradient(180deg, rgba(10, 23, 51, 0.32), rgba(5, 13, 31, 0.55)) padding-box,
    var(--metal-edge) border-box;
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  padding: 2rem; border-radius: 18px 6px 18px 6px;  /* tailfin cut */
}
.feature h3 { font-size: 1.25rem; margin-bottom: 0.5rem; color: var(--heading); }
.feature p { color: var(--silver-dim); }
/* 2026-09-17 issue#1：標題前的圖示脫離鏡面漸層，改白色實體，與鍍鉻標題字跳出色差 */
.feature-icon {
  background-image: none;
  color: var(--starlight);
  -webkit-text-fill-color: var(--starlight);
}
/* 2026-09-18 issue #2：姓名學/名詞解釋為整卡連結 — 擋全域 a 的底線/hover 光暈/改色，
   讓連結卡與 div 卡視覺一致（全域 a:hover 會穿透子元素，故逐項重設） */
a.feature { display: block; text-decoration: none; color: inherit; }
a.feature:hover { text-decoration: none; color: inherit; text-shadow: none; }

/* chrome ring on the ONE featured card — silver-white only (hue-rotate
   drift removed: it does nothing on a hueless gradient) */
.feature-grid .feature:first-child {
  position: relative;
  isolation: isolate;
}
.feature-grid .feature:first-child::before {
  content: '';
  position: absolute;
  inset: 0;
  padding: 1px;
  border-radius: inherit;
  pointer-events: none;
  background: conic-gradient(
    from 210deg,
    #8a93a5,
    #c8d0dc,
    #f8fafc,
    #eef2f7,
    #9aa3b2,
    #8a93a5
  );
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  mask-composite: exclude;
}

/* ── forms ── */
.auth-page { padding: 2rem; max-width: 400px; margin: 3rem auto; }
.field { margin-bottom: 1rem; }
.field label { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; font-weight: 500; color: var(--silver-dim); }
.field input { width: 100%; padding: 0.75rem; font-size: 1rem; }
.form-grid3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0.5rem; }
.form-col { display: flex; flex-direction: column; gap: 1rem; }
.form-label { font-size: 0.875rem; color: var(--silver-faint); }
.form-input {
  padding: 0.5rem; border: 1px solid var(--glass-border); border-radius: 4px;
  width: 100%; background: var(--glass-bg); color: var(--text);
}
.hour-row { display: flex; gap: 0.5rem; align-items: center; }
.hour-unknown { display: flex; align-items: center; gap: 0.25rem; font-size: 0.875rem; color: var(--silver-dim); }
.prediction-tuner {
  margin: 0 0 1rem;
  padding: 0.9rem 1rem 0.85rem;
  border: 1px solid var(--glass-border);
  border-radius: 12px 4px 12px 4px;
  background: rgba(10, 23, 51, 0.42);
}
.prediction-tuner-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 0.75rem;
  margin-bottom: 0.7rem;
}
.prediction-tuner-head strong { color: var(--heading); font-size: 0.95rem; }
.prediction-tuner-caption,
.prediction-tuner-scale,
.prediction-tuner-hint,
.prediction-tuner-locked {
  color: var(--silver-dim);
  font-size: 0.75rem;
}
.prediction-tuner-caption { display: block; margin-top: 0.15rem; }
.prediction-tuner-scale { white-space: nowrap; }
.prediction-tuner-actions { margin: -0.2rem 0 0.6rem; text-align: right; }
.prediction-tuner-reroll { padding: 0; font-size: 0.75rem; }
.prediction-tuner-reroll:disabled { opacity: 0.55; cursor: not-allowed; }
.prediction-tuner-rows { display: grid; gap: 0.5rem; }
.strength-slider-row {
  display: grid;
  grid-template-columns: 3.25rem minmax(0, 1fr) 3.5rem;
  align-items: center;
  gap: 0.65rem;
  font-size: 0.85rem;
}
.strength-slider-label { color: var(--text); }
.strength-slider-row input[type="range"] {
  width: 100%;
  accent-color: var(--starlight);
  cursor: pointer;
}
.strength-slider-row input[type="range"]:disabled { cursor: not-allowed; }
.strength-slider-value {
  color: var(--starlight);
  font-size: 0.78rem;
  text-align: right;
  white-space: nowrap;
}
.prediction-tuner-hint { margin: 0.75rem 0; }
.prediction-tuner-locked { margin: 0.75rem 0 0; }

/* ── ziwei palace grid ── */
.chart-meta { display: flex; flex-wrap: wrap; gap: 1rem; font-size: 0.9rem; color: var(--silver-dim); }
.palace-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 0.5rem; }
.palace {
  border: 1px solid var(--glass-border); border-radius: 8px; padding: 0.5rem;
  background: rgba(10, 23, 51, 0.55);
}
/* life palace: informational highlight — chrome border + inner glow,
   distinct from the inverted-plate "selected" state used by quiz */
.palace.life {
  border: 1px solid transparent;
  background:
    linear-gradient(rgba(255, 255, 255, 0.07), rgba(255, 255, 255, 0.03)) padding-box,
    linear-gradient(180deg, rgba(248, 250, 252, 0.85), rgba(154, 163, 178, 0.25) 45%, rgba(248, 250, 252, 0.5)) border-box;
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, 0.06),
    0 0 14px -4px rgba(248, 250, 252, 0.4);
}
.palace-head { font-weight: 600; font-size: 0.85rem; color: var(--heading); }
.palace-stars { margin-top: 0.25rem; display: flex; flex-wrap: wrap; gap: 0.25rem; }
.star { font-size: 0.8rem; padding: 0.15rem 0.35rem; border-radius: 4px; background: rgba(255, 255, 255, 0.07); color: var(--silver-dim); }
.star.main { background: rgba(229, 228, 226, 0.14); color: var(--starlight); }
.star.transformation { background: rgba(251, 113, 133, 0.12); color: var(--rose); }
/* The life palace swaps the navy plate for a near-white highlight
   (rgba(255,255,255,.07) top stop). Star pills are semi-transparent, so
   they used to resolve against that brighter plate and lost the AA floor
   the navy palaces hold: silver-dim 4.05:1, rose 3.48:1 (star-blue ground,
   2026-09-17). Re-lay the navy plate UNDER the role tint inside the life
   palace only. Result: life-palace pills silver-dim 6.7:1, starlight
   9.3:1, rose 4.6:1 — i.e. DARKER than an ordinary palace (6.0 / 5.0),
   not "the same as"; rose there is the tightest passing text on the site.
   These selectors are 3 and 4 classes so they outrank both `.star*` (1-2)
   and `.on-light .star` (2). If a life palace is ever nested inside an
   `.on-light` surface, the background below would still win while the
   colour came from the light branch — keep the pair together. */
.palace.life .star {
  background: rgba(10, 23, 51, 0.55);
  color: var(--silver-dim);
}
.palace.life .star.main {
  background:
    linear-gradient(rgba(229, 228, 226, 0.14), rgba(229, 228, 226, 0.14)),
    rgba(10, 23, 51, 0.55);
  color: var(--starlight);
}
.palace.life .star.transformation {
  background:
    linear-gradient(rgba(251, 113, 133, 0.12), rgba(251, 113, 133, 0.12)),
    rgba(10, 23, 51, 0.55);
  color: var(--rose);
}

/* ── /personality result: OCEAN score tracks (Grok design review) ── */
.ocean-dim {
  background: rgba(255, 255, 255, 0.04);
  border-radius: 8px;
  padding: 1rem 1.125rem 1.125rem;
  margin-bottom: 0.75rem;
}
.ocean-dim:last-of-type { margin-bottom: 0; }
.ocean-dim-head {
  display: flex; justify-content: space-between; align-items: baseline;
  gap: 1rem; margin-bottom: 0.375rem;
}
.ocean-dim-head strong { font-size: 0.9375rem; color: var(--heading); font-weight: 600; }
.ocean-score {
  font-variant-numeric: tabular-nums;
  font-size: 1.375rem;
  font-weight: 700;
  line-height: 1;
  letter-spacing: -0.02em;
  background-image: linear-gradient(180deg, #fdfeff 0%, #dbe2eb 55%, #a8b1bf 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}
.ocean-track-wrap { padding: 10px 12px 8px; }
.ocean-track {
  position: relative;
  height: 8px;
  background: rgba(255, 255, 255, 0.08);
  border-radius: 999px;
}
.ocean-band {
  position: absolute; top: 0; height: 100%;
  background: linear-gradient(90deg, #8e97a6, #e2e8f0);  /* value = length, not hue */
  border-radius: 999px;
}
.ocean-mean {
  position: absolute;
  top: -5px; width: 2px; height: 18px;
  background: var(--silver-faint);
  border-radius: 1px;
  transform: translateX(-50%);
}
.ocean-marker {
  position: absolute; top: 50%;
  width: 14px; height: 14px;
  background: var(--starlight);
  border: 2px solid var(--deep-space);
  box-shadow: 0 0 0 1px var(--metal-mid), 0 0 8px rgba(248, 250, 252, 0.45);
  border-radius: 50%;
  transform: translate(-50%, -50%);
}
.ocean-caption {
  font-size: 0.75rem;
  color: var(--silver-faint);
  margin: 0.375rem 0 0;
}
.ocean-copy {
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  line-height: 1.65;
  color: var(--silver-dim);
}
.ocean-foot {
  margin-top: 1.5rem;
  padding-top: 1.25rem;
  border-top: 0;
}
/* chrome trim: divider between the result body and actions */
.ocean-foot::before {
  content: '';
  display: block;
  width: 8rem;
  height: 2px;
  border-radius: 2px;
  margin-bottom: 1rem;
  background: linear-gradient(90deg,
    transparent 0%, #6f7787 10%, #f8fafc 45%,
    #8e97a6 55%, #3f4756 90%, transparent 100%);
  opacity: 0.75;
}
.ocean-foot strong {
  display: block;
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--silver-dim);
}
.ocean-foot > .muted { font-size: 0.8rem; margin-top: 0.375rem; }
.ocean-foot details { margin-top: 1rem; }
.ocean-foot summary { color: var(--silver-faint); font-size: 0.875rem; cursor: pointer; }
.ocean-foot .actions { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.25rem; }

/* ── /personality quiz: Likert matrix (Grok design review) ── */
.quiz-head { display: flex; justify-content: space-between; gap: 1rem; align-items: start; margin-bottom: 1rem; }
.quiz-head .muted { color: var(--silver-dim); }
.quiz-head .btn-link { flex-shrink: 0; font-size: 0.875rem; white-space: nowrap; }
.quiz-consent { font-size: 0.8125rem; margin-bottom: 1.25rem; color: var(--silver-dim); }
.quiz-progress { font-size: 0.8125rem; color: var(--silver-dim); margin: 0; font-variant-numeric: tabular-nums; }
.quiz-progress strong { color: var(--text); font-weight: 700; }
.quiz-progress-bar { height: 3px; background: rgba(255, 255, 255, 0.12); border-radius: 999px; margin: 0.5rem 0 1.25rem; overflow: hidden; }
.quiz-progress-bar > span { display: block; height: 100%; background: linear-gradient(90deg, #8e97a6, #f8fafc); border-radius: inherit; }
.quiz-key {
  display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.375rem;
  padding: 0 1rem 0.75rem; font-size: 0.6875rem; line-height: 1.3;
  color: var(--silver-dim); text-align: center;
}
.quiz-item {
  border: 0; min-width: 0; background: rgba(255, 255, 255, 0.04); border-radius: 8px;
  margin: 0 0 0.5rem; padding: 0.75rem 1rem 0.875rem;
}
.quiz-item:last-of-type { margin-bottom: 0; }
.quiz-item legend {
  float: none; width: 100%; padding: 0; margin: 0 0 0.625rem;
  font-weight: 600; font-size: 0.9375rem; color: var(--heading);
}
.quiz-no {
  display: inline-block; min-width: 1.5rem; text-align: center; margin-right: 0.5rem;
  font-size: 0.75rem; font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--ink-on-chrome); background: linear-gradient(180deg, #e8edf4, #b6bfcc); border-radius: 4px; padding: 0.1rem 0.35rem;
}
.quiz-choices { display: grid; grid-template-columns: repeat(5, minmax(0, 1fr)); gap: 0.375rem; }
.quiz-choice {
  position: relative; display: flex; align-items: center; justify-content: center;
  min-height: 44px; border: 1px solid var(--glass-border); border-radius: 8px;
  background: rgba(10, 23, 51, 0.55);
  cursor: pointer; font-variant-numeric: tabular-nums; font-weight: 600; color: var(--silver-dim);
}
.quiz-choice:hover { border-color: var(--metal-mid); background: rgba(255, 255, 255, 0.07); }
/* selected = inverted chrome plate — inversion is reserved for selection only */
.quiz-choice:has(input:checked) {
  background: linear-gradient(180deg, #f8fafc, #c8d0dc);
  border-color: var(--metal-hi);
  color: var(--ink-on-chrome);
}
.quiz-choice:has(input:focus-visible) { outline: 2px solid var(--starlight); outline-offset: 2px; }
.quiz-choice input {
  appearance: none; position: absolute; inset: 0; opacity: 0; margin: 0; border: 0; cursor: pointer;
}
.quiz-submit {
  position: sticky; bottom: 0;
  margin: 1.25rem -1.5rem -1.5rem;
  padding: 0.75rem 1.5rem calc(0.75rem + env(safe-area-inset-bottom));
  background: var(--glass-bg-strong);
  -webkit-backdrop-filter: blur(20px); backdrop-filter: blur(20px);
  border-top: 1px solid var(--metal-line);
}
.quiz-submit .btn-primary { width: 100%; }
.quiz-submit .btn-primary:disabled { opacity: 1; background: rgba(255, 255, 255, 0.08); color: var(--silver-faint); cursor: not-allowed; }
@media (max-width: 639px) {
  .quiz-key { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 0.25rem 0.75rem; padding: 0 0.25rem 0.75rem; }
  .quiz-key { counter-reset: k; }
  .quiz-key span { counter-increment: k; }
  .quiz-key span::before { content: counter(k) " "; font-weight: 600; color: var(--metal-mid); }
}

/* dark scrollbar polish */
::-webkit-scrollbar { width: 10px; }
::-webkit-scrollbar-track { background: var(--void); }
::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.12); border-radius: 999px; }
::-webkit-scrollbar-thumb:hover { background: rgba(255, 255, 255, 0.2); }

/* coarse-pointer fallback (spec §8): drop blur (which would recompute
   over the animating canvas every frame) and raise the strong-glass
   alpha so nav/sticky bars stay legible */
@media (pointer: coarse) {
  .nav,
  .card,
  .feature,
  .quiz-submit {
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  .card,
  .feature {
    background: rgba(10, 23, 51, 0.82);  /* solid ground: no blur to rely on */
  }
  :root { --glass-bg-strong: rgba(8, 18, 42, 0.9); }
  /* glint off on touch devices too: every pass repaints the heading over
     the animating galaxy canvas — same reason blur is dropped above */
  h1, h2, h3, h4, h5, h6, .nav-brand {
    animation: none;
  }
}

/* ── light-surface safety (contrast fix) ──
   任何白/淺底面板內的文字必須用深墨色，否則會繼承 var(--text)/var(--starlight)
   的淡色而隱形（如 divination 西洋行星白卡）。掛上 .on-light 即自動翻正，
   並把鏡面標題的漸層關掉改實色，避免白字在白底上消失。
   另外提供 .text-frame 給疊在不確定背景上的淡字（加描邊/陰影）備用。 */
.on-light { color: var(--ink-on-chrome); }
.on-light h1, .on-light h2, .on-light h3, .on-light h4, .on-light h5, .on-light h6,
.on-light .palace-head {
  background: none;
  -webkit-background-clip: border-box;
  background-clip: border-box;
  -webkit-text-fill-color: var(--ink-on-chrome);
  filter: none;
  color: var(--ink-on-chrome);
  animation: none;  /* glint layer is clipped-text only; keep light surfaces fully static */
}
.on-light .muted { color: var(--text-muted-on-light); }
.on-light a { color: #1e3a8a; text-decoration-color: rgba(30, 58, 138, 0.35); }
.on-light a:hover { color: #1e40af; text-decoration-color: #1e40af; }
/* 淺底上的 star 標籤：覆蓋深色玻璃版的淡字設定 */
.on-light .star { background: #fff; color: var(--text-muted-on-light); border-color: #e5e7eb; }
.on-light .star.main { background: #fff; color: #374151; border-color: #e5e7eb; }

/* 字框備用：淡字疊在照片/漸層等不確定底色上時，描邊保底線可讀性 */
.text-frame {
  text-shadow:
    0 1px 2px rgba(16, 20, 31, 0.75),
    0 0 1px rgba(16, 20, 31, 0.9),
    0 0 8px rgba(16, 20, 31, 0.45);
}
.text-frame--light {
  -webkit-text-stroke: 0.45px rgba(16, 20, 31, 0.55);
  paint-order: stroke fill;
}
