/* CoupleLore — shared visual language for every customer-facing page.
 *
 * The website is the box the gift arrives in. It borrows the game's palette and
 * a little of its pixel vocabulary, and stops there: an ordinary form is an
 * ordinary form, not an inventory screen.
 *
 * Everything here is tokens and primitives. Page-specific layout lives in
 * `landing.css` and `creator.css`, which both assume this file is loaded first.
 *
 * One web font, and it lives here.
 * ---------------------------------------------------------------------------
 * The pages are served under a CSP with `font-src 'self'`, so a hosted family
 * would silently fall back on every browser. Fraunces is served from this
 * origin instead, which satisfies the policy without touching it; the licence,
 * the subsetting decisions and the deterministic build are documented in
 * `scripts/build-display-font.cjs` beside the file it produces.
 *
 * The `@font-face` was written in `landing.css` while the landing page was the
 * only surface using it. The creator now shares that language, and a second
 * copy of the declaration is how two surfaces start disagreeing about which
 * file, which weight and which `font-display` they are asking for — so the
 * declaration is here, once, and the surfaces opt in by choosing a token:
 *
 *   --display-book       the system editorial serif this file has always used
 *   --display-fraunces   Fraunces in front of that same stack
 *   --display            what a heading actually resolves to
 *
 * `--display` defaults to the system stack, so a surface that has not been
 * through the redesign renders exactly as it did before. The landing page and
 * the creator each promote it to `--display-fraunces` on their own `body`.
 */

