/* ==========================================================================
   94 STUDIOS — portfolio stylesheet
   --------------------------------------------------------------------------
   Everything themable lives in :root below. Change a token there and it
   propagates site-wide. Nothing else in this file hardcodes a colour, a font
   or an easing curve.
   ========================================================================== */

/* --------------------------------------------------------------------------
   1. DESIGN TOKENS
   -------------------------------------------------------------------------- */
:root {
  /* --- Colour ----------------------------------------------------------- */
  --bg:            #fafafa;   /* page background          */
  --ink:           #0f0f0f;   /* primary text             */
  --muted:         #757575;   /* secondary / meta text    */
  --line:          rgba(15, 15, 15, 0.12);  /* hairline rules  */
  --line-strong:   rgba(15, 15, 15, 0.22);
  --surface:       #f1f0ee;   /* tinted panels, logo cells */
  --bg-invert:     #0f0f0f;   /* dark footer block        */
  --ink-invert:    #fafafa;
  --muted-invert:  rgba(250, 250, 250, 0.55);
  --line-invert:   rgba(250, 250, 250, 0.16);

  /* --- Typography ------------------------------------------------------- */
  --font-sans: "Schibsted Grotesk", -apple-system, BlinkMacSystemFont,
               "Segoe UI", Helvetica, Arial, sans-serif;

  /* Weight: the reference sets everything at 500 and lets size carry hierarchy. */
  --fw-regular: 400;
  --fw-medium:  500;
  --fw-semi:    600;

  /* Size ramp. Fluid where it matters; fixed for meta text. */
  --fs-meta:    13px;                            /* card titles, nav, labels  */
  --fs-label:   14px;                            /* eyebrows, list items      */
  --fs-body:    clamp(15px, 0.4vw + 13.5px, 16px);
  --fs-lead:    clamp(17px, 0.5vw + 14.5px, 18px); /* hero statement          */
  --fs-sub:     clamp(18px, 0.5vw + 15px, 20px);   /* service group headings  */
  --fs-h2:      clamp(34px, 4vw, 54px);            /* SERVICES. / CLIENTS.    */
  --fs-h1:      clamp(38px, 5vw, 64px);            /* LET'S WORK TOGETHER.    */
  --fs-page:    clamp(44px, 5.6vw, 80px);          /* PROJECTS. / INFO. / CONTACT. */

  /* Tracking tiers — measured off the reference. */
  --ls-tight:   -0.03em;   /* 13–14px text */
  --ls-tighter: -0.04em;   /* 16–20px text */
  --ls-display: -0.05em;   /* 34px and up  */
  --ls-page:    -0.06em;   /* interior page titles */

  --lh-body:    1.4;
  --lh-sub:     1.2;
  --lh-display: 0.85;

  /* --- Space ------------------------------------------------------------ */
  --gutter:      20px;                          /* page side padding        */
  --gap-grid:    8px;                           /* project grid column gap  */
  --gap-row:     12px;                          /* project grid row gap     */
  --space-xs:    8px;
  --space-sm:    16px;
  --space-md:    32px;
  --space-lg:    clamp(48px, 6vw, 88px);
  --section-gap: clamp(72px, 9vw, 140px);       /* vertical rhythm          */
  --header-gap:  clamp(24px, 4vw, 64px);        /* wordmark ↔ portrait      */

  /* --- Motion ----------------------------------------------------------- */
  --ease:      cubic-bezier(0.22, 1, 0.36, 1);  /* the one curve, everywhere */
  --ease-soft: cubic-bezier(0.33, 1, 0.68, 1);
  --dur-fast:  0.3s;
  --dur:       0.45s;
  --dur-slow:  0.9s;

  /* --- Component sizing ------------------------------------------------- */
  /* --- Header wordmark & nav (these two work together) -------------------
     The wordmark grows until its right edge meets the last nav link's, so:
       • --nav-span      pushes CONTACT right/left → the wordmark follows.
       • --wordmark-max  is a hard ceiling in px. Set it BELOW the size the
                         nav boundary would give and it becomes the size,
                         letting the wordmark stop short of CONTACT.
     ---------------------------------------------------------------------- */
  --nav-span:     90%;     /* how far right the 4 primary nav links spread   */
  --wordmark-max: 240px;   /* upper bound for the auto-fitting wordmark      */
  --avatar:       134px;   /* header portrait square                           */
  --logo-cell:    230px;   /* client marquee cell                              */
  --media-ratio:  4 / 3;   /* project thumbnail aspect ratio                   */
}

