:root {
  /* Ink on paper. Every value here clears 4.5:1 on the white ground at body
     sizes; the two display golds clear 4.5:1 as well, so they can carry headings
     and small accent text alike. */
  --ink: #10192b;
  --ink-soft: #33405a;
  --ink-muted: #5c6a83;

  /* Gold splits in two on a light ground: the -fill pair is the original bright
     leaf, which only ever sits behind dark text or as a wash, while --gold and
     --gold-bright are darkened to stay legible AS text on white. */
  --gold: #9a7420;
  --gold-bright: #7a5a11;
  --gold-fill: #e8c37a;
  --gold-fill-bright: #f7dfa8;
  --gold-wash: rgba(232, 195, 122, 0.22);
  --azure: #1f4fa8;
  --danger: #b3261e;
  --success: #1a7f4b;

  --paper: #ffffff;
  --panel: #fbf8f1;
  --panel-solid: #ffffff;
  --line: rgba(138, 106, 31, 0.28);
  --line-soft: rgba(16, 25, 43, 0.12);
  --shadow: 0 10px 30px rgba(16, 25, 43, 0.08);
  --radius: 16px;
  --maxw: 1100px;

  /* Height of the pinned header. header.js overwrites it with the measured value
     on load and on resize; these are the fallbacks for the first paint and for
     the case where the script never runs. */
  --header-h: 68px;

  /* Marcellus keeps the Roman inscriptional feel the display face is after, but
     it ships a single 400 weight — so display rules must not ask for 600/700 or
     the browser synthesises a smeared faux-bold. Lato carries the body: humanist,
     large x-height, and far more legible at small sizes than a Garamond is. */
  --font-display: "Marcellus", "Noto Serif Devanagari", "Trajan Pro", Georgia, "Times New Roman", serif;
  --font-body: "Lato", "Noto Sans Devanagari", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;

  /* The Noto faces sit second in each stack for the Devanagari that Marcellus
     and Lato do not carry. Google Fonts serves them split by script, so an
     English page never downloads them: the browser only fetches the Devanagari
     subset once a Devanagari letter is actually drawn. */

  /* Held at none: the scrim existed to lift light glyphs off the background
     artwork, and dark text on white needs no such help. Kept as a token so the
     rules that reference it don't all have to be rewritten. */
  --text-scrim: none;

  /* Gold-to-azure sweep for the display headings, darkened for a white ground. */
  --grad-accent: linear-gradient(100deg, #a8781f, #7a5a11 45%, var(--azure));
}

* { box-sizing: border-box; }

/* Lato has a large x-height, so the scale that Garamond needed nudged up to 17px
   goes back to the 16px default without the text reading any smaller. */
html {
  scroll-behavior: smooth;
  font-size: 16px;
  /* Stops iOS inflating body copy when the phone turns landscape. */
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  padding-top: var(--header-h);
  font-family: var(--font-body);
  font-weight: 400;
  color: var(--ink);
  background: var(--paper);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -webkit-tap-highlight-color: rgba(154, 116, 32, 0.15);
  overflow-wrap: break-word;
}

h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1.25;
  margin: 0;
}

p { margin: 0; }

/* ---------- Header / nav ---------- */

.site-header {
  /* Fixed, not sticky: the bar is out of flow entirely, so it cannot ride up or
     down with the page on any browser. body's padding-top reserves its space. */
  position: fixed;
  /* 0 on the site itself; header.js raises it to the height of Google's bar
     when the page is read through the translation proxy. */
  top: var(--bar-top, 0px);
  left: 0;
  right: 0;
  z-index: 20;
  background: rgba(255, 255, 255, 0.88);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}

.nav-wrap {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0.9rem 1.5rem;
  display: flex;
  align-items: center;
  gap: 1.5rem;
  flex-wrap: wrap;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  text-decoration: none;
  color: var(--ink);
}

.brand-mark {
  width: 38px;
  height: 38px;
  display: block;
  flex: 0 0 auto;
  transition: transform 0.25s ease;
}

.brand:hover .brand-mark { transform: scale(1.07); }

.brand-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 1.05rem;
  letter-spacing: 0.04em;
}

.site-nav {
  display: flex;
  gap: 1.75rem;
  font-size: 0.9rem;
  /* Pushed to the far side of the bar; the language switcher follows it. */
  margin-left: auto;
}

.site-nav a {
  color: var(--ink-soft);
  text-decoration: none;
  position: relative;
  padding-bottom: 2px;
  transition: color 0.2s ease;
}

.site-nav a::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 0;
  height: 1px;
  background: var(--gold);
  transition: width 0.25s ease;
}

.site-nav a:hover { color: var(--gold-bright); }
.site-nav a:hover::after { width: 100%; }

/* The selected tab. [aria-current] covers both cases: "page" is set in the markup
   on guide.html and about.html, and header.js sets "location" on whichever
   in-page section the reader has scrolled to. The rule reuses the hover
   underline, so the two states line up rather than sitting at different heights. */
.site-nav a[aria-current] {
  color: var(--gold-bright);
}

.site-nav a[aria-current]::after {
  width: 100%;
  height: 2px;
  background: linear-gradient(90deg, var(--gold), var(--gold-bright));
}

/* The hamburger. Hidden on the desktop layout, where all five tabs fit on the
   bar; the 820px breakpoint below reveals it as the only nav control. */
