*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  height: 100%;
  height: -webkit-fill-available;
}

body {
  min-height: 100%;
  min-height: -webkit-fill-available;
  color: #111;
  overflow-x: hidden;
  overflow-y: auto;
  -webkit-font-smoothing: antialiased;
  background-color: #f5f5f3;
  background-image: url("assets/dots.png");
  background-repeat: repeat;
  background-size: 1400px auto;
  background-position: top left;
}

body.is-booting,
body.contents-open,
html.is-locked body {
  overflow: hidden;
}

/* ---------- Soft password gate ---------- */

.gate {
  display: none;
  position: fixed;
  inset: 0;
  z-index: 10000;
  align-items: center;
  justify-content: center;
  padding: max(1.5rem, env(safe-area-inset-top)) 1.5rem max(1.5rem, env(safe-area-inset-bottom));
  /* Let the body off-white + grid show through */
  background: transparent;
}

html.is-locked .gate {
  display: flex;
}

html.is-locked #site {
  visibility: hidden;
  pointer-events: none;
}

.gate__box {
  width: min(22rem, 88vw);
  padding: 2rem 1.75rem 1.75rem;
  border: 1px solid #111;
  border-radius: 10px;
  background-color: #f5f5f3;
}

.gate__form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.85rem;
  width: 100%;
}

.gate__label {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: clamp(0.85rem, 2vw, 0.95rem);
  letter-spacing: 0.16em;
  line-height: 1.2;
  color: rgba(17, 17, 17, 0.5);
  text-align: center;
}

/* Field chrome lives here so the input can stay ≥16px (no iOS focus zoom)
   while the mask dots still read small via scale. */
.gate__field {
  width: 100%;
  height: 2.1rem;
  display: flex;
  align-items: center;
  justify-content: center;
  border-bottom: 1px solid rgba(17, 17, 17, 0.22);
  transition: border-color 0.25s ease;
  overflow: hidden;
}

.gate__form:focus-within .gate__field {
  border-bottom-color: rgba(17, 17, 17, 0.55);
}

.gate__input {
  width: 200%;
  height: 2.1rem;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: 16px; /* iOS won't zoom if ≥16px */
  letter-spacing: 0.45em;
  line-height: 2.1rem;
  color: #111;
  text-align: center;
  background: transparent;
  border: none;
  border-radius: 0;
  padding: 0;
  outline: none;
  box-shadow: none;
  caret-color: rgba(17, 17, 17, 0.75);
  -webkit-appearance: none;
  appearance: none;
  -webkit-text-security: disc;
  transform: scale(0.5);
  transform-origin: center center;
}

.gate__error {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  color: rgba(17, 17, 17, 0.5);
  min-height: 1.1em;
  text-align: center;
}

.gate__submit {
  margin-top: 0.35rem;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: clamp(0.8rem, 1.8vw, 0.9rem);
  letter-spacing: 0.16em;
  line-height: 1;
  color: #111;
  background: transparent;
  border: 1px solid #111;
  border-radius: 10px;
  padding: 0.72rem 1.9rem;
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition:
    background-color 0.2s ease,
    color 0.2s ease;
}

.gate__submit:hover,
.gate__submit:focus-visible {
  background-color: #111;
  color: #f5f5f3;
  outline: none;
}

.gate__submit:active {
  opacity: 0.88;
}

.gate__form.is-wrong .gate__field {
  border-bottom-color: rgba(17, 17, 17, 0.55);
  animation: gate-shake 0.4s ease;
}

@keyframes gate-shake {
  0%,
  100% {
    transform: translateX(0);
  }
  25% {
    transform: translateX(-5px);
  }
  75% {
    transform: translateX(5px);
  }
}

/* ---------- Hero ---------- */

.landing {
  position: relative;
  width: 100%;
  /* Fallbacks first — some mobile browsers still mishandle svh/dvh alone */
  height: 100vh;
  height: 100svh;
  min-height: 100vh;
  min-height: -webkit-fill-available;
  min-height: 100dvh;
  overflow: hidden;
}

