/* ==========================================================================
   Components
   ========================================================================== */

/* ---------- Buttons / links ---------- */
.btn{
  display: inline-flex;
  align-items: center;
  gap: var(--space-xs);
  padding: 16px 32px;
  border-radius: var(--radius-pill);
  /* Korean label: IBM Plex Mono has no Hangul glyphs, so its very wide
     monospace SPACE glyph was being used between two proportionally-
     rendered fallback-font words, producing an oversized, lopsided gap
     ("프로젝트␣␣␣␣문의하기"). Pretendard covers the Hangul + space
     glyphs from one family, so spacing renders evenly. */
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.01em;
  background: var(--color-accent);
  color: var(--color-accent-on-accent);
  transition: transform var(--dur-micro) var(--ease-standard), background var(--dur-micro) var(--ease-standard);
  min-height: 44px;
}
.btn:hover, .btn:focus-visible{
  background: var(--color-accent-soft);
  transform: translateY(-2px);
}

.link-arrow{
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.link-arrow svg{
  transition: transform var(--dur-micro) var(--ease-standard);
}
.link-arrow:hover svg{ transform: translate(4px,-4px); }

/* ---------- Nav ---------- */
.nav{
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: center;
  background: rgba(18,16,22,0);
  backdrop-filter: blur(0px);
  -webkit-backdrop-filter: blur(0px);
  transition: background 500ms var(--ease-standard), backdrop-filter 500ms var(--ease-standard);
}
.nav.is-scrolled{
  background: rgba(18,16,22,0.72);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
/* backdrop-filter establishes a new containing block for fixed-position
   descendants in Chromium/WebKit — that would trap the full-screen mobile
   menu (position:fixed) inside the 76px-tall nav bar instead of the
   viewport. Drop it while the menu is open so .nav__menu can size against
   the real viewport, and make the bar itself solid for legibility. */
.nav.is-open{
  background: var(--color-bg-dark);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}
.nav__inner{
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.nav__wordmark{
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 20px;
  letter-spacing: -0.02em;
  color: var(--color-text-on-dark);
}
.nav__menu{
  display: flex;
  gap: var(--space-lg);
}
.nav__menu a{
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.18em;
  text-transform: lowercase;
  color: var(--color-text-on-dark);
  position: relative;
  padding-bottom: 4px;
}
.nav__menu a::after{
  content: '';
  position: absolute;
  left: 0; bottom: 0;
  width: 100%; height: 1px;
  background: var(--color-accent);
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur-micro) var(--ease-standard);
}
.nav__menu a:hover::after, .nav__menu a:focus-visible::after{
  transform: scaleX(1);
  transform-origin: left;
}
.nav__burger{
  display: none;
  flex-direction: column;
  gap: 5px;
  width: 44px;
  height: 44px;
  align-items: center;
  justify-content: center;
}
.nav__burger span{
  display: block;
  width: 22px;
  height: 1.5px;
  background: var(--color-text-on-dark);
  transition: transform var(--dur-tilt) var(--ease-standard), opacity var(--dur-tilt) var(--ease-standard);
}
.nav.is-open .nav__burger span:nth-child(1){ transform: translateY(6.5px) rotate(45deg); }
.nav.is-open .nav__burger span:nth-child(2){ opacity: 0; }
.nav.is-open .nav__burger span:nth-child(3){ transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 767px){
  .nav__menu{
    position: fixed;
    inset: 0;
    top: var(--nav-h);
    background: var(--color-bg-dark);
    flex-direction: column;
    padding: var(--space-xl) var(--gutter);
    gap: var(--space-md);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--dur-tilt) var(--ease-standard), transform var(--dur-tilt) var(--ease-standard);
  }
  .nav.is-open .nav__menu{
    opacity: 1;
    transform: translateY(0);
    pointer-events: auto;
  }
  .nav__menu a{ font-size: 20px; }
  .nav__burger{ display: flex; }
}

/* ---------- Hero ---------- */
.hero{
  position: relative;
  /* z-index:0 (not just position:relative) makes .hero establish its own
     stacking context, so the negative z-index photo/canvas layers below
     paint *within* it instead of slipping behind .hero's own [data-theme]
     background (that escape is what made the photo invisible originally). */
  z-index: 0;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding-top: calc(var(--nav-h) + var(--space-lg));
  padding-bottom: var(--space-xl);
  overflow: hidden;
}
.hero__media{
  position: absolute;
  inset: 0;
  z-index: -2;
  overflow: hidden;
}
.hero__bg-img{
  position: absolute;
  /* oversized + centered so the parallax translate never exposes an edge */
  top: -6%;
  left: -3%;
  width: 106%;
  height: 112%;
  object-fit: cover;
  filter: saturate(0.68) contrast(1.08) brightness(0.72);
  will-change: transform;
  opacity: 0;
  transition: opacity 1100ms var(--ease-reveal);
}
.hero__bg-img.is-visible{ opacity: 1; }
@media (prefers-reduced-motion: reduce){
  .hero__bg-img{ opacity: 1; transition: none; }
}
.hero__bg-grain{
  position: absolute;
  inset: 0;
  background-image: var(--grain-svg);
  background-size: 220px 220px;
  opacity: 0.05;
  mix-blend-mode: overlay;
  pointer-events: none;
}
.hero__canvas{
  position: absolute;
  inset: 0;
  z-index: -1;
  opacity: 0.68;
  mix-blend-mode: screen;
}
.hero__scrim{
  position: absolute;
  inset: 0;
  z-index: 0;
  background:
    linear-gradient(180deg, rgba(18,16,22,0.55) 0%, rgba(18,16,22,0.32) 32%, rgba(18,16,22,0.62) 78%, rgba(18,16,22,0.88) 100%),
    linear-gradient(90deg, rgba(18,16,22,0.55) 0%, rgba(18,16,22,0.08) 45%);
}
.hero__content{
  position: relative;
  z-index: 2;
  width: 100%;
  max-width: var(--max-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.hero__eyebrow{ margin-bottom: var(--space-md); }
.hero h1{
  font-family: var(--font-display);
  font-size: var(--fs-hero);
  font-weight: 700;
  line-height: var(--lh-hero);
  letter-spacing: var(--ls-hero);
  text-transform: uppercase;
  max-width: 22ch;
}
.hero__line{
  display: block;
  overflow: hidden;
}
/* Below ~480px the token clamp (min 44px) still wraps each manual
   hero__line into two physical lines, orphaning "GRAIN," / "SIGNAL."
   on their own row. Scale the headline down further just on small
   phones so each line fits on one row. */
@media (max-width: 480px){
  .hero h1{ font-size: clamp(1.75rem, 1.05rem + 4.8vw, 2.35rem); }
}
.hero__sub{
  margin-top: var(--space-lg);
  max-width: 46ch;
  font-size: 18px;
  color: var(--color-muted-on-dark);
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 700ms var(--ease-reveal), transform 700ms var(--ease-reveal);
}
.hero__sub.is-visible{ opacity: 1; transform: translateY(0); }

.hero__scroll{
  position: absolute;
  bottom: var(--space-lg);
  left: 50%;
  transform: translateX(-50%);
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  color: var(--color-muted-on-dark);
  opacity: 0;
  transition: opacity 700ms var(--ease-reveal) 900ms;
}
.hero__scroll.is-visible{ opacity: 1; }
.hero__scroll span{
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.3em;
}
.hero__scroll-line{
  width: 1px;
  height: 44px;
  background: var(--color-border-on-dark);
  position: relative;
  overflow: hidden;
}
.hero__scroll-line::after{
  content: '';
  position: absolute;
  left: 0; top: -100%;
  width: 100%; height: 100%;
  background: var(--color-accent);
  animation: scrollLine 1.8s var(--ease-standard) infinite;
}
@keyframes scrollLine{
  0%{ top: -100%; }
  60%{ top: 100%; }
  100%{ top: 100%; }
}
@media (prefers-reduced-motion: reduce){
  .hero__scroll-line::after{ animation: none; top: 0; }
}

/* ---------- Wordmark interlude ---------- */
.wordmark-interlude{
  position: relative;
  padding-block: var(--space-xl);
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  overflow: hidden;
}
.wordmark-interlude__texture{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05) brightness(0.85);
  opacity: 0.14;
  z-index: 0;
}
.wordmark-interlude__mark,
.wordmark-interlude__caption{
  position: relative;
  z-index: 1;
}
.wordmark-interlude__mark{
  font-family: var(--font-display);
  font-weight: 900;
  font-size: var(--fs-wordmark);
  line-height: 0.85;
  letter-spacing: -0.02em;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--color-text);
  white-space: nowrap;
}
.wordmark-interlude__caption{
  margin-top: var(--space-md);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--color-muted);
}

