/* ============================================================
   STYLES.CSS
   Base styles, design tokens, and component layout.
   All sizing in rem (1rem = 10px, set in breakpoints.css).
   ============================================================ */


/* ============================================================
   FONT
   ============================================================ */

@font-face {
  font-family: "NeueHaas";
  src: url("font/NeueHaas.woff2") format("woff2"),
       url("font/NeueHaas.woff")  format("woff"),
       url("font/NeueHaas.ttf")   format("truetype");
  font-style:  normal;
  font-weight: 400;
  font-display: swap;
}


/* ============================================================
   DESIGN TOKENS
   Typography and spacing defined here as defaults (desktop).
   Responsive overrides in breakpoints.css via @media blocks.
   ============================================================ */

:root {
  /* Colour */
  --color-bg:       #0a0a0a;
  --color-text:     #f2f2f0;
  --color-muted:    #878787;
  --color-border:   rgba(255, 255, 255, 0.12);

  /* Typography scale */
  --fs-sm:    1.2rem;    /* 12px  labels, captions, copyright  */
  --fs-body:  2.4rem;      /* 24px  body, nav links, card titles */
  --fs-md:    3.2rem;    /* 32px  clients + service names (h3) */
  --fs-xl:    5.6rem;    /* 56px  section titles (h2)          */
  --fs-hero: 14.8rem;    /* 148px hero (h1)                    */

  /* Spacing scale */
  --space-xs:              1.6rem;   /* 16px */
  --space-sm:              2.4rem;   /* 24px */
  --space-md:              3.2rem;   /* 32px */
  --space-lg:              4.2rem;   /* 42px */
  --space-page-pad:        4.8rem;   /* 48px  horizontal page padding  */
  --space-section-top:    12.4rem;   /* 124px section vertical padding */
  --space-hero-top:        8.0rem;   /* 80px  */
  --space-hero-bottom:    14.8rem;   /* 148px */
  --space-contact-bottom:  5.6rem;   /* 56px  */
  --space-nav-v:           2.2rem;   /* 22px  */
  --space-service-row:     3.6rem;   /* 36px  */
  --space-service-gap:     4.8rem;   /* 48px  */
}


/* ============================================================
   SLEEK AUDIO PLAYER — THEME BRIDGE
   Maps this theme's real design tokens onto the plugin's own
   namespaced custom properties (which ship with generic defaults
   so the plugin looks reasonable on any theme out of the box).
   This is the entire integration surface — no plugin code/CSS
   fork needed to make it look native here.
   ============================================================ */

:root {
  --sleek-audio-wave-color:     var(--color-muted);
  --sleek-audio-progress-color: var(--color-text);
  --sleek-audio-loading-color:  var(--color-muted);
  --sleek-audio-ease:           cubic-bezier(0.16, 1, 0.3, 1);
}


/* ============================================================
   SELECTION
   ============================================================ */

::selection {
  background: var(--color-muted);
  color:      var(--color-bg);
}


/* ============================================================
   RESET
   ============================================================ */

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

html, body,
h1, h2, h3, h4, h5, h6,
p, figure, ol, ul, li {
  margin:  0;
  padding: 0;
}

ol, ul {
  list-style: none;
}


/* ============================================================
   BASE
   ============================================================ */

