/* components.css */

/* =====================
   NAV / FOLDER TABS
   ===================== */

.site-nav {
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 12px clamp(24px, 5vw, 80px) 20px;
  transition: backdrop-filter 0.3s ease, box-shadow 0.3s ease, background-color var(--transition-color);
}

.site-nav.scrolled {
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: 0 1px 0 var(--stroke-subtle);
}

.nav-inner {
  display: flex;
  align-items: center;
  gap: 0;
}

.nav-tabs {
  display: flex;
  align-items: center;
  gap: 4px;
  flex: 1;
}

.nav-tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  padding: 10px 20px;
  background-color: var(--bg-surface);
  border: 1.5px solid var(--stroke);
  border-bottom: none;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-decoration: none;
  cursor: pointer;
  transition: background-color var(--transition-color), color var(--transition-color), border-color var(--transition-color);
  border-radius: 0 6px 0 0;
  will-change: transform;
}

/* Tab ear */
.nav-tab::before {
  content: '';
  position: absolute;
  top: -10px;
  left: -1px;
  width: 32px;
  height: 10px;
  background-color: var(--bg-surface);
  border: 1.5px solid var(--stroke);
  border-bottom: none;
  border-radius: 6px 6px 0 0;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

/* Inactive tab has full border */
.nav-tab.inactive {
  border-bottom: 1.5px solid var(--stroke);
  color: var(--text-muted);
}

/* Active tab */
.nav-tab.active {
  color: var(--text);
  z-index: 2;
  border-bottom: none;
  background-color: var(--bg-surface);
}

.nav-tab.active::before {
  background-color: var(--accent);
  border-color: var(--accent);
}

/* Active tab hover ear stays accent */
.nav-tab.active:hover::before {
  background-color: var(--accent);
}

/* Inactive hover ear */
.nav-tab:not(.active):hover::before {
  background-color: var(--bg-raised);
  transition: background-color var(--transition-fast);
}

/* Lottie contact tab — no box, no ear */
.nav-tab.nav-tab--lottie,
.nav-tab.nav-tab--lottie.active,
.nav-tab.nav-tab--lottie.inactive {
  border: none;
  background: none;
  padding: 0;
  align-self: center;
  color: #1E1E1E;
}

.nav-tab--lottie::before {
  display: none;
}

.nav-lottie {
  width: 82.5px;
  height: 60.5px;
  display: block;
  opacity: 0;
  transition: opacity 0.15s ease;
}

.nav-lottie.loaded {
  opacity: 1;
}

.nav-lottie svg text,
.nav-lottie svg tspan {
  fill: #1E1E1E !important;
}

/* Nav name / home link */
.nav-name {
  display: inline-flex;
  align-items: center;
  height: 60.5px;
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 3rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text);
  text-decoration: none;
  margin-top: 8px;
  margin-right: 28px;
  transition: color var(--transition-fast);
}

.nav-name:hover {
  color: var(--text-muted);
}

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

.work-card-link {
  display: block;
  text-decoration: none;
  color: inherit;
}

/* Works-in-progress cards don't link anywhere. */
.work-card-link--wip {
  cursor: default;
}

.work-card {
  position: relative;
  background-color: var(--bg-surface);
  border: none;
  outline: 1.5px solid var(--stroke);
  border-radius: 0 8px 8px 8px;
  overflow: visible;
  margin-top: 25px;
  transition: background-color var(--transition-color), outline-color var(--transition-color);
  will-change: transform;
}

@media (-webkit-max-device-pixel-ratio: 1.99), (max-resolution: 1.99dppx) {
  .work-card {
    outline-width: 2px;
    outline-offset: -1px;
  }
  .card-ear {
    left: -1px;
  }
}

/* Card ear */
.card-ear {
  position: absolute;
  top: -24px;
  left: -1.5px;
  width: 152px;
  height: 25px;
  overflow: visible;
  pointer-events: none;
  z-index: 1;
}

.card-ear-fill {
  fill: var(--bg-raised);
  transition: fill var(--transition-fast);
}

.work-card:hover .card-ear-fill {
  fill: #F1E2C5;
}

.work-card:hover {
  background-color: #F1E2C5;
}

.card-ear-stroke {
  fill: var(--stroke);
  transition: fill var(--transition-color);
}

/* Card image area */
.card-image {
  width: 100%;
  aspect-ratio: 3 / 2;
  border-bottom: 1.5px solid var(--stroke-subtle);
  border-radius: 0 6px 0 0;
  overflow: hidden;
  transition: border-color var(--transition-color);
}

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

/* Card body */
.card-body {
  padding: 20px 24px 24px;
}

.card-title {
  display: block;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-sm);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
  line-height: var(--lh-body);
  margin-bottom: 6px;
  transition: color var(--transition-color);
}

/* Tags */
.tag-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 12px;
}

.tag {
  display: inline-flex;
  align-items: center;
  padding: 4px 10px;
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 6px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--text);
  transition: background-color var(--transition-fast), border-color var(--transition-color), color var(--transition-color);
}

.work-card:hover .tag {
  background-color: #FFF9EB;
}

/* Per-tag pastel colours on card hover */
.work-card:hover .tag[data-tag="content-design"]  { background-color: #C5EAFF; color: oklch(38% 0.14 235); }
.work-card:hover .tag[data-tag="content-strategy"] { background-color: #C3EFB8; color: oklch(36% 0.14 148); }
.work-card:hover .tag[data-tag="ux-writing"]       { background-color: oklch(91% 0.05 293); color: oklch(38% 0.14 293); }
.work-card:hover .tag[data-tag="user-research"]    { background-color: #FFCEF0; color: oklch(38% 0.14 18); }
.work-card:hover .tag[data-tag="ux-design"]        { background-color: #FFE0C2; color: oklch(42% 0.13 55); }

.card-description {
  display: block;
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-3xl);
  font-weight: 700;
  color: var(--text);
  line-height: var(--lh-heading);
  transition: color var(--transition-color);
}

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

.hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-start;
  padding: 48px clamp(24px, 5vw, 80px) 64px;
  background-color: var(--bg);
  transition: background-color var(--transition-color);
}

.hero-clip {
  overflow: visible;
}

.hero h1 {
  font-style: normal;
  max-width: 900px;
  color: var(--text);
  transition: color var(--transition-color);
}

.hero-sub {
  font-size: var(--text-xl);
  font-weight: 500;
  margin-top: 24px;
  max-width: 700px;
  transition: color var(--transition-color);
}

/* =====================
   BRANDS SECTION
   ===================== */

.brands-clip,
.works-clip {
  overflow: hidden;
}

.card-clip-wrap {
  overflow: hidden;
  padding: 8px 2px 10px;
}

.card-clip-wrap.is-hidden {
  display: none;
}

.brands-section {
  padding: 30px clamp(24px, 5vw, 80px);
  background-color: var(--bg);
  transition: background-color var(--transition-color);
}

.brands-section h2 {
  font-size: var(--text-4xl);
  text-align: center;
  margin-bottom: 48px;
  color: var(--text);
  transition: color var(--transition-color);
}

.brands-row {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 24px 32px;
  align-items: center;
  justify-items: center;
}

@media (min-width: 600px) {
  .brands-row {
    grid-template-columns: repeat(3, 1fr);
    gap: 28px 40px;
  }
}

@media (min-width: 900px) {
  .brands-row {
    grid-template-columns: repeat(5, 1fr);
    gap: 32px 48px;
  }
}

.brand-logo {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
}

.brand-logo img {
  width: 100px;
  height: 40px;
  display: block;
  object-fit: contain;
}

.brand-logo img[alt="Pan Pacific"] {
  width: 120px;
  height: 48px;
}

@media (min-width: 600px) {
  .brand-logo img {
    width: 160px;
    height: 64px;
  }

  .brand-logo img[alt="Pan Pacific"] {
    width: 200px;
    height: 80px;
  }
}


/* =====================
   FEATURED SECTION
   ===================== */

.featured-section {
  padding: 80px clamp(24px, 5vw, 80px) 1px;
  background-color: var(--bg);
  transition: background-color var(--transition-color);
}

@media (min-width: 600px) {
  .works-clip {
    overflow: visible;
  }

  .featured-section {
    overflow: hidden;
    padding-bottom: 80px;
  }

  .featured-section .grid-gallery {
    display: flex;
    flex-wrap: nowrap;
    grid-template-columns: unset;
    max-width: none;
    width: max-content;
    margin: 0;
    gap: 24px;
    padding-right: clamp(24px, 5vw, 80px);
  }

  .featured-section .card-clip-wrap {
    flex: 0 0 clamp(250px, 32vw, 430px);
    width: clamp(250px, 32vw, 430px);
  }
}

@media (min-width: 600px) and (min-height: 900px) {
  .featured-section {
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    padding-top: 0;
    padding-bottom: 0;
  }
}

.featured-section h2 {
  font-size: var(--text-4xl);
  color: var(--text);
  margin-bottom: 24px;
  transition: color var(--transition-color);
}

/* Featured: heading and filter share one line to free vertical space */
.featured-header {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 12px 18px;
  margin-bottom: 24px;
}

.featured-header h2 {
  margin-bottom: 0;
}

.featured-header .works-filter {
  margin-bottom: 0;
}

/* Divider between the heading and the filter, matching the filter's | */
.featured-sep {
  font-size: var(--text-base);
  font-weight: 500;
}

/* Works filter bar */
.works-filter {
  display: flex;
  align-items: baseline;
  gap: 10px;
  margin-bottom: 30px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-base);
  font-weight: 500;
}

.works-filter-label {
  color: var(--text-muted);
  transition: color var(--transition-color);
}

.filter-sep {
  color: var(--text-muted);
  transition: color var(--transition-color);
}

.filter-btn {
  background: none;
  border: none;
  padding: 0;
  cursor: pointer;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--text);
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 1.5px;
  transition: color var(--transition-color), background-size 0.35s ease;
}