.landing__bg {
  position: absolute;
  inset: 0;
  /* Slight vertical gradient off #9BEFC8 — a touch lighter at the top, a touch
     deeper at the bottom, so the ground has depth without reading as banded. */
  background: linear-gradient(180deg, #b0f4d6 0%, #9befc8 52%, #7fe3b4 100%);
  z-index: 0;
}

/* Two identical layers. script.js paints the incoming image onto the hidden
   one, raises its z-index so it covers the other, and fades its opacity up.
   Stacking is set explicitly because DOM order alone would always put the same
   element on top, and half the transitions would then happen out of sight.
   Duration is overridden from script.js (FADE_MS) so the two can't drift. */
.landing__bg--fade {
  transition: opacity 0.55s ease;
}

@media (prefers-reduced-motion: reduce) {
  .landing__bg--fade {
    transition: none;
  }
}

.landing__logo-wrap {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 clamp(0.5rem, 1.5vw, 1.25rem);
}

.hero-logo {
  position: relative;
  /* Matches the logo.svg viewBox. At ~5:1 the mark can't overflow the landing
     section vertically, so no height cap is needed. */
  width: 72vw;
  max-width: none;
  aspect-ratio: 1082 / 214;
  opacity: 0;
  transition: opacity 0.2s ease;
}

.hero-logo.is-ready {
  opacity: 1;
}

.hero-logo svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  overflow: visible;
}

.hero-logo path {
  fill: #221f20;
}

/* The threshold sweep re-runs a blur every frame; hint it only while running. */
.hero-logo.is-inking svg {
  will-change: filter;
}

/* ---------- Slides ---------- */

.slides {
  --slide-width: 72vw;
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  /* 45% tighter than the original clamp(3rem, 8vh, 5.5rem). */
  gap: clamp(1.65rem, 4.4vh, 3.03rem);
  padding:
    clamp(4rem, 10vh, 7rem)
    clamp(1rem, 4vw, 2rem)
    clamp(5rem, 12vh, 8rem);
  background: transparent;
}

.slide {
  width: var(--slide-width);
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.85rem;
  scroll-margin-top: 5.5rem;
  opacity: 0;
  translate: 0 28px;
  transition:
    opacity 0.9s cubic-bezier(0.22, 1, 0.36, 1),
    translate 0.9s cubic-bezier(0.22, 1, 0.36, 1);
}

.slide.is-visible {
  opacity: 1;
  translate: 0 0;
}

.slide__title {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: clamp(0.8rem, 1.35vw, 0.95rem);
  letter-spacing: 0.04em;
  line-height: 1.2;
  color: rgba(17, 17, 17, 0.72);
  text-shadow:
    0 0 0.4px rgba(0, 0, 0, 0.28),
    0.35px 0 0 rgba(0, 0, 0, 0.22),
    -0.35px 0 0 rgba(0, 0, 0, 0.22),
    0 0.35px 0 rgba(0, 0, 0, 0.22),
    0 -0.35px 0 rgba(0, 0, 0, 0.22);
}

.slide__img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 10px;
  /* Same 8% shadow on every slide. Positive spread pushes the soft cast
     onto the page so it still reads around near-black artwork. */
  box-shadow: 0 8px 28px 4px rgba(0, 0, 0, 0.08);
}


/* ---------- Overview grid (bird's eye view of the deck) ---------- */

.overview {
  position: relative;
  z-index: 1;
  padding:
    clamp(2rem, 5vh, 3.5rem)
    clamp(1rem, 4vw, 2rem)
    clamp(4rem, 9vh, 6rem);
}

.overview__inner {
  width: var(--overview-width, 72vw);
  margin: 0 auto;
}

.overview__heading {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: clamp(0.8rem, 1.35vw, 0.95rem);
  letter-spacing: 0.04em;
  color: rgba(17, 17, 17, 0.72);
  margin-bottom: 1.1rem;
}

