/* Moon Portrait — one stylesheet, no framework.
   System fonts lead every stack so first paint is instant, which matters because
   most visitors arrive on a phone from a link. The Noto webfonts declared at the
   bottom exist for one reason: the preview canvas and the printed PDF must use
   the SAME typefaces, and the system stacks have no Arabic, CJK, Hebrew, Thai or
   Devanagari. They are range-scoped, so a Latin visitor fetches none of them. */

:root {
  /* Tells the browser to render native widgets (form controls, scrollbars,
     focus rings) for a dark UI. Without this, Safari draws light-mode controls
     on the dark page. */
  color-scheme: dark;

  --bg: #0b1020;
  --bg-2: #121829;
  --bg-3: #171e33;
  --ink: #f5f2ec;
  --ink-dim: #a8b0c6;
  --ink-faint: #6b7593;
  --line: #262f47;
  --accent: #f0dfae;
  --accent-ink: #1b1a15;
  --danger: #ffb4a8;
  /* The MP Noto families are appended rather than led with, so system text still
     paints immediately and only non-Latin characters wait for a download. This
     matters for the title field: the buyer should see their own name in the same
     face the keepsake will print it in. */
  --serif: "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif,
           "MP Noto Serif", "MP Noto Arabic", "MP Noto Hebrew", "MP Noto Thai",
           "MP Noto Devanagari", "MP Noto SC", "MP Noto JP", "MP Noto KR";
  --sans: "Helvetica Neue", Helvetica, -apple-system, BlinkMacSystemFont, "Segoe UI", Arial, sans-serif,
          "MP Noto Sans", "MP Noto Arabic", "MP Noto Hebrew", "MP Noto Thai",
          "MP Noto Devanagari", "MP Noto SC", "MP Noto JP", "MP Noto KR";
  --measure: 34rem;
  --pad: clamp(1.25rem, 4vw, 3rem);
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
}

/* A very faint wash so the page reads as a night sky without any image. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  background:
    radial-gradient(60rem 40rem at 50% -12rem, #16203d 0%, transparent 70%),
    radial-gradient(50rem 35rem at 50% -8rem, rgba(240, 223, 174, 0.06), transparent 70%);
  pointer-events: none;
  z-index: 0;
}

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

a { color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 2px; }
/* :not(.btn) matters: without it, a hovered .btn.primary anchor turned white text
   on the white hover background and vanished. */
