/* Inter, matching alessandrogillies.com. Subset to Latin and Latin Extended,
   which takes it from 352KB to 141KB; both variable axes are intact. */
@font-face {
  font-family: Inter;
  src: url('/fonts/InterVariable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

:root {
  color-scheme: light;
  --mark-size: 5.5rem;
}

:root[data-theme="dark"] {
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    color-scheme: dark;
  }

  /* Keep the control honest even if the pre-paint script could not declare a
     theme. The page already follows the OS in that state, so the icon must
     follow it too instead of making the first tap a no-op. */
  :root:not([data-theme="light"]) .theme-toggle .theme-icon-light {
    display: none;
  }

  :root:not([data-theme="light"]) .theme-toggle .theme-icon-dark {
    display: block;
  }
}

/* Every page is coloured by its Pokémon, in both schemes. Each palette below
   names its two versions once, as -l and -d pairs; the three blocks after them
   are the only place that picks between the two, so adding a page means adding
   one block and nothing else. Defaults are Solrock by day, Lunatone by night. */
body {
  --ink-l: #2b2320;
  --ink-soft-l: #6b5c50;
  --paper-l: #f7ecdd;
  --accent-l: #b04b1d;
  --shadow-l: 47 42 38;

  --ink-d: #ece7f5;
  --ink-soft-d: #b3a9cf;
  --paper-d: #1b1830;
  --accent-d: #9b7fd4;
  --shadow-d: 8 5 20;
}

/* Hale is the two of us: Mudkip blue on Ditto lilac. */
body[data-accent="hale"] {
  --ink-l: #241f30;
  --ink-soft-l: #5c5470;
  --paper-l: #f3eef9;
  --accent-l: #2f6ea8;
  --shadow-l: 36 31 48;

  --ink-d: #eae6f6;
  --ink-soft-d: #b0a8ca;
  --paper-d: #1a1630;
  --accent-d: #82c4f2;
  --shadow-d: 8 5 20;
}

body[data-accent="chansey"] {
  --ink-l: #2e1f26;
  --ink-soft-l: #6e5a60;
  --paper-l: #fbeff1;
  --accent-l: #b04566;
  --shadow-l: 46 31 38;

  --ink-d: #f6e8ec;
  --ink-soft-d: #cfb2bc;
  --paper-d: #2a1a22;
  --accent-d: #f2a0b8;
  --shadow-d: 20 8 12;
}

body[data-accent="lapras"] {
  --ink-l: #1f2530;
  --ink-soft-l: #545e6e;
  --paper-l: #edf1f8;
  --accent-l: #45689f;
  --shadow-l: 31 37 48;

  --ink-d: #e6ebf6;
  --ink-soft-d: #a9b4cc;
  --paper-d: #141a2c;
  --accent-d: #93b6ea;
  --shadow-d: 6 8 18;
}

body[data-accent="bellibolt"] {
  --ink-l: #1c2a26;
  --ink-soft-l: #506059;
  --paper-l: #e9f4ef;
  --accent-l: #14745f;
  --shadow-l: 28 42 38;

  --ink-d: #e4f2ec;
  --ink-soft-d: #a3c2b8;
  --paper-d: #0f2420;
  --accent-d: #4fd8b8;
  --shadow-d: 4 16 12;
}

body {
  --ink: var(--ink-l);
  --ink-soft: var(--ink-soft-l);
  --paper: var(--paper-l);
  --accent: var(--accent-l);
  --shadow: var(--shadow-l);
}

/* These two must stay in sync: the first serves the manual toggle, the second
   an untouched dark-OS visitor. */
:root[data-theme="dark"] body {
  --ink: var(--ink-d);
  --ink-soft: var(--ink-soft-d);
  --paper: var(--paper-d);
  --accent: var(--accent-d);
  --shadow: var(--shadow-d);
}

@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) body {
    --ink: var(--ink-d);
    --ink-soft: var(--ink-soft-d);
    --paper: var(--paper-d);
    --accent: var(--accent-d);
    --shadow: var(--shadow-d);
  }
}

* {
  box-sizing: border-box;
}

