@font-face {
  font-family: "PP Mondwest";
  src: url("Fonts/PPMondwest-Bold.woff2") format("woff2"),
       url("Fonts/PPMondwest-Bold.woff") format("woff");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Mondwest";
  src: url("Fonts/PPMondwest-Regular.woff2") format("woff2"),
       url("Fonts/PPMondwest-Regular.woff") format("woff");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "PP Neue Montreal";
  src: url("Fonts/PPNeueMontreal-SemiBold.woff2") format("woff2"),
       url("Fonts/PPNeueMontreal-SemiBold.woff") format("woff");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #dd3d00;
  --coral: #f97d50;
  --paper: #ffffff;
  --design-w: 595;
  --design-h: 842;
  --sans: "PP Neue Montreal", system-ui, sans-serif;
  --serif: "PP Mondwest", serif;
}

* { margin: 0; padding: 0; box-sizing: border-box; }

html, body {
  background: var(--paper);
  color: var(--coral);
  font-family: var(--sans);
  -webkit-font-smoothing: antialiased;
}

body {
  min-height: 100dvh;
  display: grid;
  place-items: start center;
  overflow-x: hidden;
}

.stage {
  width: min(100vw, calc(var(--design-w) * 1px));
  aspect-ratio: var(--design-w) / var(--design-h);
  position: relative;
}

.flyer {
  position: absolute;
  top: 0;
  left: 0;
  width: calc(var(--design-w) * 1px);
  height: calc(var(--design-h) * 1px);
  transform-origin: top left;
  transform: scale(calc(min(100vw, calc(var(--design-w) * 1px)) / (var(--design-w) * 1px)));
}

.flyer > * {
  position: absolute;
  text-align: center;
}

a { color: inherit; text-decoration: none; }

/* Poss Studio — 100:82618 — x=234 y=40 w=129, PP Neue Montreal SemiBold 20/-0.4px */
.studio {
  left: 234px; top: 40px; width: 129px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
}

/* Presents — 100:82619 — x=264 y=60 w=68, PP Mondwest Bold 14/-0.28px */
.presents {
  left: 264px; top: 60px; width: 68px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
}

/* Title — 100:82035 (top, red w/ white stroke) + 100:82034 (shadow, coral, +4px) */
.title,
.title-shadow {
  left: 99px; width: 397px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 80px;
  letter-spacing: -0.03em;
  line-height: 0.85;
  text-transform: capitalize;
  white-space: nowrap;
}

.title-shadow {
  top: 112px;
  color: var(--coral);
}

.title {
  top: 108px;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
  text-shadow:
    1px 0 0 var(--paper),
    -1px 0 0 var(--paper),
    0 1px 0 var(--paper),
    0 -1px 0 var(--paper),
    1px 1px 0 var(--paper),
    -1px -1px 0 var(--paper),
    1px -1px 0 var(--paper),
    -1px 1px 0 var(--paper);
}

.title > span,
.title-shadow > span { display: block; }

.title .notes-slot,
.title-shadow .notes-slot { visibility: hidden; }

/* Musical notes — 100:82047 (top, red w/ white stroke) + 100:82048 (shadow, coral, +3px) */
.notes,
.notes-shadow {
  left: 267px; width: 61px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 60px;
  letter-spacing: -0.03em;
  line-height: 0.85;
}

.notes-shadow {
  top: 260px;
  color: var(--coral);
}

.notes {
  top: 257px;
  color: var(--ink);
  text-shadow:
    1px 0 0 var(--paper),
    -1px 0 0 var(--paper),
    0 1px 0 var(--paper),
    0 -1px 0 var(--paper),
    1px 1px 0 var(--paper),
    -1px -1px 0 var(--paper),
    1px -1px 0 var(--paper),
    -1px 1px 0 var(--paper);
}

/* Date — 100:82045 — x=231 y=516 w=135, PP Neue Montreal SemiBold 20/-0.4px */
.date {
  left: 231px; top: 516px; width: 135px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
}
.date > span { display: block; }

/* URL — 100:82040 (top, red w/ white stroke) + 100:82041 (shadow, coral, +3px) */
.url,
.url-shadow {
  left: 112px; width: 370px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 56px;
  letter-spacing: -0.03em;
  line-height: 1;
}