/* --------------------------------------------------------------------------
   2. RESET / BASE
   -------------------------------------------------------------------------- */
*,
*::before,
*::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  /* Lenis drives scrolling; native smooth-scroll would fight it. */
  scroll-behavior: auto;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-tighter);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Lenis needs the document to not be height-constrained. */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-stopped { overflow: hidden; }

h1, h2, h3, h4, p, figure, ul, ol { margin: 0; }
ul, ol { padding: 0; list-style: none; }

img, svg { display: block; max-width: 100%; }

a {
  color: inherit;
  text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
}

/* Visible keyboard focus that matches the minimal language. */
:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 3px;
  border-radius: 2px;
}
.on-dark :focus-visible { outline-color: var(--ink-invert); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------------------------
   3. LAYOUT PRIMITIVES
   -------------------------------------------------------------------------- */
.container {
  width: 100%;
  padding-inline: var(--gutter);
}

/* Hairline rule used between header rows and above section headings. */
.rule {
  height: 1px;
  background: var(--line);
  border: 0;
  margin: 0;
}

/* Small uppercase/meta type — "Featured work", card titles, eyebrows. */
.meta {
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  line-height: var(--lh-body);
}
.meta--muted { color: var(--muted); }

/* Big section headings: SERVICES. / CLIENTS. */
.section-title {
  font-size: var(--fs-h2);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  font-weight: var(--fw-medium);
}

.section { padding-block: 0; }
/* Vertical rhythm between every top-level section, whatever classes it carries. */
main > section + section { margin-top: var(--section-gap); }

/* --------------------------------------------------------------------------
   4. HEADER
   -------------------------------------------------------------------------- */
.site-header {
  position: relative;
  z-index: 60;
  background: var(--bg);
  padding-top: 12px;
}

/* Row 1 — giant wordmark on the left, portrait square on the right. */
.header-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--header-gap);
  padding-bottom: 10px;
}

/* flex-basis:0 (not auto) is deliberate: it makes this column's width depend
   only on the space left by the portrait, never on the wordmark's own
   font-size. That's what lets main.js resize the text without the container
   resizing in response — no measure/resize feedback loop. */
.wordmark-slot { flex: 1 1 0%; min-width: 0; }

/* The link shrink-wraps the text rather than spanning the whole slot, so
   clicking the empty space to its right doesn't navigate home. */
.wordmark-link { display: inline-block; max-width: 100%; }

/* The wordmark is live text. js/main.js measures it and sets font-size so it
   fills the row — swap the string in js/site.js and it re-fits automatically. */
.wordmark {
  display: block;
  font-size: 64px;                 /* pre-JS fallback; overwritten inline */
  line-height: 0.75;
  letter-spacing: -0.045em;
  font-weight: var(--fw-medium);
  text-transform: uppercase;
  white-space: nowrap;
  /* Clip-reveal wrapper for the load-in animation. */
  overflow: hidden;
}
.wordmark > span { display: inline-block; will-change: transform; }

.header-meta {
  flex: 0 0 auto;
  display: flex;
  align-items: stretch;
  height: var(--avatar);
}

.header-portrait {
  width: var(--avatar);
  height: var(--avatar);
  object-fit: cover;
  background: var(--surface);
}

/* Row 2 — primary nav on the left, socials on the right. */
.header-nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block: 8px 10px;
}

/* Primary links are evenly distributed across the left half, like the
   reference — a fixed-column grid rather than a gap keeps them aligned. */
.nav-primary {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  flex: 1 1 auto;
  max-width: var(--nav-span);
}

