*, *::before, *::after { box-sizing: border-box; }

html { background: var(--surface-sunken); }

body {
  margin: 0;
  color: var(--ink);
  font: 400 15px/23px var(--font-sans);
}

h1, h2, h3, p { margin: 0; }
a, .link { color: var(--ice); }
/* A button that reads as a text link, for links that open something in place (the terms) */
.link { padding: 0; border: 0; background: none; font: inherit; text-decoration: underline; cursor: pointer; }
/* Text links warm to lantern amber, the primary button's colour, when pointed at or focused */
a:not(.btn):hover, a:not(.btn):focus-visible, .link:hover, .link:focus-visible { color: var(--lantern-ink); }

:focus-visible { outline: none; box-shadow: var(--focus-ring); }

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Type styles */
.hero-title { font: 600 48px/52px var(--font-display); letter-spacing: -0.01em; }
.title { font: 600 32px/38px var(--font-display); letter-spacing: -0.005em; }
.subtitle { font: 500 22px/30px var(--font-display); }
.heading { font: 700 19px/26px var(--font-sans); }
.body-lg { font: 400 17px/27px var(--font-sans); }
.body { font: 400 15px/23px var(--font-sans); }
.body-strong { font: 700 15px/23px var(--font-sans); }
.caption { font: 600 13px/18px var(--font-sans); letter-spacing: 0.01em; }
.overline { font: 700 11px/14px var(--font-sans); letter-spacing: 0.08em; color: var(--ink-muted); }
.logo { font: 400 20px/26px var(--font-pixel); letter-spacing: 0.02em; color: var(--cranberry); text-decoration: none; }
.pixel-tag { font: 400 10px/16px var(--font-pixel); letter-spacing: 0.04em; }
.muted { color: var(--ink-muted); }
.error-text { color: var(--cranberry); }

/* Icons: line SVGs tinted with the current text colour */
.icon {
  display: inline-block;
  width: 1.25em;
  height: 1.25em;
  background: currentColor;
  mask: var(--icon) center / contain no-repeat;
  -webkit-mask: var(--icon) center / contain no-repeat;
}
.icon-envelope { --icon: url("../assets/icons/envelope.svg"); }
.icon-send { --icon: url("../assets/icons/send.svg"); }
.icon-share-link { --icon: url("../assets/icons/share-link.svg"); }
.icon-snowflake { --icon: url("../assets/icons/snowflake.svg"); }
.icon-sparkle { --icon: url("../assets/icons/sparkle.svg"); }
.icon-check { --icon: url("../assets/icons/check.svg"); }
.icon-arrow-up-right { --icon: url("../assets/icons/arrow-up-right.svg"); }
.icon-write { --icon: url("../assets/icons/write.svg"); }
.icon-arrow-left { --icon: url("../assets/icons/arrow-left.svg"); }
.icon-x { --icon: url("../assets/icons/x.svg"); }
.icon-plus { --icon: url("../assets/icons/plus.svg"); }
.icon-image { --icon: url("../assets/icons/image.svg"); }

/* Motion curves (not in the design system yet, DESIGN.md §7) */
:root {
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
}

/* Stage (design/DESIGN.md §1–3): the diorama fills the screen, and the content sits on one panel
   over the left half. The right half is always left to the scene and Astro. On desktop the page
   never scrolls; long content scrolls inside the panel. */
body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-template-rows: minmax(0, 1fr);
  height: 100vh;
  height: 100dvh;
  overflow: hidden;
}

/* The background shows only around the window on phones; the script repaints it with the scene's own snow (rule 13) */
.diorama { position: fixed; inset: 0; overflow: hidden; background: var(--surface-sunken); }
.diorama canvas { position: absolute; display: block; image-rendering: pixelated; }

/* The window onto the scene above the letter on phones (§2, rule 13). Once the content shows, the
   scene slides up into it; the diorama script sets --window-shift (0 everywhere else). */
.scene-window { display: none; }
.diorama canvas { transition: transform 700ms var(--ease-in-out); }
:root:not([data-diorama-front]) .diorama canvas { transform: translateY(var(--window-shift, 0px)); }