@font-face {
  font-family: 'Fraunces';
  src: url('/creator/assets/fraunces-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  /* Swap, not block: the fallback stack is a serif of similar colour, so a
     reader who beats the font to the paint sees the right kind of page rather
     than a blank one. */
  font-display: swap;
}

:root {
  /* --- surface ---------------------------------------------------------- */
  /* Deep midnight, warmed slightly towards violet so it sits with the art. */
  --night: #0d0917;
  --night-deep: #080512;
  --surface: #150f24;
  --surface-raised: #1c1430;
  --surface-sunken: #100b1d;
  --line: #2e2444;
  --line-soft: #241b38;
  --line-strong: #453458;

  /* --- ink -------------------------------------------------------------- */
  --ink: #f4ece2; /* cream, not white: paper rather than screen */
  --ink-dim: #bfb3cc;
  --ink-faint: #8d81a3;

  /* --- accents ---------------------------------------------------------- */
  /* Coral/rose carries every primary action. Gold is for warmth and is used
     sparingly — rules, small marks, the occasional emphasis. Nothing else. */
  --rose: #e4657f;
  --rose-bright: #f07f95;
  --rose-deep: #c2415f;
  --rose-ink: #ffffff;
  --gold: #e0b774;
  --gold-dim: #a8874e;
  --alarm: #ffb1a6;
  --alarm-line: #7a3242;
  --alarm-bed: #2a1421;
  --good: #93d4a5;

  /* --- glass / wash ------------------------------------------------------ */
  --wash-rose: rgb(228 101 127 / 12%);
  --wash-gold: rgb(224 183 116 / 10%);
  --wash-ink: rgb(255 255 255 / 4%);

  /* --- type ------------------------------------------------------------- */
  /* Romantic serif for feeling; plain sans for anything the customer has to
     read, type into, or act on. */
  /* The faces that actually ship on desktop and mobile, and the fallback plan
     for the one that does not: if the WOFF2 never arrives, every heading on
     every surface renders in the serif it rendered in before it existed. */
  --display-book:
    'Iowan Old Style', 'Palatino Linotype', Palatino, 'Book Antiqua', Georgia,
    'Times New Roman', serif;
  --display-fraunces: 'Fraunces', var(--display-book);
  --display: var(--display-book);
  --body:
    system-ui, -apple-system, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
  --mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Consolas, monospace;

  /* --- rhythm ----------------------------------------------------------- */
  --gap-xs: 0.4rem;
  --gap-sm: 0.75rem;
  --gap: 1.15rem;
  --gap-lg: 2rem;
  --gap-xl: 3.5rem;
  --gap-2xl: 5.5rem;

  --radius-sm: 8px;
  --radius: 14px;
  --radius-lg: 20px;

  /* Restrained: a lift off the page, never a drop shadow with an opinion. */
  --lift: 0 1px 0 rgb(255 255 255 / 4%) inset, 0 10px 30px rgb(0 0 0 / 35%);
  --lift-sm: 0 4px 14px rgb(0 0 0 / 28%);

  /* Comfortable on a thumb. Every interactive control meets this. */
  --touch: 44px;

  --shell: 68rem;
  --shell-narrow: 44rem;
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

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

body {
  margin: 0;
  background-color: var(--night);
  color: var(--ink);
  font-family: var(--body);
  font-size: 1rem;
  line-height: 1.6;
  /* Subtle texture instead of a gradient: two very wide, very faint radial
     washes that read as candlelight in the corners of a dark room. */
  background-image:
    radial-gradient(120% 80% at 12% -10%, rgb(107 62 116 / 34%) 0%, transparent 62%),
    radial-gradient(90% 70% at 92% 4%, rgb(196 88 106 / 18%) 0%, transparent 58%);
  background-attachment: fixed;
  background-repeat: no-repeat;
  min-height: 100vh;
}

img {
  max-width: 100%;
}

/* --- typography ----------------------------------------------------------- */

h1,
h2,
h3 {
  font-family: var(--display);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: -0.005em;
  margin: 0;
  /* Fluid rather than stepped, so a heading never sits awkwardly between two
     breakpoints on a phone held either way up. */
}

h1 {
  font-size: clamp(2.25rem, 6.5vw, 3.9rem);
}

h2 {
  font-size: clamp(1.7rem, 4vw, 2.5rem);
}

h3 {
  font-size: clamp(1.15rem, 2.2vw, 1.4rem);
}

/* The one place colour is allowed inside a heading: a phrase set in rose, as
   the references do. Applied by hand, never to a whole heading. */
.said {
  color: var(--rose-bright);
}

.lede {
  color: var(--ink-dim);
  font-size: clamp(1rem, 1.6vw, 1.12rem);
  margin: 0;
  max-width: 46ch;
}

/* The editorial eyebrow: a short rose rule and the label beside it, in its own
   casing. No border, no fill, no pill — the same treatment as `.public-eyebrow`. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.7rem;
  color: var(--ink-dim);
  font-size: 0.86rem;
  letter-spacing: 0.02em;
}

.eyebrow::before {
  content: "";
  flex: none;
  width: 28px;
  height: 1px;
  background: var(--rose);
}

/* A label, not a badge: any icon an eyebrow carries is left out of the drawing. */
.eyebrow > svg {
  display: none;
}

.hint {
  color: var(--ink-faint);
  font-size: 0.85rem;
  line-height: 1.55;
  margin: 0.4rem 0 0;
}

.optional {
  margin-left: 0.5rem;
  padding: 0.12rem 0.5rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: transparent;
  color: var(--ink-faint);
  font-family: var(--body);
  font-size: 0.66rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  vertical-align: middle;
}

code {
  font-family: var(--mono);
  font-size: 0.86em;
  padding: 0.1em 0.35em;
  border-radius: 4px;
  background: var(--wash-ink);
  color: var(--gold);
}

/* --- pixel motifs --------------------------------------------------------- */

/* The one pixel flourish that appears everywhere. Inline SVG rather than a
   sprite: it inherits colour, scales to the text beside it, and costs no
   request. `currentColor` is what lets the same mark sit in a heading, a button
   and a stage rail without three copies of it. */
.pixel-heart {
  flex: none;
  width: 1em;
  height: 1em;
  color: var(--rose);
  vertical-align: -0.12em;
}

/* A thin gold rule with a heart in the middle, used to close a section. */
.rule {
  display: flex;
  align-items: center;
  gap: var(--gap-sm);
  color: var(--gold-dim);
}

.rule::before,
.rule::after {
  content: '';
  flex: 1;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}

/* --- layout --------------------------------------------------------------- */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: clamp(1.1rem, 4vw, 2rem);
}

.shell-narrow {
  max-width: var(--shell-narrow);
}

.band {
  padding-block: clamp(2.5rem, 5vw, var(--gap-xl));
}

.stack {
  display: flex;
  flex-direction: column;
  gap: var(--gap);
}

/* --- site chrome ---------------------------------------------------------- */

.site-header {
  position: relative;
  z-index: 5;
  border-bottom: 1px solid var(--line-soft);
  background: rgb(13 9 23 / 72%);
}

.site-header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap);
  min-height: 4.25rem;
}