/* ---------- Services ---------- */
.services__grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  border-top: 1px solid var(--color-border-on-dark);
  border-left: 1px solid var(--color-border-on-dark);
}
.service-card{
  position: relative;
  border-right: 1px solid var(--color-border-on-dark);
  border-bottom: 1px solid var(--color-border-on-dark);
  padding: var(--space-lg) var(--space-md);
  min-height: 340px;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  perspective: 800px;
}
.service-card__inner{
  transition: transform var(--dur-tilt) ease-out;
  transform-style: preserve-3d;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  height: 100%;
}
.service-card:hover .service-card__inner,
.service-card:focus-within .service-card__inner,
.service-card.is-open .service-card__inner{
  transform: perspective(800px) rotateX(4deg) rotateY(-4deg);
}
.service-card__index{
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-accent);
  letter-spacing: 0.1em;
}
.service-card__roll{
  position: relative;
  overflow: hidden;
  min-height: 180px;
  margin-top: var(--space-md);
}
.service-card__face{
  position: absolute;
  inset: 0;
  transition: transform var(--dur-tilt) ease-out;
}
.service-card__face--default{ transform: translateY(0); }
.service-card__face--alt{ transform: translateY(100%); }
.service-card:hover .service-card__face--default,
.service-card:focus-within .service-card__face--default,
.service-card.is-open .service-card__face--default{ transform: translateY(-100%); }
.service-card:hover .service-card__face--alt,
.service-card:focus-within .service-card__face--alt,
.service-card.is-open .service-card__face--alt{ transform: translateY(0); }