body {
  background-color:       var(--color-bg);
  color:                  var(--color-text);
  font-family:            "NeueHaas", sans-serif;
  font-size:              var(--fs-body);
  line-height:            1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

a {
  color:           inherit;
  text-decoration: none;
}

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

hr {
  border:     none;
  border-top: 1px solid var(--color-border);
  margin:     0;
}


/* ============================================================
   NAV
   ============================================================ */

.nav {
  position:        sticky;
  top:             0;
  /* Above .modal (z-index: 200) so nav stays reachable while a
     project modal is open — see script.js's nav-link click handling,
     which closes the modal before navigating so clicking a link
     while a modal's open actually goes somewhere. */
  z-index:         400;
  display:         flex;
  align-items:     center;
  justify-content: space-between;
  padding:         var(--space-nav-v) var(--space-page-pad);
  background:      linear-gradient(to bottom, var(--color-bg) 0%, transparent 100%);
  transition:      opacity 0.4s ease;
}

.nav--hidden {
  opacity: 0;
  /* pointer-events stays enabled (unlike most hidden states) so
     hovering the nav's area while invisible can still trigger
     the reveal in script.js. */
}


/* Mobile: nav always visible — no cursor to discover it */
@media (max-width: 767px) {
  .nav--hidden {
    opacity:        1;
    pointer-events: auto;
  }
}

.nav__brand {
  font-size:       var(--fs-body);
  letter-spacing:  -0.01em;
  line-height:     1;
  transition:      color 0.2s ease-in-out;
}

.nav__brand:hover {
  color: var(--color-muted);
}

.nav__links {
  display: flex;
  gap:     var(--space-md);
}

.nav__link {
  font-size:   var(--fs-body);
  font-weight: 400;
  line-height: 1;
  transition:  color 0.2s ease-in-out;
}

.nav__link:hover {
  color: var(--color-muted);
}

/* Flip hover effect — desktop nav brand + links.
   Two stacked copies of the label; on hover the default-color
   face slides/fades out as the muted-color face slides/fades in,
   reusing the section indicator's fade + 3px slide tokens. */

.nav__flip {
  display:        inline-block;
  overflow:       hidden;
  padding-bottom: 0.12em; /* prevent descender clipping during the slide */
}

.nav__flip-inner {
  display:  block;
  position: relative;
}

.nav__flip-face {
  display:     block;
  line-height: 1;
  transition:  opacity 0.2s ease 0.2s, transform 0.2s ease 0.2s; /* reappears only once the alt face has cleared */
}

.nav__flip-face--alt {
  position:   absolute;
  inset:      0;
  color:      var(--color-muted);
  opacity:    0;
  transform:  translateY(3px);
  transition: opacity 0.2s ease, transform 0.2s ease; /* clears immediately on mouse-leave */
}

.nav__flip:hover .nav__flip-face {
  opacity:    0;
  transform:  translateY(3px);
  transition: opacity 0.2s ease, transform 0.2s ease; /* clears immediately on hover */
}

.nav__flip:hover .nav__flip-face--alt {
  opacity:    1;
  transform:  translateY(0);
  transition: opacity 0.2s ease 0.2s, transform 0.2s ease 0.2s; /* arrives only once the default face has cleared */
}

/* Toggle button — hidden on desktop, shown via breakpoints.css */
.nav__toggle {
  display:        none;
  background:     none;
  border:         none;
  padding:        0;
  cursor:         pointer;
  color:          var(--color-text);
  font-family:    inherit;
  font-size:      var(--fs-body);
  font-weight:    500;
  letter-spacing: 0.08em;
  /* text-transform: uppercase;*/
  line-height:    1;
  transition:     color 0.2s ease-in-out;
}

.nav__toggle:hover {
  color: var(--color-muted);
}

.nav__toggle-close { display: none; }

/* Overlay — hidden by default */
.nav__overlay {
  position:       fixed;
  inset:          0;
  /* Above .modal (z-index: 200), matching .nav — otherwise tapping
     the now-reachable hamburger toggle while a project modal is open
     would render this overlay behind the modal, invisibly. */
  z-index:        300;
  background:     var(--color-bg);
  display:        flex;
  align-items:    flex-end;
  padding:        var(--space-page-pad);
  padding-bottom: calc(var(--space-page-pad) * 2);
  opacity:        0;
  pointer-events: none;
  transform:      translateY(-2rem);
  transition:     opacity 0.2s ease-in-out, transform 0.2s ease-in-out;
}

.nav__overlay-links {
  display:        flex;
  flex-direction: column;
  gap:            var(--space-sm);
}

.nav__overlay-link {
  font-size:      var(--fs-xl);
  font-weight:    400;
  letter-spacing: -0.02em;
  line-height:    1.1;
  transition:     color 0.2s ease-in-out;
}

.nav__overlay-link:hover {
  color: var(--color-muted);
}

/* Open state — JS adds .menu-open to <body> */
body.menu-open .nav__overlay {
  opacity:        1;
  pointer-events: auto;
  transform:      translateY(0);
}

body.menu-open .nav__toggle-open  { display: none; }
body.menu-open .nav__toggle-close { display: inline; }

body.menu-open { overflow: hidden; }


/* ============================================================
   INTRO CURTAIN
   Solid overlay holds the page for a beat while a single line
   mark draws in, then lifts as the hero reveal fires beneath it.
   ============================================================ */

#curtain {
  position:        fixed;
  inset:            0;
  z-index:          9999;
  display:          flex;
  align-items:      center;
  justify-content:  center;
  background:       var(--color-bg);
  opacity:          1;
  transition:       opacity 0.2s ease;
}