/* The brand lockup: the CoupleLore wordmark, and nothing else beside it.
 *
 * It used to be a pixel heart followed by the product name set as text. The
 * heart was a placeholder from the working-name era and was never part of this
 * identity — `docs/brand/couplelore/brand-notes.md` is explicit that the
 * primary logo is **wordmark-only**, for header and footer alike, and that the
 * castle/path/heart is secondary and belongs to the favicon. Renaming the text
 * beside a mark is not rebranding, so the mark went.
 *
 * The wordmark is real artwork rather than set type because two of its
 * characteristics cannot be expressed in CSS at all: the initial `C` is
 * quantized onto a pixel grid, and a pixel heart is knocked out of the `o` in
 * `Lore`. It is still the same typeface as the headings around it — the
 * outlines are Fraunces, read out of the WOFF2 this origin already serves.
 *
 * **Which file, and why it is not the primary one.** These pages are near-black
 * and `couplelore-logo-primary.svg` is drawn in Royal Berry: #5B1E2E on #0d0917
 * is all but invisible. The surfaces render the *reversed* variant — identical
 * geometry, Powder Blush over Rose Blush, both canonical tokens. The primary
 * and monochrome files are for the light surfaces that need a picture.
 *
 * The heart itself is untouched everywhere else on these pages. It is the
 * design's own flourish in buttons, eyebrows, section rules and note boxes,
 * which is a different job from being a logo. */
.wordmark {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
}

/* The wordmark artwork.
 *
 * Sized by **height**, with `width: auto`, because the height is what has to
 * agree with the things beside it in a header bar and the width is whatever the
 * word happens to be. `--wordmark-height` is the single knob the surfaces and
 * the breakpoints turn.
 *
 * The artwork's box is the ink box: cap height is 1400 of its 1990 units, the
 * rest being the descender of the `p` and a little air. So the optical size is
 * roughly 0.7 of whatever height is set here, which is why these numbers are
 * larger than the font-size they replaced. */
.wordmark-art {
  display: block;
  height: var(--wordmark-height, 1.95rem);
  width: auto;
}

.wordmark-sm {
  --wordmark-height: 1.7rem;
}

.site-footer {
  border-top: 1px solid var(--line-soft);
  padding-block: var(--gap-lg);
  color: var(--ink-faint);
  font-size: 0.85rem;
}

.site-footer-inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--gap-sm);
}

/* --- buttons -------------------------------------------------------------- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.55rem;
  min-height: var(--touch);
  padding: 0.7rem 1.5rem;
  border: 1px solid transparent;
  border-radius: 999px;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-weight: 600;
  font-size: 0.98rem;
  line-height: 1.2;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color 160ms ease,
    border-color 160ms ease,
    transform 160ms ease;
}

.btn-primary {
  background: linear-gradient(180deg, var(--rose-bright), var(--rose-deep));
  color: var(--rose-ink);
  box-shadow: var(--lift-sm);
}

.btn-primary:hover {
  background: linear-gradient(180deg, #f68fa3, var(--rose));
}

.btn-ghost {
  border-color: var(--line-strong);
  color: var(--ink);
  background: var(--wash-ink);
}

.btn-ghost:hover {
  border-color: var(--rose);
  color: var(--rose-bright);
}

/* Third weight, for actions that sit beside a primary one and must not compete
   with it: Copy, Revoke, Remove, Clear. */
.btn-quiet {
  min-height: 0;
  padding: 0.45rem 0.95rem;
  border-color: var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink-dim);
  font-size: 0.88rem;
  font-weight: 500;
}

.btn-quiet:hover {
  border-color: var(--line-strong);
  color: var(--ink);
}