html, body {
  min-height: 100%;
}

/* Our Story is tall enough to scroll and RSVP usually isn't, so on any
   browser with classic scrollbars the scrolling page lost ~15px of width
   and its centred content sat half that to the left of the other pages'.
   Reserving the gutter everywhere keeps the two pages aligned. */
html {
  scrollbar-gutter: stable;
}

/* Set while the lightbox is open, so the page cannot drift about behind the
   photo. The gutter above stays reserved, so nothing jumps sideways as the
   scrollbar goes. */
html.is-locked {
  overflow: hidden;
}

body {
  margin: 0;
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  background: var(--paper);
  color: var(--ink);
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Arial, sans-serif;
  transition: background-color 0.2s ease, color 0.2s ease;
}

a {
  color: var(--accent);
}

/* Tapping a control on a touch screen paints a translucent grey-blue
   rectangle over it, which sits square over the round theme toggle. Touch
   gets its own :active feedback below instead. */
a,
button,
label,
input {
  -webkit-tap-highlight-color: transparent;
}

::selection {
  background: color-mix(in srgb, var(--accent) 28%, transparent);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.site-header {
  position: sticky;
  top: 0;
  z-index: 10;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1.5rem 2rem;
  background: var(--paper);
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
  transition: background-color 0.2s ease;
}

.site-header .nav-group {
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

.site-header .brand {
  text-decoration: none;
  color: var(--ink);
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  white-space: nowrap;
}

.site-header .brand .amp {
  color: var(--accent);
}

.site-header nav {
  display: flex;
  gap: 1.5rem;
}

/* Every link carries the underline slot, so the header keeps the same height
   and the nav sits on the same baseline whether or not a page is current. */
.site-header nav a {
  text-decoration: none;
  font-size: 0.85rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  white-space: nowrap;
  padding-bottom: 0.2rem;
  border-bottom: 1px solid transparent;
  transition: color 0.15s ease, border-color 0.15s ease;
}

@media (hover: hover) {
  .site-header nav a:hover {
    color: var(--ink);
  }
}

.site-header nav a[aria-current="page"] {
  color: var(--ink);
  border-bottom-color: var(--accent);
}

main {
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: 4rem 2rem;
}

main.centered {
  justify-content: center;
}

/* Letter-spacing adds a trailing gap after the last character, which nudges
   centred text left of true centre. The indent puts it back. */
.eyebrow {
  letter-spacing: 0.3em;
  text-indent: 0.3em;
  text-transform: uppercase;
  font-size: 0.75rem;
  font-weight: 400;
  line-height: 1.6;
  color: var(--accent);
  margin-bottom: 1.5rem;
}

h1 {
  font-size: clamp(2rem, 9vw, 4rem);
  font-weight: 300;
  letter-spacing: -0.02em;
  margin: 0 0 1rem;
  line-height: 1.15;
}

/* The ampersand is set at the same size as the names either side of it, so
   only colour marks it out. Its margin is what the old smaller version came
   to once its own font-size was applied, which keeps the spacing as it was. */
h1 .amp {
  color: var(--accent);
  font-weight: 300;
  margin: 0 0.12em;
}

h1.page-title {
  font-size: clamp(2rem, 5vw, 3rem);
}

p {
  font-size: 1.05rem;
  line-height: 1.6;
  color: var(--ink-soft);
  margin: 0;
  max-width: 32rem;
}

p.quote {
  font-size: 1.3rem;
  font-weight: 300;
}

.theme-toggle {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0.4rem;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 50%;
  background: none;
  cursor: pointer;
  transition: background-color 0.15s ease;
}

@media (hover: hover) {
  .theme-toggle:hover {
    background: color-mix(in srgb, var(--accent) 12%, transparent);
  }
}

.theme-toggle:active {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
}

.theme-toggle img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

.theme-toggle .theme-icon-dark {
  display: none;
}

:root[data-theme="dark"] .theme-toggle .theme-icon-light {
  display: none;
}

:root[data-theme="dark"] .theme-toggle .theme-icon-dark {
  display: block;
}

.rule {
  width: 3rem;
  height: 1px;
  background: var(--accent);
  margin: 1.75rem auto;
}

/* Marks are locked by height, not width, so every page's badge row is the
   same height and the rule below it lands in the same place on each page. */
.page-mark {
  display: block;
  height: var(--mark-size);
  width: auto;
  margin: 0 auto 1.5rem;
}

/* Every mark is the way in to the safari at /game, which is linked from
   nowhere else and stays out of search. Making it a rule rather than hiding
   the door behind one particular Pokémon means whichever one you reach for is
   the one that works.

   The anchor has to leave the mark exactly where it was, so it takes over the
   img's own centring and the img gives it up. The mark is display:block, so
   no line box forms inside the link and nothing gains a descender's worth of
   height. */
.mark-link {
  display: block;
  width: fit-content;
  margin: 0 auto 1.5rem;
  border-radius: 4px;
  transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.mark-link .page-mark {
  margin: 0;
}

/* Enough to say it is a door, not enough to announce one. */
@media (hover: hover) {
  .mark-link:hover {
    transform: scale(1.05);
  }
}

.mark-link:active {
  transform: scale(0.97);
  transition-duration: 0.12s;
}

.page-marks {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  margin: 0 auto 1.5rem;
}

.page-marks .page-mark,
.page-marks .mark-link {
  margin: 0;
}

/* Wider than the 34rem the text blocks keep to. A photo held to the reading
   width is a stamp in the middle of a big screen, and 44rem is as far as the
   originals go before a retina screen starts upscaling them. */
.moment {
  width: 100%;
  max-width: 44rem;
  margin-top: 3rem;
}

/* Interior pages open straight from the title with no rule under it, so the
   first block carries the gap the rule used to hold open. */
.moment:first-of-type {
  margin-top: 4.5rem;
}

.moment .eyebrow {
  margin-bottom: 0.75rem;
}

.moment img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: 4px;
  box-shadow: 0 1.5rem 3rem -1.5rem rgb(var(--shadow) / 0.45);
}

/* A thumb gets no cursor and no hover, so a press gives a little under it and
   springs back, and the photo opens. The overshoot in the easing is the
   bounce. lightbox.js listens for touchstart, which is what makes :active
   fire on iOS at all. */
@media (hover: none) {
  .moment img {
    transition: transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1);
  }

  .moment img:active {
    transform: scale(0.97);
    transition-duration: 0.12s;
  }
}

/* lightbox.js wraps each photo in this button. It has to leave the figure
   looking exactly as it did, so everything a button brings with it goes. */
.moment .zoom {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: none;
  font: inherit;
  cursor: zoom-in;
}

/* Opening a photo enlarges it into the page rather than taking you somewhere
   else. The header stays put and stays sharp, and the page beneath it goes
   soft behind the photo: a thin wash of the page's own paper over a light
   blur, enough to settle everything behind the photo without hiding it. A
   black surround made this feel like arriving on another page.

   The wash sits on the dialog, not on ::backdrop, because ::backdrop is not
   reliably reached by the page's custom properties and the colour has to be
   whichever paper this page is wearing.

   lightbox.js measures the header and sets --header-h, since the header is
   two rows on a phone and one on everything else. */
.lightbox {
  position: fixed;
  inset: var(--header-h, 0px) 0 0;
  width: auto;
  max-width: none;
  height: auto;
  max-height: none;
  margin: 0;
  /* Slim on a phone, where the margin is growth the photo cannot have, and
     generous on a desktop, where it is what keeps the page in view. */
  padding: clamp(0.5rem, 3vw, 3rem);
  border: none;
  background: color-mix(in srgb, var(--paper) 55%, transparent);
  backdrop-filter: blur(8px);
  overflow: hidden;
  cursor: zoom-out;
  opacity: 0;
  transition: opacity 0.2s ease, overlay 0.2s ease allow-discrete, display 0.2s ease allow-discrete;
}

/* Scoped to [open] so the browser's own rule still hides a closed dialog. */
.lightbox[open] {
  display: flex;
  opacity: 1;
}

@starting-style {
  .lightbox[open] {
    opacity: 0;
  }
}

/* The dialog carries the wash, so the backdrop behind it stays out of the way
   entirely. Left to itself it paints a black sheet. */
.lightbox::backdrop {
  background: none;
}

/* Whole and centred, never cropped and never scrolling. The shadow is the one
   the photos already wear on the page, deepened for the lift. */
.lightbox-image {
  margin: auto;
  max-width: 100%;
  max-height: 100%;
  border-radius: 6px;
  box-shadow: 0 2rem 4rem -1rem rgb(var(--shadow) / 0.4);
}

/* Same circle as the theme toggle in the header, in the page's own colours,
   sitting in the margin the wash leaves rather than on top of the photo. */
.lightbox-close {
  position: absolute;
  top: 1rem;
  right: 1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  padding: 0;
  font: inherit;
  font-size: 1.4rem;
  line-height: 1;
  color: var(--ink-soft);
  background: var(--paper);
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 50%;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease;
}

@media (hover: hover) {
  .lightbox-close:hover {
    color: var(--ink);
    background: color-mix(in srgb, var(--accent) 12%, var(--paper));
  }
}

.moment figcaption {
  margin-top: 1.25rem;
  font-size: 0.95rem;
  color: var(--accent);
}

.rsvp-form {
  width: 100%;
  max-width: 26rem;
  margin-top: 4rem;
  text-align: left;
}

.field {
  margin-bottom: 1.5rem;
}

.field > legend,
.field > label {
  display: block;
  font-size: 0.75rem;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 0.6rem;
}

fieldset.field {
  width: 100%;
  min-inline-size: 0;
  padding: 0;
  border: 0;
}

.field input[type="text"],
.field input[type="number"] {
  width: 100%;
  padding: 0.6rem 0.1rem;
  font: inherit;
  font-size: 1.05rem;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 0;
  transition: border-color 0.15s ease;
}

.field input[type="text"]:focus,
.field input[type="number"]:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

.toggle-group {
  position: relative;
  display: flex;
  gap: 0.75rem;
}

/* Visually hidden but still focusable, and kept inside the group so focusing
   a radio by keyboard cannot scroll the page off to a stray position. */
.toggle-group input {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  border: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.toggle-group label {
  flex: 1;
  text-align: center;
  padding: 0.6rem 1rem;
  border: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 999px;
  cursor: pointer;
  font-size: 0.85rem;
  letter-spacing: 0.1em;
  text-indent: 0.1em;
  text-transform: uppercase;
  margin: 0;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}

@media (hover: hover) {
  .toggle-group label:hover {
    background: color-mix(in srgb, var(--accent) 12%, transparent);
  }
}

.toggle-group label:active {
  background: color-mix(in srgb, var(--accent) 20%, transparent);
}

.toggle-group input:checked + label {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--paper);
}

.toggle-group input:focus-visible + label {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
}

.field-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.rsvp-submit {
  width: 100%;
  padding: 0.8rem 1.5rem;
  font: inherit;
  font-size: 0.9rem;
  letter-spacing: 0.15em;
  text-indent: 0.15em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--accent);
  border: none;
  border-radius: 999px;
  cursor: pointer;
  transition: background-color 0.15s ease, opacity 0.15s ease;
}

