/* The design tokens from docs/design/design-direction.md, verbatim.
 *
 * The audience palette is set once, on <html data-audience="...">, and every
 * guest and host screen inherits it. Nothing below hardcodes a palette colour:
 * if a component needs raspberry it asks for --accent and gets raspberry at a
 * wedding and cobalt at a game.
 *
 * The mark is NOT recoloured here. Each of the four mark files bakes its own
 * colours into its own gradient ids, and the direction says never redraw it, so
 * the audience mark is chosen by swapping the file. --mark is the path.
 */

/* Weddings is the default so a page with no audience yet is never unstyled. */
:root,
[data-audience='weddings'] {
  --accent: #D6336C;
  --accent-hover: #B8265A;
  --second: #FFB86B;
  --second-soft: #FFEBD3;
  --tint: #FBE3EC;
  --ground: #FBF7F9;
  --card: #FFFFFF;
  --ink: #2B1A2E;
  --muted: #6B5A6E;
  --wash-mid: #FDF1F5;
  --ink-rgb: 43, 26, 46;
  --mark: url('/marks/weddings.svg');
}

[data-audience='parties'] {
  --accent: #00B3A4;
  --accent-hover: #00998C;
  --second: #FFE45C;
  --second-soft: #FFF8CC;
  --tint: #D6F3EF;
  --ground: #F2F9FA;
  --card: #FFFFFF;
  --ink: #0F2A33;
  --muted: #4F6B74;
  --wash-mid: #EAF6F6;
  --ink-rgb: 15, 42, 51;
  --mark: url('/marks/parties.svg');
}

[data-audience='sports'] {
  --accent: #2F5BFF;
  --accent-hover: #1E44D6;
  --second: #FFD23F;
  --second-soft: #FFF4C7;
  --tint: #E4E9FF;
  --ground: #F6F7FB;
  --card: #FFFFFF;
  --ink: #12162B;
  --muted: #5C6178;
  --wash-mid: #F0F2FB;
  --ink-rgb: 18, 22, 43;
  --mark: url('/marks/sports.svg');
}

:root {
  /* Shapes. Radii and shadow from the direction, not invented. */
  --r-card: 28px;
  --r-tile: 20px;
  --r-chip: 14px;
  --r-pill: 999px;
  --shadow-card: 0 1px 0 rgba(var(--ink-rgb), .04), 0 24px 60px rgba(var(--ink-rgb), .07);
  --shadow-btn: 0 10px 24px rgba(var(--ink-rgb), .16);

  --gutter: 20px;
  --section: 72px;

  --font: 'Plus Jakarta Sans', 'Avenir Next', 'Helvetica Neue', Arial, sans-serif;

  /* The hero wash: tint to a mid tone to the ground. */
  --wash: linear-gradient(180deg, var(--tint) 0%, var(--wash-mid) 46%, var(--ground) 100%);
}

@media (min-width: 900px) {
  :root { --gutter: 72px; --section: 130px; }
}

/* ------------------------------------------------------------------ reset --- */

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

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

body {
  margin: 0;
  background: var(--ground);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
}

img, svg, video { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
a { color: var(--accent); text-decoration: none; }
a:hover { color: var(--accent-hover); }

/* ------------------------------------------------------------------- type --- */

.display, h1 {
  font-weight: 800;
  letter-spacing: -0.025em;
  line-height: 1.05;
  text-wrap: balance;
  margin: 0;
}

h1 { font-size: 44px; }
h2 { font-size: 34px; font-weight: 800; letter-spacing: -0.025em; line-height: 1.05; text-wrap: balance; margin: 0; }
h3 { font-size: 20px; font-weight: 700; letter-spacing: -0.015em; margin: 0; }

@media (min-width: 900px) {
  h1 { font-size: 76px; }
  h2 { font-size: 54px; }
}

p { margin: 0; max-width: 52ch; }
.muted { color: var(--muted); }
.accent { color: var(--accent); }
.tnum { font-variant-numeric: tabular-nums; }

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  background: var(--tint);
  border-radius: var(--r-pill);
  padding: 7px 14px;
}

/* An eyebrow that sits beside the mark has no pill, per screen 02. */
.eyebrow.bare { background: none; padding: 0; }

/* ---------------------------------------------------------------- surfaces --- */

.card {
  background: var(--card);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
}

.wash {
  background: var(--wash);
}