.filter-btn:hover {
  background-size: 100% 1.5px;
}

.filter-btn.active {
  background-size: 100% 1.5px;
  pointer-events: none;
}

.work-card-link.is-hidden {
  display: none;
}

/* =====================
   FOOTER
   ===================== */

.footer-clip {
  position: sticky;
  bottom: 0;
  z-index: 0;
}

body[data-page="contact"] .footer-clip {
  display: none;
}

body[data-page="contact"] main {
  min-height: unset;
}

.site-footer {
  background-color: var(--bg-surface);
  border-top: 1px solid var(--stroke-subtle);
  padding: 40px clamp(24px, 5vw, 80px);
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

.footer-row-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 24px;
}

.footer-nav {
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: flex-end;
}

.footer-nav a {
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--text);
  text-decoration: none;
  transition: color var(--transition-color);
}

.footer-nav a:hover {
  color: var(--accent);
}

.footer-row-bottom {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.footer-header {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: 3rem;
  font-weight: 700;
  line-height: 1;
  color: var(--text);
  text-decoration: none;
}

.footer-left {
  display: flex;
  flex-direction: column;
  gap: 16px;
}

.footer-contact-links {
  display: flex;
  gap: 24px;
}

.footer-contact-link {
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-base);
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 1.5px;
  transition: color var(--transition-color), background-size 0.35s ease;
}

.footer-contact-link:hover {
  background-size: 100% 1.5px;
}

.footer-copy {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  transition: color var(--transition-color);
}

@media (max-width: 600px) {
  .footer-row-top,
  .footer-row-bottom {
    flex-direction: column;
    align-items: flex-start;
    gap: 16px;
  }

  .footer-nav {
    flex-wrap: wrap;
    gap: 12px;
  }
}

/* =====================
   CASE STUDY LAYOUT
   ===================== */

.case-study-layout {
  display: grid;
  grid-template-columns: var(--nav-name-width, 240px) 1fr;
  grid-template-areas:
    "sidebar back"
    "sidebar content";
  gap: 28px;
  padding: 60px clamp(24px, 5vw, 80px);
  align-items: start;
}

.case-study-layout > .back-link { grid-area: back; margin-bottom: 0; }
.case-study-sidebar { grid-area: sidebar; }
.case-study-content { grid-area: content; }

.case-study-sidebar {
  position: sticky;
  top: 104px;
}

.sidebar-nav {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 0;
}

/* A single short bar that slides between chapters. Created by JS; the per-link
   active border below is the no-JS / reduced-motion fallback. */
.sidebar-indicator {
  position: absolute;
  left: 0;
  top: 0;
  width: 2px;
  height: 18px;
  background-color: var(--accent);
  border-radius: 1px;
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), width 0.4s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

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

.sidebar-nav a {
  display: block;
  padding: 10px 16px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--text-muted);
  text-decoration: none;
  border-left: 2px solid transparent;
  transition: color var(--transition-fast), border-color var(--transition-fast);
}

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

.sidebar-nav a.active {
  color: var(--accent);
  border-left-color: var(--accent);
}

/* When the sliding indicator is active, drop the per-link border (the bar
   replaces it). */
.sidebar-nav.js-indicator a.active {
  border-left-color: transparent;
}

/* Metadata row */
.metadata-row {
  display: flex;
  flex-wrap: wrap;
  gap: 24px;
  margin-top: 24px;
  padding: 24px;
  background-color: var(--bg-surface);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

.metadata-item {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.metadata-label {
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  transition: color var(--transition-color);
}

.metadata-value {
  font-size: var(--text-sm);
  color: var(--text);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  transition: color var(--transition-color);
}

/* Back link */
.back-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--accent);
  text-decoration: none;
  margin-bottom: 32px;
  transition: color var(--transition-color);
}

.back-link:hover {
  color: var(--accent-hover);
}

/* "More work" prev/next pager at the foot of a case study. Rendered by
   case-study-pager.js from the shared WORKS order, so it mirrors the works
   page sequence and wraps around at both ends. */
.cs-pager {
  display: flex;
  gap: 24px;
  margin-top: 16px;
  padding-top: 40px;
  border-top: 1px solid var(--stroke-subtle);
  transition: border-color var(--transition-color);
}

.cs-pager-link {
  display: flex;
  align-items: center;
  gap: 16px;
  max-width: 48%;
  text-decoration: none;
  transition: transform var(--transition-fast);
}

/* margin-left:auto keeps "Next" hard right whether or not a "Previous" link
   precedes it (so the first project's lone Next still sits on the right). */
.cs-pager-next {
  margin-left: auto;
  flex-direction: row-reverse;
  text-align: right;
}

.cs-pager-link:hover {
  transform: translateY(-2px);
}

/* Work-in-progress projects render without an href: not navigable, and inert
   on hover (no lift or colour change). */
.cs-pager-link--wip {
  cursor: default;
}

.cs-pager-link--wip:hover {
  transform: none;
}

.cs-pager-link--wip:hover .cs-pager-thumb {
  border-color: var(--stroke-subtle);
}

.cs-pager-link--wip:hover .cs-pager-dir {
  color: var(--accent);
}

.cs-pager-link--wip:hover .cs-pager-title {
  color: var(--text);
}

.cs-pager-thumb {
  flex: none;
  width: 84px;
  height: 60px;
  overflow: hidden;
  border-radius: 8px;
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  transition: border-color var(--transition-color);
}

.cs-pager-link:hover .cs-pager-thumb {
  border-color: var(--accent);
}