.nav-toggle {
  display: none;
  width: 44px;
  height: 44px;
  flex: 0 0 auto;
  padding: 0;
  margin-right: -0.35rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: rgba(232, 195, 122, 0.16);
  color: var(--gold-bright);
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.nav-toggle:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Three bars drawn from one box: the box itself is the middle bar, the two
   pseudo-elements the outer pair. Open state rotates the middle into a cross and
   hides the outers, so the icon animates without a second SVG. */
.nav-toggle-bars,
.nav-toggle-bars::before,
.nav-toggle-bars::after {
  display: block;
  width: 20px;
  height: 2px;
  margin: 0 auto;
  border-radius: 2px;
  background: currentColor;
  transition: transform 0.22s ease, opacity 0.18s ease;
}

.nav-toggle-bars { position: relative; }

.nav-toggle-bars::before,
.nav-toggle-bars::after {
  content: "";
  position: absolute;
  left: 0;
}

.nav-toggle-bars::before { top: -6px; }
.nav-toggle-bars::after { top: 6px; }

.nav-toggle[aria-expanded="true"] .nav-toggle-bars { transform: rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::before { opacity: 0; transform: translateY(6px); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars::after { transform: translateY(-6px) rotate(-90deg); }

/* ---------- Language ---------- */

/* A translation arrives with the page's lang attribute set to its language.
   Devanagari sets taller than Latin — vowel signs hang above and below the
   headline — and tracking pulls a base letter away from its own signs, so the
   spaced-out small caps the design uses elsewhere are set solid in the
   languages written in it. */
:lang(hi), :lang(mr), :lang(ne) { line-height: 1.75; }
:lang(hi) h1, :lang(hi) h2, :lang(hi) h3,
:lang(mr) h1, :lang(mr) h2, :lang(mr) h3,
:lang(ne) h1, :lang(ne) h2, :lang(ne) h3 { line-height: 1.35; }
:lang(hi) .eyebrow, :lang(mr) .eyebrow, :lang(ne) .eyebrow,
:lang(hi) .brand-name,
:lang(hi) .section-title,
:lang(hi) .result-name,
:lang(hi) .field label,
:lang(hi) .correction-label,
:lang(hi) .label-hint,
:lang(hi) .number-card .label,
:lang(hi) .axis-label,
:lang(hi) .plane-name span,
:lang(hi) .anti-tag,
:lang(hi) .forecast th,
:lang(hi) .inside-num,
:lang(hi) .footer-name,
:lang(hi) th { letter-spacing: 0; }

/* The switcher, built by translate.js: one select on the header bar. On the
   wide layout it follows the tabs; on the narrow one it sits beside the
   hamburger. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  flex: 0 0 auto;
  /* Last on the bar. It is inserted before the hamburger in the markup so the
     two stay together on the narrow layout; here it follows the tabs. */
  order: 1;
}

.lang-select {
  appearance: none;
  -webkit-appearance: none;
  height: 34px;
  padding: 0 1.7rem 0 0.7rem;
  border: 1px solid var(--line);
  border-radius: 9px;
  background: rgba(232, 195, 122, 0.16)
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%239a7420' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E")
    no-repeat right 0.65rem center;
  color: var(--ink-soft);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
}

.lang-select:hover { color: var(--gold-bright); }

.lang-select:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
}

/* Text for a screen reader that leaves no mark on the layout. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---------- Hero ---------- */

.hero {
  position: relative;
  max-width: 780px;
  margin: 0 auto;
  padding: 6rem 1.5rem 4.5rem;
  text-align: center;
}

.eyebrow {
  font-size: 0.75rem;
  letter-spacing: 0.28em;
  text-transform: uppercase;
  color: var(--gold);
  margin-bottom: 1.5rem;
  text-shadow: var(--text-scrim);
}

.hero h1 {
  font-size: clamp(1.75rem, 4.2vw, 2.6rem);
  margin-bottom: 1.35rem;
}

.hero h1 span {
  display: block;
  background: var(--grad-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Homepage headline: one gold-to-azure sweep across the whole heading, so the
   inner span only breaks the line rather than starting a second gradient. */
.hero h1.gradient-title {
  background: var(--grad-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.hero h1.gradient-title span { background: none; }

.hero-sub {
  font-size: clamp(0.92rem, 1.4vw, 1.02rem);
  color: var(--ink-soft);
  max-width: 620px;
  margin: 0 auto 2.25rem;
  text-shadow: var(--text-scrim);
}

/* ---------- Buttons ---------- */

.btn {
  display: inline-block;
  padding: 0.85rem 2rem;
  border: none;
  border-radius: 999px;
  font-family: inherit;
  font-size: 0.95rem;
  font-weight: 500;
  letter-spacing: 0.03em;
  cursor: pointer;
  text-decoration: none;
  transition: transform 0.18s ease, box-shadow 0.25s ease, filter 0.2s ease;
}

.btn-primary {
  background: linear-gradient(120deg, var(--gold-fill-bright), var(--gold-fill) 50%, #d9a95c);
  color: #2a1a05;
  box-shadow: 0 8px 22px rgba(138, 106, 31, 0.22);
}

.btn-primary:hover {
  transform: translateY(-2px);
  filter: brightness(1.06);
  box-shadow: 0 14px 30px rgba(138, 106, 31, 0.3);
}

.btn-primary:active { transform: translateY(0); }

/* Centred explicitly: a <button> centres its label by default, a link styled as
   one does not, and the details card now carries both. */
.btn-block { width: 100%; margin-top: 0.5rem; text-align: center; }

/* The hero and the guide/about CTA blocks have no bottom padding of their own,
   so the clearance under the call to action lives on the button. */
.btn-cta { margin-bottom: 20px; }

/* ---------- Cards ---------- */

.card {
  background: var(--panel);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}

/* ---------- Google's in-page translator ----------
   translate.js loads Google's Website Translator for a reader who has chosen a
   language. The header's switcher is the only control the reader needs, so
   Google's own pieces are kept out of sight: its banner (which would also push
   the page down 40px), its hidden language picker, and the balloon it pops over
   any translated sentence that is hovered or tapped — a popup over the report
   is the very thing the in-page translator was brought in to avoid. Google's
   newer builds use obfuscated class names; both generations are listed. */
.goog-te-banner-frame,
iframe.skiptranslate,
.skiptranslate > iframe,
.VIpgJd-ZVi9od-ORHb-OEVmcd,
#google_translate_element,
#goog-gt-tt,
.goog-te-balloon-frame,
.goog-tooltip,
.VIpgJd-yAWNEb-L7lbkb,
.VIpgJd-ZVi9od-aZ2wEe-wOHMyf { display: none !important; }

/* The banner shifts the page by setting top on <body>; with the banner hidden
   that would only leave a gap. */
body { top: 0 !important; }

/* The highlight Google paints behind a sentence on hover. */
.goog-text-highlight,
.VIpgJd-yAWNEb-VIpgJd-fmcmS-sn54Q {
  background: none !important;
  box-shadow: none !important;
}

/* ---------- Calculator ---------- */

.calculator-section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 0 1.5rem 5rem;
  scroll-margin-top: 90px;
}

.form-card {
  max-width: 480px;
  margin: 0 auto;
  padding: 2.25rem;
}

.form-card h2 {
  font-size: 1.35rem;
  text-align: center;
  margin-bottom: 1.75rem;
  color: var(--gold-bright);
}

.field { margin-bottom: 1.25rem; }

.field label {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.5rem;
}

.field input,
.field select {
  width: 100%;
  padding: 0.85rem 1rem;
  font-family: inherit;
  font-size: 1rem;
  font-weight: 400;
  color: var(--ink);
  background: #fff;
  border: 1px solid rgba(16, 25, 43, 0.22);
  border-radius: 10px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease, background 0.2s ease;
}

.field input::placeholder { color: #8a95a8; }

.field input:focus,
.field select:focus {
  outline: none;
  border-color: var(--gold);
  background: #fff;
  box-shadow: 0 0 0 3px rgba(154, 116, 32, 0.18);
}

.field input[aria-invalid="true"],
.field select[aria-invalid="true"] {
  border-color: var(--danger);
  box-shadow: 0 0 0 3px rgba(179, 38, 30, 0.14);
}

/* One line under each control saying what it is for. Sits above the error
   slot, so a message appearing never moves the hint. */
.field-hint {
  margin-top: 0.45rem;
  font-size: 0.8rem;
  line-height: 1.45;
  color: #8a95a8;
}

.field-error {
  display: block;
  min-height: 1.1rem;
  margin-top: 0.4rem;
  font-size: 0.78rem;
  color: var(--danger);
}

/* A date input ignores its placeholder attribute, and iOS Safari shows an empty
   date as a blank box — no prompt at all until a date is picked. So the prompt
   is painted here, and only there: Chrome and desktop Safari already show the
   format in the field itself, and would show both. -webkit-touch-callout is
   supported by iOS WebKit alone, which is what the @supports selects on. The
   field is data-empty in the markup and script.js takes the attribute off once
   it holds a value — an attribute rather than :invalid, so a chosen date the
   min attribute rejects is not painted over. */
@supports (-webkit-touch-callout: none) {
  .field input[type="date"][data-empty]::before {
    content: attr(placeholder);
    color: #8a95a8;
  }
}

input[type="date"]::-webkit-calendar-picker-indicator {
  cursor: pointer;
  opacity: 0.6;
}

/* ---------- Results ---------- */

.results-section {
  margin-top: 3.5rem;
  scroll-margin-top: 100px;
  animation: rise 0.5s ease both;
}

.results-section.hidden { display: none; }

/* Shown in place of the whole report when it cannot be built — a gap in the
   reference data behind the calculator. Carries the panel's own card treatment
   rather than the danger red used for a field the visitor can correct: nothing
   here is theirs to fix, and shouting about it would only suggest otherwise. */
.report-error {
  background: var(--panel);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--line);
  border-left: 3px solid var(--danger);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 1.75rem;
}

.report-error h2 {
  font-size: 1.15rem;
  margin: 0 0 0.75rem;
}

.report-error p {
  color: var(--ink-muted);
  font-size: 0.92rem;
  margin: 0 0 0.6rem;
}

.report-error p:last-child { margin-bottom: 0; }

@keyframes rise {
  from { opacity: 0; transform: translateY(18px); }
  to { opacity: 1; transform: translateY(0); }
}

.report-head { text-align: center; margin-bottom: 2rem; text-shadow: var(--text-scrim); }

.results-title {
  font-size: clamp(1.5rem, 3vw, 1.9rem);
  color: var(--gold-bright);
  margin-bottom: 0.5rem;
}

/* The one line in the report that says whose it is — the name, its total, and
   the date the whole chart is built from. Set bold and a couple of points up on
   the rest of the small caps, so a printed sheet is identifiable at a glance. */
.result-name {
  color: var(--ink-soft);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-size: 0.9rem;
  font-weight: 700;
}

.number-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(190px, 100%), 1fr));
  gap: 1.25rem;
}

.number-card {
  padding: 1.75rem 1.25rem;
  text-align: center;
  background: var(--panel);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  transition: transform 0.25s ease, border-color 0.25s ease;
}

.number-card:hover {
  transform: translateY(-4px);
  border-color: rgba(138, 106, 31, 0.45);
}

.number-card .label {
  font-size: 0.72rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--ink-muted);
}

.number-card .value {
  font-family: var(--font-display);
  font-size: 3.2rem;
  font-weight: 400;
  line-height: 1.1;
  margin: 0.35rem 0 0.5rem;
  background: linear-gradient(150deg, #a8781f, #6f5210);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.number-card .detail {
  font-size: 0.82rem;
  color: var(--ink-soft);
}

.master-note {
  margin-top: 1.5rem;
  padding: 1rem 1.25rem;
  border-left: 2px solid var(--gold);
  background: var(--gold-wash);
  border-radius: 0 10px 10px 0;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

/* A chart can throw a master number on both the Driver and the Conductor. Two
   notes running together read as one group rather than two separate callouts. */
.master-note + .master-note {
  margin-top: 0.75rem;
}

/* ---------- Report sections ---------- */

.report-section {
  margin-top: 3.25rem;
  padding-top: 2.25rem;
  border-top: 1px solid var(--line-soft);
}

.section-title {
  font-size: 1.25rem;
  color: var(--gold-bright);
  margin-bottom: 0.35rem;
  text-shadow: var(--text-scrim);
}

.section-note {
  font-size: 0.85rem;
  color: var(--ink-muted);
  text-shadow: var(--text-scrim);
  margin-bottom: 1.5rem;
  max-width: 62ch;
}

.section-title + .bullets,
.section-title + .trait-list,
.section-title + .plane-grid,
.section-title + .remedy-grid,
.section-title + .prospect-grid,
.section-title + .reading-card,
.section-title + .loshu-layout,
.section-title + .table-scroll { margin-top: 1.5rem; }

.empty-note { color: var(--ink-muted); font-size: 0.9rem; text-shadow: var(--text-scrim); }

.bullets {
  margin: 0;
  padding-left: 1.15rem;
  color: var(--ink-soft);
  font-size: 0.92rem;
}

.bullets li { margin-bottom: 0.5rem; }
.bullets strong { color: var(--gold-bright); font-weight: 500; }

.trait-list { list-style: none; margin: 0; padding: 0; }

.trait-list li {
  display: flex;
  gap: 0.9rem;
  align-items: baseline;
  padding: 0.85rem 0;
  border-bottom: 1px solid rgba(16, 25, 43, 0.08);
  color: var(--ink-soft);
  font-size: 0.92rem;
}

.trait-list li:last-child { border-bottom: none; }

.trait-num {
  flex: 0 0 auto;
  min-width: 2.6rem;
  padding: 0.15rem 0.5rem;
  text-align: center;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.95rem;
  color: var(--gold-bright);
  background: rgba(232, 195, 122, 0.3);
  border: 1px solid var(--line);
  border-radius: 7px;
}

.trait-num.absent {
  color: #8c2b27;
  background: rgba(226, 114, 110, 0.16);
  border-color: rgba(163, 58, 54, 0.35);
}

/* One left edge down the whole list. The number column is measured once for the
   list rather than row by row, so a wide chip — "111111" in Repeat Numbers — no
   longer pushes its own paragraph right while the rows above and below start
   further left. Subgrid is what lets each row borrow the list's columns; where
   it is missing the flex rules above still stand. */
@supports (grid-template-columns: subgrid) {
  .trait-list {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
  }

  .trait-list li {
    display: grid;
    grid-column: 1 / -1;
    grid-template-columns: subgrid;
  }
}

/* ---------- Driver-Conductor reading ---------- */

.reading-card {
  padding: 1.5rem 1.6rem;
  background: linear-gradient(150deg, rgba(232, 195, 122, 0.24), rgba(79, 134, 232, 0.12));
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink-soft);
}

.reading-head {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.6rem 1rem;
  margin-bottom: 0.9rem;
}

.reading-head .combo {
  font-family: var(--font-display);
  font-size: 1.75rem;
  font-weight: 400;
  color: var(--gold-bright);
}

.stars {
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  font-size: 0.82rem;
  font-weight: 500;
  color: #2a1a05;
  background: linear-gradient(120deg, var(--gold-fill-bright), var(--gold-fill));
}

.stars-warn {
  color: #8c2b27;
  background: rgba(226, 114, 110, 0.2);
  border: 1px solid rgba(163, 58, 54, 0.4);
}

/* The rating as five stars: a row of outlines with the solid row laid over it
   and clipped to the rating's share of the width, so 3.5 shows three and a half.
   Both rows are set in the same glyph advance, which is what keeps them in
   register; letter-spacing is applied to both for the same reason. */
.stars {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
}

.star-row {
  position: relative;
  display: inline-block;
  font-size: 0.95rem;
  line-height: 1;
  letter-spacing: 0.08em;
  color: rgba(42, 26, 5, 0.45);
  white-space: nowrap;
}

.star-fill {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  white-space: nowrap;
  color: #2a1a05;
}

.star-figure {
  font-variant-numeric: tabular-nums;
}

/* ---------- Lo Shu grid ---------- */

.loshu-layout {
  width: min(100%, 500px);
  margin: 0 auto;
}

.axis-row {
  display: grid;
  grid-template-columns: 5.5rem repeat(3, minmax(0, 1fr)) 5.5rem;
  gap: 10px;
  margin-bottom: 0.5rem;
}

.axis-label {
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
  text-align: center;
}

.grid {
  display: grid;
  grid-template-columns: 5.5rem minmax(0, 1fr) 5.5rem;
  gap: 10px;
  align-items: stretch;
}

/* The nine cells form their own square block: the Raj Yoga arrows are laid over
   this box, so nothing but cells and gaps may sit inside it. Its 1fr column in
   .grid is exactly as wide as the three column labels plus their two gaps in
   .axis-row, which is what keeps the labels over their columns. */
.loshu-cells {
  position: relative;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.row-labels {
  display: grid;
  grid-template-rows: repeat(3, minmax(0, 1fr));
  gap: 10px;
  align-items: center;
}

.row-label { text-align: left; }

/* ---------- Raj Yoga arrows ---------- */

/* The overlay is square, as the block of cells is, so the viewBox maps cell for
   cell onto it. It never takes a pointer: the cells below keep their hover. */
.yoga-arrows {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
  overflow: visible;
  z-index: 2;
}

/* An arrow runs over the cells it crosses, but never over what they say: the
   cell backgrounds stay under the overlay while the numbers on them are lifted
   above it, so the centre 5 both diagonals pass through stays on top.
   Being on top is not enough on its own — a gold arrow under a gold digit is
   gold on gold — so the digits carry a one-pixel white outline as well. This is
   the one place --text-scrim was retired from that still needs it: the ground
   under these glyphs is an arrow, not the page. */
.cell .position,
.cell .digits {
  position: relative;
  z-index: 3;
  text-shadow:
    1px 0 0 #fff, -1px 0 0 #fff, 0 1px 0 #fff, 0 -1px 0 #fff,
    1px 1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, -1px -1px 0 #fff;
}

/* Both diagonals are drawn in the same gold — their opposite directions are what
   tell them apart, and the report is gold throughout. The arrow itself is
   struck in metal: the script hands each one a gradient of that gold as its ink
   (see YOGA_GOLD_STOPS), so the flat colour here is what remains if the paint
   server ever fails to resolve. */
.yoga-arrow { --yoga-ink: #8a6a1f; }

.yoga-arrow line { fill: none; }
.yoga-arrow polygon { stroke-linejoin: round; }

/* A thin white outline, laid under the arrow: it separates the two diagonals
   where they cross at the centre cell — which direction alone could not do once
   both are the same colour — and lifts each off the gold cell fills. The line
   and the arrowhead carry it differently: a line's underlay is a wider line, so
   it is the ink width plus the border twice over, while a polygon's stroke is
   centred on its edge and only half of it falls outside. Both come to the same
   0.6 of white. */
.yoga-arrow .halo {
  stroke: #fff;
  stroke-linecap: round;
  stroke-linejoin: round;
  fill: #fff;
}

.yoga-arrow line.halo { stroke-width: 3.4; }
.yoga-arrow polygon.halo { stroke-width: 1.2; }

.yoga-arrow line.ink {
  stroke: var(--yoga-ink);
  stroke-width: 2.2;
  stroke-linecap: round;
}

.yoga-arrow polygon.ink {
  fill: var(--yoga-ink);
  stroke: var(--yoga-ink);
  stroke-width: 0.6;
}

.yoga-legend {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.4rem 1.5rem;
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  font-size: 0.82rem;
  color: var(--ink-soft);
}

.yoga-legend li { display: flex; align-items: baseline; gap: 0.45rem; }

/* The legend's arrow is the same piece of gold as the one on the grid, so it
   takes the same sheen — clipped to the glyph, over the flat gold that shows
   through wherever background-clip: text is not honoured. */
.yoga-legend .yoga-key {
  color: #8a6a1f;
  background-image: linear-gradient(100deg,
    #c9992e 0%, #e6c86e 10%, #f6e3a6 18%, #d3a838 28%, #c08f22 40%,
    #e2bf60 50%, #f7e6b0 58%, #cfa236 70%, #c9982e 80%, #f0d78d 88%, #d3a63c 100%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

.yoga-key { font-size: 1.05rem; line-height: 1; font-weight: 700; }

.yoga-note {
  margin-top: 1rem;
  text-align: center;
  font-size: 0.82rem;
  color: var(--ink-muted);
}

.cell {
  aspect-ratio: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.2rem;
  padding: 0.5rem;
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  background: #f4f1e8;
  transition: transform 0.2s ease, box-shadow 0.25s ease;
}

.cell:hover { transform: scale(1.04); }

.cell .position {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--ink-soft);
  opacity: 0.75;
  letter-spacing: 0.1em;
}

.cell .digits {
  font-family: var(--font-display);
  font-size: clamp(1.1rem, 3.8vw, 1.55rem);
  font-weight: 400;
  letter-spacing: 0.04em;
  line-height: 1.15;
  color: var(--ink-muted);
  word-break: break-all;
  text-align: center;
}

.cell.filled {
  border-color: rgba(138, 106, 31, 0.5);
  background: linear-gradient(160deg, rgba(232, 195, 122, 0.55), rgba(232, 195, 122, 0.26));
  box-shadow: none;
}

.cell.filled .digits { color: var(--gold-bright); }

/* ---------- Planes ---------- */

.plane-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(250px, 100%), 1fr));
  gap: 1rem;
}

.plane-card {
  padding: 1.25rem 1.35rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-size: 0.88rem;
}

.plane-name {
  font-family: var(--font-display);
  color: var(--gold-bright);
  font-size: 1rem;
  margin-bottom: 0.5rem;
}

/* A diagonal card is one of the two Raj Yogas — the rarest thing a grid can
   form, and the card says so before a word of it is read: leaf-gold edges
   rather than the plain rule every other card carries, a warm ground, and a
   slow specular sweep across it, the glint off a cut stone. The border is a
   gradient, which a border-color cannot be, so it is painted as a second
   background layer under a padding-box ground — hence the transparent border
   holding the space for it. */
.plane-card.raj {
  --yoga-ink: #8a6a1f;
  /* Two pixels up on every size in this card — the reading, the name, the
     numbers and the capsule below — so the rarest thing in the report sits a
     shade larger than the planes beside it. 0.88rem + 2px. */
  font-size: 1rem;
  position: relative;
  overflow: hidden;
  border: 1.5px solid transparent;
  border-left-width: 3px;
  background:
    /* The stone's own highlight, off the top-left corner. */
    radial-gradient(120% 90% at 12% 0%, rgba(255, 255, 255, 0.95), rgba(255, 255, 255, 0) 55%) padding-box,
    linear-gradient(145deg, #fffdf8 0%, #fdf4e0 55%, #fffaf0 100%) padding-box,
    linear-gradient(120deg,
      #c9992e 0%, #f0d78d 12%, #f7e6b0 22%, #cfa236 38%, #c08f22 50%,
      #e2bf60 62%, #f6e3a6 74%, #d3a838 86%, #c9992e 100%) border-box;
  box-shadow: 0 6px 22px rgba(138, 106, 31, 0.16);
}

/* The sweep: a narrow band of light crossing the card, then a long wait before
   it comes round again. Anything faster reads as a banner ad rather than as a
   sheen. Reduced motion stops it dead — the gold ground and edges carry the
   card on their own. */
.plane-card.raj::after {
  content: "";
  position: absolute;
  top: -60%;
  bottom: -60%;
  left: 0;
  width: 22%;
  background: linear-gradient(90deg,
    rgba(255, 255, 255, 0) 0%, rgba(255, 252, 235, 0.85) 45%,
    rgba(255, 255, 255, 0.95) 55%, rgba(255, 255, 255, 0) 100%);
  transform: translateX(-200%) rotate(18deg);
  animation: raj-shine 7s ease-in-out infinite;
  pointer-events: none;
}

@keyframes raj-shine {
  0% { transform: translateX(-200%) rotate(18deg); opacity: 0; }
  8% { opacity: 1; }
  38% { opacity: 1; }
  45%, 100% { transform: translateX(560%) rotate(18deg); opacity: 0; }
}

/* The card's own text sits above the sweep rather than under it. */
.plane-card.raj > * { position: relative; z-index: 1; }

/* The lettering is struck in the same metal as the edges: a dark gold worked
   light and back again across the glyphs, drifting so the metal catches the
   light as the sweep passes beneath it. Every stop in the gradient clears
   4.5:1 on this ground — the shine is in the banding, not in going pale — and
   the flat colour beneath shows through wherever background-clip: text is not
   honoured. */
.plane-card.raj .plane-name {
  font-size: 1.125rem; /* 1rem + 2px */
  color: #6b4f12;
  background-image: linear-gradient(100deg,
    #4a3306 0%, #7a5a11 14%, #8a6a1f 22%, #5a4008 34%, #4f3807 44%,
    #7d5d13 54%, #8a6a1f 62%, #604510 74%, #4a3306 84%, #85651a 92%, #6b4f12 100%);
  background-size: 220% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  animation: raj-metal 7s ease-in-out infinite;
}

/* The numbers beside the name, and the reading below it: dark gold flat, since
   a gradient clipped to text this small reads as a smudge rather than a sheen.
   The tag is not one of them — it carries its own gold ground, and is put back
   on its own ink below. */
.plane-card.raj .plane-name > span:not(.raj-tag) { font-size: 0.875rem; color: #6b4f12; } /* 0.75rem + 2px */
.plane-card.raj p { color: #6b4f12; }

@keyframes raj-metal {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

/* The capsule heads the card, so its gap is on the right — the numbers follow it. */
.raj-tag {
  display: inline-block;
  margin-right: 0.5rem;
  padding: 0.1rem 0.5rem;
  border: 1px solid var(--yoga-ink);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--yoga-ink);
  vertical-align: middle;
}

/* On the Raj Yoga card the tag is struck in the leaf itself: dark lettering on
   gold, which is the one place on a white page the bright gold can be used as a
   fill rather than as text. */
.plane-card.raj .raj-tag {
  font-size: 0.785rem; /* 0.66rem + 2px */
  border-color: transparent;
  color: #3d2c05;
  /* The name clips its gradient to every glyph inside it, this tag's included,
     and the tag's own gold pill then paints over that — which left the
     lettering blank. Filling the glyphs here puts it back. */
  -webkit-text-fill-color: #3d2c05;
  background-image: linear-gradient(100deg, #e2bf60, #f7e6b0 35%, #d9ad42 65%, #efd68c);
  box-shadow: inset 0 0 0 1px rgba(138, 106, 31, 0.45);
}

.plane-name > span:not(.raj-tag) {
  font-family: var(--font-body);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  color: var(--ink-muted);
  margin-left: 0.4rem;
}

.leaning {
  margin-top: 1.25rem;
  font-size: 0.92rem;
  color: var(--gold-bright);
}

.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  margin-top: 1.5rem;
}

.chip {
  padding: 0.45rem 1rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--gold-wash);
  color: var(--ink-soft);
  font-size: 0.86rem;
}

/* ---------- Name & number correction ---------- */

.correction-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 1.15rem;
}

/* On its own page (solution.html) the tool is headed like the report, centred,
   so the note that leads into the two panels is centred under it too. */
.correction-tool .report-head { margin-bottom: 1.5rem; }
.correction-tool .section-note { margin-left: auto; margin-right: auto; text-align: center; }

.correction-card { display: flex; flex-direction: column; }

.correction-label {
  display: block;
  font-size: 0.78rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--ink-muted);
  margin-bottom: 0.5rem;
}

.correction-input {
  width: 100%;
  padding: 0.7rem 0.9rem;
  margin-bottom: 1rem;
  border: 1px solid rgba(16, 25, 43, 0.22);
  border-radius: 10px;
  background: #fff;
  color: var(--ink);
  font-family: inherit;
  font-size: 0.95rem;
  letter-spacing: 0.02em;
}

.correction-input:focus {
  outline: none;
  border-color: var(--gold);
  box-shadow: 0 0 0 3px rgba(154, 116, 32, 0.16);
}

.letter-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-bottom: 0.85rem;
}

.letter-chip {
  display: inline-flex;
  align-items: baseline;
  gap: 0.25rem;
  padding: 0.2rem 0.5rem;
  border: 1px solid var(--line-soft);
  border-radius: 8px;
  font-size: 0.8rem;
  color: var(--ink-soft);
}

.letter-chip b { color: var(--gold); font-weight: 500; }

.correction-total {
  font-size: 0.86rem;
  color: var(--ink-muted);
  margin-bottom: 0.85rem !important;
}

/* Sized to its label rather than the card, so it reads as the panel's own
   action and not as another full-width field below the input. */
.correction-submit {
  align-self: flex-start;
  margin-bottom: 1rem;
}

.correction-error {
  font-size: 0.82rem;
  color: var(--danger);
  margin-bottom: 0.7rem !important;
}

.verdict { font-size: 0.88rem; margin-bottom: 0.75rem !important; }
.verdict.is-good { color: var(--success); }
.verdict.is-off { color: var(--gold-bright); }
/* A mobile number is suitable or it is not — nothing for the reader to correct
   in the way a name's spelling can be, so this one states it in red rather than
   in the gold the name panel uses to introduce its suggestions. */
.verdict.is-bad { color: var(--danger); }

.check-list { list-style: none; margin: 0 0 1rem; padding: 0; font-size: 0.88rem; }

.check-list li {
  display: flex;
  gap: 0.6rem;
  align-items: baseline;
  padding: 0.35rem 0;
  color: var(--ink-soft);
}

.check-list li.pass > span:first-child { color: var(--success); }
.check-list li.fail > span:first-child { color: var(--danger); }

.variant-list { list-style: none; margin: 0; padding: 0; }

.variant-list li {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.5rem;
  padding: 0.3rem 0;
}

.variant {
  padding: 0.3rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--gold-wash);
  color: var(--gold-bright);
  font-family: inherit;
  font-size: 0.86rem;
  letter-spacing: 0.02em;
  cursor: pointer;
  transition: background 0.18s ease, border-color 0.18s ease;
}

.variant:hover, .variant:focus-visible {
  background: rgba(232, 195, 122, 0.38);
  border-color: var(--gold);
}

.variant-note { font-size: 0.78rem; color: var(--ink-muted); }

/* ---------- Prospects ---------- */

.prospect-grid,
.remedy-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  gap: 1.15rem;
}

.prospect-card,
.remedy-card {
  padding: 1.4rem 1.5rem;
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--ink-soft);
  font-size: 0.9rem;
}

