/* Chinese display companion to Anton — Noto Sans SC weight 900 (Black).
   Heavy industrial sans that pairs cleanly with Anton's bold uppercase Latin. */
@import url("https://fonts.googleapis.com/css2?family=Noto+Sans+SC:wght@900&display=swap");

:root {
  --ease-elastic: cubic-bezier(0.16, 1.36, 0.5, 1);
  --ease-out-soft: cubic-bezier(0.16, 1, 0.3, 1);
}

::selection {
  background: #ff0c35;
  color: #fff;
}
::-moz-selection {
  background: #ff0c35;
  color: #fff;
}

/* ---------- Reset & Base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  scroll-behavior: smooth;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: "Inter", "PingFang SC", "Helvetica Neue", Helvetica, Arial,
    sans-serif;
  font-size: 16px;
  line-height: 1.6;
  color: #111;
  background: #fff;
  font-weight: 400;
  letter-spacing: 0.01em;
}

img {
  display: block;
  max-width: 100%;
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
  transition: opacity 0.2s ease;
}

a:hover {
  opacity: 0.55;
}

/* ---------- Layout ---------- */
.container {
  width: 100%;
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 40px;
}

section {
  padding: 120px 0;
}

/* ---------- Full-width Glass Header ---------- */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 64px;
  padding: 0 40px;
  background: rgba(255, 255, 255, 0.55);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
}

.site-logo {
  justify-self: start;
  width: 40px;
  height: 40px;
  background: #111;
  border-radius: 10px;
  transition: transform 0.3s var(--ease-out-soft), opacity 0.2s;
}

.site-logo:hover {
  transform: scale(0.92);
  opacity: 1;
}

.nav-pill {
  display: flex;
  align-items: center;
  gap: 24px;
  list-style: none;
  background: transparent;
  border: none;
  box-shadow: none;
  padding: 0;
  border-radius: 0;
}

.nav-pill a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 10px 16px;
  font-size: 14px;
  font-weight: 500;
  color: #a1a1ab;
  letter-spacing: -0.005em;
  transition: color 0.25s ease;
}

.nav-pill a:hover,
.nav-pill a.active:hover {
  color: #ff0c35;
  opacity: 1;
}

.site-avatar {
  justify-self: end;
  width: 40px;
  height: 40px;
  background: transparent;
  border: none;
  padding: 0;
  border-radius: 50%;
  cursor: default;
  transition:
    transform 0.55s cubic-bezier(0.34, 1.55, 0.5, 1),
    box-shadow 0.4s ease;
}

.site-avatar:hover {
  transform: scale(1.12);
  opacity: 1;
  box-shadow: 0 10px 24px rgba(0, 0, 0, 0.22);
}

/* Recolour the avatar background circle from yellow to neutral grey. The
   eye/mouth shapes live inside `<g class="mood">` groups so this selector
   only catches the SVG's first direct-child circle (the face background). */
.site-avatar svg > circle {
  fill: #D2D2D2;
}

.site-avatar svg {
  display: block;
  width: 100%;
  height: 100%;
}

.site-avatar .mood {
  opacity: 0;
  transition: opacity 0.15s ease;
}

.site-avatar[data-mood="0"] .mood-0,
.site-avatar[data-mood="1"] .mood-1,
.site-avatar[data-mood="2"] .mood-2,
.site-avatar[data-mood="3"] .mood-3 {
  opacity: 1;
}

@media (max-width: 640px) {
  .site-header { padding: 0 16px; height: 72px; }
  .nav-pill { gap: 16px; }
  .nav-pill a { padding: 8px 10px; font-size: 16px; }
}

/* ---------- Hero ---------- */
.hero {
  padding: 160px 0 120px;
}

.hero-eyebrow {
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #999;
  margin-bottom: 32px;
}

.hero h1 {
  font-size: clamp(48px, 7vw, 96px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 32px;
}

.hero h1 .accent {
  color: #aaa;
}

.hero-sub {
  font-size: 18px;
  color: #555;
  max-width: 560px;
  margin-bottom: 48px;
}

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 14px 28px;
  border: 1px solid #111;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  transition: background 0.25s ease, color 0.25s ease, opacity 0.2s ease;
}

.btn:hover {
  background: #111;
  color: #fff;
  opacity: 1;
}

.btn .arrow {
  transition: transform 0.25s ease;
}

.btn:hover .arrow {
  transform: translateX(4px);
}

/* Pill "more" button used in fan-center — lifts and gains a stronger shadow on hover. */
.btn--more {
  background: #d8d8d8;
  border: none;
  border-radius: 999px;
  padding: 16px 44px;
  font-family: "Anton", "Inter", sans-serif;
  font-size: 16px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: #363636;
  text-transform: lowercase;
  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.06);
  /* Big back-out bounce: y peaks at 1.9 (90% overshoot) so on hover OUT the button
     travels from translateY(-8) past 0 to ~+7px below rest, then springs back to 0.
     Combined with the larger 8px lift this gives a clearly visible Q-弹 motion. */
  transition:
    transform 0.6s cubic-bezier(0.34, 1.9, 0.45, 1),
    box-shadow 0.55s cubic-bezier(0.34, 1.5, 0.55, 1),
    background 0.25s ease;
}

.btn--more:hover {
  background: #d8d8d8;
  color: #363636;
  transform: translateY(-8px);
  box-shadow:
    0 4px 8px rgba(0, 0, 0, 0.04),
    0 10px 20px rgba(0, 0, 0, 0.06);
  opacity: 1;
}

/* ---------- Section Headers ---------- */
.section-head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  margin-bottom: 64px;
  gap: 24px;
  flex-wrap: wrap;
}

.section-head h2 {
  font-size: clamp(32px, 4vw, 48px);
  font-weight: 500;
  letter-spacing: -0.02em;
}

.section-head .label {
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #999;
}

/* ---------- Works Grid ---------- */
.works-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 48px 32px;
}