/* Reserved for a control that destroys something the customer already shared. */
.btn-danger:hover {
  border-color: var(--alarm-line);
  color: var(--alarm);
}

.btn-block {
  width: 100%;
}

.btn[disabled],
.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
  box-shadow: none;
}

.btn:active:not([disabled]) {
  transform: translateY(1px);
}

/* --- cards and panels ----------------------------------------------------- */

.card {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  box-shadow: var(--lift);
}

.card-pad {
  padding: clamp(1.1rem, 3vw, 1.75rem);
}

/* A quieter box for a note or an aside inside a card. */
.note-box {
  display: flex;
  gap: var(--gap-sm);
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--line-soft);
  border-left: 2px solid var(--gold-dim);
  border-radius: var(--radius-sm);
  background: var(--wash-gold);
  color: var(--ink-dim);
  font-size: 0.88rem;
}

.note-box .pixel-heart {
  color: var(--gold);
  margin-top: 0.25em;
}

/* --- form primitives ------------------------------------------------------ */

label {
  display: block;
  font-size: 0.94rem;
}

.label-text {
  display: block;
  margin-bottom: 0.35rem;
  color: var(--ink-dim);
  font-size: 0.88rem;
  font-weight: 500;
}

input[type='text'],
input[type='email'],
input[type='file'],
select,
textarea {
  width: 100%;
  min-height: var(--touch);
  padding: 0.65rem 0.8rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-sm);
  background: var(--surface-sunken);
  color: var(--ink);
  font: inherit;
  /* 16px on mobile, so iOS does not zoom the page when a field is focused. */
  font-size: max(1rem, 16px);
}

input[type='text']:hover,
input[type='email']:hover,
select:hover,
textarea:hover {
  border-color: var(--line-strong);
}

textarea {
  min-height: 6rem;
  line-height: 1.55;
  resize: vertical;
}

select {
  appearance: none;
  padding-right: 2.4rem;
  /* Drawn rather than fetched: an inline data: chevron needs no request and is
     allowed by the page's `img-src 'self' data:`. */
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%238d81a3' d='M1 1.5 6 6.5l5-5'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 0.9rem center;
  background-size: 0.7rem;
}

/* The file input is the one control that cannot be restyled from the inside, so
   it is given a surface to sit on instead and its button is toned down. */
input[type='file'] {
  padding: 0.55rem 0.7rem;
  color: var(--ink-dim);
  font-size: 0.9rem;
  cursor: pointer;
}

input[type='file']::file-selector-button {
  min-height: 2.1rem;
  margin-right: 0.8rem;
  padding: 0.35rem 0.9rem;
  border: 1px solid var(--line-strong);
  border-radius: 999px;
  background: var(--surface-raised);
  color: var(--ink);
  font: inherit;
  font-size: 0.86rem;
  font-weight: 500;
  cursor: pointer;
}

input[type='file']::file-selector-button:hover {
  border-color: var(--rose);
  color: var(--rose-bright);
}

input[type='checkbox'],
input[type='radio'] {
  accent-color: var(--rose);
}

.checkbox {
  display: flex;
  gap: 0.7rem;
  align-items: flex-start;
  font-size: 0.88rem;
  line-height: 1.55;
  color: var(--ink-dim);
}

.checkbox input {
  flex: none;
  width: 1.15rem;
  height: 1.15rem;
  margin-top: 0.25rem;
}

/* --- problems ------------------------------------------------------------- */

.problems {
  margin: 0 0 var(--gap);
  padding: 0.9rem 1.1rem;
  border: 1px solid var(--alarm-line);
  border-radius: var(--radius-sm);
  background: var(--alarm-bed);
  color: var(--alarm);
  font-size: 0.92rem;
}

.problems:empty {
  display: none;
}

.problems ul {
  margin: 0.4rem 0 0;
  padding-left: 1.15rem;
}

/* --- accessibility -------------------------------------------------------- */

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 2px;
  border-radius: 4px;
}

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

