/*
 * together we Party - the server-rendered surfaces.
 *
 * The public site and every event page are styled from this one file. It is a
 * static asset rather than an inline <style>, so it caches, and so the content
 * security policy on guest-facing pages can stay strict without a per-request
 * nonce on the stylesheet.
 *
 * The direction is the "bold poster" one: a deep navy ground, cream sections,
 * enormous tightly-tracked display type, and three accents used as punctuation
 * rather than decoration.
 */

:root {
  --ink: #14213D;
  --ink-2: #1E2C4F;
  --ink-3: #2D3A5C;
  --cream: #FBF8F3;
  --cream-2: #F1ECE3;
  --white: #FFFFFF;

  --magenta: #E2397A;
  --amber: #F5A623;
  --teal: #1FA3A8;
  --teal-dark: #157A7E;

  --muted-on-dark: #B8C0D4;
  --muted-on-light: #4A5568;
  --faint: #6B7280;
  --line: #E5E0D6;

  /* The second name in each stack is Arial with the real font's metrics put
     on it - see fonts.css. It is what holds the layout still if the webfont
     arrives after the first paint. */
  --display: 'Bricolage Grotesque', 'Bricolage Fallback', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;
  --body: 'Space Grotesk', 'Space Fallback', ui-sans-serif, system-ui, -apple-system, 'Segoe UI', sans-serif;

  --radius: 12px;
  --radius-lg: 18px;
  --shell: 1240px;
}

* { box-sizing: border-box; }

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

body {
  margin: 0;
  font-family: var(--body);
  font-size: 16px;
  line-height: 1.55;
  color: var(--ink);
  background: var(--cream);
  -webkit-font-smoothing: antialiased;
}

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

a { color: inherit; text-decoration: none; }
a:hover { color: var(--magenta); }

h1, h2, h3, h4 {
  font-family: var(--display);
  font-weight: 800;
  letter-spacing: -0.04em;
  line-height: 0.98;
  margin: 0 0 0.4em;
  text-wrap: balance;
}

h1 { font-size: clamp(40px, 8vw, 116px); line-height: 0.92; letter-spacing: -0.045em; }
h2 { font-size: clamp(30px, 4.6vw, 60px); }
h3 { font-size: clamp(21px, 2.4vw, 30px); letter-spacing: -0.03em; }

p { margin: 0 0 1em; text-wrap: pretty; }

.shell { max-width: var(--shell); margin: 0 auto; padding: 0 24px; }
.shell-narrow { max-width: 760px; margin: 0 auto; padding: 0 24px; }

.dark { background: var(--ink); color: var(--white); }
.dark a:hover { color: var(--amber); }
.dark .muted { color: var(--muted-on-dark); }

.light { background: var(--cream); color: var(--ink); }
.plain { background: var(--white); color: var(--ink); }

.muted { color: var(--muted-on-light); }
.faint { color: var(--faint); font-size: 14px; }

.section { padding: clamp(48px, 8vw, 96px) 0; }
.section-tight { padding: clamp(32px, 5vw, 56px) 0; }

/* ------------------------------------------------------------------ */
/* Navigation                                                          */
/* ------------------------------------------------------------------ */

.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 24px;
  max-width: var(--shell);
  margin: 0 auto;
  flex-wrap: wrap;
}

.brand { display: flex; align-items: center; gap: 10px; font-family: var(--display); font-weight: 800; font-size: 18px; letter-spacing: -0.02em; }
.brand img { width: 40px; height: 40px; border-radius: 10px; background: var(--white); object-fit: contain; padding: 3px; }
.brand .accent { color: var(--magenta); }

/* ------------------------------------------------------------------ */
/* The brand, which changes shape as you scroll                        */
/* ------------------------------------------------------------------ */

/*
 * At the top of the page the logo is shown whole, at the size of something
 * you are meant to look at, with its own lettering. Once the page moves it
 * stands aside: the glasses shrink to a corner mark and the name is set in
 * type beside them, which is the version that has to survive being small.
 *
 * Sticky, because a header that shrinks as you scroll has to still be there
 * to see. The name lives on the link itself so that swapping the artwork
 * never changes what a screen reader announces.
 */