.panel {
  position: relative;
  grid-column: 1;
  display: flex;
  flex-direction: column;
  margin: var(--space-6);
  padding: 40px var(--space-12);
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  background: color-mix(in srgb, var(--surface-raised) 60%, transparent);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border: 1px solid var(--line);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
  transition: opacity 600ms ease;
}

/* The scene in front: the content fades out and can't be reached until it comes back (§2, rules 5–7).
   On Send it goes quicker, as the letter lifts out of it (below). */
[data-diorama-front] .panel {
  opacity: 0;
  visibility: hidden;
  transition: opacity 800ms ease, visibility 0s 800ms;
}
[data-sending][data-diorama-front] .panel { transition: opacity 300ms ease, visibility 0s 300ms; }

/* The sending card (§2, rule 6): while a letter is on its way the scene is in front, and this card
   says what is happening, in the left half where the panel was. On Create it comes in once Astro has
   caught the letter (data-letter-caught); on the letter page it is there from the start, and goes
   just before the letter rises in. It keeps its place through the page change between them. */
.sending-card {
  position: fixed;
  inset: 0 50% 0 0;
  display: grid;
  place-items: center;
  padding: var(--space-6);
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transition: opacity 250ms ease, visibility 0s 250ms;
  view-transition-name: sending-card;
}
:root[data-diorama-front]:is([data-letter-caught], [data-diorama="delivery"]) .sending-card {
  opacity: 1;
  visibility: visible;
  transition: opacity 300ms ease, visibility 0s;
}
/* The end of the delivery: the card goes first, then the letter comes in (the entrances below wait too) */
:root[data-diorama="delivery"] { --after-card: 200ms; }
:root:not([data-diorama-front]) .panel { transition-delay: var(--after-card, 0ms); }

/* Send: the letter folds into an envelope and flies to Astro (§2, rule 6; js/diorama/letter-flight.js).
   A 200x420 sheet folded in three is 200x140, the envelope's 10x7 pixels at 20px each. */
.letter-flight { position: fixed; inset: 0; z-index: 20; overflow: hidden; pointer-events: none; }
.flight-sheet { position: absolute; width: 200px; height: 420px; }
.flight-flap { position: absolute; left: 0; width: 100%; height: 140px; transform-style: preserve-3d; }
.flight-flap-top { top: 0; z-index: 3; transform-origin: 50% 100%; }
.flight-flap-middle { top: 140px; z-index: 1; }
.flight-flap-bottom { top: 280px; z-index: 2; transform-origin: 50% 0; }
.flight-face { position: absolute; inset: 0; overflow: hidden; background: var(--paper); backface-visibility: hidden; }
.flight-face-back { background: color-mix(in srgb, var(--paper), var(--paper-line) 60%); transform: rotateX(180deg); }
.flight-flap-top .flight-face { border-radius: var(--radius-md) var(--radius-md) 0 0; }
.flight-flap-bottom .flight-face { border-radius: 0 0 var(--radius-md) var(--radius-md); }
.flight-flap-middle .flight-face { box-shadow: var(--shadow-md); }
.flight-content {
  position: absolute;
  left: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 200px;
  height: 420px;
  padding: 20px 18px;
  color: var(--on-paper);
}
.flight-dear { font: 500 18px/24px var(--font-display); }
.flight-words {
  flex: 1;
  overflow: hidden;
  font: 400 16px/24px var(--font-hand);
  white-space: pre-line;
  overflow-wrap: anywhere;
  background: repeating-linear-gradient(to bottom, transparent 0 23px, var(--paper-line) 23px 24px);
}
.flight-love { font: 400 16px/24px var(--font-hand); text-align: right; }
.flight-envelope { position: absolute; left: 0; top: 0; width: 200px; height: 140px; transform-origin: 0 0; }
.flight-pixels { position: absolute; inset: 0; width: 100%; height: 100%; image-rendering: pixelated; }
.flight-seal { transform-origin: 50% 57%; }

/* The page change after Send crossfades instead of cutting (browsers without cross-document view
   transitions keep the cut). Every other page change skips it (app.js). The scene's old picture stays
   under the new one until the new page has drawn its own, so the sky never blinks. The new one is laid
   over it plainly: the browser's own crossfade adds the two pictures together (plus-lighter), which
   with the old one held at full strength flashes the screen twice as bright. */