.prospect-card h4,
.remedy-card h4 {
  font-family: var(--font-display);
  font-size: 0.95rem;
  font-weight: 400;
  color: var(--gold-bright);
  margin: 0 0 0.7rem;
}

.remedy-card p { margin-bottom: 0.7rem; }
.remedy-card p:last-child { margin-bottom: 0; }
.remedy-card strong { color: var(--gold-bright); font-weight: 500; }

/* Share market card: the verdict leads, the numbers it rests on close. */
.prospect-verdict {
  color: var(--gold-bright);
  margin-bottom: 0.45rem !important;
}

.prospect-basis {
  margin-top: 0.7rem;
  font-size: 0.84rem;
  color: var(--ink-muted);
}

.prospect-basis strong { color: var(--gold-bright); font-weight: 500; }

.lucky-line { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 0.9rem !important; }

.lucky-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  font-family: var(--font-display);
  font-weight: 400;
  color: #2a1a05;
  background: linear-gradient(140deg, var(--gold-fill-bright), var(--gold-fill));
}

.swatch {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 50%;
  margin-right: 0.35rem;
  vertical-align: -1px;
  border: 1px solid rgba(16, 25, 43, 0.25);
}

.swatch[data-color="red"] { background: #e2453d; }
.swatch[data-color="white"] { background: #f4f1ea; }
.swatch[data-color="yellow"] { background: #f0c93f; }
.swatch[data-color="blue"] { background: #3f7ce0; }
.swatch[data-color="green"] { background: #3fb87a; }
.swatch[data-color="grey"] { background: #98a3b4; }
.swatch[data-color="black"] { background: #141b2b; }
.swatch[data-color="orange"] { background: #e8843d; }

/* ---------- Forecast table ---------- */

.table-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}

.forecast {
  width: 100%;
  min-width: 560px;
  border-collapse: collapse;
  font-size: 0.88rem;
  color: var(--ink-soft);
}

.forecast th {
  text-align: left;
  padding: 0.9rem 1rem;
  font-family: var(--font-body);
  font-size: 0.7rem;
  font-weight: 500;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.forecast td {
  padding: 0.9rem 1rem;
  border-bottom: 1px solid rgba(16, 25, 43, 0.08);
  vertical-align: top;
}

.forecast:has(thead th:nth-child(6)) { min-width: 760px; }

.forecast tr:last-child td { border-bottom: none; }
.forecast tbody tr:hover { background: rgba(16, 25, 43, 0.03); }

.forecast td strong { color: var(--ink); font-weight: 500; }

.py-chip {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 1.9rem;
  height: 1.9rem;
  border-radius: 8px;
  font-family: var(--font-display);
  font-weight: 400;
  color: var(--gold-bright);
  background: rgba(232, 195, 122, 0.3);
  border: 1px solid var(--line);
}

.py-detail {
  display: block;
  margin-top: 0.3rem;
  font-size: 0.76rem;
  color: var(--ink-muted);
  max-width: 46ch;
}

.forecast .luck { white-space: nowrap; color: var(--gold-bright); font-weight: 500; }

.anti-year { background: rgba(226, 114, 110, 0.12); }

.anti-tag {
  display: inline-block;
  padding: 0.1rem 0.5rem;
  margin-left: 0.35rem;
  border-radius: 999px;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: #8c2b27;
  background: rgba(226, 114, 110, 0.2);
  border: 1px solid rgba(163, 58, 54, 0.4);
}

/* ---------- Info section ---------- */

.info-section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 4rem 1.5rem 5rem;
  border-top: 1px solid var(--line-soft);
  scroll-margin-top: 90px;
}

.info-section > h2 {
  text-align: center;
  font-size: clamp(1.5rem, 3vw, 2rem);
  margin-bottom: 2.75rem;
  text-shadow: var(--text-scrim);
}

.info-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(230px, 100%), 1fr));
  gap: 1.25rem;
}

.info-card {
  padding: 1.75rem 1.5rem;
  scroll-margin-top: 90px;
  transition: transform 0.25s ease, border-color 0.25s ease;
}

.info-card:hover {
  transform: translateY(-4px);
  border-color: rgba(138, 106, 31, 0.4);
}

.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  margin-bottom: 1rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--gold);
  background: var(--gold-wash);
}

.info-icon svg { width: 22px; height: 22px; }

.info-card h3 {
  font-size: 1.05rem;
  color: var(--gold-bright);
  margin-bottom: 0.6rem;
}

.info-card p {
  font-size: 0.9rem;
  color: var(--ink-soft);
}

/* ---------- What's inside ---------- */

.inside-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(240px, 100%), 1fr));
  gap: 1.75rem 2rem;
}