/* --------------------------------------------------------------------------
   4b. LANGUAGE TOGGLE
   --------------------------------------------------------------------------
   Reads as "EN / PT": the active language sits at full ink, the other is
   muted until hovered. It sits alone at the right end of the nav row, so it
   needs no divider to separate it from anything.
   -------------------------------------------------------------------------- */
.lang-toggle {
  display: inline-flex;
  align-items: baseline;
  flex: 0 0 auto;
  gap: 6px;
}

.lang-option {
  position: relative;
  font-size: var(--fs-meta);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  color: var(--muted);
  transition: color var(--dur) var(--ease);
}

.lang-option[aria-pressed="true"] { color: var(--ink); }

.lang-option:hover,
.lang-option:focus-visible { color: var(--ink); }

/* Same underline-reveal as the nav, so the two read as one system. */
.lang-option::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: -2px;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.lang-option:hover::after { transform: scaleX(1); transform-origin: left; }
/* The active language doesn't need an affordance — it's already here. */
.lang-option[aria-pressed="true"]::after { content: none; }

.lang-sep {
  font-size: var(--fs-meta);
  line-height: 1;
  color: var(--line-strong);
  user-select: none;
}

/* In the overlay the options sit larger, to match the menu's scale. */
.menu-overlay-foot .lang-option,
.menu-overlay-foot .lang-sep { font-size: var(--fs-label); }

.nav-link {
  position: relative;
  display: inline-block;
  justify-self: start;
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  color: var(--ink);
  padding-block: 2px;
}

/* Underline reveal: wipes in from the left, out to the right. */
.nav-link::after {
  content: "";
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.nav-link:hover::after,
.nav-link:focus-visible::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Active page: permanently underlined, full-strength ink. */
.nav-link[aria-current="page"]::after {
  transform: scaleX(1);
  transform-origin: left;
}

/* Mobile-only "+" that opens the overlay menu. */
.nav-toggle {
  display: none;
  width: 36px;
  height: 36px;
  align-items: center;
  justify-content: center;
  margin-right: -8px;
}
.nav-toggle svg { transition: transform var(--dur) var(--ease); }
body.menu-open .nav-toggle svg { transform: rotate(135deg); }

/* --------------------------------------------------------------------------
   5. MOBILE MENU OVERLAY
   -------------------------------------------------------------------------- */
.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: 55;
  background: var(--bg);
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: var(--gutter);
  opacity: 0;
  visibility: hidden;
  transition: opacity var(--dur) var(--ease), visibility 0s linear var(--dur);
}
body.menu-open .menu-overlay {
  opacity: 1;
  visibility: visible;
  transition: opacity var(--dur) var(--ease), visibility 0s;
}

.menu-overlay ul { display: flex; flex-direction: column; gap: 4px; }

/* Scoped to the nav list — the footer's social links and language toggle
   must keep their small meta scale, not blow up to menu size. */
.menu-overlay ul a {
  display: block;
  font-size: clamp(34px, 11vw, 56px);
  line-height: 1.05;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
body.menu-open .menu-overlay ul a { opacity: 1; transform: none; }
/* Stagger the links in. */
body.menu-open .menu-overlay li:nth-child(1) a { transition-delay: 0.06s; }
body.menu-open .menu-overlay li:nth-child(2) a { transition-delay: 0.12s; }
body.menu-open .menu-overlay li:nth-child(3) a { transition-delay: 0.18s; }
body.menu-open .menu-overlay li:nth-child(4) a { transition-delay: 0.24s; }

/* Holds the language switch below the nav links. */
.menu-overlay-foot {
  margin-top: var(--space-lg);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  color: var(--muted);
  /* Fades in after the nav links have finished staggering. */
  opacity: 0;
  transform: translateY(24px);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
body.menu-open .menu-overlay-foot {
  opacity: 1;
  transform: none;
  transition-delay: 0.3s;
}

/* --------------------------------------------------------------------------
   6. HERO
   -------------------------------------------------------------------------- */
.hero { padding-top: clamp(40px, 7vw, 96px); }

.hero-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: clamp(20px, 2.5vw, 34px);
}

.hero-statement {
  /* Explicit basis: without it the flex item shrinks to min-content
     (one word per line) once main.js wraps the words for splitting. */
  flex: 0 1 600px;
  min-width: 0;
  max-width: 600px;
  font-size: var(--fs-lead);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-tighter);
}