/*
 * Fixed rather than sticky, with a spacer holding its place - see the comment
 * in layouts/site.php for why. The spacer's height is the at-rest header:
 * 20px of padding, the full logo, and 20px again.
 */
.site-header { position: fixed; top: 0; left: 0; right: 0; z-index: 40; }

/*
 * Room for the header above anything jumped to.
 *
 * "See examples" scrolls to #templates, and a fixed bar would otherwise land
 * on top of the heading it just took you to. The figure is the shrunk header
 * plus a little air, because by the time a jump lands the header is always in
 * its small state.
 */
html { scroll-padding-top: 84px; }
[id] { scroll-margin-top: 84px; }
/* A starting value only - site.js measures the real one, because the bar
   wraps at narrow widths and no single number is right at every size. */
.site-header-spacer { height: 212px; }

/*
 * One duration and one curve for every part of the header, so the padding,
 * the artwork and the wordmark arrive together instead of in a sequence.
 */
:root { --header-ease: cubic-bezier(.32, .72, 0, 1); --header-time: .34s; }

.site-header .nav { transition: padding var(--header-time) var(--header-ease); }
.site-header.is-scrolled .nav { padding-top: 10px; padding-bottom: 10px; }

/*
 * The swap, without display.
 *
 * `display: none` cannot be animated, so the old version dropped 128px of
 * logo in a single frame and then eased the remaining 16px of padding - a
 * header that fell over and then settled. Both images stay in the layout now
 * and their heights are animated to and from zero. Because each is width:auto
 * it keeps its aspect ratio, so the width collapses with the height and the
 * row closes up on its own - no second measurement to keep in step.
 */
.brand-swap { gap: 0; }
.brand-swap img {
  width: auto;
  min-width: 0;
  padding: 0;
  border-radius: 0;
  background: none;
  transition:
    height var(--header-time) var(--header-ease),
    margin var(--header-time) var(--header-ease),
    opacity calc(var(--header-time) * .55) ease;
}

/*
 * Qualified with the element, because the general ".brand img" above sets a
 * 40px square for the small logo used elsewhere and a bare class would lose
 * to it - one class against a class and an element.
 */
.brand-swap img.brand-logo-full { height: 172px; opacity: 1; }
.brand-swap img.brand-logo-mark { height: 0; opacity: 0; margin-right: 0; }

.brand-wordmark {
  white-space: nowrap;
  display: inline-block;
  opacity: 0;
  max-width: 0;
  overflow: hidden;
  transition:
    max-width var(--header-time) var(--header-ease),
    opacity calc(var(--header-time) * .55) ease;
}

/* The footer keeps the name in type beside the mark, so the artwork does not
   have to carry lettering twice at two different sizes. */
.brand-footer img { width: auto; height: 46px; padding: 0; border-radius: 0; background: none; }

.site-header.is-scrolled .brand-swap img.brand-logo-full { height: 0; opacity: 0; }
.site-header.is-scrolled .brand-swap img.brand-logo-mark { height: 44px; opacity: 1; margin-right: 10px; }
.site-header.is-scrolled .brand-wordmark { opacity: 1; max-width: 240px; }

@media (max-width: 700px) {
  .brand-swap img.brand-logo-full { height: 104px; }
  .brand-swap img.brand-logo-mark { height: 34px; }
  .site-header-spacer { height: 252px; }
}

/* The two phones in the hero ---------------------------------------

   Widths and transforms live here rather than in a style attribute so a
   narrow screen can undo them. Overlapped and rotated, the pair is wider
   than a small phone is, and it was pushing the whole front page sideways
   at 320px - a horizontal scrollbar on the first thing anybody sees.

   Below 760px the second one goes and the first straightens up: one phone
   showing an invitation says the same thing as two, and says it without a
   scrollbar. */
.hero-phones {
  display: flex;
  justify-content: center;
  align-items: center;
  position: relative;
  min-height: 520px;
  /* Whatever happens inside, the hero never widens the page. */
  max-width: 100%;
  overflow: hidden;
}

/* min() rather than a flat 250px: the mockup should never be the reason a
   page scrolls sideways, however narrow the window gets. */