.inside-card {
  padding: 0.9rem 1rem 1rem 1.25rem;
  border-left: 1px solid var(--line);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: linear-gradient(90deg, var(--panel), rgba(251, 248, 241, 0));
  text-shadow: var(--text-scrim);
}

.inside-num {
  display: block;
  font-family: var(--font-body);
  font-weight: 700;
  font-size: 0.8rem;
  letter-spacing: 0.16em;
  color: var(--gold);
  margin-bottom: 0.55rem;
}

.inside-card h3 {
  font-size: 1rem;
  margin-bottom: 0.45rem;
}

.inside-card p {
  font-size: 0.87rem;
  color: var(--ink-soft);
}

.label-hint {
  text-transform: none;
  letter-spacing: 0;
  color: #8a95a8;
}

/* ---------- Footer ---------- */

/* Fixed 80px bar: the rows are centred in it rather than the height being the
   sum of paddings, so the bar keeps its size if the wordmark or copy changes. */
.site-footer {
  min-height: 80px;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  text-align: center;
  padding: 0.5rem 1.5rem;
  border-top: 1px solid var(--line-soft);
  background: var(--panel);
  font-size: 0.85rem;
  color: var(--ink-muted);
}

/* Mark and wordmark sit on one line, the way they do in the header — stacking
   them is what made the bar tall. */