/* Line-by-line clip reveal. main.js wraps each visual line in .line > .line-inner.
   Applies to any element carrying data-split="lines" — hero statement, page titles. */
[data-split="lines"] .line { display: block; overflow: hidden; }
[data-split="lines"] .line-inner { display: block; will-change: transform; }
/* Descenders (g, y, p) would otherwise be shaved off by the clip box. */
[data-split="lines"] .line { padding-bottom: 0.12em; margin-bottom: -0.12em; }

.hero-eyebrow {
  flex: 0 0 auto;
  display: flex;
  gap: 6px;
  font-size: var(--fs-label);
  letter-spacing: var(--ls-tight);
  white-space: nowrap;
}
.hero-eyebrow span:last-child { color: var(--muted); }

/* --------------------------------------------------------------------------
   7. PROJECT GRID + CARDS
   -------------------------------------------------------------------------- */
.project-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  column-gap: var(--gap-grid);
  row-gap: var(--gap-row);
}

.project-card {
  display: flex;
  flex-direction: column;
  gap: 4px;
  color: var(--ink);
}

.card-media {
  position: relative;
  aspect-ratio: var(--media-ratio);
  overflow: hidden;
  background: var(--surface);
}

.card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: filter var(--dur) var(--ease);
}

/* Hover, part 1: the image dims a little. */
.project-card:hover .card-media img,
.project-card:focus-visible .card-media img { filter: brightness(0.88); }

/* --------------------------------------------------------------------------
   Hover, part 2: four corner brackets fly inward.
   --------------------------------------------------------------------------
   One element does all four corners: a 2px border masked down to a 14px
   square at each corner — the same geometry the reference draws with SVG
   (14x14 box, 2px stroke).

   At rest the frame sits at inset:-2px, i.e. just OUTSIDE .card-media's
   overflow:hidden, so it is clipped away entirely rather than faded. On
   hover it moves inward and the corners appear to slide in from the edges.
   -------------------------------------------------------------------------- */