#curtain.curtain--hidden {
  opacity:        0;
  pointer-events: none;
}

.curtain__mark {
  width:      4.8rem;
  height:     1px;
  background: var(--color-text);
  transform:  scaleX(0);
  transition: transform 0.2s cubic-bezier(0.16, 1, 0.3, 1);
}

#curtain.curtain--drawn .curtain__mark {
  transform: scaleX(1);
}

body.curtain-active {
  overflow: hidden;
}


/* ============================================================
   HERO
   ============================================================ */

.hero {
  position:          relative;
  min-height:        100vh;
  box-sizing:        border-box;
  scroll-snap-align: start;
  padding:           var(--space-hero-top) var(--space-page-pad) var(--space-hero-bottom);
  overflow:          hidden;
}

.hero::before {
  content:    "";
  position:   absolute;
  inset:      0;
  z-index:    0;
  background: radial-gradient(circle at 30% 30%, rgba(242, 242, 240, 0.05), transparent 38%),
              radial-gradient(circle at 70% 70%, rgba(242, 242, 240, 0.04), transparent 38%);
  mask-image:         linear-gradient(to bottom, transparent 0%, black 18%, black 82%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, transparent 0%, black 18%, black 82%, transparent 100%);
  opacity:    0;
  transition: opacity 1.2s ease;
  animation:  hero-drift 18s ease-in-out infinite;
  animation-play-state: paused;
  pointer-events: none;
}

.hero--visible::before {
  opacity:               1;
  animation-play-state:  running;
}

.hero__heading {
  position: relative;
  z-index:  1;
}

@keyframes hero-drift {
  0%   { transform: translate(0, 0) scale(1); }
  50%  { transform: translate(-3%, 2%) scale(1.08); }
  100% { transform: translate(0, 0) scale(1); }
}

.hero__heading {
  font-size:      var(--fs-hero);
  font-weight:    400;
  letter-spacing: -0.02em;
  line-height:    0.82;
}


/* ============================================================
   SECTION — shared
   ============================================================ */

.section {
  min-height:        100vh;
  box-sizing:        border-box;
  scroll-snap-align: start;
  padding:           var(--space-hero-top) var(--space-page-pad) var(--space-section-top);
  margin-top:        8rem;
}

.section__header {
  display:         flex;
  align-items:     baseline;
  justify-content: space-between;
  gap:             var(--space-md);
  margin-bottom:   var(--space-md);
}

.section__title {
  font-size:      var(--fs-xl);
  font-weight:    400;
  letter-spacing: -0.02em;
  line-height:    1;
}

.section__label {
  font-size:      var(--fs-sm);
  font-weight:    500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  line-height:    1.2;
  color:          var(--color-muted);
  text-align:     right;
}

.section__label--link {
  transition: color 0.2s ease-in-out;
}

.section__label--link:hover {
  color: var(--color-muted);
}

.section__divider {
  margin-bottom: var(--space-lg);
}



/* ============================================================
   ABOUT
   ============================================================ */

.about__body {
  overflow:       hidden;
  padding-bottom: 0.1em;
}

/* Only fade in — let the inner text handle the wipe motion */
.about__body[data-reveal] {
  transform: none;
}
.about__body[data-reveal].is-visible {
  transform: none;
}

.about__text {
  font-size:      var(--fs-xl);
  font-weight:    400;
  line-height:    1.1;
  letter-spacing: -0.02em;
  transform:      translateY(110%);
  transition:     transform 1.2s cubic-bezier(0.16, 1, 0.3, 1) 0.15s;
}

.about__body.is-visible .about__text {
  transform: translateY(0);
}

.about__cols {
  display:               grid;
  grid-template-columns: 1fr 1fr;
  gap:                   var(--space-lg);
  margin-top:            var(--space-lg);
  margin-bottom:         var(--space-lg);
}

.about__col-text {
  font-size:   var(--fs-body);
  line-height: 1.6;
  color:       var(--color-muted);
}

/* Paragraphs otherwise sit flush (global reset zeroes p margin) — see
   the matching comment on .modal-block--text p. */
.about__col-text p {
  margin-bottom: 1em;
}

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