@view-transition { navigation: auto; }
.diorama canvas { view-transition-name: diorama; }
::view-transition-old(diorama) { animation: none; mix-blend-mode: normal; }
::view-transition-new(diorama) { animation: fade-in 400ms ease both; mix-blend-mode: normal; }
.sending-card p {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-6);
  background: var(--surface-raised);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
  font: 700 15px/23px var(--font-sans);
}
.sending-card .icon { flex-shrink: 0; color: var(--lantern-ink); }
@keyframes dot-blink { 0%, 60%, 100% { opacity: 1; } 30% { opacity: 0.2; } }
.sending-dots span { animation: dot-blink 1200ms linear infinite; }
.sending-dots span:nth-child(2) { animation-delay: 200ms; }
.sending-dots span:nth-child(3) { animation-delay: 400ms; }

@media (prefers-reduced-motion: reduce) {
  .panel, .diorama canvas { transition: none; }
  .sending-dots span { animation: none; }
}

/* Narrow screens: one column, the panel goes full width and the page scrolls over the fixed scene */
@media (max-width: 819px) {
  body { display: block; height: auto; overflow: visible; }
  .panel {
    min-height: calc(100dvh - 2 * var(--space-4));
    margin: var(--space-4);
    padding: var(--space-6) var(--space-4);
    overflow: visible;
  }
  .scene-window { display: block; height: 40svh; }
  .sending-card { inset: 0; }
}

/* Page frame, inside the panel */
/* The wordmark centred, with room on its left for a link such as Create's Back */
.site-header { display: grid; grid-template-columns: 1fr auto 1fr; align-items: center; padding-bottom: var(--space-6); }
.site-header .logo { grid-column: 2; }
.back-link { grid-column: 1; justify-self: start; display: inline-flex; align-items: center; gap: var(--space-1); min-height: 44px; font-weight: 700; text-decoration: none; }
/* Too narrow to centre the wordmark beside the link: link on the left, wordmark on the right */
@media (max-width: 480px) {
  .site-header:has(.back-link) { grid-template-columns: auto 1fr; gap: var(--space-3); }
  .site-header:has(.back-link) .logo { justify-self: end; }
}
.site-main { flex: 1 0 auto; display: flex; flex-direction: column; justify-content: center; width: 100%; max-width: 720px; margin: 0 auto; }
.site-footer { display: flex; flex-wrap: wrap; justify-content: center; align-items: center; gap: var(--space-2); padding-top: var(--space-6); color: var(--ink-muted); }
.footer-break { flex-basis: 100%; height: 0; }
/* Only the words are underlined, not the heart */
.support-link { display: inline-flex; align-items: center; gap: var(--space-1); text-decoration: none; }
.support-link span { text-decoration: underline; }
.support-heart { width: 13px; height: 12px; fill: var(--cranberry); }

.page { display: flex; flex-direction: column; gap: var(--space-4); }

/* Buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-6);
  border: 2px solid transparent;
  border-radius: var(--radius-md);
  font: 700 15px/23px var(--font-sans);
  text-decoration: none;
  cursor: pointer;
  transition: background-color 120ms ease, border-color 120ms ease, box-shadow 160ms ease, transform 160ms var(--ease-out);
}
.btn:active:not(:disabled) { transform: scale(0.97); }
/* A button that wraps a visually hidden input (Add picture) shows that input's keyboard focus */
.btn:has(:focus-visible) { box-shadow: var(--focus-ring); }

/* The one lantern action per screen */
.btn-primary { background: var(--lantern); color: var(--on-lantern); box-shadow: var(--glow); }
/* Pointed at with a mouse, the lantern glows brighter (not on touch, where hover sticks after a tap) */
@media (hover: hover) and (pointer: fine) {
  .btn-primary:not(:disabled):hover {
    box-shadow: 0 0 0 1px color-mix(in srgb, var(--lantern) 50%, transparent),
                0 8px 36px -4px color-mix(in srgb, var(--lantern) 75%, transparent);
  }
}
/* The glow would otherwise replace the focus ring */
.btn.btn-primary:focus-visible { box-shadow: var(--focus-ring), var(--glow); }
/* Everything else: a simple outline, so the lantern button stays the only filled action.
   Hover and press tint with moonlight instead of a surface colour, so they show on any
   background: the panel, a wish card or the share modal. */
