/* ==========================================================================
   Fonts — self-hosted.
   Loading these from Google meant two extra cross-origin handshakes
   (fonts.googleapis.com for the CSS, then fonts.gstatic.com for the file)
   before the real face could paint, which is what produced the flash of
   fallback text on reload. Served from our own origin and preloaded in the
   <head>, they arrive with the stylesheet instead.
   ========================================================================== */

@font-face {
  font-family: 'Anton';
  src: url('/fonts/anton-latin.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* One variable file covers every weight the UI uses. */
@font-face {
  font-family: 'Fredoka';
  src: url('/fonts/fredoka-latin-var.woff2') format('woff2');
  font-weight: 300 700;
  font-style: normal;
  font-display: swap;
}

/* Metric-matched fallbacks. If the webfont ever loses the race (cold load on a
   slow link), these keep the line lengths identical so nothing reflows — only
   the letterforms differ. Ratios measured against the real faces at 100px;
   each face names a single local font so its size-adjust is actually correct. */
@font-face {
  font-family: 'Anton Fallback';
  src: local('Impact');
  size-adjust: 96.4%;
}
@font-face {
  font-family: 'Anton Fallback 2';
  src: local('Arial Narrow');
  size-adjust: 91.3%;
}
@font-face {
  font-family: 'Fredoka Fallback';
  src: local('Arial'), local('Helvetica'), local('Liberation Sans');
  size-adjust: 100.4%;
}

/* ==========================================================================
   Parker's Super Mario evite
   Palette + type are lifted from the printed invitation.
   ========================================================================== */

:root {
  --red:    #e52521;
  --blue:   #049cd8;
  --green:  #43b047;
  --yellow: #fbd000;
  --ink:    #141414;
  --grey:   #8b8b8b;

  --paper:  #ffffff;
  --page:   #eef2f6;

  --display: 'Anton', 'Anton Fallback', 'Anton Fallback 2', Impact, 'Arial Narrow', sans-serif;
  --ui: 'Fredoka', 'Fredoka Fallback', ui-rounded, system-ui, -apple-system, sans-serif;

  /* Everything inside the invite scales off this, so the poster keeps its
     proportions from a 320px phone up to the 720px cap. */
  --invite-w: 720px;
  --radius: 16px;
  --shadow: 0 10px 30px rgba(20,20,20,.10), 0 2px 6px rgba(20,20,20,.06);
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  background: var(--page);
  color: var(--ink);
  font-family: var(--ui);
  /* Portrait poster: full width, height just scrolls. */
  overflow-x: hidden;
}

img { max-width: 100%; display: block; }

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

.skip {
  position: absolute; left: -9999px; top: 0;
  background: var(--ink); color: #fff; padding: 10px 16px; z-index: 999;
}
.skip:focus { left: 8px; top: 8px; }

#app {
  position: relative;         /* deliberately no z-index: the flyers need to
                                 paint between this background and the panels */
  max-width: var(--invite-w);
  margin: 0 auto;
  background: var(--paper);
  min-height: 100vh;
  padding-bottom: 24px;       /* contains the last panel's margin, which would
                                 otherwise collapse out through overflow-x:clip */
  box-shadow: var(--shadow);
  overflow-x: clip;           /* characters bleed off the edge, no h-scroll */
}

/* ==========================================================================
   Flying ? blocks
   ========================================================================== */

/* Sits above the invite artwork and copy, below the panels — so the blocks
   drift across the poster without ever landing on top of a form field. */
#flyers {
  position: fixed;
  inset: 0;
  z-index: 3;
  pointer-events: none;
  overflow: hidden;
}
#flyers img {
  position: absolute;
  top: 0; left: 0;
  width: 90px;
  opacity: .9;
  will-change: transform;
  filter: drop-shadow(0 6px 10px rgba(0,0,0,.12));
}

/* ==========================================================================
   The invitation
   ========================================================================== */

.invite {
  position: relative;
  padding-bottom: 8px;
  background: var(--paper);
}

/* Each band is its own positioning context so characters stay anchored to the
   copy they sit beside, even as the text reflows. */