.about__col-text a {
  transition: color 0.2s ease-in-out;
}

.about__col-text a:hover {
  color: var(--color-text);
}


/* ============================================================
   WORK
   ============================================================ */

.work__grid {
  display:               grid;
  grid-template-columns: repeat(2, minmax(30rem, 1fr));
  gap:                   12rem;
  margin-bottom:         var(--space-lg);
}

.work__card-image {
  position:      relative;
  aspect-ratio:  16 / 9;
  overflow:      hidden;
  margin:        0;
  margin-bottom: var(--space-xs);
  background:    #111;
}

.work__card-image img {
  width:      100%;
  height:     100%;
  object-fit: cover;
}

.work__card-image--contain img {
  object-fit: contain;
}

.work__card-title {
  font-size:      var(--fs-body);
  letter-spacing: -0.01em;
  line-height:    1.1;
  margin-bottom:  0.4rem;
}

.work__card-category {
  font-size:      var(--fs-sm);
  font-weight:    500;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color:          var(--color-muted);
}


/* ============================================================
   SERVICES
   ============================================================ */

.services__list {
  margin-top: 0;
}

/* Each item is a two-row grid: bar / expand zone */
.services__item {
  display:               grid;
  grid-template-rows:    auto 0fr;
  border-top:            1px solid var(--color-border);
  transition:            grid-template-rows 0.4s ease-in-out;
  overflow:              hidden;
}

.services__item:last-child {
  border-bottom: 1px solid var(--color-border);
}

.services__item.is-open {
  grid-template-rows: auto 1fr;
}

/* Clickable bar — full-width button reset */
.services__bar {
  display:     grid;
  grid-template-columns: 6rem 1fr 2fr auto;
  align-items: baseline;
  gap:         var(--space-service-gap);
  padding:     var(--space-service-row) var(--space-xs);
  width:       100%;
  background:  none;
  border:      none;
  color:       inherit;
  font-family: inherit;
  text-align:  left;
  cursor:      pointer;
}

.services__number {
  font-size:      var(--fs-body);
  font-weight:    500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color:          var(--color-muted);
  line-height:    1.4;
  transition:     color 0.2s ease-in-out;
}

.services__name {
  font-size:      var(--fs-md);
  font-weight:    400;
  letter-spacing: -0.02em;
  line-height:    1.05;
  transition:     color 0.2s ease-in-out;
}

.services__desc {
  font-size:   var(--fs-body);
  line-height: 1.6;
  color:       var(--color-muted);
  transition:  color 0.2s ease-in-out;
}

.services__arrow {
  font-size:      var(--fs-body);
  color:          var(--color-muted);
  line-height:    1;
  justify-self:   end;
  transition:     transform 0.4s ease-in-out, color 0.2s ease-in-out;
}

.services__item.is-open .services__arrow {
  transform: rotate(180deg);
}

.services__item.is-open .services__number {
  color: var(--color-text);
}

/* Hover state — soft lift, number brightens */
.services__bar {
  transition: background 0.2s ease;
}

.services__bar:hover {
  background: rgba(242, 242, 240, 0.035);
}

.services__bar:hover .services__number,
.services__bar:hover .services__arrow {
  color: var(--color-text);
}

/* Expand zone */
.services__expand {
  overflow: hidden;
  min-height: 0;
}

.services__expand-inner {
  display:     grid;
  grid-template-columns: 6rem 1fr 2fr auto;
  gap:         var(--space-service-gap);
  padding:     var(--space-sm) var(--space-xs) var(--space-service-row);
  color:       var(--color-muted);
  font-size:   var(--fs-body);
  line-height: 1.6;
}

/* Align expand content under the name column (col 2). A stable
   wrapper (not a tag selector) since content_blocks renders a mix of
   <p> (Text layout) and <div> (Rich Text/Audio/Video/Two Column) —
   a tag-specific selector would only correctly grid-position the
   plain Text layout, leaving everything else to fall to the grid's
   default auto-placement. Blocks handle their own spacing via the
   shared .modal-block / .modal-block:last-child rules. */
.services__expand-inner > .services__expand-blocks {
  grid-column: 2 / 4;
}

.services__expand-inner a {
  transition: color 0.2s ease-in-out;
}

.services__expand-inner a:hover {
  color: var(--color-text);
}