.service-card__title{
  font-family: var(--font-display);
  font-size: clamp(22px, 1.6vw + 14px, 30px);
  font-weight: 700;
  letter-spacing: -0.01em;
  margin-bottom: var(--space-sm);
}
.service-card__caption{
  color: var(--color-muted-on-dark);
  font-size: 15px;
  max-width: 26ch;
}
.service-card__list li{
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.02em;
  color: var(--color-text-on-dark);
  padding-block: 6px;
  border-bottom: 1px solid var(--color-border-on-dark);
}
.service-card__list li:first-child{ border-top: 1px solid var(--color-border-on-dark); }

@media (max-width: 1023px){
  .services__grid{ grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 639px){
  .services__grid{ grid-template-columns: 1fr; }
  .service-card{ min-height: 300px; }
}

/* ---------- Manifesto pin (keyword wipe) ---------- */
.manifesto-pin{
  position: relative;
  height: 260vh;
  height: 260svh;
  background:
    radial-gradient(60% 50% at 20% 20%, rgba(74,85,255,0.16), transparent 60%),
    radial-gradient(50% 50% at 80% 80%, rgba(138,92,255,0.14), transparent 60%),
    var(--color-bg-dark);
}
.manifesto-pin__sticky{
  position: sticky;
  top: 0;
  height: 100svh;
  overflow: hidden;
}
.manifesto-pin__eyebrow{
  position: absolute;
  top: var(--space-lg);
  left: var(--gutter);
  z-index: 5;
}
.keyword-panel{
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding-inline: var(--gutter);
  background: var(--color-bg-dark);
  clip-path: inset(0 100% 0 0);
  transition: clip-path var(--dur-wipe) var(--ease-wipe);
}
.keyword-panel.is-active{ clip-path: inset(0 0 0 0); }
.keyword-panel__word{
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(3rem, 2rem + 8vw, 9rem);
  letter-spacing: -0.02em;
  line-height: 1;
  background: linear-gradient(90deg, var(--color-accent), var(--color-accent-soft));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.keyword-panel__ko{
  margin-top: var(--space-sm);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.4em;
  text-transform: uppercase;
  color: var(--color-muted-on-dark);
}
.keyword-panel__statement{
  margin-top: var(--space-lg);
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 380;
  font-size: var(--fs-quote);
  line-height: var(--lh-quote);
  max-width: 20ch;
}
.manifesto-pin__progress{
  position: absolute;
  bottom: var(--space-lg);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  gap: 10px;
  z-index: 5;
}
.manifesto-pin__progress span{
  width: 28px;
  height: 2px;
  background: var(--color-border-on-dark);
  transition: background var(--dur-micro) var(--ease-standard);
}
.manifesto-pin__progress span.is-active{ background: var(--color-accent); }

@media (prefers-reduced-motion: reduce){
  .manifesto-pin{ height: auto; padding-block: var(--space-xl); }
  .manifesto-pin__sticky{ position: relative; height: auto; }
  .keyword-panel{
    position: relative;
    inset: auto;
    clip-path: none !important;
    padding-block: var(--space-lg);
    min-height: auto;
  }
  .manifesto-pin__progress{ display: none; }
}

/* ---------- Portfolio ---------- */
.portfolio-list{
  border-top: 1px solid var(--color-border);
}
.portfolio-row{
  position: relative;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding: var(--space-md) 0;
  border-bottom: 1px solid var(--color-border);
  overflow: hidden;
}
.portfolio-row__tag{
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-muted);
  width: 140px;
  flex-shrink: 0;
}
.portfolio-row__title{
  font-family: var(--font-display);
  font-size: clamp(24px, 2vw + 14px, 44px);
  font-weight: 600;
  letter-spacing: -0.01em;
  flex: 1;
  transition: transform var(--dur-micro) var(--ease-standard), color var(--dur-micro) var(--ease-standard);
}
.portfolio-row:hover .portfolio-row__title{
  transform: translateX(12px);
  color: var(--color-accent);
}
.portfolio-row__year{
  font-family: var(--font-mono);
  font-size: 14px;
  color: var(--color-muted);
  flex-shrink: 0;
}
.portfolio-row__thumb{
  position: absolute;
  top: 50%;
  right: var(--space-lg);
  transform: translate(160%, -50%);
  width: clamp(140px, 18vw, 220px);
  height: clamp(90px, 12vw, 140px);
  clip-path: polygon(12% 0, 100% 0, 88% 100%, 0 100%);
  transition: transform var(--dur-mask) var(--ease-standard);
  pointer-events: none;
  overflow: hidden;
  background: var(--color-surface-panel); /* shows briefly while the jpg decodes */
}
.portfolio-row__thumb img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade-filter);
}
.portfolio-row__thumb::after{
  /* signal-blue duotone wash ties the photography into the single-accent
     palette instead of reading as a raw, unrelated stock photo */
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(135deg, var(--color-accent) 0%, var(--color-accent-soft) 100%);
  mix-blend-mode: color;
  opacity: 0.35;
}
.portfolio-row:hover .portfolio-row__thumb,
.portfolio-row.is-touch-active .portfolio-row__thumb{
  transform: translate(0, -50%);
}
.portfolio-row.is-touch-active .portfolio-row__title{
  transform: translateX(12px);
  color: var(--color-accent);
}
@media (max-width: 767px){
  .portfolio-row{ flex-wrap: wrap; }
  .portfolio-row__title{ order: 1; width: 100%; flex: 1 1 100%; }
  .portfolio-row__tag{ order: 2; }
  .portfolio-row__year{ order: 3; }
  .portfolio-row__thumb{
    width: clamp(96px, 34vw, 150px);
    height: clamp(62px, 22vw, 96px);
    right: 0;
  }
}