.cs-pager-thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.cs-pager-text {
  display: flex;
  flex-direction: column;
  gap: 4px;
  min-width: 0;
}

.cs-pager-dir {
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 500;
  font-size: var(--text-sm);
  color: var(--accent);
  transition: color var(--transition-color);
}

.cs-pager-title {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-lg);
  line-height: 1.2;
  color: var(--text);
  transition: color var(--transition-color);
}

.cs-pager-link:hover .cs-pager-dir {
  color: var(--accent-hover);
}

.cs-pager-link:hover .cs-pager-title {
  color: var(--accent);
}

@media (max-width: 600px) {
  .cs-pager {
    gap: 16px;
  }
  .cs-pager-thumb {
    display: none;
  }
  .cs-pager-title {
    font-size: var(--text-base, 1rem);
  }
}

.inline-link {
  display: inline;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--text-lg);
  color: var(--accent);
  text-decoration: none;
  margin-top: 16px;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 1.5px;
  transition: color var(--transition-fast), background-size 0.35s ease;
}

.inline-link:hover {
  color: var(--accent-hover);
  background-size: 100% 1.5px;
}

/* External-arrow variant: no underline; instead the ↗ nudges up-right and the
   whole link fades from accent green to ink on hover. */
.inline-link--arrow {
  background-image: none;
}

.inline-link--arrow:hover {
  color: var(--text);
  background-size: 0 0;
}

.inline-link-arrow {
  display: inline-block;
  transition: transform var(--transition-fast);
}

.inline-link--arrow:hover .inline-link-arrow {
  transform: translate(3px, -3px);
}

/* Case study content */

.case-study-content {
  padding-left: 10px;
}

.case-study-content section {
  padding: 48px 0;
  border-top: 1px solid var(--stroke-subtle);
  transition: border-color var(--transition-color);
  scroll-margin-top: 104px;
}

.case-study-content section:first-child {
  border-top: none;
  padding-top: 0;
}

.case-study-content section.no-separator {
  border-top: none;
}

/* No divider directly below the overview (Role/Platform/Year) box, and
   halve the gap left behind once the divider is gone. */
.case-study-content section:nth-of-type(1) {
  padding-bottom: 24px;
}

.case-study-content section:nth-of-type(2) {
  border-top: none;
  padding-top: 24px;
}

.case-study-content section:has(+ section.no-separator) {
  padding-bottom: 0;
}

/* Mobile: halve the gap between Solution 2's buttons and Solution 3 below. */
@media (max-width: 640px) {
  .case-study-content #solution-3 {
    padding-top: 24px;
  }
}

.case-study-divider {
  border: none;
  border-top: 1px solid var(--stroke-subtle);
  margin: 48px 0;
  transition: border-color var(--transition-color);
}

/* Eyebrow: the small all-caps label that sits above a serif heading (mainly on
   project pages). Was previously the case-study h2 styling. */
.eyebrow {
  margin-bottom: var(--label-mb);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-sm);
  font-weight: 500;
  font-style: normal;
  line-height: var(--lh-heading);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
  transition: color var(--transition-color);
}

/* Section headings now use the serif look (matching the former lead). */
.case-study-content h2 {
  margin-top: 48px;
  margin-bottom: 20px;
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-3xl);
  font-style: normal;
  font-weight: 700;
  line-height: 1.4;
  letter-spacing: var(--ls-h2);
  color: var(--text);
  max-width: 58ch;
  transition: color var(--transition-color);
}

/* No top gap when the heading starts a container or directly follows its eyebrow. */
.case-study-content h2:first-child,
.case-study-content .eyebrow + h2 {
  margin-top: 0;
}

.case-study-content h3 {
  margin-top: 32px;
  margin-bottom: 12px;
  color: var(--text);
  font-family: 'Instrument Serif', Georgia, serif;
  font-style: normal;
  font-size: var(--text-xl);
  transition: color var(--transition-color);
}

.case-study-content p:not(.eyebrow):not(.vstack-caption):not(:where(.vstack-copy *)) {
  font-size: var(--text-lg);
  color: var(--text);
  line-height: var(--lh-body);
  margin-bottom: 16px;
  transition: color var(--transition-color);
}

.case-study-content ul {
  list-style: none;
  padding-left: 0;
  margin-bottom: 16px;
}

/* Hanging indent: the ✦ marker sits in the gutter and wrapped lines align
   under the text, not under the bullet. */
.case-study-content li {
  padding-left: 1.2em;
  text-indent: -1.2em;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-lg);
  color: var(--text);
  line-height: var(--lh-body);
  margin-bottom: 8px;
  transition: color var(--transition-color);
}

.case-study-content li::before {
  content: "✦";
  display: inline-block;
  width: 1.2em;
  text-indent: 0;
  color: currentColor;
}

.case-study-content h1 {
  font-size: var(--text-4xl);
  margin-bottom: 20px;
  color: var(--text);
  transition: color var(--transition-color);
}

.case-study-content .lead {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-3xl);
  font-style: normal;
  font-weight: 700;
  line-height: 1.4;
  color: var(--text);
  margin-bottom: 20px;
  max-width: 58ch;
  transition: color var(--transition-color);
}

.cs-split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 40px;
  align-items: start;
}