/* ---------------------------------------------------------------- controls --- */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 54px;
  padding: 0 26px;
  border: 0;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: #fff;
  font-size: 17px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: var(--shadow-btn);
}

.btn:hover { background: var(--accent-hover); }
.btn:active { transform: translateY(1px); }
.btn[disabled] { opacity: .45; cursor: default; box-shadow: none; }

.btn.ghost {
  background: transparent;
  color: var(--ink);
  box-shadow: none;
  border: 2px solid var(--ink);
}
.btn.ghost:hover { background: transparent; color: var(--ink); }

.btn.block { width: 100%; }

.chip {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 0 20px;
  border-radius: var(--r-pill);
  background: var(--card);
  color: var(--ink);
  font-weight: 700;
  font-size: 16px;
  border: 0;
  box-shadow: 0 1px 0 rgba(var(--ink-rgb), .04), 0 6px 18px rgba(var(--ink-rgb), .05);
  cursor: pointer;
  white-space: nowrap;
}

.chip[aria-pressed='true'] { background: var(--ink); color: #fff; }

.field {
  width: 100%;
  min-height: 52px;
  padding: 0 18px;
  border: 2px solid rgba(var(--ink-rgb), .12);
  border-radius: var(--r-tile);
  background: var(--card);
}
.field:focus { outline: 0; border-color: var(--accent); }

:where(a, button, input, select, textarea):focus-visible {
  outline: 3px solid var(--accent);
  outline-offset: 2px;
}

/* ------------------------------------------------------------------ layout --- */

.page { padding: 0 var(--gutter) 120px; }
.wrap { max-width: 1180px; margin: 0 auto; }
.stack { display: flex; flex-direction: column; gap: 14px; }
.row { display: flex; align-items: center; gap: 12px; }
.row.between { justify-content: space-between; }
.grow { flex: 1; min-width: 0; }
.hide { display: none !important; }

/* --------------------------------------------------------------- the mark --- */

.mark {
  width: 32px;
  height: 32px;
  flex: 0 0 auto;
  background: var(--mark) center / contain no-repeat;
}
@media (min-width: 900px) { .mark { width: 40px; height: 40px; } }

.wordmark {
  font-weight: 800;
  letter-spacing: -0.025em;
  color: var(--ink);
  font-size: 20px;
}

/* ------------------------------------------------------------ hub tiles --- */

/* Shared, because the landing page renders the same three tiles inside its
   phone mock. Kept here rather than duplicated into site.css so there is one
   definition of what an option tile looks like.
   A data URI cannot read a custom property, so the glyph colour is written per
   audience rather than recoloured. */

.tile-icon {
  width: 54px; height: 54px;
  flex: 0 0 auto;
  border-radius: var(--r-tile);
  background: var(--tint) center / 28px 28px no-repeat;
  display: block;
}

/* The hunt tile's chip is solid accent with a white glyph, per screen 02. */
.tile-icon.accent-chip { background-color: var(--accent); }

.tile-icon[data-icon='photos'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D6336C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='16' rx='3'/><circle cx='9' cy='10' r='1.6'/><path d='M4 17l5-5 4 4 3-2 4 4'/></svg>");
}
.tile-icon[data-icon='hunt'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='2'><circle cx='12' cy='12' r='8'/><circle cx='12' cy='12' r='3.2'/></svg>");
}
.tile-icon[data-icon='message'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D6336C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='6' width='12' height='12' rx='3'/><path d='M15 11l6-3v8l-6-3z'/></svg>");
}

.tile-icon[data-icon='download'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D6336C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4v10'/><path d='M8 11l4 4 4-4'/><path d='M5 19h14'/></svg>");
}
.tile-icon[data-icon='book'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D6336C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 5.5A2.5 2.5 0 0 1 6.5 3H19v15H6.5A2.5 2.5 0 0 0 4 20.5z'/><path d='M4 20.5A2.5 2.5 0 0 1 6.5 18H19v3H6.5A2.5 2.5 0 0 1 4 20.5z'/></svg>");
}
.tile-icon[data-icon='star'] {
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23D6336C' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4l2.2 4.8 5.3.6-3.9 3.6 1 5.2-4.6-2.6-4.6 2.6 1-5.2L4.5 9.4l5.3-.6z'/></svg>");
}

/* The icon glyphs are drawn in accent. A data URI cannot read a custom
   property, so the two audiences that are not raspberry get their own copies
   rather than a recoloured mark. */
[data-audience='parties'] .tile-icon[data-icon='photos'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300B3A4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='16' rx='3'/><circle cx='9' cy='10' r='1.6'/><path d='M4 17l5-5 4 4 3-2 4 4'/></svg>"); }
[data-audience='parties'] .tile-icon[data-icon='message'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300B3A4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='6' width='12' height='12' rx='3'/><path d='M15 11l6-3v8l-6-3z'/></svg>"); }
[data-audience='parties'] .tile-icon[data-icon='download'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300B3A4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4v10'/><path d='M8 11l4 4 4-4'/><path d='M5 19h14'/></svg>"); }
[data-audience='parties'] .tile-icon[data-icon='book'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300B3A4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 5.5A2.5 2.5 0 0 1 6.5 3H19v15H6.5A2.5 2.5 0 0 0 4 20.5z'/><path d='M4 20.5A2.5 2.5 0 0 1 6.5 18H19v3H6.5A2.5 2.5 0 0 1 4 20.5z'/></svg>"); }
[data-audience='parties'] .tile-icon[data-icon='star'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2300B3A4' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4l2.2 4.8 5.3.6-3.9 3.6 1 5.2-4.6-2.6-4.6 2.6 1-5.2L4.5 9.4l5.3-.6z'/></svg>"); }
[data-audience='sports'] .tile-icon[data-icon='photos'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F5BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='4' width='18' height='16' rx='3'/><circle cx='9' cy='10' r='1.6'/><path d='M4 17l5-5 4 4 3-2 4 4'/></svg>"); }
[data-audience='sports'] .tile-icon[data-icon='message'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F5BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><rect x='3' y='6' width='12' height='12' rx='3'/><path d='M15 11l6-3v8l-6-3z'/></svg>"); }
[data-audience='sports'] .tile-icon[data-icon='download'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F5BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4v10'/><path d='M8 11l4 4 4-4'/><path d='M5 19h14'/></svg>"); }
[data-audience='sports'] .tile-icon[data-icon='book'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F5BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M4 5.5A2.5 2.5 0 0 1 6.5 3H19v15H6.5A2.5 2.5 0 0 0 4 20.5z'/><path d='M4 20.5A2.5 2.5 0 0 1 6.5 18H19v3H6.5A2.5 2.5 0 0 1 4 20.5z'/></svg>"); }
[data-audience='sports'] .tile-icon[data-icon='star'] { background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%232F5BFF' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M12 4l2.2 4.8 5.3.6-3.9 3.6 1 5.2-4.6-2.6-4.6 2.6 1-5.2L4.5 9.4l5.3-.6z'/></svg>"); }


/* --------------------------------------------------------------- confetti --- */

/* Dots live in margins and empty space only. Their container is aria-hidden
   and pointer-events none, and every dot is positioned clear of text at every
   width, including where the bob carries it. */
.confetti {
  position: absolute;
  inset: 0;
  overflow: hidden;
  pointer-events: none;
  z-index: 0;
}

.confetti i {
  position: absolute;
  display: block;
  border-radius: 50%;
  animation: bob 6s ease-in-out infinite alternate;
}

@keyframes bob {
  from { transform: translateY(0); opacity: .9; }
  to   { transform: translateY(-18px); opacity: .5; }
}

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

@keyframes up {
  from { opacity: 0; transform: translateY(22px); }
  to   { opacity: 1; transform: none; }
}

@keyframes land {
  from { opacity: 0; transform: translateY(30px) scale(.96); }
  to   { opacity: 1; transform: none; }
}

@keyframes drift {
  from { transform: translateY(0) rotate(var(--tilt, 0deg)); }
  to   { transform: translateY(-14px) rotate(var(--tilt, 0deg)); }
}

/* Content is never parked invisible: the animation runs on load, and if it
   never runs the element is already at its resting state. */
.up { animation: up 700ms cubic-bezier(.2, .8, .2, 1) both; }
.land { animation: land 800ms cubic-bezier(.2, .8, .2, 1) both; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* `hidden` has to win.
 *
 * The UA rule is `[hidden] { display: none }`, one specificity point, and any
 * class rule that sets display beats it. `.btn` sets `display: inline-flex`, so
 * every button in this product that was hidden with the attribute was on screen
 * anyway: "Load more" sat under every album that had nothing more to load.
 * Found by reading the computed style, which said hidden true and display
 * inline-flex at the same time. */
[hidden] { display: none !important; }

/* ----------------------------------------------------------------- viewer --- */

/* Shared by the guest album and the host album, so it lives here rather than in
   either one. Dark, because a photo is the whole point of the screen and a
   white surround changes how the picture reads. Ink, never #000. */

body.viewer-open { overflow: hidden; }

.viewer {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: grid;
  grid-template-rows: 1fr auto;
  /* Solid. The photo is the whole point of this screen, and a translucent
     backdrop left the album's headline and counters readable behind it. */
  background: var(--ink);
  /* A fade, not the `up` rise. `up` animates a transform, and a transform on a
     fixed element makes it the containing block for its own fixed positioning:
     the overlay sat 22px down the page and left a strip of the album showing
     along the top. Measured over CDP, not guessed. */
  animation: fade-in 200ms ease both;
}

@keyframes fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* The site's own furniture goes away while a photo is open. The bottom bar was
   sitting across the guest's name and the time. */
body.viewer-open .guest-nav,
body.viewer-open .pinned { display: none; }

.viewer-stage {
  margin: 0;
  position: relative;
  min-height: 0;
  padding: 56px 16px 8px;
  /* The outgoing photo slides out of this box, not across the close button
     and the name underneath it. */
  overflow: hidden;
  /* The whole stage is a tap target now: left third back, the rest forward.
     No text selection flash, no grey tap highlight on iOS. */
  -webkit-tap-highlight-color: transparent;
  user-select: none;
  touch-action: pan-y;
}

/* Absolutely placed inside the stage rather than sized with percentage maxima.
   A percentage max-height against a grid track resolves to nothing until the
   image has loaded, so a portrait photo overflowed the stage and got cropped on
   both sides for the first moment it was on screen. This cannot overflow. */
.viewer-stage img {
  position: absolute;
  inset: 56px 16px 8px;
  width: calc(100% - 32px);
  height: calc(100% - 64px);
  border-radius: 16px;
  object-fit: contain;
  /* Composited, so a slide is the GPU moving a texture and not the phone
     repainting a 1600 px photo every frame. */
  will-change: transform;
  -webkit-user-drag: none;
}

/* The spare image waits off stage with nothing in it. */
.viewer-stage img:not([src]) { visibility: hidden; }

/* ?viewer-debug only: numbers for measuring on a real phone. */
.viewer-debug {
  position: absolute;
  left: 10px;
  top: 12px;
  z-index: 2;
  margin: 0;
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  font: 12px/1.35 ui-monospace, Menlo, monospace;
  pointer-events: none;
  white-space: pre;
}

.viewer-bar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 16px 20px calc(20px + env(safe-area-inset-bottom));
  color: #fff;
}

.viewer-meta { display: grid; gap: 2px; min-width: 0; }
.viewer-meta strong { font-size: 17px; font-weight: 700; }
.viewer-meta .muted { color: rgba(255, 255, 255, .68); font-size: 14px; }

.viewer-actions { display: flex; gap: 10px; flex-wrap: wrap; }

.viewer-action {
  border: 2px solid rgba(255, 255, 255, .5);
  background: transparent;
  color: #fff;
  border-radius: 999px;
  padding: 10px 18px;
  font: inherit;
  font-weight: 700;
  font-size: 15px;
  cursor: pointer;
}

.viewer-action:hover { border-color: #fff; }
.viewer-action[disabled] { opacity: .5; cursor: default; }

.viewer-close,
.viewer-step {
  position: absolute;
  z-index: 1;
  border: 0;
  background: rgba(255, 255, 255, .14);
  color: #fff;
  border-radius: 999px;
  cursor: pointer;
  line-height: 1;
}

.viewer-close {
  top: 12px;
  right: 14px;
  width: 42px;
  height: 42px;
  font-size: 28px;
}

.viewer-step {
  top: 50%;
  transform: translateY(-50%);
  width: 46px;
  height: 46px;
  font-size: 30px;
}

.viewer-step.prev { left: 10px; }
.viewer-step.next { right: 10px; }

/* On a phone the gesture is the swipe, and two circles sitting over the photo
   are just something to hit by accident. */
@media (max-width: 700px) {
  .viewer-step { display: none; }
}