/* ---------- Process / Numbers (rounded panel) ---------- */
.process-panel{
  margin-inline: var(--gutter);
  border-radius: var(--radius-panel);
  padding: 0 var(--space-lg) var(--space-xl);
  overflow: hidden; /* clip the media band to the panel's own corner radius */
}
@media (max-width: 1023px){
  .process-panel{ border-radius: 40px; padding: 0 var(--space-md) var(--space-xl); }
}
@media (max-width: 767px){
  .process-panel{ border-radius: 24px; }
}
@media (max-width: 479px){
  .process-panel{ border-radius: 16px; margin-inline: var(--space-sm); }
}

.process-panel__media{
  position: relative;
  margin-inline: calc(var(--space-lg) * -1);
  margin-bottom: var(--space-xl);
  aspect-ratio: 21 / 9;
  overflow: hidden;
}
@media (max-width: 1023px){
  .process-panel__media{ margin-inline: calc(var(--space-md) * -1); aspect-ratio: 16 / 9; }
}
.process-panel__media img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  filter: var(--grade-filter) brightness(0.82);
}
.process-panel__media::after{
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(18,16,22,0.05) 0%, rgba(18,16,22,0.55) 100%);
}

.process-steps{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  margin-top: var(--space-xl);
}
.process-step{
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-md);
}
.process-step__num{
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-accent);
}
.process-step__title{
  font-family: var(--font-display);
  font-size: 22px;
  font-weight: 700;
  margin-block: var(--space-xs);
}
.process-step__desc{
  color: var(--color-muted);
  font-size: 15px;
}