/* ============================================================
   CLIENTS
   ============================================================ */

.clients__grid {
  display:               grid;
  grid-template-columns: repeat(4, 1fr);
  gap:                   var(--space-lg);
}

.clients__col {
  padding-bottom: var(--space-sm);
}

.clients__col--offset {
  padding-top: calc(var(--fs-md) * 1.2);
}

.clients__text {
  font-size:   var(--fs-md);
  line-height: 1.2;
  font-weight: normal;
}

.clients__text a:hover {
  color: var(--color-muted);
}


/* ============================================================
   CONTACT & FOOTER
   ============================================================ */

.footer {
  min-height:        25vh;
  scroll-snap-align: start;
  padding:           0 var(--space-page-pad) var(--space-md);
}

.footer__divider {
  margin-bottom: var(--space-sm);
}

.footer__inner {
  display:         flex;
  justify-content: space-between;
  align-items:     baseline;
}

.footer__brand {
  font-size:   var(--fs-body);
  line-height: 1;
}

.footer__copy {
  font-size:      var(--fs-sm);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color:          var(--color-muted);
}


/* ============================================================
   HERO REVEAL
   Lines wipe upward on load. Overflow hidden on parent clips
   each line during the translate, creating a mask effect.
   ============================================================ */

.hero__line {
  display:      block;
  overflow:     hidden;
  padding-bottom: 0.12em; /* prevent descender clipping at tight line-height */
}

.hero__line-inner {
  display:    block;
  transform:  translateY(110%);
  filter:     blur(8px);
  color:      var(--color-bg);
  transition: transform 1.2s cubic-bezier(0.16, 1, 0.3, 1),
              filter    1.4s ease-out,
              color     1.4s ease-out;
}

.hero--visible .hero__line:nth-child(1) .hero__line-inner {
  transform:         translateY(0);
  filter:            blur(0);
  color:             var(--color-text);
  transition-delay:  0.075s;
}

.hero--visible .hero__line:nth-child(2) .hero__line-inner {
  transform:         translateY(0);
  filter:            blur(0);
  color:             var(--color-text);
  transition-delay:  0.33s;
}

.hero--visible .hero__line:nth-child(3) .hero__line-inner {
  transform:         translateY(0);
  filter:            blur(0);
  color:             var(--color-text);
  transition-delay:  0.585s;
}


/* ============================================================
   SCROLL REVEAL
   Elements tagged [data-reveal] start invisible and translate
   up into view as they enter the viewport via IntersectionObserver.
   Stagger delays set per component via --reveal-delay token.
   ============================================================ */

[data-reveal] {
  opacity:    0;
  transform:  translateY(2rem);
  transition: opacity 0.6s ease-in-out var(--reveal-delay, 0s),
              transform 0.6s ease-in-out var(--reveal-delay, 0s);
}

[data-reveal].is-visible {
  opacity:   1;
  transform: translateY(0);
}

/* Stagger work cards by column position */
.work__card:nth-child(2) { --reveal-delay: 0.1s; }
.work__card:nth-child(3) { --reveal-delay: 0.05s; }
.work__card:nth-child(4) { --reveal-delay: 0.15s; }

/* Stagger services items */
.services__item:nth-child(2) { --reveal-delay: 0.06s; }
.services__item:nth-child(3) { --reveal-delay: 0.12s; }
.services__item:nth-child(4) { --reveal-delay: 0.18s; }
.services__item:nth-child(5) { --reveal-delay: 0.24s; }
.services__item:nth-child(6) { --reveal-delay: 0.30s; }

/* Elements that need both scroll-reveal AND their own expand transition.
   Specificity (0,2,0) beats the individual [data-reveal] (0,1,0) and
   .services__item / .work__card (0,1,0) rules above — merging both. */
.services__item[data-reveal] {
  transition: grid-template-rows 0.4s ease-in-out,
              opacity 0.6s ease-in-out var(--reveal-delay, 0s),
              transform 0.6s ease-in-out var(--reveal-delay, 0s);
}


/* ============================================================
   WORK CARD — THUMBNAIL GRID
   Cards are pure thumbnails; click opens the modal.
   ============================================================ */

.work__card {
  cursor: pointer;
}

.work__card-play {
  position:        absolute;
  inset:           0;
  display:         flex;
  align-items:     center;
  justify-content: center;
  background:      rgba(0, 0, 0, 0.35);
  opacity:         0;
  transition:      opacity 0.2s ease-in-out;
}