.card-frame {
  --corner: 14px;
  position: absolute;
  inset: -2px;
  border: 2px solid var(--ink-invert);
  pointer-events: none;
  -webkit-mask:
    linear-gradient(#000 0 0) top left     / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) top right    / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) bottom left  / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) bottom right / var(--corner) var(--corner) no-repeat;
  mask:
    linear-gradient(#000 0 0) top left     / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) top right    / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) bottom left  / var(--corner) var(--corner) no-repeat,
    linear-gradient(#000 0 0) bottom right / var(--corner) var(--corner) no-repeat;
  /* Longhands, not the `inset` shorthand — not every engine transitions it. */
  transition: top var(--dur) var(--ease), right var(--dur) var(--ease),
              bottom var(--dur) var(--ease), left var(--dur) var(--ease);
}

.project-card:hover .card-frame,
.project-card:focus-visible .card-frame {
  top: 6px; right: 6px; bottom: 6px; left: 6px;
}

.project-card .card-info {
  display: flex;
  gap: 6px;
  overflow: hidden;
  transform: translateY(0);
  transition: transform var(--dur) var(--ease);
}
.project-card:hover .card-info,
.project-card:focus-visible .card-info { transform: translateY(-2px); }

.card-title {
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  text-transform: uppercase;
  white-space: nowrap;
}
.card-category {
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
  transition: color var(--dur) var(--ease);
}
.project-card:hover .card-category { color: var(--ink); }

/* --------------------------------------------------------------------------
   8. SERVICES
   -------------------------------------------------------------------------- */
.services-head { margin-bottom: var(--space-sm); }
.services-head .rule { margin-top: 6px; }

.services-body {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap-grid);
  margin-top: clamp(20px, 3vw, 40px);
}

.services-intro {
  grid-column: 1 / span 5;
  max-width: 600px;
  font-size: var(--fs-body);
  letter-spacing: var(--ls-tighter);
}

.service-group:nth-of-type(1) { grid-column: 7 / span 2; }
.service-group:nth-of-type(2) { grid-column: 9 / span 2; }
.service-group:nth-of-type(3) { grid-column: 11 / span 2; }

.service-group h3 {
  font-size: var(--fs-sub);
  font-weight: var(--fw-medium);
  line-height: var(--lh-sub);
  letter-spacing: var(--ls-tighter);
  margin-bottom: 10px;
}

.service-group li {
  position: relative;
  padding-left: 10px;
  font-size: var(--fs-label);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
}
.service-group li::before {
  content: "•";
  position: absolute;
  left: 0;
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   9. CLIENT MARQUEE
   -------------------------------------------------------------------------- */
.clients-head { margin-bottom: clamp(20px, 3vw, 40px); }
.clients-head .rule { margin-top: 6px; }

.marquee {
  position: relative;
  overflow: hidden;
  /* Full-bleed out of the gutter so logos run edge to edge. */
  width: 100vw;
  margin-left: calc(50% - 50vw);
  border-block: 1px solid var(--line);
}

.marquee-track {
  display: flex;
  width: max-content;
  animation: marquee-scroll var(--marquee-duration, 42s) linear infinite;
  will-change: transform;
}
/* Slow (don't stop — a hard stop reads as a bug) when the pointer is over it. */
.marquee:hover .marquee-track { animation-play-state: paused; }

@keyframes marquee-scroll {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(-50%, 0, 0); }   /* track content is duplicated */
}

.marquee-item {
  flex: 0 0 auto;
  width: var(--logo-cell);
  height: var(--logo-cell);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  border-right: 1px solid var(--line);
  background: var(--bg);
  transition: background var(--dur) var(--ease);
}
.marquee-item:hover { background: var(--surface); }

.marquee-item img {
  width: 130px;
  height: auto;
  opacity: 0.68;
  transition: opacity var(--dur) var(--ease);
}
.marquee-item:hover img { opacity: 1; }

.marquee-item .client-name {
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.marquee-item:hover .client-name { opacity: 1; transform: none; }

/* Touch devices get no hover, so keep the names permanently visible. */
@media (hover: none) {
  .marquee-item .client-name { opacity: 1; transform: none; }
  .marquee-item img { opacity: 0.75; }
}

/* --------------------------------------------------------------------------
   10. FOOTER
   -------------------------------------------------------------------------- */
.site-footer { margin-top: var(--section-gap); }

.footer-cta {
  background: var(--bg-invert);
  color: var(--ink-invert);
  padding-block: clamp(48px, 6vw, 88px) 20px;
}

.footer-headline {
  font-size: var(--fs-h1);
  font-weight: var(--fw-medium);
  line-height: 1;
  letter-spacing: var(--ls-display);
  text-transform: uppercase;
}

.footer-sub {
  margin-top: 12px;
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted-invert);
  max-width: 46ch;
}

.footer-contact {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm) var(--space-md);
  margin-top: clamp(56px, 8vw, 120px);
  padding-top: 18px;
  border-top: 1px solid var(--line-invert);
}

.footer-group { display: flex; flex-wrap: wrap; gap: 22px; }

.footer-link {
  position: relative;
  font-size: var(--fs-meta);
  font-weight: var(--fw-semi);
  letter-spacing: -0.02em;
  text-transform: uppercase;
  opacity: 0.85;
  transition: opacity var(--dur) var(--ease);
}
.footer-link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.footer-link:hover { opacity: 1; }
.footer-link:hover::after,
.footer-link:focus-visible::after { transform: scaleX(1); transform-origin: left; }

.footer-base {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-xs) var(--space-md);
  margin-top: 44px;
  font-size: 12px;
  letter-spacing: var(--ls-tight);
  color: var(--muted-invert);
}
.footer-base a { text-decoration: underline; text-underline-offset: 3px; }