.footer-brand {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
}

.footer-mark {
  width: 34px;
  height: 34px;
  display: block;
}

/* The wordmark is set in HTML rather than taken from logo.svg: an SVG loaded
   through <img> can't reach the page's webfonts, so Cinzel would fall back. */
.footer-name {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: 0.98rem;
  letter-spacing: 0.07em;
  background: var(--grad-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.copyright { font-size: 0.78rem; }

/* ---------- Responsive ---------- */

/* Below this width the five tabs no longer fit beside the wordmark, so the bar
   collapses to the hamburger and the tabs move into a drop-down panel. The panel
   is positioned out of flow, which keeps the bar one row tall — and --header-h,
   the space body reserves for it, correct whether the menu is open or shut. */
@media (max-width: 820px) {
  .nav-wrap {
    flex-wrap: nowrap;
    gap: 1rem;
    padding: 0.7rem 1.15rem;
  }

  /* The hamburger takes the far edge and the switcher sits inside it; the
     tabs are out of flow here, so the switcher is what pushes both right. */
  .nav-toggle { display: block; order: 2; }

  .lang-switch { margin-left: auto; }

  .site-nav {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    padding: 0.3rem 1.15rem 0.7rem;
    font-size: 0.95rem;
    /* Opaque, not the header's translucent wash: the panel sits over body copy,
       and at 0.97 the headline behind it still read through the rows. */
    background: var(--paper);
    border-bottom: 1px solid var(--line-soft);
    box-shadow: 0 14px 26px rgba(16, 25, 43, 0.1);
    /* A short screen in landscape can be shorter than the open panel. dvh tracks
       the browser chrome as it collapses; vh is the fallback where it doesn't. */
    max-height: calc(100vh - var(--header-h));
    max-height: calc(100dvh - var(--header-h));
    overflow-y: auto;
  }

  .site-nav.is-open { display: flex; }

  .site-nav a {
    display: flex;
    align-items: center;
    min-height: 46px;
    padding: 0 0.15rem;
    border-bottom: 1px solid var(--line-soft);
  }

  .site-nav a:last-child { border-bottom: none; }

  /* The sliding underline is a pointer affordance and reads as a stray rule on a
     stacked row; the selected row is marked by its own ground instead. */
  .site-nav a::after { display: none; }

  .site-nav a[aria-current] {
    padding-left: 0.75rem;
    background: var(--gold-wash);
    box-shadow: inset 3px 0 0 var(--gold);
  }
}

@media (max-width: 760px) {
  .number-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .number-card .value { font-size: 2.6rem; }

  /* Edge shadows that appear only while a table still has width to scroll — the
     one cue that the columns continue past the screen. The two panel-coloured
     layers scroll with the content and mask the shadows at each end. */
  .table-scroll {
    background-image:
      linear-gradient(to right, var(--panel) 40%, rgba(251, 248, 241, 0)),
      linear-gradient(to left, var(--panel) 40%, rgba(251, 248, 241, 0)),
      radial-gradient(farthest-side at 0 50%, rgba(16, 25, 43, 0.14), rgba(16, 25, 43, 0)),
      radial-gradient(farthest-side at 100% 50%, rgba(16, 25, 43, 0.14), rgba(16, 25, 43, 0));
    background-position: 0 0, 100% 0, 0 0, 100% 0;
    background-repeat: no-repeat;
    background-size: 34px 100%, 34px 100%, 13px 100%, 13px 100%;
    background-attachment: local, local, scroll, scroll;
  }
}

@media (max-width: 600px) {
  .hero { padding: 3.25rem 1.25rem 2.75rem; }
  .form-card { padding: 1.75rem 1.35rem; }
  .calculator-section { padding-left: 1.15rem; padding-right: 1.15rem; }
  .info-section { padding: 3rem 1.15rem 3.5rem; }
  .info-section > h2 { margin-bottom: 2rem; }
  .results-section { margin-top: 2.5rem; scroll-margin-top: 80px; }
  .report-section { margin-top: 2.5rem; padding-top: 1.75rem; }
  .info-card { padding: 1.5rem 1.25rem; }
  .inside-grid { gap: 1.25rem 1.5rem; }
  .reading-card,
  .prospect-card,
  .remedy-card,
  .plane-card { padding: 1.15rem 1.2rem; }
  .chips { gap: 0.5rem; }

  /* A phone has room for one label column, not two. Drop the empty left one and
     keep the row names — Mental, Emotional and Practical read the grid across,
     and without them the three plane rows are unlabelled. Both grids keep the
     same track sizes, which is what holds THOUGHT / WILL / ACTION centred over
     the cells they head. */
  .axis-row {
    grid-template-columns: repeat(3, minmax(0, 1fr)) 4.7rem;
    gap: 8px;
  }
  .grid { grid-template-columns: minmax(0, 1fr) 4.7rem; gap: 8px; }
  .loshu-cells, .row-labels { gap: 8px; }
  .grid .axis-spacer,
  .axis-row .axis-spacer:first-child { display: none; }
  .axis-label { font-size: 0.6rem; letter-spacing: 0.06em; }
  .row-label { line-height: 1.25; }

  .trait-list li { flex-direction: column; gap: 0.45rem; }
  .trait-num { align-self: flex-start; }
  /* Stacked, the number sits above its own paragraph: one column for the list
     and one for each row, with the chip holding its own width rather than
     stretching the length of the row. */
  .trait-list,
  .trait-list li { grid-template-columns: minmax(0, 1fr); }
  .trait-list li { justify-items: start; }

  .report-actions .btn,
  .vault-toolbar .btn { flex: 1 1 auto; justify-content: center; }

  .table-scroll { border-radius: 12px; }
  .forecast { font-size: 0.84rem; }
  .forecast th, .forecast td { padding: 0.7rem 0.75rem; }

  .dialog-body { padding: 1.35rem 1.15rem; }
  .dialog-actions { flex-direction: column-reverse; }
  .dialog-actions .btn { width: 100%; text-align: center; }
}

/* Small phones — 360px and under, where the wordmark and the two-up number
   cards are the first things to run out of room. */
@media (max-width: 400px) {
  .nav-wrap { gap: 0.6rem; padding: 0.6rem 1rem; }
  .brand-mark { width: 32px; height: 32px; }
  .brand-name { font-size: 0.92rem; letter-spacing: 0.02em; }
  .hero { padding: 2.75rem 1rem 2.5rem; }
  .eyebrow { letter-spacing: 0.2em; }
  .calculator-section, .info-section { padding-left: 1rem; padding-right: 1rem; }
  .form-card { padding: 1.5rem 1.1rem; }
  .number-card { padding: 1.35rem 0.9rem; }
  .number-card .value { font-size: 2.2rem; }
  .number-card .label { letter-spacing: 0.12em; }
  .cell { padding: 0.35rem; border-radius: 10px; }
  .cell .position { font-size: 0.66rem; letter-spacing: 0.04em; }
  .btn { padding: 0.8rem 1.5rem; }
}

/* Touch ergonomics, keyed to the pointer rather than the viewport. A phone in
   landscape is 700-900px wide — wide enough to miss every width query above —
   but it is still a thumb on a screen that zooms on a small input. */
@media (pointer: coarse) {
  /* Anything under 16px makes iOS zoom the page on focus and leaves it zoomed. */
  .correction-input,
  .field input,
  .field select { font-size: 1rem; }

  /* Comfortable thumb targets for the report tools and the guide's contents. */
  .btn-ghost,
  .variant { min-height: 44px; }

  .variant { display: inline-flex; align-items: center; }
  .link-btn { min-height: 40px; }
  .guide-toc a { display: inline-block; padding: 0.35rem 0; }

  /* iOS Safari sizes a date input from its own native content and ignores
     width: 100%, so on a phone this one field runs past the card's right edge
     while Name and Gender stay inside it. Dropping the native appearance makes
     it obey the box, and line-height: normal keeps the field from inheriting the
     body's taller line box once the widget's own sizing is gone. */
  .field input[type="date"] {
    -webkit-appearance: none;
    appearance: none;
    min-width: 0;
    max-width: 100%;
    line-height: normal;
  }

  /* iOS centres the value once the native appearance is gone, and gives an
     empty date no line box at all — which collapses the field to its padding
     and leaves it visibly shorter than Name and Gender until a date is picked. */
  .field input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    margin: 0;
    min-height: 1.25em;
  }
}

/* The lift-on-hover states are pointer affordances: on a touch screen they fire
   on tap and leave the card stuck in its raised state. */
@media (hover: none) {
  .number-card:hover,
  .info-card:hover,
  .cell:hover,
  .btn-primary:hover {
    transform: none;
    box-shadow: var(--shadow);
  }

  .brand:hover .brand-mark { transform: none; }
  .site-nav a:hover::after { width: 0; }
  .site-nav a[aria-current]::after { width: 100%; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001s !important;
    transition-duration: 0.001s !important;
  }

  /* A repeating animation cut to a millisecond does not stop, it flickers — so
     the Raj Yoga sweep is taken off outright rather than sped up. The card
     keeps its gold edges and ground, which is most of what it was saying. */
  .plane-card.raj::after {
    animation: none !important;
    opacity: 0 !important;
  }

  /* Same for the lettering's drift: the gradient stays, it simply stops moving. */
  .plane-card.raj .plane-name { animation: none !important; }
}

/* ---------- Ghost / danger buttons ---------- */

.btn-ghost {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  background: #fff;
  border: 1px solid var(--line);
  color: var(--ink);
  padding: 0.6rem 1.1rem;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}

.btn-ghost:hover:not(:disabled) {
  border-color: var(--gold);
  color: var(--gold-bright);
  background: rgba(232, 195, 122, 0.2);
}

.btn-ghost:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.btn-danger:hover:not(:disabled) {
  border-color: rgba(179, 38, 30, 0.5);
  color: var(--danger);
  background: rgba(226, 69, 61, 0.1);
}

.btn-primary.btn-danger {
  background: linear-gradient(135deg, #d8433a, #a92d26);
  border-color: transparent;
  color: #fff;
}

/* ---------- Report action bar ---------- */

.report-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  margin: 0 0 2rem;
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--line-soft);
}