.band { position: relative; }

/* A character illustration. Position and size come from three custom
   properties in art.css, all percentages of the invite width — including the
   vertical one, because a percentage margin resolves against the containing
   block's WIDTH. That keeps the composition proportional at every screen size
   and gives the tuner one uniform model to edit. */
.ch {
  position: absolute;
  top: 0;
  left: var(--ch-x, 0%);
  margin-top: var(--ch-y, 0%);
  width: var(--ch-w, 25%);
  z-index: 0;
  pointer-events: none;
  user-select: none;
}

/* Centred, in-flow artwork (logo, boo, name, age block) uses the same two
   knobs so the tuner treats every asset identically. */
.band-logo .logo,
.band-boo .boo,
.band-name .name,
.band-age .agebox {
  width: var(--ch-w, 30%);
  margin-left: auto;
  margin-right: auto;
  margin-top: var(--ch-y, 0%);
}

/* Copy always sits above the artwork. */
.band > .copy { position: relative; z-index: 2; }

/* ---- band 1: logo ---- */
.band-logo { padding: 3% 0 1%; }

/* ---- band 2: boo ---- */
.band-boo { padding: 0 0 4px; }

/* ---- band 3: name ---- */
.band-name { padding: 4px 0 0; }

/* ---- band 4: age block ---- */
.band-age { padding: 6px 0 14px; }
.band-age .agebox {
  image-rendering: pixelated;   /* it's a small sprite — keep the edges crisp */
  animation: bob 2.6s ease-in-out infinite;
}
@keyframes bob {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-9px); }
}

/* ---- band 5: the details ---- */
.band-details { padding: 0 0 10px; }
.details {
  width: 62%;
  margin: 0 auto;
  text-align: center;
  font-family: var(--display);
  letter-spacing: .01em;
  line-height: 1.16;
  text-transform: uppercase;
}
.details p { margin: 0; }
.details .venue { color: var(--red);   font-size: clamp(17px, 4.9vw, 32px); }
.details .when  { color: var(--green); font-size: clamp(17px, 4.9vw, 32px); }
.details .extra { color: var(--grey);  font-size: clamp(15px, 4.4vw, 28px); }
.details .rsvp  { color: var(--blue);  font-size: clamp(14px, 4.0vw, 25px); }
.details .rsvp a { color: inherit; text-decoration: none; }
.details .rsvp a:hover { text-decoration: underline; }
.details .venue a { color: inherit; text-decoration: none; }
.details .venue a:hover { text-decoration: underline; }

/* The chunky dashed rules between each block on the printed invite. */
.dashes {
  height: 6px;
  margin: 12px auto;
  width: 74%;
  background-image: repeating-linear-gradient(
    to right, var(--ink) 0 18px, transparent 18px 32px);
  background-size: 32px 6px;
  background-repeat: repeat-x;
  background-position: center;
}


/* ---- band 6: call to action + bottom characters ---- */
.band-cta { padding: 1% 0 18px; min-height: min(30vw, 216px); }
.cta-wrap { position: relative; z-index: 4; text-align: center; padding: 0 6%; }

/* Floating coins — decorative, dropped in by JS. */
.coin {
  position: absolute;
  width: var(--coin-w, 5.6%);
  z-index: 1;
  pointer-events: none;
  animation: coinspin 3s linear infinite;
}
@keyframes coinspin {
  0%, 100% { transform: rotateY(0deg)   translateY(0); }
  50%      { transform: rotateY(180deg) translateY(-6px); }
}

/* ==========================================================================
   Buttons + blocks
   ========================================================================== */

.btn {
  display: inline-block;
  font-family: var(--display);
  text-transform: uppercase;
  letter-spacing: .04em;
  font-size: clamp(18px, 4.6vw, 24px);
  color: #fff;
  background: var(--red);
  border: 3px solid var(--ink);
  border-radius: 999px;
  padding: 14px 34px;
  text-decoration: none;
  cursor: pointer;
  transition: transform .08s ease, filter .15s ease;
  -webkit-tap-highlight-color: transparent;
}
.btn:hover { filter: brightness(1.06); }
.btn:active { transform: translateY(1px); }
.btn:disabled, .btn[aria-disabled="true"] { opacity: .55; cursor: not-allowed; }
.btn.blue  { background: var(--blue); }
.btn.green { background: var(--green); }
.btn.ghost {
  background: #fff; color: var(--ink);
  font-size: clamp(15px, 3.4vw, 18px); padding: 10px 22px;
}
.btn.sm { font-size: 15px; padding: 8px 16px; }
.btn-row { display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; }