.btn-secondary { background: transparent; color: var(--ink); border-color: var(--border-strong); }
.btn-secondary:not(:disabled):hover { background: color-mix(in srgb, var(--ink) 8%, transparent); border-color: var(--ink-muted); }
.btn-secondary:not(:disabled):active { background: color-mix(in srgb, var(--ink) 16%, transparent); }
.btn-quiet { background: transparent; color: var(--ink-muted); }
.btn-small { padding: var(--space-2) var(--space-4); }
.btn:disabled { opacity: var(--opacity-disabled); cursor: not-allowed; }
/* Busy (Send while the letter saves): looks the same, but can't be pressed again */
.btn[aria-disabled="true"] { pointer-events: none; }
.btn[hidden] { display: none; }

/* Form */
.group { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-6); }
.field {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: var(--surface-sunken);
  color: var(--ink);
  border: 2px solid var(--border-strong);
  border-radius: var(--radius-md);
  font: 400 15px/23px var(--font-sans);
}
.field::placeholder { color: var(--ink-muted); }
/* A secondary field, such as a wish's optional link */
.field-small { padding: var(--space-2) var(--space-3); font: 400 13px/18px var(--font-sans); }

/* An icon-only button, such as a wish's remove × */
.icon-button {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  padding: 0;
  background: transparent;
  color: var(--ink-muted);
  border: 2px solid var(--border-strong);
  border-radius: var(--radius-md);
  cursor: pointer;
  transition: background-color 120ms ease, color 120ms ease, transform 160ms var(--ease-out);
}
.icon-button:active { transform: scale(0.97); }
.icon-button[hidden] { display: none; }


.banner { padding: var(--space-3) var(--space-4); border-radius: var(--radius-md); margin-bottom: var(--space-4); }
.banner-error { background: var(--cranberry-soft); color: var(--cranberry); }
.banner-error.validation-summary-valid { display: none; }
.banner-error ul { margin: 0; padding-left: var(--space-4); }

.badge { display: inline-flex; align-items: center; gap: var(--space-2); padding: 6px var(--space-3); border-radius: var(--radius-sm); }
.badge .icon { width: 16px; height: 16px; }
.badge-aurora { background: var(--aurora-soft); color: var(--aurora); }

/* The letter page (DESIGN.md §4): status row, the paper filling the rest of the panel and scrolling
   inside itself, then the share section. */
.site-main:has(> .letter-page) { flex: 1 1 0; min-height: 0; justify-content: flex-start; }
.letter-page { flex: 1; min-height: 0; }
.letter-status { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-4); }
.letter-page .paper {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--paper-line) transparent;
}

/* The letter: warm paper, the brightest thing on the screen */
.paper {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-8);
  background: var(--paper);
  color: var(--on-paper);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  overflow-wrap: anywhere;
}

.letter-address { display: flex; justify-content: space-between; align-items: flex-start; gap: var(--space-4); }
.letter-address .overline { color: var(--paper-muted); line-height: 20px; }
/* A round North Pole postmark with the sent date, stamped a little crooked */
.postmark {
  flex-shrink: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  width: 88px;
  height: 88px;
  border: 2px solid var(--paper-muted);
  border-radius: var(--radius-full);
  box-shadow: inset 0 0 0 3px var(--paper), inset 0 0 0 4px var(--paper-muted);
  color: var(--paper-muted);
  font: 700 10px/13px var(--font-sans);
  letter-spacing: 0.02em;
  transform: rotate(-10deg);
}
.postmark-day { font: 600 16px/20px var(--font-display); letter-spacing: 0; }

/* The child's own words: handwriting on ruled lines, one rule under each line of text */
.hand {
  font: 400 20px/28px var(--font-hand);
  background: repeating-linear-gradient(to bottom, transparent 0 27px, var(--paper-line) 27px 28px);
}
.sign-off { text-align: right; }

/* The wishes: polaroids taped to the paper, each tilted a little, two to a row (one on phones).
   Every fourth one repeats the same tilt and tape colour. */