.skip-link {
  position: absolute;
  left: 0.75rem;
  top: -4rem;
  z-index: 20;
  padding: 0.6rem 1rem;
  border-radius: var(--radius-sm);
  background: var(--rose);
  color: var(--rose-ink);
  font-weight: 600;
  text-decoration: none;
  transition: top 140ms ease;
}

.skip-link:focus {
  top: 0.75rem;
}

/* --- language picker ------------------------------------------------------- */

/* One control, drawn into both headers by `localePicker.js` from the locales
   that are actually published. It replaced a segmented `English | Türkçe` pair,
   which read well at two languages and would have run the header out of room at
   four. Styled once, here, because it is one component on two pages.

   The trigger shows the current language by its own name — a Turkish reader
   looks for "Türkçe", whatever the page currently says — with an optional flag
   beside it. The flag is decoration: it is `aria-hidden` in the markup, and
   nothing in the product reads one to decide anything. */
.lang-picker {
  position: relative;
  display: flex;
  align-items: center;
}

.lang-trigger {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  margin: 0;
  padding: 0.34rem 0.6rem 0.34rem 0.55rem;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-sunken);
  color: var(--ink-dim);
  font: inherit;
  font-size: 0.82rem;
  line-height: 1.1;
  cursor: pointer;
  white-space: nowrap;
  -webkit-tap-highlight-color: transparent;
}

.lang-trigger:hover {
  border-color: var(--line-strong);
  color: var(--ink);
}

/* Focus is visible on every state and is never removed: this control is
   reachable by keyboard and the ring is how a keyboard user knows where it is. */
.lang-trigger:focus-visible,
.lang-option:focus-visible {
  outline: 2px solid var(--rose);
  outline-offset: 2px;
}

.lang-flag {
  font-size: 1em;
  line-height: 1;
}

.lang-caret {
  color: var(--ink-faint);
  font-size: 0.7em;
  line-height: 1;
  transition: transform 120ms ease;
}

.lang-picker[data-open='true'] .lang-caret {
  transform: rotate(180deg);
}

/* Fetching a language. The control stays live — a visitor may change their mind
   mid-flight — and only dims to say something is happening. */
.lang-trigger[aria-busy='true'] {
  opacity: 0.7;
}

/* The menu hangs from the trigger's right edge so it can never push the header
   wider than the viewport, and is capped so a long list scrolls inside itself
   rather than off the bottom of a phone. */
.lang-menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 40;
  min-width: max(10rem, 100%);
  max-height: min(60vh, 20rem);
  margin: 0;
  padding: 4px;
  overflow-y: auto;
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-sm);
  background: var(--surface-raised);
  box-shadow: var(--lift);
  list-style: none;
}

.lang-option {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  min-height: var(--touch);
  padding: 0 0.7rem;
  border-radius: var(--radius-sm);
  color: var(--ink-dim);
  font-size: 0.88rem;
  line-height: 1.2;
  cursor: pointer;
  white-space: nowrap;
}

.lang-option:hover {
  background: var(--wash-ink);
  color: var(--ink);
}

/* The active language, stated in colour and with a tick as well as in
   `aria-selected` — the attribute is what a screen reader reads and these are
   what everyone else does. */
.lang-option[aria-selected='true'] {
  background: var(--wash-rose);
  color: var(--ink);
}

.lang-mark {
  margin-left: auto;
  color: var(--rose);
  opacity: 0;
}

.lang-option[aria-selected='true'] .lang-mark {
  opacity: 1;
}

/* On a phone the header is a row of thumb targets and the trigger joins them.
   The name stays visible rather than collapsing to a flag alone: a flag is not
   a language, and a control whose only label is a picture of a country is one a
   visitor has to guess at. */
@media (max-width: 62rem) {
  .lang-picker {
    order: 2;
  }

  /* A full 44px, not the 36px the old two-button pill used. There is one
     control here now rather than two side by side, so it can be a proper thumb
     target without making the header row taller than the call to action. */
  .lang-trigger {
    min-height: var(--touch);
    padding-inline: 0.7rem;
  }
}

@media (max-width: 26rem) {
  .lang-trigger {
    padding-inline: 0.55rem;
    font-size: 0.78rem;
  }
}

/* --- reduced motion -------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
