/* Wedding RSVP — see .claude/rules/frontend.md for the brief this implements. */

@font-face {
  font-family: "Alegreya";
  src: url("../fonts/alegreya-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alegreya";
  src: url("../fonts/alegreya-600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Alegreya";
  src: url("../fonts/alegreya-italic-500.woff2") format("woff2");
  font-weight: 500;
  font-style: italic;
  font-display: swap;
}

:root {
  /* Palette taken from the paper invitation. */
  --paper: #f7f4ef;      /* page ground: the invite's off-white */
  --card: #ffffff;       /* the form sits on a whiter card so the layers read apart */
  --ink: #3e3a3b;        /* all text: the invite's charcoal (11.2:1 on card, 10.2:1 on paper) */
  --rose: #b98aa0;       /* flower line art only; too light for text */
  --rose-deep: #8a4f6a;  /* button fill, add control, focus ring (6.2:1 on card) */
  --rule: #e8e2e5;       /* hairlines and input underlines */
  --error: #b42318;      /* required-field asterisk and message: 6.6:1 on card */

  /* 1.25 scale on a 16px base */
  --step-0: 1rem;
  --step-1: 1.25rem;
  --step-2: 1.5625rem;
  --step-3: 1.953rem;
  --step-4: 2.441rem;
  --step-5: 3.052rem;
  --step-6: 3.815rem;

  --serif: "Alegreya", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, serif;
  --gutter: 1.25rem;
  --section: 3rem;
  --foot: 9rem; /* room under the card for the bottom flower border */
  --lily: clamp(96px, 27vw, 190px); /* top-right lily width; the hero clears its height */
  --ease-out: cubic-bezier(0.2, 0.7, 0.2, 1);

  color-scheme: light;
}

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

html {
  -webkit-text-size-adjust: 100%;
  text-size-adjust: 100%;
  background: var(--paper);
}

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--serif);
  font-size: var(--step-0);
  line-height: 1.6;
  font-variant-numeric: oldstyle-nums proportional-nums;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3,
p,
ul {
  margin: 0;
}

a {
  color: var(--ink);
  text-decoration-thickness: 1px;
  text-underline-offset: 0.2em;
}

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

/* Components set their own display; the hidden attribute must still win. */
[hidden] {
  display: none !important;
}

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

/* ---------------------------------------------------------------- page and flowers */

/* The flowers are positioned against the whole page and clipped at its edges,
   so ones cut off in the invitation sit flush against the screen edge. */
.page {
  position: relative;
  overflow: hidden;
  min-height: 100vh;
  min-height: 100svh;
  padding-bottom: calc(var(--foot) + env(safe-area-inset-bottom, 0px));
}

.flowers {
  position: absolute;
  inset: 0;
  z-index: 0;
  color: var(--rose);
  pointer-events: none;
  animation: flowers-in 900ms ease-out both;
}

/* Width only: height follows each symbol's viewBox. --r is height / width,
   needed where a rotated flower is positioned by its rotated footprint. */
.fl {
  position: absolute;
  display: block;
  height: auto;
  overflow: visible;
}

/* Every traced flower is cut on one side (it ran off the invitation's edge).
   Each placement keeps that cut side against a page edge: flipped or rotated
   so the straight edge never shows in the open. */
.fl--top-right { top: 0; right: 0; width: var(--lily); }                /* cut: top, right */
.fl--top-left { top: 1.25rem; left: 0; width: clamp(30px, 8vw, 56px); }             /* cut: left */
.fl--top-1 {                        /* lily-bl (facing out) turned so its left cut lies on the top edge */
  --w: clamp(48px, 14vw, 90px);
  --r: 1.2;
  width: var(--w);
  top: 0;
  left: calc(14% + var(--w) * var(--r)); /* its footprint starts at 14% */
  transform-origin: left top;
  transform: rotate(90deg);
}
.fl--top-2 {                        /* petals-l2 turned so its left cut lies on the top edge */
  --w: clamp(52px, 15vw, 96px);
  --r: 1.2;
  width: var(--w);
  top: 0;
  left: calc(40% + var(--w) * var(--r)); /* its footprint starts at 40% */
  transform-origin: left top;
  transform: rotate(90deg);
}
.fl--left-1 { top: 27%; left: 0; width: clamp(64px, 20vw, 130px); }                 /* cut: left */
.fl--right-1 { top: 36%; right: 0; width: clamp(80px, 24vw, 160px); }               /* cut: right */
.fl--left-2 { top: 50%; left: 0; width: clamp(76px, 22vw, 160px); }                 /* cut: left */
.fl--right-2 { top: 62%; right: 0; width: clamp(56px, 16vw, 110px); }               /* cut: right */
.fl--left-3 { top: 72%; left: 0; width: clamp(70px, 20vw, 140px); transform: scaleX(-1); }  /* mirrored: cut left */
.fl--right-3 { top: 27%; right: 0; width: clamp(56px, 16vw, 110px); transform: scaleX(-1); } /* mirrored: cut right */

/* Bottom border: corners plus two blooms turned so their cut edge lies on the
   bottom of the page. */
.fl--bottom-1 { bottom: 0; left: 0; width: clamp(80px, 22vw, 150px); }              /* cut: left */
.fl--bottom-4 { bottom: 0; right: 0; width: clamp(96px, 28vw, 190px); transform: scaleY(-1); } /* flipped: cut bottom, right */
.fl--bottom-2 {                     /* petals-l2 turned so its left cut lies on the bottom edge */
  --w: clamp(56px, 16vw, 110px);
  --r: 1.2;
  width: var(--w);
  bottom: 0;
  left: calc(30% + var(--w) * var(--r));
  transform-origin: left bottom;
  transform: rotate(-90deg);
}
.fl--bottom-3 {                     /* bloom-r1 turned so its right cut lies on the bottom edge */
  --w: clamp(60px, 17vw, 115px);
  --r: 1.074;
  width: var(--w);
  bottom: 0;
  right: calc(30% + var(--w) * var(--r));
  transform-origin: right bottom;
  transform: rotate(90deg);
}

@keyframes flowers-in {
  from {
    opacity: 0;
  }
}

.hero {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.35rem;
  /* Start below the top-right lily (height = 1.32 x width) so no flower line
     ever sits behind the names. */
  padding: calc(var(--lily) * 1.42 + env(safe-area-inset-top, 0px)) var(--gutter) 2rem;
  text-align: center;
  /* Stacked like the invitation. The traced lettering has small lowercase
     (4.75% of "Abdulmuizz"'s width) under tall swashes, so the names use
     most of the screen width to keep the letters readable: about 16.5px
     lowercase at 390px wide, about 27px on desktop. Hajra is 0.446 of
     Abdulmuizz at the same scale, so the two keep the invite's proportions.
     The flowers beside the hero text are sized from it too. */
  --name-w: min(calc(100vw - 2.5rem), 27rem);
}

.hero__names {
  display: flex;
  flex-direction: column;
  align-items: center;
  font-size: clamp(var(--step-4), 12vw, var(--step-5)); /* sets the gap between the names */
  line-height: 1;
}

/* The invitation's lettering, traced into static/img/names.svg with smooth
   outlines at the page's weight (tools/trace_names.py). Width only: height
   follows the viewBox. Filled with currentColor, so it is --ink. */
.hero__name {
  display: block;
  height: auto;
}

.hero__name--first {
  width: var(--name-w);
}

.hero__name--second {
  width: calc(var(--name-w) * 0.446);
}

/* The row between the names keeps the height the "&" had (0.8em of the
   heading), so the names sit where they did. The word is the invitation's
   spaced serif capitals, in the same Alegreya as "The wedding of". */
.hero__amp {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 0.8em;
  height: 1em;
}

.hero__and {
  font-size: var(--step-0);
  font-weight: 400;
  letter-spacing: 0.18em;
  margin-right: -0.18em; /* the spacing trails the D; this keeps AND centred */
}

/* "The wedding of" and the date: the page's Alegreya, not the traced script. */
.hero__lead,
.hero__date {
  font-size: var(--step-1);
  letter-spacing: 0.01em;
}

.hero__lead {
  position: relative;
}

/* Flowers beside the hero text. Each sits inside the line it flanks, so it
   follows that line at every width. The line is centred, so 50% - 50vw from
   its edge is the screen's edge, where each flower's cut side goes. Sized
   from the names, so the gaps to the lettering scale with it. */
.fl--hero {
  color: var(--rose);
  pointer-events: none;
  animation: flowers-in 900ms ease-out both;
}

.fl--by-lead {                      /* bloom-bl, facing out: cut left */
  width: calc(var(--name-w) * 0.19);
  left: calc(50% - 50vw);
  bottom: -0.25rem;
}

.fl--by-and-left {                  /* lily-bl, facing out: cut left, beside AND and Hajra */
  width: calc(var(--name-w) * 0.24);
  left: calc(50% - 50vw);
  top: 0;
}

.fl--by-and-right {                 /* petals-l2, mirrored: cut right */
  width: calc(var(--name-w) * 0.22);
  right: calc(50% - 50vw);
  top: 0.5rem;
  transform: scaleX(-1);
}

/* ---------------------------------------------------------------- paper */

/* The form card: white on the off-white page, on every screen size. */
.paper {
  position: relative;
  z-index: 1;
  width: calc(100% - 2rem);
  max-width: 34rem;
  margin: 0 auto;
  padding: 1.75rem var(--gutter) 2.5rem;
  border: 1px solid var(--rule);
  border-radius: 1rem;
  background: var(--card);
  box-shadow:
    0 1px 2px rgba(62, 58, 59, 0.05),
    0 14px 36px -14px rgba(62, 58, 59, 0.18);
}

.intro {
  text-align: center;
  text-wrap: balance;
}

.intro__welcome {
  font-size: var(--step-1);
  line-height: 1.45;
}

/* Venue and time: one line each, with a small line icon in the text colour. */
.intro__meta {
  margin-top: 0.5rem;
  font-variant-numeric: lining-nums; /* postcode and time read better in lining figures */
}

.intro__welcome + .intro__meta {
  margin-top: 0.75rem;
}

/* The reply deadline: set a little apart from the venue and time. */
.intro__meta--deadline {
  margin-top: 0.75rem;
}

.intro__meta strong {
  font-weight: 600;
}

.intro__meta svg {
  width: 1em;
  height: 1em;
  margin-right: 0.1em;
  vertical-align: -0.14em;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
}

h2 {
  font-size: var(--step-3);
  font-weight: 600;
  line-height: 1.2;
  letter-spacing: -0.005em;
}

h3 {
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.3;
}

h2:focus {
  outline: none;
}

.section,
.view > .section:first-of-type {
  margin-top: var(--section);
}

.state,
.review {
  margin-top: var(--section);
}

.state p,
.review > p {
  margin-top: 0.75rem;
}

.notice {
  margin-top: var(--section);
  padding-left: 1rem;
  border-left: 2px solid var(--rose-deep);
}

/* ---------------------------------------------------------------- name rows */

.rows {
  margin-top: 1rem;
}

.row + .row {
  margin-top: 1.5rem;
  padding-top: 0.25rem;
  border-top: 1px solid var(--rule);
}

.row__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 2.75rem;
}