@media (max-width: 640px) {
  .cs-split {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

/* When a cs-split's second column is hidden (e.g. the discovery phase carousel
   is taken out with `hidden`), collapse to one column and let the remaining
   text run to 3/4 width on desktop. Remove the `hidden` attribute to restore
   the original two-column layout. */
.carousel[hidden] {
  display: none;
}

.cs-split:has(> [hidden]) {
  grid-template-columns: 1fr;
}

@media (min-width: 641px) {
  .cs-split:has(> [hidden]) > div:not([hidden]) {
    max-width: 75%;
  }
}

/* Two SmartPoints screens crossfade inside a fixed-height frame. Both sit at
   full width, stacked in one grid cell; the "Card listing" / "Card detail"
   buttons fade between them (toggle group — exactly one is always shown). The
   frame clips the tall screens and the bottom fades out (see .sp-fade) as a
   soft cutoff. */
/* Carousel-style frame: the two screens sit side by side on a track that
   slides horizontally (no overlap, no crossfade). Each screen is its own
   vertical scroll area, so the scroll length always matches the visible one. */
.sp-stage {
  position: relative;
  height: 600px;
  overflow: hidden; /* clip the off-screen screen; each slide scrolls itself */
}

.sp-track {
  display: flex;
  gap: 28px; /* space between the two screens (seen during the slide) */
  height: 100%;
  transition: transform 0.4s ease;
  will-change: transform;
}

.sp-stage .sp-slide {
  flex: 0 0 100%; /* each screen = full stage width; JS translates by width + gap */
  height: 100%;
  overflow-x: hidden;
  overflow-y: auto;
  scrollbar-width: none; /* hide scrollbar; the bottom fade signals scroll */
  overflow-anchor: none;
  /* Stay fully opaque — the carousel slide handles the transition, not the
     toggle-group crossfade. */
  opacity: 1;
  visibility: visible;
}

.sp-stage .sp-slide::-webkit-scrollbar {
  display: none;
}

.sp-stage .sp-slide img {
  width: 100%;
  height: auto;
  display: block;
}

/* Desktop: text column on the left, images on the right (swapped from DOM
   order). On mobile .sp-text is display:contents, so this order is inert there. */
.cs-split--sp .sp-text {
  order: -1;
}

/* Mobile: intro text above the images, controls (buttons + bullets) below.
   display:contents lets .sp-intro / .sp-controls become direct grid items of
   the stacked split so order can interleave them around the image block. */
@media (max-width: 640px) {
  .cs-split--sp .sp-text { display: contents; }
  .cs-split--sp .sp-intro { order: 1; }
  .cs-split--sp .sp-duo-wrap { order: 2; }
  .cs-split--sp .sp-controls { order: 3; }
}

/* Bottom fade hinting more content below. An overlay gradient (rather than a
   mask) so its opacity can transition smoothly; toggled by JS only while the
   container is scrollable and not yet scrolled to the bottom. */
.sp-duo-wrap {
  position: relative;
}

.sp-fade {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 56px;
  pointer-events: none;
  background: linear-gradient(to bottom, transparent, var(--bg));
  opacity: 0;
  transition: opacity 0.3s ease;
}

/* Shown by JS only while the frame can still scroll down (hidden at the end). */
.sp-duo-wrap.is-fade .sp-fade {
  opacity: 1;
}

/* Tags act as buttons; hover + pressed state match the Copywriting tag (the
   warm cream it shows on works-card hover). Shared by the Solution 2 (.sp-tag)
   and Solution 3 (.sf-tag) toggle buttons. */
.sp-tag,
.sf-tag {
  transition: background-color var(--transition-fast), border-color var(--transition-fast),
              color var(--transition-fast), box-shadow var(--transition-fast),
              transform var(--transition-fast);
}

.sp-tag:hover,
.sp-tag[aria-pressed="true"],
.sf-tag:hover,
.sf-tag[aria-pressed="true"] {
  background-color: #FFF9EB;
}

/* Pressed (active) buttons look recessed: inset shadow + a 1px nudge down. */
.sp-tag[aria-pressed="true"],
.sf-tag[aria-pressed="true"] {
  box-shadow: inset 0 1px 1.5px rgba(30, 30, 30, 0.25);
  transform: translateY(1px);
}

/* Paragraph-sized gap beneath the tag row. */
.tag-row:has(.sp-tag),
.tag-row:has(.sf-tag) {
  margin-bottom: 16px;
}


/* Impact stat panel — the Round 2 results, visual counterpart to the Round 1
   box in the Process section (same bordered, serif-number treatment). */
.impact-stats {
  margin: 24px 0;
  padding: 28px clamp(24px, 4vw, 40px);
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

.impact-stats .duo-label {
  margin-bottom: 24px;
}

.impact-stats-row {
  display: flex;
  flex-wrap: wrap;
  gap: 28px 56px;
}

.impact-stat {
  display: flex;
  flex-direction: column;
  gap: 8px;
}

.impact-stat-num {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-4xl);
  line-height: 1;
  color: var(--text);
}

.impact-stat-unit {
  color: var(--text-muted);
}

.impact-stat-arrow {
  color: var(--accent);
}

.impact-stat-desc {
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-lg);
  color: var(--text);
  line-height: var(--lh-body);
  max-width: 24ch;
}

/* Impact outcomes — two parallel results */
.impact-outcomes {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 40px;
  margin-top: 40px;
}

.impact-outcomes h3 {
  margin-top: 0;
}

.impact-outcomes p {
  margin-bottom: 0;
}

@media (max-width: 760px) {
  .impact-outcomes {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

/* Full-width case study image */
.cs-full-image {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  object-fit: cover;
  margin-top: 24px;
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  transition: border-color var(--transition-color);
}

/* Narrower text column so the iPad sits larger in the right column (desktop). */
@media (min-width: 641px) {
  .cs-split--tablet {
    grid-template-columns: 2fr 3fr;
    align-items: center;
  }
  /* Mirror of --tablet: wide media on the left, narrow text on the right. */
  .cs-split--carousel {
    grid-template-columns: 3fr 2fr;
    align-items: center;
  }
  /* Offset the text down-padding by the carousel's caption + controls height so
     the text centres on the image, not the whole carousel component. */
  .cs-split--carousel > :last-child {
    margin-bottom: 98px;
  }

  /* Mirror of --tablet (text 2fr left, carousel 3fr right), with the same
     image-centring offset applied to the text (the first child here). */
  .cs-split--carousel-r {
    grid-template-columns: 2fr 3fr;
    align-items: center;
  }
  .cs-split--carousel-r > :first-child {
    margin-bottom: 98px;
  }
}

/* Small grey caption beneath a carousel slide image. */

/* Flush carousel: no surrounding box; each slide is a full-width image (its
   natural ratio) with a caption beneath. (Compound selectors so these beat the
   later .carousel-split box rules.) */
.carousel-flush.carousel-split .carousel-stage {
  background: none;
  border: none;
  border-radius: 0;
  overflow: visible;
}

.carousel-flush.carousel-split .carousel-slide {
  padding: 0;
}

.carousel-flush .carousel-slide > img {
  width: 100%;
  height: auto;
  border-radius: 8px;
  display: block;
}

/* Landscape iPad mockup: the SVG bezel sits on top; the image shows through its
   transparent screen cutout (measured from the SVG, in %). */
.tablet-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 2000 / 1532;
}

.tablet-screen {
  position: absolute;
  /* Bleed slightly under the bezel so no hairline gap shows at the edges. */
  left: 3%;
  top: 3.9%;
  width: 94%;
  height: 92.2%;
  overflow: hidden;
}

.tablet-screen img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
  display: block;
}

.tablet-bezel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

/* Context image sitting in the right column of the intro split: 4:3, and no top
   margin so its top lines up with the heading on the left. */
.cs-context-media {
  aspect-ratio: 4 / 3;
  margin-top: 0;
}

/* Stat list: a big serif figure in its own column beside the supporting text. */
.stat-list {
  display: flex;
  flex-direction: column;
  gap: 24px;
}

.stat-row {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 20px;
  align-items: center;
}

.stat-num {
  font-family: 'Instrument Serif', Georgia, serif;
  font-size: var(--text-4xl);
  line-height: 1.1;
  color: var(--text);
  white-space: nowrap;
}

.case-study-content .stat-text {
  margin: 0;
}

/* Process carousel */
.carousel {
  margin-top: 24px;
  min-width: 0; /* allow shrinking inside a grid/flex column (prevents overflow) */
}

.carousel-stage {
  display: flex;
  align-items: center;
  gap: clamp(10px, 2vw, 24px);
}

.carousel-viewport {
  flex: 1;
  min-width: 0;
  overflow: hidden;
}

.carousel-track {
  display: flex;
  transition: transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}

/* Fade mode: stack the slides; the incoming fades in over the outgoing (which
   holds underneath), so the frame never dips to see-through. Opacity/z-index are
   driven by JS. */
.carousel-fade .carousel-track {
  display: grid;
}

.carousel-fade .carousel-slide {
  grid-area: 1 / 1;
  opacity: 0;
  transition: opacity 0.4s ease;
}

/* Slides all share the tallest slide's height (default flex stretch) so the
   carousel height is stable and the side controls never shift between slides.
   Content is top-aligned so the image/text gap stays consistent. */
.carousel-slide {
  flex: 0 0 100%;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(24px, 4vw, 48px);
  align-items: start;
  align-content: start;
}

.carousel-media {
  aspect-ratio: 4 / 3;
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

/* A slide that holds a real image (e.g. a transparent GIF) drops the framed
   placeholder treatment and shows the artwork on its own. The canvas case
   covers the SuperGif (libgif) hover-play swap on desktop. */
.carousel-media:has(img),
.carousel-media:has(canvas) {
  background: none;
  border: none;
}

.carousel-media img {
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: block;
}

/* SuperGif replaces the <img> with a .jsgif wrapper + <canvas>; keep it
   filling the (smaller, centered) media box and hide its loading toolbar. */
.carousel-media .jsgif {
  width: 100%;
  line-height: 0;
}

.carousel-media .jsgif canvas {
  width: 100%;
  height: auto;
  display: block;
}

.carousel-media .jsgif_toolbar {
  display: none;
}

.carousel-phase {
  margin-bottom: 12px;
}

.carousel-text h3 {
  margin: 0 0 12px;
  font-size: var(--text-4xl);
  line-height: var(--lh-heading);
}

/* Drop the trailing paragraph margin so the description sits closer to the
   bottom of the box (matching the top padding instead of overshooting it). */
.carousel-text > :last-child {
  margin-bottom: 0;
}

.carousel-dots {
  display: flex;
  justify-content: center;
  gap: 8px;
  margin-top: 20px;
}

.carousel-dot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background-color: var(--stroke);
  opacity: 0.25;
  cursor: pointer;
  transition: opacity var(--transition-fast);
}

.carousel-dot.active {
  opacity: 1;
}

.carousel-arrow {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1.5px solid var(--stroke-subtle);
  background-color: var(--bg-surface);
  color: var(--text);
  font-size: var(--text-base);
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  outline: none;
  -webkit-tap-highlight-color: transparent;
  transition: border-color var(--transition-fast), background-color var(--transition-fast), opacity var(--transition-fast);
}

.carousel-arrow:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

.carousel-arrow:not(:disabled):hover {
  border-color: var(--text-muted);
}


.carousel-arrow:disabled {
  opacity: 0.3;
  cursor: default;
}

/* Controls row beneath the carousel: prev arrow · dots · next arrow. */
.carousel-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  margin-top: 20px;
}