.hero-phone { width: min(250px, 100%); flex: none; }
.hero-phone-a { transform: rotate(-6deg) translateX(30px); }
.hero-phone-b { transform: rotate(5deg) translateX(-30px) translateY(40px); }

/*
 * Where the second phone stops fitting.
 *
 * The hero is a two-column grid that holds both columns down to about 656px,
 * so between there and roughly a thousand the phones get a column narrower
 * than the pair needs - 440px once the overlap is counted - and pushed the
 * page sideways. The first cut of this hid the second phone below 760px,
 * which fixed a 320px screen and left a tablet scrolling horizontally.
 */
@media (max-width: 1000px) {
  .hero-phones { min-height: 0; }
  .hero-phone-a { transform: none; }
  .hero-phone-b { display: none; }
}

/* Somebody who has asked for less movement gets the change without the
   animation, not a header that resizes underneath them. */
@media (prefers-reduced-motion: reduce) {
  .brand-swap img,
  .brand-wordmark,
  .site-header .nav { transition: none; }
}

.nav-links { display: flex; gap: 22px; font-size: 14px; font-weight: 500; flex-wrap: wrap; }
.nav-actions { display: flex; gap: 10px; align-items: center; flex-wrap: wrap; }

/* ------------------------------------------------------------------ */
/* Buttons                                                             */
/* ------------------------------------------------------------------ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--body);
  font-weight: 700;
  font-size: 16px;
  line-height: 1;
  padding: 15px 22px;
  border-radius: 10px;
  border: 2px solid transparent;
  cursor: pointer;
  transition: transform .12s ease, background-color .12s ease, color .12s ease;
}

.btn:hover { transform: translateY(-1px); color: inherit; }
.btn:active { transform: translateY(0); }
.btn:focus-visible { outline: 3px solid var(--teal); outline-offset: 2px; }

.btn-primary { background: var(--magenta); color: var(--white); }
.btn-primary:hover { background: #c92e69; color: var(--white); }

.btn-amber { background: var(--amber); color: var(--ink); }
.btn-amber:hover { background: #e0951b; color: var(--ink); }

.btn-ink { background: var(--ink); color: var(--white); }
.btn-ink:hover { background: var(--ink-2); color: var(--white); }

.btn-ghost { border-color: var(--line); color: inherit; }
.dark .btn-ghost { border-color: var(--ink-3); color: var(--white); }
.btn-ghost:hover { border-color: currentColor; }

.btn-block { width: 100%; }
.btn-small { padding: 10px 14px; font-size: 14px; }

/* ------------------------------------------------------------------ */
/* Cards, badges, forms                                                */
/* ------------------------------------------------------------------ */

.card {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: 26px;
}

.dark .card { background: var(--ink-2); border-color: var(--ink-3); }

.grid { display: grid; gap: 20px; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(190px, 1fr)); }

/*
 * Six across on a desktop.
 *
 * The track has to be small enough that six fit inside the shell, or auto-fit
 * quietly drops to four and the last two wrap onto a second row - which is what
 * "Create → Invite → ... → Share" must not do, because the row is the sentence.
 */
.grid-6 { grid-template-columns: repeat(auto-fit, minmax(165px, 1fr)); }

.eyebrow {
  font-size: 13px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--magenta);
  margin-bottom: 12px;
}

.badge {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 12px;
  font-weight: 700;
  padding: 5px 10px;
  border-radius: 999px;
  background: var(--cream-2);
  color: var(--ink);
}