.row__title {
  font-size: var(--step-0);
  font-style: italic;
}

.row__remove {
  display: inline-grid;
  place-items: center;
  width: 2.75rem;
  height: 2.75rem;
  margin-right: -0.75rem;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: none;
  color: var(--ink);
  cursor: pointer;
}

.row__remove svg {
  width: 1.125rem;
  height: 1.125rem;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.75;
  stroke-linecap: round;
}

.row__fields {
  display: grid;
  gap: 1rem;
}

@media (min-width: 480px) {
  .row__fields {
    grid-template-columns: 1fr 1fr;
  }
}

/* ---------------------------------------------------------------- fields */

.field {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

label {
  font-size: var(--step-0);
  font-weight: 600;
  line-height: 1.4;
}

.hint,
.helper {
  font-size: var(--step-0);
  line-height: 1.5;
}

/* Sits directly under the heading, above the rows, so it stays put as rows are added. */
.helper {
  margin-top: 0.5rem;
}

.hint {
  margin-top: 0.125rem;
}

input[type="text"],
textarea {
  width: 100%;
  min-height: 2.75rem;
  margin-top: 0.25rem;
  padding: 0.5rem 0 0.4rem;
  border: 0;
  border-bottom: 2px solid var(--rule);
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font: inherit;
  font-size: max(16px, var(--step-1)); /* 16px floor stops iOS zooming on focus */
  line-height: 1.35;
  font-variant-numeric: lining-nums;
  -webkit-appearance: none;
  appearance: none;
}

input[type="text"]::placeholder,
textarea::placeholder {
  color: var(--ink);
  opacity: 0.55;
}

textarea {
  display: block;
  margin-top: 0.5rem;
  padding: 0.5rem 0.625rem;
  font-size: 16px; /* smaller than the name inputs, but never under 16px (iOS zoom) */
  border: 2px solid var(--rule);
  resize: vertical;
  min-height: 6rem;
}

input[type="text"]:focus,
textarea:focus {
  border-color: var(--ink);
}

input[type="text"]:focus-visible,
textarea:focus-visible {
  outline-offset: 4px;
}

input[aria-invalid="true"] {
  border-color: var(--error);
}

/* Required-field error: a red asterisk after the label plus a message under the
   input. The words carry the meaning, so it never relies on colour alone. */
.field__req,
.field__error {
  color: var(--error);
  font-weight: 600;
}

.field__error {
  margin-top: 0.375rem;
  line-height: 1.4;
}

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

button {
  font: inherit;
  -webkit-tap-highlight-color: transparent;
}

.add {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-height: 2.75rem;
  margin-top: 0.5rem;
  margin-left: -0.25rem;
  padding: 0 0.25rem;
  border: 0;
  background: none;
  color: var(--rose-deep);
  font-size: var(--step-0);
  font-weight: 600;
  cursor: pointer;
}

.add svg {
  width: 1em;
  height: 1em;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
}

.no-js .add {
  display: none;
}

.primary,
.secondary {
  display: block;
  width: 100%;
  min-height: 3.5rem;
  padding: 0.75rem 1.5rem;
  border-radius: 999px;
  font-size: var(--step-1);
  font-weight: 600;
  line-height: 1.2;
  cursor: pointer;
}

.primary {
  border: 0;
  background: var(--rose-deep);
  color: var(--card);
}

.primary:disabled {
  cursor: progress;
}

.secondary {
  border: 2px solid var(--ink);
  background: transparent;
  color: var(--ink);
}

/* ---------------------------------------------------------------- review */

.review__names {
  margin-top: 1.5rem;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}

.review__names li {
  padding: 0.75rem 0;
  border-bottom: 1px solid var(--rule);
  font-size: var(--step-2);
  line-height: 1.3;
  overflow-wrap: anywhere;
  font-variant-numeric: lining-nums;
}

.review h3 {
  margin-top: 2rem;
}

.review__dietary {
  margin-top: 0.25rem;
  white-space: pre-line;
  overflow-wrap: anywhere;
}

.review__dietary.is-empty {
  font-style: italic;
}

.send-error {
  margin-top: 2rem;
  padding-left: 1rem;
  border-left: 2px solid var(--rose-deep);
  font-weight: 600;
}

.review__actions {
  display: grid;
  gap: 0.75rem;
  margin-top: 2rem;
}

/* ---------------------------------------------------------------- desktop */

/* Desktop needs height too: a landscape phone (e.g. 844×390) keeps the phone layout. */
@media (min-width: 768px) and (min-height: 560px) {
  :root {
    --foot: 12rem;
    --lily: clamp(190px, 20vw, 300px);
  }

  .hero {
    padding-top: clamp(4rem, 12vh, 7rem);
    padding-bottom: 2.5rem;
    gap: 0.5rem;
  }

  /* Portrait tablets: the one-line names reach the corner lily, so start
     below it as on phones. */
  @media (max-width: 1100px) {
    .hero {
      padding-top: calc(var(--lily) * 1.3);
    }
  }

  .hero {
    /* Room between the flower sprays: about 30px lowercase at 1280 wide. */
    --name-w: min(62vw, 36rem);
  }

  .hero__names {
    font-size: var(--step-5);
  }

  /* The invitation sizes AND to the names; theirs are bigger here. */
  .hero__and {
    font-size: var(--step-1);
  }

  /* The desktop side sprays already fill the space beside the hero. */
  .fl--hero {
    display: none;
  }

  .add {
    font-size: var(--step-1);
  }

  .paper {
    max-width: calc(34rem + 7rem);
    padding: 3rem 3.5rem 3.5rem;
    border-radius: 1.25rem;
  }

  /* More room beside the card: bigger, fuller sprays down both sides. */
  .fl--top-left { width: clamp(56px, 6vw, 90px); top: 2rem; }
  .fl--left-1 { width: clamp(130px, 14vw, 210px); top: 26%; }
  .fl--right-1 { width: clamp(160px, 17vw, 260px); top: 34%; }
  .fl--left-2 { width: clamp(150px, 15vw, 230px); top: 44%; }
  .fl--right-2 { width: clamp(110px, 11vw, 170px); top: 58%; }
  .fl--left-3 { width: clamp(140px, 15vw, 230px); top: 68%; }
  .fl--right-3 { width: clamp(110px, 11vw, 170px); top: 14%; }
  .fl--bottom-1 { width: clamp(150px, 15vw, 220px); }
  .fl--bottom-4 { width: clamp(190px, 19vw, 290px); }
  .fl--bottom-2 { --w: clamp(110px, 11vw, 160px); left: calc(34% + var(--w) * var(--r)); }
  .fl--bottom-3 { --w: clamp(120px, 11vw, 170px); right: calc(34% + var(--w) * var(--r)); }
  /* Top border: sized with the side sprays, and pushed out to the sides so
     they hang beside the centred hero text, never above it. The right one
     starts at 66%, or further left if it would reach the corner lily. */
  .fl--top-1 { --w: clamp(110px, 11vw, 210px); left: calc(9% + var(--w) * var(--r)); }
  .fl--top-2 {
    --w: clamp(100px, 10vw, 190px);
    left: calc(min(66%, 100% - var(--lily) - var(--w) * var(--r) - 1rem) + var(--w) * var(--r));
  }
}

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

/* The only non-interactive motion is the flowers fading in once on load
   (.flowers and .fl--hero above). Rows, review and send transitions are handled in rsvp.js. */

@media (prefers-reduced-motion: reduce) {
  .flowers,
  .fl--hero {
    animation: none;
  }

  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
  }
}