.carousel-controls .carousel-dots {
  margin-top: 0;
}

/* Carousel sitting in a half-width column: slides stack (image over text).
   Drop the top margin so the image top lines up with the left column heading. */
.carousel-split {
  margin-top: 0;
}

.carousel-split .carousel-slide {
  grid-template-columns: 1fr;
  gap: 16px;
  /* Padding lives on the slide (not the box) so content slides edge-to-edge
     within the box and is clipped at the box border. */
  padding: 28px;
}

.carousel-split .carousel-stage {
  gap: 10px;
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  overflow: hidden;
}

/* "Plain" variant: no surrounding box (used for the before/after slider
   carousel). The viewport still clips the horizontal slide. */
.carousel-plain .carousel-stage {
  background: none;
  border: none;
  border-radius: 0;
  justify-content: center;
}

/* Arrows flank the phone: constrain the viewport to the phone width so the
   side arrows sit right beside the frame rather than at the column edges. */
.carousel-plain .carousel-viewport {
  flex: 0 1 242px;
}


.carousel-plain .carousel-arrow {
  flex: 0 0 auto;
}

.carousel-plain .carousel-slide {
  padding: 0;
  gap: 8px;
}

/* Solution 3: the Sort & Filter / Quiz buttons crossfade between two slides
   (and their bullet sets). Slides + bullets are grid-stacked so they share a
   cell; only the active one is visible. Button look reuses the Solution 2 tag. */
.sf-stage,
.sf-bullets-stack {
  display: grid;
}

.sf-stage {
  width: 242px;
  max-width: 100%;
  margin-inline: auto;
}

.sf-stage > .sf-slide,
.sf-bullets-stack > .sp-bullets {
  grid-area: 1 / 1;
}

.sf-slide {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.sf-slide > img {
  width: 100%;
  height: auto;
  border-radius: 8px;
}

.sf-stage .phone-frame {
  max-width: 100%;
}

.sf-stage .phone-screen img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top;
}


/* Crossfade: hidden panels sit faded out; the active one fades in. visibility
   is delayed on hide so the fade-out plays fully. */
[data-toggle-panel] {
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.3s ease, visibility 0s linear 0.3s;
}

[data-toggle-panel].is-active {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.3s ease, visibility 0s;
}

/* Desktop: scale slides up 10% (242 -> 266) and shrink the left column to the
   slide width so the text column extends left with a tidy gap. */
@media (min-width: 641px) {
  .sf-stage {
    width: 266px;
    margin-inline: 40px 0; /* nudge the carousel slightly right of the column edge */
  }
  .cs-split--sol3 {
    grid-template-columns: auto 1fr;
    align-items: center;
  }
}

/* Mobile: lift the Solution 3 intro (eyebrow, heading, paragraph) above the
   phone, keeping the toggle buttons + bullets below it. display:contents lets
   the wrapped intro/controls become direct grid items so order can place them
   around the phone. */
@media (max-width: 640px) {
  .cs-split--sol3 .sf-text { display: contents; }
  .cs-split--sol3 .sf-intro { order: -1; }
  .cs-split--sol3 .sf-controls { order: 1; }
}

/* iPhone frame holding a before/after slider. The SVG bezel sits on top; the
   slider shows through the transparent screen cutout (measured from the SVG). */
.phone-frame {
  position: relative;
  width: 100%;
  max-width: 242px;
  margin-inline: auto;
  aspect-ratio: 426 / 860;
}

.phone-screen {
  position: absolute;
  /* Bleed slightly up/left so the screen content tucks under the bezel frame
     and leaves no hairline gap at the top-left inner edge. */
  left: 5.1%;
  top: 6.9%;
  width: 89.5%;
  height: 90.7%;
  overflow: hidden;
}

.phone-bezel {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.phone-screen .ba-compare {
  width: 100%;
  height: 100%;
  max-width: none;
  border: none;
  border-radius: 0;
}

/* The screenshots are taller than the screen; anchor them to the top so the top
   of each page is flush with the top of the screen (crop happens at the bottom). */
.phone-screen .ba-compare img {
  object-position: top;
}


/* Smaller, centered placeholder image inside the split column. */
.carousel-split .carousel-media {
  width: 100%;
  max-width: 240px;
  margin-inline: auto;
}

.carousel-split .carousel-text {
  text-align: center;
}

@media (max-width: 700px) {
  .carousel-slide {
    grid-template-columns: 1fr;
    gap: 20px;
  }

  .carousel-text {
    text-align: center;
  }

  .carousel-text p {
    margin-bottom: 0;
  }

  .carousel-stage {
    gap: 8px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .carousel-track,
  .carousel-viewport {
    transition: none;
  }
}

/* Before / after image comparison */
/* Two before/after sliders side by side within a column. */
/* SVG before/after: no phone frame; sized by the after image's aspect ratio.
   The before image is narrower — centre it and fill the empty sides with the
   vstack stage background so they read as transparent. */
.ba-compare.ba-compare--svg {
  aspect-ratio: 281 / 365;
  width: 85%;
  border: none;
  border-radius: 0;
  background: transparent;
}

.ba-compare--svg .ba-before {
  background-color: #FAF5EE;
}

.ba-compare--svg .ba-before img {
  width: auto;
  height: 100%;
  top: 0;
  bottom: 0;
  left: 50%;
  right: auto;
  transform: translateX(-50%);
}

.ba-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 28px;
}

.ba-pair .ba-compare {
  min-width: 0;
}

@media (max-width: 640px) {
  .ba-pair {
    grid-template-columns: 1fr;
  }
}

.ba-compare {
  position: relative;
  width: 100%;
  overflow: hidden;
  border: 1.5px solid #CFC8BF;
  border-radius: 8px;
  background-color: var(--bg-raised);
  touch-action: pan-y;
  user-select: none;
  cursor: ew-resize;
  transition: border-color var(--transition-color);
}

/* Two stacked layers; the "before" layer (image + its label) is clipped by
   the wiper, so the Before label gets covered along with its image. The After
   label lives in the base layer underneath, so the before layer covers it as
   the wiper moves right. */
.ba-after,
.ba-before {
  position: absolute;
  inset: 0;
}

.ba-before {
  clip-path: inset(0 50% 0 0);
}

.ba-compare img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  pointer-events: none;
  -webkit-user-drag: none;
}

.ba-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: 50%;
  width: 1.5px;
  margin-left: -0.75px;
  background: #CFC8BF;
  pointer-events: none;
}