.overview__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
  gap: clamp(0.6rem, 1.2vw, 1rem);
}

.overview__item {
  position: relative;
  display: block;
  border-radius: 6px;
  overflow: hidden;
  text-decoration: none;
  background: rgba(17, 17, 17, 0.06);
  box-shadow: 0 4px 14px 2px rgba(0, 0, 0, 0.07);
  transition:
    transform 0.25s cubic-bezier(0.22, 1, 0.36, 1),
    box-shadow 0.25s cubic-bezier(0.22, 1, 0.36, 1);
}

.overview__thumb {
  display: block;
  width: 100%;
  height: auto;
}

.overview__meta {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 0.15rem;
  padding: 0.5rem 0.55rem;
  background: linear-gradient(
    180deg,
    rgba(0, 0, 0, 0) 45%,
    rgba(0, 0, 0, 0.78) 100%
  );
  opacity: 0;
  transition: opacity 0.25s ease;
}

.overview__num,
.overview__label {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  color: #fff;
  line-height: 1.2;
}

.overview__num {
  font-weight: 400;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
  opacity: 0.75;
}

.overview__label {
  font-weight: 300;
  font-size: 0.72rem;
  letter-spacing: 0.01em;
}

.overview__item:hover,
.overview__item:focus-visible {
  transform: translateY(-3px);
  box-shadow: 0 10px 24px 4px rgba(0, 0, 0, 0.14);
}

.overview__item:hover .overview__meta,
.overview__item:focus-visible .overview__meta {
  opacity: 1;
}

.overview__item:focus-visible {
  outline: 2px solid #111;
  outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
  .overview__item {
    transition: none;
  }
}

/* ---------- Contents toggle (sticky + / x) — LEFT ---------- */

.contents-toggle {
  position: sticky;
  top: 1.25rem;
  /* Sit in the left gutter beside the slide column — never over the slides,
     and never flush to the viewport edge on wide screens */
  align-self: flex-start;
  margin-top: 0;
  margin-right: 0;
  margin-bottom: -44px;
  margin-left: max(
    1rem,
    calc((100% - var(--slide-width)) / 2 - 44px - 1.1rem)
  );
  z-index: 90;
  width: 44px;
  height: 44px;
  border: none;
  border-radius: 50%;
  background: #000;
  color: #fff;
  cursor: pointer;
  display: grid;
  place-items: center;
  flex-shrink: 0;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.18);
  transition:
    transform 0.45s cubic-bezier(0.22, 1, 0.36, 1),
    background-color 0.35s ease,
    box-shadow 0.35s ease;
}

.contents-toggle:hover {
  transform: scale(1.04);
  box-shadow: 0 10px 28px rgba(0, 0, 0, 0.22);
}

.contents-toggle:active {
  transform: scale(0.96);
}

.contents-toggle__icon {
  position: relative;
  width: 14px;
  height: 14px;
  display: block;
}

.contents-toggle__bar {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 1.5px;
  background: #fff;
  border-radius: 999px;
  transition: transform 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.contents-toggle__bar--a {
  transform: translate(-50%, -50%) rotate(0deg);
}

.contents-toggle__bar--b {
  transform: translate(-50%, -50%) rotate(90deg);
}

body.contents-open .contents-toggle__bar--a {
  transform: translate(-50%, -50%) rotate(45deg);
}

body.contents-open .contents-toggle__bar--b {
  transform: translate(-50%, -50%) rotate(-45deg);
}

/* When open, park the toggle over the panel's top-left corner */
body.contents-open .contents-toggle {
  position: fixed;
  top: calc(1.1rem + 12px);
  left: calc(1.1rem + 12px);
  right: auto;
  align-self: auto;
  margin: 0;
  z-index: 95;
}

/* ---------- Contents panel ---------- */

.contents-backdrop {
  position: fixed;
  inset: 0;
  z-index: 70;
  background: rgba(0, 0, 0, 0.18);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.45s cubic-bezier(0.22, 1, 0.36, 1);
}

.contents-backdrop:not([hidden]) {
  display: block;
}

body.contents-open .contents-backdrop {
  opacity: 1;
  pointer-events: auto;
}

.contents-panel {
  position: fixed;
  top: 1.1rem;
  left: 1.1rem;
  bottom: 1.1rem;
  z-index: 80;
  width: min(320px, calc(100vw - 2.2rem));
  background: #000;
  color: #fff;
  border-radius: 10px;
  overflow: hidden;
  transform: translate3d(-110%, 0, 0);
  opacity: 0;
  pointer-events: none;
  transition:
    transform 0.55s cubic-bezier(0.22, 1, 0.36, 1),
    opacity 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.35);
}