.polaroids {
  list-style: none;
  margin: 0;
  padding: var(--space-3) var(--space-2) var(--space-4);
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: var(--space-8) var(--space-6);
}
.polaroid { position: relative; isolation: isolate; transform-origin: 50% 0; --tilt: -2deg; --tape: var(--cranberry); }
.polaroid:nth-child(4n+2) { --tilt: 1.5deg; --tape: var(--aurora); }
.polaroid:nth-child(4n+3) { --tilt: 2deg; --tape: var(--ice); }
.polaroid:nth-child(4n) { --tilt: -1.25deg; --tape: var(--lantern); }

.polaroid-front, .polaroid-back {
  padding: 10px 10px var(--space-3);
  background: color-mix(in srgb, var(--paper), white 75%);
  border-radius: 3px;
  box-shadow: 0 1px 2px color-mix(in srgb, var(--on-paper) 25%, transparent),
              0 10px 18px -10px color-mix(in srgb, var(--on-paper) 55%, transparent);
  transform: rotate(var(--tilt));
  transition: transform 220ms var(--ease-out);
}
.polaroid-front { position: relative; display: flex; flex-direction: column; gap: var(--space-2); height: 100%; }
/* A strip of tape holds each polaroid to the paper */
.polaroid-front::before {
  content: "";
  position: absolute;
  top: -11px;
  left: 50%;
  z-index: 1;
  width: 76px;
  height: 22px;
  background: color-mix(in srgb, var(--tape) 45%, transparent);
  transform: translateX(-50%) rotate(-4deg);
}
/* A wish's other picture, behind the first and turned a little further */
.polaroid-back { position: absolute; inset: 0; z-index: -1; transform: rotate(calc(var(--tilt) + 5deg)) translate(6px, 2px); }

.polaroid-picture { position: relative; display: block; border-radius: 2px; transition: transform 160ms var(--ease-out); }
.polaroid-picture:active { transform: scale(0.97); }
.polaroid-picture img { display: block; width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: 2px; background: var(--paper-line); }
/* "2 pictures", on the front picture of a stack */
.polaroid-count {
  position: absolute;
  right: 6px;
  bottom: 6px;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px var(--space-2);
  background: color-mix(in srgb, var(--on-paper) 72%, transparent);
  color: var(--paper);
  border-radius: var(--radius-full);
  font: 700 12px/16px var(--font-sans);
}
.polaroid-count .icon { width: 14px; height: 14px; }

.polaroid-caption { display: flex; align-items: flex-start; gap: var(--space-2); }
.polaroid-caption .wish-number { width: 26px; height: 26px; font-size: 14px; }
.polaroid-name { padding-top: 2px; font: 700 15px/21px var(--font-sans); }
.polaroid .find-it { align-self: flex-start; margin-top: auto; }

/* A wish with no pictures: a sticky note with its top-right corner folded over. Its words stay in
   Nunito; the handwriting font is only for the message and the sign-off (§5). */
.sticky-note .polaroid-front {
  justify-content: center;
  min-height: 180px;
  padding: var(--space-6) var(--space-4) var(--space-4);
  background: linear-gradient(225deg, transparent 18px, color-mix(in srgb, var(--lantern) 45%, var(--paper)) 0);
  box-shadow: none;
  filter: drop-shadow(0 6px 6px color-mix(in srgb, var(--on-paper) 30%, transparent));
}
.sticky-note .polaroid-front::before { display: none; }
.sticky-note .polaroid-front::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 25px;
  height: 25px;
  background: linear-gradient(to bottom left, transparent 50%, color-mix(in srgb, var(--lantern) 70%, var(--paper-muted)) 0);
}
.sticky-note .polaroid-name { font-size: 17px; line-height: 24px; }
.sticky-note .find-it { margin-top: var(--space-2); }

/* Pointed at, a polaroid straightens and lifts, and its stack fans out (mouse pointers only) */
@media (hover: hover) and (pointer: fine) {
  .polaroid:hover .polaroid-front { transform: rotate(0deg) translateY(-3px); }
  .polaroid:hover .polaroid-back { transform: rotate(calc(var(--tilt) + 8deg)) translate(12px, 0); }
}