.url-shadow {
  top: 575.5px;
  color: var(--coral);
}

.url {
  top: 572.5px;
  color: var(--ink);
  text-shadow:
    1px 0 0 var(--paper),
    -1px 0 0 var(--paper),
    0 1px 0 var(--paper),
    0 -1px 0 var(--paper),
    1px 1px 0 var(--paper),
    -1px -1px 0 var(--paper),
    1px -1px 0 var(--paper),
    -1px 1px 0 var(--paper);
}

/* I.R.L. / Online — 100:82044 — x=235 y=634 w=124, PP Mondwest Bold 14/-0.28px */
.mode {
  left: 235px; top: 634px; width: 124px;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
  white-space: pre;
}

/* Address — 100:82043 — x=162 y=652 w=273, PP Neue Montreal SemiBold 20/-0.4px */
.address {
  left: 162px; top: 652px; width: 273px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 20px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
}
.address > span { display: block; }

/* Washer — 100:82607 — x=271 y=717 w=54 h=54 */
.washer {
  left: 271px; top: 717px;
  width: 54px; height: 54px;
  display: block;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

/* Each Claude SVG is wrapped in a .claude-wrap div. The wrapper carries
   the position, size, z-index, and the group-rotation transform-origin
   that points at the washer porthole center (x=297.5, y=751.5 in flyer
   space). The inner <svg> fills the wrapper and handles its own
   pop/walk/scale transforms. */
.claude-wrap-84 { left:  91px; top: 741px; width: 48px; height: 30px; transform-origin:  206.5px 10.5px; }
.claude-wrap-88 { left: 148px; top: 729px; width: 48px; height: 42px; transform-origin:  149.5px 22.5px; }
.claude-wrap-89 { left: 202px; top: 735px; width: 54px; height: 36px; transform-origin:   95.5px 16.5px; }
.claude-wrap-87 { left: 343px; top: 726px; width: 48px; height: 45px; transform-origin:  -45.5px 25.5px; }
.claude-wrap-85 { left: 400px; top: 738px; width: 48px; height: 33px; transform-origin: -102.5px 13.5px; }
.claude-wrap-86 { left: 457px; top: 741px; width: 48px; height: 30px; transform-origin: -159.5px 10.5px; }

/* Inner SVG fills its wrapper and scales/walks from its own center-bottom. */
.claude {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  image-rendering: pixelated;
  image-rendering: crisp-edges;
}

/* RSVP — 100:82037 — x=96 y=780 w=234, PP Neue Montreal SemiBold 14/-0.28px, color ink */
.rsvp {
  left: 96px; top: 780px; width: 234px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--ink);
  white-space: pre;
}

/* BYO — 100:82038 — x=348 y=780 w=151, same type as RSVP */
.byo {
  left: 348px; top: 780px; width: 151px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  line-height: 1;
  color: var(--ink);
  white-space: pre;
}

/* Inline Mondwest spans inside RSVP/BYO (email + "Beer + Bots") and
   modal checkbox labels ("The Event", "Poss Newsletter"). */
.rsvp .serif,
.byo .serif,
.modal-check .serif {
  font-family: var(--serif);
  font-weight: 700;
  letter-spacing: -0.02em;
  text-transform: none;
}

/* ─── Disco mode ───────────────────────────────────────────── */

/* Hue cycle: applied to flyer and rain so everything shifts together.
   White/paper is unaffected by hue-rotate. */
@keyframes disco-hue-cycle {
  from { filter: hue-rotate(0deg); }
  to { filter: hue-rotate(360deg); }
}

body.disco-mode .flyer,
body.disco-mode .ascii-rain,
body.disco-mode .modal {
  animation: disco-hue-cycle 14.4s linear infinite;
}

/* Title already has transform from .flyer parent; child transforms stack fine.
   Both layers wobble together to preserve the 4px offset. */
@keyframes disco-wobble {
  0%, 100% { transform: rotate(0deg); }
  25%      { transform: rotate(-1deg); }
  75%      { transform: rotate(1deg); }
}