a:not(.btn):hover { color: #fff; }

h1, h2, h3 { font-family: var(--serif); font-weight: 400; letter-spacing: -0.01em; }

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

.skip {
  position: absolute; left: -9999px; top: 0; padding: 0.6rem 1rem;
  background: var(--accent); color: var(--accent-ink); z-index: 10;
}
.skip:focus { left: 0.5rem; top: 0.5rem; }

.muted { color: var(--ink-dim); }
.tiny { font-size: 0.8rem; line-height: 1.5; }
.error { color: var(--danger); font-size: 0.9rem; }

/* ---------------------------------------------------------------- hero ---- */

.hero {
  max-width: 46rem;
  margin: 0 auto;
  padding: clamp(3rem, 10vh, 7rem) var(--pad) clamp(2rem, 6vh, 3.5rem);
  text-align: center;
}

.eyebrow {
  font-size: 0.72rem;
  letter-spacing: 0.34em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin: 0 0 1.6rem;
}

h1 {
  font-size: clamp(2.1rem, 6.4vw, 3.5rem);
  line-height: 1.08;
  margin: 0 0 1.2rem;
  text-wrap: balance;
}

.lede {
  max-width: var(--measure);
  margin: 0 auto 2.5rem;
  color: var(--ink-dim);
  font-size: clamp(1rem, 2.4vw, 1.12rem);
  text-wrap: pretty;
}

form fieldset { border: 0; margin: 0; padding: 0; }

.fields {
  display: flex;
  gap: 0.6rem;
  justify-content: center;
  flex-wrap: wrap;
  margin-bottom: 1.25rem;
}

label { display: block; text-align: left; }

label > span {
  display: block;
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  margin-bottom: 0.4rem;
}
label > span em { text-transform: none; letter-spacing: 0; font-style: normal; }

input, select {
  font: inherit;
  /* Safari on macOS otherwise draws its own control chrome — a bevelled select
     with a native chevron and different metrics — which is why the form looked
     unlike Chrome's. Resetting the appearance makes the two agree. */
  appearance: none;
  -webkit-appearance: none;
  color: var(--ink);
  background-color: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 0.7rem 0.8rem;
  width: 100%;
  min-height: 48px; /* comfortable tap target */
  line-height: 1.3;
  /* Safari refuses to shrink the text of a control below 16px on iOS without
     this, and zooms the page on focus instead. */
  font-size: max(1rem, 16px);
}

/* Our own chevron, since appearance:none removes the native one. Delivered as a
   data: URI, which the site's img-src allows. */
select {
  padding-right: 2.2rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' fill='none' stroke='%23a8b0c6' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.85rem center;
  background-size: 0.7rem auto;
  text-overflow: ellipsis;
}
select:disabled { opacity: 0.5; }
input:focus-visible, select:focus-visible, button:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
input::placeholder { color: var(--ink-faint); }
/* Remove the spinners; they invite fiddling and add nothing here. */
input[type="number"] { -moz-appearance: textfield; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }

.fields label:nth-child(1) { flex: 0 0 9.5rem; }
.fields label:nth-child(2) { flex: 0 0 5rem; }
.fields label:nth-child(3) { flex: 0 0 6.5rem; }

/* The three fixed bases come to 22.2rem including gaps. An iPhone 13 offers
   about 21.9rem inside the page padding, so YEAR wrapped onto its own line and
   sat centred under a left-aligned MONTH and DAY — on the first thing every
   visitor sees, and most of them arrive on a phone. Found by the first
   cross-browser test run, not by eye.

   A grid below that width keeps the three on one row and lets them share the
   space proportionally instead of wrapping. */
@media (max-width: 27rem) {
  .fields {
    display: grid;
    grid-template-columns: minmax(0, 1.7fr) minmax(0, 1fr) minmax(0, 1.25fr);
    gap: 0.5rem;
  }
  .fields label { flex: none; }
}

/* `.btn` carries everything a button needs, so an <a> can be styled as one.
   Previously .primary/.secondary relied on the bare `button` selector for their
   padding and border, so anchors wearing those classes came out unpadded and
   borderless. */
button, .btn {
  font: inherit;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  border-radius: 10px;
  border: 1px solid transparent;
  padding: 0.75rem 1.4rem;
  min-height: 48px;
  appearance: none;
  -webkit-appearance: none;
  text-decoration: none;
  transition: transform 0.08s ease, background 0.15s ease, border-color 0.15s ease;
}
button:active, .btn:active { transform: translateY(1px); }

/* The colour is restated on :hover so it survives the generic link rules. */
.primary,
.primary:hover,
.primary:visited { background: var(--accent); color: var(--accent-ink); font-weight: 600; }
.primary:hover { background: #fff; }
.primary.big { font-size: 1.06rem; padding: 0.95rem 1.8rem; }
.primary strong { font-weight: 700; }

.secondary,
.secondary:hover,
.secondary:visited {
  background: transparent;
  color: var(--ink);
  border-color: var(--line);
}
.secondary:hover { border-color: var(--ink-faint); background: var(--bg-2); }

.reassure { font-size: 0.82rem; color: var(--ink-faint); margin: 1rem 0 0; }

/* -------------------------------------------------------------- result ---- */

main { padding-bottom: 4rem; }

.result { max-width: 62rem; margin: 0 auto; padding: 0 var(--pad); }

.result-head { text-align: center; margin-bottom: 2.5rem; }
.result-head h2 { font-size: clamp(1.7rem, 5vw, 2.5rem); margin: 0 0 0.4rem; }

.grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(64px, 1fr));
  gap: clamp(0.5rem, 2vw, 1.1rem);
  margin-bottom: 0.9rem;
}

