/* Participant pages: "Winternacht mit Adventskalender" (design D). */

@font-face {
  font-family: "Bricolage Grotesque";
  src: url("/static/fonts/bricolage-grotesque.woff2") format("woff2");
  font-weight: 200 800;
  font-display: swap;
}
@font-face {
  font-family: "DM Sans";
  src: url("/static/fonts/dm-sans.woff2") format("woff2");
  font-weight: 100 1000;
  font-display: swap;
}

@font-face {
  font-family: "Caveat";
  src: url("/static/fonts/caveat.woff2") format("woff2");
  font-weight: 400 700;
  font-display: swap;
}

:root {
  --pine: #0f3b2e;
  --pine-mid: #174a39;
  --forest: #1e5a45;
  --green: #2c7a5c;
  --mint: #8fd3b6;
  --cream: #f3ead8;
  --cream-2: #e7dcc6;
  --paper: #fffaf0;
  --line: #e3d6bd;
  --line-strong: #d8cbb1;
  --mustard: #f2b544;
  --tomato: #e5533c;
  --ink: #0f3b2e;
  --sub: #cfe0d6;
  --muted-dark: #3d5a50;
  --muted-light: #9fb8ab;
  --display: "Bricolage Grotesque", system-ui, sans-serif;
  --body: "DM Sans", system-ui, sans-serif;
  --hand: "Caveat", "Segoe Print", "Bradley Hand", cursive;
  --rule: 34px;
  --mono: ui-monospace, "Cascadia Mono", Menlo, monospace;
  --gutter-left: max(20px, env(safe-area-inset-left));
  --gutter-right: max(20px, env(safe-area-inset-right));
}

* { box-sizing: border-box; }

body.winter {
  margin: 0;
  min-height: 100vh;
  background: var(--pine);
  color: var(--cream);
  font: 16px/1.5 var(--body);
  -webkit-font-smoothing: antialiased;
}
.winter :focus-visible { outline: 3px solid var(--mustard); outline-offset: 2px; }
.sr-only {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); white-space: nowrap;
}

/* ---------- Shared pieces ---------- */

.brand {
  display: inline-flex; align-items: center; gap: 8px;
  font: 800 1.25rem/1 var(--display); letter-spacing: -0.02em;
  color: var(--cream); text-decoration: none;
}
/* The present turns once around its upright axis when pointed at. */
.brand svg { width: 1.2em; height: 1.2em; transition: transform 0.7s ease-in-out; }
.brand:hover svg, .brand:focus-visible svg { transform: rotateY(360deg); }
@media (prefers-reduced-motion: reduce) {
  .brand:hover svg, .brand:focus-visible svg { transform: none; }
}

.eyebrow {
  margin: 0; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.12em;
  text-transform: uppercase; color: var(--mustard);
}
.pill {
  display: inline-block; margin: 0; padding: 7px 14px; border-radius: 999px;
  background: rgba(242, 181, 68, 0.14); color: var(--mustard); font-weight: 700; font-size: 0.875rem;
}

/* Rules info box on the dark header: every rule is an inset tile. */
/* A note taped to the sheet: the tape strip sits centred on its top edge. */
.rules {
  position: relative; margin-top: 8px; padding: 22px 18px 16px;
  border-radius: 14px; background: var(--paper); border: 1.5px solid var(--line);
  box-shadow: 0 6px 16px rgba(15, 59, 46, 0.08);
}
.rules::before {
  content: ""; position: absolute; top: -9px; left: 50%; width: 76px; height: 18px;
  border-radius: 3px; background: rgba(242, 181, 68, 0.75); transform: translateX(-50%) rotate(-2deg);
}
.rules-title { margin: 0 0 10px; text-align: center; font: 700 1.625rem/1.1 var(--hand); color: var(--forest); }
/* The list sits centred as a block, so the checks still line up below each other. */
.rules-list { display: grid; gap: 8px; width: fit-content; max-width: 100%; margin: 0 auto; padding: 0; list-style: none; }
.rules-list li { display: flex; align-items: flex-start; gap: 10px; font-weight: 600; overflow-wrap: anywhere; }
.rules-list svg { flex: none; margin-top: 2px; color: var(--tomato); }
.rules-list span { min-width: 0; }

.button {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  min-height: 50px; padding: 0 22px; border: 0; border-radius: 999px;
  background: var(--tomato); color: #fff; font: 800 1.0625rem/1 var(--display);
  text-decoration: none; cursor: pointer; transition: transform 0.15s ease, filter 0.15s ease;
}
.button:hover { filter: brightness(1.06); transform: translateY(-1px); }
.button--small { min-height: 44px; padding: 0 16px; font: 700 0.9375rem/1 var(--body); }
.button--ghost { background: transparent; color: var(--ink); border: 1.5px solid var(--line-strong); }

.icon-button {
  flex: none; display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px; border: 0; border-radius: 50%;
  background: transparent; color: #6f7f76; cursor: pointer;
}
.icon-button:hover { background: rgba(15, 59, 46, 0.08); color: var(--tomato); }