.stat-grid{
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: var(--space-md);
  margin-top: var(--space-xxl);
}
.stat{
  text-align: left;
}
.stat__num{
  font-family: var(--font-display);
  font-size: var(--fs-stat);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--color-accent);
}
.stat__label{
  margin-top: var(--space-xs);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-muted);
}

@media (max-width: 1023px){
  .process-steps, .stat-grid{ grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 479px){
  .process-steps, .stat-grid{ grid-template-columns: 1fr; }
}

/* ---------- Statement ---------- */
.statement{
  text-align: center;
}
.statement blockquote{
  font-family: var(--font-serif);
  font-style: italic;
  font-weight: 380;
  font-size: clamp(1.75rem, 1.1rem + 3vw, 3.25rem);
  line-height: var(--lh-quote);
  max-width: 20ch;
  margin-inline: auto;
}
.statement__sub{
  margin-top: var(--space-md);
  color: var(--color-muted);
}
.statement__rule{
  width: 64px;
  height: 1px;
  background: var(--color-border);
  margin: var(--space-lg) auto;
}

/* ---------- CTA ---------- */
.cta{
  position: relative;
  z-index: 0;
  text-align: center;
  overflow: hidden;
}
.cta__media{
  position: absolute;
  inset: -6% -3%;
  z-index: 0;
  overflow: hidden;
  will-change: transform;
}
.cta__media img{
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* cta-water.jpg carries a baked-in filmstrip/sprocket border — scale past
     it so the CTA background reads as an edge-to-edge water surface */
  transform: scale(1.28);
  filter: var(--grade-filter) brightness(0.6) hue-rotate(-8deg);
}
.cta__scrim{
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    radial-gradient(70% 60% at 50% 40%, rgba(18,16,22,0.35), rgba(18,16,22,0.78) 75%),
    linear-gradient(180deg, rgba(18,16,22,0.6), rgba(18,16,22,0.85));
}
.cta .container{
  position: relative;
  z-index: 2;
}
.cta__link{
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2rem, 1.2rem + 4.5vw, 5rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  background: linear-gradient(90deg, var(--color-accent), var(--color-accent-soft));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  transition: opacity var(--dur-micro) var(--ease-standard);
}
.cta__link:hover{ opacity: 0.85; }
.cta .btn{ margin-top: var(--space-xl); }

/* ---------- Footer ---------- */
.footer{
  padding-top: var(--space-xxl);
}
.footer__wordmark{
  font-family: var(--font-display);
  font-weight: 800;
  font-size: var(--fs-wordmark-sm);
  line-height: 0.9;
  letter-spacing: -0.02em;
  text-align: center;
  margin-bottom: var(--space-xxl);
}
.footer__grid{
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: var(--space-lg);
  padding-bottom: var(--space-xl);
  border-bottom: 1px solid var(--color-border-on-dark);
}
.footer__col h4{
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--color-muted-on-dark);
  margin-bottom: var(--space-md);
}
.footer__col ul{
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.footer__col a, .footer__col p{
  font-size: 15px;
  color: var(--color-text-on-dark);
}
.footer__col a{
  transition: color var(--dur-micro) var(--ease-standard);
}
.footer__col a:hover{ color: var(--color-accent); }
.footer__bottom{
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: var(--space-md);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-muted-on-dark);
}