.hint { font-size: 15px; color: #5a6673; margin: 10px 0 0; line-height: 1.55; }

/* ==========================================================================
   Panels (RSVP form, guest list, host)
   ========================================================================== */

.panel {
  position: relative;
  z-index: 4;
  margin: 0 4% 22px;
  padding: 22px 20px;
  background: #fff;
  border: 3px solid var(--ink);
  border-radius: var(--radius);
}
.panel + .panel { margin-top: 0; }
/* the container's padding provides the trailing space instead */
#main > *:last-child { margin-bottom: 0; }

.panel h2 {
  font-family: var(--display);
  text-transform: uppercase;
  font-size: clamp(22px, 6vw, 30px);
  margin: 0 0 4px;
  letter-spacing: .01em;
}
.panel h3 {
  font-family: var(--display);
  text-transform: uppercase;
  font-size: 19px;
  letter-spacing: .04em;
  margin: 22px 0 10px;
  color: #555;
}
.panel > p { margin: 0 0 14px; font-size: 16px; line-height: 1.6; color: #3b4149; }

.panel-tag {
  display: inline-block;
  font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
  padding: 5px 11px; border-radius: 999px; background: var(--yellow); color: var(--ink);
  margin-bottom: 10px;
}

/* ---- forms ---- */
.field { margin-bottom: 14px; }
.field label {
  display: block; font-weight: 600; font-size: 16px; margin-bottom: 6px; color: #2a2f36;
}
.field .req { color: var(--red); }

input[type=text], input[type=email], input[type=password], textarea, select {
  width: 100%;
  font: inherit;
  font-size: 16px;              /* 16px stops iOS zooming on focus */
  padding: 11px 13px;
  border: 3px solid #d8dee6;
  border-radius: 11px;
  background: #fff;
  color: var(--ink);
}
input.invalid, textarea.invalid {
  border-color: var(--red);
  box-shadow: 0 0 0 4px rgba(229,37,33,.14);
}
.field-error {
  margin: 7px 0 0; font-size: 15px; font-weight: 600; color: var(--red); line-height: 1.45;
}

input:focus, textarea:focus, select:focus {
  outline: none; border-color: var(--blue); box-shadow: 0 0 0 4px rgba(4,156,216,.16);
}
textarea { resize: vertical; min-height: 70px; }

.pair { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
/* Grid/flex children default to min-width:auto; inputs have a wide intrinsic
   size, which would otherwise push the whole page past the viewport. */
.pair > *, .choice > label, .guest-row > * { min-width: 0; }
@media (max-width: 420px) { .pair { grid-template-columns: 1fr; } }

.code-input {
  font-family: 'Courier New', monospace;
  font-size: 26px; letter-spacing: 6px; text-align: center; text-transform: uppercase;
  font-weight: bold;
}

/* Yes / no toggle */
.choice { display: grid; grid-template-columns: minmax(0,1fr) minmax(0,1fr); gap: 10px; margin-bottom: 18px; }
.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice label {
  display: block; text-align: center; cursor: pointer;
  font-family: var(--display); text-transform: uppercase; font-size: 19px; letter-spacing: .03em;
  padding: 14px 8px; border: 3px solid var(--ink); border-radius: 13px; overflow-wrap: break-word;
  background: #fff; color: var(--ink);
  transition: background .12s ease, color .12s ease, transform .08s ease;
}
.choice input:checked + label { background: var(--green); color: #fff; }
.choice input#att-no:checked + label { background: var(--grey); }
.choice input:focus-visible + label { box-shadow: 0 0 0 4px rgba(4,156,216,.35); }

/* Guest rows in the form */
.guest-row { display: grid; grid-template-columns: minmax(0,1fr) auto; gap: 10px; align-items: start; margin-bottom: 10px; }
.guest-main { display: grid; gap: 8px; min-width: 0; }

/* Adult / child picker on each guest row. Selecting by [value] works because
   it's a static attribute, so no per-row class plumbing is needed. */
.type-seg { display: inline-grid; grid-auto-flow: column; justify-content: start; gap: 6px; }
.type-seg input { position: absolute; opacity: 0; pointer-events: none; }
.type-seg label {
  cursor: pointer; font-size: 13px; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase;
  padding: 7px 15px; border: 3px solid #d8dee6; border-radius: 999px;
  background: #fff; color: #7a8697; white-space: nowrap;
  transition: background .12s ease, color .12s ease, border-color .12s ease;
}
.type-seg input[value="adult"]:checked + label {
  background: var(--blue); border-color: var(--blue); color: #fff;
}
.type-seg input[value="child"]:checked + label {
  background: var(--green); border-color: var(--green); color: #fff;
}
.type-seg input:focus-visible + label { box-shadow: 0 0 0 4px rgba(4,156,216,.3); }
.icon-btn {
  border: 3px solid var(--ink); background: #fff; border-radius: 10px;
  width: 42px; height: 46px; align-self: start; font-size: 20px; line-height: 1; cursor: pointer; color: var(--red);
  font-weight: bold;
}
.icon-btn:hover { background: #ffecec; }

.alert {
  padding: 13px 15px; border-radius: 11px; margin-bottom: 14px;
  font-size: 16px; font-weight: 500; line-height: 1.55; border: 3px solid;
}
.alert.err  { background: #fff0ef; border-color: var(--red);   color: #8d1512; }
.alert.ok   { background: #eefaf0; border-color: var(--green); color: #1f6b2b; }
.alert.info { background: #eef8fd; border-color: var(--blue);  color: #0a5b81; }
.alert.warn { background: #fffaea; border-color: #e0ab00;      color: #6d5200; }

/* ---- status chips ---- */
.chip {
  display: inline-block; font-size: 12px; font-weight: 700;
  letter-spacing: .1em; text-transform: uppercase;
  padding: 5px 10px; border-radius: 999px; white-space: nowrap;
}
.chip.pending   { background: #fff2cd; color: #7a5a00; }
.chip.confirmed { background: #dcf5e1; color: #1f6b2b; }
.chip.declined  { background: #eceff3; color: #667; }
.chip.added     { background: #e6e0ff; color: #4a2f9e; }

/* ---- guest list ---- */
.locked {
  text-align: center; padding: 26px 18px;
  background: #fbfcfe; border: 3px dashed #c8d2de; border-radius: 13px;
}
.locked .lock-box { width: 84px; margin: 0 auto 12px; animation: bob 2.6s ease-in-out infinite; }
.locked p { margin: 0; color: #48505a; line-height: 1.6; font-size: 16px; }

.guests { list-style: none; margin: 0; padding: 0; }
.guests li {
  display: flex; align-items: center; gap: 12px;
  padding: 11px 4px; border-bottom: 2px dashed #e3e8ef;
}
.guests li:last-child { border-bottom: 0; }
.guests .avatar {
  flex: 0 0 38px; height: 38px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--display); color: #fff; font-size: 17px;
}
.guests .who { font-weight: 600; font-size: 17px; }
.guests .with { font-size: 15px; color: #5a6673; margin-top: 2px; }
.guests li.is-you { background: #fffbe8; border-radius: 10px; padding-inline: 10px; }
.guests .kid-tag {
  margin-left: 6px; font-size: 11px; letter-spacing: .08em; text-transform: uppercase;
  background: #dcf5e1; color: #1f6b2b; padding: 3px 8px; border-radius: 999px; font-weight: 700;
}
.code-pill {
  background: var(--ink); color: var(--yellow); padding: 3px 9px; border-radius: 6px;
  font-size: 13px; letter-spacing: 1.5px; font-weight: bold;
}
.guests .you-tag {
  margin-left: 6px; font-size: 11px; letter-spacing: .1em; text-transform: uppercase;
  background: var(--yellow); color: var(--ink); padding: 3px 8px; border-radius: 999px; font-weight: 700;
}

.tally {
  display: flex; gap: 10px; flex-wrap: wrap; margin: 0 0 16px;
}
.tally div {
  flex: 1 1 68px; text-align: center; padding: 10px 6px;
  background: #f6f8fb; border-radius: 12px; border: 2px solid #e3e8ef;
}
.tally b { display: block; font-family: var(--display); font-size: 26px; line-height: 1.1; }
.tally .lead { background: #fff7d6; border-color: var(--yellow); }
.tally .lead b { color: var(--red); font-size: 30px; }
.tally + .tally { margin-top: -6px; }
.tally span { font-size: 12px; letter-spacing: .07em; text-transform: uppercase; color: #5f6973; }

/* ---- host table ---- */
.rsvp-card {
  border: 3px solid #e3e8ef; border-radius: 13px; padding: 14px; margin-bottom: 12px;
}
.rsvp-card.pending { border-color: var(--yellow); background: #fffdf5; }
.rsvp-card header { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.rsvp-card .nm { font-family: var(--display); font-size: 20px; text-transform: uppercase; }
.rsvp-card .meta { font-size: 15px; color: #4d5661; line-height: 1.7; margin-top: 7px; word-break: break-word; }
.rsvp-card .meta code {
  background: var(--ink); color: var(--yellow); padding: 2px 7px; border-radius: 5px;
  font-size: 12px; letter-spacing: 1px;
}
.rsvp-card .acts { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 12px; }
.danger { background: #fff !important; color: var(--red) !important; }

.filters { display: flex; gap: 8px; margin-bottom: 14px; flex-wrap: wrap; }
.filters button {
  font: inherit; font-size: 14px; font-weight: 600; cursor: pointer;
  padding: 7px 15px; border-radius: 999px; border: 3px solid #d8dee6; background: #fff; color: #3b4149;
}
.filters button[aria-pressed="true"] { background: var(--ink); color: #fff; border-color: var(--ink); }

/* ==========================================================================
   Chrome
   ========================================================================== */

.site-foot {
  position: relative; z-index: 1;
  max-width: var(--invite-w); margin: 0 auto;
  padding: 18px 12px 34px; text-align: center;
  font-size: 15px; color: #7a8492; background: var(--paper);
}
.site-foot a { color: #8794a3; text-decoration: none; margin: 0 6px; }
.site-foot a:hover { color: var(--blue); text-decoration: underline; }
.site-foot span { opacity: .5; }

.toast {
  position: fixed; left: 50%; bottom: 22px; transform: translate(-50%, 120%);
  background: var(--ink); color: #fff; padding: 12px 20px; border-radius: 999px;
  font-size: 15px; font-weight: 600; z-index: 500; max-width: 88vw; text-align: center;
  transition: transform .28s cubic-bezier(.2,.9,.3,1.3); pointer-events: none;
}
.toast.show { transform: translate(-50%, 0); }

.spinner {
  width: 26px; height: 26px; margin: 30px auto;
  border: 4px solid #e3e8ef; border-top-color: var(--blue); border-radius: 50%;
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.back-link {
  display: inline-block; margin: 16px 0 0 4%; font-size: 15px;
  color: #8794a3; text-decoration: none; position: relative; z-index: 4;
}
.back-link:hover { color: var(--blue); }

/* ==========================================================================
   Narrow phones: pull the characters further into the margins so they never
   crowd the copy, and let the detail text use more of the width.
   ========================================================================== */
@media (max-width: 460px) {
  .details { width: 70%; }
  .dashes { width: 84%; }
  #flyers img { width: 66px; }
  .panel { margin-inline: 3%; padding: 18px 15px; }
}

@media (min-width: 760px) {
  body { padding: 0; }
  #app { border-left: 1px solid #dde3ea; border-right: 1px solid #dde3ea; }
}

/* Honour the OS "reduce motion" setting everywhere. */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  #flyers { display: none; }
}