.work-card {
  display: block;
  cursor: pointer;
}

.work-card:hover {
  opacity: 1;
}

.work-thumb {
  position: relative;
  width: 100%;
  aspect-ratio: 4 / 3;
  background: #f5f5f5;
  border-radius: 20px;
  overflow: hidden;
  margin-bottom: 20px;
  transition: transform 0.45s cubic-bezier(0.34, 1.55, 0.5, 1);
}

.work-card:hover .work-thumb {
  transform: scale(1.03);
}

/* ---------- Work Detail Modal ----------
   Full-screen overlay that appears on card click. The .work-modal element is
   fixed and covers the viewport; its inner .work-modal__scroll handles
   vertical scrolling (for long case-study images). The close button sticks
   to the top-right corner, body scroll is locked while the modal is open. */
.work-modal {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: #fff;
  opacity: 0;
  pointer-events: none;
}

/* Transition lives on the open state, so opening fades smoothly but
   closing reverts instantly (no fade-out) once the rule stops applying. */
.work-modal[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
  transition: opacity 0.35s cubic-bezier(0.16, 1, 0.3, 1);
}

.work-modal__scroll {
  position: absolute;
  inset: 0;
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.work-modal__scroll::-webkit-scrollbar {
  display: none;
}

.work-modal__body {
  max-width: 960px;
  margin: 0 auto;
  padding: 120px 24px 160px;
  transform: translateY(24px) scale(0.98);
}

.work-modal[data-open="true"] .work-modal__body {
  transform: translateY(0) scale(1);
  transition: transform 0.45s cubic-bezier(0.34, 1.45, 0.5, 1);
}

.work-modal__close {
  position: fixed;
  top: 28px;
  right: 28px;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  border: none;
  background: #d8d8d8;
  color: #363636;
  cursor: pointer;
  z-index: 110;
  display: flex;
  align-items: center;
  justify-content: center;
  transition:
    transform 0.4s cubic-bezier(0.34, 1.55, 0.5, 1),
    background 0.25s ease;
}

.work-modal__close:hover {
  background: #c4c4c4;
  transform: scale(1.08) rotate(90deg);
}

.work-modal__title {
  font-family: "Anton", "Noto Sans SC", "Inter", sans-serif;
  font-size: clamp(40px, 5vw, 72px);
  font-weight: 400;
  letter-spacing: 0.01em;
  line-height: 1;
  text-transform: uppercase;
  margin-bottom: 12px;
  color: #1a1a1a;
}

.work-modal__tag {
  font-family: "Anton", "Noto Sans SC", "Inter", sans-serif;
  font-size: 14px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: #999;
  margin-bottom: 56px;
}

.work-modal__image {
  width: 100%;
  display: block;
  border-radius: 16px;
  margin-bottom: 24px;
}

.work-modal__placeholder {
  width: 100%;
  aspect-ratio: 3 / 4;
  background: #f0f0f0;
  border-radius: 20px;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #c0c0c0;
  font-size: 16px;
  letter-spacing: 0.04em;
}

/* Lock the page when modal is open */
body.modal-open {
  overflow: hidden;
}

.work-thumb-inner {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 64px;
  font-weight: 300;
  color: #ddd;
  letter-spacing: -0.02em;
  transition: transform 0.6s cubic-bezier(0.16, 1, 0.3, 1);
}

.work-card:hover .work-thumb-inner {
  transform: scale(1.04);
}

.work-meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 16px;
}

/* CJK runs inside work-card titles sit visually 5px lower than Anton on
   the same baseline; this span (added by JS) lifts only the Chinese chars
   so Latin and CJK look optically aligned. */
.cjk-lift {
  display: inline-block;
  transform: translateY(-2px);
}

.work-title {
  font-family: "Anton", "Noto Sans SC", "Inter", sans-serif;
  font-size: 22px;
  font-weight: 400;
  letter-spacing: 0.01em;
  text-transform: uppercase;
  line-height: 1.2;
}

.work-tag {
  font-family: "Anton", "Noto Sans SC", "Inter", sans-serif;
  font-size: 13px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: #999;
  line-height: 1.4;
}