.wish-number {
  flex-shrink: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--radius-full);
  background: var(--lantern-soft);
  color: var(--lantern-ink);
  font: 600 17px/1 var(--font-display);
}
/* Links on the paper use its own inks: ice and lantern amber are too light on paper */
.paper .find-it {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  min-height: 44px;
  padding: 0 var(--space-4);
  background: var(--paper);
  color: var(--paper-muted);
  border: 1.5px solid var(--paper-line);
  border-radius: var(--radius-full);
  font: 700 15px/23px var(--font-sans);
  text-decoration: none;
  transition: color 150ms ease, border-color 150ms ease;
}
.paper .find-it:hover, .paper .find-it:focus-visible { color: var(--on-paper); border-color: var(--paper-muted); }

.share { display: flex; flex-direction: column; gap: var(--space-2); }
.share-link { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-top: var(--space-1); }
.share-link .field { flex: 1 1 240px; min-width: 0; }
.share-apps { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.write-own { align-self: center; font-weight: 700; }

/* Support modal (Ko-fi): a close button over Ko-fi's form. The form is light, so it sits on its own light card. */
.modal-support { width: min(420px, calc(100% - var(--space-8))); }
.modal-support[open] { display: flex; flex-direction: column; }
.support-top { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); padding: var(--space-3) var(--space-3) var(--space-3) var(--space-6); }
.support-note { margin: calc(-1 * var(--space-2)) var(--space-6) var(--space-3); }
.modal-support iframe {
  display: block;
  width: calc(100% - 2 * var(--space-3));
  height: min(620px, 100dvh - 160px);
  margin: 0 var(--space-3) var(--space-3);
  border: 0;
  border-radius: var(--radius-lg);
  background: #f9f9f9;
}

/* Landing (DESIGN.md §4): a left-aligned block, then the three steps */
.landing { gap: var(--space-8); }
.landing-intro { display: flex; flex-direction: column; align-items: flex-start; gap: var(--space-4); }
.landing-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3) var(--space-6); margin-top: var(--space-2); }
.landing-example { font-weight: 700; }
.steps { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--space-4); }
.step { display: flex; flex-direction: column; gap: var(--space-2); padding: var(--space-4); background: var(--surface-raised); border: 1px solid var(--line); border-radius: var(--radius-lg); }
.step-icon { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--radius-full); background: var(--lantern-soft); color: var(--lantern-ink); }
.step-icon .icon { width: 20px; height: 20px; }

/* Create (DESIGN.md §4): the middle scrolls between the header and the action bar. The terms link
   lives in the action bar, so the site footer isn't shown. */
.site-main:has(> .create-page) { flex: 1 1 0; min-height: 0; justify-content: flex-start; }
.panel:has(.create-page) .site-footer { display: none; }
.create-page, .create-form { flex: 1; min-height: 0; display: flex; flex-direction: column; }
.create-middle {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
  /* Room for focus rings and card edges, without moving the content off the panel's padding */
  margin: 0 calc(-1 * var(--space-4));
  padding: var(--space-1) var(--space-4) var(--space-2);
}
.create-intro { display: flex; flex-direction: column; gap: var(--space-1); margin-bottom: var(--space-6); }
.nickname .field { max-width: 420px; }

/* The message, written on the letter paper as it will look once sent */
.letter-draft { gap: var(--space-2); padding: var(--space-6); transition: box-shadow 150ms ease; }
.letter-draft:focus-within { box-shadow: var(--shadow-md), var(--focus-ring); }
.draft-message {
  display: block;
  width: 100%;
  min-height: calc(4 * 28px);
  field-sizing: content;
  padding: 0;
  border: 0;
  resize: none;
  color: var(--on-paper);
  background-attachment: local; /* the ruled lines scroll with the text */
}
.draft-message:focus-visible { box-shadow: none; outline: none; } /* the paper shows the focus instead */
.draft-message::placeholder { color: var(--paper-muted); }
.draft-count { align-self: flex-end; color: var(--paper-muted); }
#sign-name:empty::before { content: "your nickname"; color: var(--paper-muted); }