body.contents-open .contents-panel {
  transform: translate3d(0, 0, 0);
  opacity: 1;
  pointer-events: auto;
}

.contents-panel__inner {
  height: 100%;
  overflow-y: auto;
  padding: 1.35rem 1.25rem 1.5rem;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, 0.25) transparent;
}

.contents-panel__header {
  margin-bottom: 1.35rem;
  padding-left: 2.6rem;
}

.contents-panel__brand {
  font-family: "Geist Sans", Geist, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-size: 1.35rem;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: #fff;
}

.contents-panel__label {
  margin-top: 0.55rem;
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: 0.78rem;
  letter-spacing: 0.02em;
  color: rgba(255, 255, 255, 0.72);
}

.contents-panel__nav {
  display: flex;
  flex-direction: column;
  gap: 0.72rem;
}

.contents-link {
  display: grid;
  grid-template-columns: 1.7rem 1fr;
  gap: 0.65rem;
  align-items: baseline;
  text-decoration: none;
  color: #fff;
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.contents-link:hover {
  opacity: 0.72;
}

.contents-link:active {
  transform: translateX(2px);
}

.contents-link__num {
  font-family: "Geist Sans", Geist, "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: -0.01em;
  color: #fff;
}

.contents-link__label {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-weight: 100;
  font-size: 0.82rem;
  letter-spacing: 0.01em;
  color: rgba(255, 255, 255, 0.92);
}

/* ---------- Footer ---------- */

.site-footer {
  position: relative;
  z-index: 1;
  width: 100%;
  background: #000000;
  overflow: hidden;
  line-height: 0;
}

.site-footer__inner {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  padding: clamp(3rem, 7vw, 6rem) clamp(1rem, 3vw, 3rem) 0;
  margin: 0;
}

.site-footer__logo {
  display: block;
  width: 100%;
  max-width: none;
  height: auto;
  /* logo.svg has no fill attribute, so it renders black. Inverting is the
     one-liner that turns it white while keeping a single source of truth for
     the mark — alpha is untouched, so the transparent ground stays black. */
  filter: invert(1);
  /* Push the mark past the page edge so .site-footer's overflow: hidden slices
     its lower edge. Percentage margins resolve against width, and the mark is
     ~2:1, so -7% here crops roughly 14% of its height. */
  margin-bottom: -7%;
}

@media (max-width: 720px) {
  /* The ground is a gradient now, not a fixed-ratio photo, so the splash can
     take the full viewport again without cropping anything. */
  .landing__logo-wrap {
    align-items: center;
    padding: 0 clamp(1rem, 5vw, 1.5rem);
  }

  .hero-logo {
    width: 88vw;
  }

  .slides {
    --slide-width: 88vw;
  }

  .overview__inner {
    --overview-width: 88vw;
  }

  .overview__grid {
    grid-template-columns: repeat(auto-fill, minmax(110px, 1fr));
  }

  .slide {
    width: var(--slide-width);
  }

  .contents-toggle {
    margin-left: max(
      0.65rem,
      calc((100% - var(--slide-width)) / 2 - 44px - 0.65rem)
    );
  }
}
