/* ---- Site footer (js/site-footer.js) ----
 * Three modules in a row: a CD player, a postcard for the guest book, and
 * a leather pocket of links. It sits fixed under the page, and the page
 * scrolls up off it, so it's revealed from underneath.
 *
 * Each module is drawn at its Figma frame's size (322×503, 960×503) in
 * `--u` units (1u = one Figma px at the module's current width), so the
 * whole thing scales with the window. Images are in images/footer/.
 */

/* ---- The reveal ----
   The page covers the footer until its end scrolls past. The page needs
   its own background for that; clip-path keeps the fixed dot grid
   (js/dot-grid.js, moved inside the page) from covering the footer too.
   The room to scroll it into view is padding under the page
   (--footer-h, set by js/site-footer.js); a margin would collapse out of
   the page and not scroll. A footer taller than the window can't be
   revealed this way, so then it just follows the page (html.footer-static). */
html {
  --page-corner: 2rem; /* the page's rounded bottom corners */
}

.page-wrapper {
  z-index: 1;
  background-color: var(--page-bg, #fff);
  clip-path: inset(0 round 0 0 var(--page-corner) var(--page-corner));
  /* Always taller than the window (corners included), so the footer
     never peeks out before you scroll, however short the page */
  min-height: calc(100vh + var(--page-corner));
}

body {
  position: relative; /* for the shadow below */
  padding-bottom: var(--footer-h, 0px);
}

html.footer-static body {
  padding-bottom: 0;
}

/* A soft shadow along the page's bottom edge, so the page reads as a sheet
   lifting off the footer (Figma "Footer-Mockup-Full": black 24%, y -3,
   blur 38). It can't go on .page-wrapper (its clip-path would cut it
   off), so it's an empty box with the same rounded corners, sat right on
   that edge. As ::before it's drawn under the page, so the page hides the
   shadow's upper half and only the part over the footer shows. */
body::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: var(--footer-h, 0px);
  z-index: 1;
  height: var(--page-corner);
  border-radius: 0 0 var(--page-corner) var(--page-corner);
  box-shadow: 0 -3px 38px rgba(0, 0, 0, .24);
  pointer-events: none;
}

html.footer-static body::before {
  display: none;
}

@media screen and (max-width: 767px) {
  html {
    --page-corner: 1.25rem;
  }
}

/* The footer's CSS images wait like its <img>s do (js/site-footer.js) */
.site-footer:not(.has-images) .mp,
.site-footer:not(.has-images) .lk,
.site-footer:not(.has-images) .pc-grain {
  background-image: none !important;
}

/* Not drawn until js/site-footer.js fills it. Growing from an empty strip
   to its full height counted as a layout shift. */
.site-footer:empty {
  display: none;
}

.site-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 0;
  padding: 1.3vw;
  background-color: #e7e7e7;
}

/* The archive (dark mode): dark under the dark player, but darker than
   the page, so the page's rounded bottom corners still show against it */
html.is-dark .site-footer {
  background-color: #070505;
}

/* Behind everything: the page's color, or the footer's once it's showing
   (html.footer-near, js/site-footer.js). Safari's bounce past the end
   lifts the page while the fixed footer stays put, and the gap between
   them showed white. */
html {
  background-color: var(--page-bg, #fff);
}

/* (the body's own color would cover that gap, which is its padding) */
html body {
  background-color: transparent;
}

html.footer-near {
  background-color: #e7e7e7;
}

html.is-dark.footer-near {
  background-color: #070505;
}

/* The footer's color reaches a little above it, behind the page's rounded
   corners. Scrolled all the way down, the footer's top meets the page's
   edge, and without this the corners would show the white behind
   everything and look square. */
.site-footer::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: calc(var(--page-corner) + 1px);
  background-color: inherit;
  pointer-events: none;
}

/* Text drawn the way Figma draws it. Browsers on a Mac otherwise render
   it a touch heavier, so the semibold looked bold. */