.cell {
  border: 0;
  background: transparent;
  padding: 0.3rem 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.3rem;
  border-radius: 10px;
  min-height: 0;
}
.cell:hover, .cell[aria-expanded="true"] { background: var(--bg-2); }
.cell svg { width: 100%; height: auto; display: block; max-width: 68px; }
.cell b {
  font-size: 0.72rem;
  font-weight: 500;
  color: var(--ink-faint);
  font-variant-numeric: tabular-nums;
}
.cell[aria-expanded="true"] b { color: var(--accent); }

.grid-hint { text-align: center; font-size: 0.82rem; margin: 0 0 2.5rem; }

.detail {
  text-align: center;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 12px;
  padding: 0.9rem 1rem;
  margin: -1.5rem 0 2.5rem;
  font-size: 0.95rem;
}
.detail strong { font-family: var(--serif); font-size: 1.05rem; }

.facts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  margin-bottom: 3.5rem;
}

.fact { background: var(--bg); padding: 1.4rem 1.3rem; }
.fact h4 {
  margin: 0 0 0.5rem;
  font-family: var(--sans);
  font-size: 0.7rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--ink-faint);
  font-weight: 600;
}
.fact p { margin: 0; font-size: 0.95rem; color: var(--ink-dim); }
.fact .big-num {
  font-family: var(--serif);
  font-size: 1.9rem;
  line-height: 1.1;
  color: var(--ink);
  display: block;
  margin-bottom: 0.3rem;
  font-variant-numeric: tabular-nums;
}
.fact em { color: var(--ink); font-style: normal; }

/* ---------------------------------------------------- share and poster ---- */

.share, .poster {
  border-top: 1px solid var(--line);
  padding-top: 2.5rem;
  margin-bottom: 3.5rem;
}
.share h3, .poster h3, .about h2 {
  font-size: clamp(1.4rem, 4vw, 1.9rem);
  margin: 0 0 0.6rem;
}
.share p, .poster > p { max-width: var(--measure); color: var(--ink-dim); margin-top: 0; }

.row { display: flex; gap: 0.7rem; flex-wrap: wrap; margin-top: 1.2rem; }

/* The free/paid comparison. Deliberately plain language, no file formats. */
.compare {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.55fr);
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 14px;
  overflow: hidden;
  margin: 1.75rem 0 0;
}
@media (max-width: 40rem) { .compare { grid-template-columns: 1fr; } }

.compare-col { background: var(--bg); padding: 1.3rem; }
.compare-col.paid { background: var(--bg-2); }
.compare-col p { margin: 0; color: var(--ink-dim); font-size: 0.95rem; }
.compare-col.paid p { color: var(--ink); }
.compare-col strong { color: var(--ink); font-weight: 600; }
.compare-tag {
  font-family: var(--serif);
  font-size: 1.25rem !important;
  color: var(--ink) !important;
  margin-bottom: 0.4rem !important;
}
.compare-col.paid .compare-tag { color: var(--accent) !important; }

/*
 * Two columns, but the previews are far taller than the controls. If the buy
 * button sat below the whole grid it left a large dead gap under the controls —
 * exactly what it did. So the preview column spans both rows and the buy button
 * takes the space beneath the controls instead.
 */
.poster-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.05fr);
  grid-template-rows: auto 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;
  margin: 2rem 0;
}
.poster-controls { grid-column: 1; grid-row: 1; }
.preview-stack { grid-column: 2; grid-row: 1 / span 2; }
.poster-wrap .buy { grid-column: 1; grid-row: 2; margin-top: 0; }

