/* Palette: blush ground, bordeaux ink + buttons, oat paper, citrus accents.
   Citrus is decorative only — it does not have enough contrast for text. */
:root {
  --oat: #EDD5AB;
  --denim: #97B2D1;
  --blush: #EFCCC9;          /* page background: sampled from the plain pink in Couple.mp4 so the videos blend in */
  --citrus: #99992C;
  --bordeaux: #601D2D;
  --red: #CF2104;            /* sampled from the linework of Architecture.png; all text, rules and buttons */

  --paper: #F8EEDB;          /* lighter oat, for cards and inputs */
  --ink: #3F121D;            /* deeper bordeaux, for body copy */

  /* Calcado (Type/CALCADO-Font) for all site text; only "Save the Date" differs. */
  --font-calcado: "Calcado", system-ui, -apple-system, "Segoe UI", sans-serif;
  --font-display: var(--font-calcado);
  --font-serif: var(--font-calcado);
  --font-ui: var(--font-calcado);
  /* The two forms (opening and postcard): a quiet regular-weight book serif. */
  --font-note: "Iowan Old Style", "Palatino Linotype", Palatino, "Book Antiqua", Georgia, serif;

  --gutter: 20px;
  --column: 26rem;
}

@font-face {
  font-family: "Calcado";
  /* The desktop .otf: the supplied web-font versions are missing most lowercase letters. */
  src: url("fonts/calcado.otf") format("opentype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* Script for the "Save the Date" heading. SIL Open Font License (fonts/MonsieurLaDoulaise-OFL.txt). */
@font-face {
  font-family: "Monsieur La Doulaise";
  src: url("fonts/monsieurladoulaise-regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* Handwritten script, used only for the postcard's question. SIL Open Font License (fonts/MsMadi-OFL.txt). */
@font-face {
  font-family: "Ms Madi";
  src: url("fonts/msmadi-regular.ttf") format("truetype");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

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

body {
  margin: 0;
  font-synthesis: none;
  background: var(--blush);
  color: var(--red);
  font-family: var(--font-ui);
  font-size: 1.0625rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, p { margin: 0; }
svg { display: block; }

/* ---------- Opening screen: image + phone ---------- */

.entry {
  position: fixed;
  inset: 0;
  z-index: 25;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* --art: one width for Mochi and the garland, the tighter of the column and the height left
     after the form (~330px), so the whole opening fits a phone screen with the keyboard closed. */
  --art: min(100%, 17.5rem, max(11rem, calc((100svh - 330px) * 1.24)));
  gap: 0;
  padding: 20px var(--gutter) calc(max(20px, env(safe-area-inset-bottom)) + var(--kb, 0px));
  background: var(--blush);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  transition: opacity 0.45s ease;
}
/* Centred as a group; the auto margins (not justify-content) keep the top reachable by
   scrolling when the keyboard leaves less room than the content needs. */
.entry > .picado { margin-top: auto; }
.entry > .entry__form { margin-bottom: auto; }
.entry__image { display: block; flex: 0 0 auto; }
/* The form is quiet stationery so Mochi and the garland stay the focus: a regular-weight
   book serif, small labels above transparent fields with a thin red rule, and a text-only
   "Continue →". Entered text stays 16px so phones don't zoom in. No shadows or scaling. */
.entry__form {
  width: 100%;
  max-width: 20rem;
  margin-top: 14px;
  font-family: var(--font-note);
  transition: opacity 0.35s ease, visibility 0s linear 0.35s;
}
.entry__field { margin-bottom: 18px; }
.entry__field label { margin: 0; font: 400 0.8125rem/1.3 var(--font-note); letter-spacing: 0.02em; color: var(--red); }
.entry__form input[type="text"], .entry__form input[type="tel"], .entry__code {
  box-sizing: border-box;
  height: 40px;
  min-height: 0;
  margin: 0;
  padding: 8px 0 6px;
  border: 0;
  border-bottom: 1px solid var(--red);
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  outline: none;
  color: var(--red);
  -webkit-text-fill-color: var(--red);
  caret-color: var(--red);
  font: 400 1rem/1.5 var(--font-note);   /* 16px: phones don't zoom */
  -webkit-appearance: none;
  appearance: none;
}
/* Focus (mouse, touch or keyboard): the rule thickens to 2px; padding keeps the text still.
   No outline box on top of it. */
.entry__form input[type="text"]:focus, .entry__form input[type="tel"]:focus, .entry__code:focus-within {
  outline: none;
  border-bottom-width: 2px;
  padding-bottom: 5px;
}
.entry__form input[aria-invalid="true"] { border-bottom-width: 2px; padding-bottom: 5px; }
/* Autofill: browsers paint their own yellow/blue fill; cover it with the blush and keep the text red. */
.entry__form input:-webkit-autofill,
.entry__form input:-webkit-autofill:hover,
.entry__form input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--red);
  -webkit-box-shadow: 0 0 0 1000px var(--blush) inset;
  box-shadow: 0 0 0 1000px var(--blush) inset;
  caret-color: var(--red);
  transition: background-color 600000s 0s, color 600000s 0s;
}
.entry__form input:autofill { background: var(--blush); color: var(--red); }
.entry__name { width: 100%; }
.entry__phone { display: flex; align-items: flex-end; gap: 14px; }
.entry__phone input { flex: 1; min-width: 0; }
.entry__code { position: relative; flex: none; display: flex; align-items: center; gap: 7px; width: auto; padding-right: 2px; white-space: nowrap; }
.entry__code::after {        /* small dropdown arrow */
  content: "";
  width: 5px;
  height: 5px;
  margin-top: -3px;
  border: solid currentColor;
  border-width: 0 1px 1px 0;
  transform: rotate(45deg);
}
.entry__code select {
  position: absolute;
  inset: 0;
  width: 100%;
  min-height: 0;
  padding: 0;
  border: 0;
  opacity: 0;
  font-size: 16px;            /* no zoom when it opens on iPhone */
  cursor: pointer;
}
.entry__form .form-error {
  margin: -6px 0 12px;
  padding: 2px 0 2px 10px;
  border-left-width: 2px;
  border-radius: 0;
  background: transparent;
  font: 400 0.875rem/1.4 var(--font-note);
}
/* "Continue": a small version of the site's rounded red button, blush lettering in the
   form's serif, regular weight. No shadow and no press animation. */
.entry__continue {
  display: block;
  width: 168px;
  height: 44px;
  margin: 8px auto 0;
  padding: 0 16px;
  border: 1px solid var(--red);
  border-radius: 999px;
  background: var(--red);
  box-shadow: none;
  color: var(--blush);
  font: 400 0.9375rem/1 var(--font-note);
  letter-spacing: 0.06em;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
/* Turnstile slots: empty and invisible unless Cloudflare needs the guest to tick a box. */
.turnstile { display: flex; justify-content: center; }
.entry__continue:focus { outline: none; }
.entry__continue:focus-visible { outline: 1.5px solid var(--red); outline-offset: 3px; }   /* keyboard only */
.entry__continue[disabled] { opacity: 0.45; cursor: default; }

/* Papel picado garland: the same width rule as Mochi, a little narrower, and pulled down
   into the empty sky at the top of his video so it hangs just above his ears. It is
   decorative only and sits above the form, so it never takes taps. */
.picado {
  position: relative;
  z-index: 1;
  display: block;
  flex: 0 0 auto;
  width: var(--art);
  height: auto;
  margin-bottom: calc(var(--art) * -0.02);   /* flags hang just clear of Mochi's ears */
  overflow: visible;
  pointer-events: none;
}
.picado__letter { font: 400 24px var(--font-calcado); fill: var(--blush); }
/* Each flag swings from the middle of its top edge; each note from its own centre. */
.picado__flag, .picado__note { transform-box: fill-box; }
.picado__flag { transform-origin: 50% 0; }
.picado__note { opacity: 0; }

.entry.is-sending .entry__form { opacity: 0; visibility: hidden; }
.entry.is-sending .picado__flag { animation: picado-sway 1.3s ease-in-out infinite alternate; }
.entry.is-sending .picado__flag--b { animation-delay: -0.3s; }
.entry.is-sending .picado__flag--c { animation-delay: -0.6s; }
.entry.is-sending .picado__flag--d { animation-delay: -0.9s; }
.entry.is-sending .picado__flag--e { animation-delay: -1.2s; }
.entry.is-sending .picado__note { animation: note-float 1.9s ease-out infinite; }
.entry.is-sending .picado__note--b { animation-delay: 0.45s; }
.entry.is-sending .picado__note--c { animation-delay: 0.9s; }
.entry.is-sending .picado__note--d { animation-delay: 1.3s; }

/* Then the whole opening screen fades away over the couple page beneath it. */
.entry.is-gone { opacity: 0; pointer-events: none; transition: opacity 0.9s ease; }

@keyframes picado-sway { from { transform: rotate(-4deg); } to { transform: rotate(4deg); } }
@keyframes note-float {
  0%   { opacity: 0; transform: translate(0, 6px) rotate(-6deg); }
  20%  { opacity: 1; }
  100% { opacity: 0; transform: translate(5px, -46px) rotate(8deg); }
}

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

/* ---------- Save-the-date ---------- */

main {
  max-width: calc(var(--column) + 2 * var(--gutter));
  margin: 0 auto;
  padding: 28px var(--gutter) 72px;
  text-align: center;
}

/* Both artworks keep their own proportions and are never cropped. */
/* Videos keep their own proportions (no cropping): the box takes the video's aspect
   ratio and is sized by whichever limit is tighter, the column width or the screen height. */
.clip { position: relative; margin: 0 auto; }
.clip video {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  /* "darken" keeps whichever is darker, video or page, per colour channel. The red linework
     always wins; where a browser draws the video's pink a shade lighter than the page,
     the page colour shows instead, so no box appears around the animation. */
  mix-blend-mode: darken;
  pointer-events: none;      /* taps go "through" the animation: nothing pauses it */
}
/* Browsers decode video colour slightly differently (a few levels either way), so the
   outer edges fade softly into the page instead of showing a faint rectangle. */
.clip video {
  -webkit-mask-image: linear-gradient(to right, transparent, #000 4%, #000 96%, transparent), linear-gradient(to bottom, transparent, #000 3%, #000 97%, transparent);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to right, transparent, #000 4%, #000 96%, transparent), linear-gradient(to bottom, transparent, #000 3%, #000 97%, transparent);
  mask-composite: intersect;
}
/* Mochi only fills the middle of his frame (x 37.5-63%, y 22-78% in every frame), so the box
   shows the region x 27-73%, y 17-83% and he is drawn much larger. The fades move to that
   window's edges, so no rectangle shows where the video's pink differs from the page. */
.clip--mochi { width: var(--art); aspect-ratio: 147 / 119; overflow: hidden; }
.clip--mochi video {
  width: 217.4%;             /* 1 / 0.46 */
  height: auto;
  aspect-ratio: 16 / 9;
  margin: -20.8% 0 0 -58.7%; /* 17% of the frame height and 27% of its width, as % of the box width */
  -webkit-mask-image: linear-gradient(to right, transparent 27%, #000 31%, #000 69%, transparent 73%), linear-gradient(to bottom, transparent 17%, #000 20.5%, #000 79.5%, transparent 83%);
  mask-image: linear-gradient(to right, transparent 27%, #000 31%, #000 69%, transparent 73%), linear-gradient(to bottom, transparent 17%, #000 20.5%, #000 79.5%, transparent 83%);
}
/* The couple file keeps ~11% empty pink above the hat and ~11.5% below the feet (of its width).
   Never cropped: negative margins let the heading and names sit closer to the drawing instead. */
.clip--couple {
  --couple-w: min(100%, 64svh * 400 / 790);
  width: var(--couple-w);
  aspect-ratio: 400 / 790;
  margin-top: calc(var(--couple-w) * -0.06);
  margin-bottom: calc(var(--couple-w) * -0.095);
}

/* Small play button in the corner, separate from any form; hidden once playing */
.clip__toggle {
  position: absolute;
  right: 6px;
  bottom: 6px;
  width: 44px;
  height: 44px;
  display: grid;
  place-items: center;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: var(--red);
  color: var(--paper);
  cursor: pointer;
  opacity: 0.92;
}
.clip__toggle:hover { opacity: 1; }
.clip__icon { width: 20px; height: 20px; fill: currentColor; }
.clip--couple .clip__toggle { width: 36px; height: 36px; bottom: 7%; opacity: 0.75; }   /* above the tucked-in margin */
.clip--couple .clip__icon { width: 16px; height: 16px; }
.architecture { display: block; width: 85%; max-width: 19.5rem; height: auto; margin: var(--group-gap) auto 0; }

/* Invitation text beneath the portrait. Two families only: a regular serif for
   everything, and the expressive italic for "Save the Date". Lines sit close
   within a group (names / invite + title / date + place); the larger gaps fall
   between groups. */
.announce {
  --group-gap: clamp(26px, 7vw, 34px);
  position: relative;        /* paints above the couple's tucked-in empty margin */
  margin-top: 12px;
  color: var(--red);
  font-family: var(--font-serif);
  font-weight: 400;
}


/* Names: a centred, shrink-wrapped group. Equal columns either side keep the
   "&" on the page's centre line and stop the names running into each other. */
.announce__names {
  display: inline-grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: end;
  align-items: last baseline;   /* surnames and "&" share one baseline */
  column-gap: clamp(8px, 2.6vw, 14px);
  margin: 0 0 2px;
  max-width: 100%;
}
.announce__name { display: flex; flex-direction: column; align-items: center; white-space: nowrap; }
/* Calcado is wide, so the given names scale down on narrow phones to stay inside the screen. */
.announce__given { font-size: clamp(0.6875rem, 3.1vw, 0.875rem); line-height: 1.35; letter-spacing: 0.04em; }
.announce__family { font-size: clamp(1.35rem, 6.4vw, 1.65rem); line-height: 1.15; }
.announce__amp { font-size: 0.875rem; line-height: 1.15; }

/* "Save the Date", above the couple: Monsieur La Doulaise script, in title case. Its lowercase
   is tiny and its capitals carry tall swashes, so it runs large with roomy line-height and
   padding; nothing clips the loops. Sized so the line, flourishes included, fits a 320px phone. */
.invite__title {
  margin: 0 0 clamp(6px, 2vw, 14px);
  padding: 0.12em 0 0.18em;
  font-family: "Monsieur La Doulaise", cursive;
  font-style: normal;
  font-weight: 400;
  font-size: clamp(3rem, 15.5vw, 4.4rem);
  line-height: 1.25;
  white-space: nowrap;
  overflow: visible;
}
.invite__title:focus { outline: none; }

/* Date + place: one tight group close under the architecture. */
/* Written out in full; sized so "November 5, 2027" holds one line on a 320px phone. */
.announce__date { margin: 12px 0 18px; font-size: clamp(1.05rem, 5.4vw, 1.4rem); line-height: 1.2; white-space: nowrap; }
.announce__tagline { font-size: 0.8125rem; line-height: 1.3; letter-spacing: 0.12em; }
.announce__place { font-size: 0.6875rem; line-height: 1.3; letter-spacing: 0.05em; }
/* "Roma Norte" lettering (refrence-images/RomaNte2.png, recoloured to the site red).
   Scales with the screen; its proportions come from the width/height attributes. */
.announce__roma { display: block; width: min(59vw, 14.5rem); height: auto; margin: 2px auto 4px; }   /* a little narrower than the architecture */

/* Scroll parallax (app.js): the architecture lags the scroll by up to 18px and the
   date + place group by up to 12px; at the top of the page both sit at 0. */
.architecture, .announce__details { transform: translate3d(0, var(--parallax, 0px), 0); }
.announce__details { display: flow-root; }   /* keeps the date's margin inside the moving group */

.section { margin-top: 64px; }
.section:focus { outline: none; }
.section h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(1.75rem, 8vw, 2.15rem);
  line-height: 1.12;
  color: var(--red);
  text-wrap: balance;
}
.section__lede { margin: 12px auto 0; max-width: 21rem; text-wrap: pretty; }

.card {
  margin-top: 26px;
  padding: 24px 18px;
  border-radius: 16px;
  background: var(--paper);
  text-align: left;
  box-shadow: 0 22px 36px -26px rgba(63, 18, 29, 0.75);
}

/* ---------- Forms ---------- */

.field { margin-bottom: 16px; min-width: 0; }

label { display: block; margin-bottom: 6px; font-weight: 700; font-size: 0.9375rem; color: var(--red); }
.optional { font-weight: 400; font-size: 0.8125rem; }

input[type="text"], input[type="tel"], select {
  width: 100%;
  min-height: 54px;
  padding: 12px 14px;
  border: 1.5px solid var(--red);
  border-radius: 10px;
  background: var(--paper);
  color: var(--red);
  font: 400 1.0625rem/1.3 var(--font-ui);   /* 16px+ stops iOS zooming on focus */
  appearance: none;
}
input::placeholder { color: var(--red); opacity: 1; }
input[aria-invalid="true"], select[aria-invalid="true"] { border-width: 2.5px; }

select {
  padding-right: 34px;
  text-overflow: ellipsis;
  background-image: linear-gradient(45deg, transparent 50%, var(--red) 50%), linear-gradient(135deg, var(--red) 50%, transparent 50%);
  background-position: right 18px center, right 12px center;
  background-size: 6px 6px;
  background-repeat: no-repeat;
}

:focus-visible { outline: 3px solid var(--red); outline-offset: 3px; }
.card :focus-visible { outline-color: var(--red); }

.help { margin: 8px 0 18px; font-size: 0.875rem; line-height: 1.45; text-align: center; }
.help:last-child { margin-bottom: 0; }

.form-error {
  margin-bottom: 14px;
  padding: 12px 14px;
  border-left: 5px solid var(--red);
  border-radius: 6px;
  background: var(--paper);
  color: var(--red);
  font-weight: 500;
  text-align: left;
}

.button {
  display: block;
  width: 100%;
  min-height: 56px;
  padding: 16px 20px;
  border: 1.5px solid var(--red);
  border-radius: 999px;
  background: var(--red);
  color: var(--paper);
  font: 700 0.875rem/1.3 var(--font-ui);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  text-align: center;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s;
}
.button:active { transform: scale(0.98); }
.button[disabled] { opacity: 0.7; cursor: progress; }
.button--ghost { background: transparent; color: var(--red); }

.link {
  display: block;
  margin: 12px auto 0;
  padding: 10px 6px;
  border: 0;
  background: none;
  color: var(--red);
  font: 500 0.9375rem var(--font-ui);
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}

/* ---------- Confirmation ---------- */

.confirm { text-align: center; }
.confirm:focus { outline: none; }
.confirm__seal {
  width: 58px;
  height: 58px;
  margin: 4px auto 14px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--red);
  color: var(--paper);
}
.confirm__seal svg { width: 30px; height: 30px; }
.confirm h3 { font-family: var(--font-display); font-weight: 400; font-size: 1.6rem; line-height: 1.15; color: var(--red); }
.confirm #address-summary { margin-top: 10px; white-space: pre-line; }

/* ---------- Mailing address postcard ---------- */

/* Wider than the reading column: the section reaches out evenly on both
   sides (negative margins, so it never fights the .rise transform). */
.postcard-section {
  margin-top: 50px;          /* a little closer to the location than other sections */
  --postcard: #F9E8E8;       /* a breath lighter than the page blush */
  --postcard-width: min(46rem, 100vw - 2 * var(--gutter));
  margin-inline: calc((100% - var(--postcard-width)) / 2);
  text-align: left;
}
.postcard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 1.5px minmax(0, 1fr);
  column-gap: clamp(18px, 4vw, 34px);
  padding: clamp(22px, 4.5vw, 40px);
  border: 1.5px solid var(--red);
  border-radius: 6px;
  background: var(--postcard);
  color: var(--red);
  box-shadow: 0 22px 36px -28px rgba(63, 18, 29, 0.7);
}

/* Scroll entrance (app.js): the whole card waits, then fades up once when ~18% is on screen.
   Without JavaScript, IntersectionObserver or with reduced motion, it is simply shown. */
.postcard.is-waiting { opacity: 0; transform: translateY(12px); }
.postcard.is-entering { transition: opacity 0.8s ease, transform 0.8s cubic-bezier(.2, .7, .2, 1); }

/* Left: the message, headline at the top and the note towards the foot. */
.postcard__message { display: flex; flex-direction: column; gap: 16px; }
/* Handwritten heading: the hand-lettering image, the postcard's focal point. It scales with
   the column (proportions from its width/height), never stretched or cropped. */
.postcard .postcard__lettering { margin: 0; line-height: 0; }
.postcard__lettering img { display: block; width: 100%; max-width: 24rem; height: auto; margin: 0 auto 0 0; }   /* flush left */
.postcard__lede { max-width: 17rem; font-size: 0.75rem; line-height: 1.5; letter-spacing: 0.12em; opacity: 0.85; text-wrap: pretty; }   /* small and quiet beside the lettering */

.postcard__rule { background: var(--red); margin-top: clamp(40px, 12vw, 96px); }

/* Right: stamp, then the writing lines. */
.postcard__address { display: flex; flex-direction: column; min-width: 0; }
.postcard__stamp { width: clamp(156px, 25vw, 198px); height: auto; margin: -6px 0 18px auto; color: var(--red); overflow: visible; }
.postcard__stamp text { font-family: var(--font-display); }
.postmark { opacity: 0.86; }   /* a little faded, like a real hand-stamped cancellation */
.postmark__ring { font: 400 6.4px var(--font-ui); letter-spacing: 0.16em; fill: currentColor; }
.postmark__mono { font: 400 14.5px var(--font-ui); fill: currentColor; }

/* Address fields: the same quiet stationery as the opening form. Small serif labels, transparent
   fields with a thin red rule, red 16px text, the rule thickening to 2px on focus. */
.postcard .field { margin-bottom: 18px; }
.postcard label { margin: 0; font: 400 0.8125rem/1.3 var(--font-note); letter-spacing: 0.02em; text-transform: none; color: var(--red); }
.postcard .optional { font: inherit; opacity: 0.75; }
.postcard input[type="text"], .postcard select {
  box-sizing: border-box;
  height: 40px;
  min-height: 0;
  margin: 0;
  padding: 8px 0 6px;
  border: 0;
  border-bottom: 1px solid var(--red);
  border-radius: 0;
  background-color: transparent;
  box-shadow: none;
  outline: none;
  color: var(--red);
  -webkit-text-fill-color: var(--red);
  caret-color: var(--red);
  font: 400 1rem/1.5 var(--font-note);   /* 16px: phones don't zoom */
  -webkit-appearance: none;
  appearance: none;
}
/* Country: a small chevron like the opening form's code selector. */
.postcard select {
  padding-right: 22px;
  background: transparent url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 6'%3E%3Cpath d='M1 1l4 4 4-4' fill='none' stroke='%23CF2104' stroke-width='1.2'/%3E%3C/svg%3E") no-repeat right 3px center / 9px 6px;
}
.postcard input[type="text"]:focus, .postcard select:focus { outline: none; border-bottom-width: 2px; padding-bottom: 5px; }
.postcard input[aria-invalid="true"], .postcard select[aria-invalid="true"] { border-bottom-width: 2px; padding-bottom: 5px; }
/* Autofill: cover the browser's yellow/blue with the postcard colour and keep the text red. */
.postcard input:-webkit-autofill,
.postcard input:-webkit-autofill:hover,
.postcard input:-webkit-autofill:focus {
  -webkit-text-fill-color: var(--red);
  -webkit-box-shadow: 0 0 0 1000px var(--postcard) inset;
  box-shadow: 0 0 0 1000px var(--postcard) inset;
  caret-color: var(--red);
  transition: background-color 600000s 0s, color 600000s 0s;
}
.postcard input:autofill { background: var(--postcard); color: var(--red); }
/* "I'll fill out my mailing address later": the whole line tappable, in the form's serif. */
.postcard .later {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  margin: 2px 0 0;
  font: 400 0.9375rem/1.35 var(--font-note);
  letter-spacing: 0;
  text-transform: none;
  color: var(--red);
  cursor: pointer;
}
/* A thin red box; ticked, it fills red with a blush tick. */
.postcard .later input {
  flex: none;
  width: 20px;
  height: 20px;
  margin: 0;
  border: 1px solid var(--red);
  border-radius: 3px;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.postcard .later input:checked {
  background: var(--red) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath d='M5 10.5l3.2 3.2L15 7' fill='none' stroke='%23EFCCC9' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E") center / 100% no-repeat;
}
.postcard .later input:focus-visible { outline: 1.5px solid var(--red); outline-offset: 3px; }
.postcard .form-error {
  margin: 10px 0 0;
  padding: 2px 0 2px 10px;
  border-left-width: 2px;
  border-radius: 0;
  background: transparent;
  font: 400 0.875rem/1.4 var(--font-note);
}
/* The opening form's compact rounded red button, blush serif lettering. */
.postcard__submit {
  display: block;
  min-width: 168px;
  height: 44px;
  margin: 18px auto 0;
  padding: 0 22px;
  border: 1px solid var(--red);
  border-radius: 999px;
  background: var(--red);
  box-shadow: none;
  color: var(--blush);
  font: 400 0.9375rem/1 var(--font-note);
  letter-spacing: 0.06em;
  white-space: nowrap;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
}
.postcard__submit:focus { outline: none; }
.postcard__submit:focus-visible { outline: 1.5px solid var(--red); outline-offset: 3px; }
.postcard__submit[disabled] { opacity: 0.45; cursor: default; }
.confirm__text { margin-top: 10px; }
/* Confirmations on the postcard: the heading stays in the display face, the rest in the form's serif. */
.postcard .confirm p, .postcard .confirm .link { font: 400 1rem/1.5 var(--font-note); letter-spacing: 0; text-transform: none; }
.postcard .confirm #address-summary { margin-top: 6px; }
.postcard .confirm { margin: auto 0; padding: 8px 0; color: var(--red); }

/* Two columns only while each half is comfortably wide (about 16rem of writing line).
   Narrower: heading and stamps on top, full-width fields below, no divider. */
@media (max-width: 719px) {
  .postcard { grid-template-columns: minmax(0, 1fr); row-gap: 14px; }
  .postcard__message { gap: 12px; }
  .postcard__lettering img { width: calc(100% + 14px); max-width: none; margin: 0; }   /* flush left with the fields; may run 14px into the right padding */
  .postcard__lede { max-width: none; }
  .postcard__rule { display: none; }
  .postcard__stamp { width: clamp(188px, 58vw, 228px); margin: 0 0 12px auto; }   /* own row here, so a little larger */
}

/* ---------- Calendar ---------- */

/* Smaller than the names: a quiet label for the button beneath it. */
/* Heading, then the garland, the shot glass, and the button, each its own step with clear gaps. */
.cal__picado { width: min(80vw, 18rem); height: auto; margin: 0 auto; overflow: visible; }
/* Scroll parallax (app.js): the garland and the glasses start a little higher (up to 24px and
   14px) and settle into place as the page bottom arrives, so they never move toward the button. */
.cal__picado, .cal__drinks { transform: translate3d(0, var(--parallax, 0px), 0); }
.cal__picado-letter { font: 400 21px var(--font-calcado); fill: var(--blush); }
/* A light breeze: each flag swings about 1.5deg either way from the middle of its top edge
   (the string stays put), one smooth 6 s cycle, the flags slightly out of step. The scroll
   parallax moves the whole garland, so the two combine. Reduced motion: no sway. */
.cal__flag { transform-box: fill-box; transform-origin: 50% 0; animation: cal-breeze 6s ease-in-out infinite; }
.cal__picado > g:nth-of-type(3) .cal__flag { animation-delay: -0.8s; }
.cal__picado > g:nth-of-type(4) .cal__flag { animation-delay: -1.6s; }
.cal__picado > g:nth-of-type(5) .cal__flag { animation-delay: -2.4s; }
.cal__picado > g:nth-of-type(6) .cal__flag { animation-delay: -3.2s; }
@keyframes cal-breeze { 0%, 100% { transform: rotate(-1.5deg); } 50% { transform: rotate(1.5deg); } }
/* Two glasses, side by side and mirrored, centred under the garland and clear of the button. */
.cal__drinks { display: flex; justify-content: center; gap: 4px; margin-top: 12px; pointer-events: none; user-select: none; }
.cal__drink { display: block; width: 50px; height: auto; }
.cal__drink--flip { transform: scaleX(-1); }
.cal { margin-top: 18px; }
.cal__options { margin-top: 14px; }

/* ---------- Motion ---------- */

/* Each stem rotates around its own base (0,0 in its local drawing space). */
.sway { transform-origin: 0 0; animation: sway 5.5s ease-in-out infinite alternate; }
.sway--b { animation-duration: 6.5s; animation-delay: -2s; }
.sway--c { animation-duration: 4.8s; animation-delay: -3.4s; }



/* The save-the-date fades up in order once the opening screen has gone. */
main.is-revealed .rise { animation: rise 0.9s cubic-bezier(.2, .7, .2, 1) both; }
main.is-revealed .rise:nth-child(2) { animation-delay: 0.15s; }
main.is-revealed .rise:nth-child(3) { animation-delay: 0.3s; }
main.is-revealed .rise:nth-child(4) { animation-delay: 0.45s; }
main.is-revealed .rise:nth-child(5) { animation-delay: 0.6s; }
main.is-revealed .rise:nth-child(6) { animation-delay: 0.75s; }

@keyframes sway  { from { transform: rotate(-3.5deg); } to { transform: rotate(3.5deg); } }
@keyframes drift { from { transform: translate(-4px, 6px); opacity: 0.55; } to { transform: translate(6px, -8px); opacity: 1; } }
@keyframes rise  { from { opacity: 0; transform: translateY(22px); } }

/* Reduced motion: static illustrations, and the reveal happens without movement. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation: none !important; transition: none !important; }
  /* Still allowed: the opening screen's simple fade into the couple page. */
  .entry.is-gone { transition: opacity 0.6s ease !important; }
  /* The garland stays still; two notes simply appear between the flags. */
  .entry.is-sending .picado__note--b, .entry.is-sending .picado__note--d { opacity: 1; transform: translateY(-6px); transition: opacity 0.4s ease !important; }
}