.site-footer,
.pc-face {
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

html.footer-static .site-footer {
  position: relative;
}

.ft-row {
  display: grid;
  grid-template-columns: 322fr 960fr 322fr;
  gap: 1.25vw;
}

.ft-mod {
  position: relative;
  container-type: inline-size;
  overflow: hidden;
  border-radius: var(--radius, .75rem);
  --u: calc(100cqw / 322);
  aspect-ratio: 322 / 503;
}

/* Everything inside a module is placed by its Figma position */
.ft-mod * {
  box-sizing: border-box;
}

.ft-abs {
  position: absolute;
  display: block;
}

/* ---- Music player ---- */

.mp {
  background: url("../images/footer/music-body-light.avif") center / 100% 100% no-repeat;
}

html.is-dark .mp {
  background-image: url("../images/footer/music-body-dark.avif");
}

/* SoundCloud logo: links to the mix that's in */
.mp_logo {
  left: calc(272 * var(--u));
  top: calc(16 * var(--u));
  width: calc(36 * var(--u));
  height: calc(16 * var(--u));
  color: #f1f1f1;
  transition: color .6s ease, opacity .2s ease;
}

html.is-dark .mp_logo {
  color: #757575;
}

.mp_logo:hover {
  opacity: .7;
}

.mp_logo svg {
  display: block;
  width: 100%;
  height: 100%;
}

/* The round slot the CDs sit in. Its shape is the mask: a CD swinging in
   or out only shows inside it. */
.mp_well {
  left: calc(33.5 * var(--u)); /* centered: (322 - 255) / 2 */
  top: calc(49 * var(--u));
  width: calc(255 * var(--u));
  height: calc(255 * var(--u));
  border-radius: 50%;
  background-color: #262626;
  box-shadow: inset 0 calc(-5 * var(--u)) calc(4.2 * var(--u)) calc(2 * var(--u)) rgba(0, 0, 0, .25);
  overflow: hidden;
  clip-path: circle(50%);
}

/* One per CD. It swings in and out round a point well below the slot,
   like a wheel; the disc inside spins on its own. */
.mp_disc {
  position: absolute;
  left: calc(18.5 * var(--u));
  top: calc(18.5 * var(--u));
  width: calc(218 * var(--u));
  height: calc(218 * var(--u));
  transform-origin: 50% 210%;
  visibility: hidden;
}

.mp_disc.is-in {
  visibility: visible;
}

.mp_disc img {
  display: block;
  width: 100%;
  height: 100%;
  will-change: transform;
  -webkit-user-drag: none;
  user-select: none;
}

.mp_controls {
  left: calc(25 * var(--u));
  top: calc(335 * var(--u));
  width: calc(272 * var(--u));
  height: calc(120 * var(--u));
  pointer-events: none;
}

/* Status light: red while stopped, green while playing */
.mp_led {
  left: calc(212 * var(--u));
  top: calc(338 * var(--u));
  width: calc(12 * var(--u));
  height: calc(12 * var(--u));
  border-radius: 50%;
  background: radial-gradient(circle at 50% 42%, #5a5a5a, #999);
  pointer-events: none;
}

.mp_led::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background-color: #ff0000;
  filter: blur(calc(3 * var(--u)));
  transition: background-color .4s ease;
}

.mp.is-playing .mp_led::after {
  background-color: #9dff00;
  animation: mp-led-blink 1.2s ease-in-out infinite;
}

/* Blinks while playing, like a stereo's activity light */
@keyframes mp-led-blink {
  0%, 45% { opacity: 1; }
  60%, 85% { opacity: .2; }
  100% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .mp.is-playing .mp_led::after {
    animation: none;
  }
}

/* The three buttons: see-through, over the buttons in the image. Pressing
   one shades its face, as if it's pushed in. */
.mp_btn {
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

.mp_btn::after {
  content: "";
  position: absolute;
  inset: 9.5%;
  border-radius: 50%;
  background-color: rgba(0, 0, 0, 0);
  box-shadow: inset 0 0 0 rgba(0, 0, 0, 0);
  transition: background-color .25s ease, box-shadow .25s ease;
}

.mp_btn:active::after {
  background-color: rgba(0, 0, 0, .06);
  box-shadow: inset 0 calc(3 * var(--u)) calc(7 * var(--u)) rgba(0, 0, 0, .3);
  transition-duration: .06s;
}

.mp_btn:focus-visible {
  outline: 2px solid var(--gundam-blue, #2519ab);
  outline-offset: 2px;
}

.mp_prev {
  left: calc((68 - 34) * var(--u));
  top: calc((396 - 34) * var(--u));
  width: calc(68 * var(--u));
  height: calc(68 * var(--u));
}

.mp_play {
  left: calc((161 - 47) * var(--u));
  top: calc((397 - 47) * var(--u));
  width: calc(94 * var(--u));
  height: calc(94 * var(--u));
}

.mp_next {
  left: calc((254 - 34) * var(--u));
  top: calc((396 - 34) * var(--u));
  width: calc(68 * var(--u));
  height: calc(68 * var(--u));
}

/* The hidden SoundCloud player that does the playing */
.mp_widget {
  position: absolute;
  left: -9999px;
  top: 0;
  width: 300px;
  height: 166px;
  border: 0;
  opacity: 0;
  pointer-events: none;
}

/* ---- Postcard module ---- */

.ft-pc {
  --stage-w: 960; /* how much of the 960-wide Figma frame shows */
  --u: calc(100cqw / var(--stage-w));
  /* The text stays on its two lines: once it stops shrinking at 11px,
     its box stops shrinking too (each line is about 31 letters' widths).
     Small desktop windows and iPads in landscape need it as much as
     tablets do. */
  --head-px: max(calc(435 * var(--u)), 352px);
  aspect-ratio: 960 / 503;
  background-color: #fff;
  box-shadow: inset 0 1px 4px rgba(185, 182, 249, .25);
  transition: background-color .6s ease;
}

/* The archive (dark mode): Figma "guest-note-module-darkmode". Only the
   module goes dark; the card, stamps and gray text stay as they are. */
html.is-dark .ft-pc {
  background-color: #313131;
}

/* The full 960×503 frame, centered (phones crop its sides) */
.pc-stage {
  position: absolute;
  top: calc(var(--stage-top, 0) * var(--u));
  left: calc((var(--stage-w) - 960) / 2 * var(--u));
  width: calc(960 * var(--u));
  height: calc(503 * var(--u));
}

/* The text and the dashed line from it down to the postcard. Together
   they fill the space above the card (to 28 short of it, as in Figma):
   the line takes what the text leaves, so it always ends above the card,
   however many lines the text wraps to. */
.pc-head {
  --head-w: 435; /* text width */
  left: calc(480 * var(--u) - var(--head-px, var(--head-w) * var(--u)) / 2);
  top: calc((39 - var(--stage-top, 0)) * var(--u));
  width: var(--head-px, calc(var(--head-w) * var(--u)));
  height: calc((128 + var(--stage-top, 0)) * var(--u));
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: calc(28 * var(--u));
}

.pc-blurb {
  flex: none;
  margin: 0;
  color: #b2b2b2;
  font-family: Geist, sans-serif;
  font-size: var(--pc-font, max(11px, calc(14 * var(--u))));
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: calc(-.25 * var(--u));
  text-align: center;
  text-wrap: balance;
}

.pc-string {
  flex: 1 1 auto;
  width: 1px;
  min-height: calc(12 * var(--u));
  max-height: calc(58 * var(--u));
  background: repeating-linear-gradient(to bottom, #b2b2b2 0 calc(3 * var(--u)), transparent 0 calc(6 * var(--u)));
}

.pc-blurb,
.pc-string {
  transition: opacity .45s ease, translate .6s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Loose stamps around the card. Their size and angle are measured from
   the card's own stamp image (stamp-*.avif). */
.pc-loose {
  width: calc(107.7 * var(--u));
  height: calc(127.3 * var(--u));
  margin: calc(-63.65 * var(--u)) 0 0 calc(-53.85 * var(--u));
  transition: translate .7s cubic-bezier(0.22, 1, 0.36, 1), rotate .7s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
  /* A firmer edge than the image's own faint shadow, so the white scallops
     show on the white module (Figma: 20% black, y 1, blur 1.1; the blur
     means the same in CSS). At least a pixel, so it doesn't fade out when
     the footer is drawn smaller than in Figma. */
  filter: drop-shadow(0 max(1px, calc(1 * var(--u))) max(1.1px, calc(1.1 * var(--u))) rgba(0, 0, 0, .2));
}

.pc-loose.is-green { left: calc(112.5 * var(--u)); top: calc(292.1 * var(--u)); rotate: -16.2deg; }
.pc-loose.is-yellow { left: calc(116.2 * var(--u)); top: calc(474.4 * var(--u)); rotate: 20.1deg; }
.pc-loose.is-red { left: calc(861.7 * var(--u)); top: calc(463.5 * var(--u)); rotate: -24.4deg; }

/* The postcard: peeks up from the bottom; hovering lifts it into view */
.ft-pc .pc-card {
  left: calc(202 * var(--u));
  top: calc(195 * var(--u));
  width: calc(556 * var(--u));
  height: calc(393.17 * var(--u));
  cursor: pointer;
  transition: translate .7s cubic-bezier(0.22, 1, 0.36, 1);
  -webkit-tap-highlight-color: transparent;
}

.ft-pc .pc-card:focus-visible {
  outline: none;
}

.ft-pc .pc-card:focus-visible .pc-face {
  outline: 2px solid var(--gundam-blue, #2519ab);
  outline-offset: 3px;
}

.ft-pc.is-lifted .pc-card { translate: 0 calc(-140 * var(--u)); }
/* Hovered, the loose stamps fly up and turn (Figma: guest-note-hover) */
.ft-pc.is-lifted .pc-loose.is-green { translate: calc(-17.9 * var(--u)) calc(-155.4 * var(--u)); rotate: 20.8deg; }
.ft-pc.is-lifted .pc-loose.is-yellow { translate: calc(30.9 * var(--u)) calc(-142.7 * var(--u)); rotate: -25deg; }
.ft-pc.is-lifted .pc-loose.is-red { translate: calc(-8.6 * var(--u)) calc(-170.6 * var(--u)); rotate: 12.7deg; }
.ft-pc.is-lifted .pc-loose.is-yellow { transition-delay: .03s; }
.ft-pc.is-lifted .pc-loose.is-red { transition-delay: .05s; }
.ft-pc.is-lifted .pc-blurb,
.ft-pc.is-lifted .pc-string {
  opacity: 0;
  translate: 0 calc(-12 * var(--u));
}

/* While the card is open in the middle of the screen, the footer's copy
   of it is hidden */
.ft-pc.is-out .pc-card {
  visibility: hidden;
}

/* ---- The postcard itself ----
   Used in the footer, opened in the middle of the screen
   (js/footer-postcard.js) and on the guest book page (guestbook.html).
   Laid out in --u units of its 556×393 Figma frame. */
.pc-face {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: calc(10.6 * var(--u));
  background-color: #fff;
  box-shadow: 0 calc(5.3 * var(--u)) calc(17.9 * var(--u)) rgba(0, 0, 0, .09);
  color: #555;
  text-align: left;
  --tint-blue: #dce7ff;
  --tint-red: #ffdcdc;
  --tint-yellow: #fff3dc;
  --tint-green: #e7ffdc;
  --post-blue: #e6eeff;
}

/* One tinted layer per color; the chosen one shows */
.pc-tint {
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
}

.pc-tint.is-on {
  opacity: 1;
}

.pc-tint[data-color="blue"] { background: linear-gradient(199deg, var(--tint-blue) 1%, #fff 57%); }
.pc-tint[data-color="red"] { background: linear-gradient(199deg, var(--tint-red) 1%, #fff 57%); }
.pc-tint[data-color="yellow"] { background: linear-gradient(199deg, var(--tint-yellow) 1%, #fff 57%); }
.pc-tint[data-color="green"] { background: linear-gradient(199deg, var(--tint-green) 1%, #fff 57%); }

/* Paper grain */
.pc-grain {
  position: absolute;
  inset: 0;
  pointer-events: none;
  /* No blend mode: over the card's near-white it looks the same, and a
     blend mode inside the guest book carousel's 3D turn made it lag */
  opacity: .32;
  /* A ready-made tile rather than an SVG noise filter: the filter is slow
     to redraw, and the guest book carousel redraws cards as they turn.
     Made at 2x (360px shown at 180), so the grain stays fine on Retina. */
  background-image: url("../images/footer/grain.avif");
  background-size: 180px 180px;
}

.pc-divider {
  left: calc(375.5 * var(--u));
  top: calc(27.5 * var(--u));
  width: max(1px, calc(.66 * var(--u)));
  height: calc(336 * var(--u));
  background: repeating-linear-gradient(to bottom, #a9a9a9 0 calc(2 * var(--u)), transparent 0 calc(4 * var(--u)));
}

/* Small labels ("Message", "From"...): placed by their middle */
.pc-label {
  margin: 0;
  font-family: Geist, sans-serif;
  font-size: calc(11.9 * var(--u));
  font-weight: 600;
  line-height: 1;
  letter-spacing: calc(-.33 * var(--u));
  white-space: nowrap;
  translate: 0 -50%;
}

/* Handwriting: the message, names and "Pedro" */
.pc-hand {
  font-family: Caveat, cursive;
  font-size: calc(23.8 * var(--u));
  font-weight: 700;
  line-height: calc(27.8 * var(--u));
  letter-spacing: calc(-.33 * var(--u));
  color: #130f0f;
}

.pc-hand.is-empty,
.pc-hand::placeholder {
  color: #d1d1d1;
  opacity: 1;
}

.pc-guest,
.pc-date { left: calc(19.5 * var(--u)); top: calc(41 * var(--u)); }
.pc-msg-label { left: calc(19.5 * var(--u)); top: calc(110 * var(--u)); }

/* Message: four ruled lines, the writing sits on them */
.pc-msg {
  left: calc(19.5 * var(--u));
  top: calc(130.2 * var(--u));
  width: calc(336.2 * var(--u));
  height: calc(111.2 * var(--u));
  margin: 0;
  padding: 0 0 0 calc(1 * var(--u));
  border: 0;
  outline: 0;
  resize: none;
  overflow: hidden;
  overflow-wrap: break-word;
  background: repeating-linear-gradient(to bottom, transparent 0 calc(27.14 * var(--u)), #a9a9a9 calc(27.14 * var(--u)) calc(27.8 * var(--u)));
}

.pc-from-label { left: calc(19.5 * var(--u)); top: calc(333.5 * var(--u)); }
.pc-from {
  left: calc(19.5 * var(--u));
  top: calc((355 - 13.9) * var(--u));
  width: calc(336 * var(--u));
  height: calc(27.8 * var(--u));
  margin: 0;
  padding: 0;
  border: 0;
  outline: 0;
  background: transparent;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.pc-to-label { left: calc(395 * var(--u)); top: calc(333.5 * var(--u)); }
.pc-to { left: calc(395 * var(--u)); top: calc((355 - 13.9) * var(--u)); color: #555; }

/* .pc-face in front so the carousel's own image rule (.hcar_media img,
   css/home.css) doesn't stretch it on the guest book page */
.pc-face .pc-stamp {
  left: calc((479.2 - 53.85) * var(--u));
  top: calc((88.2 - 63.65) * var(--u));
  width: calc(107.7 * var(--u));
  height: calc(127.3 * var(--u));
  object-fit: fill;
  border-radius: 0;
  opacity: 0;
  pointer-events: none;
  -webkit-user-drag: none;
}

.pc-stamp.is-on {
  opacity: 1;
}

/* Form-only parts: the date, colors, buttons and the guest book link.
   They only show once the card is opened to write one. */
.pc-date,
.pc-colors,
.pc-back,
.pc-post,
.pc-view {
  opacity: 0;
  visibility: hidden;
}

.pc-colors {
  left: calc(19 * var(--u));
  top: calc(63 * var(--u));
  display: flex;
  gap: calc(12 * var(--u));
}

.pc-dot {
  width: calc(28 * var(--u));
  height: calc(28 * var(--u));
  margin: 0;
  padding: 0;
  border: 1px solid transparent;
  border-radius: 50%;
  cursor: pointer;
  transition: border-color .3s ease, scale .3s cubic-bezier(0.34, 1.56, 0.64, 1);
  -webkit-tap-highlight-color: transparent;
}

.pc-dot[data-color="blue"] { background-color: var(--tint-blue); }
.pc-dot[data-color="red"] { background-color: var(--tint-red); }
.pc-dot[data-color="yellow"] { background-color: var(--tint-yellow); }
.pc-dot[data-color="green"] { background-color: var(--tint-green); }

.pc-dot[aria-pressed="true"] {
  border-color: #a7a7a7;
}

.pc-dot:hover {
  scale: 1.08;
}

.pc-dot:focus-visible,
.pc-back:focus-visible,
.pc-post:focus-visible {
  outline: 2px solid var(--gundam-blue, #2519ab);
  outline-offset: 2px;
}

.pc-back,
.pc-post,
.pc-view {
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  color: #555;
  font-family: Geist, sans-serif;
  font-size: calc(11.9 * var(--u));
  font-weight: 600;
  letter-spacing: calc(-.33 * var(--u));
  cursor: pointer;
}

.pc-back {
  left: calc(21 * var(--u));
  top: calc((353 - 11.5) * var(--u));
  height: calc(23 * var(--u));
  display: flex;
  align-items: center;
  gap: calc(4 * var(--u));
}

.pc-back svg {
  width: calc(22 * var(--u));
  height: calc(8 * var(--u));
  transition: translate .3s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-back:hover svg {
  translate: calc(-3 * var(--u)) 0;
}

.pc-post {
  left: calc(250 * var(--u));
  top: calc(341.5 * var(--u));
  width: calc(106 * var(--u));
  height: calc(23 * var(--u));
  border-radius: calc(6 * var(--u));
  background-color: var(--post-color, var(--post-blue));
  transition: background-color .5s ease, filter .2s ease, opacity .45s ease, translate .6s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-post:hover {
  filter: brightness(.97);
}

/* "View guest book", top right of the message side */
.pc-view {
  left: calc(256 * var(--u));
  top: calc(30.7 * var(--u));
  width: calc(106 * var(--u));
  height: calc(18 * var(--u));
  display: flex;
  align-items: center;
  justify-content: center;
  text-decoration: none;
}

.pc-view:hover {
  color: var(--black, #130f0f);
}

.pc-post:disabled {
  cursor: default;
}

/* Spam trap: people never see or fill it */
.pc-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* Opening the card turns its footer layout into the form: "Guest book"
   gives way to the date and colors, "From" moves up, the buttons come in */
.pc-guest,
.pc-from-label,
.pc-from {
  transition: opacity .35s ease, translate .6s cubic-bezier(0.22, 1, 0.36, 1);
}

.pc-date,
.pc-colors,
.pc-back,
.pc-post,
.pc-view {
  transition: opacity .45s ease, visibility 0s .45s, translate .6s cubic-bezier(0.22, 1, 0.36, 1);
  translate: 0 calc(6 * var(--u));
}

.pc-date {
  translate: 0 calc(-50% + 6 * var(--u));
}

.pc-face.is-form .pc-guest {
  opacity: 0;
}

.pc-face.is-form .pc-date,
.pc-face.is-form .pc-colors,
.pc-face.is-form .pc-back,
.pc-face.is-form .pc-post,
.pc-face.is-form .pc-view {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  transition: opacity .45s ease .12s, visibility 0s, translate .6s cubic-bezier(0.22, 1, 0.36, 1) .12s, background-color .5s ease, filter .2s ease;
}

.pc-face.is-form .pc-date {
  translate: 0 -50%;
}

.pc-face.is-form .pc-colors { transition-delay: .18s, 0s, .18s; }
.pc-face.is-form .pc-back,
.pc-face.is-form .pc-post { transition-delay: .24s, 0s, .24s, 0s, 0s; }

.pc-face.is-form .pc-from-label,
.pc-face.is-form .pc-from {
  translate: 0 calc(-54.5 * var(--u));
}

.pc-face.is-form .pc-from-label {
  translate: 0 calc(-50% - 54.5 * var(--u));
}

/* A finished note (guest book page): date instead of "Guest book", "From"
   up where the form has it, no buttons */
.pc-face.is-note .pc-guest { opacity: 0; }
.pc-face.is-note .pc-date { opacity: 1; visibility: visible; translate: 0 -50%; }
.pc-face.is-note .pc-from { translate: 0 calc(-54.5 * var(--u)); }
.pc-face.is-note .pc-from-label { translate: 0 calc(-50% - 54.5 * var(--u)); }

/* ---- The open postcard, in the middle of the screen ---- */
.pc-overlay {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  visibility: hidden;
}

.pc-overlay.is-open {
  visibility: visible;
}

/* Just a dim, no blur: Chrome redraws a blur whenever something on the
   card animates, so it flickered while switching colors */
.pc-dim {
  position: absolute;
  inset: 0;
  background-color: rgba(19, 15, 15, .4);
  opacity: 0;
  transition: opacity .5s ease;
}

.pc-overlay.is-open .pc-dim {
  opacity: 1;
}

.pc-overlay .pc-card {
  position: relative;
  width: min(92vw, 780px, calc(86vh * 556 / 393.17));
  aspect-ratio: 556 / 393.17;
  container-type: inline-size;
}

.pc-overlay .pc-face {
  --u: calc(100cqw / 556);
}

/* At least 16px, or iPhones zoom in on tapping them */
.pc-overlay .pc-msg,
.pc-overlay .pc-from {
  font-size: max(16px, calc(23.8 * var(--u)));
}

/* A posted note can have line breaks */
span.pc-msg {
  white-space: pre-wrap;
}

.pc-face,
.pc-face * {
  box-sizing: border-box;
}

/* A little shake when Post is pressed with no message */
.pc-msg.is-nudged {
  animation: pc-nudge .4s ease;
}

@keyframes pc-nudge {
  20% { translate: calc(-4 * var(--u)) 0; }
  40% { translate: calc(4 * var(--u)) 0; }
  60% { translate: calc(-2 * var(--u)) 0; }
  80% { translate: calc(2 * var(--u)) 0; }
}

/* ---- Links module ---- */

.lk {
  background: #2c2c2c url("../images/footer/links-leather.avif") center / 100% 100% no-repeat;
  box-shadow: inset 0 1px 4px rgba(185, 182, 249, .25);
}

.lk a {
  -webkit-tap-highlight-color: transparent;
}

.lk a:focus-visible {
  outline: 2px solid #fff;
  outline-offset: 3px;
}

/* Tucked in the pocket at rest; hovering pulls them out and straightens
   them (js/site-footer.js adds is-open for touch screens) */
.lk-email,
.lk-insta,
.lk-arena {
  transition: transform .5s cubic-bezier(0.22, 1, 0.36, 1);
}

.lk-email {
  left: calc((144.8 - 91.75) * var(--u));
  top: calc((242.8 - 118.8) * var(--u));
  width: calc(183.5 * var(--u));
  height: calc(237.6 * var(--u));
  transform: rotate(-13.4deg);
  border-radius: calc(12 * var(--u));
  background-color: #fff;
  overflow: hidden;
  color: #000;
  text-decoration: none;
}

.lk-insta,
.lk-arena {
  width: calc(124.5 * var(--u));
  height: calc(124.5 * var(--u));
  filter: drop-shadow(0 calc(4 * var(--u)) calc(6.75 * var(--u)) rgba(0, 0, 0, .09));
}

.lk-insta {
  left: calc((256 - 62.25) * var(--u));
  top: calc((201 - 62.25) * var(--u));
  transform: rotate(-9.8deg);
}

.lk-arena {
  left: calc((71.7 - 62.25) * var(--u));
  top: calc((364.7 - 62.25) * var(--u));
  transform: rotate(14.3deg);
}

.lk-insta img,
.lk-arena img {
  display: block;
  width: 100%;
  height: 100%;
  -webkit-user-drag: none;
}

.lk-pocket {
  left: 0;
  top: calc(114.7 * var(--u));
  width: calc(322 * var(--u));
  height: calc(388.3 * var(--u));
  pointer-events: none;
  transition: translate .55s cubic-bezier(0.22, 1, 0.36, 1);
}

.lk.is-open .lk-email { transform: translate(calc(-45.1 * var(--u)), calc(-115 * var(--u))); transition-duration: .65s; }
.lk.is-open .lk-insta { transform: translate(calc(2.8 * var(--u)), calc(-137.2 * var(--u))) scale(.8795); transition-duration: .65s; transition-delay: .04s; }
.lk.is-open .lk-arena { transform: translate(calc(-8.9 * var(--u)), calc(-51.9 * var(--u))) scale(.8795); transition-duration: .65s; transition-delay: .08s; }
.lk.is-open .lk-pocket { translate: 0 calc(53 * var(--u)); transition-duration: .65s; }

/* Each pulled-out item lifts a little more under the mouse */
.lk.is-open .lk-insta:hover,
.lk.is-open .lk-arena:hover {
  transition-delay: 0s;
}

.lk.is-open .lk-insta:hover { transform: translate(calc(2.8 * var(--u)), calc(-140 * var(--u))) scale(.9); }
.lk.is-open .lk-arena:hover { transform: translate(calc(-8.9 * var(--u)), calc(-54.7 * var(--u))) scale(.9); }

/* Notebook paper: blue rules and a red margin line */
.lk-paper {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(to right, transparent calc(24 * var(--u)), #ff8484 calc(24 * var(--u)) calc(24.7 * var(--u)), transparent 0),
    repeating-linear-gradient(to bottom, transparent 0 calc(16.2 * var(--u)), #e4ebf7 calc(16.2 * var(--u)) calc(16.9 * var(--u)));
  background-position: 0 0, 0 calc(3.7 * var(--u));
}

/* Three punched holes, cut out of the paper so what's behind shows
   through. Each layer is opaque except one hole; intersecting them leaves
   all three. */
.lk-email {
  --hole: calc(4.7 * var(--u)); /* radius */
  --hole-x: calc(12.5 * var(--u));
  -webkit-mask-image:
    radial-gradient(circle at var(--hole-x) calc(28.2 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px)),
    radial-gradient(circle at var(--hole-x) calc(119.2 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px)),
    radial-gradient(circle at var(--hole-x) calc(214.1 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px));
  mask-image:
    radial-gradient(circle at var(--hole-x) calc(28.2 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px)),
    radial-gradient(circle at var(--hole-x) calc(119.2 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px)),
    radial-gradient(circle at var(--hole-x) calc(214.1 * var(--u)), transparent var(--hole), #000 calc(var(--hole) + .5px));
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

.lk-dear,
.lk-q {
  position: absolute;
  margin: 0;
  font-family: Caveat, cursive;
  font-size: calc(21 * var(--u));
  font-weight: 700;
  line-height: calc(18 * var(--u));
  letter-spacing: calc(-.25 * var(--u));
}

.lk-dear {
  left: calc(28.5 * var(--u));
  top: calc(18.4 * var(--u));
  white-space: nowrap;
}

.lk-q {
  left: calc(26 * var(--u));
  top: calc(51 * var(--u));
  width: calc(139 * var(--u));
}

/* The question writes itself in, letter by letter (js/site-footer.js) */
.lk-q .ch {
  display: inline-block;
  white-space: pre;
}

.lk-q .w {
  display: inline-block;
  white-space: nowrap;
}

.lk-q.is-leaving {
  opacity: 0;
  transition: opacity .25s ease;
}

/* ---- Smaller screens ---- */

/* Tablets: the postcard across the top, the player and links under it,
   from the Figma section "Tablet" (postcard-module-tablet 744×503,
   music-player-module-*-tablet and links-module-tablet 366×420). The
   three line up: two 366s and the gap make 744. */
@media screen and (max-width: 991px) {
  .site-footer {
    padding: 12px;
  }

  .ft-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 12px;
  }

  .ft-pc {
    flex: 1 1 100%;
    order: -1; /* across the top */
  }

  .ft-music,
  .ft-links {
    flex: 0 0 auto;
    width: calc((100% - 12px) / 2);
    --u: calc(100cqw / 366);
    aspect-ratio: 366 / 420;
  }

  /* Music player: the same parts, moved for the wider, shorter body */
  .mp {
    background-image: url("../images/footer/music-body-light-tablet.avif");
  }

  html.is-dark .mp {
    background-image: url("../images/footer/music-body-dark-tablet.avif");
  }

  .mp_logo { left: calc(309 * var(--u)); }
  /* The slot and CDs at 90%, lower down, to make room for the speaker
     grills along the top (drawn into the body image) */
  .mp_well {
    left: calc(68.25 * var(--u)); /* centered: (366 - 229.5) / 2 */
    top: calc(47 * var(--u));
    width: calc(229.5 * var(--u));
    height: calc(229.5 * var(--u));
  }
  .mp_disc {
    left: calc(16.65 * var(--u));
    top: calc(16.65 * var(--u));
    width: calc(196.2 * var(--u));
    height: calc(196.2 * var(--u));
  }
  .mp_controls { left: calc(47 * var(--u)); top: calc(285.5 * var(--u)); }
  .mp_led { left: calc(234 * var(--u)); top: calc(288.5 * var(--u)); }
  .mp_prev { left: calc((90 - 34) * var(--u)); top: calc((346.5 - 34) * var(--u)); }
  .mp_play { left: calc((183 - 47) * var(--u)); top: calc((347.5 - 47) * var(--u)); }
  .mp_next { left: calc((276 - 34) * var(--u)); top: calc((346.5 - 34) * var(--u)); }

  /* Links: a deeper pocket, cut on a slant (its image is swapped in the
     markup's <picture>). Pulled out as in links-module-tablet-hover. */
  .lk {
    background-image: url("../images/footer/links-leather-tablet.avif");
  }

  .lk-email { left: calc((150.8 - 91.75) * var(--u)); top: calc((163.85 - 118.8) * var(--u)); }
  .lk-insta { left: calc((280 - 62.25) * var(--u)); top: calc((121 - 62.25) * var(--u)); }
  .lk-arena { left: calc((71.7 - 62.25) * var(--u)); top: calc((286.7 - 62.25) * var(--u)); }

  .lk-pocket {
    top: calc(44.67 * var(--u));
    width: calc(366 * var(--u));
    height: calc(375.33 * var(--u));
  }

  .lk.is-open .lk-email { transform: translate(calc(-51.05 * var(--u)), calc(-36.05 * var(--u))); }
  .lk.is-open .lk-insta { transform: translate(calc(-29 * var(--u)), calc(-62.5 * var(--u))) scale(.79); }
  .lk.is-open .lk-arena { transform: translate(calc(-14.2 * var(--u)), calc(19.8 * var(--u))) scale(.795); }
  .lk.is-open .lk-pocket { translate: 0 calc(56 * var(--u)); }
  .lk.is-open .lk-insta:hover { transform: translate(calc(-29 * var(--u)), calc(-65.3 * var(--u))) scale(.81); }
  .lk.is-open .lk-arena:hover { transform: translate(calc(-14.2 * var(--u)), calc(17 * var(--u))) scale(.815); }
}

/* Tablets (not phones): the postcard module is 744 wide, the 960 frame
   with its sides cut off, and the loose stamps tucked in closer */
@media screen and (min-width: 480px) and (max-width: 991px) {
  .ft-pc {
    --stage-w: 744;
    aspect-ratio: 744 / 503;
  }

  /* In the 960 frame's units: Figma's tablet positions plus the 108 cut
     off each side */
  .pc-loose.is-green { left: calc(172.6 * var(--u)); }
  .pc-loose.is-yellow { left: calc(187.2 * var(--u)); }
  .pc-loose.is-red { left: calc(792.7 * var(--u)); }

  /* Hovered (postcard-module-tablet-hover): the card lifts as on desktop;
     green and red fly up. Figma leaves yellow where it is, but it lifts
     like on desktop, as far left of the card as it is there. */
  .ft-pc.is-lifted .pc-loose.is-green { translate: calc(-16 * var(--u)) calc(-200 * var(--u)); rotate: -16.2deg; }
  .ft-pc.is-lifted .pc-loose.is-yellow { translate: calc(-40 * var(--u)) calc(-142.7 * var(--u)); rotate: -25deg; }
  .ft-pc.is-lifted .pc-loose.is-red { translate: 0 calc(-187.05 * var(--u)); rotate: 26.7deg; }
}

/* Phones: crop the postcard module's sides so the card stays big */
@media screen and (max-width: 479px) {
  .site-footer {
    padding: 8px;
  }

  .ft-row {
    gap: 8px;
  }

  .ft-music,
  .ft-links {
    width: calc((100% - 8px) / 2);
  }

  /* Phones: the whole frame shows, stamps included, with the text set
     wider. The module is taller than the frame (--pc-h): the extra room
     goes on top, so the card still peeks up from the bottom, and the
     lifted card sits in the middle. 100vw - 16px is the module's width,
     as --u can't be used for the module's own height. */
  .ft-pc {
    /* The text on two lines across the module: a box nearly its full
       width, and type that fits the whole blurb in two of them */
    --head-px: calc(100vw - 40px);
    --pc-font: min(11px, (100vw - 40px) / 36);
    --pc-h: calc((100vw - 16px) * 393.17 / 960 + 6 * var(--pc-font) + 24px);
    --top-room: calc(var(--pc-h) - 503 * var(--u));
    height: var(--pc-h);
    aspect-ratio: auto;
  }

  .pc-stage {
    top: var(--top-room);
  }

  /* The text keeps the room above the card, its line still ending 28 short
     of the card */
  .pc-head {
    top: calc(39 * var(--u) - var(--top-room));
    height: calc(128 * var(--u) + var(--top-room));
    justify-content: center;
  }

  .ft-pc.is-lifted .pc-card {
    translate: 0 calc(111.415 * var(--u) - var(--pc-h) / 2);
  }

  .pc-br {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .ft-pc .pc-card,
  .pc-loose,
  .pc-blurb,
  .pc-string,
  .lk-email,
  .lk-insta,
  .lk-arena,
  .lk-pocket {
    transition-duration: .01s !important;
    transition-delay: 0s !important;
  }
}