@media (max-width: 46rem) {
  .poster-wrap { grid-template-columns: 1fr; grid-template-rows: none; }
  /* Stack in reading order: customise, see it, then buy. */
  .poster-controls { grid-column: 1; grid-row: auto; }
  .preview-stack { grid-column: 1; grid-row: auto; }
  .poster-wrap .buy { grid-column: 1; grid-row: auto; }
}

/* Milestones */
.milestone-row {
  display: grid;
  grid-template-columns: 5.2rem minmax(0, 1fr) 2.2rem;
  gap: 0.4rem;
  margin-bottom: 0.4rem;
}
.milestone-row input { min-height: 44px; padding: 0.5rem 0.6rem; }
.ms-remove {
  background: transparent;
  border: 1px solid var(--line);
  color: var(--ink-faint);
  min-height: 44px;
  padding: 0;
  font-size: 1.2rem;
  line-height: 1;
}
.ms-remove:hover { color: var(--danger); border-color: var(--danger); }
.ms-actions { margin-top: 0.5rem; }
button.small { padding: 0.45rem 0.9rem; min-height: 40px; font-size: 0.88rem; }
button:disabled { opacity: 0.4; cursor: not-allowed; }

/* Previews are raster canvases, never vector. */
.preview-stack { display: flex; flex-direction: column; gap: 1.6rem; }
.preview.small { max-width: 62%; }
@media (max-width: 46rem) { .preview.small { max-width: 78%; } }
.preview canvas {
  width: 100%;
  height: auto;
  display: block;
  /* The preview is intentionally low resolution; let the browser smooth it
     rather than showing the visitor a crunchy artefact. */
  image-rendering: auto;
}

.poster-controls { display: flex; flex-direction: column; gap: 1.2rem; }

.chooser { border: 0; padding: 0; margin: 0; }
.chooser legend {
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink-faint);
  padding: 0;
  margin-bottom: 0.4rem;
}

.segmented {
  display: inline-flex;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 3px;
  gap: 3px;
}
.segmented button {
  background: transparent;
  color: var(--ink-dim);
  border: 0;
  border-radius: 7px;
  padding: 0.45rem 1.1rem;
  min-height: 40px;
  font-size: 0.92rem;
}
.segmented button[aria-checked="true"] {
  background: var(--bg-3);
  color: var(--ink);
  box-shadow: inset 0 0 0 1px var(--line);
}
.chooser .tiny { margin: 0.5rem 0 0; }

.preview { margin: 0; }
.preview > div {
  border-radius: 6px;
  overflow: hidden;
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.07);
  background: #fff;
  line-height: 0;
}
.preview figcaption { margin-top: 0.8rem; }

.buy { margin-top: 2rem; }
.buy .tiny { max-width: 30rem; margin: 0.9rem 0 0; }

/* --------------------------------------------------------------- about ---- */

.about {
  max-width: 62rem;
  margin: 0 auto;
  padding: 3.5rem var(--pad) 0;
  border-top: 1px solid var(--line);
}
.about h2 { text-align: center; margin-bottom: 2.5rem; }
.cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(17rem, 1fr));
  gap: 2rem 2.5rem;
}
.cols h3 { font-size: 1.15rem; margin: 0 0 0.5rem; }
.cols p { margin: 0 0 0.8rem; color: var(--ink-dim); font-size: 0.94rem; }
.cols strong { color: var(--ink); }

footer {
  max-width: 62rem;
  margin: 4rem auto 0;
  padding: 2rem var(--pad) 3rem;
  border-top: 1px solid var(--line);
  text-align: center;
}
footer p { margin: 0 0 0.6rem; color: var(--ink-dim); font-size: 0.9rem; }

/* ------------------------------------------------------------ niceties ---- */

@media (prefers-reduced-motion: reduce) {
  * { transition: none !important; animation: none !important; }
}

.spinner { opacity: 0.6; pointer-events: none; }