@media (hover: hover) {
  .rsvp-submit:hover:not(:disabled) {
    background: color-mix(in srgb, var(--accent) 85%, var(--ink));
  }
}

.rsvp-submit:active:not(:disabled) {
  background: color-mix(in srgb, var(--accent) 78%, var(--ink));
}

.rsvp-submit:disabled {
  opacity: 0.6;
  cursor: default;
}

.rsvp-privacy {
  max-width: 24rem;
  margin: 1rem auto 0;
  font-size: 0.75rem;
  line-height: 1.5;
  color: var(--ink-soft);
}

.rsvp-status {
  margin-top: 1.25rem;
  font-size: 0.95rem;
  text-align: center;
}

.rsvp-status[data-state="error"] {
  color: var(--accent);
}

/* Once the form is gone the thank-you takes over its place in the rhythm. */
.rsvp-form.is-hidden + .rsvp-status {
  margin-top: 4rem;
}

.rsvp-form.is-hidden,
.rsvp-status.is-hidden,
.field-party.is-hidden {
  display: none;
}

/* Homepage date and countdown. The homepage has no rule under the names, so
   the date carries the gap the rule used to hold open. */
.date-line {
  margin-top: 2.5rem;
  font-size: 1.15rem;
  color: var(--ink);
  letter-spacing: 0.02em;
}