body.disco-mode .title,
body.disco-mode .title-shadow,
body.disco-mode .notes,
body.disco-mode .notes-shadow,
body.disco-mode .url,
body.disco-mode .url-shadow,
body.disco-mode .claude,
body.disco-mode .washer {
  animation: disco-wobble 1s linear infinite;
}

/* ASCII rain overlay. Spans sit at top:-50px (above the viewport,
   clipped by overflow: hidden) whenever disco-mode is off. Applying the
   fall animation only while disco is on guarantees each activation
   starts fresh from the top instead of popping in mid-fall. */
.ascii-rain {
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 9997;
  overflow: hidden;
}

.ascii-rain span {
  position: absolute;
  top: -50px;
  font-family: var(--serif);
  color: var(--ink);
}

body.disco-mode .ascii-rain span {
  animation: ascii-fall linear infinite;
}

@keyframes ascii-fall {
  from { transform: translateY(-50px) rotate(0deg); }
  to   { transform: translateY(calc(100dvh + 50px)) rotate(720deg); }
}

/* Claude dancing legs — toggle bottom-leg rects in alternating halves.
   Cycle: 0-25% neutral, 25-50% left up, 50-75% neutral, 75-100% right up.
   Matches dj-claude's 4-frame @ 200ms pattern (800ms total). */
@keyframes claude-leg-left {
  0%, 24.9%   { opacity: 1; }
  25%, 49.9%  { opacity: 0; }
  50%, 100%   { opacity: 1; }
}

@keyframes claude-leg-right {
  0%, 74.9%   { opacity: 1; }
  75%, 100%   { opacity: 0; }
}

body.disco-mode .claude .leg-left {
  animation: claude-leg-left 0.8s linear infinite;
}

body.disco-mode .claude .leg-right {
  animation: claude-leg-right 0.8s linear infinite;
}

/* Porthole spin — rotate around each shape's own center using fill-box.
   The shadow path lives inside a <g translate(0,3)> so its +3px offset
   survives when CSS transform (rotate) is applied to the path itself. */
.porthole,
.porthole-shadow {
  transform-origin: center;
  transform-box: fill-box;
}

@keyframes porthole-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

/* Porthole does one full rotation in lock-step with the Claude group
   spin (0.3s - 2.55s). `both` keeps rotate(0) during delay, rotate(360)
   after (visually 0). */
.porthole {
  animation: porthole-spin 2.25s 0.3s linear both;
}

body.disco-mode .porthole {
  animation: porthole-spin 2.75s linear infinite;
}