/* Static pages (privacy, terms, unlocked) */
.page {
  max-width: 40rem;
  margin: 0 auto;
  padding: clamp(3rem, 8vh, 5rem) var(--pad) 4rem;
}
.page h1 { font-size: clamp(1.8rem, 5vw, 2.6rem); }
.page h2 { font-size: 1.2rem; margin-top: 2.2rem; }
.page p, .page li { color: var(--ink-dim); }
.page a.back { display: inline-block; margin-top: 2.5rem; }
.download-row { display: flex; gap: 0.8rem; flex-wrap: wrap; margin: 2rem 0; }
.badge {
  display: inline-block;
  background: var(--bg-2);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.3rem 0.9rem;
  font-size: 0.78rem;
  color: var(--ink-dim);
  margin-bottom: 1.5rem;
}

/* ---------------------------------------------------------------------------
 * Webfonts — the SAME files the PDF renderer embeds.
 *
 * The preview is a canvas, and canvas has no font fallback chain of its own
 * beyond what the CSS font stack provides. Before these were declared, the stack
 * named only Helvetica and Palatino, neither of which has Arabic, CJK, Hebrew,
 * Thai or Devanagari — so the browser substituted an OS face while the printed
 * file used Noto. The buyer approved one typeface and received another.
 *
 * Loaded lazily by unicode-range where the browser supports it, so a visitor
 * with a Latin name never downloads the 10 MB CJK face. The Latin faces are the
 * only ones fetched eagerly.
 * ------------------------------------------------------------------------- */

@font-face {
  font-family: "MP Noto Sans";
  src: url("/fonts/NotoSans-Regular.ttf") format("truetype");
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: "MP Noto Sans";
  src: url("/fonts/NotoSans-Bold.ttf") format("truetype");
  font-weight: 700; font-display: swap;
}
@font-face {
  font-family: "MP Noto Serif";
  src: url("/fonts/NotoSerif-Regular.ttf") format("truetype");
  font-weight: 400; font-style: normal; font-display: swap;
}
@font-face {
  font-family: "MP Noto Serif";
  src: url("/fonts/NotoSerif-Italic.ttf") format("truetype");
  font-weight: 400; font-style: italic; font-display: swap;
}

/* Script faces, each restricted to its own range so nothing is fetched until a
   character in that range is actually rendered. */
@font-face {
  font-family: "MP Noto Arabic";
  src: url("/fonts/NotoNaskhArabic-Regular.ttf") format("truetype");
  unicode-range: U+0600-06FF, U+0750-077F, U+08A0-08FF, U+FB50-FDFF, U+FE70-FEFF;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto Hebrew";
  src: url("/fonts/NotoSansHebrew-Regular.ttf") format("truetype");
  unicode-range: U+0590-05FF, U+FB1D-FB4F;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto Thai";
  src: url("/fonts/NotoSansThai-Regular.ttf") format("truetype");
  unicode-range: U+0E00-0E7F;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto Devanagari";
  src: url("/fonts/NotoSansDevanagari-Regular.ttf") format("truetype");
  unicode-range: U+0900-097F, U+A8E0-A8FF;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto SC";
  src: url("/fonts/NotoSansSC-Regular.ttf") format("truetype");
  unicode-range: U+2E80-2EFF, U+3000-303F, U+3400-4DBF, U+4E00-9FFF,
                 U+F900-FAFF, U+FF00-FFEF;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto JP";
  src: url("/fonts/NotoSansJP-Regular.ttf") format("truetype");
  unicode-range: U+3040-30FF, U+31F0-31FF;
  font-display: swap;
}
@font-face {
  font-family: "MP Noto KR";
  src: url("/fonts/NotoSansKR-Regular.ttf") format("truetype");
  unicode-range: U+1100-11FF, U+3130-318F, U+A960-A97F, U+AC00-D7AF;
  font-display: swap;
}
