/* Family link sites: dark poster page, one accent theme per person, name over a 3:1 banner. No JavaScript. */
/* The page stops at 1320px so the banner box never exceeds 1200 css px: on a 2x screen that is 2400
   physical px, exactly the source banner width, so the image is never upscaled. */
:root {
  --paper: #F5F1E8;
  --line: #0B0B0B;
  --font-title: "Oswald", Impact, "Arial Narrow", sans-serif;
  --font-body: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  /* Entrance start offsets; the inline script randomises them on every load. */
  --enter-name-y: 0%;
  --enter-card-y: 0%;
  --enter-card-rot: -1.5deg;
}
[data-theme="orange"] { --accent: #FF8A00; --accent-2: #FFD400; --bg: #14100B; --ink: #FFF6E5; }
[data-theme="pink"]   { --accent: #FF2E9A; --accent-2: #7A3CFF; --bg: #120A18; --ink: #FFE9F5; }
[data-theme="blue"]   { --accent: #1F8CFF; --accent-2: #00E0FF; --bg: #080E1A; --ink: #E8F3FF; }
[data-theme="green"]  { --accent: #39D353; --accent-2: #C7F464; --bg: #07140B; --ink: #EAFBEA; }

*, *::before, *::after { box-sizing: border-box; }
/* Both clip: with overflow hidden only on body (propagated to the viewport), Android Chrome widens the
   layout viewport to fit the entrance flight and the fixed family bar ends up below the screen. */
html { overflow-x: clip; background: var(--bg); color: var(--ink); font-family: var(--font-body); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100dvh;
  overflow-x: clip;
  background:
    radial-gradient(circle at 15% 8%, color-mix(in srgb, var(--accent) 26%, transparent), transparent 42%),
    radial-gradient(circle at 85% 92%, color-mix(in srgb, var(--accent-2) 20%, transparent), transparent 46%),
    var(--bg);
}
/* Fine halftone over the whole page: the printed-poster feel. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: radial-gradient(circle, rgb(255 255 255 / .07) 1px, transparent 1.4px);
  background-size: 7px 7px;
}
.page { position: relative; z-index: 1; max-width: 1320px; margin: 0 auto; padding: 28px 16px 96px; }
@media (min-width: 640px) { .page { padding: 48px 32px 104px; } }

/* Cream panel with a black border and a solid accent shadow, outlined again in black. */
.panel {
  background: var(--paper);
  border: 4px solid var(--line);
  box-shadow: 10px 10px 0 var(--accent), 14px 14px 0 var(--line);
}

/* Hero: the name sits at the top right, its lower ~22% overlapping the photo panel. */
.hero { --name-size: clamp(96px, 28vw, 270px); position: relative; display: grid; justify-items: center; text-align: center; gap: 18px; padding-top: calc(var(--name-size) * .78); }
.hero__name {
  position: absolute;
  top: 0;
  right: 3%;
  z-index: 3;
  margin: 0;
  animation: fly-in-left 720ms cubic-bezier(.16, 1.06, .3, 1) both;
  font-family: var(--font-title);
  font-weight: 700;
  font-size: var(--name-size);
  line-height: 1;
  letter-spacing: .02em;
  text-transform: uppercase;
  color: var(--paper);
  -webkit-text-stroke: 4px var(--line);
  paint-order: stroke fill;
}
/* The offset copies are real text layers, not text-shadow: WebKit on iOS casts the shadow from the
   stroke alone, which left the copies hollow. Painted black first, accent over it, name on top. */
.hero__name::before,
.hero__name::after {
  content: attr(data-name);
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}
.hero__name::before {
  color: var(--line);
  -webkit-text-stroke: 4px var(--line);
  transform: translate(12px, 12px);
}
.hero__name::after {
  color: var(--accent);
  -webkit-text-stroke: 4px var(--accent);
  transform: translate(6px, 6px);
}
/* City lights: a 30 s generated loop (scripts/lights.mjs), stretched over the background and
   blended in, so the page keeps a slow flicker without any heavy asset. */
.lights {
  position: fixed;
  inset: 0;
  z-index: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mix-blend-mode: screen;
  opacity: .9;
  filter: brightness(1.35) saturate(1.1);
  pointer-events: none;
}

/* The plate: white frame and picture on one layer, the coloured backing on its own just behind it.
   The wrapper owns the entrance flight. */
.hero__plate {
  position: relative;
  width: calc(100% - 28px);
  animation: fly-in-right 720ms cubic-bezier(.16, 1.06, .3, 1) both;
}
.hero__backing {
  position: absolute;
  inset: 0;
  z-index: -1;
  background: var(--accent);
  border: 4px solid var(--line);
  transform: translate(12px, 12px) rotate(-1.5deg);
}
.hero__photo {
  position: relative;
  margin: 0;
  padding: 10px;
  background: var(--paper);
  border: 4px solid var(--line);
  box-shadow: 0 20px 34px -22px rgb(0 0 0 / .75);
  transform: rotate(-1.5deg);
}
.hero__crop {
  display: block;
  overflow: hidden;
  border: 3px solid var(--line);
  background: var(--paper);
}
.hero__photo img {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  object-position: var(--hero-focus, 50% 50%);
  filter: contrast(1.12) saturate(1.25);
}
@media (min-width: 640px) { .hero__photo img { aspect-ratio: 3 / 1; } }

/* Email under the photo's bottom-left corner. */
/* Slides out from behind the photo panel once the panel has settled. */
.hero__mail {
  position: relative;
  z-index: 1;
  justify-self: start;
  margin: 38px 0 0 52px;
  animation: slide-from-under 650ms cubic-bezier(.16, 1, .3, 1) 680ms both;
  font: 600 16px/1 var(--font-body);
  letter-spacing: .04em;
  color: var(--ink);
  text-decoration: none;
  padding-bottom: 3px;
  border-bottom: 2px solid var(--accent);
}
.hero__mail:hover, .hero__mail:focus-visible { color: var(--accent-2); border-color: var(--accent-2); outline: none; }

/* Entrance: the name flies in from the left, the photo from the right, both easing to a stop;
   the email then slides down from under the photo. */
@keyframes fly-in-left {
  from { opacity: 0; transform: translate(-118%, var(--enter-name-y)); }
  to   { opacity: 1; transform: translate(0, 0); }
}
@keyframes fly-in-right {
  from { opacity: 0; transform: translate(118%, var(--enter-card-y)) rotate(var(--enter-card-rot)); }
  to   { opacity: 1; transform: translate(0, 0) rotate(-1.5deg); }
}
@keyframes slide-from-under {
  from { opacity: 0; transform: translateY(-48px); }
  to   { opacity: 1; transform: translateY(0); }
}

/* Family bar pinned to the bottom of the viewport: the other members. */
.family {
  position: fixed;
  isolation: isolate;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 5;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  padding: 12px 16px calc(12px + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--bg) 86%, transparent);
  backdrop-filter: blur(6px);
  border-top: 1px solid color-mix(in srgb, var(--ink) 18%, transparent);
}
/* Frosted glass, with the hovered person's own light glowing up through the dotted surface. */
.chip {
  position: relative;
  z-index: 1;
  padding: 10px 16px;
  font: 600 14px/1 var(--font-body);
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--ink);
  text-decoration: none;
  background: rgb(255 255 255 / .08);
  border: 1px solid rgb(255 255 255 / .28);
  border-radius: 4px;
  backdrop-filter: blur(12px) saturate(1.4);
  -webkit-backdrop-filter: blur(12px) saturate(1.4);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / .35), 0 8px 20px -14px rgb(0 0 0 / .9);
  transition: color .2s ease, border-color .2s ease, transform .2s ease;
}
/* the light itself */
.chip::before {
  content: "";
  position: absolute;
  z-index: -2;
  inset: -22px -30px;
  background: radial-gradient(closest-side, color-mix(in srgb, var(--chip-accent, var(--accent)) 85%, transparent), transparent 78%);
  filter: blur(8px);
  opacity: 0;
  transition: opacity .26s ease;
}
/* the dotted surface it shines through */
.chip::after {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -22px -30px;
  background-image: radial-gradient(circle, rgb(0 0 0 / .45) 1px, transparent 1.6px);
  background-size: 6px 6px;
  opacity: 0;
  transition: opacity .26s ease;
}
.chip:hover, .chip:focus-visible {
  color: #FFFFFF;
  border-color: color-mix(in srgb, var(--chip-accent, var(--accent)) 70%, transparent);
  transform: translateY(-1px);
  outline: none;
}
.chip:hover::before, .chip:focus-visible::before { opacity: .9; }
.chip:hover::after, .chip:focus-visible::after { opacity: .85; }

@media (prefers-reduced-motion: reduce) {
  .chip, .hero__mail { transition: none; }
  .lights { display: none; }
  .hero__name, .hero__plate, .hero__mail { animation: none; }
}