.wishes-head { display: flex; flex-wrap: wrap; align-items: flex-end; justify-content: space-between; gap: var(--space-2) var(--space-4); }
.wishes { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }
.wish {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--surface-raised);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.wish-top { display: flex; align-items: flex-end; gap: var(--space-3); }
.wish-field { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.add-wish { align-self: flex-start; }

/* Pictures: thumbnails first, then the Add image tile, then the caption. The slots don't box
   their children, so the order can mix them. */
.wish-images { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); }
.picture-slot { display: contents; }
.thumb { position: relative; order: 0; width: 96px; height: 96px; margin: 0; }
.thumb[hidden], .add-image[hidden] { display: none; }
.thumb img { display: block; width: 100%; height: 100%; object-fit: cover; border-radius: var(--radius-md); background: var(--surface-sunken); }
/* A 28px circle inside a 44px hit area, on the thumbnail's top-right corner */
.thumb-remove {
  position: absolute;
  top: -14px;
  right: -14px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--surface);
  cursor: pointer;
}
.thumb-remove::before { content: ""; position: absolute; width: 28px; height: 28px; border-radius: var(--radius-full); background: var(--ink); }
.thumb-remove .icon { position: relative; width: 16px; height: 16px; }
.add-image {
  position: relative; /* keeps its visually hidden file input inside the scrolling middle */
  order: 1;
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 96px;
  height: 96px;
  color: var(--ink-muted);
  border: 2px dashed var(--border-strong);
  border-radius: var(--radius-md);
  font: 700 13px/18px var(--font-sans);
  cursor: pointer;
  transition: color 120ms ease, border-color 120ms ease, transform 160ms var(--ease-out);
}
.add-image:active { transform: scale(0.97); }
.add-image:has(:focus-visible) { box-shadow: var(--focus-ring); }
.wish-images .caption { order: 2; }

@media (hover: hover) and (pointer: fine) {
  .icon-button:hover { color: var(--ink); background: color-mix(in srgb, var(--ink) 8%, transparent); }
  .add-image:hover { color: var(--ink); border-color: var(--ink-muted); }
}

.action-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2) var(--space-4);
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}
.info-note {
  flex: 1 1 280px;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-4);
  background: var(--ice-soft);
  color: var(--ice);
  border-radius: var(--radius-md);
  font: 600 15px/23px var(--font-sans);
}
.info-note .icon { flex-shrink: 0; }
.action-terms { flex-basis: 100%; text-align: right; }

/* Entrances (DESIGN.md §4): the letter and the Landing content appear once each time the page
   opens. While the scene is in front (just sent, first arrival) the animation isn't set, so it
   starts as the panel fades in. With reduced motion they only fade. */
@keyframes rise-in { from { opacity: 0; transform: translateY(16px); } }
@keyframes fade-in { from { opacity: 0; } }
:root:not([data-diorama-front]) .letter-page .paper {
  animation: rise-in 400ms var(--ease-out) both;
  animation-delay: var(--after-card, 0ms);
}
/* Each polaroid drops onto the paper after it, turning into its tilt */
@keyframes polaroid-in { from { opacity: 0; transform: translateY(-10px) rotate(4deg) scale(1.04); } }
:root:not([data-diorama-front]) .polaroid {
  animation: polaroid-in 300ms var(--ease-out) both;
  animation-delay: calc(var(--after-card, 0ms) + 200ms + min(var(--i), 8) * 60ms);
}
/* Landing: each .rise piece in turn, --i being its place in the order */
:root:not([data-diorama-front]) .rise {
  animation: rise-in 400ms var(--ease-out) both;
  animation-delay: calc(var(--i, 0) * 50ms);
}
/* Create: an added wish card rises in; a picked picture's thumbnail grows in each time it shows.
   Removals fade out in the page script. */
@keyframes card-in { from { opacity: 0; transform: translateY(8px); } }
@keyframes thumb-in { from { opacity: 0; transform: scale(0.95); } }
.wish.is-new { animation: card-in 200ms var(--ease-out) both; }
.thumb { animation: thumb-in 150ms var(--ease-out) both; }

@media (prefers-reduced-motion: reduce) {
  :root:not([data-diorama-front]) .letter-page .paper,
  :root:not([data-diorama-front]) .polaroid,
  :root:not([data-diorama-front]) .rise,
  .wish.is-new,
  .thumb { animation-name: fade-in; }
  .polaroid-front, .polaroid-back, .polaroid-picture { transition: none; }
}

/* Narrow screens: the page scrolls instead of the paper. Right after sending, the share section
   comes first so the sender sees it without scrolling past the letter. */
@media (max-width: 819px) {
  .site-main:has(> .letter-page) { flex: 1 0 auto; }
  .letter-page .paper { flex: none; overflow: visible; }
  .letter-page[data-just-sent="true"] .share { order: -1; }
}