/* Touch release: ease the wipe and divider back to the middle. */
.ba-compare.ba-returning .ba-before {
  transition: clip-path 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.ba-compare.ba-returning .ba-divider {
  transition: left 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.ba-tag {
  position: absolute;
  bottom: 12px;
  padding: 4px 10px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: #fff;
  background: rgba(0, 0, 0, 0.55);
  border-radius: 4px;
  pointer-events: none;
}

.ba-tag-before { left: 12px; }
.ba-tag-after { right: 12px; }

/* "Drag" hint, centred over the handle. Fades for good on desktop once the
   divider moves (ba-moved); on touch it hides only while interacting
   (ba-touching) and returns afterwards. */
.ba-hint {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  padding: 5px 12px;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-xs);
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: #fff;
  background: rgba(0, 0, 0, 0.6);
  border-radius: 100px;
  white-space: nowrap;
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.35s ease;
}

.ba-compare.ba-moved .ba-hint,
.ba-compare.ba-touching .ba-hint {
  opacity: 0;
}

.ba-compare:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
}

/* Full-width image frame that clips, so the inner <img> can be zoomed/panned
   (object-fit cover gives no horizontal crop room when the source is narrower
   than the frame, so a transform on the image is how we zoom and pan). */
.cs-image-frame {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  overflow: hidden;
  margin-top: 24px;
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  transition: border-color var(--transition-color);
}

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