.countdown {
  margin-top: 0.5rem;
  font-size: 0.95rem;
  color: var(--accent);
  /* The seconds change width every tick; tabular figures stop the centred
     line shuffling sideways once a second. */
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Nothing is booked yet, so anything provisional says so in the same voice
   everywhere rather than each page inventing its own hedge. */
.tbc {
  color: var(--ink-soft);
  opacity: 0.85;
}

/* One way to reach us, on every page, below whatever the page is about. */
.site-footer {
  padding: 2.5rem 2rem 3rem;
  text-align: center;
  border-top: 1px solid color-mix(in srgb, var(--accent) 18%, transparent);
}

.site-footer p {
  margin: 0 auto;
  font-size: 0.85rem;
  letter-spacing: 0.02em;
}

.site-footer a {
  color: var(--accent);
  text-decoration-color: color-mix(in srgb, var(--accent) 45%, transparent);
  text-underline-offset: 0.25em;
}

/* Stacked information sections on The Day and Travel. */
.info {
  width: 100%;
  max-width: 34rem;
  margin-top: 2.75rem;
  text-align: left;
}

.info:first-of-type {
  margin-top: 4rem;
}

.info h2 {
  font-size: 0.75rem;
  font-weight: 400;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0 0 0.75rem;
}

.info p + p {
  margin-top: 0.75rem;
}

.info p {
  max-width: none;
}

.field textarea {
  width: 100%;
  min-height: 4.5rem;
  padding: 0.6rem 0.1rem;
  font: inherit;
  font-size: 1.05rem;
  line-height: 1.5;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 0;
  resize: vertical;
  transition: border-color 0.15s ease;
}

.field textarea:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

.field input[type="email"] {
  width: 100%;
  padding: 0.6rem 0.1rem;
  font: inherit;
  font-size: 1.05rem;
  color: var(--ink);
  background: none;
  border: none;
  border-bottom: 1px solid color-mix(in srgb, var(--accent) 40%, transparent);
  border-radius: 0;
  transition: border-color 0.15s ease;
}

.field input[type="email"]:focus {
  outline: none;
  border-bottom-color: var(--accent);
}

.field-hint {
  margin-top: 0.4rem;
  font-size: 0.8rem;
  color: var(--ink-soft);
}

@media (max-width: 40rem) {
  :root {
    --mark-size: 4.5rem;
  }

  .site-header {
    gap: 1rem;
    padding: 1rem 1.25rem;
  }

  .site-header .brand {
    font-size: 1rem;
  }

  .site-header .nav-group,
  .site-header nav {
    gap: 1rem;
  }

  .site-header nav a {
    font-size: 0.75rem;
    letter-spacing: 0.1em;
  }

  main {
    padding: 2.5rem 1.25rem 3.5rem;
  }

  .site-footer {
    padding: 2rem 1.25rem 2.5rem;
  }

  .rsvp-form,
  .info:first-of-type,
  .moment:first-of-type {
    margin-top: 3rem;
  }

}

/* Five nav links no longer fit beside the brand on a phone. Rather than
   squash anything, the header becomes two rows: brand and toggle at the
   edges, nav centred underneath. Dissolving .nav-group with display:contents
   lets its two children take part in the header's own wrap. */
@media (max-width: 32rem) {
  .site-header {
    flex-wrap: wrap;
    gap: 0.85rem;
  }

  .site-header .nav-group {
    display: contents;
  }

  .site-header .brand {
    order: 1;
  }

  .site-header .theme-toggle {
    order: 2;
  }

  .site-header nav {
    order: 3;
    width: 100%;
    justify-content: center;
    flex-wrap: wrap;
    row-gap: 0.5rem;
  }
}

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