/* --------------------------------------------------------------------------
   11. INTERIOR PAGE BLOCKS (projects / info / contact)
   -------------------------------------------------------------------------- */
.page-head {
  padding-top: clamp(40px, 7vw, 96px);
  margin-bottom: clamp(24px, 3vw, 44px);
}
.page-head .rule { margin-top: 6px; }

/* Interior page titles run larger than section headings — 80px in the
   reference, against 54px for SERVICES. / CLIENTS. */
.page-title {
  font-size: var(--fs-page);
  line-height: 1;
  letter-spacing: var(--ls-page);
  text-transform: uppercase;
  font-weight: var(--fw-medium);
}

.page-intro {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: var(--space-md);
  margin-bottom: clamp(20px, 2.5vw, 34px);
}
.page-lead {
  flex: 0 1 600px;
  min-width: 0;
  max-width: 600px;
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-tighter);
}

/* --- Info page ---------------------------------------------------------- */
.about-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: var(--gap-grid);
  row-gap: var(--space-lg);
}
.about-portrait { grid-column: 1 / span 4; }
.about-portrait img {
  width: 100%;
  /* height:auto is required or the img's height attribute wins and
     aspect-ratio is ignored, leaving a non-square frame. */
  height: auto;
  aspect-ratio: 1;
  object-fit: cover;
  background: var(--surface);
}
.about-copy {
  grid-column: 6 / span 7;
  display: grid;
  gap: 18px;
  /* Without this the auto rows stretch to match the portrait's height and
     the paragraphs drift apart. */
  align-content: start;
}
.about-copy p { font-size: var(--fs-body); letter-spacing: var(--ls-tighter); }
.about-copy p + p { color: var(--muted); }

/* Numbered stat row */
.stats {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--gap-grid);
  border-top: 1px solid var(--line);
  padding-top: 18px;
}
.stat-value {
  font-size: clamp(28px, 3.4vw, 44px);
  line-height: 1;
  letter-spacing: var(--ls-display);
}
.stat-label {
  margin-top: 8px;
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
}

/* Timeline-style list used for "Approach" and "Recognition" */
.list-rows { border-top: 1px solid var(--line); }
.list-row {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr) auto;
  gap: var(--space-sm);
  align-items: baseline;
  padding-block: 18px;
  border-bottom: 1px solid var(--line);
  transition: background var(--dur) var(--ease);
}
.list-row-index { font-size: var(--fs-meta); letter-spacing: var(--ls-tight); color: var(--muted); }
.list-row-title { font-size: var(--fs-sub); letter-spacing: var(--ls-tighter); }
.list-row-note  { font-size: var(--fs-meta); letter-spacing: var(--ls-tight); color: var(--muted); }

/* --------------------------------------------------------------------------
   CONTACT PAGE
   --------------------------------------------------------------------------
   Two columns throughout, matching the reference: title left / contact
   details right, then intro left / form right.
   -------------------------------------------------------------------------- */
.contact-head {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-md);
  align-items: end;                 /* details sit on the title's baseline */
  padding-top: clamp(40px, 7vw, 96px);
}
.contact-head + .rule { margin-top: 10px; }