.action-note {
  flex-basis: 100%;
  text-align: center;
  min-height: 1.2em;
  font-size: 0.82rem;
  color: var(--gold);
}

.action-note.is-error { color: var(--danger); }

/* ---------- Saved records ---------- */

.vault-intro {
  max-width: 720px;
  margin: 0 auto 2rem;
  text-align: center;
}

.vault-intro strong { color: var(--gold-bright); font-weight: 500; }

.vault-section > h2 { margin-bottom: 1.25rem; }

.vault-card { padding: 1.75rem; }

/* The card already supplies the panel, so the table shouldn't draw a second one. */
.vault-card .table-scroll {
  background: transparent;
  border: none;
  border-radius: 0;
}

.vault-status {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1.25rem;
}

.vault-badge {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.3rem 0.8rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-soft);
  white-space: nowrap;
}

.vault-badge.is-ok { border-color: rgba(26, 127, 75, 0.5); color: var(--success); }
.vault-badge.is-warn { border-color: rgba(154, 116, 32, 0.5); color: var(--gold); }

.vault-detail { font-size: 0.82rem; color: var(--ink-muted); }

.vault-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  padding-bottom: 1.25rem;
  border-bottom: 1px solid var(--line-soft);
}

.vault-message {
  min-height: 1.2em;
  margin: 0.9rem 0;
  font-size: 0.83rem;
  color: var(--gold);
}

.vault-message.is-error { color: var(--danger); }

.records { width: 100%; border-collapse: collapse; font-size: 0.86rem; }

.records th {
  text-align: left;
  padding: 0.6rem 0.7rem;
  font-family: var(--font-body);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-muted);
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.records td {
  padding: 0.65rem 0.7rem;
  border-bottom: 1px solid var(--line-soft);
  color: var(--ink-soft);
  white-space: nowrap;
}

.records tr:last-child td { border-bottom: none; }
.records tbody tr:hover td { background: rgba(232, 195, 122, 0.16); }
.records .cell-name { color: var(--ink); white-space: normal; min-width: 10rem; }
.records .muted { color: var(--ink-muted); font-style: italic; white-space: normal; }
.records .row-actions { text-align: right; }

.link-btn {
  background: none;
  border: none;
  padding: 0.15rem 0.35rem;
  font: inherit;
  font-size: 0.8rem;
  color: var(--gold);
  cursor: pointer;
  border-radius: 6px;
}

.link-btn:hover { color: var(--gold-bright); background: rgba(232, 195, 122, 0.25); }
.link-btn.danger { color: var(--ink-muted); }
.link-btn.danger:hover { color: var(--danger); background: rgba(226, 69, 61, 0.12); }

.vault-empty { margin-top: 0.5rem; }

/* ---------- Dialogs ---------- */

.app-dialog {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel-solid);
  color: var(--ink);
  padding: 0;
  max-width: 440px;
  width: calc(100% - 2.5rem);
  box-shadow: var(--shadow);
}

.app-dialog::backdrop {
  background: rgba(16, 25, 43, 0.45);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}

.dialog-body { padding: 1.75rem; }

.dialog-body h3 {
  font-size: 1.15rem;
  color: var(--gold);
  margin-bottom: 0.6rem;
}

.dialog-note {
  font-size: 0.85rem;
  color: var(--ink-soft);
  margin-bottom: 1.25rem;
}

.dialog-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  margin-top: 1.5rem;
}

.dialog-actions .btn { padding: 0.6rem 1.2rem; font-size: 0.85rem; }

/* ---------- Report sheet shell ---------- */

/* The table shell around the report is print furniture: on screen the report is
   one continuous scroll with no page edges to dress. The shell is flattened back
   to plain blocks so it lays out as the bare sections did, and the branded
   masthead and footer rows stay out of the way until there are sheets to head. */
.report-sheet,
.report-sheet > tbody,
.report-sheet > tbody > tr,
.report-sheet > tbody > tr > td {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
}

.report-sheet > thead,
.report-sheet > tfoot { display: none; }

.report-foot { display: none; }

/* ---------- Print: keep the report, drop the rest ---------- */

