/*
 * This is a manifest file that'll be compiled into application.css.
 *
 * With Propshaft, assets are served efficiently without preprocessing steps. You can still include
 * application-wide styles in this file, but keep in mind that CSS precedence will follow the standard
 * cascading order, meaning styles declared later in the document or manifest will override earlier ones,
 * depending on specificity.
 *
 * Consider organizing styles into separate files for maintainability.
 */

/*
  Plain custom properties, not `@theme`. Tailwind's input is
  app/assets/tailwind/application.css -- this file is never fed to the
  compiler, so an `@theme` block here reached the browser as an unknown
  at-rule and was dropped. `var(--font-body)` had nothing to resolve to.
*/
/*
  The look comes from friendlyrb.com: navy and red, Sora headings over Work
  Sans, handwritten eyebrows, and hard offset shadows in --accent (the
  edition's colour, set per gallery by gallery_accent). Interactive text stays
  navy or red-600: the brand red and yellow fail contrast as text.
*/
:root {
  --gap: 4px;
  --font-body: "Work Sans", ui-sans-serif, system-ui, sans-serif;
  --font-heading: "Sora", ui-sans-serif, system-ui, sans-serif;
  --font-handwriting: "Nanum Brush Script", cursive;
  --color-brand: #012B7F;
  --color-red: #FF3A36;
  --color-red-text: #dc2626;
  --color-yellow: #FFC53D;
  --color-muted: #4b5563;
  --accent: var(--color-red);
}

/* In-page anchors clear the sticky nav and, as on friendlyrb.com, scroll
   smoothly. On the root, not on each target: Turbo's same-page anchor
   scroll ignored the sections' own scroll-margin. */
html { scroll-padding-top: 4.5rem; }
@media (prefers-reduced-motion: no-preference) { html { scroll-behavior: smooth; } }

body {
  font-family: var(--font-body);
  background: #fff;
  color: #1f2937;
  margin: 0;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: var(--font-heading); font-weight: 700; color: var(--color-brand); letter-spacing: -0.02em; }

:focus-visible { outline: 3px solid var(--color-red); outline-offset: 2px; }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}

.skip-link {
  position: absolute; left: 1rem; top: -4rem; z-index: 50;
  background: var(--color-brand); color: #fff; font-weight: 600;
  padding: 0.75rem 1.5rem; border-radius: 999px; text-decoration: none;
}
.skip-link:focus { top: 1rem; }

/*
  The friendlyrb.com nav (_tailwind.css .site-nav-*): a card that sticks to the
  top. It sits flush until the page scrolls, then narrows and lifts with its
  border and hard shadow. --accent is the gallery's edition colour.
*/
.site-nav { position: sticky; top: 0; z-index: 40; padding: 0.75rem 0.75rem 0; pointer-events: none; }
@media (min-width: 40rem) { .site-nav { padding: 0.75rem 1.5rem 0; } }
.site-nav-card {
  pointer-events: auto;
  max-width: 72rem; margin: 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; column-gap: 0.5rem;
  padding-left: 0.75rem;
  background: #fff; border: 2px solid transparent; border-radius: 1rem;
  transition: max-width 350ms cubic-bezier(0.22, 1, 0.36, 1), border-color 200ms ease, box-shadow 200ms ease, translate 200ms ease;
}
.site-nav.is-stuck .site-nav-card {
  max-width: 64rem;
  border-color: var(--color-brand);
  box-shadow: 4px 4px 0 var(--accent);
  translate: -2px -2px;
}
.site-nav-home {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 3.5rem; flex-shrink: 0;
  font-family: var(--font-heading); font-weight: 700; font-size: 1.25rem;
  color: var(--color-brand); text-decoration: none; white-space: nowrap; border-radius: 0.5rem;
}
.site-nav-photos { color: var(--color-red-text); }
.site-nav-logo { width: 2.5rem; height: 2rem; flex-shrink: 0; transition: rotate 260ms cubic-bezier(0.34, 1.56, 0.64, 1); }
.site-nav-home:hover .site-nav-logo { rotate: -8deg; }
.site-nav-links {
  list-style: none; margin: 0 0 0 auto; padding: 0 0.75rem 0 0;
  display: flex; align-items: center; gap: 0.25rem; min-width: 0;
  overflow-x: auto; scrollbar-width: none;
}
.site-nav-links::-webkit-scrollbar { display: none; }
.site-nav-links > li { flex-shrink: 0; }
.site-nav-link {
  position: relative; display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 0.75rem;
  border-radius: 0.5rem; white-space: nowrap; text-decoration: none;
  font-weight: 600; font-size: 0.9375rem; color: rgb(1 43 127 / 0.7); transition: color 150ms ease;
}
.site-nav-link:hover, .site-nav-link[aria-current] { color: var(--color-brand); }
/* The pixel marker under the link, as on friendlyrb.com. */
.site-nav-link::after {
  content: ""; position: absolute; left: 50%; bottom: 0.3rem;
  width: 6px; height: 6px; margin-left: -3px;
  background: var(--accent); box-shadow: 1px 1px 0 var(--color-brand);
  scale: 0; transition: scale 260ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.site-nav-link:hover::after { scale: 0.6; }
.site-nav-link[aria-current]::after { scale: 1; }
.site-nav-divider { width: 2px; height: 1.25rem; margin: 0 0.5rem; background: rgb(1 43 127 / 0.15); }
.site-nav-toggle {
  margin: 0 0.5rem 0 auto; display: inline-flex; align-items: center; gap: 0.5rem; min-height: 2.75rem; padding: 0 0.75rem;
  border: 0; border-radius: 0.5rem; background: none; cursor: pointer;
  font: inherit; font-weight: 600; font-size: 0.9375rem; color: var(--color-brand);
}
.site-nav-toggle[hidden] { display: none; }
.site-nav-toggle-icon { width: 1.25rem; height: 1.25rem; }
.site-nav-toggle-icon .menu-bar {
  transform-box: fill-box; transform-origin: center;
  transition: translate 220ms cubic-bezier(0.22, 1, 0.36, 1), rotate 220ms cubic-bezier(0.22, 1, 0.36, 1), scale 150ms ease;
}
.site-nav-toggle[aria-expanded="true"] .menu-bar-top { translate: 0 5.5px; rotate: 45deg; }
.site-nav-toggle[aria-expanded="true"] .menu-bar-middle { scale: 0 1; }
.site-nav-toggle[aria-expanded="true"] .menu-bar-bottom { translate: 0 -5.5px; rotate: -45deg; }
@media (max-width: 23rem) { .site-nav-toggle-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0, 0, 0, 0); } }