/* "Email / HELLO@…"  "Phone / +351…" — 40px apart, like the reference. */
.contact-channels {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 40px;
}
.channel-label {
  font-size: var(--fs-label);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
}
.channel-value {
  position: relative;
  display: inline-block;
  margin-top: 3px;
  font-size: var(--fs-meta);
  font-weight: var(--fw-semi);
  letter-spacing: -0.02em;
  text-transform: uppercase;
  white-space: nowrap;
}
.channel-value::after {
  content: "";
  position: absolute;
  left: 0; bottom: -2px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.channel-value:hover::after,
.channel-value:focus-visible::after { transform: scaleX(1); transform-origin: left; }

.contact-body {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: var(--space-lg) var(--space-md);
  margin-top: clamp(28px, 3.5vw, 48px);
}

.contact-intro {
  max-width: 600px;
  font-size: var(--fs-body);
  letter-spacing: var(--ls-tighter);
}

/* --- The form ----------------------------------------------------------- */
.contact-form {
  display: flex;
  flex-direction: column;
  gap: 24px;                        /* the reference's field rhythm */
}

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

.field-label {
  font-size: var(--fs-label);
  font-weight: var(--fw-medium);
  letter-spacing: var(--ls-tight);
  color: var(--ink);
}

/* The underline lives on the wrapper, not the input, so the padding sits
   between the text and the rule exactly as the reference has it. */
.field-control {
  display: block;
  padding: 8px 20px 8px 0;
  border-bottom: 1px solid var(--line-strong);
  transition: border-color var(--dur) var(--ease);
}
.field-control:focus-within { border-bottom-color: var(--ink); }

.field-control input,
.field-control textarea {
  display: block;
  width: 100%;
  margin: 0;
  padding: 0;
  border: 0;
  background: none;
  font-family: inherit;
  font-size: var(--fs-body);
  font-weight: var(--fw-medium);
  line-height: var(--lh-body);
  letter-spacing: var(--ls-tighter);
  color: var(--ink);
  resize: none;
}
.field-control input:focus,
.field-control textarea:focus { outline: none; }

.field-control input::placeholder,
.field-control textarea::placeholder {
  color: var(--muted);
  opacity: 1;                       /* Firefox dims placeholders by default */
}

.field-control textarea { height: 124px; }

/* Flag a field the browser rejected, but only once the user has tried. */
.contact-form.is-validated input:invalid,
.contact-form.is-validated textarea:invalid { color: var(--ink); }
.contact-form.is-validated .field-control:has(:invalid) { border-bottom-color: #c0392b; }

/* Spam trap: bots fill what they can't see. Kept off-screen rather than
   display:none, which some bots skip. */
.field-honeypot {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.form-foot {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 8px 20px;
}

.form-submit {
  position: relative;
  align-self: flex-start;
  font-size: var(--fs-body);
  font-weight: var(--fw-semi);
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--ink);
}
.form-submit::after {
  content: "";
  position: absolute;
  left: 0; bottom: -3px;
  width: 100%; height: 1px;
  background: currentColor;
  transform: scaleX(0);
  transform-origin: right;
  transition: transform var(--dur) var(--ease);
}
.form-submit:hover::after,
.form-submit:focus-visible::after { transform: scaleX(1); transform-origin: left; }

.form-status {
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--dur) var(--ease), transform var(--dur) var(--ease);
}
.form-status.is-visible { opacity: 1; transform: none; }

.availability {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: var(--fs-meta);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
  margin-top: 20px;
}
.availability::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: #3fae6a;
  animation: pulse 2.4s var(--ease) infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50%      { opacity: 0.45; transform: scale(0.82); }
}

/* Accordion-free FAQ — plain details/summary, styled to match. */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-sm);
  padding-block: 16px;
  cursor: pointer;
  list-style: none;
  font-size: var(--fs-body);
  letter-spacing: var(--ls-tighter);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: "+";
  font-size: 18px;
  line-height: 1;
  color: var(--muted);
  transition: transform var(--dur) var(--ease);
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq p {
  padding-bottom: 18px;
  max-width: 62ch;
  font-size: var(--fs-label);
  letter-spacing: var(--ls-tight);
  color: var(--muted);
}

/* --------------------------------------------------------------------------
   12. SCROLL REVEAL
   --------------------------------------------------------------------------
   Elements start hidden via .reveal. Either GSAP/ScrollTrigger or the
   IntersectionObserver fallback adds .is-visible. Both share this transition,
   so motion is identical whichever path runs.
   -------------------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(32px);
}
/* Only the fallback path transitions in CSS; GSAP animates inline styles. */
html:not(.gsap-active) .reveal {
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
html:not(.gsap-active) .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* Until JS boots, don't leave content invisible for no-JS visitors. */
html.no-js .reveal { opacity: 1; transform: none; }

/* --------------------------------------------------------------------------
   13. PAGE TRANSITION
   -------------------------------------------------------------------------- */
.page-veil {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--bg);
  pointer-events: none;
  opacity: 1;
  transition: opacity 0.5s var(--ease);
}
html.is-ready .page-veil { opacity: 0; }
html.is-leaving .page-veil { opacity: 1; transition-duration: 0.32s; }
html.no-js .page-veil { display: none; }