@media print {
  .site-header,
  .site-footer,
  .hero,
  .info-section,
  .form-card,
  .no-print { display: none !important; }

  html, body { background: #fff !important; color: #10192b !important; }
  body { padding-top: 0 !important; }

  /* Without this the browser drops every background fill unless the user ticks
     "Background graphics", which is what left the Lo Shu grid flat in the PDF. */
  * { -webkit-print-color-adjust: exact !important; print-color-adjust: exact !important; }

  /* The on-screen scrims exist to lift light text off the background artwork.
     Printed on white they only smear the glyphs, and the grounds behind the
     bare-background blocks have nothing left to sit on. */
  * { text-shadow: none !important; }

  /* Except the grid digits: on paper too they sit over the Raj Yoga arrows, and
     without the outline a gold digit is lost in a gold arrow. */
  .cell .position,
  .cell .digits {
    text-shadow:
      1px 0 0 #fff, -1px 0 0 #fff, 0 1px 0 #fff, 0 -1px 0 #fff,
      1px 1px 0 #fff, 1px -1px 0 #fff, -1px 1px 0 #fff, -1px -1px 0 #fff !important;
  }
  /* Text clipped to a background is the one thing print engines drop most
     readily, and it drops to nothing: the legend's arrow goes back to solid
     gold on paper rather than risk printing as a blank. */
  .yoga-legend .yoga-key {
    background-image: none !important;
    -webkit-text-fill-color: #8a6a1f !important;
  }

  .inside-card, .guide-section { background: none !important; }

  .calculator-section { padding: 0 !important; }

  /* The sheet's own margins. @page carries none — a zero page margin leaves the
     browser no margin box to print its title, URL and date in — so the report
     holds itself clear of the paper edge instead: the side rails below, the
     repeating masthead for the top band and the fixed address line for the
     bottom one. */
  :root {
    --sheet-margin-x: 15mm;
    --sheet-margin-y: 11mm;
  }

  /* Horizontal padding applies to every fragment of a block, so this one rule
     insets all the sheets. */
  .results-section:not(.hidden) {
    display: block !important;
    padding: 0 var(--sheet-margin-x) !important;
    /* The on-screen gap under the form would push the first sheet's content
       lower than every other sheet's. */
    margin-top: 0 !important;
  }

  /* A thead and a tfoot repeat on every sheet of a print run, which is what
     puts the mark on each page: the masthead rides the top of every sheet and
     the address line the bottom, with the content flowing between them. */
  .report-sheet { display: table; width: 100%; table-layout: fixed; }
  .report-sheet > thead { display: table-header-group; }
  .report-sheet > tfoot { display: table-footer-group; }
  .report-sheet > tbody { display: table-row-group; }
  .report-sheet tr { display: table-row; }
  .report-sheet td { display: table-cell; padding: 0; vertical-align: top; }

  .sheet-head {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: var(--sheet-margin-y) 0 3mm;
    margin-bottom: 6mm;
    border-bottom: 1px solid #ded7c7;
  }

  .sheet-logo { width: 6.6mm; height: 6.6mm; flex: 0 0 auto; }

  .sheet-brand {
    font-family: var(--font-display);
    font-size: 12pt;
    line-height: 1.1;
    letter-spacing: 0.06em;
    color: #8a6a1f !important;
  }

  /* The address line is fixed rather than flowed. A footer row would sit
     directly under the content on the last, part-filled sheet; fixed, it repeats
     on every page of the print run and stays on the paper's bottom edge. The
     tfoot row below reserves the band so no content runs underneath it. */
  body:has(.results-section:not(.hidden)) .report-foot {
    display: block;
    position: fixed;
    left: var(--sheet-margin-x);
    right: var(--sheet-margin-x);
    bottom: 0;
    padding: 3mm 0 var(--sheet-margin-y);
    border-top: 1px solid #ded7c7;
    text-align: center;
    background: #fff;
  }

  .sheet-foot-pad { height: calc(var(--sheet-margin-y) + 14mm); }

  .sheet-url {
    font-size: 8pt;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: #5c6a83 !important;
  }

  .card,
  .number-card,
  .reading-card,
  .plane-card,
  .prospect-card,
  .remedy-card {
    background: #fbf8f1 !important;
    border-color: #e3ddd0 !important;
    box-shadow: none !important;
  }

  /* Text clipped to a background prints as nothing often enough that the card's
     name goes back to solid dark gold on paper, the way the legend's arrow does. */
  .plane-card.raj .plane-name {
    background-image: none !important;
    -webkit-text-fill-color: #6b4f12 !important;
    color: #6b4f12 !important;
    animation: none !important;
  }

  .plane-card.raj .plane-name > span:not(.raj-tag),
  .plane-card.raj p { color: #6b4f12 !important; }

  /* A Raj Yoga still has to read as the rare one on paper, where the sweep
     means nothing and the gradient border is flattened along with every other
     card's: gold edges, and the tag in solid leaf. */
  .plane-card.raj {
    border-color: #8a6a1f !important;
    background: #fffaf0 !important;
  }

  .plane-card.raj::after { display: none !important; }

  .plane-card.raj .raj-tag {
    background: #e8c37a !important;
    border-color: #8a6a1f !important;
    color: #3d2c05 !important;
  }

  h1, h2, h3, h4,
  .results-title, .section-title, .number-card .value, .trait-num,
  .lucky-num, .py-chip, .reading-head .combo, strong {
    color: #8a6a1f !important;
  }

  /* .value paints its gold through background-clip:text. The rule above gives it
     an opaque print colour, but the gradient box stays behind the glyph and, with
     colour-adjust forced on, printed as a solid gold slab beside the number. */
  .number-card .value {
    background: none !important;
    -webkit-background-clip: border-box !important;
    background-clip: border-box !important;
  }

  p, td, th, li, .result-name, .section-note, .detail, .label, .py-detail, .axis-label {
    color: #3d4a63 !important;
  }

  /* The report tells the reader "gold cells are present; faded cells are missing",
     so the two states have to stay visually apart on paper as well. */
  .cell {
    background: #f4f1e8 !important;
    border-color: #ded7c7 !important;
    box-shadow: none !important;
  }

  .cell.filled {
    background: #f6e6bd !important;
    border-color: #c9a44c !important;
  }

  .cell .position { color: #5c6a83 !important; opacity: 1; }
  .cell .digits { color:#808da2!important; }
  .cell.filled .digits { color: #7a5a11 !important; }

  /* Every label and cell value stays on one line — no mid-word or mid-run breaks. */
  .axis-label,
  .cell .position,
  .cell .digits {
    white-space: nowrap !important;
    word-break: keep-all !important;
    overflow-wrap: normal !important;
    hyphens: none !important;
  }

  /* Sized so even a seven-times repeated digit still fits the cell on one line,
     now that the run is no longer allowed to break across lines. */
  .cell { padding: 0.35rem !important; }
  .cell .digits { font-size: 1.15rem !important; letter-spacing: 0.02em !important; }

  /* Sections flow across sheets rather than being held whole: a whole section
     rarely fits after another one, which would leave half of every sheet empty.
     What stays unbroken is the pieces inside them, and a heading always travels
     with the block it introduces. */
  .report-section {
    break-inside: auto;
    /* A section that opens a sheet drew its divider a hair under the masthead's
       own rule. The gap and the gold heading carry the separation instead. */
    border-top: none !important;
    padding-top: 0 !important;
    margin-top: 11mm;
  }
  .section-title, .section-note, .report-head { break-after: avoid; }
  /* A note is at most three lines: split across a sheet it reads as a stray
     line under the masthead. */
  .section-note { break-inside: avoid; }
  p, li { orphans: 2; widows: 2; }

  .number-card,
  .reading-card,
  .plane-card,
  .prospect-card,
  .remedy-card,
  .loshu-layout,
  .trait-list li,
  .bullets li,
  .check-list li { break-inside: avoid; }
  /* Read as one set rather than a run of parts: the remedy cards and the career
     chips travel together instead of stranding half of themselves on the next
     sheet. Neither runs to a full sheet, so neither can be left with nowhere to
     go. */
  .remedy-grid, .chips { break-inside: avoid; }
  /* A scroll container prints as a clipped box; on paper the table simply has
     to fit the column instead. The wide-column floor exists so phone tables stay
     readable while scrolling — kept on paper it would run the last columns off
     the sheet, which is what pushed "Education 40%" past the table's own edge. */
  .table-scroll { overflow: visible !important; background-image: none !important; }
  .forecast, .forecast:has(thead th:nth-child(6)) { min-width: 0 !important; }
  .forecast { table-layout: fixed !important; width: 100% !important; }
  .forecast th, .forecast td { padding: 0.55rem 0.7rem !important; overflow-wrap: break-word; }
  /* Year and PY hold two to four characters; the indication takes the rest
     and the luck band stays wide enough for "80-100%" on one line. */
  .forecast th:nth-child(1), .forecast td:nth-child(1) { width: 12%; }
  .forecast th:nth-child(2), .forecast td:nth-child(2) { width: 10%; }
  .forecast th:nth-child(4), .forecast td:nth-child(4) { width: 18%; }
  /* The measure is set by the column here, not by a screen-width ceiling that
     would leave the text hugging the left of a wider cell. */
  .py-detail { max-width: none !important; }

  /* Everything in the report reads off the same left edge; the cards and the
     grid that are centred by design keep their own alignment. */
  .report-section, .report-section p, .report-section li, .report-section td { text-align: left; }
  .report-head, .number-card, .cell, .axis-label, .trait-num, .sheet-head, .report-foot { text-align: center; }
  /* The line under the grid belongs to the grid rather than to the column of
     body copy, and sits centred under it on screen. It is a <p> inside a report
     section, so the rule above had been pulling it to the left margin on paper
     — where it read as a stray sentence rather than as the grid's own caption.
     Specific enough to outrank that rule; the legend beside it is a flex row
     and was never affected. */
  .report-section .yoga-note { text-align: center; }
  /* The headline numbers sit on one line across a sheet, which is what leaves
     the Lo Shu grid room to open the report on the same page. Column flow rather
     than a fixed count of tracks: the Name Number card is only drawn when the
     chart carries a name, so a fixed four-track grid left a three-card report
     bunched against the left edge with an empty column beside it. */
  .number-grid {
    grid-template-columns: none !important;
    grid-auto-flow: column !important;
    grid-auto-columns: 1fr !important;
  }
  .number-card { padding: 1.1rem 0.75rem !important; }
  .number-card .value { font-size: 2.6rem !important; }
  /* Notes and body copy run to the column, not to a screen measure that would
     break lines early on paper. */
  .section-note { max-width: none !important; }

  /* "Next 9 Years" starts its own page: the section is tall enough that it
     otherwise trails onto a half-empty sheet. The divider rule that separates
     sections mid-page is pointless at the top of a fresh one. */
  #s-forecast {
    break-before: page;
    page-break-before: always;
    border-top: none !important;
    /* The masthead row already holds the top of every sheet clear. */
    padding-top: 0 !important;
    margin-top: 0 !important;
    /* Overrides .report-section's avoid: the rows can outrun a single sheet,
       and an unbreakable block that tall overflows instead of continuing. */
    break-inside: auto;
  }

  #s-forecast .forecast tr { break-inside: avoid; }

  /* Printed flat — no panel fill behind the table, no tinted anti-year rows,
     no chip or tag fills. Borders carry the structure instead. */
  #s-forecast .table-scroll,
  #s-forecast .forecast,
  #s-forecast tbody tr,
  #s-forecast .anti-year,
  #s-forecast .py-chip,
  #s-forecast .anti-tag {
    background: none !important;
  }

  #s-forecast .table-scroll { border-color: #e3ddd0 !important; }
  #s-forecast .forecast th { border-bottom-color: #cfc7b6 !important; }
  #s-forecast .forecast td { border-bottom-color: #e3ddd0 !important; }
  #s-forecast .py-chip { border-color: #d8c398 !important; }
  #s-forecast .forecast .luck { color: #8a6a1f !important; }

  #s-forecast .anti-tag {
    color: #a33a36 !important;
    border-color: #d8a3a1 !important;
  }
  a[href]::after { content: none !important; }

  /* A zero page margin leaves the browser no margin box to print its own header and
     footer in, which is what keeps the page URL, title and date out of the saved PDF. */
  @page { margin: 0; }
}

@media (max-width: 600px) {
  .vault-card { padding: 1.35rem 1.15rem; }
}

/* ---------- Guide page ---------- */

.guide-hero { padding-bottom: 2rem; }

.guide-toc {
  max-width: var(--maxw);
  margin: 0 auto 1rem;
  padding: 0 1.5rem;
}

.guide-toc ol {
  list-style: none;
  margin: 0;
  padding: 1.25rem 1.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(220px, 100%), 1fr));
  gap: 0.55rem 1.5rem;
  counter-reset: toc;
}