.field {
  width: 100%; min-height: 46px; padding: 0 14px; border: 1px solid var(--line-strong);
  border-radius: 12px; background: var(--paper); color: var(--ink); font: 1rem var(--body);
}
.field::placeholder { color: #8a9a90; }
.field--small { min-height: 44px; font-size: 0.875rem; }

.alert {
  margin: 0 0 14px; padding: 10px 14px; border-radius: 12px;
  background: rgba(229, 83, 60, 0.18); border: 1px solid rgba(229, 83, 60, 0.55); color: var(--cream);
}
.notice {
  margin: 0 0 14px; padding: 10px 14px; border-radius: 12px;
  background: rgba(242, 181, 68, 0.16); border: 1px solid rgba(242, 181, 68, 0.55); color: var(--cream);
}

.moon {
  position: absolute; top: 84px; right: 40px; width: 120px; height: 120px;
  border-radius: 50%; background: var(--mustard);
}
.moon::after {
  content: ""; position: absolute; top: 14px; left: 22px; width: 104px; height: 104px;
  border-radius: 50%; background: var(--pine);
}
.sky-dot { position: absolute; width: 5px; height: 5px; border-radius: 50%; background: var(--cream); }

/* Door tiles, used in the calendar and as wish numbers. */
.door { border-radius: 10px; padding: 6px 9px; font: 800 1.375rem/1 var(--display); }
.door--cream { background: var(--cream); color: var(--ink); }
.door--tomato { background: var(--tomato); color: #fff; }
.door--mustard { background: var(--mustard); color: var(--ink); }
.door--mint { background: var(--mint); color: var(--ink); }
.door--green { background: var(--green); color: var(--cream); }
.door--mint-outline { border: 2px solid var(--mint); color: var(--mint); }
.door--mustard-outline { border: 2px solid var(--mustard); color: var(--mustard); }
.door--wide { grid-column: span 2; display: flex; justify-content: space-between; }
.door--tall { grid-row: span 2; display: flex; flex-direction: column; justify-content: space-between; }

@keyframes door-open {
  from { transform: perspective(480px) rotateY(0); box-shadow: none; }
}

/* ---------- Landing ---------- */

.landing { position: relative; overflow: hidden; min-height: 100vh; }

/* Snowfall: painted before the hero and the hills, so flakes drift behind the house and the snow. */
.snow { position: fixed; inset: 0; overflow: hidden; pointer-events: none; }
.snow span {
  position: absolute; top: -12px; left: var(--x); width: var(--size); height: var(--size);
  border-radius: 50%; background: #fff; opacity: var(--opacity);
  animation: snowfall var(--duration) linear var(--delay) infinite;
}
@keyframes snowfall {
  0% { transform: translate(0, 0); }
  25% { transform: translate(14px, 27vh); }
  50% { transform: translate(-10px, 55vh); }
  75% { transform: translate(12px, 82vh); }
  100% { transform: translate(0, 110vh); }
}
/* Santa's sleigh: one flight across the sky; the landing script picks a new route and pause for every flight. */
.santa {
  --santa-y0: 90px; --santa-y1: 50px; --santa-y2: 100px;
  --santa-tilt0: -4deg; --santa-tilt1: 0deg; --santa-tilt2: 4deg;
  position: absolute; top: 0; left: 0; pointer-events: none;
  /* Both fill modes: before and after a flight the sleigh waits off-screen, never at its resting place top left. */
  animation: santa-fly 10s linear 1.5s both;
}
.santa-sleigh { display: block; width: 200px; height: auto; animation: santa-bob 1.2s ease-in-out infinite; }
/* Flying right to left: play the route backwards and mirror the sleigh, the tilts still match the slope. */
.santa--reversed { animation-direction: reverse; }
.santa--reversed .santa-sleigh { scale: -1 1; }
@keyframes santa-fly {
  0% { transform: translate(-240px, var(--santa-y0)) rotate(var(--santa-tilt0)); }
  50% { transform: translate(calc(50vw - 100px), var(--santa-y1)) rotate(var(--santa-tilt1)); }
  100% { transform: translate(calc(100vw + 40px), var(--santa-y2)) rotate(var(--santa-tilt2)); }
}
@keyframes santa-bob {
  50% { transform: translateY(-6px); }
}
/* A present lost from the sack: /static/santa.js drops it right after the sleigh in the page, so it falls
   behind the hero like the sleigh flies, and lands behind the hills' snow, on their curve. */
.santa-gift { position: absolute; top: 0; left: 0; width: 18px; height: 18px; margin: -9px 0 0 -9px; pointer-events: none; }
.santa-gift svg { display: block; width: 100%; height: 100%; }
@media (max-width: 600px) {
  .santa-gift { width: 14px; height: 14px; margin: -7px 0 0 -7px; }
}
@media (prefers-reduced-motion: reduce) {
  .snow, .santa { display: none; }
}

/* ---------- Christmas market (gift page) ---------- */

/* Fixed to the window and clipped, so it stays put while the lists scroll and never widens the page. */
.market { position: fixed; inset: 0; overflow: hidden; pointer-events: none; }

/* Strings of lights: the bulbs light up one after another, so the glow runs along the wire. */
.garland { position: absolute; left: 0; right: 0; }
.garland svg { display: block; width: 100%; height: calc(100% - 16px); overflow: visible; }
.bulb {
  position: absolute; width: 7px; height: 10px; margin: 1px 0 0 -3.5px; border-radius: 50% 50% 45% 45%;
  background: var(--bulb); opacity: 0.45;
  animation: bulb-glow 3s ease-in-out var(--delay) infinite;
}
.bulb--mustard { --bulb: var(--mustard); }
.bulb--tomato { --bulb: var(--tomato); }
.bulb--mint { --bulb: var(--mint); }
.bulb--cream { --bulb: var(--cream); }
@keyframes bulb-glow {
  0%, 60%, 100% { opacity: 0.45; box-shadow: none; }
  30% { opacity: 1; box-shadow: 0 0 10px 3px var(--bulb); }
}

/* The stalls stand in a row on a strip of snow; on a narrow window the outer ones are cut off. */
.stalls {
  position: absolute; left: 0; right: 0; bottom: 0;
  display: flex; justify-content: center; align-items: flex-end; gap: 14px;
}
.stalls::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 14px; background: var(--cream-2);
}
.stall { position: relative; flex: none; width: 170px; }
.stall svg { display: block; width: 100%; height: auto; }
.stall-glow { opacity: 0.35; animation: stall-flicker 4s ease-in-out var(--flicker-delay) infinite; }
.stall-lamp { animation: lamp-flicker 4s ease-in-out var(--flicker-delay) infinite; }
@keyframes stall-flicker {
  0%, 100% { opacity: 0.35; }
  40% { opacity: 0.5; }
  55% { opacity: 0.3; }
  70% { opacity: 0.45; }
}
@keyframes lamp-flicker {
  0%, 100% { opacity: 0.9; }
  40% { opacity: 1; }
  55% { opacity: 0.75; }
}
/* Steam curling up from the mulled wine. */
.steam {
  position: absolute; top: 60%; width: 6px; height: 14px; margin-left: -3px; border-radius: 50%;
  background: rgba(255, 255, 255, 0.55); filter: blur(2px); opacity: 0;
  animation: steam-rise 3s ease-out var(--delay) infinite;
}
@keyframes steam-rise {
  0% { transform: translate(0, 0) scale(0.8); opacity: 0; }
  30% { opacity: 0.7; }
  100% { transform: translate(4px, -30px) scale(1.4, 1.2); opacity: 0; }
}

@media (max-width: 600px) {
  .stall { width: 120px; }
  .stalls { gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
  .bulb, .stall-glow, .stall-lamp { animation: none; }
  .steam { display: none; }
}

/* ---------- Living room (gift page) ---------- */

/* Fixed to the window like the market, with a faintly striped wallpaper and a wooden floor along the bottom.
   The fireplace and the tree stand on either side of the 560px page column, like the village on the wish page. */
.stube {
  position: fixed; inset: 0; overflow: hidden; pointer-events: none;
  background: repeating-linear-gradient(90deg, transparent 0 46px, rgba(243, 234, 216, 0.03) 46px 50px), var(--pine);
}
.stube-floor {
  position: absolute; left: 0; right: 0; bottom: 0; height: 14px;
  background: #5a3a26; border-top: 3px solid #6b4429;
}
.stube-side { position: absolute; bottom: 10px; }
.stube-side--left { right: calc(50% + 296px); }
.stube-side--right { left: calc(50% + 296px); }
.stube-side svg { display: block; width: 100%; height: auto; overflow: visible; }

.fireplace { width: 200px; }
.fire-glow { opacity: 0.35; animation: stall-flicker 3s ease-in-out infinite; }
.flame {
  transform-box: fill-box; transform-origin: 50% 100%;
  animation: flame-flicker 0.9s ease-in-out var(--delay) infinite alternate;
}
@keyframes flame-flicker {
  0% { transform: scale(1, 0.9); }
  50% { transform: scale(0.9, 1.08); }
  100% { transform: scale(1.05, 0.95); }
}
.candle-flame, .tree-light { animation: lamp-flicker 4s ease-in-out var(--flicker-delay) infinite; }

.gift-tree { position: relative; width: 260px; }
.tree-star { animation: twinkle 2.4s ease-in-out infinite; }
/* A gift that is new since the last visit falls onto the pile, squashes a little and settles. */
.gift-box { transform-box: fill-box; transform-origin: 50% 100%; }
.gift-box--new { animation: gift-drop 0.8s cubic-bezier(0.3, 0, 0.6, 1) var(--drop-delay) both; }
@keyframes gift-drop {
  0% { transform: translateY(-180px); opacity: 0; }
  15% { opacity: 1; }
  65% { transform: translateY(0) scale(1.1, 0.88); }
  82% { transform: translateY(-6px) scale(0.97, 1.03); }
  100% { transform: none; }
}
/* A gift tag hangs from the lowest branch and counts the gifts. */
.pile-tag {
  position: absolute; left: -4%; top: 52%; padding: 4px 9px 4px 14px;
  border-radius: 4px 8px 8px 4px; background: var(--cream); color: var(--ink);
  font: 800 0.75rem/1.2 var(--display); white-space: nowrap;
  transform: rotate(-7deg); box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}
.pile-tag::before {
  content: ""; position: absolute; left: 5px; top: 50%; width: 4px; height: 4px; margin-top: -2px;
  border-radius: 50%; background: var(--pine);
}

/* On a narrow window the room shows below the sheet: the tree in the middle, the fireplace beside it. */
@media (max-width: 900px) {
  .stube-side--right { left: calc(50% - 80px); }
  .stube-side--left { right: calc(50% + 92px); }
  .gift-tree { width: 160px; }
  .fireplace { width: 130px; }
  .pile-tag { font-size: 0.6875rem; }
}
@media (max-width: 600px) {
  .stube-side--right { left: calc(50% - 70px); }
  .stube-side--left { right: calc(50% + 80px); }
  .gift-tree { width: 140px; }
  .fireplace { width: 110px; }
}
/* ---------- Night sky (wish page) ---------- */

/* The wish page sits under a midnight-blue polar night instead of the pine-green one. */
.winter--aurora { --pine: #0b1d33; --pine-mid: #142a4a; --sub: #cbd8ea; --muted-light: #9db1cb; }

/* Fixed to the window behind the page, like the Christmas market; the cream sheet covers its lower part.
   The sky darkens towards the top, the horizon above the village keeps a little light. */
.sky {
  position: fixed; inset: 0; overflow: hidden; pointer-events: none;
  background: linear-gradient(180deg, #06111f 0%, var(--pine) 45%, #12324a 100%);
}
/* The crescent is cut out with a mask rather than a disc in the sky colour, so the gradient and the polar
   lights show through it. */
.sky .moon {
  top: 64px; right: max(40px, calc(50% - 280px - 200px)); width: 96px; height: 96px;
  -webkit-mask: radial-gradient(circle 42px at 60px 53px, transparent 98%, #000 100%);
  mask: radial-gradient(circle 42px at 60px 53px, transparent 98%, #000 100%);
}
.sky .moon::after { display: none; }

/* Polar lights: wide, blurred bands that sway, stretch and brighten slowly, each at its own pace. */
.aurora { position: absolute; top: 0; left: 0; right: 0; height: 65vh; }
.aurora span {
  position: absolute; top: var(--top); left: -15vw; width: 130vw; height: 30vh; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(var(--glow), 0.55) 0%, rgba(var(--glow), 0) 70%);
  filter: blur(20px); mix-blend-mode: screen; opacity: 0.5; transform: rotate(var(--tilt));
  animation: aurora-sway var(--duration) ease-in-out var(--delay) infinite alternate;
}
@keyframes aurora-sway {
  from { transform: translateX(-6vw) rotate(var(--tilt)) scaleY(0.9); opacity: 0.35; }
  to { transform: translateX(6vw) rotate(calc(var(--tilt) * -1)) scaleY(1.3); opacity: 0.75; }
}
.star {
  position: absolute; left: var(--x); top: var(--y); width: 3px; height: 3px; border-radius: 50%;
  background: var(--cream); animation: star-twinkle var(--duration) ease-in-out var(--delay) infinite;
}
.star--big { width: 12px; height: 12px; margin: -4px 0 0 -4px; background: none; }
.star--big svg { display: block; width: 100%; height: 100%; }
@keyframes star-twinkle {
  0%, 100% { opacity: 0.9; transform: scale(1); }
  50% { opacity: 0.25; transform: scale(0.7); }
}

/* A shooting star: the outer layer sets start and slope, the trail rushes along it and fades out. */
.shooting-star {
  --star-x: 18vw; --star-y: 90px; --star-angle: 24deg; --star-distance: 380px;
  position: absolute; top: 0; left: 0;
  transform: translate(var(--star-x), var(--star-y)) rotate(var(--star-angle));
}
.shooting-star-trail {
  position: relative; display: block; width: 120px; height: 2px; border-radius: 2px;
  background: linear-gradient(90deg, transparent, rgba(255, 250, 240, 0.9));
  opacity: 0; animation: shooting-star 1.3s ease-in 2.5s both;
}
.shooting-star-trail::after {
  content: ""; position: absolute; top: -2px; right: -3px; width: 6px; height: 6px; border-radius: 50%;
  background: #fff; box-shadow: 0 0 10px 3px rgba(242, 181, 68, 0.6);
}
@keyframes shooting-star {
  0% { transform: translateX(0); opacity: 0; }
  15%, 65% { opacity: 1; }
  100% { transform: translateX(var(--star-distance)); opacity: 0; }
}

/* The village: one group on each side of the 560px page column, each growing outwards from it and cut off
   at the window edge. A strip of snow runs along the bottom, as under the market stalls. */
.village { position: absolute; left: 0; right: 0; bottom: 0; height: 180px; }
.village::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 14px; background: var(--cream-2);
}
.village-side { position: absolute; bottom: 0; display: flex; align-items: flex-end; gap: 14px; width: max-content; }
.village-side--left { right: calc(50% + 296px); }
.village-side--right { left: calc(50% + 296px); }
.house, .post-office, .mailbox { position: relative; flex: none; }
.house { width: 96px; }
.house:nth-child(odd) { width: 84px; }
.post-office { width: 200px; }
.mailbox { --send-delay: 3s; --letter-drift: 60px; width: 52px; margin-bottom: 4px; }
.village svg { display: block; width: 100%; height: auto; overflow: visible; }
.village-window, .village-lamp { animation: lamp-flicker 4s ease-in-out var(--flicker-delay) infinite; }

/* Smoke curling up from the chimneys. */
.smoke {
  position: absolute; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%;
  background: rgba(243, 234, 216, 0.4); filter: blur(3px); opacity: 0;
  animation: smoke-rise 5s ease-out var(--delay) infinite;
}
@keyframes smoke-rise {
  0% { transform: translate(0, 0) scale(0.6); opacity: 0; }
  20% { opacity: 0.8; }
  100% { transform: translate(14px, -48px) scale(2); opacity: 0; }
}

/* Posting a letter: the flap lifts, the letter slips out and rises while it sways from side to side. */
.mailbox-flap { transform-box: fill-box; transform-origin: left top; }
.mailbox--sending .mailbox-flap { animation: flap-open 1.4s ease-in-out var(--send-delay) both; }
@keyframes flap-open {
  0%, 100% { transform: none; }
  25%, 60% { transform: translateY(-3px) rotate(-14deg); }
}
.letter { position: absolute; top: 26%; left: 50%; width: 18px; margin-left: -9px; opacity: 0; }
.mailbox--sending .letter { animation: letter-rise 6s cubic-bezier(0.3, 0.1, 0.6, 1) calc(var(--send-delay) + 0.3s) both; }
.mailbox--sending .letter svg { animation: letter-sway 1.4s ease-in-out infinite alternate; }
@keyframes letter-rise {
  0% { transform: translateY(0) scale(0.6); opacity: 0; }
  8% { transform: translateY(-16px) scale(1); opacity: 1; }
  80% { opacity: 1; }
  100% { transform: translate(var(--letter-drift), -70vh) scale(0.5); opacity: 0; }
}
@keyframes letter-sway {
  from { transform: translateX(-14px) rotate(-12deg); }
  to { transform: translateX(14px) rotate(12deg); }
}

/* On a narrow window both sides are cut off, so the village gathers around the middle instead, where it
   shows below the sheet: the mailbox and the post office in the centre, the houses growing out from them. */
@media (max-width: 900px) {
  .sky .moon { display: none; }
  .village-side { gap: 8px; }
  .village-side--left { right: calc(50% + 107px); }
  .village-side--right { left: calc(50% - 99px); }
  .house { width: 72px; }
  .house:nth-child(odd) { width: 64px; }
  .post-office { width: 150px; }
  .mailbox { width: 40px; }
}
/* The tree sled walks along the strip of snow from one window edge to the other; the puller bobs with each
   step and leans into the rope. A trip to the left mirrors the whole group. */
.tree-sled {
  --trip-duration: 40s; --trip-delay: 8s;
  position: absolute; z-index: 1; left: 0; bottom: 3px;
  animation: sled-trip var(--trip-duration) linear var(--trip-delay) both;
}
.tree-sled--reversed { animation-name: sled-trip-back; }
.tree-sled-body { display: flex; align-items: flex-end; }
.tree-sled--reversed .tree-sled-body { transform: scaleX(-1); }
.tree-sled .tree-sled-load { width: 90px; flex: none; }
.tree-sled .person { margin: 0 0 1px -2px; }
.tree-sled .person svg { transform-origin: 50% 100%; animation: sled-step 0.45s ease-in-out infinite alternate; }
@keyframes sled-trip {
  from { transform: translateX(-160px); }
  to { transform: translateX(100vw); }
}
@keyframes sled-trip-back {
  from { transform: translateX(100vw); }
  to { transform: translateX(-160px); }
}
@keyframes sled-step {
  from { transform: rotate(6deg); }
  to { transform: translateY(-2px) rotate(10deg); }
}
@media (max-width: 900px) {
  .tree-sled .tree-sled-load { width: 66px; }
}

@media (prefers-reduced-motion: reduce) {
  .shooting-star, .smoke, .letter, .tree-sled { display: none; }
}

.landing-top, .landing-hero {
  position: relative; max-width: 1180px; margin: 0 auto;
  padding-left: var(--gutter-left); padding-right: var(--gutter-right);
}
.landing-top {
  display: flex; flex-wrap: wrap; gap: 8px 16px; align-items: center; justify-content: space-between;
  padding-top: 24px;
}
/* The year and the countdown sit side by side above the title; on a narrow screen the countdown moves below. */
.landing-pills { display: flex; flex-wrap: wrap; gap: 8px; }
.pill--countdown { background: rgba(143, 211, 182, 0.14); color: var(--mint); }
.landing-hero {
  display: flex; flex-wrap: wrap; gap: 48px; align-items: flex-start; justify-content: space-between;
  padding-top: 48px; padding-bottom: 200px;
}
.landing-copy { flex: 1 1 440px; min-width: 0; max-width: 600px; padding-top: 16px; }
.landing-title {
  margin: 22px 0 18px; font: 800 clamp(3rem, 9vw, 5.75rem)/0.92 var(--display); letter-spacing: -0.035em;
}
.landing-title span { color: var(--mustard); }
.landing-lead { margin: 0; max-width: 34ch; font-size: clamp(1.0625rem, 2vw, 1.25rem); color: var(--sub); }

.code-form { margin-top: 36px; max-width: 520px; }
.code-form label {
  display: block; margin-bottom: 10px; font-size: 0.8125rem; font-weight: 700;
  letter-spacing: 0.12em; text-transform: uppercase; color: var(--sub);
}
.code-row { display: flex; gap: 10px; }
.code-row input {
  flex: 1; min-width: 0; min-height: 62px; padding: 0 22px;
  border: 2px solid transparent; border-radius: 999px; background: var(--cream); color: var(--ink);
  font: 700 1.25rem/1 var(--mono); letter-spacing: 0.14em; text-transform: uppercase;
}
.code-row input::placeholder { color: #7d8f86; }
.code-row input:focus { outline: none; border-color: var(--mustard); box-shadow: 0 0 0 5px rgba(242, 181, 68, 0.3); }
.code-submit {
  flex: none; display: flex; align-items: center; justify-content: center;
  width: 62px; height: 62px; border: 0; border-radius: 50%;
  background: var(--tomato); color: #fff; cursor: pointer; transition: transform 0.15s ease;
}
.code-submit:hover { transform: translateX(2px); }
.welcome-back {
  display: inline-flex; align-items: center; gap: 14px; margin-top: 36px; min-height: 62px; padding: 0 28px;
  border-radius: 999px; background: var(--tomato); color: #fff; text-decoration: none;
  font: 800 1.375rem/1 var(--display); transition: transform 0.15s ease;
}
.welcome-back:hover { transform: translateX(2px); }
/* From the day of the gift exchange on, the photos are one tap away, too. */
.welcome-photos {
  display: inline-flex; align-items: center; margin: 12px 0 0 8px; min-height: 62px; padding: 0 24px;
  border-radius: 999px; background: var(--mustard); color: var(--ink); text-decoration: none;
  font: 800 1.1875rem/1 var(--display); transition: transform 0.15s ease;
}
.welcome-photos:hover { transform: translateY(-1px); }
.other-code { margin-top: 18px; }
.other-code summary {
  width: fit-content; cursor: pointer; font-weight: 700; color: var(--sub);
  text-decoration: underline; text-underline-offset: 3px;
}
.other-code .code-form { margin-top: 16px; }
.hint { margin: 12px 0 0; font-size: 0.875rem; color: var(--muted-light); }

/* The advent calendar, drawn as a Nordic house. */
.calendar { position: relative; flex: 0 1 540px; min-width: 0; margin: 0 auto; padding: 0 40px; }
.calendar-star { display: flex; justify-content: center; }
.calendar-star svg { width: 34px; height: 34px; }
.calendar-roof { position: relative; height: 104px; margin: 0 -14px; }
.calendar-roof::before, .calendar-roof::after {
  content: ""; position: absolute; clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
.calendar-roof::before { inset: 0; background: var(--cream); }
.calendar-roof::after { left: 22%; right: 22%; bottom: 0; height: 44px; background: var(--tomato); }
.calendar-grid {
  /* Fewer columns for a calendar of only a few days, so its doors still fill whole rows. */
  display: grid; grid-template-columns: repeat(var(--columns, 6), minmax(0, 1fr)); grid-auto-rows: 60px;
  grid-auto-flow: dense; gap: 8px; padding: 14px;
  background: var(--pine-mid); border: 3px solid var(--cream); border-top: 0; border-radius: 0 0 10px 10px;
}
.calendar-grid svg { width: 24px; height: 24px; }
.door-gift { position: relative; grid-column: span 2; grid-row: span 2; border-radius: 12px; background: var(--tomato); }
.door-gift-icon {
  position: absolute; top: 50%; right: 8%; display: block; width: 36%; max-width: 52px;
  color: var(--cream); transform: translateY(-50%);
}
.calendar-grid .door-gift-icon svg { display: block; width: 100%; height: auto; }
.door-gift-flap {
  position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: space-between;
  padding: 10px 12px; border-radius: 12px; background: var(--mustard); color: var(--ink);
  transform: perspective(480px) rotateY(-62deg); transform-origin: left center;
  box-shadow: 12px 10px 22px rgba(0, 0, 0, 0.35);
  animation: door-open 1.2s cubic-bezier(0.2, 0.8, 0.2, 1) 0.6s backwards;
}
.door-gift-flap strong { font: 800 2.6rem/1 var(--display); }

/* Until the wish start the gift door stays shut: a padlock hangs on its seam, swaying a little, and its tag
   counts the days. A code tried too early rattles it, and the code field shakes its head. */
.landing--locked .door-gift-flap { transform: none; box-shadow: none; animation: none; }
.padlock {
  position: absolute; top: 30%; right: -14px; z-index: 1; display: flex; flex-direction: column; align-items: center;
  width: 46px; transform-origin: 50% 0; animation: padlock-sway 3.2s ease-in-out infinite alternate;
}
.calendar-grid .padlock svg { display: block; width: 100%; height: auto; filter: drop-shadow(0 4px 6px rgba(0, 0, 0, 0.35)); }
.padlock-tag {
  margin-top: 4px; padding: 3px 7px; border-radius: 4px; background: var(--cream); color: var(--ink);
  font: 800 0.6875rem/1.1 var(--display); white-space: nowrap; transform: rotate(-6deg);
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25);
}
.landing--rattle .padlock { animation: padlock-rattle 0.7s ease-in-out 0.4s 2, padlock-sway 3.2s ease-in-out 1.8s infinite alternate; }
.landing--rattle .code-row { animation: head-shake 0.5s ease-in-out 0.2s; }
.landing--locked .code-form label svg { vertical-align: -2px; margin-right: 4px; }
@keyframes padlock-sway {
  from { transform: rotate(-5deg); }
  to { transform: rotate(5deg); }
}
@keyframes padlock-rattle {
  0%, 100% { transform: rotate(0); }
  15% { transform: rotate(-18deg) translateY(2px); }
  35% { transform: rotate(14deg); }
  55% { transform: rotate(-10deg) translateY(1px); }
  75% { transform: rotate(6deg); }
}
@keyframes head-shake {
  20%, 60% { transform: translateX(-8px); }
  40%, 80% { transform: translateX(8px); }
}
@media (prefers-reduced-motion: reduce) {
  .padlock, .landing--rattle .padlock, .landing--rattle .code-row { animation: none; }
}

.tree { position: absolute; bottom: -6px; }
.tree span { position: absolute; clip-path: polygon(50% 0, 100% 100%, 0 100%); }
/* The trunk is a pseudo-element, not a span, so the landing script keeps hanging baubles only on the triangles.
   It starts a little inside the lowest tier and fills the extra height below it, like the trunk of the mini tree. */
.tree::before {
  content: ""; position: absolute; bottom: 0; left: 50%; width: 14%; height: 20px;
  border-radius: 2px; background: #6b4429; transform: translateX(-50%);
}
.tree--left { left: -30px; width: 110px; height: 204px; }
.tree--left span:nth-child(1) { top: 0; left: 15px; width: 80px; height: 90px; background: var(--green); }
.tree--left span:nth-child(2) { top: 60px; left: 0; width: 110px; height: 130px; background: var(--forest); }
.tree--right { right: -24px; width: 90px; height: 162px; }
.tree--right span:nth-child(1) { top: 0; left: 12px; width: 66px; height: 70px; background: var(--mint); }
.tree--right span:nth-child(2) { top: 46px; left: 0; width: 90px; height: 104px; background: var(--green); }
/* A light spot up-left makes each bauble read as a shiny ball rather than a flat dot.
   Now and then it catches the light: a short glow, then it rests again for most of its cycle. */
.bauble {
  position: absolute; left: var(--x); top: var(--y); width: 10px; height: 10px; border-radius: 50%;
  background: radial-gradient(circle at 35% 35%, rgba(255, 255, 255, 0.7) 0 18%, transparent 30%), var(--color);
  transform: translate(-50%, -50%);
  animation: bauble-twinkle var(--duration, 5s) ease-in-out var(--delay, 0s) infinite;
}
@keyframes bauble-twinkle {
  0%, 70%, 100% { filter: none; box-shadow: none; }
  85% { filter: brightness(1.35); box-shadow: 0 0 8px 2px var(--color); }
}
@media (prefers-reduced-motion: reduce) {
  .bauble { animation: none; }
}

.hills > span { position: absolute; border-radius: 50%; pointer-events: none; }
.hills > span:nth-child(1) { left: -10%; bottom: -190px; width: 70%; height: 320px; background: var(--cream-2); }
.hills > span:nth-child(2) { right: -15%; bottom: -200px; width: 80%; height: 330px; background: var(--cream); }
/* Anchored at its feet on the hill's curve and set back into the snow, so it stands on the hill, not its rim. */
.snowman {
  position: absolute; left: var(--x); top: var(--y); width: 64px;
  transform: translate(-50%, -72%);
}
.snowman svg { display: block; width: 100%; height: auto; transform-origin: 50% 100%; }
.snowman--small { width: 42px; }
/* A wooden signpost on the left hill, anchored like a snowman: the post's foot on the curve, set into the snow.
   The board points right and carries a cap of snow along its top edge. */
.signpost {
  position: absolute; left: var(--x); top: var(--y); padding-bottom: 46px;
  transform: translate(-11px, calc(-100% + 10px));
}
.signpost::before {
  content: ""; position: absolute; left: 8px; top: 12px; bottom: 0; width: 7px;
  border-radius: 2px; background: #5a3a26;
}
.signpost-board {
  position: relative; display: block; padding: 8px 24px 6px 10px; white-space: nowrap;
  background: repeating-linear-gradient(180deg, transparent 0 9px, rgba(0, 0, 0, 0.08) 9px 10px), #8a5a36;
  box-shadow: inset 0 4px 0 #fff;
  clip-path: polygon(0 0, calc(100% - 14px) 0, 100% 50%, calc(100% - 14px) 100%, 0 100%);
  color: var(--cream); font: 800 0.75rem/1.2 var(--display); letter-spacing: 0.01em;
  transform: rotate(-4deg);
}

/* A child sledding down a hill, anchored like a snowman: the runners on the curve, a little sunk into the snow,
   and tilted along the slope by /static/sledding.js. A run to the left mirrors the drawing. */
.sledder {
  --tilt: 0deg;
  position: absolute; left: var(--x); top: var(--y); width: 54px;
  transform: translate(-50%, -86%) rotate(var(--tilt)); transform-origin: 50% 86%;
  transition: opacity 0.4s ease;
}
.sledder svg { display: block; width: 100%; height: auto; }
.sledder--left svg { transform: scaleX(-1); }
.sledder--away { opacity: 0; }
@media (max-width: 600px) {
  .sledder { width: 40px; }
}

/* Villagers on the wish page stand in the row between the houses, on the strip of snow. */
.person { position: relative; flex: none; width: 34px; margin-bottom: 2px; }
.person--kid { width: 28px; }
.person svg { display: block; width: 100%; height: auto; transform-origin: 50% 100%; }
@media (max-width: 900px) {
  .person { width: 26px; }
  .person--kid { width: 22px; }
}

/* Snowball fight, thrown by /static/snowballs.js among snowmen and villagers: the thrower leans back, the
   one hit wobbles on its feet. */
.snowball-throw svg { animation: snowball-throw 0.4s ease-out; }
.snowball-hit svg { animation: snowball-wobble 0.7s ease-out; }
@keyframes snowball-throw {
  40% { transform: rotate(var(--lean)); }
}
@keyframes snowball-wobble {
  20% { transform: rotate(var(--lean)); }
  45% { transform: rotate(calc(var(--lean) * -0.6)); }
  70% { transform: rotate(calc(var(--lean) * 0.3)); }
}
/* A snowman between the market stalls stands in the flow, on the strip of snow. */
.snowman--standing { position: relative; left: auto; top: auto; flex: none; width: 46px; margin-bottom: 2px; transform: none; }
.snowman--standing.snowman--small { width: 34px; }
@media (max-width: 600px) {
  .stalls .snowman--standing { width: 38px; }
  .stalls .snowman--standing.snowman--small { width: 28px; }
}
.snowball, .snow-crumb { position: absolute; top: 0; left: 0; border-radius: 50%; pointer-events: none; }
.snowball {
  width: 10px; height: 10px; margin: -5px 0 0 -5px;
  background: #fff; box-shadow: inset -2px -2px 0 #e3d6bd;
}
.snow-crumb { width: 4px; height: 4px; margin: -2px 0 0 -2px; background: #fff; }

@media (max-width: 600px) {
  .moon { top: 18px; right: 18px; width: 64px; height: 64px; }
  .moon::after { top: 8px; left: 12px; width: 56px; height: 56px; }
  .santa-sleigh { width: 130px; }
  .snowman { width: 46px; }
  .snowman--small { width: 32px; }
  .landing-hero { gap: 40px; padding-top: 28px; }
  .calendar { padding: 0 8px; }
  .calendar-roof { height: 70px; margin: 0 -6px; }
  .calendar-roof::after { height: 30px; }
  .calendar-grid { grid-auto-rows: 44px; gap: 6px; padding: 10px; }
  .door { padding: 4px 6px; font-size: 1rem; }
  .calendar-grid svg { width: 16px; height: 16px; }
  .door-gift-flap strong { font-size: 1.8rem; }
  .padlock { right: -10px; width: 34px; }
  .padlock-tag { font-size: 0.625rem; }
  .tree { display: none; }
}

/* ---------- Participant pages ---------- */

/* Positioned so it paints above the fixed scenes behind the pages. */
.page {
  position: relative;
  display: flex; flex-direction: column; max-width: 560px; min-height: 100vh; margin: 0 auto;
}
.head { position: relative; padding: 20px var(--gutter-right) 20px var(--gutter-left); }
.head-intro { padding-right: 124px; }
.title { margin: 6px 0 4px; font: 800 2.625rem/1 var(--display); letter-spacing: -0.03em; overflow-wrap: anywhere; }
.title--small { font-size: 2.25rem; line-height: 1.02; }
.head .eyebrow { margin-top: 24px; }
.sub { margin: 0 0 18px; font-size: 1rem; color: var(--sub); }
.sub:has(+ .dates) { margin-bottom: 6px; }
.dates {
  display: flex; flex-wrap: wrap; gap: 4px 16px; margin: 0 0 18px;
  font-size: 0.9375rem; font-weight: 700; color: var(--sub);
}
.dates span { white-space: nowrap; }
/* Below the intro and the tree the dates and the budget span the whole header as centred chips. */
.head-intro + .dates { justify-content: center; gap: 8px; margin: 4px 0 0; }
.head-intro + .dates > * { padding: 5px 12px; border-radius: 999px; background: rgba(243, 234, 216, 0.1); }
/* The place links to Google Maps; an address can be longer than the line, so it may wrap. */
.dates-place {
  color: inherit; overflow-wrap: anywhere;
  text-decoration: underline; text-decoration-style: dotted; text-underline-offset: 3px;
}
.dates-place::after { content: " ↗"; }
.dates-place:hover { color: var(--mustard); }

.head-intro .title { margin-top: 28px; }

.mini-tree { position: absolute; top: 24px; right: var(--gutter-right); width: 100px; height: 130px; }
.mini-tree-star { animation: twinkle 2.4s ease-in-out infinite; }
@keyframes twinkle {
  50% { opacity: 0.55; }
}

.sheet {
  flex: 1; display: flex; flex-direction: column; gap: 12px;
  padding: 22px max(18px, env(safe-area-inset-right)) calc(28px + env(safe-area-inset-bottom)) max(18px, env(safe-area-inset-left));
  border-radius: 28px 28px 0 0; background: var(--cream); color: var(--ink);
}
/* Pages with a scene along the bottom of the window. On a wide window it shows beside the column; on a narrow
   one the sheet would cover it, so the sheet ends above it with rounded corners and the scene shows below the
   list, right away on a short list and once scrolled to the end on a long one. */
.page--scene { --scene-height: 170px; }
@media (max-width: 900px) {
  .page--scene { padding-bottom: calc(var(--scene-height) + env(safe-area-inset-bottom)); }
  .page--scene .sheet { border-radius: 28px; padding-bottom: 28px; }
}
@media (max-width: 600px) {
  .page--scene { --scene-height: 150px; }
}
.sheet a { color: var(--forest); }
.sheet-head { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
.sheet h2 { margin: 0; font: 800 1.375rem/1.2 var(--display); letter-spacing: -0.02em; }
.count {
  display: flex; align-items: center; justify-content: center; min-width: 28px; height: 28px; padding: 0 8px;
  border-radius: 999px; background: var(--ink); color: var(--cream); font-weight: 700; font-size: 0.875rem;
}

/* The wish page as letters to the North Pole post. */

/* The form: a letter on ruled paper, its lower edge tucked into an open envelope. On sending, /static/wishes.js
   slides the paper in, closes the flap and presses the seal. */
.composer { display: flex; flex-direction: column; gap: 14px; }
.composer-envelope { position: relative; padding-top: 6px; }
.envelope-back {
  position: absolute; right: 0; bottom: 0; left: 0; height: 150px; border-radius: 10px; background: var(--cream-2);
}
.paper {
  position: relative; z-index: 1; margin: 0 14px; padding: 22px 22px 70px 60px; border-radius: 4px 4px 0 0;
  background: linear-gradient(90deg, transparent 0 46px, rgba(229, 83, 60, 0.28) 46px 47px, transparent 47px), var(--paper);
  box-shadow: 0 1px 0 var(--line), 0 10px 24px -14px rgba(15, 59, 46, 0.35);
  transform-origin: 50% 100%;
}
.paper:focus-within { box-shadow: 0 1px 0 var(--line), 0 0 0 3px rgba(242, 181, 68, 0.6); }
.salutation { margin: 0; font: 700 2rem/1.1 var(--hand); }
.paper-lead { display: block; margin-top: 4px; font: 500 1.5rem/var(--rule) var(--hand); color: var(--muted-dark); }
.ruled {
  display: block; width: 100%; margin: 0; padding: 0; border: 0; border-radius: 0; resize: none;
  background: repeating-linear-gradient(180deg, transparent 0 calc(var(--rule) - 1px), rgba(15, 59, 46, 0.16) calc(var(--rule) - 1px) var(--rule));
  color: var(--ink); font: 700 1.625rem/var(--rule) var(--hand);
}
.ruled::placeholder { color: #a7b2a9; }
.winter .ruled:focus-visible { outline: none; }
.ruled--wish { min-height: calc(var(--rule) * 3); overflow: hidden; }
.ps { display: flex; align-items: baseline; gap: 8px; margin-top: 14px; }
.ps label { flex: none; font: 700 1.375rem/var(--rule) var(--hand); color: var(--muted-dark); }
.ruled--link { flex: 1; min-width: 0; height: var(--rule); font: 600 0.9375rem/var(--rule) var(--body); }
.signature { margin: 14px 0 0; text-align: right; font: 700 1.625rem/1.05 var(--hand); color: var(--forest); overflow-wrap: anywhere; }
.pocket {
  position: relative; z-index: 2; height: 110px; margin-top: -64px; border-radius: 0 0 10px 10px;
  background: linear-gradient(180deg, rgba(15, 59, 46, 0.08), transparent 60%), var(--cream-2);
  clip-path: polygon(0 0, 50% 58%, 100% 0, 100% 100%, 0 100%);
}
.pocket-address {
  position: absolute; bottom: 14px; left: 18px; max-width: 60%;
  font: 700 0.6875rem/1.3 var(--body); letter-spacing: 0.12em; text-transform: uppercase; color: #6b7d73;
}
.pocket-stamp {
  position: absolute; right: 16px; bottom: 12px; display: grid; place-items: center; width: 44px; height: 50px;
  border: 2px dashed var(--line-strong); border-radius: 4px; font: 800 1.125rem/1 var(--display); color: #6b7d73;
}
.flap, .seal { position: absolute; display: none; }
.flap {
  right: 0; left: 0; z-index: 3; height: 92px; background: var(--cream-2);
  clip-path: polygon(0 0, 100% 0, 50% 100%); transform-origin: 50% 0;
}
.seal {
  z-index: 4; left: 50%; width: 46px; height: 46px; margin-left: -23px; padding: 11px; border-radius: 50%;
  background: radial-gradient(circle at 35% 30%, #f07a63, var(--tomato) 55%, #b83a26);
  box-shadow: 0 3px 6px rgba(15, 59, 46, 0.3);
}
.seal svg { display: block; width: 100%; height: 100%; }
.composer-actions { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; }
.chars { margin: 0; font-size: 0.875rem; font-weight: 600; color: #6b7d73; font-variant-numeric: tabular-nums; }
.chars--low { color: var(--tomato); }
.post-button {
  display: inline-flex; align-items: center; gap: 10px; min-height: 54px; margin-left: auto; padding: 0 22px;
  border: 0; border-radius: 999px; background: var(--mustard); color: var(--ink);
  font: 800 1.0625rem/1 var(--display); cursor: pointer;
  box-shadow: 0 4px 0 #c98f22; transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.post-button:hover { transform: translateY(-1px); }
.post-button:active { transform: translateY(3px); box-shadow: 0 1px 0 #c98f22; }

/* Every wish sent is an envelope with a sleigh-mail border, a stamp in its door colour and the postmark. */
.letters-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: 4px 12px; margin-top: 10px; }
.letters-progress { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; font-size: 0.875rem; font-weight: 700; color: var(--muted-dark); }
.letters-progress .count { min-width: 24px; height: 24px; }
.letters { display: grid; gap: 16px; margin: 0; padding: 0; list-style: none; }
.env {
  --tilt: -0.3deg;
  position: relative; display: flex; flex-direction: column; gap: 10px; padding: 18px 20px 12px;
  border-radius: 6px; background: var(--paper);
  box-shadow: 0 1px 0 var(--line-strong), 0 8px 18px -12px rgba(15, 59, 46, 0.45);
  transform: rotate(var(--tilt)); transition: transform 0.25s ease;
}
.env:nth-child(3n + 1) { --tilt: -0.8deg; }
.env:nth-child(3n + 2) { --tilt: 0.6deg; }
.env:hover { transform: rotate(0deg) translateY(-2px); }
.env::before {
  content: ""; position: absolute; inset: 0; padding: 5px; border-radius: inherit; pointer-events: none; opacity: 0.85;
  background: repeating-linear-gradient(135deg, var(--tomato) 0 10px, transparent 10px 16px, var(--forest) 16px 26px, transparent 26px 32px);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.env-top { position: relative; min-height: 58px; padding-right: 130px; }
.env-label { display: block; font: 700 0.6875rem/1.3 var(--body); letter-spacing: 0.12em; text-transform: uppercase; color: #6b7d73; }
.env-to { display: block; margin-top: 2px; font-size: 0.875rem; font-weight: 600; color: var(--muted-dark); }
/* The perforation: holes on an 8px grid, the inner area left whole. */
.env-stamp {
  position: absolute; top: -4px; right: 0; width: 52px; height: 60px; padding: 4px; background: var(--paper);
  transform: rotate(4deg); filter: drop-shadow(0 1px 2px rgba(15, 59, 46, 0.25));
  -webkit-mask: linear-gradient(#000 0 0) content-box, radial-gradient(circle at 4px 4px, transparent 2.4px, #000 2.7px) -4px -4px / 8px 8px;
  mask: linear-gradient(#000 0 0) content-box, radial-gradient(circle at 4px 4px, transparent 2.4px, #000 2.7px) -4px -4px / 8px 8px;
}
.env-stamp span {
  display: block; width: 100%; height: 100%; padding: 4px 6px;
  font: 800 1.375rem/1 var(--display); box-shadow: inset -5px 0 0 rgba(0, 0, 0, 0.12);
}
.env-postmark { position: absolute; top: 4px; right: 42px; width: 96px; height: auto; color: rgba(15, 59, 46, 0.42); transform: rotate(-10deg); }
.env-text { margin: 0; font: 700 1.75rem/1.15 var(--hand); overflow-wrap: anywhere; }
.env-foot {
  display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; padding-top: 8px;
  border-top: 1px dashed var(--line-strong);
}
.env-foot form { margin-left: auto; }
.sheet a.env-link {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%; padding: 4px 12px; border-radius: 999px;
  background: var(--cream-2); color: var(--forest); font-size: 0.8125rem; font-weight: 700; text-decoration: none; overflow-wrap: anywhere;
}
.env-link span { font-weight: 500; }
.env-link::after { content: "↗"; }
.sheet a.env-link:hover { background: var(--mustard); color: var(--ink); }
.env-meta { font-size: 0.8125rem; color: #5b6b62; }
.env-back {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 12px; border: 0; border-radius: 999px;
  background: transparent; color: #5b6b62; font: 700 0.8125rem/1 var(--body); cursor: pointer;
}
.env-back:hover { background: rgba(229, 83, 60, 0.1); color: var(--tomato); }

/* A wish just added: the envelope drops onto the pile, its stamp lands and the postmark hits, then the count bumps. */
.env--new { animation: env-arrive 0.45s ease-out backwards; }
.env--new .env-stamp { animation: stamp-land 0.55s cubic-bezier(0.3, 1.5, 0.5, 1) 0.3s backwards; }
.env--new .env-postmark { animation: postmark-hit 0.3s ease-out 0.8s backwards; }
@keyframes env-arrive {
  from { opacity: 0; transform: translateY(-16px) rotate(var(--tilt)); }
}
@keyframes stamp-land {
  from { opacity: 0; transform: rotate(-20deg) scale(1.9); }
}
@keyframes postmark-hit {
  from { opacity: 0; transform: rotate(-10deg) scale(1.3); }
}
.count--bump { animation: count-bump 0.5s ease-out 0.9s; }
@keyframes count-bump {
  40% { transform: scale(1.35); background: var(--tomato); }
}
/* A wish taken back: the envelope slides off the pile before the page reloads. */
.env--leaving { animation: env-leave 0.38s ease-in forwards; }
@keyframes env-leave {
  to { opacity: 0; transform: translateX(40px) rotate(6deg); }
}
.empty { margin: 0; padding: 14px; border-radius: 18px; background: var(--paper); color: var(--muted-dark); }
.empty-letters {
  margin: 0; padding: 20px 16px; border: 2px dashed rgba(15, 59, 46, 0.25); border-radius: 12px;
  text-align: center; font: 700 1.5rem/1.2 var(--hand); color: var(--muted-dark);
}

@media (max-width: 440px) {
  .paper { margin: 0 8px; padding: 18px 14px 66px; background: var(--paper); }
  .env-top { padding-right: 70px; }
  .env-postmark { display: none; }
}

/* The letter flying from the form to the mailbox (/static/wishes.js). */
.flying-letter { position: fixed; z-index: 50; width: 28px; margin: -10px 0 0 -14px; pointer-events: none; }
.flying-letter svg { display: block; width: 100%; height: auto; }

.lock { display: flex; align-items: flex-start; gap: 10px; margin: 4px 0 0; font-size: 0.8125rem; color: var(--muted-dark); }
.lock svg { flex: none; margin-top: 1px; }
.fineprint { margin: 0; font-size: 0.75rem; color: #5b6b62; }

/* After the draw: two doors with the people to give a gift to. */
.gift-doors { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 16px 0; }
.gift-door {
  position: relative; display: block; height: 128px; border: 3px solid transparent; border-radius: 16px;
  background: var(--cream); color: var(--ink); text-decoration: none;
}
.gift-door[aria-current="true"] { border-color: var(--mustard); }
.gift-door-label { position: absolute; right: 12px; bottom: 12px; left: 50%; text-align: right; }
.gift-door-label small { display: block; font-size: 0.75rem; font-weight: 700; color: var(--muted-dark); }
.gift-door-label strong { display: block; font: 800 1.5rem/1.05 var(--display); overflow-wrap: anywhere; }
.gift-door-flap {
  position: absolute; top: 0; bottom: 0; left: 0; width: 46%; padding: 8px 10px; border-radius: 12px;
  font: 800 1.375rem/1 var(--display);
  transform: perspective(300px) rotateY(-48deg); transform-origin: left center;
  box-shadow: 8px 6px 14px rgba(0, 0, 0, 0.3);
  animation: gift-door-open 1.1s cubic-bezier(0.2, 0.8, 0.2, 1) 0.4s backwards;
}
.gift-door:nth-child(2) .gift-door-flap { animation-delay: 0.7s; }
@keyframes gift-door-open {
  from { transform: perspective(300px) rotateY(0); box-shadow: none; }
}

.gift-list { display: flex; flex-direction: column; gap: 12px; }
.gift-list h3 { margin: 0; font: 800 1.125rem/1.2 var(--display); }

/* Children only receive gifts; their lists follow the participant's own. */
.children { display: flex; flex-direction: column; gap: 12px; margin-top: 12px; padding-top: 20px; border-top: 2px dashed rgba(15, 59, 46, 0.2); }
.children-intro { margin: 4px 0 0; font-size: 0.875rem; color: var(--muted-dark); }
.gift-list[hidden] { display: none; }
.item-text { font-weight: 700; overflow-wrap: anywhere; }
.item-link {
  display: inline-flex; align-items: center; gap: 4px; max-width: 100%; padding: 3px 10px; border-radius: 999px;
  background: var(--cream-2); font-size: 0.8125rem; font-weight: 700; text-decoration: none; overflow-wrap: anywhere;
}
.item-link::after { content: "↗"; }
.item-link:hover { background: var(--mustard); color: var(--ink); }
.gift {
  display: flex; flex-direction: column; gap: 10px; padding: 12px;
  border-radius: 18px; background: var(--paper); border: 1px solid var(--line);
}
.gift--taken { flex-direction: row; align-items: center; justify-content: space-between; background: #efe5d2; }
.gift--taken .item-text { color: #5b6b62; }
.gift-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; }
.badge {
  display: inline-flex; align-items: center; gap: 6px; padding: 6px 12px; border-radius: 999px;
  font-weight: 700; font-size: 0.875rem; white-space: nowrap;
}
.badge--mine { background: #d4efe2; color: #14523c; }
.badge--taken { background: #e0d4bd; color: #4a5a51; font-size: 0.8125rem; }

/* ---------- Own snowman ---------- */

.own-snowman { display: inline-block; flex: none; width: 34px; }
.own-snowman svg { display: block; width: 100%; height: auto; }
.gift-list-title { display: flex; align-items: flex-end; gap: 10px; }
.gift-list-title .own-snowman { width: 30px; margin-bottom: -2px; }
/* In the half-open gift door, above the name; the flap covers the left part of the door. */
.gift-door-snowman { position: absolute; top: 10px; right: 12px; width: 32px; }

.dresser {
  display: flex; align-items: center; gap: 16px; margin-top: 12px; padding: 16px;
  border-radius: 20px; background: var(--paper); border: 1px solid var(--line);
}
.dresser-preview {
  flex: none; display: flex; align-items: flex-end; justify-content: center; width: 86px; height: 110px;
  border-radius: 16px; background: linear-gradient(180deg, var(--pine-mid) 0 70%, var(--cream-2) 70%);
}
.dresser-preview .own-snowman { width: 66px; margin-bottom: 14px; }
.dresser-preview--hop .own-snowman svg { transform-origin: 50% 100%; animation: snowman-hop 0.5s ease-out; }
@keyframes snowman-hop {
  30% { transform: translateY(-10px) scale(0.96, 1.04); }
  60% { transform: translateY(0) scale(1.06, 0.94); }
}
.dresser-form { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 10px; }
.dresser-form h2 { font-size: 1.1875rem; }
.dresser-intro { margin: -6px 0 0; font-size: 0.875rem; color: var(--muted-dark); }
.figure-picker {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(44px, 1fr)); gap: 6px; margin: 0; padding: 0; border: 0;
}
.figure-picker legend { margin-bottom: 4px; padding: 0; font-size: 0.8125rem; font-weight: 700; color: var(--muted-dark); }
.figure-option {
  position: relative; display: flex; align-items: flex-end; justify-content: center; height: 54px; padding: 4px;
  border-radius: 12px; background: var(--cream); cursor: pointer; transition: transform 0.15s ease;
}
.figure-option:hover { transform: translateY(-2px); }
.figure-option svg { display: block; width: 34px; height: auto; }
.figure-option input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.figure-option:has(input:checked) { background: var(--cream-2); box-shadow: 0 0 0 2px var(--ink); }
.figure-option:has(input:focus-visible) { outline: 3px solid var(--mustard); outline-offset: 2px; }
.swatches { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; margin: 0; padding: 0; border: 0; }
.swatches legend { margin-bottom: 4px; padding: 0; font-size: 0.8125rem; font-weight: 700; color: var(--muted-dark); }
.swatch {
  position: relative; width: 30px; height: 30px; border-radius: 50%; cursor: pointer;
  background: var(--swatch); box-shadow: inset 0 0 0 1px rgba(15, 59, 46, 0.2);
  transition: transform 0.15s ease;
}
.swatch:hover { transform: scale(1.1); }
.swatch input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.swatch:has(input:checked) { box-shadow: 0 0 0 3px var(--paper), 0 0 0 5px var(--ink); }
.swatch:has(input:focus-visible) { outline: 3px solid var(--mustard); outline-offset: 4px; }
.dresser-actions { display: flex; align-items: center; gap: 10px; min-height: 20px; }
/* .button would show it again: /static/snowman.js hides it, as every pick is saved right away. */
.dresser-actions .button[hidden] { display: none; }
.dresser-status { font-size: 0.8125rem; font-weight: 700; color: var(--green); }
/* The dresser waits as a dialog (/static/snowman.js); without JavaScript the link to it shows it in the page. */
.dresser-dialog {
  position: relative; width: min(520px, calc(100vw - 32px)); max-height: calc(100dvh - 32px); margin: 0;
  overflow-y: auto; color: var(--ink);
}
.dresser-dialog .dresser-preview { align-self: flex-start; }
.dresser-dialog:not([open]):not(:target) { display: none; }
.dresser-dialog[open] { margin: auto; }
.dresser-dialog::backdrop { background: rgba(7, 31, 23, 0.7); }
.dresser-close {
  position: absolute; top: 8px; right: 8px; width: 40px; height: 40px; border: 0; border-radius: 50%;
  background: rgba(15, 59, 46, 0.08); color: var(--ink); font: 800 1.5rem/1 var(--display); cursor: pointer;
}
.dresser-close[hidden] { display: none; }
.dresser-dialog .dresser-form h2 { padding-right: 40px; }
/* The way to the dresser: the snowman as it is dressed now, in the header or beside a child's name. */
.snowman-button {
  display: inline-flex; align-items: flex-end; gap: 8px; padding: 6px 14px 6px 10px; border-radius: 999px;
  background: rgba(243, 234, 216, 0.12); color: var(--cream); font-size: 0.9375rem; font-weight: 700;
  text-decoration: none; transition: background 0.15s ease;
}
.snowman-button:hover { background: rgba(243, 234, 216, 0.22); }
.snowman-button .own-snowman { width: 22px; }
.snowman-button span { padding-bottom: 2px; }
.snowman-button:hover .own-snowman svg { transform-origin: 50% 100%; animation: snowman-hop 0.5s ease-out; }
/* Beside "Hey Name,": just the snowman, which hops a little now and then to show it can be tapped. */
.title--snowman { display: flex; align-items: flex-end; gap: 12px; }
.title--snowman > span { min-width: 0; }
.snowman-button--title { flex: none; padding: 0; background: none; border-radius: 12px; }
.snowman-button--title:hover { background: none; }
.snowman-button--title .own-snowman { width: 40px; }
.snowman-button--title:focus-visible { outline: 3px solid var(--mustard); outline-offset: 4px; }
.snowman-button--title .own-snowman svg { transform-origin: 50% 100%; animation: snowman-nudge 6s ease-in-out 2s infinite; }
.snowman-button--title:hover .own-snowman svg { animation: snowman-hop 0.5s ease-out; }
/* The pencil on the figure beside the title, as on a profile picture: it can be changed. */
.snowman-button--title { position: relative; }
.snowman-button .snowman-badge {
  position: absolute; right: -7px; bottom: -3px; display: grid; place-items: center; width: 22px; height: 22px;
  padding: 0; border-radius: 50%; background: var(--mustard); color: var(--ink);
  box-shadow: 0 0 0 2px rgba(11, 29, 51, 0.55); transition: transform 0.15s ease;
}
.snowman-button--title:hover .snowman-badge { transform: scale(1.12); }
/* Until the own figure is dressed for the first time: what it is for and the way to it. */
.dress-hint {
  display: flex; align-items: center; gap: 14px; padding: 14px 16px;
  border-radius: 20px; background: var(--cream-2); border: 1px solid var(--line); color: var(--ink);
}
.dress-hint-figure {
  flex: none; display: flex; align-items: flex-end; justify-content: center; width: 56px; height: 64px;
  border-radius: 14px; background: linear-gradient(180deg, var(--pine-mid) 0 70%, var(--cream) 70%);
}
.dress-hint-figure .own-snowman { width: 38px; margin-bottom: 8px; }
.dress-hint-figure .own-snowman svg { transform-origin: 50% 100%; animation: snowman-nudge 6s ease-in-out 1s infinite; }
.dress-hint-text { flex: 1; min-width: 0; }
.dress-hint h2 { font: 800 1.1875rem/1.2 var(--display); }
.dress-hint p { margin: 2px 0 0; font-size: 0.875rem; color: var(--muted-dark); }
.sheet .dress-hint .button { flex: none; color: #fff; }
@media (max-width: 420px) {
  .dress-hint { flex-wrap: wrap; }
  .sheet .dress-hint .button { flex: 1 1 100%; }
}
@keyframes snowman-nudge {
  0%, 88%, 100% { transform: none; }
  92% { transform: translateY(-6px) rotate(-4deg); }
  96% { transform: translateY(0) rotate(3deg); }
}
.snowman-button--small {
  margin-left: auto; padding: 4px 12px 4px 8px; background: var(--paper); color: var(--ink);
  border: 1px solid var(--line); font-size: 0.8125rem;
}
.snowman-button--small:hover { background: var(--cream-2); }
.snowman-button--small .own-snowman { width: 18px; }
@media (max-width: 420px) {
  .dresser { flex-direction: column; align-items: stretch; }
  .dresser-preview { width: 100%; height: 96px; }
  .dresser-preview .own-snowman { width: 56px; margin-bottom: 10px; }
}

/* ---------- Photos of the party ---------- */

.photos-banner {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px;
  border-radius: 20px; background: var(--mustard); color: var(--ink); text-decoration: none;
  transition: transform 0.15s ease, filter 0.15s ease;
}
.sheet a.photos-banner { color: var(--ink); }
.photos-banner:hover { filter: brightness(1.04); transform: translateY(-1px); }
.photos-banner > span:nth-child(2) { flex: 1; min-width: 0; }
.photos-banner strong { display: block; font: 800 1.1875rem/1.2 var(--display); }
.photos-banner small { display: block; font-size: 0.875rem; color: var(--muted-dark); }
.photos-banner-icon { font-size: 1.75rem; line-height: 1; }

.back-link { color: var(--sub); font-weight: 700; font-size: 0.9375rem; }
.back-link:hover { color: var(--mustard); }

/* Lights across the top and falling snow behind the photo page. */
.photo-backdrop { position: fixed; inset: 0; overflow: hidden; pointer-events: none; }

/* Who took photos: their snowmen overlap like a group photo. */
.photo-stats { display: flex; align-items: center; gap: 14px; margin: 0 0 16px; font-weight: 700; color: var(--sub); }
.photo-stats strong { color: var(--cream); }
.photo-stats-snowmen { display: flex; flex: none; padding-right: 8px; }
.photo-stats-snowmen .own-snowman {
  width: 36px; height: 36px; margin-right: -10px; padding: 4px 6px 0; overflow: hidden;
  border-radius: 50%; background: var(--pine-mid); border: 2px solid var(--pine);
}
.photo-download { margin: 0 0 14px; background: var(--mustard); color: var(--ink); }
/* .button would show it again; /static/photos.js shows it with the first photo. */
.photo-download[hidden] { display: none; }
.back-link { display: block; width: fit-content; }

/* The page column holds only the header and the card for sharing; the photos get the whole night below it. */
.page--photos { min-height: 0; }
.photo-sheet { flex: none; border-radius: 28px; padding-bottom: 22px; }
.photo-upload { display: flex; flex-direction: column; gap: 10px; }
.photo-area {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 20px;
  max-width: 1000px; margin: 0 auto;
  padding: 8px var(--gutter-right) 28px var(--gutter-left);
}
.photo-area > * { width: 100%; }
.photo-area > .view-switch { width: auto; }
.photo-closed { margin: 0; text-align: center; font-weight: 700; color: var(--sub); }
.photo-area .empty { max-width: 560px; text-align: center; }
.photo-upload h2 { font-size: 1.25rem; }
/* The whole button opens the camera or the gallery; the file field inside it stays hidden. */
.photo-pick { width: 100%; min-height: 60px; font-size: 1.1875rem; }
.photo-pick:has(input:focus-visible) { outline: 3px solid var(--mustard); outline-offset: 2px; }
.photo-pick:has(input:disabled) { opacity: 0.6; pointer-events: none; }
/* .button would show it again: /static/photos.js hides it, as picked photos go up right away. */
.photo-upload .button[hidden] { display: none; }
.photo-hint { margin: 0; font-size: 0.8125rem; color: var(--muted-dark); }
.photo-status { margin: 0; font-weight: 700; color: var(--green); }
.photo-status:empty { display: none; }

/* The timeline: a dashed line down the left with the time of each photo on it. */
.photo-timeline { position: relative; display: flex; flex-direction: column; gap: 26px; padding: 6px 0 4px; }
.photo-timeline:not(:has(.photo-card)) { display: none; }
.photo-timeline::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 27px; border-left: 2px dashed rgba(15, 59, 46, 0.22);
}
.photo-card { display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 12px; align-items: start; }
.photo-card-time {
  position: relative; display: flex; flex-direction: column; align-items: center; gap: 3px; padding-top: 18px;
}
.photo-card-time strong {
  padding: 4px 8px; border-radius: 999px; background: var(--ink); color: var(--cream);
  font: 800 0.8125rem/1.1 var(--display); font-variant-numeric: tabular-nums;
}
.photo-card-time small {
  padding: 0 2px; background: var(--cream); font-size: 0.6875rem; font-weight: 700; color: var(--muted-dark);
  white-space: nowrap;
}

/* Every photo as a polaroid, slightly askew, with a strip of tape at the top. */
.polaroid {
  position: relative; margin: 0; padding: 10px 10px 0; border-radius: 3px; background: #fff;
  box-shadow: 0 1px 3px rgba(15, 59, 46, 0.12), 0 12px 26px rgba(15, 59, 46, 0.14);
  transform: rotate(var(--tilt)); transition: transform 0.2s ease;
}
.polaroid:hover { transform: rotate(0deg) scale(1.01); }
.polaroid::before {
  content: ""; position: absolute; top: -11px; left: 50%; width: 88px; height: 22px; margin-left: -44px;
  background: rgba(242, 181, 68, 0.6); box-shadow: 0 1px 2px rgba(15, 59, 46, 0.1);
  transform: rotate(calc(var(--tilt) * -2.5));
}
.polaroid-image { display: block; background: var(--cream-2); }
.polaroid-image img { display: block; width: 100%; height: auto; max-height: 75vh; object-fit: contain; background: #fff; }
.polaroid-caption { display: flex; flex-direction: column; gap: 6px; padding: 12px 4px 14px; }
.polaroid-text { font: 700 1.1875rem/1.3 var(--display); color: var(--ink); overflow-wrap: anywhere; }
.polaroid-who { display: flex; align-items: center; gap: 8px; font-size: 0.875rem; font-weight: 700; color: var(--muted-dark); }
.polaroid-who .own-snowman { width: 20px; }
/* The heart under the photo: an outline to give, red and full once given, with whose hearts it has beside it. */
.photo-likes { display: flex; align-items: center; gap: 10px; min-height: 40px; }
.photo-likes form { margin: 0; }
.photo-likers { min-width: 0; font-size: 0.875rem; color: var(--muted-dark); overflow-wrap: anywhere; }
.like-button {
  display: inline-flex; align-items: center; gap: 6px; min-height: 40px; padding: 0 14px 0 10px; border: 0;
  border-radius: 999px; cursor: pointer; background: var(--cream); color: var(--tomato);
  font: 800 0.9375rem/1 var(--display); font-variant-numeric: tabular-nums;
  transition: background-color 0.15s ease;
}
.like-button:hover { background: var(--cream-2); }
.like-button .heart {
  width: 22px; height: 22px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linejoin: round;
  transition: fill 0.15s ease;
}
.like-button[aria-pressed="true"] .heart { fill: currentColor; }
.like-button--pop .heart { animation: heart-pop 0.5s cubic-bezier(0.3, 1.6, 0.5, 1); }
.polaroid-delete { position: absolute; top: 18px; right: 18px; }
.polaroid-delete .icon-button { background: rgba(255, 250, 240, 0.92); color: var(--ink); box-shadow: 0 2px 6px rgba(15, 59, 46, 0.2); }
.polaroid-delete .icon-button:hover { color: var(--tomato); }

/* A photo that just came in drops onto the page. */
.photo-card--new .polaroid { animation: photo-drop 0.7s cubic-bezier(0.2, 0.8, 0.3, 1.2) both; }
@keyframes photo-drop {
  from { opacity: 0; transform: translateY(-28px) rotate(calc(var(--tilt) * 5)) scale(0.92); }
}
@media (prefers-reduced-motion: reduce) {
  .photo-card--new .polaroid { animation: none; }
  .polaroid, .polaroid:hover { transition: none; }
}
@media (max-width: 420px) {
  .photo-card { grid-template-columns: 44px minmax(0, 1fr); gap: 8px; }
  .photo-timeline::before { left: 21px; }
  .photo-card-time strong { padding: 4px 6px; font-size: 0.75rem; }
}

/* ---------- The photos on the Christmas tree ---------- */

.view-switch {
  display: flex; gap: 4px; padding: 4px; border-radius: 999px;
  background: rgba(243, 234, 216, 0.1); border: 1.5px solid rgba(243, 234, 216, 0.18);
}
.view-switch[hidden] { display: none; }
.view-switch button {
  min-height: 40px; padding: 0 16px; border: 0; border-radius: 999px; cursor: pointer;
  background: transparent; color: var(--sub); font: 700 0.9375rem var(--body);
}
.view-switch button[aria-pressed="true"] { background: var(--cream); color: var(--ink); }

/* The list in the night: a light line, the times as cream pills, the polaroids at most as wide as the column.
   Without JavaScript the page shows the list; /static/photos.js hangs the photos on the tree. */
.photo-wall--tree .photo-timeline, .photo-wall:not(.photo-wall--tree) .photo-tree { display: none; }
.photo-timeline { max-width: 560px; margin: 0 auto; }
.photo-wall .photo-timeline::before { border-left-color: rgba(243, 234, 216, 0.28); }
.photo-wall .photo-card-time strong { background: var(--cream); color: var(--ink); }
.photo-wall .photo-card-time small { background: var(--pine); color: var(--sub); }

/* One tree as tall as the window: the more photos hang on it, the smaller the baubles get. /static/photos.js
   places them row by row inside the outline of the branches; the drawing stretches to the size of the box. */
/* As tall as the window and about as wide as tall, but never slimmer than a fir: at most 1.45 times as tall as
   the page is wide. */
.photo-tree {
  --tree-height: min(clamp(440px, calc(100vh - 24px), 1200px), calc((100vw - 40px) * 1.45));
  position: relative; width: min(100%, var(--tree-height)); height: var(--tree-height); margin: 0 auto;
  -webkit-tap-highlight-color: transparent;
}
@supports (height: 100svh) {
  .photo-tree { --tree-height: min(clamp(440px, calc(100svh - 24px), 1200px), calc((100vw - 40px) * 1.45)); }
}
/* A warm halo around the tree, breathing slowly. */
.photo-tree::before {
  content: ""; position: absolute; top: 12%; right: 4%; bottom: 8%; left: 4%; border-radius: 50%;
  background: radial-gradient(ellipse at 50% 58%, rgba(242, 181, 68, 0.11), rgba(242, 181, 68, 0.03) 48%, transparent 70%);
  filter: blur(14px); pointer-events: none; animation: tree-breathe 7s ease-in-out infinite alternate;
}
@keyframes tree-breathe {
  from { opacity: 0.7; transform: scale(0.97); }
  to { opacity: 1; transform: scale(1.03); }
}
.photo-tree-shape, .photo-tree-decor, .photo-tree-lights {
  position: absolute; inset: 0; width: 100%; height: 100%; overflow: visible;
}
.tree-tier-shadow { fill: #0a2f22; opacity: 0.85; }
.tree-tier-needles {
  fill: none; stroke: #6cc596; stroke-width: 1.2; stroke-linecap: round; opacity: 0.35;
  vector-effect: non-scaling-stroke;
}
.tree-tier-snow { fill: var(--cream); }
.photo-tree-glow { mix-blend-mode: screen; animation: tree-glow 5s ease-in-out infinite alternate; }
@keyframes tree-glow {
  from { opacity: 0.4; }
  to { opacity: 0.65; }
}
/* Frost glinting here and there on the branches. */
.tree-sparkle {
  position: absolute; width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px; pointer-events: none;
  background: #fff; clip-path: polygon(50% 0, 62% 38%, 100% 50%, 62% 62%, 50% 100%, 38% 62%, 0 50%, 38% 38%);
  filter: drop-shadow(0 0 3px #fff); opacity: 0; animation: sparkle 4s ease-in-out var(--delay) infinite;
}
@keyframes sparkle {
  0%, 70%, 100% { opacity: 0; transform: scale(0.2) rotate(0deg); }
  82% { opacity: 1; transform: scale(1) rotate(45deg); }
}
/* Candles on the tips of the branches: a cream stick in a golden clip, the flame flickering on its own. */
.photo-tree-candles { position: absolute; inset: 0; z-index: 2; pointer-events: none; }
.tree-candle {
  position: absolute; width: 6px; height: 20px; margin-left: -3px; transform: translateY(-100%);
  border-radius: 1.5px 1.5px 0 0; background: linear-gradient(90deg, #fffaf0, #f3ead8 50%, #d3c6ab);
  box-shadow: 0 3px 0 #c9a24a;
}
.tree-candle::after {
  content: ""; position: absolute; bottom: 100%; left: 50%; width: 1px; height: 3px; margin-left: -0.5px;
  background: #3a2a1a;
}
.tree-candle::before {
  content: ""; position: absolute; bottom: calc(100% + 1px); left: 50%; width: 8px; height: 14px; margin-left: -4px;
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
  background: radial-gradient(ellipse at 50% 72%, #fff 0 18%, #ffd27a 45%, #f2a13a 85%);
  box-shadow: 0 0 8px 2px rgba(255, 196, 92, 0.45); transform-origin: 50% 100%;
  animation: candle-flicker 1.6s ease-in-out var(--delay) infinite alternate;
}
@keyframes candle-flicker {
  0% { transform: scale(1, 1) rotate(-2deg); }
  30% { transform: scale(0.9, 1.1) rotate(2.5deg); }
  60% { transform: scale(1.06, 0.94) rotate(-1deg); }
  100% { transform: scale(0.95, 1.05) rotate(1.5deg); }
}
/* The star with a slowly turning wreath of rays behind it. */
.photo-tree-star { position: absolute; top: -6px; left: 50%; z-index: 3; width: 64px; height: 64px; margin-left: -32px; }
.photo-tree-star::before {
  content: ""; position: absolute; inset: -110%; z-index: -1; border-radius: 50%; pointer-events: none;
  background: repeating-conic-gradient(rgba(255, 214, 122, 0.4) 0 5deg, transparent 5deg 20deg);
  -webkit-mask: radial-gradient(circle, #000 8%, transparent 62%); mask: radial-gradient(circle, #000 8%, transparent 62%);
  animation: star-rays 60s linear infinite;
}
@keyframes star-rays {
  to { transform: rotate(1turn); }
}
.photo-tree-star svg {
  display: block; width: 100%; height: 100%; animation: twinkle 2.4s ease-in-out infinite;
  filter: drop-shadow(0 0 12px rgba(242, 181, 68, 0.95));
}

/* The string of lights around the tree (/static/photos.js turns it): a light in front shines over the photos,
   one behind sits small and dim between the branches. Each one flickers on its own. */
.photo-tree-lights { pointer-events: none; }
.tree-light {
  position: absolute; top: 0; left: 0; width: 10px; height: 13px; margin: -6.5px 0 0 -5px;
  border-radius: 50% 50% 45% 45%; background: var(--bulb); box-shadow: 0 0 4px var(--bulb);
  will-change: transform, opacity;
}
.tree-light::after {
  content: ""; position: absolute; inset: -6px; border-radius: 50%;
  background: radial-gradient(circle, var(--bulb), transparent 70%); opacity: 0.5;
  animation: light-flicker var(--flicker) ease-in-out var(--delay) infinite alternate;
}
.tree-light--warm { --bulb: #ffe6a6; }
.tree-light--mustard { --bulb: var(--mustard); }
.tree-light--tomato { --bulb: #ff7a5c; }
.tree-light--mint { --bulb: var(--mint); }
@keyframes light-flicker {
  from { opacity: 0.2; transform: scale(0.8); }
  to { opacity: 0.6; transform: scale(1.15); }
}
.photo-tree-lights--shiver .tree-light { animation: light-shiver 0.5s ease-in-out 2; }
@keyframes light-shiver {
  25% { translate: 0 -3px; }
  75% { translate: 0 2px; }
}
.photo-tree-gifts {
  position: absolute; bottom: 0; left: 50%; width: min(80%, 460px); height: auto; overflow: visible;
  transform: translateX(-50%);
}
/* The pile grows with the photos (/static/photos.js); a gift that comes while the page is open drops onto it. */
.photo-gift:not(.photo-gift--shown) { display: none; }
.photo-gift--new .gift-box { animation: gift-drop 0.8s cubic-bezier(0.3, 0, 0.6, 1) both; }
@media (prefers-reduced-motion: reduce) {
  .photo-gift--new .gift-box { animation: none; }
}
.photo-tree-baubles { position: absolute; inset: 0; }

/* A photo as tree decoration, in one of five kinds that follows from its id (/static/photos.js): a glass bauble,
   a little polaroid on a red ribbon, a gingerbread heart, a golden star or a drop. Each hangs on a thread of its
   own length and sways at its own pace from the top of the thread; a gust (a tap on the branches) swings it out
   on top of that, and hovering lifts it a little. */
.tree-bauble {
  --thread: 12px; --sway: bauble-sway; --sway-duration: 5s; --sway-delay: 0s;
  position: absolute; padding: 0; border: 0; background: none; cursor: pointer; color: var(--ink);
  transform-origin: 50% calc(var(--thread) * -1);
  animation: var(--sway) var(--sway-duration) ease-in-out var(--sway-delay) infinite alternate;
  transition: left 0.6s ease, top 0.6s ease, width 0.6s ease, height 0.6s ease, scale 0.25s ease;
}
.tree-bauble:hover, .tree-bauble:focus-visible { z-index: 4; scale: 1.12; }
.tree-bauble:focus-visible { outline: none; }
.tree-bauble:focus-visible .tree-bauble-frame { outline: 3px solid var(--mustard); outline-offset: 3px; }
.tree-bauble-thread {
  position: absolute; bottom: calc(100% - 2px); left: 50%; width: 1.5px; height: calc(var(--thread) + 2px);
  margin-left: -0.75px; background: #f2d48a; pointer-events: none;
}
.tree-bauble-frame {
  position: absolute; inset: 0; display: block; overflow: hidden; background: var(--bauble);
  box-shadow: inset -3px -4px 0 rgba(0, 0, 0, 0.14), 0 5px 12px rgba(7, 31, 23, 0.45);
}
.tree-bauble-frame img { position: absolute; display: block; width: 100%; height: 100%; object-fit: cover; }
.tree-bauble-cap {
  position: absolute; top: -8%; left: 50%; width: 26%; height: 12%; transform: translateX(-50%);
  border-radius: 3px 3px 1px 1px; background: linear-gradient(90deg, #a87724, #f7dd94 45%, #b8862e);
  box-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
}
.tree-bauble-shine { position: absolute; inset: 0; display: block; pointer-events: none; }
/* The time on a little paper tag tied below; while the photo is lifted, its caption instead. */
.tree-bauble-tag {
  position: absolute; top: calc(100% + 2px); left: 50%; max-width: 14ch; padding: 0 7px 1px;
  transform: translateX(-50%) rotate(var(--tag-tilt, 0deg)); transform-origin: 50% 0;
  border-radius: 2px 2px 6px 6px; background: var(--paper); color: var(--ink); white-space: nowrap;
  font: 700 0.9375rem/1.25 var(--hand); box-shadow: 0 2px 5px rgba(7, 31, 23, 0.35); pointer-events: none;
}
.tree-bauble-tag[hidden] { display: none; }
.tree-bauble-caption { display: none; overflow: hidden; text-overflow: ellipsis; }
.tree-bauble:is(:hover, :focus-visible) .tree-bauble-tag:has(.tree-bauble-caption:not(:empty)) { display: block; }
.tree-bauble:is(:hover, :focus-visible) .tree-bauble-tag:has(.tree-bauble-caption:not(:empty)) .tree-bauble-time { display: none; }
.tree-bauble:is(:hover, :focus-visible) .tree-bauble-caption { display: block; }

/* The glass bauble: round, in its colour, a golden cap and the gleam of glass over the photo. */
.tree-bauble--glass .tree-bauble-frame { border-radius: 50%; }
.tree-bauble--glass img { inset: 7%; width: 86%; height: 86%; border-radius: 50%; }
.tree-bauble--glass .tree-bauble-shine {
  border-radius: 50%;
  background: radial-gradient(circle at 32% 26%, rgba(255, 255, 255, 0.75) 0 5%, rgba(255, 255, 255, 0.18) 14%, transparent 34%),
    radial-gradient(circle at 70% 80%, transparent 50%, rgba(7, 31, 23, 0.25) 72%);
}

/* The polaroid: a white frame with the time handwritten below, hung on a red ribbon with a bow; it twists on it. */
.tree-bauble--polaroid { --sway: polaroid-twist; }
.tree-bauble--polaroid .tree-bauble-thread { width: 2.5px; margin-left: -1.25px; background: var(--tomato); }
.tree-bauble--polaroid .tree-bauble-frame {
  border-radius: 2px; background: #fff; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.2), 0 6px 14px rgba(7, 31, 23, 0.45);
}
.tree-bauble--polaroid img { top: 7%; left: 8%; width: 84%; height: 70%; background: var(--cream-2); }
.tree-bauble--polaroid .tree-bauble-cap {
  top: -7%; width: 40%; height: 14%; border-radius: 0; box-shadow: none;
  background: radial-gradient(circle at 50% 50%, #c43f2c 0 16%, transparent 18%),
    radial-gradient(ellipse 30% 46% at 28% 50%, var(--tomato) 96%, transparent),
    radial-gradient(ellipse 30% 46% at 72% 50%, var(--tomato) 96%, transparent);
}
.tree-bauble--polaroid .tree-bauble-tag {
  top: auto; bottom: 2%; max-width: 92%; padding: 0; transform: translateX(-50%); background: none;
  box-shadow: none; font-size: clamp(0.625rem, calc(var(--size) * 0.15), 1.0625rem); line-height: 1.2;
}
@keyframes polaroid-twist {
  from { transform: perspective(500px) rotate(calc(var(--tilt) * 1.5)) rotateY(-22deg); }
  to { transform: perspective(500px) rotate(calc(var(--tilt) * -1.5)) rotateY(22deg); }
}

/* The gingerbread heart with a dotted rim of icing. */
.tree-bauble--heart {
  --sway: heart-sway;
  --heart: polygon(50% 100%, 37% 89%, 22% 76%, 9% 61%, 2% 46%, 0% 31%, 3% 17%, 11% 7%, 22% 1%, 33% 1%, 43% 6%,
    50% 14%, 57% 6%, 67% 1%, 78% 1%, 89% 7%, 97% 17%, 100% 31%, 98% 46%, 91% 61%, 78% 76%, 63% 89%);
}
.tree-bauble--heart .tree-bauble-frame { clip-path: var(--heart); background: #a8642d; box-shadow: none; }
.tree-bauble--heart .tree-bauble-frame::before, .tree-bauble--heart .tree-bauble-frame::after {
  content: ""; position: absolute; clip-path: var(--heart);
}
.tree-bauble--heart .tree-bauble-frame::before {
  inset: 5%; background: repeating-conic-gradient(from 0deg at 50% 52%, #fffaf0 0 7deg, transparent 7deg 16deg);
}
.tree-bauble--heart .tree-bauble-frame::after { inset: 9%; background: #8e5122; }
.tree-bauble--heart img { z-index: 1; inset: 14%; width: 72%; height: 72%; clip-path: var(--heart); }
.tree-bauble--heart .tree-bauble-thread { bottom: calc(86% - 2px); height: calc(var(--thread) + 14%); background: #fffaf0; }
.tree-bauble--heart, .tree-bauble--star, .tree-bauble--drop { filter: drop-shadow(0 5px 6px rgba(7, 31, 23, 0.45)); }
@keyframes heart-sway {
  from { transform: rotate(calc(var(--tilt) * 2.4)); }
  to { transform: rotate(calc(var(--tilt) * -2.4)); }
}

/* The golden star, shining. */
.tree-bauble--star {
  --sway: star-sway;
  --star: polygon(50% 0%, 62.5% 34%, 98% 35%, 70% 57%, 79.5% 91%, 50% 71%, 20.5% 91%, 30% 57%, 2% 35%, 37.5% 34%);
}
.tree-bauble--star .tree-bauble-frame {
  clip-path: var(--star); box-shadow: none; background: linear-gradient(135deg, #ffe7a3, #f2b544 45%, #b8862e);
}
.tree-bauble.tree-bauble--star { filter: drop-shadow(0 0 6px rgba(242, 181, 68, 0.7)) drop-shadow(0 4px 6px rgba(7, 31, 23, 0.4)); }
.tree-bauble--star img { inset: 12%; width: 76%; height: 76%; clip-path: var(--star); }
@keyframes star-sway {
  from { transform: rotate(calc(var(--tilt) * 3)) scale(0.97); }
  to { transform: rotate(calc(var(--tilt) * -3)) scale(1.03); }
}

/* The drop: round on top, pointed below, with a golden rim and a streak of light. */
.tree-bauble--drop {
  --sway: drop-sway;
  --drop: polygon(50% 100%, 59% 93%, 69% 84%, 79% 73%, 88% 61%, 95% 48%, 99% 36%, 99% 24%, 95% 13%, 87% 5%, 76% 1%,
    63% 0%, 37% 0%, 24% 1%, 13% 5%, 5% 13%, 1% 24%, 1% 36%, 5% 48%, 12% 61%, 21% 73%, 31% 84%, 41% 93%);
}
.tree-bauble--drop .tree-bauble-frame {
  clip-path: var(--drop); box-shadow: none; background: linear-gradient(90deg, #b8862e, #f7dd94 40%, #b8862e);
}
.tree-bauble--drop img { top: 6%; left: 9%; width: 82%; height: 84%; clip-path: var(--drop); }
.tree-bauble--drop .tree-bauble-shine {
  clip-path: var(--drop); background: linear-gradient(100deg, transparent 22%, rgba(255, 255, 255, 0.45) 27%, transparent 34%);
}
.tree-bauble--drop .tree-bauble-cap { top: -5%; width: 30%; }
@keyframes drop-sway {
  from { transform: rotate(calc(var(--tilt) * 1.4)); }
  to { transform: rotate(calc(var(--tilt) * -1.4)); }
}

@keyframes bauble-sway {
  from { transform: rotate(calc(var(--tilt) * 2)); }
  to { transform: rotate(calc(var(--tilt) * -2)); }
}
/* A photo that comes in while the page is open swings onto the tree. */
.tree-bauble--new {
  animation: bauble-hang 0.9s cubic-bezier(0.2, 0.8, 0.3, 1.3) both,
    var(--sway) var(--sway-duration) ease-in-out 0.9s infinite alternate;
}
@keyframes bauble-hang {
  from { opacity: 0; transform: translateY(-40px) rotate(12deg) scale(0.6); }
}
/* A gust runs over the tree from where it was tapped: everything swings out, back, and settles. */
.tree-bauble--gust {
  animation: var(--sway) var(--sway-duration) ease-in-out var(--sway-delay) infinite alternate,
    bauble-gust 1.8s ease-out var(--gust-delay, 0s) both;
}
@keyframes bauble-gust {
  0% { rotate: 0deg; }
  18% { rotate: var(--gust, 12deg); }
  42% { rotate: calc(var(--gust, 12deg) * -0.6); }
  66% { rotate: calc(var(--gust, 12deg) * 0.3); }
  84% { rotate: calc(var(--gust, 12deg) * -0.1); }
  100% { rotate: 0deg; }
}
/* The newest photo glows and wears a little "neu". */
.tree-bauble--newest::before {
  content: ""; position: absolute; inset: -30%; z-index: -1; border-radius: 50%; pointer-events: none;
  background: radial-gradient(circle, rgba(255, 214, 122, 0.7), transparent 65%);
  animation: newest-glow 2.2s ease-in-out infinite alternate;
}
.tree-bauble--newest::after {
  content: "neu"; position: absolute; top: -4%; right: -14%; z-index: 2; padding: 1px 6px; border-radius: 999px;
  background: var(--tomato); color: #fff; font: 800 0.6875rem/1.3 var(--display);
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); transform: rotate(12deg);
}
@keyframes newest-glow {
  from { opacity: 0.45; transform: scale(0.9); }
  to { opacity: 1; transform: scale(1.08); }
}
/* The number of hearts on a little red pill at the lower right; too small a bauble goes without. */
.tree-bauble-likes {
  position: absolute; right: -12%; bottom: -4%; z-index: 2; display: inline-flex; align-items: center; gap: 2px;
  padding: 1px 6px 1px 4px; border-radius: 999px; background: var(--tomato); color: #fff;
  font: 800 0.6875rem/1.3 var(--display); font-variant-numeric: tabular-nums;
  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3); pointer-events: none;
}
.tree-bauble-likes[hidden], .tree-bauble--tiny .tree-bauble-likes { display: none; }
.tree-bauble-likes .heart { width: 11px; height: 11px; fill: currentColor; }
.tree-bauble-likes--pop { animation: heart-pop 0.5s cubic-bezier(0.3, 1.6, 0.5, 1); }
/* The favourite under the star: a golden crown, a golden pill and a warm glow. */
.tree-bauble-crown {
  position: absolute; top: -16%; left: -14%; z-index: 2; display: none; width: 42%; height: 28%;
  max-width: 34px; max-height: 22px; min-width: 14px; min-height: 9px; transform: rotate(-18deg);
  clip-path: polygon(0 100%, 0 20%, 25% 55%, 50% 0, 75% 55%, 100% 20%, 100% 100%);
  background: linear-gradient(180deg, #ffe7a3, #f2b544 55%, #b8862e); pointer-events: none;
}
.tree-bauble--favorite .tree-bauble-crown { display: block; animation: crown-in 0.6s cubic-bezier(0.3, 1.6, 0.5, 1); }
.tree-bauble--favorite .tree-bauble-likes { background: var(--mustard); color: var(--ink); }
.tree-bauble.tree-bauble--favorite { filter: drop-shadow(0 0 7px rgba(255, 214, 122, 0.85)); }
@keyframes crown-in {
  from { opacity: 0; transform: translateY(-10px) rotate(-40deg) scale(0.4); }
}
@keyframes heart-pop {
  40% { transform: scale(1.35); }
}
@media (min-width: 800px) {
  .photo-tree-star { width: 84px; height: 84px; margin-left: -42px; }
  .tree-bauble-tag { font-size: 1.0625rem; }
  .tree-light { width: 13px; height: 17px; margin: -8.5px 0 0 -6.5px; }
  .tree-sparkle { width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; }
  .tree-candle { width: 9px; height: 30px; margin-left: -4.5px; }
  .tree-candle::before { width: 11px; height: 19px; margin-left: -5.5px; }
}

/* The snow the tree stands in, as wide as the window, with a drift rising under the tree. It lies over the
   falling snow of the backdrop, so the flakes disappear at its edge as if they settled, and under the photos,
   so the pot and the gifts stand in it. The light of the tree falls on it, the pot casts a soft shadow. */
.photo-area { z-index: 1; }
.photo-ground {
  --snow: #e9eff1; --edge: 50px;
  position: relative; z-index: 0; margin-top: -14px; padding-top: 26px;
  background: linear-gradient(var(--snow), #d6e0e2 320px, #cbd6d9);
}
.photo-ground-edge {
  position: absolute; bottom: calc(100% - 1px); left: 0; display: block; width: 100%; height: var(--edge);
  fill: var(--snow);
}
.photo-ground::before, .photo-ground::after {
  content: ""; position: absolute; left: 50%; z-index: 1; transform: translateX(-50%); pointer-events: none;
}
.photo-ground::before {
  top: calc(var(--edge) * -1); width: min(96vw, 760px); height: 220px;
  background: radial-gradient(ellipse at 50% 22%, rgba(242, 181, 68, 0.2), rgba(242, 181, 68, 0.05) 45%, transparent 70%);
}
.photo-ground::after {
  top: calc(var(--edge) * -0.82); width: min(70%, 420px); height: 36px; border-radius: 50%;
  background: radial-gradient(ellipse, rgba(52, 84, 96, 0.32), transparent 70%);
}
.photo-ground-glints { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.photo-ground .tree-sparkle { filter: drop-shadow(0 0 2px #8fb8cc); }
.photo-tree-hint {
  position: relative; z-index: 2; max-width: 560px; margin: 0 auto;
  padding: 18px var(--gutter-right) 6px var(--gutter-left);
  text-align: center; font-size: 0.9375rem; color: var(--muted-dark);
}
/* Only for the tree, and only once photos hang on it. */
body:not(:has(.photo-wall--tree)) .photo-tree-hint, body:not(:has(.photo-card)) .photo-tree-hint { display: none; }
.photo-ground .photo-sheet { box-shadow: 0 2px 4px rgba(15, 59, 46, 0.08), 0 14px 34px rgba(15, 59, 46, 0.16); }
@media (min-width: 800px) {
  .photo-ground { --edge: 64px; }
}

/* Below the photos: taking all of them home and sharing new ones. */
.photo-share {
  display: flex; flex-direction: column; align-items: center; gap: 16px; max-width: 560px; margin: 0 auto;
  padding: 8px var(--gutter-right) calc(100px + env(safe-area-inset-bottom)) var(--gutter-left);
  scroll-margin-top: 16px;
}
.photo-share .photo-download { margin: 0; }
.photo-share .photo-sheet { width: 100%; }
/* Sharing stays one tap away; /static/photos.js hides the button while the form itself is in view. */
.photo-fab {
  position: fixed; bottom: max(16px, env(safe-area-inset-bottom)); left: 50%; z-index: 50;
  display: inline-flex; align-items: center; min-height: 52px; padding: 0 24px; transform: translateX(-50%);
  border-radius: 999px; background: var(--tomato); color: #fff; text-decoration: none;
  font: 800 1.0625rem/1 var(--display); box-shadow: 0 8px 22px rgba(0, 0, 0, 0.35);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.photo-fab--away { opacity: 0; pointer-events: none; transform: translate(-50%, 12px); }
html:has(.photo-fab) { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  .tree-bauble, .tree-bauble--new, .tree-bauble--gust { animation: none; transition: none; }
  .photo-tree::before, .photo-tree-glow, .photo-tree-star svg, .photo-tree-star::before, .tree-light::after,
  .tree-bauble--newest::before, .photo-tree-lights--shiver .tree-light, .tree-candle::before { animation: none; }
  .tree-sparkle { display: none; }
  html:has(.photo-fab) { scroll-behavior: auto; }
}

/* A photo in full screen (/static/photos.js). As big as the window without its scrollbar: 100vw would count the
   scrollbar in and push the buttons on the right under it. The page behind stays where it is. */
.lightbox {
  inset: 0; width: 100%; height: 100%; max-width: none; max-height: none; margin: 0; padding: 0; border: 0;
  background: #071f17; color: var(--cream);
}
.lightbox:focus { outline: none; }
html:has(.lightbox[open]) { overflow: hidden; }
.lightbox[open] { display: flex; flex-direction: column; }
.lightbox::backdrop { background: rgba(7, 31, 23, 0.8); }
.lightbox-image {
  flex: 1; min-height: 0; width: 100%; object-fit: contain;
  padding: max(60px, env(safe-area-inset-top)) 12px 0; touch-action: pan-y;
}
.lightbox-bar {
  display: flex; align-items: center; gap: 12px;
  padding: 14px var(--gutter-right) calc(14px + env(safe-area-inset-bottom)) var(--gutter-left);
}
.lightbox-info { flex: 1; min-width: 0; margin: 0; overflow-wrap: anywhere; }
.lightbox-info strong { font: 800 1.0625rem var(--display); }
.lightbox-info span { color: var(--sub); font-size: 0.875rem; }
.lightbox-info .lightbox-caption { display: block; color: var(--cream); font-size: 1rem; font-weight: 700; }
.lightbox-info .lightbox-likers { display: block; margin-top: 2px; color: #ff9a85; font-weight: 700; }
.lightbox-info .lightbox-likers:empty { display: none; }
.like-button--big { min-height: 48px; padding: 0 16px 0 12px; font-size: 1.0625rem; }
.like-button--big .heart { width: 24px; height: 24px; }
/* The heart a double tap gives, popping up over the photo and fading. */
.lightbox-burst {
  position: absolute; top: 45%; left: 50%; z-index: 1; width: 120px; height: 120px; margin: -60px 0 0 -60px;
  color: var(--tomato); opacity: 0; pointer-events: none;
  filter: drop-shadow(0 6px 18px rgba(0, 0, 0, 0.45));
}
.lightbox-burst .heart { display: block; width: 100%; height: 100%; fill: currentColor; stroke: #fff; stroke-width: 1.2; }
.lightbox-burst--show { animation: heart-burst 0.9s ease-out; }
@keyframes heart-burst {
  0% { opacity: 0; transform: scale(0.3); }
  20% { opacity: 1; transform: scale(1.1); }
  35% { transform: scale(0.95); }
  70% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(1.15) translateY(-20px); }
}
@media (prefers-reduced-motion: reduce) {
  .like-button--pop .heart, .tree-bauble-likes--pop, .tree-bauble--favorite .tree-bauble-crown { animation: none; }
}
.lightbox-download, .lightbox-close, .lightbox-nav {
  display: inline-flex; align-items: center; justify-content: center; width: 48px; height: 48px; flex: none;
  padding: 0; border: 0; border-radius: 50%; cursor: pointer; text-decoration: none;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.lightbox-download svg, .lightbox-close svg, .lightbox-nav svg {
  width: 24px; height: 24px; fill: none; stroke: currentColor; stroke-width: 2.4; stroke-linecap: round;
  stroke-linejoin: round;
}
.lightbox-download { background: var(--mustard); color: var(--ink); }
.lightbox-download:hover { background: #ffc85c; }
/* Dark and solid with a light rim and a shadow, so they stand out on bright photos, too. */
.lightbox-close, .lightbox-nav {
  position: absolute; z-index: 1; background: rgba(7, 31, 23, 0.72); color: #fff;
  border: 1.5px solid rgba(243, 234, 216, 0.45); box-shadow: 0 4px 14px rgba(0, 0, 0, 0.45);
  -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px);
}
.lightbox-close:hover, .lightbox-nav:hover { background: rgba(30, 90, 69, 0.9); }
.lightbox-nav:active { transform: translateY(-50%) scale(0.92); }
.lightbox-nav { width: 52px; height: 52px; }
.lightbox-nav svg { width: 28px; height: 28px; stroke-width: 2.8; }
/* Which photo of how many, at the top left. */
.lightbox-count {
  position: absolute; top: max(20px, env(safe-area-inset-top)); left: max(16px, env(safe-area-inset-left));
  z-index: 1; padding: 6px 12px; border-radius: 999px; background: rgba(7, 31, 23, 0.72); color: var(--cream);
  font: 800 0.9375rem/1 var(--display); font-variant-numeric: tabular-nums;
  border: 1.5px solid rgba(243, 234, 216, 0.3);
}
/* The next photo slides in from the side it comes from. */
.lightbox-image--from-next { animation: lightbox-from-next 0.3s ease-out; }
.lightbox-image--from-prev { animation: lightbox-from-prev 0.3s ease-out; }
@keyframes lightbox-from-next { from { opacity: 0.3; transform: translateX(28px); } }
@keyframes lightbox-from-prev { from { opacity: 0.3; transform: translateX(-28px); } }
@media (prefers-reduced-motion: reduce) {
  .lightbox-image--from-next, .lightbox-image--from-prev { animation: none; }
}
.lightbox-close { top: max(12px, env(safe-area-inset-top)); right: max(12px, env(safe-area-inset-right)); }
.lightbox-nav { top: 50%; transform: translateY(-50%); }
.lightbox-nav--prev { left: max(12px, env(safe-area-inset-left)); }
.lightbox-nav--next { right: max(12px, env(safe-area-inset-right)); }
.lightbox-nav[hidden] { display: none; }
/* On a wide window the arrows sit beside the photo, not on it. */
@media (min-width: 800px) {
  .lightbox-image { padding: 72px 96px 0; }
  .lightbox-bar { padding-right: 96px; padding-left: 96px; }
  .lightbox-close, .lightbox-nav { width: 56px; height: 56px; }
  .lightbox-close { top: 20px; right: 20px; }
  .lightbox-count { top: 30px; left: 24px; }
  .lightbox-nav--prev { left: 20px; }
  .lightbox-nav--next { right: 20px; }
}

/* ---------- The reveal after the draw (/static/reveal.js) ---------- */

.replay-reveal {
  display: block; margin: -4px 0 16px; padding: 4px 0; border: 0; background: none; cursor: pointer;
  font: 700 0.875rem var(--body); color: var(--sub); text-decoration: underline; text-underline-offset: 3px;
}
.replay-reveal[hidden] { display: none; }
.replay-reveal:hover { color: var(--mustard); }

.reveal {
  position: fixed; inset: 0; z-index: 100; overflow: hidden;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 28px;
  padding: 24px var(--gutter-right) 24px var(--gutter-left);
  background: radial-gradient(circle at 50% 40%, var(--pine-mid), #071f17 75%);
  animation: reveal-in 0.5s ease-out;
}
.reveal--leaving { animation: reveal-out 0.45s ease-in forwards; }
@keyframes reveal-in { from { opacity: 0; } }
@keyframes reveal-out { to { opacity: 0; transform: scale(1.04); } }
.reveal-intro {
  margin: 0; font: 800 clamp(1.5rem, 6vw, 2.25rem)/1.1 var(--display); letter-spacing: -0.02em; text-align: center;
}
.reveal-doors { display: flex; flex-wrap: wrap; justify-content: center; gap: 20px; }
.reveal-door {
  position: relative; width: min(42vw, 200px); aspect-ratio: 3 / 4; padding: 0; border: 0;
  border-radius: 18px; background: var(--cream); color: var(--ink); cursor: pointer;
  perspective: 700px; box-shadow: 0 18px 40px rgba(0, 0, 0, 0.35);
}
.reveal-door:not(.reveal-door--open) { animation: reveal-wiggle 2.6s ease-in-out infinite; }
.reveal-door:nth-child(2):not(.reveal-door--open) { animation-delay: -1.3s; }
@keyframes reveal-wiggle {
  0%, 80%, 100% { transform: none; }
  85% { transform: rotate(-2deg); }
  90% { transform: rotate(2deg); }
  95% { transform: rotate(-1deg); }
}
.reveal-behind {
  position: absolute; inset: 0; display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: 2px; padding: 14px; text-align: center;
}
.reveal-behind .own-snowman { width: 46%; margin-bottom: 8px; }
.reveal-behind small { font-size: 0.8125rem; font-weight: 700; color: var(--muted-dark); }
.reveal-behind strong { font: 800 clamp(1.25rem, 5vw, 1.75rem)/1.05 var(--display); overflow-wrap: anywhere; }
.reveal-door--open .reveal-behind > * { animation: reveal-pop 0.6s cubic-bezier(0.3, 1.5, 0.5, 1) 0.35s backwards; }
@keyframes reveal-pop { from { opacity: 0; transform: translateY(14px) scale(0.8); } }
.reveal-flap {
  position: absolute; inset: 0; display: flex; align-items: flex-start; padding: 14px 16px; border-radius: 18px;
  font: 800 clamp(2.5rem, 12vw, 4rem)/1 var(--display); backface-visibility: hidden;
  transform-origin: left center; transition: transform 1s cubic-bezier(0.2, 0.8, 0.2, 1), box-shadow 1s ease;
  box-shadow: inset -10px 0 0 rgba(0, 0, 0, 0.12);
}
.reveal-door--open .reveal-flap { transform: rotateY(-105deg); box-shadow: 18px 10px 30px rgba(0, 0, 0, 0.35); }
.reveal-done { animation: reveal-pop 0.5s ease-out; }
.reveal-done[hidden] { display: none; }
.reveal-confetti, .reveal-flake { position: absolute; top: 0; left: 0; pointer-events: none; }
.reveal-confetti { width: 8px; height: 12px; margin: -6px 0 0 -4px; border-radius: 2px; }
.reveal-flake { width: 7px; height: 7px; margin: -3.5px 0 0 -3.5px; border-radius: 50%; }

/* ---------- Snow from the mouse (/static/snow_pile.js) ---------- */

/* Behind the scene: the script puts it right before the scene's foreground, so the houses, hills and the page
   that come after it are painted on top. */
.snow-pile { position: fixed; inset: 0; width: 100%; height: 100%; pointer-events: none; }
.snow-shovel {
  position: fixed; right: max(16px, env(safe-area-inset-right)); bottom: max(16px, env(safe-area-inset-bottom)); z-index: 201;
  min-height: 44px; padding: 0 18px; border: 0; border-radius: 999px; cursor: pointer;
  background: var(--tomato); color: #fff; font: 800 0.9375rem/1 var(--display);
  box-shadow: 0 6px 18px rgba(0, 0, 0, 0.3); animation: reveal-pop 0.4s ease-out;
}
.snow-shovel::before { content: "❄ "; }
.snow-shovel[hidden] { display: none; }

/* ---------- Error page ---------- */

.page--center { justify-content: center; gap: 24px; padding: 24px var(--gutter-right) 24px var(--gutter-left); }
.error-card { padding: 24px; border-radius: 24px; background: var(--cream); color: var(--ink); }
.error-card h1 { margin: 0 0 8px; font: 800 2rem/1.1 var(--display); }
.error-card p { margin: 0 0 18px; }
.actions { display: flex; flex-wrap: wrap; gap: 10px; }

@media (max-width: 360px) {
  .mini-tree { display: none; }
  .head-intro { padding-right: 0; }
}

@media (prefers-reduced-motion: reduce) {
  .winter *, .winter *::before, .winter *::after { animation: none !important; transition: none !important; }
}