/* Flash the rightmost white button coral on disco */
@keyframes washer-button-flash {
  0%, 49.9%   { fill: #ffffff; }
  50%, 100%   { fill: #f97d50; }
}

body.disco-mode .washer-button-flash {
  animation: washer-button-flash 0.8s steps(1) infinite;
}

/* Mouth "talking" effect — .mouth-extra rects sit below each 2-pixel
   mouth, coral (blended) by default. During disco talking bursts they
   flash white, making the mouth expand from 2 pixels to a 2x2 square.
   Each character has its own duration + delay so the group looks like
   a conversation instead of synchronized mouthing. */
@keyframes mouth-talk {
  0%, 34%   { fill: #f97d50; }
  36%, 41%  { fill: #ffffff; }
  43%, 48%  { fill: #f97d50; }
  50%, 55%  { fill: #ffffff; }
  57%, 62%  { fill: #f97d50; }
  64%, 100% { fill: #f97d50; }
}

body.disco-mode .claude-84 .mouth-extra { animation: mouth-talk 2.3s steps(1) infinite; animation-delay: 0s;   }
body.disco-mode .claude-85 .mouth-extra { animation: mouth-talk 2.9s steps(1) infinite; animation-delay: 0.6s; }
body.disco-mode .claude-86 .mouth-extra { animation: mouth-talk 2.5s steps(1) infinite; animation-delay: 1.1s; }
body.disco-mode .claude-87 .mouth-extra { animation: mouth-talk 3.1s steps(1) infinite; animation-delay: 0.3s; }
body.disco-mode .claude-88 .mouth-extra { animation: mouth-talk 2.7s steps(1) infinite; animation-delay: 1.7s; }
body.disco-mode .claude-89 .mouth-extra { animation: mouth-talk 3.3s steps(1) infinite; animation-delay: 2.2s; }

/* ─── Page-load intro ───────────────────────────────────────────
   Phase 1: fade in all contextual orange text + bottom RSVP row +
           pixel characters and washer.
   Phase 2: sequentially fade in the big title lines / notes / URL.
   Each line fades both its coral shadow + red top layer together. */
@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Phase 1 — supporting elements appear together (now includes the
   washer so it's present before the group rotation kicks in).
   0.3s head-start delay gives the page a beat of empty white before
   anything appears. */
.studio, .presents, .date, .mode, .address, .rsvp, .byo,
.washer {
  animation: fade-in 0.6s 0.3s ease-out both;
}

/* Phase 2 — sequential per-row fade; each row's two layers share a delay */
.title > span:nth-child(1), .title-shadow > span:nth-child(1),
.title > span:nth-child(2), .title-shadow > span:nth-child(2),
.title > span:nth-child(4), .title-shadow > span:nth-child(4),
.title > span:nth-child(5), .title-shadow > span:nth-child(5),
.notes, .notes-shadow,
.url, .url-shadow {
  animation: fade-in 0.4s ease-out both;
}

/* 1. "6 Claudes" */
.title > span:nth-child(1),
.title-shadow > span:nth-child(1) { animation-delay: 0.9s; }

/* 2. "Jamming" */
.title > span:nth-child(2),
.title-shadow > span:nth-child(2) { animation-delay: 1.15s; }

/* 3. Musical notes */
.notes, .notes-shadow { animation-delay: 1.4s; }

/* 4. "In A" */
.title > span:nth-child(4),
.title-shadow > span:nth-child(4) { animation-delay: 1.65s; }

/* 5. "Launderette" */
.title > span:nth-child(5),
.title-shadow > span:nth-child(5) { animation-delay: 1.9s; }

/* 6. "(https://claw.dj)" — give it a longer fade so it doesn't end on
   the same beat as the group rotation and feel abrupt. */
.url, .url-shadow {
  animation-duration: 0.6s;
  animation-delay: 2.15s;
}

/* ─── Claude emerge (phase 3) ────────────────────────────────────
   Three phases per character:
   1. `claude-appear` — fades the SVG in with the washer (2.1-2.5s).
   2. `claude-wrap-spin` on the WRAPPER — all six wrappers rotate 360°
      together around the porthole center (2.5-3.5s). Because each
      wrapper's transform-origin points at the porthole and the inner
      SVG is already translated to sit at the porthole, every Claude
      appears to rotate in unison with the porthole as one group.
   3. `claude-emerge` on the inner SVG — pop + waddle, staggered per
      character starting at 3.5s. */
@keyframes claude-appear {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@keyframes claude-wrap-spin {
  from { transform: rotate(0deg); }
  to   { transform: rotate(360deg); }
}

@keyframes claude-emerge {
  /* 0-25%: jump up and out of the washer window — start at 1/3 scale
     (bottom-pinned via transform-origin) translated up by --pop-up so
     the tiny character sits just above the red rim; peak at 12.5%
     (--pop-up - 8px, half-scaled), land at 25% at full scale on the
     floor. 25-100%: waddle to the final x-position. */
  0%    { transform: translateX(var(--walk-from)) translateY(var(--pop-up))              scale(0.333333); }
  12.5% { transform: translateX(var(--walk-from)) translateY(calc(var(--pop-up) - 8px))  scale(0.666667); }
  25%   { transform: translateX(var(--walk-from)) translateY(0)                          scale(1);        }
  100%  { transform: translateX(0)                translateY(0)                          scale(1);        }
}

/* Stack in emerge order: first to move sits on top of the stack. */
.washer         { z-index: 1; }
.claude-wrap-87 { z-index: 2; } /* 6th to emerge */
.claude-wrap-89 { z-index: 3; } /* 5th */
.claude-wrap-85 { z-index: 4; } /* 4th */
.claude-wrap-88 { z-index: 5; } /* 3rd */
.claude-wrap-86 { z-index: 6; } /* 2nd */
.claude-wrap-84 { z-index: 7; } /* 1st — on top */

/* All six wrappers share the rotation timing so they spin as one
   group around the porthole center (0.3s - 2.55s). Rotation starts
   together with the Phase 1 fade-in and finishes when the https URL
   finishes fading in. */
.claude-wrap {
  animation: claude-wrap-spin 2.25s 0.3s linear both;
}

/* Scale from bottom-center so feet stay pinned to the floor during the
   1/3 → 1 pop. Dial --pop-up to place the tiny character just above
   the washer's red rim. */
.claude {
  transform-origin: center bottom;
  --pop-up: -8px;
}

.claude-84 { --walk-from:  183px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 2.85s ease-out both; }
.claude-86 { --walk-from: -183px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 3.05s ease-out both; }
.claude-88 { --walk-from:  126px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 3.25s ease-out both; }
.claude-85 { --walk-from: -126px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 3.45s ease-out both; }
.claude-89 { --walk-from:   69px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 3.65s ease-out both; }
.claude-87 { --walk-from:  -69px; animation: claude-appear 0.6s 0.3s ease-out both, claude-emerge 0.8s 3.85s ease-out both; }

/* Waddle: legs dance only during the walk portion of the emerge
   (after the scale-up pop). Each character's delay = emerge-start +
   0.2s; 0.2s cycle × 3 iterations = 0.6s matches the walk window. */
.claude-84 .leg-left  { animation: claude-leg-left  0.2s 3.05s linear 3; }
.claude-84 .leg-right { animation: claude-leg-right 0.2s 3.05s linear 3; }
.claude-86 .leg-left  { animation: claude-leg-left  0.2s 3.25s linear 3; }
.claude-86 .leg-right { animation: claude-leg-right 0.2s 3.25s linear 3; }
.claude-88 .leg-left  { animation: claude-leg-left  0.2s 3.45s linear 3; }
.claude-88 .leg-right { animation: claude-leg-right 0.2s 3.45s linear 3; }
.claude-85 .leg-left  { animation: claude-leg-left  0.2s 3.65s linear 3; }
.claude-85 .leg-right { animation: claude-leg-right 0.2s 3.65s linear 3; }
.claude-89 .leg-left  { animation: claude-leg-left  0.2s 3.85s linear 3; }
.claude-89 .leg-right { animation: claude-leg-right 0.2s 3.85s linear 3; }
.claude-87 .leg-left  { animation: claude-leg-left  0.2s 4.05s linear 3; }
.claude-87 .leg-right { animation: claude-leg-right 0.2s 4.05s linear 3; }

/* Once intro completes (body.intro-done added by JS at 2.6s), kill the
   fade-in animation and lock opacity at 1 so toggling disco-mode can't
   retrigger the delayed animation.

   Elements that DON'T wobble in disco (small text, title spans) use
   body.intro-done — animation:none applies regardless of disco state,
   which prevents any restart when disco-mode toggles. Their parent
   (.title / .title-shadow) still wobbles as a unit. */
body.intro-done .studio,
body.intro-done .presents,
body.intro-done .date,
body.intro-done .mode,
body.intro-done .address,
body.intro-done .rsvp,
body.intro-done .byo,
body.intro-done .title > span,
body.intro-done .title-shadow > span {
  animation: none;
  opacity: 1;
}

/* Elements that DO wobble/spin in disco (.notes, .url, .washer, .claude)
   get the lock only when disco is off — otherwise disco-mode's animation
   rule provides the wobble. Turning disco off falls back to this rule. */
body.intro-done:not(.disco-mode) .claude,
body.intro-done:not(.disco-mode) .notes,
body.intro-done:not(.disco-mode) .notes-shadow,
body.intro-done:not(.disco-mode) .url,
body.intro-done:not(.disco-mode) .url-shadow,
body.intro-done:not(.disco-mode) .washer {
  animation: none;
  opacity: 1;
}

/* ─── RSVP modal ──────────────────────────────────────────────── */

.modal {
  position: fixed;
  top: 0;
  left: 0;
  display: none;
  background: var(--paper);
  border: 2px solid var(--ink);
  padding: 32px 28px 28px;
  width: min(400px, calc(100vw - 32px));
  color: var(--ink);
  font-family: var(--sans);
  z-index: 10000;
  will-change: transform;
  /* Start far above the viewport so the first paint after display:block
     is already off-screen. JS overrides transform once the bounce tick
     begins. */
  transform: translate(0, -200dvh);
  transition: opacity 500ms ease;
}

.modal.is-fading {
  opacity: 0;
  pointer-events: none;
}

body.modal-open .modal {
  display: block;
}

.modal-close {
  position: absolute;
  top: 6px;
  right: 10px;
  background: transparent;
  border: none;
  color: var(--ink);
  font-family: var(--serif);
  font-weight: 700;
  font-size: 28px;
  line-height: 1;
  padding: 4px 8px;
  cursor: pointer;
}
.modal-close:hover { color: var(--coral); }

.modal-title {
  font-family: var(--serif);
  font-weight: 700;
  font-size: 56px;
  line-height: 1;
  letter-spacing: -0.03em;
  color: var(--ink);
  text-align: center;
  margin-bottom: 5px;
  /* Match the https URL treatment: coral shadow peeking out 3px below,
     white outer stroke around the red main text. */
  text-shadow:
    1px 0 0 var(--paper),
    -1px 0 0 var(--paper),
    0 1px 0 var(--paper),
    0 -1px 0 var(--paper),
    1px 1px 0 var(--paper),
    -1px -1px 0 var(--paper),
    1px -1px 0 var(--paper),
    -1px 1px 0 var(--paper),
    0 3px 0 var(--coral);
}

.modal-sub {
  text-align: center;
  font-family: var(--serif);
  font-weight: 700;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--coral);
}

.modal-form {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-top: 24px;
}

.modal-form[hidden] {
  display: none;
}

/* Trim 5px off the gap between the email input and the first checkbox
   (form flex gap is 16px → effective gap becomes 11px). */
.modal-field { margin-bottom: -5px; }

/* Same trim between the two checkbox rows. */
.modal-check + .modal-check { margin-top: -5px; }

.modal-field span {
  display: block;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 12px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--coral);
  margin-bottom: 6px;
}

.modal-field input[type="email"] {
  width: 100%;
  padding: 10px 12px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.02em;
  color: var(--ink);
  background: var(--paper);
  border: 2px solid var(--ink);
  border-radius: 0;
}

.modal-field input[type="email"]::placeholder { color: var(--coral); opacity: 0.6; }
.modal-field input[type="email"]:focus { outline: none; border-color: var(--coral); }

.modal-check {
  display: flex;
  align-items: center;
  gap: 8px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 14px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--ink);
  cursor: pointer;
  user-select: none;
}

.modal-check input[type="checkbox"] {
  appearance: none;
  -webkit-appearance: none;
  width: 16px;
  height: 16px;
  border: 1px solid var(--ink);
  border-radius: 1px;
  background: var(--paper);
  cursor: pointer;
  flex-shrink: 0;
  position: relative;
  transition: background 120ms ease;
}

.modal-check input[type="checkbox"]:checked {
  background: var(--ink);
}

.modal-check input[type="checkbox"]:checked::after {
  content: '';
  position: absolute;
  left: 3px;
  top: -1px;
  width: 5px;
  height: 9px;
  border: solid var(--paper);
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.modal-submit {
  margin-top: 11px;
  padding: 10px 12px;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 16px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--paper);
  background: var(--ink);
  border: 2px solid var(--ink);
  border-radius: 1px;
  cursor: pointer;
  transition: background 150ms ease, border-color 150ms ease;
}

.modal-submit:hover {
  background: var(--coral);
  border-color: var(--coral);
}

/* Make the RSVP row read as clickable */
.rsvp { cursor: pointer; }

/* Inline form error (e.g., "pick at least one box") */
.modal-error {
  font-family: var(--sans);
  font-weight: 600;
  font-size: 13px;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--ink);
  background: rgba(249, 125, 80, 0.18);
  border: 2px solid var(--coral);
  padding: 8px 10px;
  margin: 0 0 -4px; /* tuck the submit button up slightly */
}

.modal-submit:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}