@media (max-width: 767px){
  .footer__grid{ grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 479px){
  .footer__grid{ grid-template-columns: 1fr; }
}

/* ---------- Floating back-to-top ---------- */
.float-top{
  position: fixed;
  right: var(--space-md);
  bottom: var(--space-md);
  z-index: 90;
  width: 52px;
  height: 52px;
  border-radius: var(--radius-pill);
  background: var(--color-accent);
  color: var(--color-accent-on-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: var(--shadow-float);
  opacity: 0;
  transform: translateY(12px);
  pointer-events: none;
  transition: opacity var(--dur-tilt) var(--ease-standard), transform var(--dur-tilt) var(--ease-standard), background var(--dur-micro);
}
.float-top.is-visible{
  opacity: 1;
  transform: translateY(0);
  pointer-events: auto;
}
.float-top:hover{ background: var(--color-accent-soft); }

/* ---------- Reveal-on-scroll utility ---------- */
.reveal{
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 800ms var(--ease-reveal), transform 800ms var(--ease-reveal);
}
.reveal.is-visible{
  opacity: 1;
  transform: translateY(0);
}
@media (prefers-reduced-motion: reduce){
  .reveal{ opacity: 1; transform: none; transition: none; }
}

/* ---------- Photography: shared grain + scroll-reveal wipe ---------- */

/* reusable film-grain layer, dropped over any photo block that includes
   a sibling <div class="media-grain">; ties every photograph on the site
   to the same faint texture so they read as one consistent shoot */
.media-grain{
  position: absolute;
  inset: 0;
  z-index: 1;
  background-image: var(--grain-svg);
  background-size: 220px 220px;
  opacity: 0.045;
  mix-blend-mode: overlay;
  pointer-events: none;
}

/* clip-path wipe + scale settle for real photography, direction varied
   per section via data-dir so the site doesn't feel like one repeated
   animation stamped everywhere.

   IMPORTANT: the clip-path/transform live on the *inner* <img>, while
   IntersectionObserver watches the unclipped `.img-reveal` wrapper.
   IntersectionObserver computes intersection against rendered geometry,
   so a target that starts fully clip-path-clipped (0 visible area) would
   never report as intersecting — a self-referential deadlock — if we
   clipped the observed element itself. */
.img-reveal > img{
  clip-path: inset(0 100% 0 0);
  transform: scale(1.08);
  transition: clip-path 900ms var(--ease-wipe), transform 1100ms var(--ease-reveal);
}
.img-reveal[data-dir="right"] > img{ clip-path: inset(0 0 0 100%); }
.img-reveal[data-dir="up"] > img{ clip-path: inset(100% 0 0 0); }
.img-reveal[data-dir="down"] > img{ clip-path: inset(0 0 100% 0); }
/* .is-visible must win over the [data-dir] starting-state rules above even
   though both are (0,2,1) specificity — declaring it last settles the tie
   in its favour regardless of which data-dir a given instance uses. */
.img-reveal.is-visible > img{
  clip-path: inset(0 0 0 0);
  transform: scale(1);
}
@media (prefers-reduced-motion: reduce){
  .img-reveal > img{ clip-path: inset(0 0 0 0) !important; transform: none; transition: none; }
}

/* QA (a): tablet/desktop GNB links need a >=44px touch target even though
   the visible label stays small. Padding goes almost entirely on top so
   the accent underline (bottom:0 of this box) stays a tight 4px under the
   label instead of drifting into a big empty gap. The extra height is
   absorbed by nav__inner's align-items:center, so the row doesn't grow. */
.nav__menu a{
  display: inline-flex;
  align-items: flex-end;
  padding: 22px 2px 4px;
}