/* --------------------------------------------------------------------------
   14. RESPONSIVE
   -------------------------------------------------------------------------- */

/* --- Tablet ------------------------------------------------------------- */
@media (max-width: 1080px) {
  :root { --avatar: 104px; --logo-cell: 190px; }

  .project-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }

  .services-intro { grid-column: 1 / span 12; }
  .service-group:nth-of-type(1) { grid-column: 1 / span 4; }
  .service-group:nth-of-type(2) { grid-column: 5 / span 4; }
  .service-group:nth-of-type(3) { grid-column: 9 / span 4; }
  .services-body { row-gap: var(--space-lg); }

  .about-portrait { grid-column: 1 / span 5; }
  .about-copy     { grid-column: 7 / span 6; }

  /* Title and details stack; form drops below the intro. */
  .contact-head,
  .contact-body {
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
  }
  .contact-head { gap: 20px; }
  .contact-intro { max-width: none; }
}

/* --- Compact header + single-column layouts ----------------------------- */
@media (max-width: 860px) {
  :root { --avatar: 0px; }

  .header-top {
    align-items: center;
    padding-bottom: 12px;
  }
  /* Compact wordmark: JS stops auto-fitting below this width. */
  .wordmark { font-size: clamp(24px, 6.4vw, 34px); line-height: 1; }

  .header-meta { display: none; }
  .header-portrait { display: none; }

  .nav-toggle { display: flex; }

  /* Row 2 collapses — nav lives in the overlay instead. */
  .header-nav { display: none; }

  .hero-head,
  .page-intro { flex-direction: column; align-items: flex-start; gap: 14px; }

  /* The 600px flex-basis is a WIDTH on desktop but would become a HEIGHT
     once the container stacks — reset it or the hero grows a 600px gap. */
  .hero-statement,
  .page-lead { flex: 0 1 auto; max-width: none; }

  .stats { grid-template-columns: repeat(2, minmax(0, 1fr)); row-gap: var(--space-md); }

  .list-row { grid-template-columns: 56px minmax(0, 1fr); }
  .list-row-note { grid-column: 2; }

  .about-portrait { grid-column: 1 / span 12; max-width: 320px; }
  .about-copy     { grid-column: 1 / span 12; }
}

/* --- Phone -------------------------------------------------------------- */
@media (max-width: 640px) {
  :root {
    --gutter: 16px;
    --logo-cell: 152px;
    --gap-row: 20px;
  }

  .project-grid { grid-template-columns: minmax(0, 1fr); }

  .services-intro { grid-column: 1 / span 12; }
  .service-group:nth-of-type(1),
  .service-group:nth-of-type(2),
  .service-group:nth-of-type(3) { grid-column: 1 / span 12; }

  .marquee-item img { width: 92px; }

  .footer-contact { flex-direction: column; align-items: flex-start; }
  .footer-group { gap: 16px; }
}

/* --------------------------------------------------------------------------
   15. REDUCED MOTION
   --------------------------------------------------------------------------
   Everything resolves to its final state instantly. Lenis is also
   disabled in JS.
   -------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
    scroll-behavior: auto !important;
  }

  .reveal { opacity: 1 !important; transform: none !important; }
  [data-split="lines"] .line-inner { transform: none !important; }
  .wordmark > span { transform: none !important; }
  .marquee-track { animation: none !important; }
  .page-veil { display: none; }
  .availability::before { animation: none !important; }
}

/* --------------------------------------------------------------------------
   16. PRINT
   -------------------------------------------------------------------------- */
@media print {
  .page-veil, .marquee, .nav-toggle { display: none !important; }
  .reveal { opacity: 1 !important; transform: none !important; }
  body { background: #fff; }
}