.image-placeholder {
  width: 100%;
  height: 280px;
  background-color: var(--bg-raised);
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 8px;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

.image-placeholder-label {
  font-size: var(--text-sm);
  color: var(--text-muted);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  transition: color var(--transition-color);
}

/* Menu carousel: a row of folder tabs drives a fading, vertically sliding
   stage of copy + image below. (Mobile uses a native select instead.) */
.vstack {
  margin-top: 0;
}

.vstack-menu {
  display: flex;
  align-items: flex-end;
  gap: 0;
  /* No margin/hairline: the tabs sit flush on top of the .vstack-stage box,
     whose top border is the shared edge they rest on. */
  margin-bottom: 0;
  overflow-x: auto;
  overflow-y: hidden; /* clip the lowered (unselected) tabs at the baseline */
  scrollbar-width: none;
}

.vstack-menu::-webkit-scrollbar {
  display: none;
}

/* Fade the right edge while there's more of the tab row to scroll (toggled by
   JS; only added when the row actually overflows, so desktop is unaffected). */
.vstack-menu--fade {
  -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
  mask-image: linear-gradient(to right, #000 calc(100% - 36px), transparent);
}

/* Folder tabs: rounded top corners, square bottom, wider than tall, sitting
   flush side by side (adjacent borders overlap into a single edge). */
.vstack-tab {
  flex: 0 0 auto;
  position: relative;
  padding: 10px 22px;
  border: 1.5px solid var(--stroke-subtle);
  border-bottom: none; /* the menu's bottom hairline is the single shared edge */
  border-radius: 8px 8px 0 0;
  background-color: #F5E2C1;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-sm);
  font-weight: 500;
  line-height: 1.2;
  white-space: nowrap;
  color: var(--text-muted);
  cursor: pointer;
  /* Unselected tabs sit lower; the selected (and hovered) tab rises to full height. */
  transform: translateY(8px);
  transition: transform 0.2s ease, color var(--transition-fast), background-color var(--transition-fast), border-color var(--transition-fast);
}

/* Cascade: each tab tucks its left edge behind the previous one. Earlier tabs
   get a higher z-index so they stay on top regardless of which is selected. */
.vstack-tab + .vstack-tab {
  margin-left: -14px;
}

.vstack-tab:nth-child(1) { z-index: 7; }
.vstack-tab:nth-child(2) { z-index: 6; }
.vstack-tab:nth-child(3) { z-index: 5; }
.vstack-tab:nth-child(4) { z-index: 4; }
.vstack-tab:nth-child(5) { z-index: 3; }
.vstack-tab:nth-child(6) { z-index: 2; }
.vstack-tab:nth-child(7) { z-index: 1; }

/* Desktop: hovering a tab raises it to full height, no colour change. */
@media (hover: hover) {
  .vstack-tab:hover {
    transform: translateY(0);
  }
}

.vstack-tab.active {
  transform: translateY(0);
  background-color: var(--accent);
  border-color: var(--accent);
  color: var(--bg);
  /* No z-index change: the cascade order stays the same when a tab is selected. */
}

/* All slides share one grid cell so the stage sizes to the tallest and the
   active one fades/slides over the others. The box matches the phase carousel
   (same fill + hairline); top-left is squared so the leftmost tab flows into
   it, the other three corners are rounded. */
.vstack-stage {
  display: grid;
  align-items: center;
  padding: 32px;
  background-color: #FAF5EE;
  border: 1.5px solid var(--stroke-subtle);
  border-radius: 0 8px 8px 8px;
  transition: background-color var(--transition-color), border-color var(--transition-color);
}

.vstack-slide {
  grid-area: 1 / 1;
  display: grid;
  grid-template-columns: minmax(320px, 400px) minmax(200px, 500px);
  gap: 48px;
  align-items: center;
  opacity: 0;
  transform: translateX(32px);
  transition: opacity 0.18s ease, transform 0.25s cubic-bezier(0.22, 1, 0.36, 1);
  pointer-events: none;
}

.vstack-slide.active {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}

.vstack-slide .vstack-media { order: 1; align-self: stretch; justify-content: center; }
.vstack-slide .vstack-copy  { order: 2; }

.vstack-copy .duo-label {
  font-size: var(--text-sm);
  margin-bottom: var(--label-mb);
  color: var(--text-muted);
}

.vstack-media .image-placeholder {
  height: 320px;
}

/* Scoped so it beats `.case-study-content p`; keeps the caption below body size. */
/* Universal image-caption style (used by vstack, carousels, sf-stage, etc.).
   Scoped to case-study-content so it beats the body-copy `p` rule. */
.case-study-content .vstack-caption {
  margin-top: 0;
  margin-bottom: 0;
  font-size: var(--text-sm);
  color: #4A4742;
  text-align: center;
  width: 100%;
}


/* Vstack body copy matches the case-study page body copy.
   Excludes duo-label, lead, and vstack-caption which have their own rules. */
.vstack-copy p:not(.duo-label):not(.lead):not(.vstack-caption) {
  font-size: var(--text-lg);
  color: var(--text);
  line-height: var(--lh-body);
  margin-bottom: 16px;
  transition: color var(--transition-color);
}

/* Image and caption centred as a unit within their column. */
.vstack-media {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
}

/* The before/after carousel must fill the column so its side arrows flank the
   phone; otherwise align-items:center shrinks it to the phone's min-content. */
.vstack-media > .carousel {
  align-self: stretch;
}

/* Mobile: menu becomes a horizontal scroll row on top; the slide stacks as
   image -> caption -> label/header/body; switching is instant (no animation). */
@media (max-width: 700px) {
  .vstack {
    grid-template-columns: 1fr;
    gap: 24px;
  }

  .vstack-stage {
    padding: 20px;
    align-items: start;
  }

  .vstack-slide {
    grid-template-columns: 1fr;
    /* Match the lead→body gap (the lead's 20px margin) so the caption→duo-label
       spacing is consistent when the slide stacks. */
    gap: 20px;
    transition: none;
  }

  .vstack-media {
    order: -1; /* image + caption above the copy */
    align-items: flex-start;
  }

  .vstack-copy .lead {
    margin-top: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .vstack-slide {
    transition: opacity 0.2s ease;
    transform: none !important;
  }
}

/* Before / After labels */
.duo-label {
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: var(--lh-heading);
  text-transform: uppercase;
  letter-spacing: var(--ls-label);
  color: var(--text-muted);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  margin-bottom: 12px;
  transition: color var(--transition-color);
}

@media (max-width: 900px) {
  .case-study-layout {
    grid-template-columns: 1fr;
    grid-template-areas:
      "back"
      "sidebar"
      "content";
    gap: 32px;
    padding-top: 24px;
  }

  /* Let the single column shrink to the viewport instead of expanding to its
     content's min-width (which caused horizontal overflow on mobile). */
  .case-study-sidebar,
  .case-study-content {
    min-width: 0;
  }

  /* The 10px left offset is for the desktop two-column layout; remove it on
     mobile so the content is centred with equal margins. */
  .case-study-content {
    padding-left: 0;
  }

  /* Quick nav sits below the back-link and sticks under the site nav so it's
     always reachable while scrolling. */
  .case-study-sidebar {
    position: sticky;
    top: 64px;
    z-index: 50;
    background-color: var(--bg);
    padding: 0;
  }

  .sidebar-nav {
    flex-direction: row;
    flex-wrap: nowrap;
    overflow-x: auto;
    gap: 0;
    padding-bottom: 0;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none; /* no grey scrollbar line under the nav */
  }

  .sidebar-nav::-webkit-scrollbar {
    display: none;
  }

  /* Fade the right edge while the tab row can still scroll (toggled by JS). */
  .sidebar-nav--fade {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
    mask-image: linear-gradient(to right, #000 calc(100% - 32px), transparent);
  }

  /* Mobile: the indicator becomes a horizontal underline at the bottom of the
     nav that slides between tabs (width set by JS). */
  .sidebar-indicator {
    top: auto;
    bottom: 0;
    height: 2px;
  }

  .sidebar-nav.js-indicator a.active {
    border-bottom-color: transparent;
  }

  .sidebar-nav a {
    border-left: none;
    border-bottom: 2px solid transparent;
    white-space: nowrap;
    padding: 8px 12px;
  }

  .sidebar-nav a.active {
    border-left-color: transparent;
    border-bottom-color: var(--accent);
  }
}

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

.about-section {
  padding: 48px clamp(24px, 5vw, 80px) 80px;
}

/* Two-column split layout */
.about-split {
  display: flex;
  flex-direction: column;
  gap: 40px;
  max-width: 1280px;
  margin: 0 auto;
}

@media (min-width: 900px) {
  .about-split {
    display: grid;
    grid-template-columns: 3fr 2fr;
    grid-template-rows: auto auto;
    column-gap: clamp(48px, 7vw, 96px);
    row-gap: 32px;
  }

  .about-left-heading {
    grid-column: 1;
    grid-row: 1;
  }

  .about-left-body {
    grid-column: 1;
    grid-row: 2;
    align-self: start;
  }

  .about-right {
    grid-column: 2;
    grid-row: 2;
    align-self: start;
  }

  .about-section .about-left-heading h1 {
    font-size: var(--text-hero);
    margin-bottom: 0;
  }

  .about-right {
    display: flex;
    flex-direction: column;
    gap: 32px;
  }

  /* Align "What I do" with the left body's first line. Specificity must
     beat ".about-section h2 { margin-top: 48px }", which wins on source
     order otherwise. Only the first h2 is adjusted so the gap to "Skills
     and tools" (flex gap + its own margin) is preserved. The small
     negative margin optically matches the larger serif heading's baseline
     to the body paragraph's first line (box tops alone leave it sitting low). */
  .about-section .about-right .hero-clip:first-child h2 {
    margin-top: -3px;
  }
}

.about-section h1 {
  font-style: normal;
  font-size: var(--text-4xl);
  color: var(--text);
  margin-bottom: 24px;
  transition: color var(--transition-color);
}

.about-section h2 {
  margin-top: 48px;
  margin-bottom: 16px;
  font-style: normal;
  color: var(--text);
  transition: color var(--transition-color);
}

.about-section p {
  font-size: var(--text-lg);
  color: var(--text);
  line-height: var(--lh-body);
  margin-bottom: 16px;
  transition: color var(--transition-color);
}

@media (max-width: 899px) {
  .about-section h1 {
    margin-bottom: 0;
  }

  .about-section h2 {
    margin-top: 40px;
  }
}

/* Skills tags */
.skills-row {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.skills-row .tag {
  background-color: #FFF9EB;
}

/* CV button (SVG, swaps to a second SVG on hover) */
.cv-button {
  display: inline-block;
  position: relative;
  width: 80px;
  margin-top: 16px;
  line-height: 0;
  cursor: pointer;
}

.cv-button img {
  display: block;
  width: 100%;
  height: auto;
}

.cv-button .cv-hover {
  position: absolute;
  inset: 0;
  opacity: 0;
}

.cv-button:hover .cv-default {
  opacity: 0;
}

.cv-button:hover .cv-hover {
  opacity: 1;
}

/* =====================
   CONTACT PAGE
   ===================== */

.contact-section {
  padding: 80px clamp(24px, 5vw, 80px);
}

.contact-copyright {
  padding: 24px clamp(24px, 5vw, 80px);
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-size: var(--text-sm);
  color: var(--text-muted);
  transition: color var(--transition-color);
}

.contact-section h1 {
  font-size: var(--text-4xl);
  font-style: normal;
  color: var(--text);
  margin-bottom: 12px;
  transition: color var(--transition-color);
}

.contact-sub {
  font-size: var(--text-lg);
  color: #1e1e1e;
  margin-bottom: 48px;
  transition: color var(--transition-color);
}

/* Contact page layout */
.contact-layout {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: clamp(32px, 6vw, 80px);
  max-width: 960px;
  margin-left: auto;
  margin-right: auto;
}

.contact-gif {
  width: clamp(200px, 35vw, 400px);
  height: auto;
  flex-shrink: 0;
  border-radius: 12px;
}

.contact-content {
  display: flex;
  flex-direction: column;
  gap: 16px;
  flex: 1;
}

.contact-heading {
  font-size: var(--text-3xl);
  font-style: normal;
  color: var(--text);
  line-height: 1.3;
  transition: color var(--transition-color);
}

.contact-email-link {
  display: inline-block;
  align-self: flex-start;
  font-family: 'Instrument Sans', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--text-xl);
  color: var(--text);
  text-decoration: none;
  background-image: linear-gradient(currentColor, currentColor);
  background-position: 0% 100%;
  background-repeat: no-repeat;
  background-size: 0% 1.5px;
  transition: color var(--transition-color), background-size 0.35s ease;
}

.contact-email-link:hover {
  background-size: 100% 1.5px;
}

@media (max-width: 640px) {
  .contact-layout {
    flex-direction: column;
    align-items: flex-start;
  }

  .contact-gif {
    width: clamp(120px, 50vw, 200px);
  }
}

/* =====================
   WORKS PAGE
   ===================== */

.works-header {
  padding: 48px clamp(24px, 5vw, 80px) 48px;
}

.works-header h1 {
  font-size: var(--text-4xl);
  font-style: normal;
  color: var(--text);
  margin-bottom: 12px;
  letter-spacing: var(--ls-h1);
  transition: color var(--transition-color);
}

.works-header p {
  font-size: var(--text-lg);
  color: var(--text);
  transition: color var(--transition-color);
}

.works-grid-section {
  padding: 0 clamp(24px, 5vw, 80px) 80px;
}

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

@media (max-width: 768px) {
  .nav-tabs {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    flex-wrap: nowrap;
  }

  .nav-tabs::-webkit-scrollbar {
    display: none;
  }

  .nav-tab {
    padding: 8px 14px;
    font-size: var(--text-xs);
    white-space: nowrap;
    flex-shrink: 0;
  }

  .nav-lottie {
    width: 66px;
    height: 48px;
  }

  .nav-name {
    font-size: 2rem;
    height: auto;
    line-height: 1.2;
    margin-top: 0;
    flex-shrink: 0;
  }
}

/* Hamburger button — hidden on wide screens */
.nav-hamburger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 36px;
  height: 36px;
  padding: 6px;
  margin-left: auto;
  background: none;
  border: none;
  cursor: pointer;
  flex-shrink: 0;
}

.nav-hamburger span {
  display: block;
  width: 20px;
  height: 1.5px;
  background-color: var(--text);
  border-radius: 2px;
  transform-origin: center;
  transition: transform 0.25s ease, opacity 0.2s ease, background-color var(--transition-color);
}

.site-nav.menu-open .nav-hamburger span:nth-child(1) {
  transform: translateY(6.5px) rotate(45deg);
}
.site-nav.menu-open .nav-hamburger span:nth-child(2) {
  opacity: 0;
  transform: scaleX(0);
}
.site-nav.menu-open .nav-hamburger span:nth-child(3) {
  transform: translateY(-6.5px) rotate(-45deg);
}

/* At narrow widths: hide inline tabs, show hamburger + floating panel */
@media (max-width: 520px) {
  .nav-hamburger {
    display: flex;
  }

  .nav-tabs {
    /* Reset inline flow */
    flex: none;
    overflow: visible;

    /* Float as a panel from top-right */
    position: fixed;
    top: var(--nav-h, 68px);
    right: clamp(24px, 5vw, 80px);
    flex-direction: column;
    align-items: center;
    width: auto;
    background-color: var(--bg-surface);
    border: 1.5px solid var(--stroke);
    border-radius: 12px;
    padding: 16px 8px;
    z-index: 200;
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.1);
    gap: 16px;

    /* Hidden by default */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity 0.2s ease, transform 0.2s ease, visibility 0s linear 0.2s;
  }

  .nav-tabs.menu-open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    pointer-events: auto;
    transition: opacity 0.2s ease, transform 0.2s ease;
  }
}

@media (hover: none) and (pointer: coarse) {
  .nav-tab.nav-tab--lottie:active {
    opacity: 1;
  }
  .nav-tab--lottie::before {
    display: none;
  }
}

/* Preview: discovery slides housed in paper.svg, full-width 3-up row. The
   paper sheet is the stretched background; each card is a padded column that
   stacks the (shrunk) gif, phase label, and description below the binder
   holes (~7.7% of the sheet height, cleared by the top padding). */
.paper-row {
  display: flex;
  justify-content: center;
  align-items: flex-start;
  margin-top: 20px;
}

.paper-card {
  position: relative;
  display: flex;
  flex-direction: column;
  flex: 0 1 34%;
  transition: transform 0.25s ease;
  /* The sheet is drawn in CSS (not the SVG) so the "paper" is the card box
     itself — it always grows to wrap the gif + text, never letting content
     spill outside. Top padding clears the binder holes below. */
  /* Ring outlines drawn on the card background. Both these and the mask holes
     below use the same border-box origin and identical positions, so the
     punched holes line up exactly inside the rings. */
  background-color: #F7F6F4;
  background-image:
    radial-gradient(circle 8px at 9% 22px, transparent 0 5.5px, #C4BAAA 5.5px 7px, transparent 7px),
    radial-gradient(circle 8px at 50% 22px, transparent 0 5.5px, #C4BAAA 5.5px 7px, transparent 7px),
    radial-gradient(circle 8px at 91% 22px, transparent 0 5.5px, #C4BAAA 5.5px 7px, transparent 7px);
  background-repeat: no-repeat;
  background-origin: border-box;
  border: 1px solid #C4BAAA;
  padding: 40px 5% 26px;
  text-align: center;
  /* Punch three transparent holes through the sheet (and its background) so
     whatever is behind — the page or an overlapped sheet — shows through.
     A full-opaque base layer, XOR'd with three dots, leaves dot-shaped gaps. */
  -webkit-mask-image:
    radial-gradient(circle 5.5px at 9% 22px, #000 0 5.5px, transparent 5.5px),
    radial-gradient(circle 5.5px at 50% 22px, #000 0 5.5px, transparent 5.5px),
    radial-gradient(circle 5.5px at 91% 22px, #000 0 5.5px, transparent 5.5px),
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  -webkit-mask-origin: border-box;
  mask-image:
    radial-gradient(circle 5.5px at 9% 22px, #000 0 5.5px, transparent 5.5px),
    radial-gradient(circle 5.5px at 50% 22px, #000 0 5.5px, transparent 5.5px),
    radial-gradient(circle 5.5px at 91% 22px, #000 0 5.5px, transparent 5.5px),
    linear-gradient(#000 0 0);
  mask-composite: exclude;
  mask-origin: border-box;
}

/* Strew the sheets: alternate the tilt and let each later one overlap the
   previous (raised z-index + negative margin pulling it back over). */
.paper-row .paper-card:nth-child(1) {
  transform: rotate(-2deg);
  z-index: 1;
}

.paper-row .paper-card:nth-child(2) {
  transform: rotate(1.5deg);
  z-index: 2;
  margin-left: -1%;
}

.paper-row .paper-card:nth-child(3) {
  transform: rotate(-2deg);
  z-index: 3;
  margin-left: -1%;
}

.paper-card img {
  width: 100%;
  height: auto;
  object-fit: contain;
  margin-bottom: 14px;
}

.paper-copy {
  width: 100%;
}

.paper-card .carousel-phase {
  margin-bottom: 6px;
}

.paper-card .paper-text {
  font-size: var(--text-base);
  line-height: 1.5;
  color: var(--text);
}

/* On hover-capable devices SuperGif swaps the <img> for a .jsgif canvas
   wrapper; keep it filling the slot with the same spacing as the image. */
.paper-card .jsgif {
  width: 100%;
  margin-bottom: 14px;
  line-height: 0;
}

.paper-card .jsgif canvas {
  width: 100%;
  height: auto;
  display: block;
}

.paper-card .jsgif_toolbar {
  display: none;
}

/* Hover: lift the sheet a little, travelling parallel to its own tilt (the
   translateY is applied after the rotate, so it moves along the rotated axis).
   Its stacking order is left untouched, so it stays behind whatever already
   overlaps it. */
@media (hover: hover) {
  .paper-row .paper-card:nth-child(1):hover {
    transform: rotate(-2deg) translateY(-14px);
  }

  .paper-row .paper-card:nth-child(2):hover {
    transform: rotate(1.5deg) translateY(-14px);
  }

  .paper-row .paper-card:nth-child(3):hover {
    transform: rotate(-2deg) translateY(-14px);
  }
}

@media (max-width: 700px) {
  .paper-row {
    flex-direction: column;
    align-items: center;
    gap: 0;
  }

  /* Keep the askew tilt, but stack the sheets vertically with a little overlap
     so each one's top sits over the previous one's bottom. The base stacking
     order already rises 1→2→3, so the lower sheet overlaps the one above it.
     Width is pulled in slightly to leave room for the rotated corners. */
  .paper-row .paper-card:nth-child(1),
  .paper-row .paper-card:nth-child(2),
  .paper-row .paper-card:nth-child(3) {
    flex-basis: auto;
    width: 92%;
    margin-left: 0;
  }

  .paper-row .paper-card:nth-child(2),
  .paper-row .paper-card:nth-child(3) {
    margin-top: -12px;
  }

  /* Scale the gif down a little on mobile, keep it centred, and add a bit more
     space below it before the text. */
  .paper-card img,
  .paper-card .jsgif {
    width: 70%;
    margin-left: auto;
    margin-right: auto;
    margin-bottom: 22px;
  }
}