/* Color variations for placeholder thumbnails */
.work-thumb.c1 { background: #f5f5f5; }
.work-thumb.c2 { background: #ececec; }
.work-thumb.c3 { background: #fafafa; }
.work-thumb.c4 { background: #f0f0f0; }
.work-thumb.c5 { background: #f7f4ef; }
.work-thumb.c6 { background: #eef1f4; }

/* ---------- About ---------- */
.about-grid {
  display: grid;
  grid-template-columns: 1fr 2fr;
  gap: 80px;
}

.about-grid .label {
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #999;
}

.about-text p {
  font-size: 20px;
  line-height: 1.6;
  color: #333;
  margin-bottom: 24px;
  letter-spacing: -0.005em;
}

.about-text p:last-child {
  margin-bottom: 0;
}

.skills-list {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 12px 32px;
  margin-top: 16px;
}

.skills-list li {
  font-size: 15px;
  color: #333;
  padding: 8px 0;
  border-bottom: 1px solid #eee;
}

/* ---------- Contact ---------- */
.contact {
  /* Clip the oversized CONNECT title if it overflows the viewport — no horizontal
     scrollbar. */
  overflow: hidden;
  padding: 160px 0 80px;
}

.contact-head {
  text-align: center;
  margin-bottom: 64px;
}

.contact-head .eyebrow {
  font-family: "Anton", "Inter", sans-serif;
  font-size: 18px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #d2d2d2;
  margin-bottom: 24px;
}

.contact-head h2 {
  font-family: "Anton", "Inter", sans-serif;
  font-size: clamp(72px, 19vw, 280px);
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 0.85;
  color: #d2d2d2;
  text-transform: uppercase;
  white-space: nowrap;
  margin: 0;
  overflow: visible;
}

/* Springy character pop matched to the React Bits ScrollFloat visual — each
   letter starts at scale 0.4 from below, rises and grows with a gentle back-out
   bezier (y peaks at 1.35 → mild overshoot, not cartoonish). Stagger 75ms keeps
   the clear one-at-a-time rhythm. Reversible on scroll-out. */
.contact-head .char {
  display: inline-block;
  transform-origin: 50% 80%;
  transform: translateY(70%) scale(0.4);
  opacity: 0;
  transition:
    transform 0.8s cubic-bezier(0.34, 1.35, 0.5, 1),
    opacity 0.35s ease;
  will-change: transform, opacity;
}

.contact-head.in .char {
  transform: translateY(0) scale(1);
  opacity: 1;
}

/* EXIT order (when .in is removed) — REVERSE: T first, C last. The transition
   property applies the delays from the state being transitioned TO; without .in
   we're heading back to the base/hidden state, so these are the exit delays. */
.contact-head .char:nth-child(1) { transition-delay: 0.45s, 0.45s; }   /* C */
.contact-head .char:nth-child(2) { transition-delay: 0.375s, 0.375s; } /* O */
.contact-head .char:nth-child(3) { transition-delay: 0.30s, 0.30s; }   /* N */
.contact-head .char:nth-child(4) { transition-delay: 0.225s, 0.225s; } /* N */
.contact-head .char:nth-child(5) { transition-delay: 0.15s, 0.15s; }   /* E */
.contact-head .char:nth-child(6) { transition-delay: 0.075s, 0.075s; } /* C */
.contact-head .char:nth-child(7) { transition-delay: 0s, 0s; }         /* T — exits first */

/* ENTER order (when .in is added) — FORWARD: C first, T last. These override
   the base delays only when .in is present. */
.contact-head.in .char:nth-child(1) { transition-delay: 0s, 0s; }         /* C — enters first */
.contact-head.in .char:nth-child(2) { transition-delay: 0.075s, 0.075s; } /* O */
.contact-head.in .char:nth-child(3) { transition-delay: 0.15s, 0.15s; }   /* N */
.contact-head.in .char:nth-child(4) { transition-delay: 0.225s, 0.225s; } /* N */
.contact-head.in .char:nth-child(5) { transition-delay: 0.30s, 0.30s; }   /* E */
.contact-head.in .char:nth-child(6) { transition-delay: 0.375s, 0.375s; } /* C */
.contact-head.in .char:nth-child(7) { transition-delay: 0.45s, 0.45s; }   /* T — enters last */

.contact-links {
  list-style: none;
  max-width: 640px;
  margin: 0 auto;
}

/* ---------- HymnGPT chat ---------- */
.askbot {
  max-width: 680px;
  margin: 0 auto;
}

.askbot__intro {
  text-align: center;
  font-size: 15px;
  color: #888;
  margin-bottom: 32px;
  letter-spacing: -0.005em;
}

.askbot__log {
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-height: 360px;
  overflow-y: auto;
  margin-bottom: 24px;
  padding: 0 4px;
  scroll-behavior: smooth;
  /* Scroll works, scrollbar is hidden — cleaner look. */
  scrollbar-width: none;   /* Firefox */
  -ms-overflow-style: none; /* IE / old Edge */
}

.askbot__log::-webkit-scrollbar { display: none; } /* Chrome / Safari */

.askbot__log:empty {
  display: none;
}

.askbot__msg {
  display: flex;
}

.askbot__msg--user { justify-content: flex-end; }
.askbot__msg--bot  {
  justify-content: flex-start;
  /* Column layout so an optional CTA action can stack under the bubble */
  flex-direction: column;
  align-items: flex-start;
}

/* Bubble entrance — pops in from its own side (user from right, bot from left)
   with a slight Q-bounce overshoot. transform-origin matches the bubble's anchor
   side so the scale-up reads as inflating from the speaker. */
.askbot__msg--user .askbot__bubble {
  transform-origin: 100% 50%;
  animation: askbot-pop-user 0.5s cubic-bezier(0.34, 1.55, 0.5, 1);
}

.askbot__msg--bot .askbot__bubble {
  transform-origin: 0 50%;
  animation: askbot-pop-bot 0.5s cubic-bezier(0.34, 1.55, 0.5, 1);
}

@keyframes askbot-pop-user {
  from { opacity: 0; transform: translateX(14px) scale(0.7); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

@keyframes askbot-pop-bot {
  from { opacity: 0; transform: translateX(-14px) scale(0.7); }
  to   { opacity: 1; transform: translateX(0) scale(1); }
}

/* Inline text link rendered INSIDE the bot bubble — text + arrow, right-aligned.
   Lighter color than the bubble's body text (#222) so it reads as secondary.
   Hover just brightens the colour toward white. */
.askbot__action {
  display: block;
  text-align: right;
  margin-top: 10px;
  color: #999;
  font-size: 13px;
  font-weight: 500;
  letter-spacing: -0.005em;
  text-decoration: none;
  transition: color 0.25s ease;
}

.askbot__action:hover {
  color: #363636;
  opacity: 1;
}

.askbot__action svg {
  display: inline-block;
  vertical-align: -2px;
  margin-left: 6px;
  transition: transform 0.2s ease;
}

.askbot__action:hover svg {
  transform: translateX(3px);
}

.askbot__bubble {
  width: fit-content;
  max-width: 50%;
  padding: 12px 18px;
  border-radius: 18px;
  font-size: 14.5px;
  line-height: 1.5;
  letter-spacing: -0.005em;
  white-space: pre-wrap;
  word-wrap: break-word;
}

.askbot__msg--user .askbot__bubble {
  background: #363636;
  color: #fff;
  border-bottom-right-radius: 6px;
}

.askbot__msg--bot .askbot__bubble {
  background: #f1f1f1;
  color: #222;
  border-bottom-left-radius: 6px;
}

.askbot__bubble.is-typing {
  display: inline-flex;
  gap: 5px;
  padding: 16px 20px;
  align-items: center;
}

.askbot__bubble.is-typing span {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #999;
  animation: askbot-typing 1.3s infinite ease-in-out;
}
.askbot__bubble.is-typing span:nth-child(2) { animation-delay: 0.16s; }
.askbot__bubble.is-typing span:nth-child(3) { animation-delay: 0.32s; }

@keyframes askbot-typing {
  0%, 60%, 100% { transform: translateY(0); opacity: 0.4; }
  30% { transform: translateY(-4px); opacity: 1; }
}

@keyframes askbot-pop {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}

.askbot__chips {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin-bottom: 40px;
}

.askbot__chip {
  background: transparent;
  border: 1px solid #e2e2e2;
  border-radius: 999px;
  padding: 9px 18px;
  font-size: 13px;
  font-family: inherit;
  color: #555;
  cursor: pointer;
  letter-spacing: -0.005em;
  transition: background 0.2s ease, color 0.2s ease, border-color 0.2s ease, transform 0.2s ease;
}

.askbot__chip:hover {
  background: #363636;
  border-color: #363636;
  color: #fff;
  transform: translateY(-1px);
}

.askbot__form {
  display: flex;
  align-items: center;
  gap: 6px;
  background: #f5f5f5;
  border-radius: 999px;
  padding: 6px 6px 6px 22px;
}

.askbot__input {
  flex: 1;
  border: none;
  background: transparent;
  font-family: inherit;
  font-size: 15px;
  letter-spacing: -0.005em;
  padding: 12px 0;
  outline: none;
  color: #222;
  min-width: 0;
}

.askbot__input::placeholder { color: #999; }

.askbot__send {
  width: 42px;
  height: 42px;
  border: none;
  border-radius: 50%;
  background: #363636;
  color: #fff;
  cursor: pointer;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: background 0.2s ease, transform 0.2s ease;
  flex-shrink: 0;
}

.askbot__send:hover { background: #111; transform: translateX(2px); }
.askbot__send:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

.contact-links li {
  display: flex;
  justify-content: space-between;
  padding: 18px 0;
  border-bottom: 1px solid #eee;
  font-size: 15px;
}

.contact-links li:first-child {
  border-top: 1px solid #eee;
}

.contact-links .label {
  color: #999;
}

/* ---------- Footer ---------- */
.footer {
  padding: 40px 0;
  font-size: 13px;
  color: #999;
}

.footer-inner {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 16px;
}

/* ---------- Page Headers (for inner pages) ---------- */
.page-header {
  padding: 140px 0 80px;
}

.page-header--hero {
  padding-top: 100px;
  padding-bottom: 40px;
}

.page-header .label {
  font-size: 13px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #999;
  margin-bottom: 24px;
}

.page-header h1 {
  font-size: clamp(48px, 6vw, 80px);
  font-weight: 500;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 24px;
}

.page-header .lead {
  font-size: 20px;
  color: #555;
  max-width: 640px;
}

/* ---------- Works Filters ---------- */
.filters {
  display: flex;
  gap: 12px;
  flex-wrap: wrap;
  margin-bottom: 48px;
}

.filter-btn {
  background: transparent;
  border: 1px solid #d8d8d8;
  border-radius: 999px;
  padding: 12px 28px;
  font-family: "Anton", "Inter", sans-serif;
  font-size: 14px;
  letter-spacing: 0.04em;
  line-height: 1.5;
  color: #363636;
  text-transform: lowercase;
  cursor: pointer;
  transition:
    transform 0.6s cubic-bezier(0.34, 1.9, 0.45, 1),
    box-shadow 0.55s cubic-bezier(0.34, 1.5, 0.55, 1),
    background 0.25s ease,
    border-color 0.25s ease;
}

.filter-btn:hover {
  background: #f0f0f0;
}

.filter-btn.active {
  background: #d8d8d8;
  border-color: #d8d8d8;
}

/* ---------- HYMN Hero ---------- */
.hero-hymn {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  padding: 84px 24px 70px;
  overflow: hidden;
}

.hero-hymn__title {
  position: relative;
  z-index: 4;
  top: 20px;
  font-family: "Anton", "Inter", sans-serif;
  font-size: clamp(38px, 6.2vw, 160px);
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 0.9;
  color: #363636;
  text-align: center;
  margin: 0;
  text-transform: uppercase;
}

/* ---- Per-line mask reveal (spencer-gabor-style) ----
   Each text line is wrapped in a .mask (overflow: hidden) containing a .mask__inner
   that starts translated down out of the box. On .hero-hymn.in, it slides up to 0.
   Order is staggered top→bottom via transition-delay. */
.mask {
  display: inline-block;
  overflow: hidden;
  vertical-align: bottom;
  line-height: inherit;
  padding-bottom: 0.06em; /* breathing room so descenders/caps aren't clipped */
}

.mask__inner {
  display: inline-block;
  transform: translateY(110%);
  transition: transform 1.05s cubic-bezier(0.2, 0.85, 0.25, 1);
  will-change: transform;
}

.hero-hymn.in .mask__inner,
.fan-center.in .mask__inner,
.contact-head.in .mask__inner,
.page-header--hero.in .mask__inner {
  transform: translateY(0);
}

/* Works/About page hero title — same Anton scale as the home HYMN title, but
   left-aligned to sit inside the page-header container layout. Re-declares
   font-family/weight/size/letter-spacing because `.page-header h1` (specificity
   0,1,1) wins over `.hero-hymn__title` (0,1,0) and would otherwise force a
   500 weight — which Anton doesn't ship, causing fallback to Inter. */
.page-header .page-hero-title {
  text-align: left;
  top: auto;
  margin-bottom: 24px;
  font-family: "Anton", "Inter", sans-serif;
  font-size: clamp(48px, 5.6vw, 84px);
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 0.95;
  text-transform: uppercase;
}

/* Stagger top → bottom: title first, then subtitle lines, then meta lines. */
.hero-hymn__title .mask__inner { transition-delay: 0.10s; }
.hero-hymn__sub .mask:nth-of-type(1) .mask__inner { transition-delay: 0.32s; }
.hero-hymn__sub .mask:nth-of-type(2) .mask__inner { transition-delay: 0.42s; }
.hero-meta p:nth-child(1) .mask__inner { transition-delay: 0.60s; }
.hero-meta p:nth-child(2) .mask__inner { transition-delay: 0.70s; }

/* Fan-centre reveal — eyebrow → h2 → button, staggered while cards spiral in. */
.contact-head .eyebrow .mask__inner { transition-delay: 0.05s; }
.contact-head h2 .mask__inner { transition-delay: 0.22s; }

.fan-center .eyebrow .mask__inner { transition-delay: 0.05s; }
.fan-center h2 .mask__inner       { transition-delay: 0.22s; }
.fan-center > .mask .mask__inner  { transition-delay: 0.50s; }

/* The button-wrapping mask needs to participate in inline layout cleanly so it stays
   centred under the h2 instead of collapsing or floating to the side. */
.fan-center > .mask {
  display: inline-block;
}

.hero-hymn__sub {
  position: relative;
  top: -10px;
  z-index: 1;
  font-family: "Anton", "Inter", sans-serif;
  font-size: clamp(38px, 6.2vw, 160px);
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 0.95;
  color: #d2d2d2;
  text-align: center;
  margin: 0;
  text-transform: uppercase;
}

.hero-cards {
  position: relative;
  top: -20px;
  width: 100%;
  max-width: 1200px;
  height: clamp(320px, 36vw, 480px);
  margin: -10px 0;
  z-index: 3;
}

.hero-card {
  --offsetX: 0;
  --offsetY: 0;
  --velocity: 0;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 240px;
  height: 240px;
  margin: -120px 0 0 -120px;
  border-radius: 26px;
  overflow: hidden;
  background: var(--bg, #f5f5f5);
  box-shadow:
    0 8px 20px rgba(0, 0, 0, 0.08),
    0 24px 50px rgba(0, 0, 0, 0.18),
    0 50px 100px rgba(0, 0, 0, 0.10);
  cursor: default;
  /* The translate/rotate CSS properties define the RESTING fan position. They are NOT
     transitioned because the JS mouse-interaction lerps them per frame. The entrance
     animation uses the separate `transform` property layered on top — it cancels the
     resting offset/tilt at start (stack all cards on top of each other in the centre)
     and resolves to identity at end (cards settle into their fan positions). */
  translate:
    calc(var(--tx, 0px) + var(--offsetX) * 1px)
    calc(var(--ty, 0px) + var(--offsetY) * 1px);
  rotate: calc(var(--rot, 0deg) - var(--velocity) * 0.25deg);
  transform:
    translate(calc(var(--tx, 0px) * -1), calc(var(--ty, 0px) * -1))
    rotate(calc(var(--rot, 0deg) * -1))
    scale(0.35);
  opacity: 0;
  /* Bouncy overshoot — like a spring landing with a small back-bounce. */
  transition:
    transform 1.1s cubic-bezier(0.34, 1.6, 0.5, 1),
    opacity 0.5s ease,
    box-shadow 0.4s ease;
  will-change: transform;
}

.hero-hymn.in .hero-card {
  transform: translate(0, 0) rotate(0deg) scale(1);
  opacity: 1;
}

/* Stagger the four cards so they bounce in like dealt cards, not all at once. */
.hero-card:nth-child(1) { transition-delay: 0.05s, 0.05s, 0s; }
.hero-card:nth-child(2) { transition-delay: 0.18s, 0.18s, 0s; }
.hero-card:nth-child(3) { transition-delay: 0.31s, 0.31s, 0s; }
.hero-card:nth-child(4) { transition-delay: 0.44s, 0.44s, 0s; }

.hero-card img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
}

/* Per-card resting position + alternating tilt */
.hero-card:nth-child(1) { --tx: -225px; --ty:  20px; --rot:   8deg; z-index: 1; }
.hero-card:nth-child(2) { --tx:  -75px; --ty: -20px; --rot:  -6deg; z-index: 2; }
.hero-card:nth-child(3) { --tx:   75px; --ty:  10px; --rot:   7deg; z-index: 3; }
.hero-card:nth-child(4) { --tx:  225px; --ty: -12px; --rot:  -9deg; z-index: 4; }

.hero-meta {
  position: absolute;
  bottom: 91px;
  left: 0;
  right: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 4px;
  font-size: 11px;
  letter-spacing: 0.22em;
  color: #555;
  text-transform: uppercase;
  font-weight: 800;
}

.hero-meta .email {
  color: #aaa;
  font-weight: 500;
}

/* Step 1: Universal layout fixes for ≥1440 — spacing all proportional to viewport height */
@media (min-width: 1440px) {
  .hero-hymn {
    padding: clamp(60px, 9vh, 140px) 24px clamp(40px, 5vh, 80px);
  }
  .hero-hymn__title { top: 0; }
  .hero-cards {
    top: 0;
    margin-top: clamp(40px, 5.5vh, 110px);   /* gap to HYMN */
    height: clamp(280px, 30vh, 460px);       /* hugs the cards inside */
  }
  .hero-hymn__sub {
    top: 0;
    margin-top: clamp(70px, 7vh, 90px);    /* +20px more to push subtitle down further */
  }

  .hero-meta {
    position: static;
    bottom: auto;
    margin-top: auto;
    padding-top: clamp(10px, 3vh, 60px);  /* -20px from previous to lift meta up */
  }
}

/* Step 2: Bigger cards ONLY when screen has both width AND height room */
@media (min-width: 1440px) and (min-height: 1000px) {
  .hero-card {
    width: 280px;
    height: 280px;
    margin: -140px 0 0 -140px;
    border-radius: 30px;
  }
  .hero-card:nth-child(1) { --tx: -270px; --ty:  24px; }
  .hero-card:nth-child(2) { --tx:  -90px; --ty: -24px; }
  .hero-card:nth-child(3) { --tx:   90px; --ty:  12px; }
  .hero-card:nth-child(4) { --tx:  270px; --ty: -14px; }
  .hero-cards { max-width: 1400px; }
}

/* Step 3: Ultra wide AND tall — Studio Display / iMac 27 */
@media (min-width: 1920px) and (min-height: 1200px) {
  .hero-card {
    width: 340px;
    height: 340px;
    margin: -170px 0 0 -170px;
    border-radius: 36px;
  }
  .hero-card:nth-child(1) { --tx: -330px; --ty:  28px; }
  .hero-card:nth-child(2) { --tx: -110px; --ty: -28px; }
  .hero-card:nth-child(3) { --tx:  110px; --ty:  14px; }
  .hero-card:nth-child(4) { --tx:  330px; --ty: -16px; }
  .hero-cards { max-width: 1700px; }
}

/* Tablet — 1024px and below: shrink cards & tighten spread */
@media (max-width: 1024px) {
  .hero-card {
    width: 200px;
    height: 200px;
    margin: -100px 0 0 -100px;
  }
  .hero-card:nth-child(1) { --tx: -195px; --ty:  16px; --rot:  8deg; }
  .hero-card:nth-child(2) { --tx:  -65px; --ty: -16px; --rot: -6deg; }
  .hero-card:nth-child(3) { --tx:   65px; --ty:   8px; --rot:  7deg; }
  .hero-card:nth-child(4) { --tx:  195px; --ty: -10px; --rot: -9deg; }
}

/* Mobile — 640px and below: small cards, reset offsets, recompose layout */
@media (max-width: 640px) {
  .hero-hymn {
    min-height: 100vh;
    padding: 80px 16px 24px;
    justify-content: space-between;
  }

  .hero-hymn__title { top: 10px; }
  .hero-hymn__sub  { top: -10px; }

  .hero-cards {
    top: 0;
    height: clamp(180px, 48vw, 240px);
  }

  .hero-card {
    width: 130px;
    height: 130px;
    margin: -65px 0 0 -65px;
    border-radius: 18px;
  }
  .hero-card:nth-child(1) { --tx: -125px; --ty:  10px; --rot:  8deg; }
  .hero-card:nth-child(2) { --tx:  -42px; --ty: -10px; --rot: -6deg; }
  .hero-card:nth-child(3) { --tx:   42px; --ty:   6px; --rot:  7deg; }
  .hero-card:nth-child(4) { --tx:  125px; --ty:  -6px; --rot: -9deg; }

  .hero-meta {
    position: static;
    margin-top: 24px;
  }
}

/* Very small — 380px and below: even tighter */
@media (max-width: 380px) {
  .hero-card { width: 110px; height: 110px; margin: -55px 0 0 -55px; }
  .hero-card:nth-child(1) { --tx: -108px; }
  .hero-card:nth-child(2) { --tx:  -36px; }
  .hero-card:nth-child(3) { --tx:   36px; }
  .hero-card:nth-child(4) { --tx:  108px; }
}

/* ---------- Fan Gallery ---------- */
.fan-gallery {
  padding: 120px 0 80px;
  position: relative;
  /* No overflow:hidden — card drop-shadows extend ~80px below each card and would
     otherwise be sliced off at the gallery's bottom edge. The cards themselves are
     positioned well within the gallery's box so removing the clip is safe. */
}

.fan-stage {
  position: relative;
  height: 880px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Both rows are stacked at the SAME spot — full-stage absolute. Every card therefore
   positions from the stage centre, so they share a common orbital origin. The rows
   themselves are 2D layouts; each card creates its own perspective context via the
   perspective() function in its transform, so z-index can still drive stacking. */
.fan-row {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

/* Invisible ELLIPTICAL hot-zone that triggers the card spread when the cursor enters
   the central area surrounded by the cards. The element's border-radius: 50% makes
   its hit-test region a true ellipse (not the bounding rectangle) — so hovering the
   corners of the gallery rectangle does NOT trigger the spread. */
.fan-hotzone {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 1100px;
  height: 880px;
  margin: -440px 0 0 -550px;
  border-radius: 50%;
  pointer-events: auto;
}

.fan-row .fan-card { pointer-events: auto; }

.fan-center {
  position: relative;
  z-index: 4;
  text-align: center;
  padding: 54px 0 24px; /* +30px top to push the subtitle block down */
}

.fan-center .eyebrow,
.page-header--hero .eyebrow {
  font-family: "Anton", "Inter", sans-serif;
  font-size: 18px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: #d2d2d2;
  margin-bottom: 24px;
}

.fan-center h2 {
  font-family: "Anton", "Inter", sans-serif;
  font-size: clamp(48px, 5.6vw, 84px);
  font-weight: 400;
  letter-spacing: 0.005em;
  line-height: 0.95;
  color: #363636;
  margin-bottom: 36px;
  text-transform: uppercase;
}

.fan-card {
  --x: 0px;
  --y: 0px;
  --r: 0deg;
  --spin: -180deg;
  position: absolute;
  top: 50%;
  left: 50%;
  width: 240px;
  height: 240px;
  margin: -120px 0 0 -120px;
  cursor: pointer;
  /* filter:drop-shadow follows the actual rendered alpha shape of the children —
     when the inner .fan-card-3d tilts in 3D, the drop-shadow tilts with it. This
     keeps the image, the card surface, and the cast shadow all in sync at the same
     angle, instead of a stationary box-shadow that the tilted card "floats off". */
  filter:
    drop-shadow(0 8px 18px rgba(0, 0, 0, 0.08))
    drop-shadow(0 28px 50px rgba(0, 0, 0, 0.14));
  /* Perspective is on the outer so that the inner .fan-card-3d's rotateX/Y renders
     in a 3D context. */
  perspective: 800px;
  opacity: 0;
  transform: rotate(var(--spin)) translate(0px, 0px) rotate(0deg) scale(0);
  transition: transform 1.5s cubic-bezier(0.25, 0.72, 0.28, 1),
    opacity 0.55s ease 0.05s,
    filter 0.55s ease;
  will-change: transform, filter;
}

.fan-card.in {
  opacity: 1;
  transform: rotate(0deg) translate(var(--x), var(--y)) rotate(var(--r)) scale(1);
}

/* Inner wrapper carrying ALL visual styling + the cursor-tracked 3D tilt.
   transition: transform 0s makes the tilt update instantaneously — no perceived lag
   even though the outer card still glides through its 0.5s layout transitions. */
.fan-card-3d {
  position: absolute;
  inset: 0;
  display: block;
  background: #d2d2d2;
  border-radius: 26px;
  overflow: hidden;
  /* Force this into its own GPU layer + flatten the backface so Chrome doesn't render
     a thin dark anti-aliasing line at the rounded edge when the card is mid-3D-rotation. */
  -webkit-backface-visibility: hidden;
  backface-visibility: hidden;
  isolation: isolate;
  /* Shadow moved to outer .fan-card so 3D rotation doesn't warp it. */
  transform: rotateX(var(--tilt-x)) rotateY(var(--tilt-y)) translateZ(var(--lift-z));
  transition:
    transform 0s,
    box-shadow 0.7s ease,
    opacity 0.55s ease,
    filter 0.55s ease,
    /* Fade the placeholder bg out 0.4s after .arrived fires (= after the image has
       finished its own fade-in) so the bg can't bleed through the AA at the rounded
       corners once the image is fully visible. */
    background 0.3s ease 0.4s;
  will-change: transform;
}

/* Once a card has finished its spiral entrance, swap to a smooth medium-length transition
   so the hover IN and OUT both feel deliberate — not snappy, not draggy. Same duration
   both directions because no override on the :hover selector itself. */
.fan-card.settled {
  /* Heavier, more resistant back-out — overshoot reduced from 110% to ~50%, duration
     longer (0.85s). Reads as a weighted spring rather than a snappy elastic — still
     visibly bounces but feels like the cards have some mass behind them. */
  transition: transform 0.85s cubic-bezier(0.42, 1.5, 0.55, 1);
}

/* Resting positions: cards lie on an ELLIPSE (rx=460, ry=300) — wider than tall so the
   arc reads flatter and the centre text gets a clear horizontal band.
   --cx / --cy / --cr give each card its position AND tilt on a CIRCLE of R=400 with a
   wider ±70° angular span (vs the ellipse's ±54°). The wider span lets edge cards reach
   into the 3-/9-o'clock zones — no more "empty left & right" — while the smaller radius
   keeps the whole shape compact. --cr scales each card's tilt so they "lean along" the
   circle's curvature, giving the fanned-out look. */
.fan-row.top .fan-card:nth-child(1) { --x: -372px; --y: -176px; --cx: -376px; --cy: -137px; --cr: -22deg; --r: -14deg; }
.fan-row.top .fan-card:nth-child(2) { --x: -209px; --y: -267px; --cx: -229px; --cy: -328px; --cr: -11deg; --r:  -7deg; }
.fan-row.top .fan-card:nth-child(3) { --x:    0px; --y: -300px; --cx:    0px; --cy: -400px; --cr:   0deg; --r:   0deg; }
.fan-row.top .fan-card:nth-child(4) { --x:  209px; --y: -267px; --cx:  229px; --cy: -328px; --cr:  11deg; --r:   7deg; }
.fan-row.top .fan-card:nth-child(5) { --x:  372px; --y: -176px; --cx:  376px; --cy: -137px; --cr:  22deg; --r:  14deg; }

.fan-row.bottom .fan-card:nth-child(1) { --x: -372px; --y:  176px; --cx: -376px; --cy:  137px; --cr:  22deg; --r:  14deg; }
.fan-row.bottom .fan-card:nth-child(2) { --x: -209px; --y:  267px; --cx: -229px; --cy:  328px; --cr:  11deg; --r:   7deg; }
.fan-row.bottom .fan-card:nth-child(3) { --x:    0px; --y:  300px; --cx:    0px; --cy:  400px; --cr:   0deg; --r:   0deg; }
.fan-row.bottom .fan-card:nth-child(4) { --x:  209px; --y:  267px; --cx:  229px; --cy:  328px; --cr: -11deg; --r:  -7deg; }
.fan-row.bottom .fan-card:nth-child(5) { --x:  372px; --y:  176px; --cx:  376px; --cy:  137px; --cr: -22deg; --r: -14deg; }

/* Hover — subtle lift, keep the card's resting tilt so the transition is smooth.
   Transform-function structure MUST match the resting (.in) transform exactly
   (rotate-translate-rotate-scale, 4 functions) — otherwise the browser falls back
   to matrix interpolation and the card visibly snaps. */
.fan-stage .fan-card.settled:hover {
  /* Stay pinned at the circle position — only the inner .fan-card-3d gets the tilt. */
  transform: rotate(0deg) translate(var(--cx), var(--cy)) rotate(var(--cr)) scale(1);
  z-index: 10;
}

/* Beefier shadow when hovered — filter:drop-shadow follows the tilted card shape,
   so the cast shadow tilts in sync with the image and the card surface. */
.fan-stage .fan-card.settled:hover {
  filter:
    drop-shadow(0 20px 36px rgba(0, 0, 0, 0.14))
    drop-shadow(0 50px 90px rgba(0, 0, 0, 0.22));
}

/* Sibling cards dim a touch when ANY card is hovered. The contrast shift quietly
   directs the eye to the hovered card and softens the moment the hovered card
   slides on top of the others. */
.fan-stage:has(.fan-card.settled:hover) .fan-card.settled:not(:hover) .fan-card-3d {
  opacity: 0.92;
  filter: brightness(0.98);
}

/* NOTE: deliberately no z-index on .fan-row. With position:absolute + z-index:auto
   the row does NOT create a stacking context, so cards from either row compete
   directly via their own z-index. A hovered card (z-index:10) therefore paints in
   front of cards in the OTHER row, without dragging its row-mates along. */

/* All cards spread to the R=400 circle whenever the cursor enters the elliptical
   hot-zone (or directly hovers a card that may have drifted outside it). Two branches:
   • :has(.fan-hotzone:hover) — cursor inside the central ellipse, including the
     negative space between cards.
   • :has(.fan-card.settled:hover) — cursor on a card that may have spread past the
     hot-zone bounds (the top-/bottom-most cards reach ~y=±520 in spread, just outside
     the hot-zone's ±440 vertical reach). */
.fan-stage:has(.fan-hotzone:hover) .fan-card.settled:not(:hover),
.fan-stage:has(.fan-center:hover) .fan-card.settled:not(:hover),
.fan-stage:has(.fan-card.settled:hover) .fan-card.settled:not(:hover) {
  transform: rotate(0deg) translate(var(--cx), var(--cy)) rotate(var(--cr)) scale(1);
}

/* After the fan-centre mask reveal completes, release the overflow:hidden clip so
   button hover-lift / shadow can paint outside the original line box. JS adds the
   `.revealed` class once the animations have run. */
.fan-center.revealed .mask {
  overflow: visible;
}

/* Register the tilt vars so the browser can interpolate them as proper angle/length
   types. This lets us transition them at their own fast speed (0.2s) for snappy
   cursor tracking, independent of the slow 0.5s layout transitions on the card. */
@property --tilt-x { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --tilt-y { syntax: "<angle>"; inherits: true; initial-value: 0deg; }
@property --lift-z { syntax: "<length>"; inherits: true; initial-value: 0px; }

.fan-card img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  /* object-fit: cover scales the image proportionally to completely fill the wrapper.
     Aspect ratio is preserved; if the image and wrapper ratios differ the image is
     cropped (centered by default). */
  object-fit: cover;
  display: block;
  pointer-events: none;
  user-select: none;
  -webkit-user-drag: none;
  /* Image stays hidden while the card is still flying / scaling. It fades in only after
     JS toggles .arrived (just before the card reaches full size). */
  opacity: 0;
  transition: opacity 0.35s ease,
    transform 0.55s cubic-bezier(0.22, 0.85, 0.25, 1);
}

.fan-card.arrived img {
  opacity: 1;
}

@media (max-width: 1280px) {
  .fan-stage { transform: scale(0.82); transform-origin: center; height: 760px; }
}

@media (max-width: 1080px) {
  .fan-stage { transform: scale(0.7); height: 660px; }
}

@media (max-width: 900px) {
  .fan-gallery { padding: 40px 0 60px; }
  .fan-stage {
    height: auto;
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 20px;
    transform: none;
    padding: 0 8px;
  }
  .fan-row {
    display: contents;
    height: auto;
  }
  .fan-center {
    grid-column: 1 / -1;
    padding: 24px 0;
  }
  .fan-card {
    position: relative;
    top: auto;
    left: auto;
    width: 100%;
    height: 220px;
    margin: 0;
    opacity: 1;
    transform: none !important;
  }
}

/* ---------- Reveal Animation ---------- */
.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.8s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.8s cubic-bezier(0.16, 1, 0.3, 1);
}

.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---- Works page entrance: filter pills + project cards ----
   Each item pops in one-by-one with a Q-bounce overshoot.
   Filter pills fire on page load (above the fold). Work cards fire when
   the IntersectionObserver toggles `.visible` on them. */
@keyframes filter-pop {
  0%   { opacity: 0; transform: translateY(18px) scale(0.85); }
  100% { opacity: 1; transform: translateY(0)   scale(1); }
}

.filter-btn {
  opacity: 0;
  animation: filter-pop 0.55s cubic-bezier(0.34, 1.6, 0.5, 1) 0.10s both;
}
.filter-btn:nth-child(2) { animation-delay: 0.22s; }
.filter-btn:nth-child(3) { animation-delay: 0.34s; }
.filter-btn:nth-child(4) { animation-delay: 0.46s; }
.filter-btn:nth-child(5) { animation-delay: 0.58s; }

@keyframes card-pop {
  0%   { opacity: 0; transform: translateY(26px) scale(0.88); }
  100% { opacity: 1; transform: translateY(0)    scale(1); }
}

/* Override base .reveal transition for work cards — use a keyframe animation
   with per-card stagger so we get the Q-bounce overshoot and one-by-one entry. */
.work-card.reveal {
  opacity: 0;
  transform: translateY(26px) scale(0.88);
  transition: none;
}
.work-card.reveal.visible {
  animation: card-pop 0.55s cubic-bezier(0.34, 1.45, 0.5, 1) both;
}
.works-grid .work-card.reveal.visible:nth-child(2) { animation-delay: 0.12s; }
.works-grid .work-card.reveal.visible:nth-child(3) { animation-delay: 0.24s; }
.works-grid .work-card.reveal.visible:nth-child(4) { animation-delay: 0.36s; }
.works-grid .work-card.reveal.visible:nth-child(5) { animation-delay: 0.48s; }
.works-grid .work-card.reveal.visible:nth-child(6) { animation-delay: 0.60s; }
.works-grid .work-card.reveal.visible:nth-child(7) { animation-delay: 0.72s; }
.works-grid .work-card.reveal.visible:nth-child(8) { animation-delay: 0.84s; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .container { padding: 0 24px; }
  section { padding: 80px 0; }
  .hero { padding: 100px 0 80px; }

  .works-grid {
    grid-template-columns: 1fr;
    gap: 40px;
  }

  .about-grid,
  .contact-grid {
    grid-template-columns: 1fr;
    gap: 32px;
  }

  .skills-list {
    grid-template-columns: 1fr;
  }

  .nav-links { gap: 20px; }
  .nav-inner { height: 64px; }
}