.work__card:hover .work__card-play {
  opacity: 1;
}

/* Equalizer — inert until hovered, so it never animates off-screen */
.work__card-eq {
  display:     flex;
  align-items: flex-end;
  gap:         0.5rem;
  height:      2.4rem;
}

.work__card-eq-bar {
  width:                0.1rem;
  height:               100%;
  background:           var(--color-text);
  transform:            scaleY(0.35);
  transform-origin:     bottom;
  animation:            eq-pulse 1s ease-in-out infinite;
  animation-play-state: paused;
}

.work__card:hover .work__card-eq-bar {
  animation-play-state: running;
}

.work__card-eq-bar:nth-child(1) { animation-delay: 0s;    }
.work__card-eq-bar:nth-child(2) { animation-delay: 0.15s; }
.work__card-eq-bar:nth-child(3) { animation-delay: 0.3s;  }
.work__card-eq-bar:nth-child(4) { animation-delay: 0.45s; }

@keyframes eq-pulse {
  0%, 100% { transform: scaleY(0.35); }
  50%      { transform: scaleY(1);    }
}


/* ============================================================
   WORK MODAL
   Full-screen takeover. Fades in; inner content slides up.
   iframe injected on open, cleared on close to stop playback.
   ============================================================ */

.modal {
  position:       fixed;
  inset:          0;
  z-index:        200;
  overflow-y:     auto;
  background:     var(--color-bg);
  opacity:        0;
  pointer-events: none;
  transition:     opacity 0.4s ease;
}

.modal.is-open {
  opacity:        1;
  pointer-events: auto;
}

body.modal-open {
  overflow: hidden;
}