@media (min-width: 64rem) {
  .site-nav-card { flex-wrap: nowrap; column-gap: 1.5rem; padding: 0 1rem; }
  .site-nav-toggle, .site-nav-toggle:not([hidden]) { display: none; }
  .site-nav-links { padding-right: 0; }
}

/* Small screens: without JS the links scroll sideways and fade at the edge.
   With JS (.has-menu) they hide behind Menu and open as a list in the card. */
@media (max-width: 63.999rem) {
  .site-nav-links { mask-image: linear-gradient(to right, black calc(100% - 2.5rem), transparent); }
  .site-nav.has-menu .site-nav-links { display: none; }
  .site-nav.is-open .site-nav-card { border-color: var(--color-brand); box-shadow: 4px 4px 0 var(--accent); }
  .site-nav.is-open .site-nav-links {
    display: flex; flex-basis: 100%; flex-direction: column; align-items: stretch; gap: 0;
    max-height: calc(100dvh - 6rem); margin: 0 0.75rem 0 0; padding: 0.5rem 0 0.75rem;
    border-top: 2px solid rgb(1 43 127 / 0.1); overflow-y: auto; mask-image: none;
  }
  .site-nav.is-open .site-nav-link { display: flex; min-height: 3rem; font-size: 1.0625rem; }
  .site-nav.is-open .site-nav-link::after { left: 0; top: 50%; bottom: auto; margin: -3px 0 0 0; }
  .site-nav.is-open .site-nav-divider { width: auto; height: 2px; margin: 0.375rem 0.75rem; }
  .site-nav.is-open .site-nav-links > li {
    transition: opacity 200ms ease, translate 260ms cubic-bezier(0.22, 1, 0.36, 1);
    transition-delay: calc(var(--i, 0) * 25ms);
    @starting-style { opacity: 0; translate: 0 -0.5rem; }
  }
}

main:focus { outline: none; }

/* Footer: the embroidered ribbon, then black, as on friendlyrb.com. */
.ribbon {
  height: 46px; margin-top: 4rem;
  background: #fff url("/assets/ribbon-7bf4067a.svg") repeat-x center / auto 46px;
  image-rendering: pixelated;
}
@media (min-width: 48rem) { .ribbon { height: 69px; background-size: auto 69px; } }
/* Between a hero and the content below it, as on friendlyrb.com. */
.ribbon--divider { margin-top: 0; }