.guide-toc li { counter-increment: toc; font-size: 0.88rem; }

.guide-toc li::before {
  content: counter(toc, decimal-leading-zero);
  font-family: var(--font-display);
  color: var(--gold);
  margin-right: 0.55rem;
  font-size: 0.78rem;
}

.guide-toc a { color: var(--ink-soft); text-decoration: none; transition: color 0.2s ease; }
.guide-toc a:hover { color: var(--gold-bright); }

.guide-section {
  max-width: var(--maxw);
  margin: 0 auto;
  padding: 2.75rem 2rem 0.25rem;
  scroll-margin-top: 90px;
  background: var(--panel);
}

/* The run of sections reads as one cream slab, so only its outer corners are
   rounded. :first-of-type and :last-of-type can't pick them out: the run is
   bracketed by the hero above and the CTA below, which are <section> elements
   too, so no .guide-section is ever the first or last <section> of its type. */
.guide-section { border-radius: var(--radius) var(--radius) 0 0; }
.guide-section + .guide-section { border-radius: 0; }

.guide-section:has(+ .guide-cta) {
  padding-bottom: 2.75rem;
  border-radius: 0 0 var(--radius) var(--radius);
}

.guide-section > h2 {
  font-size: clamp(1.35rem, 3.2vw, 1.85rem);
  margin-bottom: 1rem;
  text-shadow: var(--text-scrim);
}

.guide-section > h3 {
  font-size: 1.05rem;
  color: var(--gold-bright);
  margin: 1.75rem 0 0.75rem;
  text-shadow: var(--text-scrim);
}

.guide-section p { margin-bottom: 0.9rem; color: var(--ink-soft); text-shadow: var(--text-scrim); }
.guide-section p:last-child { margin-bottom: 0; }
.guide-section strong { color: var(--gold-bright); font-weight: 500; }

.guide-section .table-scroll { margin-bottom: 1rem; }

.callout {
  border: 1px solid var(--line);
  border-left: 3px solid var(--gold);
  border-radius: var(--radius);
  background: var(--panel);
  padding: 1.15rem 1.35rem;
  margin: 1.25rem 0;
}

.callout h3 {
  font-size: 0.95rem;
  color: var(--gold-bright);
  margin: 0 0 0.5rem;
}

.callout p { margin-bottom: 0.6rem; font-size: 0.9rem; }

/* Chaldean letter chart */

.letter-chart {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(110px, 100%), 1fr));
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.letter-col {
  border: 1px solid var(--line-soft);
  border-radius: 12px;
  background: var(--panel);
  padding: 0.9rem 0.75rem;
  text-align: center;
}

.letter-col .val {
  font-family: var(--font-display);
  font-size: 1.5rem;
  font-weight: 400;
  color: var(--gold-bright);
  line-height: 1;
}

.letter-col .letters {
  margin-top: 0.5rem;
  font-size: 0.9rem;
  letter-spacing: 0.14em;
  color: var(--ink-soft);
}

/* Static Lo Shu diagram on the guide page */

.loshu-static { width: min(100%, 340px); margin: 0 auto 1rem; }

.loshu-static .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.guide-cta {
  max-width: var(--maxw);
  margin: 3rem auto 0;
  padding: 2.25rem 1.5rem 0;
  text-align: center;
  border-top: 1px solid var(--line-soft);
}

.guide-cta h2 { margin-bottom: 0.75rem; }
.guide-cta p { color: var(--ink-soft); margin-bottom: 1.5rem; }

@media (max-width: 600px) {
  .guide-section, .guide-toc, .guide-cta { padding-left: 1.15rem; padding-right: 1.15rem; }
  .guide-section { padding-top: 2rem; }
  .guide-section > h3 { margin-top: 1.35rem; }
  .guide-toc ol { padding: 1rem 1.15rem; gap: 0.15rem; }

  /* One entry per row on a phone, so the counters line up in a column and the
     titles hang off a common left edge instead of stepping in and out. */
  .guide-toc li {
    display: grid;
    grid-template-columns: 1.7rem 1fr;
    align-items: baseline;
    font-size: 0.92rem;
  }

  .guide-toc li::before { margin-right: 0; }
  .letter-chart { gap: 0.5rem; }
  .letter-col { padding: 0.7rem 0.5rem; }
  .callout { padding: 1rem 1.1rem; }
  .guide-cta { margin-top: 2rem; padding-top: 1.75rem; }
  .pull-quote { margin: 1.75rem auto 1.5rem; }
}

@media (max-width: 400px) {
  .guide-section, .guide-toc, .guide-cta { padding-left: 1rem; padding-right: 1rem; }
  .letter-chart { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .letter-col .val { font-size: 1.3rem; }
  .letter-col .letters { letter-spacing: 0.08em; font-size: 0.84rem; }
}

/* ---------- Long-form copy blocks ---------- */

.section-lead {
  max-width: 680px;
  margin: 0 auto 1.1rem;
  text-align: center;
  color: var(--ink-soft);
  font-size: clamp(0.95rem, 1.5vw, 1.05rem);
}

.section-lead:last-of-type { margin-bottom: 2.5rem; }
.section-lead strong { color: var(--gold-bright); font-weight: 500; }

.pull-quote {
  max-width: 640px;
  margin: 2.5rem auto 2rem;
  text-align: center;
  font-family: var(--font-display);
  font-size: clamp(1.05rem, 2.4vw, 1.45rem);
  font-weight: 400;
  line-height: 1.45;
  background: var(--grad-accent);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.approach-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(260px, 100%), 1fr));
  gap: 0.85rem 1.75rem;
}

/* Four items, so two columns keep the rows even; auto-fit would leave a lone
   item stranded on a second row at wider widths. */
@media (min-width: 640px) {
  .approach-list { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

.approach-list li {
  display: grid;
  grid-template-columns: 1.35rem 1fr;
  gap: 0.5rem;
  align-items: baseline;
  color: var(--ink-soft);
  font-size: 0.93rem;
  line-height: 1.5;
}

.approach-list li::before {
  content: "✦";
  color: var(--gold);
  font-size: 0.95rem;
}

.center-cta { text-align: center; margin-top: 2.5rem; }