.modal__inner {
  min-height:  100vh;
  padding:     var(--space-page-pad);
  /* Nav now sits above the modal (z-index) rather than being covered
     by it — this clears .modal__close from nav's ~6.8rem height
     (--space-nav-v padding + content), a fixed estimate rather than
     JS-measured for simplicity. Nudge if it's slightly off on either
     breakpoint rather than reaching for exact measurement. */
  padding-top: calc(var(--space-page-pad) + 3rem);
  max-width:   1400px;
  margin:      0 auto;
  transform:   translateY(2.4rem);
  transition:  transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.modal.is-open .modal__inner {
  transform: translateY(0);
}

.modal__close {
  display:        block;
  margin-left:    auto;
  margin-bottom:  var(--space-sm);
  background:     none;
  border:         none;
  color:          var(--color-muted);
  font-family:    inherit;
  font-size:      var(--fs-body);
  cursor:         pointer;
  padding:        0;
  transition:     color 0.2s ease;
}

.modal__close:hover {
  color: var(--color-text);
}

/* Prev/next — desktop only, hidden below 1200px in breakpoints.css.
   Fixed to the viewport, vertically centered (top: 50% + the
   translateY below), so they sit in the same spot on every project
   regardless of scroll position or content height — deliberately NOT
   aligned to the video's own position, which used to be JS-measured
   and broke when scrolled deep into a tall project's content before
   navigating (the video's rect could be far off-screen at that
   moment). Left/right still can't be done in CSS alone (the media is
   centered in a max-width column with variable surrounding space) —
   JS sets `left` to the video's own edges on open/navigate/resize,
   clamped to the viewport edge; see positionModalNav() in script.js. */
.modal__nav {
  position:    fixed;
  top:         50%;
  transform:   translateY(-50%);
  z-index:     1;
  background:  none;
  border:      none;
  color:       var(--color-muted);
  font-size:   2.4rem;
  line-height: 1;
  cursor:      pointer;
  padding:     var(--space-sm);
  opacity:     0;
  transition:  color 0.2s ease, opacity 0.2s ease, left 0.2s ease;
}

/* Set once JS has measured a real (post-opening-transition)
   position — prevents a visible snap into place on first use. Also
   eases any later repositioning (e.g. clicking an arrow after the
   modal's own description text has been scrolled) instead of
   snapping — invisible everywhere else, since position doesn't
   actually change on open (masked by the opacity fade) or between
   projects (the video box itself doesn't move). */
.modal__nav.is-positioned {
  opacity: 1;
}

.modal__nav:hover {
  color: var(--color-text);
}

/* Content that swaps on navigation — fades/slides in the
   direction of travel. The "jump" class strips the transition
   for one frame so the entry position isn't itself animated. */
.modal__content {
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.modal__content--jump {
  transition: none;
}

.modal__content--offset-left {
  opacity:   0;
  transform: translateX(-1.6rem);
}

.modal__content--offset-right {
  opacity:   0;
  transform: translateX(1.6rem);
}

.modal__video {
  aspect-ratio: 16 / 9;
  background:   #000;
  width:        100%;
  margin-bottom: var(--space-lg);
}

.modal__video iframe {
  display:    block;
  width:      100%;
  height:     100%;
  border:     none;
  filter:     grayscale(60%);
  transition: filter 0.3s ease;
}

.modal__video:hover iframe {
  filter: grayscale(0%);
}

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

.modal__body {
  border-top: 1px solid var(--color-border);
  padding-top: var(--space-md);
}

.modal__header {
  display:         flex;
  justify-content: space-between;
  align-items:     baseline;
  /* gap:             var(--space-md); */
  margin-bottom:   var(--space-md);
  flex-wrap:       wrap;
}

.modal__title {
  font-size:      var(--fs-xl);
  font-weight:    400;
  letter-spacing: -0.02em;
  line-height:    1.05;
}

.modal__meta {
  display:     flex;
  gap:         var(--space-xs);
  flex-shrink: 1;
}

.modal__client,
.modal__year,
.modal__category {
  font-size:      var(--fs-sm);
  font-weight:    500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color:          var(--color-muted);
}

/* WYSIWYG "Meta Label" style (Format dropdown, see inc/admin.php) —
   same size/weight/spacing/case as .modal__client, applied to whatever
   text an editor selects. Color intentionally left unset so it still
   inherits its surrounding context's color (muted body text, or white
   on link hover) rather than fixing it to one value. */
.wysiwyg-label {
  font-size:      var(--fs-sm);
  font-weight:    500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Hidden for now — see theme-updates.md. Year is still populated by
   script.js/section-work.php underneath, so this is a one-line revert
   whenever it's wanted back. */
.modal__year {
  display: none;
}

.modal__description {
  font-size:     var(--fs-md);
  line-height:   1.2;
  color:         var(--color-text);
  /* max-width:     64ch; */
  margin-bottom: var(--space-lg);
}

.modal__description p {
  margin-bottom: 1em;
}

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

.modal__description a {
  transition: color 0.2s ease-in-out;
}

.modal__description a:hover {
  color: var(--color-muted);
}

/* ============================================================
   MODAL CONTENT BLOCKS
   A work project's optional content_blocks (ACF Flexible Content):
   text, an audio player, or a two-column mix of either, in whatever
   order the editor set. Text blocks keep the same readable-width
   constraint .modal__description uses; the two-column layout
   deliberately does not, so each side has real room — mirrors
   .about__cols's grid, collapsed to one column on mobile in
   breakpoints.css.
   ============================================================ */

.modal__blocks {
  margin-bottom: 8rem;
}

.modal-block {
  margin-bottom: var(--space-lg);
}

.modal-block:last-child {
  margin-bottom: 0;
}

/* Per-instance divider, toggled per-block in the admin (see
   inc/content-blocks.php) — never a per-type style, so turning this on
   for one block never affects any other block sharing its class.
   Composes with the block's own existing margin-bottom above: this
   adds the visible line plus a little extra room below it, the
   existing margin-bottom still provides the gap to whatever's next. */
.modal-block--has-divider {
  border-bottom:  1px solid var(--color-border);
  padding-bottom: var(--space-md);
}

.modal-block--text {
  font-size:   var(--fs-body);
  line-height: 1.2;
  color:       var(--color-muted);
}

/* Only the plain-text layout renders as a <p> with raw newlines that
   need preserving — Rich Text renders as a <div> whose line breaks are
   already real <p>/<br> tags, and applying pre-line there as well
   double-renders whitespace already present between its own tags. */
p.modal-block--text {
  white-space: pre-line;
}

/* Rich Text's own paragraphs otherwise sit flush against each other
   (global reset zeroes p margin) — a single Enter is then visually
   indistinguishable from the browser just wrapping text at that width.
   Real spacing makes an intentional break legible on its own. */
.modal-block--text p {
  margin-bottom: 1em;
}

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

.modal-block--text a {
  transition: color 0.2s ease-in-out;
}

.modal-block--text a:hover {
  color: var(--color-text);
}

.modal-block--columns {
  display:               grid;
  grid-template-columns: 1fr 1fr;
  gap:                   var(--space-sm);
}

.modal-block--columns .modal-block--text {
  max-width:     none;
  margin-bottom: 0;
}

.modal-block--columns .modal-block--audio {
  margin-bottom: 0;
}

.modal-block--columns .modal-block--video {
  margin-bottom: 0;
}

/* Safeguard, not an expected editorial state: the columns repeater
   allows 0-2 rows, so a two_column block could exist with only one
   column filled. Without this, CSS Grid's default auto-placement
   leaves that lone item at 50% width with empty space beside it
   rather than filling the row. */
.modal-block--columns > *:only-child {
  grid-column: 1 / -1;
}

.modal-block--video {
  aspect-ratio: 16 / 9;
  background:   #000;
}

.modal-block--video iframe {
  display:    block;
  width:      100%;
  height:     100%;
  border:     none;
  filter:     grayscale(60%);
  transition: filter 0.3s ease;
}

/* Secondary video embeds (this content-block type, not the main
   project video in .modal__video) otherwise sit at full third-party
   color/saturation against an otherwise muted, monochrome site —
   visually loud next to plain text. Desaturated at rest, full color
   on hover signals "this is about to play" rather than a random
   bright tile dropped into the page. */
.modal-block--video:hover iframe {
  filter: grayscale(0%);
}


/* ============================================================
   CUSTOM CURSOR
   Two-element cursor: dot follows instantly, ring lerps behind.
   Only active on true pointer devices (hover: hover, pointer: fine).
   ============================================================ */

@media (hover: hover) and (pointer: fine) {
  body,
  a,
  button,
  [tabindex],
  .work__card,
  .services__bar,
  .modal__close,
  .modal__nav { cursor: none; }
}

/* Single circle, moving in exact sync with the pointer — no lag.
   Difference blend inverts it against whatever's actually rendered
   underneath (dark bg → white cursor, bright image content →
   cursor reads dark) — needs a fully opaque color, since alpha
   would blend only partially and muddy the invert. JS drives
   position via `transform` on every mousemove, so hover feedback
   is a width/height change instead of scale — a second transform
   would fight the position updates and reintroduce lag.
   translate(-50%, -50%) keeps it centered on the pointer as the
   size changes, since percentages resolve against its own box. */
#cursor-dot {
  position:       fixed;
  top:            0;
  left:           0;
  z-index:        9995;
  width:          12px;
  height:         12px;
  border-radius:  50%;
  background:     var(--color-text);
  pointer-events: none;
  will-change:    transform;
  mix-blend-mode: difference;
  transition:     width 0.2s ease, height 0.2s ease;
}

body.cursor--hover #cursor-dot {
  width:  24px;
  height: 24px;
}

@media (hover: none), (pointer: coarse) {
  #cursor-dot { display: none; }
}


/* ============================================================
   SECTION INDICATOR
   Fixed bottom-right. Name in text-colour, count in muted.
   Hidden on mobile.
   ============================================================ */

#section-indicator {
  position:       fixed;
  bottom:         var(--space-page-pad);
  right:          var(--space-page-pad);
  z-index:        150;
  display:        flex;
  gap:            0;
  align-items:    baseline;
  font-size:      var(--fs-sm);
  font-weight:    500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  pointer-events: none;
}

#indicator-name { color: var(--color-text); }
#indicator-sep,
#indicator-count { color: var(--color-muted); }

#indicator-name,
#indicator-count {
  display:    inline-block;
  transition: opacity 0.2s ease, transform 0.2s ease;
}

#section-indicator.is-updating #indicator-name,
#section-indicator.is-updating #indicator-count {
  opacity:   0;
  transform: translateY(3px);
}

@media (max-width: 767px) {
  #section-indicator { display: none; }
}


/* ============================================================
   WORK CARD — IMAGE HOVER
   Slight scale + brightness lift on hover. Overflow on the
   figure clips the scale cleanly.
   ============================================================ */

.work__card-image img {
  transition: transform 0.2s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              filter    0.2s ease;
  filter: brightness(0.8);
}

.work__card:hover .work__card-image img {
  transform: scale(1.04);
  filter:    brightness(1);
}