/*
  The band behind a hero, full width: friendlyrb.com's faint pixel grid,
  fading out from the middle. isolate keeps the grid behind the hero's
  content without slipping under the page.
*/
.hero-band { position: relative; isolation: isolate; overflow: hidden; padding-bottom: 3.5rem; }
.hero-grid {
  position: absolute; inset: 0; z-index: -1; pointer-events: none;
  background-image:
    linear-gradient(to right, rgb(1 43 127 / 0.06) 1px, transparent 1px),
    linear-gradient(to bottom, rgb(1 43 127 / 0.06) 1px, transparent 1px);
  background-size: 32px 32px;
  background-position: center top;
  mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, black 20%, transparent 75%);
}
.site-footer { background: #000; color: #bfdbfe; padding: 4rem 1.5rem 2.5rem; }
.site-footer__inner { max-width: 72rem; margin: 0 auto; }
.site-footer__grid { display: grid; gap: 3rem; }
@media (min-width: 40rem) { .site-footer__grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 64rem) { .site-footer__grid { grid-template-columns: 1.6fr 1fr 1fr 1fr; } }
.site-footer ul { list-style: none; margin: 0; padding: 0; }
.site-footer h2 {
  margin: 0 0 0.5rem; color: #fff; font-family: var(--font-heading); font-size: 0.875rem;
  font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
.site-footer a { color: #bfdbfe; text-underline-offset: 4px; transition: color 150ms ease; }
.site-footer a:hover { color: #fff; }
.site-footer__grid li > a { display: inline-flex; align-items: center; min-height: 2.75rem; text-decoration: none; }
.site-footer__grid li > a:hover { text-decoration: underline; }
.site-footer__home {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 2.75rem;
  font-family: var(--font-heading); font-weight: 700; font-size: 1.25rem; color: #fff !important; text-decoration: none;
}
.site-footer__about { max-width: 20rem; margin: 1rem 0 0; font-size: 0.875rem; line-height: 1.6; }
.site-footer__social { display: flex; flex-wrap: wrap; gap: 0.75rem; margin-top: 1.5rem !important; }
.site-footer__social a {
  justify-content: center; width: 2.75rem; height: 2.75rem; border-radius: 999px;
  background: rgb(255 255 255 / 0.1); color: #dbeafe; transition: background-color 150ms ease, color 150ms ease;
}
.site-footer__social a:hover { background: var(--color-red-text); color: #fff; text-decoration: none; }
.site-footer__icon { width: 1.25rem; height: 1.25rem; }
.site-footer__bottom {
  margin-top: 3rem; padding-top: 2rem; border-top: 1px solid rgb(255 255 255 / 0.15);
  display: flex; flex-direction: column; gap: 1rem; font-size: 0.875rem;
}
.site-footer__bottom p { margin: 0; }
.site-footer__bottom a { text-decoration: underline; }
@media (min-width: 48rem) { .site-footer__bottom { flex-direction: row; align-items: center; justify-content: space-between; } }

/* Flash messages: cards in the page column under the nav, with the nav's
   pixel marker. Yellow for a notice, red for an alert. */
.flash-stack {
  max-width: 72rem; margin: 1rem auto 0; padding: 0 0.75rem;
  display: grid; gap: 0.75rem;
}
@media (min-width: 40rem) { .flash-stack { padding: 0 1.5rem; } }
@media (min-width: 75rem) { .flash-stack { padding: 0; } }
.flash {
  --flash-accent: var(--color-yellow);
  display: flex; align-items: center; gap: 0.875rem;
  padding: 0.25rem 0.25rem 0.25rem 1.25rem;
  background: #fff; color: var(--color-brand);
  border: 2px solid var(--color-brand); border-radius: 1rem;
  box-shadow: 4px 4px 0 var(--flash-accent);
  transition: opacity 200ms ease, translate 200ms ease;
  animation: flash-in 300ms cubic-bezier(0.34, 1.56, 0.64, 1);
}
.flash--alert { --flash-accent: var(--color-red); }
.flash.is-leaving { opacity: 0; translate: 0 -0.5rem; }
.flash__pixel {
  flex-shrink: 0; width: 10px; height: 10px;
  background: var(--flash-accent); box-shadow: 2px 2px 0 var(--color-brand);
}
.flash__message { flex: 1; margin: 0.5rem 0; font-weight: 600; line-height: 1.4; }
.flash__close {
  flex-shrink: 0; display: grid; place-items: center; width: 2.75rem; height: 2.75rem;
  border: 0; border-radius: 0.75rem; background: none; cursor: pointer;
  color: rgb(1 43 127 / 0.7); font-size: 1.5rem; line-height: 1;
  transition: color 150ms ease, background-color 150ms ease;
}
.flash__close:hover { color: var(--color-brand); background: rgb(1 43 127 / 0.06); }
@keyframes flash-in { from { opacity: 0; translate: 0 -0.5rem; } }

/* Back to top, as on friendlyrb.com. */
.back-to-top {
  position: fixed; right: 1.25rem; bottom: 1.25rem; z-index: 40;
  display: flex; align-items: center; justify-content: center; width: 3rem; height: 3rem;
  border: 0; border-radius: 999px; background: var(--color-brand); color: #fff; cursor: pointer;
  box-shadow: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  opacity: 0; visibility: hidden; transform: translateY(1rem);
  transition: opacity 200ms ease, transform 200ms ease, visibility 200ms, background-color 150ms ease;
}
.back-to-top.is-visible { opacity: 1; visibility: visible; transform: none; }
/* Tailwind's red-500, as on friendlyrb.com. An icon, not text, so 3:1 is the bar. */
.back-to-top:hover { background: #fb2c36; }
.back-to-top__icon { width: 1.5rem; height: 1.5rem; }

/*
  The justified wall.

  Each tile's flex-basis is its aspect ratio times the target row height, so the
  free space in a row distributes proportionally to the same ratio and every
  tile resolves to the same height. Rows justify flush, nothing is cropped, and
  because --r comes from stored dimensions the space is reserved before a single
  image byte arrives.

  The non-zero basis is load-bearing. `flex: var(--r) 1 0` -- the version most
  articles show -- never wraps, because a zero basis can never exceed the
  container, so every photo lands on one row.
*/
.wall {
  display: flex;
  flex-wrap: wrap;
  gap: var(--gap);
  --h: 240px;
}

.tile {
  flex: var(--r) 1 calc(var(--r) * var(--h));
  aspect-ratio: var(--r);
  display: block;
  overflow: hidden;
  border-radius: 4px;
  position: relative;
}
.tile img { transition: scale 400ms cubic-bezier(0.22, 1, 0.36, 1); }
.tile:hover img { scale: 1.04; }

.tile img,
.tile picture { width: 100%; height: 100%; display: block; object-fit: cover; }

.tile-spacer { flex-grow: 1e4; height: 0; }

@media (max-width: 1200px) { .wall { --h: 200px; } }
@media (max-width: 600px)  { .wall { --h: 150px; } }

.wall-placeholder { min-height: 200px; }

/*
  Polaroids, as on friendlyrb.com's heroes: a white card with a handwritten
  caption, tossed onto the page and swaying a little. Floating things keep
  soft shadows there, so these do too.
*/
.polaroid-card {
  position: relative; display: block; padding: 0.6rem 0.6rem 0;
  background: #fff; border-radius: 4px; color: var(--color-brand); text-decoration: none;
  box-shadow: 0 1px 2px rgb(1 43 127 / 0.12), 0 10px 24px -6px rgb(1 43 127 / 0.28);
  transition: scale 300ms cubic-bezier(0.34, 1.56, 0.64, 1), translate 300ms ease, box-shadow 300ms ease;
}
.polaroid-photo { display: block; aspect-ratio: 1; overflow: hidden; border-radius: 2px; }
.polaroid-photo picture, .polaroid-photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.polaroid-caption {
  display: block; padding: 0.4rem 0.25rem 0.65rem; text-align: center;
  font-family: var(--font-handwriting); font-size: 1.6rem; line-height: 1;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* A strip of tape in the edition's colour, holding the photo down. */
.polaroid-tape {
  position: absolute; top: -0.75rem; left: 50%; z-index: 1;
  width: 5.5rem; height: 1.6rem; translate: -50% 0; rotate: 4deg;
  background: color-mix(in srgb, var(--accent) 75%, transparent);
  pointer-events: none;
}
.polaroid-toss {
  animation: hero-toss 800ms cubic-bezier(0.34, 1.3, 0.64, 1) calc(var(--toss-start, 0.35s) + var(--i) * 110ms) backwards;
}
@keyframes hero-toss {
  from { opacity: 0; transform: translateY(-60px) scale(1.25) rotate(calc(var(--tilt) * -3)); }
}
@keyframes hero-sway {
  0%, 100% { transform: rotate(0deg); }
  50% { transform: rotate(2deg); }
}

/*
  The year drawn in the logo's pixels (EditionHelper#pixel_year), built pixel
  by pixel, column by column, in the edition's colour.
*/
.pixel-year { overflow: visible; }
.pixel-year .pixel-face { fill: var(--accent); }
.pixel-year .pixel-shadow { fill: var(--color-brand); }
.pixel-year .pixel-bit {
  transform-box: fill-box; transform-origin: center;
  animation: pixel-drop 650ms cubic-bezier(0.34, 1.45, 0.64, 1) calc(150ms + var(--c) * 30ms + var(--r) * 12ms) backwards;
}
@keyframes pixel-drop {
  0% { opacity: 0; transform: translate(calc(var(--dx) * 1px), -9px) rotate(calc(var(--dx) * 40deg)) scale(0.4); }
  40% { opacity: 1; }
}

/*
  Edition hero (gallery and section pages), after friendlyrb.com's edition
  pages: the label, the name, the year in pixels, then three tossed polaroids.
*/
.edition-hero {
  max-width: 74rem; margin: 0 auto; padding: 2.5rem 1rem 0;
  display: grid; gap: 2.5rem; align-items: center; overflow-x: clip;
}
@media (min-width: 64rem) { .edition-hero { grid-template-columns: 1fr 1fr; gap: 3rem; padding-top: 3rem; } }
.edition-hero__title { margin: 0; font-size: clamp(2.5rem, 6vw, 3.75rem); line-height: 1; }
.edition-hero__name { display: block; }
.edition-hero__year { display: block; width: auto; height: clamp(4.25rem, 12vw, 7.5rem); margin-top: 0.85rem; }
.edition-hero__meta { margin: 1.75rem 0 0; font-size: 1.125rem; color: var(--color-muted); }
.edition-hero__description { margin: 0.75rem 0 0; max-width: 36rem; line-height: 1.6; color: var(--color-muted); }

.edition-hero__polaroids { position: relative; height: 21rem; margin: 0; padding: 0; list-style: none; }
@media (min-width: 40rem) { .edition-hero__polaroids { height: 25rem; } }
.edition-polaroid { position: absolute; width: 10.5rem; }
@media (min-width: 40rem) { .edition-polaroid { width: 13rem; } }
/* One sway after the toss lands, done within five seconds of load: there is
   no pause control on these pages, so nothing may keep moving (WCAG 2.2.2). */
.edition-polaroid .polaroid-card { rotate: var(--tilt); animation: hero-sway 3s ease-in-out calc(1.4s + var(--i) * 0.15s) 1; }
.edition-polaroid:hover, .edition-polaroid:focus-within { z-index: 10; }
.edition-polaroid:hover .polaroid-card, .edition-polaroid:focus-within .polaroid-card {
  scale: 1.05; translate: 0 -6px;
  box-shadow: 0 2px 4px rgb(1 43 127 / 0.14), 0 22px 40px -10px rgb(1 43 127 / 0.35);
}
.edition-polaroid--0 { z-index: 3; left: 50%; top: 50%; translate: -50% -50%; width: 12.5rem; }
@media (min-width: 40rem) { .edition-polaroid--0 { width: 15.5rem; } }
.edition-polaroid--1 { z-index: 2; left: 2%; top: 0; }
.edition-polaroid--2 { z-index: 1; right: 2%; bottom: 0; }

.gallery-section h2 a { color: inherit; text-decoration: none; }
.gallery-section h2 a:hover { text-decoration: underline; text-decoration-color: var(--color-red); text-underline-offset: 6px; }

/* 74rem is the 72rem column plus its gutters, so the wall lines up with the
   cover and the nav above it. */
.gallery-section { max-width: 74rem; margin: 0 auto; padding: 2.5rem 1rem 0; }
.gallery-section h2 { font-size: clamp(1.75rem, 4vw, 2.5rem); margin: 0 0 0.25rem; }
.section-description { color: var(--color-muted); margin: 0 0 1.25rem; max-width: 42rem; }

/*
  Index hero: the title and a link per edition beside a pile of polaroids
  that deals itself (deck controller). --px/--py come from the parallax
  controller; the pile and the loose pixels drift by their own depth.
*/
.eyebrow { font-family: var(--font-handwriting); font-size: 2rem; line-height: 1; color: var(--color-red-text); margin: 0 0 0.5rem; }
.index-hero {
  --px: 0; --py: 0;
  max-width: 74rem; margin: 0 auto; padding: 2.5rem 1rem 0;
  display: grid; gap: 1.5rem; align-items: center; overflow-x: clip;
}
@media (min-width: 64rem) { .index-hero { grid-template-columns: 1fr 1fr; gap: 3rem; padding-top: 3.5rem; } }
.index-hero__title { margin: 0; font-size: clamp(2.75rem, 7vw, 4.5rem); line-height: 1.02; }
.index-hero__lede { margin: 1.25rem 0 0; max-width: 34rem; font-size: 1.125rem; line-height: 1.6; color: var(--color-muted); }

/* One link per edition, shadowed in its colour, as the cards below are. */
.edition-links { display: flex; flex-wrap: wrap; gap: 0.875rem; margin: 2rem 0 0; padding: 0; list-style: none; }
.edition-link {
  display: inline-flex; align-items: center; min-height: 3rem; padding: 0 1.5rem;
  background: #fff; border: 2px solid var(--color-brand); border-radius: 999px;
  font-family: var(--font-heading); font-size: 1.125rem; font-weight: 700; color: var(--color-brand); text-decoration: none;
  box-shadow: 3px 3px 0 var(--accent); transition: translate 200ms ease, box-shadow 200ms ease;
}
.edition-link:hover { translate: -2px -2px; box-shadow: 5px 5px 0 var(--accent); }

.deck { position: relative; display: flex; flex-direction: column; align-items: center; gap: 1.5rem; padding: 1.5rem 0 0.5rem; }
.deck__pile {
  --w: 14.5rem;
  position: relative; width: var(--w); height: calc(var(--w) + 3.1rem);
  margin: 0; padding: 0; list-style: none;
  translate: calc(var(--px) * -10px) calc(var(--py) * -10px);
  transition: translate 900ms cubic-bezier(0.22, 1, 0.36, 1);
}
@media (min-width: 40rem) { .deck__pile { --w: 17.5rem; } }
.deck__card {
  position: absolute; top: 0; left: 0; width: 100%;
  z-index: var(--z, 1);
  transform: translate(var(--x), var(--y)) rotate(var(--tilt));
  opacity: 0; transition: opacity 450ms ease;
}
.deck__card[data-depth="0"], .deck__card[data-depth="1"],
.deck__card[data-depth="2"], .deck__card[data-depth="3"] { opacity: 1; }
/* Only the photo on top is taped down; tape on every card piles into a smear. */
.deck__card .polaroid-tape { opacity: 0; transition: opacity 300ms ease; }
.deck__card[data-depth="0"]:not(.is-dealt) .polaroid-tape { opacity: 1; }
.deck__card .polaroid-card { animation: hero-toss 800ms cubic-bezier(0.34, 1.3, 0.64, 1) calc(0.35s + var(--i) * 110ms) backwards; }
.deck__card[data-depth="0"]:hover .polaroid-card,
.deck__card[data-depth="0"]:focus-within .polaroid-card {
  scale: 1.03; translate: 0 -6px;
  box-shadow: 0 2px 4px rgb(1 43 127 / 0.14), 0 22px 40px -10px rgb(1 43 127 / 0.35);
}
/* Dealt: off to the side, then tucked under the pile. z-index steps down
   halfway, while the card is clear of the others. */
.deck__card.is-dealt { animation: deck-deal 950ms cubic-bezier(0.45, 0.05, 0.3, 1); }
@keyframes deck-deal {
  0% { z-index: 50; }
  45% { z-index: 50; transform: translate(calc(var(--x) + 105%), calc(var(--y) - 6%)) rotate(calc(var(--tilt) + 12deg)); }
  55% { z-index: 0; }
  100% { z-index: 0; transform: translate(var(--x), var(--y)) rotate(var(--tilt)); }
}
.deck__toggle {
  position: relative; z-index: 1; display: inline-flex; align-items: center; min-height: 2.75rem; padding: 0 1.1rem;
  background: #fff; border: 2px solid var(--color-brand); border-radius: 999px; cursor: pointer;
  font: inherit; font-size: 0.9375rem; font-weight: 600; color: var(--color-brand);
}
.deck__toggle:hover { background: rgb(1 43 127 / 0.06); }
.deck__toggle[hidden] { display: none; }
.deck__toggle-play, .deck.is-paused .deck__toggle-pause { display: none; }
.deck.is-paused .deck__toggle-play { display: inline; }
/* Loose pixels around the pile, as around friendlyrb.com's ruby. */
.deck-pixel {
  position: absolute; left: var(--x); top: var(--y); width: 12px; height: 12px; background: var(--color);
  translate: calc(var(--px) * var(--depth) * -1px) calc(var(--py) * var(--depth) * -1px);
  transition: translate 900ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* They float only while the deck is dealing (.is-live, set by the deck
   controller), so the Pause button stops them too, and a deck too small to
   deal -- or without JS -- has nothing moving and needs no control. */
.deck.is-live:not(.is-paused) .deck-pixel {
  animation: hero-float calc(5s + var(--i) * 0.6s) ease-in-out calc(var(--i) * -0.9s) infinite;
}
.deck-pixel:nth-of-type(even) { width: 9px; height: 9px; }
@keyframes hero-float {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50% { transform: translateY(-14px) rotate(12deg); }
}

/*
  The editions trail, after friendlyrb.com's homepage: dotted paper, a dashed
  path, a stop per edition in its colour, the year in pixels, its numbers as
  inked stamps, and taped snapshots that straighten when pointed at. Nothing
  here moves on its own; the hero's deck is the page's one animated moment.
*/
.trail-band {
  padding: 4.5rem 1.25rem 5rem;
  background-color: #f9fafb;
  background-image: radial-gradient(rgb(1 43 127 / 0.07) 1px, transparent 1px);
  background-size: 18px 18px;
}
.trail-header { max-width: 40rem; margin: 0 auto 4rem; text-align: center; }
.trail-header h2 { margin: 0; font-size: clamp(2.25rem, 5vw, 3rem); line-height: 1.1; }
.trail-header p { margin: 0.75rem 0 0; font-size: 1.125rem; color: var(--color-muted); }

.gallery-index {
  position: relative; max-width: 72rem; margin: 0 auto; padding: 0; list-style: none;
  display: grid; gap: 5rem;
}
/* The dashed path, down the left edge on phones and the middle from 48rem. */
.gallery-index::before {
  content: ""; position: absolute; top: 0.5rem; bottom: -4.5rem; left: 10px; width: 3px;
  background: repeating-linear-gradient(to bottom, var(--color-brand) 0 10px, transparent 10px 20px);
}
.trail-stop { position: relative; display: grid; gap: 2.5rem; align-items: center; padding-left: 3rem; }
.trail-stop__marker {
  position: absolute; left: 0; top: 0.75rem; width: 1.5rem; height: 1.5rem;
  background: var(--accent); border: 3px solid var(--color-brand); box-shadow: 0 0 0 8px #f9fafb;
}
@media (min-width: 48rem) {
  .gallery-index { gap: 7rem; }
  .gallery-index::before { left: 50%; translate: -50% 0; }
  .trail-stop { grid-template-columns: 1fr 1fr; gap: 7rem; padding-left: 0; }
  .trail-stop__marker { left: 50%; top: 50%; translate: -50% -50%; }
  /* Alternate sides: text on the right, then on the left, aligned to the path. */
  .trail-stop--text-right .trail-stop__text { order: 2; }
  .trail-stop--text-left .trail-stop__text { text-align: right; }
  .trail-stop--text-left .trail-stop__year { margin-left: auto; }
  .trail-stop--text-left .trail-stamps,
  .trail-stop--text-left .trail-sections { justify-content: flex-end; }
}

.trail-stop__year { display: block; width: auto; height: 3.5rem; }
@media (min-width: 48rem) { .trail-stop__year { height: 5rem; } }
.pixel-year.pixel-static .pixel-bit { animation: none; }
.trail-stop__title { margin: 1.25rem 0 0; font-size: clamp(1.75rem, 3.5vw, 2.25rem); line-height: 1.15; }
/* A 44px target: the card used to be the link, so this one must be easy to hit. */
.trail-stop__title a { display: inline-flex; align-items: center; min-height: 2.75rem; color: inherit; text-decoration: none; }
.trail-stop__title a:hover { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 3px; text-underline-offset: 6px; }

/* The numbers, inked like passport stamps (friendlyrb.com's .stamp). */
.trail-stamps { display: flex; flex-wrap: wrap; gap: 0.75rem; margin: 1.25rem 0 0; padding: 0; list-style: none; }
.stamp { padding: 2px; color: var(--color-brand); background: rgb(255 255 255 / 0.7); border: 2px solid currentColor; border-radius: 0.5rem; rotate: -2deg; }
.stamp--red { color: var(--color-red-text); rotate: 1.5deg; }
.stamp-inner {
  display: flex; align-items: baseline; gap: 0.375rem; padding: 0.3rem 0.75rem;
  border: 1px dashed currentColor; border-radius: 0.3rem;
  font-size: 0.875rem; font-weight: 600; line-height: 1.2;
}
.stamp-inner strong { font-family: var(--font-heading); font-size: 1.25rem; }

/* One link per section, each with its photo count. */
.trail-sections { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 1.5rem 0 0; padding: 0; list-style: none; }
.trail-section {
  display: inline-flex; align-items: center; gap: 0.5rem; min-height: 2.75rem; padding: 0 0.5rem 0 1rem;
  background: #fff; border: 2px solid var(--color-brand); border-radius: 999px;
  font-weight: 600; font-size: 0.9375rem; color: var(--color-brand); text-decoration: none;
  transition: translate 200ms ease, box-shadow 200ms ease;
}
.trail-section:hover { translate: -2px -2px; box-shadow: 3px 3px 0 var(--accent); }
.trail-section__count {
  display: inline-grid; place-items: center; min-width: 1.75rem; height: 1.75rem; padding: 0 0.4rem;
  border-radius: 999px; background: rgb(1 43 127 / 0.08); font-size: 0.8125rem;
}

/* friendlyrb.com's "Explore" button: navy on a ledge in the edition's colour. */
.trail-cta {
  display: inline-flex; align-items: center; min-height: 3rem; margin-top: 1.75rem; padding: 0 1.75rem;
  background: var(--color-brand); border-radius: 999px; color: #fff; font-weight: 700; text-decoration: none;
  box-shadow: 0 4px 0 var(--accent); transition: translate 150ms ease, box-shadow 150ms ease;
}
.trail-cta:hover { translate: 0 -2px; box-shadow: 0 6px 0 var(--accent); }
.trail-cta:active { translate: 0 4px; box-shadow: none; }

/* Three taped snapshots: the cover in front with its caption, two behind. */
.trail-snapshots { position: relative; display: block; width: 100%; max-width: 32rem; aspect-ratio: 5 / 4; margin: 0 auto; }
.trail-snapshot { position: absolute; }
/* The cover stays in front, caption and all; hover brings any one forward. */
.trail-snapshot--0 { left: 3%; top: 6%; width: 56%; z-index: 3; }
.trail-snapshot--1 { right: 2%; top: 0; width: 44%; z-index: 1; }
.trail-snapshot--2 { right: 8%; bottom: 2%; width: 44%; z-index: 2; }
.trail-snapshot:hover { z-index: 10; }
.trail-snapshot__frame {
  position: relative; display: block; padding: 0.5rem 0.5rem 1.25rem; background: #fff; rotate: var(--tilt);
  box-shadow: 0 1px 2px rgb(1 43 127 / 0.12), 0 10px 24px -6px rgb(1 43 127 / 0.28);
  transition: rotate 300ms cubic-bezier(0.34, 1.56, 0.64, 1), translate 300ms ease;
}
.trail-snapshot--0 .trail-snapshot__frame { padding-bottom: 0; }
.trail-snapshot:hover .trail-snapshot__frame { rotate: 0deg; translate: 0 -4px; }
.trail-snapshot__photo { display: block; aspect-ratio: 1; overflow: hidden; }
.trail-snapshot__photo picture, .trail-snapshot__photo img { display: block; width: 100%; height: 100%; object-fit: cover; }
.trail-snapshot__caption {
  display: block; padding: 0.5rem 0.25rem 0.6rem; text-align: center; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-family: var(--font-handwriting); font-size: 1.5rem; line-height: 1; color: var(--color-brand);
}

/* The end of the trail, as on friendlyrb.com. */
.trail-end { position: relative; display: flex; align-items: center; gap: 1rem; max-width: 72rem; margin: 5rem auto 0; padding-left: 0; }
.trail-end__badge {
  display: grid; place-items: center; flex-shrink: 0; width: 3.5rem; height: 3.5rem; margin-left: -1rem;
  background: #fff; border: 2px solid var(--color-brand); border-radius: 50%; box-shadow: 0 0 0 8px #f9fafb;
}
.trail-end__logo { width: 2rem; height: 1.5rem; }
.trail-end p { margin: 0; font-family: var(--font-handwriting); font-size: 1.875rem; line-height: 1; color: var(--color-red-text); rotate: -2deg; }
@media (min-width: 48rem) {
  .gallery-index::before { bottom: -7rem; }
  .trail-end { flex-direction: column; margin-top: 7rem; text-align: center; }
  .trail-end__badge { margin-left: 0; }
}
.credit { text-align: center; color: var(--color-muted); padding: 3rem 1rem 0; }
.credit::before { content: "Snapped with love"; display: block; font-family: var(--font-handwriting); font-size: 1.75rem; color: var(--color-red-text); }
.empty { text-align: center; color: var(--color-muted); padding: 3rem; }

/* Pagination -- real links, so they work without JavaScript. */
.pagination { display: flex; gap: 0.5rem; justify-content: center; padding: 2rem; }
.pagination { flex-wrap: wrap; }
.pagination a {
  display: inline-grid; place-items: center; min-width: 2.75rem; min-height: 2.75rem;
  border: 2px solid var(--color-brand); border-radius: 0.75rem;
  font-weight: 600; text-decoration: none; color: var(--color-brand);
}
.pagination a:hover { box-shadow: 3px 3px 0 var(--accent); translate: -1px -1px; }
.pagination a[aria-current="page"] { background: var(--color-brand); color: #fff; box-shadow: 3px 3px 0 var(--accent); }

/* Lightbox */
.lightbox { border: 0; padding: 0; max-width: 100vw; max-height: 100vh; width: 100vw; height: 100vh; background: #0b0f1a; color: #fff; }
.lightbox::backdrop { background: rgb(0 0 0 / 0.9); }
.lightbox__figure { margin: 0; height: 100%; display: grid; place-items: center; }
/* Placeholder and photo share one grid cell, so the colour block sits exactly
   where the photo lands and a slow load is a rectangle, not a hole. */
.lightbox__figure > * { grid-area: 1 / 1; }
.lightbox__placeholder { display: block; width: min(96vw, calc(86vh * var(--r, 1.5)));
  aspect-ratio: var(--r, 1.5); border-radius: 2px; }
.lightbox__figure.is-loading img { visibility: hidden; }
.lightbox__figure:not(.is-loading) .lightbox__placeholder { display: none; }
.lightbox__figure img { max-width: 96vw; max-height: 86vh; object-fit: contain; border-radius: 0.5rem; }
.lightbox__bar { position: absolute; bottom: 0; left: 0; right: 0; display: flex; align-items: center;
  justify-content: space-between; gap: 1rem; padding: 1rem; color: #fff; flex-wrap: wrap; }
.lightbox__counter { font-variant-numeric: tabular-nums; opacity: 0.8; }
.lightbox__actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.btn { display: inline-flex; align-items: center; justify-content: center; min-height: 2.75rem;
  background: rgb(255 255 255 / 0.12); color: #fff; border: 0; border-radius: 999px;
  padding: 0 1.1rem; font: inherit; font-weight: 600; font-size: 0.9375rem; cursor: pointer; text-decoration: none;
  transition: background-color 150ms ease; }
.btn:hover { background: var(--color-red-text); }
.btn--close { font-size: 1.5rem; line-height: 1; width: 2.75rem; padding: 0; }
.lightbox__nav { position: absolute; top: 50%; transform: translateY(-50%); background: rgb(255 255 255 / 0.12);
  color: #fff; border: 0; border-radius: 999px; font-size: 2rem; line-height: 1; width: 3rem; height: 3rem; cursor: pointer;
  transition: background-color 150ms ease; }
.lightbox__nav:hover { background: var(--color-red-text); }
.lightbox__nav--prev { left: 1rem; }
.lightbox__nav--next { right: 1rem; }
.share-fallback { display: block; width: 100%; margin-top: 0.5rem; padding: 0.5rem; }

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

.admin-warning {
  margin: 0;
  padding: 0.9rem 1.25rem;
  background: var(--color-yellow);
  color: var(--color-brand);
  border-bottom: 2px solid var(--color-brand);
  font-size: 0.9rem;
  line-height: 1.4;
}

/* Sign in */
.signin {
  max-width: 24rem; margin: 5rem auto; padding: 2rem 1.75rem;
  border: 2px solid var(--color-brand); border-radius: 1.5rem; box-shadow: 6px 6px 0 var(--color-red);
}
@media (max-width: 440px) { .signin { margin: 3rem 1rem; } }
.signin h1 { font-family: var(--font-heading); font-size: 1.875rem; margin: 0 0 1.5rem; }
.signin__field { display: block; margin-bottom: 1.1rem; }
.signin__field span { display: block; font-weight: 600; margin-bottom: 0.35rem; font-size: 0.9rem; }
.signin__field input {
  width: 100%;
  padding: 0.65rem 0.75rem;
  font: inherit;
  border: 2px solid #d1d5db;
  border-radius: 0.75rem;
  box-sizing: border-box;
}
.signin__field input:focus-visible { outline: 2px solid var(--color-brand); outline-offset: 1px; border-color: var(--color-brand); }
.signin__remember { display: flex; align-items: center; gap: 0.5rem; margin-bottom: 1.25rem; font-size: 0.9rem; }
/* The friendlyrb.com primary button: navy pill on a yellow ledge. */
.btn--go {
  background: var(--color-brand);
  color: #fff;
  min-height: 3rem;
  padding: 0 2rem;
  font-weight: 700;
  box-shadow: 0 4px 0 var(--color-yellow);
}
.btn--go:hover { background: var(--color-brand); translate: 0 2px; box-shadow: 0 2px 0 var(--color-yellow); }
.signin .btn--go { width: 100%; border: 0; cursor: pointer; }
.signin__hint { margin-top: 1.5rem; color: #6b7280; font-size: 0.85rem; line-height: 1.5; }
.signin__hint code { background: #f3f4f6; padding: 0.1em 0.35em; border-radius: 3px; }