/* Narrow screens, Create: the page scrolls instead of the middle, and the action bar sticks to the
   bottom of the screen, reaching the panel's edges. */
@media (max-width: 819px) {
  .site-main:has(> .create-page) { flex: 1 0 auto; }
  .create-middle { overflow: visible; margin: 0; padding: 0 0 var(--space-4); }
  .letter-draft { padding: var(--space-4); }
  .action-bar {
    position: sticky;
    bottom: 0;
    margin: 0 calc(-1 * var(--space-4)) calc(-1 * var(--space-6));
    padding: var(--space-3) var(--space-4) var(--space-4);
    background: var(--surface-raised);
    border-radius: 0 0 var(--radius-xl) var(--radius-xl);
  }
  .info-note { padding: var(--space-2) var(--space-3); font: 600 13px/18px var(--font-sans); }
  .action-bar .btn-primary { flex: 1; }
  .action-terms { text-align: center; }
}

/* Modals (share, terms, picture): centred on the whole screen */
.modal {
  width: min(480px, calc(100% - var(--space-8)));
  padding: 0;
  border: 0;
  border-radius: var(--radius-xl);
  background: var(--surface-raised);
  color: var(--ink);
  box-shadow: var(--shadow-lg);
}
.modal::backdrop { background: color-mix(in srgb, var(--surface-sunken) 70%, transparent); }
.modal-body { display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-6); }
.modal-actions { display: flex; flex-direction: column; gap: var(--space-2); }

/* Terms: the title and Close stay put and the text between them scrolls.
   On narrow screens it covers two thirds of the screen's height, centred. */
.modal-terms[open] { display: flex; }
.modal-terms .modal-body { flex: 1; min-height: 0; }
.modal-middle {
  flex: 1;
  min-height: 0;
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  scrollbar-width: thin;
  scrollbar-color: var(--border-strong) transparent;
}
.modal-middle .heading:not(:first-child) { margin-top: var(--space-3); }

/* Picture: only the picture, as large as fits (never cropped or stretched), with its wish's name
   and link in a strip under it. The modal is exactly as wide as the picture. --picture-ratio
   (width / height) is set by the page script from the picture itself. */
.modal-picture {
  --caption-height: 52px;
  --room-width: min(960px, 100vw - 2 * var(--space-6));
  --room-height: calc(100dvh - 2 * var(--space-12) - var(--caption-height));
  width: fit-content;
  max-width: none;
  max-height: none;
  overflow: hidden;
}
.modal-picture figure { margin: 0; }
.modal-picture img {
  display: block;
  width: min(var(--room-width), var(--room-height) * var(--picture-ratio, 1));
  aspect-ratio: var(--picture-ratio, 1);
  object-fit: contain;
}
.modal-picture figcaption {
  contain: inline-size; /* the strip takes the picture's width; a long name wraps instead of widening it */
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-4);
  min-height: var(--caption-height);
  padding: var(--space-3) var(--space-4);
}
/* "2 of 5" and Find it here, on the strip's right */
.picture-end { flex-shrink: 0; display: inline-flex; align-items: baseline; gap: var(--space-3); }
/* Sideways swipes reach the page script (the next picture); up and down still scroll */
.modal-picture img { touch-action: pan-y; }

@media (max-width: 819px) {
  .modal-terms { height: calc(100dvh * 2 / 3); }
  .modal-picture { --room-height: calc(100dvh * 2 / 3 - var(--caption-height)); }
}

/* Error page: its own small page on the night sky, no diorama (Features/Error) */
body.error-page {
  display: grid;
  place-items: center;
  grid-template-columns: minmax(0, 1fr);
  min-height: 100dvh;
  height: auto;
  overflow: auto;
  padding: var(--space-4);
  background: var(--surface);
}
.error-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  width: min(480px, 100%);
  padding: var(--space-8) var(--space-6);
  text-align: center;
  background: var(--surface-raised);
  border-radius: var(--radius-xl);
  box-shadow: var(--shadow-lg);
}
.error-astro { width: 192px; height: 192px; image-rendering: pixelated; }

@media (max-width: 480px) {
  .hero-title { font-size: 34px; line-height: 40px; }
  .paper { padding: var(--space-4); }
}