.badge-yes { background: #DCF5E7; color: #14653A; }
.badge-no { background: #FCE4EE; color: #9B1B47; }
.badge-maybe { background: #FDF0D5; color: #7A5310; }
.badge-pending { background: var(--cream-2); color: var(--muted-on-light); }

label { display: block; font-weight: 600; font-size: 14px; margin-bottom: 6px; }

input[type=text], input[type=email], input[type=password], input[type=number],
input[type=tel], input[type=search], select, textarea {
  width: 100%;
  font-family: var(--body);
  font-size: 16px;
  color: var(--ink);
  background: var(--white);
  border: 2px solid var(--line);
  border-radius: 10px;
  padding: 13px 14px;
}

input:focus, select:focus, textarea:focus {
  outline: none;
  border-color: var(--teal);
}

textarea { min-height: 110px; resize: vertical; }

.field { margin-bottom: 18px; }
.field-hint { font-size: 13px; color: var(--faint); margin-top: 6px; }
.field-error { font-size: 13px; color: var(--magenta); margin-top: 6px; font-weight: 600; }

.notice {
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: 15px;
  margin-bottom: 20px;
  border: 2px solid transparent;
}

.notice-good { background: #DCF5E7; color: #14653A; }
.notice-warn { background: #FDF0D5; color: #7A5310; }
.notice-bad { background: #FCE4EE; color: #9B1B47; }
.notice-info { background: #E3F4F4; color: var(--teal-dark); }

/* Radio cards - the RSVP answer, and anything else with two or three choices */
.choices { display: grid; gap: 12px; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); }

.choice {
  position: relative;
  display: block;
  border: 2px solid var(--line);
  border-radius: var(--radius);
  padding: 18px 16px;
  text-align: center;
  cursor: pointer;
  font-weight: 700;
  background: var(--white);
}

.choice input { position: absolute; opacity: 0; pointer-events: none; }
.choice:hover { border-color: var(--ink-3); }
.choice:has(input:checked) { border-color: var(--magenta); background: #FCE4EE; color: #9B1B47; }
.choice:has(input:focus-visible) { outline: 3px solid var(--teal); outline-offset: 2px; }

/* ------------------------------------------------------------------ */
/* Event pages                                                         */
/* ------------------------------------------------------------------ */

.event-hero {
  padding: clamp(40px, 9vw, 110px) 0 clamp(32px, 6vw, 72px);
  background: var(--event-surface, var(--ink));
  color: var(--event-ink, var(--white));
  position: relative;
  overflow: hidden;
}

.event-hero h1 { margin-bottom: 16px; }
.event-when { font-size: clamp(17px, 2.2vw, 22px); font-weight: 600; }

/*
 * The guest tab strip is styled by the .ev-* rules further down, in the
 * event's own colours. What was here painted the active tab in the platform's
 * navy whatever theme the party wore, and being one step more specific it won.
 * The class name is kept on the element only so the print rules can still
 * hide it.
 */

.countdown {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  font-family: var(--display);
  font-weight: 800;
  font-size: 40px;
  letter-spacing: -0.03em;
}

.countdown span { font-family: var(--body); font-size: 14px; font-weight: 500; letter-spacing: 0; }

.timeline { display: grid; gap: 2px; }

.timeline-item {
  display: grid;
  grid-template-columns: 96px 1fr;
  gap: 18px;
  padding: 18px 20px;
  background: var(--white);
  border: 1px solid var(--line);
}

.timeline-item:first-child { border-radius: var(--radius) var(--radius) 0 0; }
.timeline-item:last-child { border-radius: 0 0 var(--radius) var(--radius); }
.timeline-time { font-family: var(--display); font-weight: 800; font-size: 20px; letter-spacing: -0.02em; }

.gift { display: flex; flex-direction: column; gap: 10px; }
.gift-taken { opacity: .55; }

.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 10px; }
.photo-grid img { border-radius: var(--radius); aspect-ratio: 1; object-fit: cover; width: 100%; }

/* ------------------------------------------------------------------ */
/* Footer                                                              */
/* ------------------------------------------------------------------ */

.footer { padding: 56px 0 40px; font-size: 14px; }
.footer-links { display: flex; gap: 20px; flex-wrap: wrap; }

/* ------------------------------------------------------------------ */
/* A template's own page, in a template's own colours -------------------

   The detail page is dressed in the palette it is showing, so the page around
   the preview and the page inside it are the same party. The derived values
   are mixed exactly as the guest pages mix them, from the same two colours, so
   a muted line on this page is the muted line a guest would see.

   The light and dark variants differ only in what a raised card is: white on a
   pale surface, and a lift of the surface itself on a dark one. One mix cannot
   do both - a card that is darker than its background reads as a hole. */

.tpl-themed {
  background: var(--tpl-surface);
  color: var(--tpl-ink);

  --tpl-muted: color-mix(in srgb, var(--tpl-ink) 72%, var(--tpl-surface));
  --tpl-faint: color-mix(in srgb, var(--tpl-ink) 52%, var(--tpl-surface));
  --tpl-line: color-mix(in srgb, var(--tpl-ink) 16%, var(--tpl-surface));
}

.tpl-themed.is-light { --tpl-card: #ffffff; --tpl-shadow: 0 12px 40px rgb(0 0 0 / .10); }
.tpl-themed.is-dark { --tpl-card: color-mix(in srgb, #ffffff 9%, var(--tpl-surface)); --tpl-shadow: 0 12px 40px rgb(0 0 0 / .35); }

/* Without color-mix there is nothing to derive from, so the page falls back
   to the site's own colours rather than to a set of invisible ones. */
@supports not (color: color-mix(in srgb, red, blue)) {
  .tpl-themed { background: var(--cream); color: var(--ink); }
  .tpl-themed .tpl-card { background: #fff; }
}

.tpl-themed h1,
.tpl-themed h2,
.tpl-themed h3 { color: var(--tpl-ink); }

.tpl-themed .muted { color: var(--tpl-muted); }
.tpl-themed .faint { color: var(--tpl-faint); }
/* Content links only. The tabs and the template cards carry their own
   treatment and were being repainted by this. */
.tpl-themed p a,
.tpl-themed li a { color: var(--tpl-primary); }

.tpl-card {
  background: var(--tpl-card);
  border: 1px solid var(--tpl-line);
  border-radius: 12px;
  padding: 16px 18px;
}

.tpl-themed .btn-primary { background: var(--tpl-primary); color: var(--tpl-on-primary); }
.tpl-themed .btn-primary:hover { background: var(--tpl-primary); filter: brightness(.92); }

.tpl-themed .btn-ghost {
  border-color: var(--tpl-line);
  color: var(--tpl-ink);
  background: transparent;
}

.tpl-themed .btn-ghost:hover { border-color: var(--tpl-ink); }

.tpl-themed .badge {
  background: color-mix(in srgb, var(--tpl-primary) 16%, var(--tpl-surface));
  color: var(--tpl-ink);
  border-color: transparent;
}

/* The name of the template, set in the template's own display face - so the
   type is being shown as well as described. */
.tpl-title { font-family: var(--tpl-display), var(--display); }

.tpl-swatch {
  width: 34px;
  height: 12px;
  border-radius: 6px;
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--tpl-ink) 22%, transparent);
}

/* The template preview -----------------------------------------------

   A frame showing the real guest page, with the guest's own tabs above it.
   Fixed height rather than growing with its contents: the pages behind it are
   different lengths, and a frame that resized when you switched tabs would
   move the rest of the page up and down under your thumb. */

.tpl-tabs {
  display: flex;
  gap: 6px;
  overflow-x: auto;
  padding-bottom: 12px;
  scrollbar-width: none;
}

.tpl-tabs::-webkit-scrollbar { display: none; }

/* Drawn from the template's own two colours rather than the site's.

   A white pill on a midnight-navy template looked like something had failed
   to load, and the "current" pill was painted in the site's navy - which on
   that template was the background, so the tab you were on was the one you
   could not see. */
.tpl-tab {
  flex: none;
  padding: 9px 16px;
  border-radius: 999px;
  border: 1px solid var(--tpl-line, var(--line));
  background: transparent;
  color: var(--tpl-muted, var(--muted-on-light));
  font-size: 14px;
  font-weight: 600;
  text-decoration: none;
  white-space: nowrap;
}

.tpl-themed .tpl-tab { color: var(--tpl-muted); }

.tpl-tab:hover,
.tpl-themed .tpl-tab:hover {
  border-color: var(--tpl-ink, var(--ink));
  color: var(--tpl-ink, var(--ink));
}

.tpl-tab.is-current,
.tpl-themed .tpl-tab.is-current {
  background: var(--tpl-ink, var(--ink));
  border-color: var(--tpl-ink, var(--ink));
  color: var(--tpl-surface, #fff);
}

/* The frame sits on the template's surface, so its border and lift come from
   the same place. */
.tpl-themed .tpl-frame {
  border-color: var(--tpl-line);
  background: var(--tpl-card);
  box-shadow: var(--tpl-shadow);
}

.tpl-frame {
  border-radius: var(--radius-lg);
  overflow: hidden;
  border: 1px solid var(--line);
  background: #fff;
  box-shadow: 0 30px 60px rgba(20, 33, 61, .12);
  /* Tall enough to show a page rather than a strip of one, and never taller
     than the window it is being looked at in. */
  height: min(760px, 78vh);
}

.tpl-frame iframe {
  display: block;
  width: 100%;
  height: 100%;
  border: 0;
}

@media (max-width: 700px) {
  .tpl-frame { height: min(560px, 62vh); }

  /* On a phone the frame fills most of the screen, and a frame that scrolls
     on its own swallows the swipe that was meant to move the page - leaving
     somebody stuck inside a preview with the rest of the page below it out of
     reach. So it becomes a window rather than something to scroll, and the
     link underneath opens the invitation properly. */
  .tpl-frame iframe { pointer-events: none; }
}

/* Decoration - the confetti marks from the logo                       */
/* ------------------------------------------------------------------ */

.confetti { position: absolute; inset: 0; pointer-events: none; overflow: hidden; }
.confetti i { position: absolute; display: block; border-radius: 5px; }
.confetti i:nth-child(1) { top: 8%; right: 8%; width: 44px; height: 10px; background: var(--magenta); transform: rotate(-35deg); }
.confetti i:nth-child(2) { top: 22%; right: 22%; width: 16px; height: 16px; border-radius: 50%; background: var(--teal); }
.confetti i:nth-child(3) { top: 46%; right: 5%; width: 30px; height: 10px; background: var(--amber); transform: rotate(20deg); }
.confetti i:nth-child(4) { top: 68%; left: 6%; width: 14px; height: 14px; border-radius: 50%; background: var(--amber); }
.confetti i:nth-child(5) { top: 12%; left: 4%; width: 34px; height: 9px; background: var(--teal); transform: rotate(28deg); }

/* On a wide screen the two left-hand pieces sit in the margin beside the
   heading. On a phone there is no margin, so they land on the words - an
   amber dot through the first letter of the venue. The pieces on the right
   stay, because the text does not reach that edge. */
@media (max-width: 700px) {
  .confetti i:nth-child(4),
  .confetti i:nth-child(5) { display: none; }
}

@media (prefers-reduced-motion: no-preference) {
  .btn { transition: transform .12s ease, background-color .12s ease; }
}

@media print {
  .nav, .event-nav, .footer, .btn { display: none !important; }
  body { background: #fff; color: #000; }
}


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

/*
 * Sections arrive rather than appear. The starting state is set here and the
 * finishing state is added by a script, which means a browser with no
 * JavaScript never applies the starting state at all and simply shows the
 * page - the failure mode of an animation must never be invisible content.
 */
/*
 * Scoped to a class the script adds to <html>, and adds only once it knows it
 * can finish the job. Written as a bare [data-rise] rule this hides half the
 * page for anyone whose script did not load, and the page never comes back -
 * an animation that fails should cost the flourish, never the content.
 */
.has-motion [data-rise] {
  opacity: 0;
  transform: translate3d(0, 18px, 0);
  transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .3, 1);
}

.has-motion [data-rise].is-in {
  opacity: 1;
  transform: none;
}

/* Staggered, so a row of cards lands one after another instead of as a block. */
[data-rise-delay="1"] { transition-delay: .07s; }
[data-rise-delay="2"] { transition-delay: .14s; }
[data-rise-delay="3"] { transition-delay: .21s; }
[data-rise-delay="4"] { transition-delay: .28s; }
[data-rise-delay="5"] { transition-delay: .35s; }

/* Parallax is driven by transform from the script; this only promotes the
   layer so the drift does not repaint the section behind it. */
[data-parallax] { will-change: transform; }

@media (prefers-reduced-motion: reduce) {
  .has-motion [data-rise] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  [data-parallax] {
    transform: none !important;
    will-change: auto;
  }
}

/* ------------------------------------------------------------------ */
/* A party's own pages                                                 */
/* ------------------------------------------------------------------ */

/*
 * Built to the Theme Preview design: a tab strip, one wide column of content
 * and a card of details that stays with you as you scroll.
 *
 * Everything is expressed against the four theme colours, so the same layout
 * carries a cream wedding and a midnight neon party without a second
 * stylesheet. The derived tones - muted text, hairlines, the raised card -
 * are mixed from ink and surface rather than written out, which is what keeps
 * a hundred themes from needing a hundred palettes.
 */

.ev {
  --ev-muted: color-mix(in srgb, var(--event-ink) 72%, var(--event-surface));
  --ev-faint: color-mix(in srgb, var(--event-ink) 52%, var(--event-surface));
  --ev-line: color-mix(in srgb, var(--event-ink) 16%, var(--event-surface));
  --ev-sunk: color-mix(in srgb, var(--event-ink) 8%, var(--event-surface));
  --ev-shell: 1120px;
}

/* Set by the layout from the theme's measured luminance: white on a light
   page, lifted on a dark one. One mix cannot do both. */
.ev-light { --ev-card: #ffffff; --ev-shadow: 0 12px 40px rgb(0 0 0 / .10); }
.ev-dark { --ev-card: color-mix(in srgb, #ffffff 9%, var(--event-surface)); --ev-shadow: 0 12px 40px rgb(0 0 0 / .35); }

.ev-shell { max-width: var(--ev-shell); margin: 0 auto; padding: 0 clamp(18px, 4vw, 48px); }

/* The tab strip ---------------------------------------------------- */

.ev-tabs { display: flex; gap: 6px; overflow-x: auto; padding: clamp(18px, 3vw, 28px) 0 0; scrollbar-width: none; }
.ev-tabs::-webkit-scrollbar { display: none; }

.ev-tab {
  font-size: 13px;
  font-weight: 600;
  padding: 9px 14px;
  border-radius: 999px;
  white-space: nowrap;
  background: var(--ev-sunk);
  color: var(--event-ink);
}

.ev-tab:hover { color: var(--event-ink); background: color-mix(in srgb, var(--event-ink) 14%, var(--event-surface)); }
.ev-tab[aria-current=page] { background: var(--event-ink); color: var(--event-surface); }

/* The two columns -------------------------------------------------- */

.ev-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: clamp(20px, 3vw, 40px);
  align-items: start;
  padding: clamp(20px, 3vw, 34px) 0 48px;
}

@media (max-width: 900px) {
  .ev-body { grid-template-columns: minmax(0, 1fr); }
}

.ev-main { display: grid; gap: 18px; min-width: 0; }

/* Type ------------------------------------------------------------- */

.ev-title {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(38px, 6vw, 52px);
  letter-spacing: -0.04em;
  line-height: .95;
  margin: 0;
}

.ev-lede { margin: 0; font-size: 17px; line-height: 1.55; color: var(--ev-muted); text-wrap: pretty; }
.ev-eyebrow { font-size: 12px; letter-spacing: .2em; font-weight: 700; color: var(--event-primary); text-transform: uppercase; }

.ev-count { display: flex; align-items: baseline; gap: 12px; }
.ev-count b { font-family: var(--display); font-weight: 800; font-size: clamp(44px, 7vw, 64px); letter-spacing: -0.05em; line-height: 1; color: var(--event-primary); }
.ev-count span { font-size: 15px; font-weight: 600; }

/* A list of times: the running order, and the summary of it ---------- */

.ev-rows { display: grid; }

.ev-row {
  display: grid;
  grid-template-columns: 72px minmax(0, 1fr);
  gap: 16px;
  padding: 18px 0;
  border-top: 1px solid var(--ev-line);
}

.ev-row .ev-at { font-family: var(--display); font-weight: 800; font-size: 20px; letter-spacing: -0.03em; color: var(--event-primary); }
.ev-row .ev-what { font-weight: 700; font-size: 16px; }
.ev-row .ev-note { font-size: 14px; color: var(--ev-faint); margin-top: 3px; }

.ev-row-tight { grid-template-columns: 64px minmax(0, 1fr); gap: 14px; padding: 12px 0; font-size: 14px; }
.ev-row-tight .ev-at { font-family: var(--body); font-size: 14px; font-weight: 700; color: var(--event-ink); }
.ev-row-tight .ev-what { font-weight: 500; font-size: 14px; color: var(--ev-muted); }

/* Tiles: photographs, and the places they will go ------------------- */

.ev-tiles { display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; }
.ev-tile { aspect-ratio: 1; border-radius: 12px; overflow: hidden; background: var(--ev-sunk); display: grid; place-items: center; }
.ev-tile img { width: 100%; height: 100%; object-fit: cover; }

/* Gifts ------------------------------------------------------------- */

.ev-gift { display: flex; align-items: center; justify-content: space-between; gap: 16px; padding: 16px 0; border-top: 1px solid var(--ev-line); flex-wrap: wrap; }
.ev-gift-name { font-weight: 700; font-size: 16px; }
.ev-gift-note { font-size: 14px; color: var(--ev-faint); margin-top: 3px; }
.ev-gift-price { font-weight: 700; }
.ev-state { font-size: 13px; font-weight: 600; color: var(--ev-faint); }

/* The details card -------------------------------------------------- */

.ev-card {
  background: var(--ev-card);
  border-radius: 18px;
  padding: 22px;
  box-shadow: var(--ev-shadow);
  display: grid;
  gap: 16px;
  position: sticky;
  top: 12px;
}

.ev-card h2 { font-family: var(--display); font-weight: 800; font-size: 22px; letter-spacing: -0.03em; margin: 0; }

/* The pass -----------------------------------------------------------

   Always white behind the code, whatever the party's colours are: a phone
   camera reading a QR off another phone screen wants contrast, and a pass
   that matches the invitation but will not scan has failed at the only job
   it has.

   Not sticky, unlike the card it borrows its shape from - this one sits in
   the page where it was put. */
.ev-pass {
  position: static;
  top: auto;
  justify-items: center;
  text-align: center;
  gap: 12px;
}

.ev-pass-code {
  background: #fff;
  border-radius: 12px;
  padding: 10px;
  line-height: 0;
  /* Big enough to scan from a hand's length away, and never wider than the
     column it is in. */
  width: min(220px, 100%);
}

.ev-pass-code svg { width: 100%; height: auto; display: block; }

.ev-pass-text {
  margin: 0;
  font-family: ui-monospace, "SFMono-Regular", Menlo, Consolas, monospace;
  font-size: 22px;
  font-weight: 700;
  letter-spacing: .18em;
  /* The letter-spacing is on the right of the last character too, which reads
     as the whole code sitting slightly left of centre. */
  text-indent: .18em;
}
.ev-fact { display: grid; gap: 4px; }
.ev-fact dt { font-size: 12px; letter-spacing: .14em; font-weight: 700; color: var(--ev-faint); text-transform: uppercase; }
.ev-fact dd { margin: 0; font-size: 15px; font-weight: 600; }
.ev-fact .ev-sub { font-size: 13px; font-weight: 400; color: var(--ev-faint); }

/* Buttons ----------------------------------------------------------- */

.ev-btn {
  display: inline-block;
  text-align: center;
  background: var(--event-ink);
  color: var(--event-surface);
  font-weight: 700;
  font-size: 15px;
  padding: 15px 22px;
  border-radius: 999px;
}

.ev-btn:hover { color: var(--event-surface); filter: brightness(1.12); }
.ev-btn-accent { background: var(--event-primary); }
.ev-btn-quiet { background: transparent; color: var(--event-ink); border: 1.5px solid var(--ev-line); }
.ev-btn-quiet:hover { color: var(--event-ink); background: var(--ev-sunk); filter: none; }
.ev-btn-block { display: block; }

/* Foot -------------------------------------------------------------- */

.ev-foot { padding: 14px 22px; text-align: center; font-size: 11px; color: var(--ev-faint); border-top: 1px solid var(--ev-line); }
