/*
  Design tokens, layout, and components for the Paul Kebokwu portfolio.
  Values pulled directly from the Figma design (node 1:1040,
  file HbM6vLvEMI9VCpquZUHNcI). Desktop-first at the 1920 Figma frame width,
  with a mobile stacking pass at the bottom.
*/

:root {
  --black: #000000;
  --near-black: #0b0c0f;
  --cream: #fffbf5;
  --white: #ffffff;
  --border-dark: #1f1f1f;
  --border-light: rgba(255, 255, 255, 0.1);
  --text-gray: #666666;
  --accent-start: #f52a03;
  --accent-end: #ff8932;
  --accent-gradient: linear-gradient(98deg, var(--accent-start) 25%, var(--accent-end) 88%);

  --font-display: 'Plus Jakarta Sans', 'Helvetica Neue', Arial, sans-serif;
  --font-ui: 'Manrope', 'Helvetica Neue', Arial, sans-serif;
  --font-number: 'Helvetica Neue', Arial, sans-serif;

  /* Smooth, premium deceleration — no bounce/overshoot — used across the
     project-card hover interaction and its entrance animation. */
  --ease-premium: cubic-bezier(0.16, 1, 0.3, 1);
}

*, *::before, *::after { box-sizing: border-box; }
/* No `scroll-behavior: smooth` here — GSAP ScrollSmoother now owns all
   scroll easing (including anchor-link jumps), and having the native CSS
   smoothing active at the same time would just fight it. */
body {
  margin: 0;
  background: var(--cream);
  color: var(--near-black);
  font-family: var(--font-ui);
  -webkit-font-smoothing: antialiased;
}
img { display: block; max-width: 100%; height: auto; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; margin: 0; padding: 0; }
h1, h2, h3, h4, h5, h6, p { margin: 0; }
button { font: inherit; cursor: pointer; }

/* ============ CUSTOM CURSOR ============ */
/* Two-part dot + ring that tracks the mouse (see assets/js/gsap-comp/
   custom-cursor.js), layered on top of — not replacing — the real OS
   cursor. Position comes from a CSS custom property the JS updates on
   every mousemove; the lag/trailing smoothness is just a plain CSS
   transition on `transform` reacting to that property changing, not a
   rAF loop. `translate(-50%, -50%)` re-centers each element on its own
   current size, which keeps it centered on the pointer even while the
   inner dot's width/height itself is mid-transition (6px -> 70px) on
   hover. Desktop (fine pointer + real hover) only — touch devices get
   plain native tap behavior, no overlay. */
@media (hover: hover) and (pointer: fine) {
  .cursor-inner,
  .cursor-outer {
    position: fixed;
    top: 0;
    left: 0;
    pointer-events: none;
    z-index: 9999;
    border-radius: 50%;
    transform: translate(var(--cursor-x, -100px), var(--cursor-y, -100px)) translate(-50%, -50%);
  }

  .cursor-inner {
    width: 6px;
    height: 6px;
    background: var(--accent-start);
    transition: transform 0.05s linear, width 0.3s ease, height 0.3s ease, opacity 0.3s ease;
  }

  .cursor-outer {
    width: 30px;
    height: 30px;
    border: 1px solid var(--accent-start);
    transition: transform 0.15s ease-out, opacity 0.3s ease;
  }

  .cursor-inner.cursor-hover { width: 70px; height: 70px; opacity: 0.3; }
  .cursor-outer.cursor-hover { opacity: 0; }
}
@media (hover: none), (pointer: coarse) {
  .cursor-inner, .cursor-outer { display: none; }
}

/* ============ BACK TO TOP ============ */
/* Fixed circular button, hidden until the page has scrolled past 20px
   (see assets/js/gsap-comp/back-to-top.js), then fades/slides in.
   pointer-events toggles with visibility so the invisible at-rest button
   can't eat clicks over whatever sits at that corner of the page. */
.back-to-top {
  position: fixed;
  right: 30px;
  bottom: 30px;
  width: 50px;
  height: 50px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--accent-start);
  border: 1px solid var(--border-light);
  z-index: 900;
  opacity: 0;
  transform: translateY(20px);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s ease, background 0.2s ease;
}
.back-to-top.is-visible { opacity: 1; transform: translateY(0); pointer-events: auto; }
.back-to-top:hover { background: var(--near-black); }
.back-to-top__icon {
  width: 10px;
  height: 10px;
  margin-top: 3px;
  border-top: 2px solid var(--white);
  border-right: 2px solid var(--white);
  transform: rotate(-45deg);
}
@media (max-width: 900px) {
  .back-to-top { right: 16px; bottom: 16px; width: 44px; height: 44px; }
}

.container {
  width: 100%;
  max-width: 1920px;
  margin-inline: auto;
  /* Fixed 63px was tuned for the 1920px reference frame — a flat value
     eats a disproportionately bigger share of the available width as
     the viewport narrows toward 1280px, which is what left several
     desktop sections (hero, footer, project cards) short on room and
     forced their flex rows to wrap. Scales down smoothly instead,
     reaching the exact same 63px at 1920px so nothing changes there. */
  padding-inline: clamp(32px, 3.3vw, 63px);
}

/* Compensates for .header1 now being position:fixed (removed from normal
   flow, see main.css HEADER section) — without this, .hero1 would render
   starting at the very top of the page, hidden underneath the fixed nav.
   --header-height is the header's real measured height (main.js), not a
   guessed pixel value, since it's responsive (wraps to more rows on
   narrow viewports). */
/* clip, not hidden: setting overflow-x alone to a non-visible value makes
   the browser compute overflow-y as auto too (CSS overflow spec), which
   would turn this into a scroll container and fight ScrollSmoother/native
   scroll. clip avoids that — it still prevents horizontal overflow bleed
   without creating a scrolling box.
   This used to live on <body> itself, but WebKit has a long-standing bug
   where any non-visible overflow on body/html makes it the containing
   block for position:fixed descendants instead of the viewport — on iOS
   Safari that broke the header, custom cursor, back-to-top button and
   preloader (all deliberately kept as direct children of body, outside
   this wrapper, specifically to stay viewport-fixed under ScrollSmoother's
   transform — see the HEADER comment below). Scoping the clip to this
   wrapper instead keeps body overflow:visible, so those fixed elements are
   never nested under a non-visible-overflow ancestor and render correctly
   on mobile Safari. */
#smooth-wrapper { overflow-x: clip; }
#smooth-content { padding-top: var(--header-height, 142px); }

/* ============ HEADER ============ */
/* position:fixed, not sticky: the header lives outside #smooth-wrapper
   (see index.html) specifically so ScrollSmoother's transform on
   #smooth-content can't break its positioning — fixed is unaffected by
   ancestor transforms since it isn't one, and being outside the wrapper
   entirely means it's never subject to the eased/lagged scroll anyway
   (always visually "caught up", exactly what a persistent nav wants). */
.header1 {
  background: var(--black);
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  z-index: 100;
  transition: box-shadow 0.3s ease;
}
.header1.sticky { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); }
.sticky-wrapper { background: var(--black); }
.sticky-wrapper.sticky { box-shadow: 0 10px 30px rgba(0, 0, 0, 0.5); }

.header1-menu {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-block: 30px;
}

.header1-social { display: flex; gap: 10px; }
.header1-social__icon {
  width: 46px;
  height: 46px;
  border-radius: 50%;
  border: 1px solid var(--border-light);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: border-color 0.2s ease;
}
.header1-social__icon:hover { border-color: var(--accent-start); }
.header1-social__icon img { width: auto; height: 16px; }

.header1-logo {
  position: relative;
  width: 42px;
  height: 42px;
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.header1-logo__ring { position: absolute; }
.header1-logo__ring--outer { inset: 0; }
.header1-logo__ring--mid { inset: 2.8px; }
.header1-logo__ring--inner { inset: 6px 6px 5.6px 6px; }
.header1-logo span {
  position: relative;
  z-index: 1;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 12px;
  color: var(--white);
}

.header1-cta { display: flex; align-items: center; gap: 15px; }
.header1-cta span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.32px;
  text-transform: uppercase;
  color: var(--white);
}
.header1-cta img { width: 44px; height: 44px; flex-shrink: 0; }
.header1-cta__text-short { display: none; }

.header1-nav {
  border-top: 1px solid var(--border-light);
  border-bottom: 1px solid var(--border-light);
}
.header1-nav ul {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 24px;
  padding-block: 5px;
}
.header1-nav a {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  letter-spacing: -0.32px;
  text-transform: uppercase;
  color: var(--white);
  transition: color 0.2s ease;
}
.header1-nav a:hover { color: var(--accent-start); }
.header1-nav a.is-active { color: var(--accent-start); }

/* Mobile menu toggle — hidden on desktop, shown + wired to open/close
   .header1-nav as a full-screen overlay under the ≤900px breakpoint
   below (assets/js/main.js toggles .is-open + aria-expanded). */
.header1-burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  background: none;
  border: none;
  padding: 0;
}
.header1-burger span {
  display: block;
  width: 22px;
  height: 2px;
  background: var(--white);
  border-radius: 2px;
  transition: transform 0.3s ease, opacity 0.2s ease;
}
.header1-burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.header1-burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.header1-burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

/* ============ HERO ============ */
.hero1 {
  position: relative;
  /* visible, not hidden: .hero-photo grows past its own natural box as it
     scales up — see gsap-comp/img-zoom-gsap.js. This section's own height
     is set dynamically by that script (min-height, in px) once it knows
     the photo's final grown height, so .counter1 starts right at the
     photo's bottom edge with no gap and no overlap. */
  overflow: visible;
  background: var(--cream);
}
.hero1-bg { position: absolute; inset: 0; z-index: 0; }
.hero1-bg img { width: 100%; height: 100%; object-fit: cover; object-position: top; }
.hero1 .container { position: relative; z-index: 1; }

.hero1-content {
  display: flex;
  /* nowrap down to the 900px mobile breakpoint (which switches this to
     a column layout of its own) — flex-wrap:wrap let the availability
     badge/date block drop onto its own row once the desc + photo +
     date's combined width outgrew the viewport, well above 1920px's
     comfortable fit. Every child below is either max-width-capped or
     clamp()-sized, so nowrap just makes them shrink together instead
     of collapsing onto a second row. */
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(16px, 2vw, 40px);
  padding-top: clamp(40px, 6vw, 130px);
}
.hero1-content__desc {
  max-width: clamp(300px, 25.3vw, 485px);
  flex-shrink: 1;
  min-width: 0;
  color: var(--white);
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: clamp(15px, 1.6vw, 24px);
  line-height: 1.4;
}
.hero1-content__thumb-spacer {
  width: clamp(190px, 24vw, 299px);
  height: clamp(90px, 11vw, 140px);
  flex-shrink: 0;
  visibility: hidden;
}

.hero1-content__thumb {
  width: clamp(190px, 24vw, 299px);
  height: clamp(90px, 11vw, 140px);
  border-radius: 150px;
  overflow: hidden;
  background: var(--near-black);
  position: absolute;
  z-index: 30; /* stays above the headline/pills as it grows — it covers them, doesn't fade them out; below the sticky header (z-index 100) */
  will-change: transform;
}
.hero1-content__thumb img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 15%; }

/* JS (img-zoom-gsap.js) grows this element from its natural pill size up to
   a full-width banner via a single uniform `scale` (never scaleX/scaleY) —
   its CSS width/height are set ONCE, at that final grown size, so scaling
   preserves the pill's own aspect ratio exactly (never distorts) and the
   <img>'s object-fit:cover crop (still plain, unchanged) is always computed
   against that same fixed box, so the crop never drifts either. */

.hero1-content-time { text-align: right; }
.hero1-content-time__label {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  text-transform: uppercase;
  color: var(--white);
}
.hero1-content-time__date {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(40px, 7vw, 100px);
  line-height: 0.9;
  text-transform: uppercase;
  color: var(--white);
  margin-top: 18px;
}

.hero1-titleArea { position: relative; padding-top: clamp(30px, 5vw, 80px); }

.hero1-titleArea__lists { position: absolute; inset: 0; pointer-events: none; }
.hero1-titleArea__list {
  position: absolute;
  pointer-events: auto;
  display: inline-flex;
  align-items: center;
  gap: 15px;
  background: var(--cream);
  border: 1px solid var(--near-black);
  border-radius: 66px;
  padding: clamp(10px, 1.04vw, 20px) clamp(18px, 2.45vw, 47px);
  white-space: nowrap;
  z-index: 2;
}
.hero1-titleArea__list span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(14px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--near-black);
}
/* Positions computed from the actual Figma pixel measurements (pill center
   as % of the 1920x1898 hero frame), not estimated — see hero title area
   overlay math: left pill center (224, 611.13) / right pill center
   (1562.15, 639.72) against a 1794x562 title-area box. */
.hero1-titleArea__list--left {
  left: 12.5%;
  top: 41.8%;
  transform: translate(-50%, -50%) rotate(-40deg);
}
.hero1-titleArea__list--right {
  left: 87.1%;
  top: 58%;
  transform: translate(-50%, -50%) rotate(-40deg);
}

.hero1-titleArea__title {
  position: relative;
  z-index: 1;
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(48px, 11.2vw, 216px);
  line-height: 0.95;
  text-transform: uppercase;
  color: var(--near-black);
}
.hero1-titleArea__title-line { display: block; }
.hero1-titleArea__title-line--product { text-align: right; padding-right: clamp(16px, 14vw, 274px); }
.hero1-titleArea__title-line--designer { text-align: left; padding-left: clamp(16px, 11vw, 214px); }

/* ============ COUNTER / STATS ============ */
.counter1 { background: var(--near-black); padding-block: 60px 70px; }
.counter1 .container { padding-inline: clamp(32px, 3.9vw, 75px); }
.counter1-item {
  display: flex;
  /* wrap stays as a genuine safety net (this row must never overflow),
     but the fixed 75px container padding + 40px gap + a flat 26px label
     font that never shrank were what actually forced it to wrap well
     before 1920px shrank down to 1280px — every one of those is now
     fluid, so the 3 stats keep their single row down to 1280px on their
     own without wrap ever needing to engage above that. */
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: clamp(20px, 2.1vw, 40px);
}
.counter1-item-box h1 {
  display: flex;
  align-items: flex-end;
  font-family: var(--font-number);
  font-weight: 700;
  font-size: clamp(60px, 11vw, 216px);
  color: var(--white);
  line-height: 0.95;
}
.counter1-suffix { font-family: var(--font-display); font-weight: 600; }
.counter1-item-box__label {
  display: inline-flex;
  align-items: center;
  gap: clamp(8px, 0.8vw, 15px);
  border: 1px solid var(--white);
  border-radius: 66px;
  padding: clamp(12px, 1.05vw, 20px) clamp(20px, 2.1vw, 40px);
  margin-top: 20px;
}
.counter1-item-box__label span {
  font-family: var(--font-ui);
  font-weight: 700;
  /* Was a flat 26px at every desktop width (including 1920, where 26px
     is the correct design size) — with nothing to shrink, this pill was
     the actual widest part of each stat once the numeral above it
     scaled down, and was the main reason the row wrapped well before
     1280px. */
  font-size: clamp(15px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}

/* ============ ABOUT ============ */
.about1 { background: var(--near-black); padding-block: 127px 130px; }
.about1 .container { padding-inline: 75px; }

.about1__intro {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(28px, 4.4vw, 60px);
  line-height: 1.17;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.1);
}

/* Scroll-scrubbed, word-by-word opacity reveal (word-reveal-gsap.js wraps
   each word of a .word-reveal element's raw text — not any existing child
   element, e.g. .about1__desc's "More about me" label stays untouched — in
   one of these spans, dim by default). Explicit solid white here, not the
   parent's own dim `color` above: the reveal animates plain `opacity`
   (0.1 -> 1) on each word in reading order, so this needs to already be
   full-strength white for that opacity value to land on the right end
   color once a word is done revealing. */
.word-reveal__word { color: var(--white); }

/* Scroll-scrubbed "fill sweep" (text-fill-gsap.js wraps .text-fill text in
   this inner span, then tweens its background-size from 0% to 200% tied to
   scroll position) — a solid-white layer clipped to the exact text shape
   sweeps left-to-right as the element passes through the viewport. The
   plain `color` above is what shows before JS runs / on browsers without
   background-clip:text support; `color: transparent` here hands rendering
   over to the clipped background once that's active. Currently has no
   .text-fill target in the markup — see the script tag comment in
   index.html. */
.text-fill > span {
  position: relative;
  width: 100%;
  color: transparent;
  -webkit-text-fill-color: rgba(255, 255, 255, 0.1);
  background-clip: text;
  -webkit-background-clip: text;
  background-repeat: no-repeat;
  background-image: linear-gradient(rgb(255, 255, 255), rgb(255, 255, 255));
  background-size: 0% 100%;
}

.about1-item {
  display: flex;
  align-items: flex-end;
  justify-content: flex-end;
  /* gap/padding were flat px tuned for 1920 — at narrower desktop
     widths they ate a bigger share of the row, dragging the whole
     "years experience" block noticeably left of its 1920 position
     instead of tracking the same relative spot. Scaled off the 1920
     reference (117/1920, 151/1920, 200/1920 as vw) so it lands in the
     same visual position at every width, not just 1920 itself. */
  gap: clamp(40px, 6.1vw, 117px);
  padding-top: clamp(60px, 7.86vw, 151px);
  padding-right: clamp(40px, 10.42vw, 200px);
  flex-wrap: wrap;
}
.about1-item-numb .odometer-digit {
  font-family: var(--font-number);
  font-weight: 700;
  font-size: clamp(90px, 21vw, 416px);
  color: var(--white);
  line-height: 1;
}
.about1-item-content { display: flex; flex-direction: column; gap: 18px; }
.about1-item-content span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(16px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}

.about1__desc {
  padding-top: 108px;
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(22px, 2.8vw, 54px);
  line-height: 1.3;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.1);
}
.about1__desc2-lowercase {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-right: 24px;
  vertical-align: middle;
}
.about1__desc2-lowercase span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(16px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}

/* ============ PORTFOLIO / PROJECTS ============ */
.project1 { background: var(--cream); }

.project1-titleArea { position: relative; overflow: hidden; }
.project1-titleArea__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.project1-titleArea .container { position: relative; z-index: 1; padding-top: 127px; padding-bottom: 130px; }
.project1-titleArea--skills .container { padding-top: 109px; }

.section-top__title1 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(36px, 7.3vw, 140px);
  line-height: 1;
  text-transform: uppercase;
  color: var(--near-black);
}
.section-top__title1.dim { color: rgba(0, 0, 0, 0.5); }
.section-top__title2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(28px, 7.3vw, 140px);
  line-height: 1;
  text-align: right;
  text-transform: uppercase;
  color: var(--near-black);
  padding-right: 150px;
  margin-top: 20px;
}
.project1-titleArea--skills .section-top__title2 { padding-right: 0; }

/* title-flip-anim-gsap.js flips each of these up into place (3D rotateX)
   as the heading scrolls into view — one real line per span (not relying
   on wherever the browser happens to wrap), so each animates as its own
   distinct unit regardless of viewport width. backface-visibility avoids
   a mirrored glimpse of the line while it's rotated past 90deg. */
.title-flip-anim__line {
  display: block;
  backface-visibility: hidden;
}

.project1-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  background: var(--near-black);
}
/* Each grid cell — not .project1-card itself — carries the thin divider
   lines and the 75px breathing room around the card. Real hairlines
   between every card, not gaps of empty background: full border on every
   cell (including the outer edges — top row, bottom row, first column,
   last column) so the whole grid reads as a closed, fully-lined box, not
   just interior seams. Replicates Figma's div.col-md-6 wrapper, which
   .project1-card alone can't do since its own border/radius/background
   below are the CARD's separate, inner styling. */
.project1-cell {
  /* Flat 75px was tuned for 1920 — at 1280 it ate ~150px out of each
     grid column, leaving the card itself too narrow for its own 3 tag
     pills to fit on one row (see .project1-card-meta below), which
     wrapped one pill onto a second line and broke the card's 1920
     composition. Scaled off the 1920 reference (75/1920 as vw). */
  padding: clamp(24px, 3.9vw, 75px);
  border: 1px solid var(--border-light);
}
.project1-card {
  background: var(--black);
  border: 1px solid var(--border-dark);
  border-radius: 10px;
  overflow: hidden;
  position: relative;
}
.project1-card-meta {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(8px, 0.78vw, 15px);
  justify-content: flex-end;
  padding: clamp(12px, 1.04vw, 20px) clamp(16px, 1.56vw, 30px);
  position: relative;
  z-index: 3;
}
.project1-card-meta__item {
  background: rgba(0, 0, 0, 0.55);
  border: 1px solid var(--border-light);
  border-radius: 65px;
  padding: clamp(5px, 0.36vw, 7px) clamp(8px, 0.52vw, 10px);
  font-family: var(--font-ui);
  font-weight: 600;
  /* Flat 16px, same story as the pill labels elsewhere on the site —
     the one part of this card that never shrank as its own container
     narrowed, so it was the actual cause of the wrap once combined
     with the cell's flat padding above. */
  font-size: clamp(12px, 0.833vw, 16px);
  color: var(--white);
  white-space: nowrap;
}

/* Clips the oversized diagonal overlay and contains the image zoom below —
   without this, both would bleed past the card's own rounded corners. */
.project1-card-media {
  aspect-ratio: 807 / 538;
  margin-top: -75px;
  overflow: hidden;
  position: relative;
  z-index: 2;
}
.project1-card-media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s var(--ease-premium);
}

/* Oversized (well past the card's own edges) and rotated, so the visible
   band always crosses corner-to-corner regardless of the card's own
   aspect ratio — a plain full-size rotated box would leave triangular
   gaps at the corners once rotated. Slides in from the left + fades in on
   hover (see the hover rules below), rather than just appearing, per the
   "light sweep" brief. */
.project1-card-media__overlay {
  position: absolute;
  inset: -25% -60%;
  background: linear-gradient(115deg, transparent 42%, rgba(255, 255, 255, 0.16) 50%, transparent 58%);
  transform: rotate(12deg) translateX(-45%);
  opacity: 0;
  transition: transform 0.55s var(--ease-premium), opacity 0.55s var(--ease-premium);
  pointer-events: none;
  z-index: 1;
}

.project1-card-media__arrow {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 72px;
  height: 72px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  background: var(--white);
  color: var(--near-black);
  font-size: 28px;
  font-weight: 700;
  line-height: 1;
  opacity: 0;
  cursor: pointer;
  transform: translate(-50%, -38%) scale(0.7);
  transition: transform 0.5s var(--ease-premium), opacity 0.5s var(--ease-premium),
    background-color 0.3s ease, color 0.3s ease;
  /* invisible by default; switched to auto only once the card reveals it
     (see .project1-card:hover / .is-active below), so the dead-zone over
     the image isn't clickable until the arrow is actually visible */
  pointer-events: none;
  z-index: 2;
}
/* hovering the arrow itself (once visible) inverts it white -> black,
   distinct from the card-wide reveal above it */
@media (hover: hover) and (pointer: fine) {
  .project1-card-media__arrow:hover {
    background: var(--near-black);
    color: var(--white);
  }
}

/* True mouse hover only — touch devices get the same visual states via
   .project1-card.is-active instead (tap-toggled in main.js), since CSS
   :hover on touch just latches on after a tap with no clean way to un-set
   it, which is exactly the "stuck open" state to avoid. */
@media (hover: hover) and (pointer: fine) {
  .project1-card:hover .project1-card-media img { transform: scale(1.03); }
  .project1-card:hover .project1-card-media__overlay {
    opacity: 1;
    transform: rotate(12deg) translateX(0%);
  }
  .project1-card:hover .project1-card-media__arrow {
    opacity: 1;
    pointer-events: auto;
    transform: translate(-50%, -50%) scale(1);
  }
}
.project1-card.is-active .project1-card-media img { transform: scale(1.03); }
.project1-card.is-active .project1-card-media__overlay {
  opacity: 1;
  transform: rotate(12deg) translateX(0%);
}
.project1-card.is-active .project1-card-media__arrow {
  opacity: 1;
  pointer-events: auto;
  transform: translate(-50%, -50%) scale(1);
}
.project1-card-content {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px;
  padding: 20px 30px 30px;
  position: relative;
  z-index: 1;
}
.project1-card-content a {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(18px, 1.8vw, 30px);
  text-transform: uppercase;
  color: var(--white);
}
/* Mobile-only shortened titles (LisBon drops "(Dubai)", Eventra drops its
   "— Marketplace Design" subtitle) — see the ≤900px override below. */
.project1-card-content__title-short { display: none; }
.project1-card-content__button {
  background: var(--white);
  color: var(--near-black);
  border-radius: 65px;
  padding: 7px 20px;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 16px;
  white-space: nowrap;
}

.project1-btn-wrapper { display: flex; justify-content: center; padding-block: 130px; background: var(--near-black); }
/* Aliyo's "flip reveal" hover: an accent-colored circle sits behind the
   icon/label, tipped 90deg back in 3D and invisible at rest; on hover it
   rotates forward flat + fades in, like a card flipping face-up behind
   the button content. `position:relative` + `isolation:isolate` give the
   ::before its own local stacking context, so its z-index:-1 tucks it
   behind the icon/label without needing to fight any OTHER element's
   z-index on the page. Icon and label stay white in both states on
   purpose — white already reads cleanly on both the black base and the
   orange flip-fill, and the icon is a hardcoded-white external SVG
   (assets/images/icons/icon-cta-arrow.svg) that a CSS `color` swap
   wouldn't reach anyway, so swapping just the label would leave the two
   mismatched. */
.project1-see-all {
  position: relative;
  isolation: isolate;
  width: 260px;
  height: 260px;
  border-radius: 130px;
  background: var(--black);
  border: 1px solid var(--near-black);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 20px;
}
.project1-see-all::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: -1;
  border-radius: 50%;
  background: var(--accent-start);
  transform: rotateX(90deg);
  opacity: 0;
  transition: transform 250ms ease-in, opacity 250ms ease-in;
}
.project1-see-all:is(:hover, :focus)::before {
  transform: rotateX(0deg);
  opacity: 1;
  transition: transform 250ms ease-out, opacity 250ms ease-out;
}
.project1-see-all img { transform: rotate(-45deg); }
.project1-see-all span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 18px;
  text-transform: uppercase;
  color: var(--white);
}

/* ============ TESTIMONIALS ============ */
.testimonial1 { position: relative; padding-block: 130px; overflow: hidden; }
.testimonial1-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.testimonial1 .container { position: relative; z-index: 1; }

.testimonial1-swiper { max-width: 1136px; margin-inline: auto; }
.testimonial1-card { background: var(--white); padding: 50px clamp(24px, 12vw, 145px) 30px; text-align: center; }
.testimonial1-card__quote { margin-bottom: 50px; }
.testimonial1-card__quote img { margin-inline: auto; }
.testimonial1-card__desc {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(18px, 2vw, 30px);
  line-height: 1.33;
  color: var(--near-black);
  margin-bottom: 20px;
}
.testimonial1-card__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(20px, 2vw, 30px);
  text-transform: uppercase;
  color: var(--near-black);
  margin-bottom: 13px;
}
.testimonial1-card__designation {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 18px;
  text-transform: uppercase;
  color: var(--text-gray);
  padding-bottom: 40px;
}

.testimonial1-card-controls {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border-top: 1px solid var(--near-black);
  padding-block: 11px;
}
.testimonial1-prev, .testimonial1-next {
  background: none;
  border: none;
  padding: 10px;
  line-height: 0;
}
.testimonial1-card-controls__numb {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 20px;
  color: var(--near-black);
}

/* ============ SKILLS MARQUEE ============ */
.marquee1 { background: var(--near-black); overflow: hidden; }
.marquee1-row { border-bottom: 1px solid var(--border-light); padding-block: 40px; overflow: hidden; }
.marquee1-track {
  display: flex;
  align-items: center;
  width: max-content;
  animation: marquee-scroll 32s linear infinite;
}
.marquee1-item { display: flex; align-items: center; gap: 70px; padding-right: 70px; flex-shrink: 0; }
.marquee1-item img { width: clamp(160px, 18vw, 360px); height: clamp(72px, 8vw, 162px); border-radius: 10px; object-fit: cover; }
.marquee1-item span {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(48px, 11vw, 216px);
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}
.marquee1-item span.gradient-text {
  background: linear-gradient(180deg, var(--accent-end) 9%, var(--accent-start) 80%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .marquee1-track { animation: none; }
}

/* ============ AWARDS ============ */
.award1 { position: relative; padding-block: 130px; overflow: hidden; }
.award1-bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.award1 .container { position: relative; z-index: 1; }

.award1-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 40px; padding-bottom: 105px; flex-wrap: wrap; }
.award1__shape { flex-shrink: 0; width: clamp(160px, 18vw, 356px); height: auto; }
.award1__heading {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(32px, 5.2vw, 100px);
  line-height: 1.3;
  text-transform: uppercase;
}
.award1__heading.dim { color: rgba(255, 255, 255, 0.1); }

.award1-bottom { display: flex; align-items: flex-end; gap: 40px; flex-wrap: wrap; }
.award1__avatar { flex-shrink: 0; max-width: 474px; width: 100%; height: auto; }
.award1-content { flex: 1; min-width: 280px; }
.award1-content__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(32px, 3.1vw, 60px);
  text-transform: uppercase;
  color: var(--near-black);
  margin-bottom: 54px;
}
.award1-content-list li {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  border-top: 1px solid var(--near-black);
  padding-block: 34px;
  flex-wrap: wrap;
}
.award1-content-list__numb {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 20px;
  color: var(--near-black);
  min-width: 30px;
  display: inline-block;
}
.award1-content-list__name {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 26px;
  color: var(--near-black);
  margin-left: 50px;
}
.award1-content-list__date {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 20px;
  color: var(--near-black);
  white-space: nowrap;
  margin-left: auto;
}

/* ============ FOOTER / CTA ============ */
.footer1 { background: var(--black); padding-top: 130px; }

.footer1-content { padding: 0 clamp(0px, 3vw, 64px) 76px; }
.footer1-content__title1 {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 40px;
  justify-content: flex-end;
  padding-bottom: 13px;
}
.footer1-content__avatar {
  width: clamp(90px, 11vw, 210px);
  height: clamp(90px, 11vw, 210px);
  border-radius: 150px;
  overflow: hidden;
  background: var(--white);
  flex-shrink: 0;
}
.footer1-content__avatar img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 17%; }
.footer1-content__title1 h2,
.footer1-content__title2 h2 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(40px, 11vw, 216px);
  line-height: 1;
  text-transform: uppercase;
  color: var(--white);
}
.footer1-content__title2 {
  display: flex;
  /* Row must never wrap here — the button belongs beside "HAPPEN" at
     every width. flex-wrap:wrap was the actual bug: title2 h2 and
     .get-touch-btn each scale off their OWN independent vw-based
     clamp(), and .get-touch-btn's clamp maxes out (hits its ceiling)
     around ~1200px while the heading's keeps growing all the way to
     ~1960px — so from ~1200px to ~1900px the heading keeps taking more
     room while the button's holds flat, and their combined width grew
     faster than the row itself, overflowing and wrapping the button
     onto its own line at every width from ~901px to ~1900px. Confirmed
     by measuring both at 1024/1280/1440/1680/1920px before touching
     anything. */
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: 35px;
}
/* Re-tuned coefficient (11vw -> 9.8vw) closes that gap across the whole
   range: solved from the measured widths above for the coefficient that
   keeps heading + gap + button under the row's own width at every
   sampled breakpoint, with headroom to spare, while landing at the same
   216px ceiling only a bit further out — 1920px itself is unaffected,
   since the heading was already well under its 216px cap there (211px)
   and had 62px of slack in the row to begin with. flex-shrink/min-width
   stay as a safety net only; the curve is meant to make them unnecessary
   in practice. */
.footer1-content__title2 h2 { font-size: clamp(40px, 9.6vw, 216px); flex-shrink: 1; min-width: 0; white-space: nowrap; }
.footer1-content__title2 .get-touch-btn { flex-shrink: 0; }
.get-touch-btn {
  display: inline-flex;
  align-items: center;
  gap: 22px;
  padding: clamp(18px, 2.5vw, 30px) clamp(28px, 3.4vw, 48px);
  border-radius: 300px;
  background: var(--accent-gradient);
}
.get-touch-btn span {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(24px, 3vw, 52px);
  text-transform: uppercase;
  color: var(--white);
}

.footer1-content-socialBtn {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 20px;
  padding-top: 60px;
}
.footer1-content-socialBtn__item {
  display: inline-flex;
  align-items: center;
  gap: 15px;
  border: 1px solid var(--cream);
  border-radius: 66px;
  padding: 20px 41px;
  /* --tilt (set per variant below) keeps each pill's own scattered angle
     intact through the hover scale — a plain `transform: scale()` on
     hover would overwrite the rotation and snap the pill flat. */
  transform: rotate(var(--tilt, 0deg));
  transition: transform 300ms var(--ease-premium), background-color 300ms var(--ease-premium), border-color 300ms var(--ease-premium);
}
.footer1-content-socialBtn__item:hover {
  transform: rotate(var(--tilt, 0deg)) scale(1.06);
  background: var(--accent-start);
  border-color: var(--accent-start);
}
.footer1-content-socialBtn__item span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 26px;
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}
.footer1-content-socialBtn__item--1 { --tilt: -10deg; }
.footer1-content-socialBtn__item--2 { --tilt: 10deg; }
.footer1-content-socialBtn__item--3 { --tilt: 10deg; }
.footer1-content-socialBtn__item--4 { --tilt: -10deg; }

.footer1-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  border-top: 1px solid var(--border-light);
  padding-block: 35px;
}
.footer1-bottom-item p,
.footer1-bottom-item a {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: 16px;
  text-transform: uppercase;
  color: var(--white);
}
.footer1-bottom-item ul { display: flex; flex-wrap: wrap; gap: 20px 41px; }
.footer1-bottom-item a:hover { color: var(--accent-start); }

/* ============ CASE STUDY PAGE ============ */
/* Shared by every case-study page (case-studies/*.html) — not just
   Eventra's. Figma reference: node 1:1690 in the same file. */
.case-hero {
  position: relative;
  background: var(--cream);
}
.case-hero__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.case-hero__title {
  position: relative;
  z-index: 1;
  text-align: center;
  padding-block: clamp(40px, 6vw, 130px) clamp(30px, 5vw, 60px);
}
.case-hero__title h1,
.case-hero__title h2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 7.3vw, 140px);
  line-height: 1;
  text-transform: uppercase;
}
.case-hero__title h1 { color: var(--white); }
.case-hero__title h2 {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--near-black);
}

.case-hero__media {
  position: relative;
  aspect-ratio: 1920 / 908;
  overflow: hidden;
  container-type: inline-size;
}
/* Figma node 13:1057 positions every layer with exact absolute px offsets
   against the 1920x908 frame (not a naive object-fit crop) — reproduced
   here as percentages of that frame so the composition scales correctly. */
.case-hero__media-bg {
  position: absolute;
  left: -2.0833%;
  top: -51.874%;
  width: 106.354%;
  height: 223.238%;
  object-fit: cover;
  z-index: 0;
}
.case-hero__media-subject {
  position: absolute;
  left: 23.073%;
  top: -13.657%;
  width: 63.854%;
  height: 202.533%;
  object-fit: cover;
  z-index: 2;
}
/* Plain full-bleed fill for a hero media image that's already a single
   flattened screenshot of the whole 1920x908 composition (Avenir) — not
   Eventra's oversized/offset crop above, which only makes sense for its
   own separate background + subject-cutout layers. */
.case-hero__media-flat {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  z-index: 0;
}
.case-hero__watermark {
  position: absolute;
  left: 11.198%;
  top: 16.08%;
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: 16.905cqw;
  color: var(--white);
  white-space: nowrap;
  z-index: 1;
  pointer-events: none;
}
.case-hero__case-label {
  position: absolute;
  left: 81.667%;
  top: 51.542%;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 2.267cqw;
  color: var(--white);
  z-index: 3;
}

/* Fundex hero media — Figma node 52:3102. Different composition than
   Eventra's (gradient bg + product illustration instead of a photo),
   same 1920x908 reference frame and percentage-positioning approach. */
.case-hero__media--fundex {
  background: linear-gradient(179.14deg, rgba(255, 201, 137, 0) 12.614%, #ba0efe 98.47%);
}
.case-hero__media-illustration {
  position: absolute;
  left: 44.063%;
  top: -9.14%;
  width: 116.04%;
  height: 163.55%;
  transform: translateX(-50%);
  object-fit: contain;
  z-index: 1;
}
.case-hero__media-tagline {
  position: absolute;
  left: 74.583%;
  top: 20.93%;
  width: 38.125%;
  transform: translateX(-50%);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 2.8125cqw;
  line-height: 1.2;
  text-align: center;
  color: var(--near-black);
  z-index: 2;
}
.case-hero__media-wallet {
  position: absolute;
  left: 1.51%;
  top: 45.37%;
  width: 21.39%;
  height: 33.92%;
  object-fit: contain;
  transform: rotate(-0.76deg);
  z-index: 1;
}
.case-hero__media-logo {
  position: absolute;
  left: 77.083%;
  top: 67.84%;
  width: 7.378%;
  height: 12%;
  z-index: 1;
}

/* card overlapping the hero media's bottom edge — Figma node 1:1797 */
.case-info-card {
  position: relative;
  z-index: 3;
  margin-top: -4.375%;
  margin-inline: clamp(16px, 3.3vw, 63px);
  display: flex;
  flex-wrap: wrap;
  background: var(--near-black);
  border: 1px solid var(--border-light);
  border-radius: 10px 10px 0 0;
}
.case-info-card__item {
  flex: 1 1 0;
  min-width: 150px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: clamp(14px, 1.8vw, 35px);
  border-left: 1px solid var(--border-light);
}
.case-info-card__item:first-child { border-left: none; }
.case-info-card__label {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: clamp(12px, 1vw, 20px);
  color: #999999;
}
.case-info-card__value {
  font-family: var(--font-ui);
  font-weight: 800;
  font-size: clamp(13px, 1vw, 20px);
  color: var(--white);
  white-space: nowrap;
}

/* details */
.case-details { background: var(--near-black); padding-block: 130px; }
.case-details-row {
  display: flex;
  flex-wrap: wrap;
  gap: 40px;
  padding-block: 60px;
  border-top: 1px solid var(--border-light);
}
.case-details-row:first-child { border-top: none; padding-top: 0; }
.case-details__label {
  flex: 1 1 320px;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(16px, 1.2vw, 20px);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--white);
}
.case-details__content { flex: 2 1 500px; max-width: 873px; }

.case-behance-btn {
  display: inline-flex;
  align-items: center;
  gap: 15px;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: 16px;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 40px;
  transition: color 0.2s ease;
}
.case-behance-btn:hover { color: var(--accent-start); }
.case-behance-btn img { width: 44px; height: 44px; flex-shrink: 0; }

.case-details__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: clamp(24px, 2.4vw, 40px);
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--white);
  margin-bottom: 24px;
}
.case-details__text {
  font-family: var(--font-ui);
  font-weight: 500;
  font-size: clamp(16px, 1.2vw, 18px);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.7);
}
.case-details__text + .case-details__text { margin-top: 20px; }

.case-thumb-group { display: flex; flex-direction: column; gap: 40px; margin-top: 40px; }
.case-thumb-group img { width: 100%; border-radius: 16px; display: block; }

.case-benefits { list-style: none; margin: 24px 0 0; padding: 0; display: flex; flex-direction: column; gap: 20px; }
.case-benefits li {
  font-family: var(--font-ui);
  font-size: clamp(16px, 1.2vw, 18px);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.7);
}
.case-benefits strong { display: block; color: var(--white); font-weight: 700; margin-bottom: 4px; }

/* Plain disc-bullet list — Avenir's Goals section lists its 5 goals as
   single-sentence bullets, not the numbered title+description pairs
   .case-benefits is built for. */
.case-details__list {
  margin: 24px 0 0;
  padding-left: 27px;
  display: flex;
  flex-direction: column;
  gap: 12px;
}
.case-details__list li {
  font-family: var(--font-ui);
  font-size: clamp(16px, 1.2vw, 18px);
  line-height: 1.7;
  color: rgba(255, 255, 255, 0.7);
}

.case-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 40px; margin-top: 80px; }
.case-gallery__item img { width: 100%; border-radius: 16px; background: var(--white); display: block; }
.case-gallery__caption {
  text-align: center;
  margin-top: 16px;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 16px;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.7);
}

/* ============ ABOUT PAGE ============ */
/* about.html only. Figma reference: node 1:2216 in the same file. Class
   names follow Figma's own component naming (hero3-*, about2-*, video1/2-*,
   work-process1-*, service2-*) per this project's convention of adopting
   the Aliyo/Figma names directly rather than inventing new ones. */

/* ---- hero3 ---- */
.hero3 { position: relative; background: var(--cream); overflow: hidden; padding-bottom: 60px; }
.hero3-bg { position: absolute; inset: 0; z-index: 0; }
.hero3-bg img { width: 100%; height: 108%; object-fit: cover; object-position: top; }
.hero3 .container { position: relative; z-index: 1; }

.hero3-content {
  display: flex;
  align-items: center;
  gap: clamp(16px, 2.2vw, 42px);
  padding-top: clamp(40px, 6vw, 130px);
}
.hero3-content__title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 11.2vw, 216px);
  line-height: 1;
  text-transform: uppercase;
  color: var(--white);
  white-space: nowrap;
}
.hero3-content__thumb {
  flex-shrink: 0;
  border: 2px dashed var(--white);
  border-radius: 10px;
  overflow: hidden;
  width: clamp(130px, 13vw, 250px);
  aspect-ratio: 250 / 168;
}
/* object-position tuned from Figma's own crop (image offset -10/-7 within
   the 250x168 frame) — default center-crop pushes this portrait's face
   out of frame, showing mostly chest/tie instead. */
.hero3-content__thumb img { width: 100%; height: 100%; object-fit: cover; object-position: 67% 8%; }

.hero3-content--desc {
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: clamp(16px, 2vw, 39px);
  padding-top: clamp(16px, 2.5vw, 24px);
}
/* Figma positions these two lines independently within a 440x136 box —
   not a simple top-to-bottom stack: the label sits indented from the
   left near the top, the paragraph is right-aligned near the bottom, the
   two overlapping in x-range rather than following one another. Recreated
   with absolute positioning at the same relative offsets (153/440,
   17/136 and 98/136) rather than flattening it into a flex column. */
.hero3-content__desc {
  position: relative;
  width: clamp(260px, 22.9vw, 440px);
  height: clamp(80px, 7.1vw, 136px);
  font-family: var(--font-display);
  font-weight: 500;
  font-size: clamp(15px, 1.25vw, 24px);
  line-height: 1.3;
  color: var(--near-black);
}
.hero3-content__desc-left {
  position: absolute;
  left: 34.8%;
  top: 12.5%;
  width: 63.7%;
  transform: translateY(-50%);
}
.hero3-content__desc-right {
  position: absolute;
  left: 0;
  top: 72%;
  width: 100%;
  transform: translateY(-50%);
  text-align: right;
}
.hero3-content__title2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 11.2vw, 216px);
  line-height: 1;
  text-transform: uppercase;
  color: var(--near-black);
}
/* Figma's mobile hero (node 192:9758) splits this into "A PRODUCT" /
   "DESIGNER" on two lines — desktop's own Figma frame only shows "a
   designer", so this is a genuine mobile-only copy difference, not a
   simplification of the same text. Swapped via paired spans (same
   pattern as the header CTA's text-full/text-short) so desktop is
   untouched. */
.hero3-content__title2-mobile { display: none; }

.hero3-numbArea {
  position: relative;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  /* Figma's own gap here is 466.47px (~24.3% of the 1920 frame) — not a
     small spacer. Without it the "5+" block just hugs the portrait
     instead of sitting centered in the row like the design. */
  gap: clamp(24px, 24.3vw, 466px);
  padding-top: clamp(30px, 5.8vw, 56px);
}
.hero3-numbArea__thumb {
  flex-shrink: 0;
  width: clamp(220px, 25vw, 479px);
  aspect-ratio: 479 / 733;
  border-radius: 10px;
  overflow: hidden;
}
.hero3-numbArea__thumb img { width: 100%; height: 100%; object-fit: cover; }

.hero3-numbArea-item { display: flex; align-items: flex-end; gap: clamp(10px, 1.5vw, 28px); }
.hero3-numbArea-item-numb h1 {
  display: flex;
  align-items: flex-end;
  font-family: var(--font-number);
  font-weight: 700;
  font-size: clamp(90px, 21vw, 416px);
  color: var(--near-black);
  line-height: 0.95;
}
.hero3-numbArea-item-numb__suffix { font-family: var(--font-display); font-weight: 600; }
.hero3-numbArea-item-content {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 18px;
  padding-bottom: clamp(8px, 1.5vw, 28px);
}
.hero3-numbArea-item-content img { width: clamp(48px, 6vw, 116px); height: auto; }
.hero3-numbArea-item-content span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(14px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--near-black);
  white-space: nowrap;
}

.hero3-titleArea__list {
  position: absolute;
  display: inline-flex;
  align-items: center;
  gap: 15px;
  background: var(--cream);
  border: 1px solid var(--near-black);
  border-radius: 66px;
  padding: clamp(10px, 1.04vw, 20px) clamp(18px, 2.45vw, 47px);
  white-space: nowrap;
  z-index: 2;
}
.hero3-titleArea__list span {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(14px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--near-black);
}
.hero3-titleArea__list--left { left: 39%; top: 21%; transform: translate(-50%, -50%) rotate(-40deg); }
.hero3-titleArea__list--right { left: 90%; top: 43%; transform: translate(-50%, -50%) rotate(-40deg); }

/* ---- about2 ---- */
.about2 { position: relative; background: var(--near-black); overflow: hidden; padding-block: 130px 220px; }
.about2__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 0.5; z-index: 0; }
/* container-type here (not on .about2) so cqw below is relative to this
   element's own content box — i.e. already net of its 63px inline
   padding — instead of the raw viewport, which is what let the nowrap
   headline overflow at in-between widths where that fixed padding is a
   bigger share of the available space. */
.about2 .container { position: relative; z-index: 1; container-type: inline-size; }
.about2__text1 {
  font-family: var(--font-display);
  font-weight: 600;
  /* cqw (relative to .about2 .container's own content-box width, i.e.
     already net of its 63px inline padding) instead of vw — sizing off
     the raw viewport meant the fixed padding ate into the "available"
     width disproportionately at in-between viewport sizes, so text sized
     to fit the full viewport didn't actually fit the padded container
     and got clipped by .about2's overflow:hidden. 59/1794 (Figma's
     144px content width at its 1920 frame) = ~3.29cqw. Min bound lowered
     from 26px so nowrap scaling stays safe all the way down to phone
     widths instead of getting stuck at a fixed size and overflowing. */
  font-size: clamp(15px, 3.29cqw, 59px);
  line-height: 1.2;
  color: rgba(255, 255, 255, 0.1);
  /* Figma sets this text white-space:nowrap — the 3 <br>-separated lines
     in the markup are meant to be exactly 3 rendered lines, never
     rewrapped. A fixed max-width fought that (a long line would wrap a
     4th time once it didn't fit), so width is intentionally not
     constrained here: font-size already scales with vw, so a nowrap
     line's rendered width scales down right along with it, staying
     proportional to the viewport instead of overflowing. */
  width: max-content;
  max-width: 100%;
  white-space: nowrap;
  margin-inline: auto;
}
.about2__text2 {
  max-width: 1261px;
  margin: 40px auto 0;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(16px, 1.35vw, 26px);
  line-height: 1.4;
  text-align: center;
  /* base dim color for the un-revealed state (word-reveal-gsap.js wraps
     each word to fade 0.1 -> 1 on scroll) — matches Figma's own spec
     color for this paragraph exactly, not an arbitrary lighter dim. */
  color: rgba(255, 255, 255, 0.1);
}
.about2__shape {
  position: absolute;
  left: 15%;
  top: 20%;
  width: 58.4%;
  z-index: 0;
  pointer-events: none;
}

/* ---- marquee2 (crossed ribbons) ---- */
.marquee2 { position: relative; background: var(--black); overflow: hidden; padding-block: 90px; }
.marquee2-row { position: absolute; left: -10%; right: -10%; overflow: hidden; height: 140px; display: flex; align-items: center; }
/* Both rows centered on the same point (section's vertical middle, which
   is also where .marquee2-btn's center falls, since padding-block above
   and below it is equal) so the two ribbons' crossing point lands
   exactly behind the button — mismatched top values here previously put
   each row's own center at a different height, shifting the X where
   they actually cross off to one side instead of under the button. */
.marquee2-row--yellow { top: 50%; transform: translateY(-50%) rotate(7deg); background: #ffff00; }
.marquee2-row--dark { top: 50%; transform: translateY(-50%) rotate(-7deg); background: var(--near-black); border-block: 1px solid var(--border-light); }
.marquee2-track {
  display: flex;
  width: max-content;
  animation: marquee2-scroll 30s linear infinite;
}
.marquee2-track--reverse { background: var(--accent-start); animation-direction: reverse; }
.marquee2-item {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(24px, 3.1vw, 60px);
  text-transform: uppercase;
  color: var(--black);
  white-space: nowrap;
  padding-inline: 20px;
}
.marquee2-row--dark .marquee2-item { color: var(--white); }
.marquee2-dot { display: inline-block; margin-inline: 20px; font-size: 0.5em; vertical-align: middle; }
@keyframes marquee2-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
.marquee2-btn {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14.5px;
  width: clamp(160px, 16vw, 310px);
  aspect-ratio: 1;
  margin-inline: auto;
  background: var(--cream);
  border: 1px solid var(--border-dark);
  border-radius: 50%;
  text-align: center;
}
.marquee2-btn span {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(14px, 1vw, 20px);
  text-transform: uppercase;
  color: var(--near-black);
}
@media (prefers-reduced-motion: reduce) { .marquee2-track { animation: none; } }

/* ---- about-tabs ---- */
.about-tabs { background: var(--near-black); padding-block: 82px 130px; }
.about-tabs-row { display: flex; flex-wrap: wrap; gap: 40px; }
.about-tabs-nav { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; align-items: center; gap: 156px; padding-top: 48px; }
.about-tabs-nav__btn {
  width: clamp(140px, 10.8vw, 207.33px);
  aspect-ratio: 1;
  border-radius: 50%;
  border: none;
  background: var(--black);
  color: var(--white);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(14px, 1vw, 20px);
  line-height: 1.5;
  text-transform: uppercase;
  text-align: center;
}
.about-tabs-nav__btn--active { background: var(--white); color: var(--black); }
.about-tabs-nav__group { display: flex; align-items: center; gap: 16px; }
.about-tabs-nav__line { width: 120px; height: 1px; background: var(--border-light); flex-shrink: 0; }
.about-tabs-nav__connector {
  position: absolute;
  top: 130px;
  width: 1px;
  height: 60px;
  background: var(--border-light);
}
.about-tabs-nav__connector--left { left: 30%; transform: rotate(25deg); transform-origin: top; }
.about-tabs-nav__connector--right { right: 30%; transform: rotate(-25deg); transform-origin: top; }

.about-tabs-list { flex: 1 1 500px; min-width: 0; }
.about-tabs-exp { padding-block: 45px; border-top: 1px solid var(--border-light); display: flex; flex-direction: column; gap: 20px; }
.about-tabs-list .about-tabs-exp:last-child { border-bottom: 1px solid var(--border-light); }
.about-tabs-exp__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(20px, 1.56vw, 30px);
  line-height: 1.2;
  text-transform: uppercase;
  color: var(--white);
}
.about-tabs-exp__title span { color: #ffff00; }
.about-tabs-exp__time {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(14px, 1vw, 20px);
  color: var(--text-color2, #999999);
}
.about-tabs-exp__desc {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(14px, 1vw, 20px);
  line-height: 1.8;
  color: var(--text-color2, #999999);
}
.about-tabs-exp__skills { display: flex; flex-wrap: wrap; gap: 15px; }
.about-tabs-exp__skills span {
  background: var(--black);
  border: 1px solid var(--border-dark);
  border-radius: 65px;
  padding: 7px 20px;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 16px;
  color: var(--white);
}

/* ---- video2 ---- */
/* .video2's height is driven by .video2-item (centered in normal flow);
   .video2-tickers is stretched to match via inset:0 and clipped by the
   parent's overflow:hidden, so it always has enough rows to fully cover
   the section regardless of how tall the poster card ends up being. */
.video2 { position: relative; background: var(--black); overflow: hidden; display: flex; align-items: center; justify-content: center; padding-block: 80px; }
.video2-tickers { position: absolute; inset: 0; display: flex; flex-direction: column; justify-content: center; z-index: 0; }
.video2-ticker-row { height: 113px; display: flex; align-items: center; overflow: hidden; border-bottom: 1px solid var(--border-dark); flex-shrink: 0; }
.video2-ticker-track { display: flex; width: max-content; gap: 20px; animation: marquee2-scroll 60s linear infinite; }
.video2-ticker-item {
  display: inline-flex;
  align-items: center;
  gap: 15px;
  border: 1px solid var(--border-dark);
  border-radius: 66px;
  padding: 20px 41px;
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(16px, 1.354vw, 26px);
  text-transform: uppercase;
  color: var(--text-color2, #999999);
  white-space: nowrap;
}
.video2-ticker-dot { color: var(--white); }
.video2-item {
  position: relative;
  z-index: 1;
  width: min(1400px, 90%);
  background: var(--cream);
  border-radius: 35px;
  padding: clamp(16px, 3vw, 45px);
  z-index: 1;
}
.video2-item video { width: 100%; height: auto; border-radius: 15px; display: block; background: var(--black); }
/* A persistent mute toggle, not the big central "click to play" button
   Figma's static mockup shows — the video autoplays on its own now (see
   about-page.js), so a button that size sitting mid-video the whole time
   it plays would just be in the way. Bottom-right corner, small, matches
   how native video-platform mute controls are usually placed. */
.video2-item__play {
  position: absolute;
  right: clamp(20px, 3vw, 45px);
  bottom: clamp(20px, 3vw, 45px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: rgba(11, 12, 15, 0.55);
  border: none;
  cursor: pointer;
  backdrop-filter: blur(4px);
}
.video2-item__play img { width: 32px; height: 32px; border-radius: 0; }
@media (prefers-reduced-motion: reduce) { .video2-ticker-track { animation: none; } }

/* ---- work-process2 (reuses .section-top__title1/2 from PORTFOLIO) ---- */
.work-process2 { background: var(--near-black); padding-block: 130px; overflow: hidden; }
.section-top { padding-inline: 80px; padding-bottom: 60px; }
/* .section-top__title1/2 were built for the light/cream portfolio
   titleArea (near-black solid text) — on this page's near-black sections
   that's invisible, so re-tint to the dark-bg treatment used elsewhere in
   the project (faint white dim text; transparent-fill white-stroke
   outline, same technique as .case-hero__title h2). */
.work-process2 .section-top__title1.dim,
.service2 .section-top__title1.dim { color: rgba(255, 255, 255, 0.1); }
.work-process2 .section-top__title2,
.service2 .section-top__title2 { color: transparent; -webkit-text-stroke: 1.5px var(--white); }
.work-process1-swiper { overflow: visible; padding-bottom: 60px; }
.work-process1-card {
  width: min(865px, 82vw);
  display: flex;
  align-items: center;
  gap: clamp(20px, 4vw, 65px);
  background: var(--cream);
  border-radius: 10px;
  padding: 60px clamp(30px, 7.7vw, 149px) 60px clamp(30px, 15vw, 290px);
  position: relative;
}
.work-process1-card__numb {
  position: absolute;
  left: clamp(20px, 3.3vw, 64px);
  top: 50%;
  transform: translateY(-50%) rotate(-90deg);
  transform-origin: center;
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(70px, 9.7vw, 140px);
  color: var(--black);
  line-height: 1;
}
.work-process1-card-content { display: flex; flex-direction: column; gap: 30px; max-width: 426px; }
.work-process1-card-content__step {
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(14px, 1vw, 20px);
  text-transform: uppercase;
  color: var(--near-black);
}
.work-process1-card-content__title {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(30px, 4.2vw, 60px);
  line-height: 1.17;
  color: var(--black);
}
.work-process1-card-content__text {
  font-family: var(--font-ui);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.55;
  color: var(--text-gray);
}
.work-process1-controls { display: flex; justify-content: center; gap: 30px; }
.work-process1-prev,
.work-process1-next {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 50%;
  background: var(--near-black);
  border: 1px solid var(--white);
}
/* icon-arrow-prev/next.svg are drawn with a #0B0C0F stroke — the same
   near-black as this button's own background, so the arrow was fully
   invisible, leaving only the white ring visible. Inverted just here
   (not in the shared SVG file) since the same icons sit on transparent
   backgrounds elsewhere — e.g. .testimonial1-prev/next — where the
   original dark stroke is what's wanted. */
.work-process1-prev img,
.work-process1-next img { filter: invert(1); }
.work-process1-prev.swiper-button-disabled,
.work-process1-next.swiper-button-disabled { opacity: 0.35; cursor: default; }

/* ---- service2 ---- */
.service2 { background: var(--near-black); padding-block: 130px; }
.service2-list { border-top: 1px solid var(--border-light); }
.service2-item {
  display: flex;
  align-items: center;
  gap: clamp(20px, 3vw, 56px);
  min-height: 170px;
  padding-block: 42px;
  border-bottom: 1px solid var(--border-light);
}
.service2-item__number {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 60px;
  height: 60px;
  border-radius: 30px;
  border: 1px solid var(--border-dark);
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: 20px;
  color: var(--white);
}
.service2-item__title {
  flex: 1 1 auto;
  min-width: 0;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(26px, 4.2vw, 60px);
  line-height: 1.17;
  color: var(--white);
}
.service2-item__text {
  flex: 0 0 auto;
  max-width: 415px;
  font-family: var(--font-ui);
  font-weight: 400;
  font-size: 18px;
  line-height: 1.55;
  color: var(--white);
}

/* ============ CONTACT PAGE ============ */
/* contact.html only. Figma reference: node 1:3227 in the same file. */

.contact-hero { position: relative; background: var(--cream); overflow: hidden; }
.contact-hero__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.contact-hero__title {
  position: relative;
  z-index: 1;
  padding: clamp(40px, 6vw, 130px) clamp(24px, 6.7vw, 128px) clamp(60px, 6.8vw, 130px);
}
.contact-hero__title h1,
.contact-hero__title h2,
.contact-hero__title h3 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 7.3vw, 140px);
  line-height: 1;
  text-transform: uppercase;
}
.contact-hero__title h1 { color: var(--white); }
.contact-hero__title h2 { color: var(--near-black); }
.contact-hero__title h3 {
  text-align: right;
  color: transparent;
  -webkit-text-stroke: 1.5px var(--near-black);
}

.contact-section {
  background: var(--black);
  padding-top: clamp(70px, 6.7vw, 130px);
  padding-bottom: clamp(36px, 3vw, 58px);
}
.contact-row {
  display: flex;
  flex-wrap: wrap;
  border-radius: 10px;
  overflow: hidden;
}
.contact-form1,
.contact-photo { flex: 1 1 480px; min-width: 0; }

.contact-form1 {
  background: var(--white2, #fffbf5);
  padding: clamp(40px, 4.7vw, 90px) clamp(30px, 3.1vw, 60px) clamp(40px, 6.5vw, 125px);
  position: relative;
}
.contact-form1__title {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(26px, 1.9vw, 36px);
  color: var(--near-black);
  margin-bottom: clamp(40px, 5.1vw, 98px);
}
.contact-form1__row { display: flex; flex-wrap: wrap; gap: 0 24px; }
/* Flat 260px flex-basis was generous enough that two fields (520px +
   24px gap = 544px) no longer fit this row's own share of the page at
   1280px (~518px), wrapping "What's Your Name" and "Your Email" onto
   separate rows — a real column-count change the 1920px design never
   intended. 260px is comfortably more than an input actually needs, so
   scaling it down at narrower widths (18vw, saturating back to the
   same 260px above ~1444px) keeps both fields on one row down to
   1280px without changing anything at 1920px. */
.contact-form1__field { flex: 1 1 clamp(140px, 18vw, 260px); min-width: 0; margin-bottom: 40px; }
.contact-form1__field--full { flex: 1 1 100%; }
.contact-form1__field input {
  width: 100%;
  border: none;
  border-bottom: 1px solid var(--near-black);
  background: transparent;
  padding-block: 10px 12px;
  font-family: var(--font-ui);
  font-size: 18px;
  color: var(--near-black);
}
.contact-form1__field input::placeholder { color: var(--near-black); opacity: 0.7; }
.contact-form1__field input:focus { outline: none; border-color: var(--accent-start); }
.contact-form1__submit {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: clamp(120px, 8.3vw, 160px);
  aspect-ratio: 1;
  border-radius: 50%;
  background: var(--black);
  border: 1px solid var(--near-black);
  cursor: pointer;
}
.contact-form1__submit-icon {
  display: block;
  font-size: 26px;
  color: var(--white);
  transform: rotate(0deg);
}
.contact-form1__submit span:last-child {
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(14px, 0.94vw, 18px);
  text-transform: uppercase;
  color: var(--white);
}
.contact-form1__submit.is-loading { opacity: 0.6; cursor: default; }
.contact-form1__status {
  margin-top: 20px;
  font-family: var(--font-ui);
  font-size: 15px;
  color: var(--near-black);
  /* Reserves no layout space when empty (the default, pre-submit state)
     — an empty <p> with this font-size would otherwise leave a visible
     gap under the button before anything has ever been sent. */
  min-height: 0;
}
.contact-form1__status:empty { display: none; }
.contact-form1__status.is-success { color: #1a7a3c; }
.contact-form1__status.is-error { color: var(--accent-start); }

.contact-photo { position: relative; background: #000a22; aspect-ratio: 885 / 720; }
.contact-photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0%; display: block; }
.contact-social {
  position: absolute;
  top: 16%;
  bottom: 19%;
  right: 0;
  width: clamp(64px, 5.6vw, 84px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: space-between;
  padding: clamp(14px, 1.5vw, 24px) 0;
  background: var(--white2, #fffbf5);
  border: clamp(14px, 1.6vw, 30px) solid var(--black);
  border-right: 0;
  border-radius: 10px 0 0 10px;
  overflow: hidden;
}
.contact-social__icons { display: flex; flex-direction: column; align-items: center; gap: clamp(10px, 1.2vw, 18px); }
.contact-social__divider {
  position: relative;
  width: 1px;
  height: 28px;
  background: var(--near-black);
  opacity: 0.6;
  flex-shrink: 0;
}
.contact-social__divider::before,
.contact-social__divider::after {
  content: '';
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  width: 9px;
  height: 1px;
  background: var(--near-black);
  opacity: 0.6;
}
.contact-social__divider::before { top: 0; }
.contact-social__divider::after { bottom: 0; }
.contact-social__icons a {
  display: flex;
  align-items: center;
  justify-content: center;
  width: clamp(30px, 2.6vw, 38px);
  height: clamp(30px, 2.6vw, 38px);
  border-radius: 50%;
  background: var(--white);
  border: 1px solid var(--border-dark);
  flex-shrink: 0;
}
.contact-social__icons a img {
  width: auto;
  height: auto;
  max-width: 15px;
  max-height: 15px;
}
/* These icon SVGs are hardcoded white-fill (built for the dark header/
   footer circles) — invert so they read as dark marks on this white
   circle instead of disappearing into it. */
.contact-social__icons a img:not([src*="facebook"]) { filter: invert(1); }
.contact-social__title {
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(13px, 1.1vw, 18px);
  color: var(--near-black);
  flex-shrink: 0;
}

.contact-info { background: #ffff00; padding-block: 35px; }
.contact-info__text {
  text-align: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(18px, 1.8vw, 35px);
  color: var(--near-black);
}

/* ============ PORTFOLIO HERO ============ */
.portfolio-hero { position: relative; background: var(--cream); overflow: hidden; }
.portfolio-hero__bg { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.portfolio-hero .container { position: relative; z-index: 1; }
.portfolio-hero__title { padding-top: clamp(40px, 6vw, 130px); }
.portfolio-hero__title h1,
.portfolio-hero__title h2 {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: clamp(40px, 7.3vw, 140px);
  line-height: 1;
  text-transform: uppercase;
}
.portfolio-hero__title h1 { color: var(--white); }
.portfolio-hero__title h2 { color: var(--near-black); }
.portfolio-hero__title h2.portfolio-hero__outline { color: transparent; }
.portfolio-hero__row3 {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(20px, 9.5vw, 183px);
  margin-top: clamp(6px, 1vw, 20px);
}
.portfolio-hero__badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  background: #fbe32c;
  border: 1px solid #0f0f0b;
  border-radius: 66px;
  padding: clamp(12px, 1.4vw, 20px) clamp(20px, 3.3vw, 47px);
  font-family: var(--font-ui);
  font-weight: 700;
  font-size: clamp(13px, 1.35vw, 26px);
  text-transform: uppercase;
  color: #0b0c0f;
  white-space: nowrap;
}
.portfolio-hero__badge-dot { width: 10px; height: 10px; border-radius: 50%; background: #0b0c0f; flex-shrink: 0; }
.portfolio-hero__outline {
  color: transparent;
  -webkit-text-stroke: 1.5px var(--near-black);
}
.portfolio-hero__photo {
  position: relative;
  margin-top: clamp(30px, 2.9vw, 56px);
  margin-bottom: clamp(30px, 3.1vw, 60px);
  aspect-ratio: 1774 / 930;
  background: #0f0303;
  border: 2px dashed var(--white);
  border-radius: 4px;
  overflow: hidden;
}
.portfolio-hero__photo img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 0%; display: block; }

/* ============ PRELOADER ============ */
/* Shell only — the infinity geometry, the three mask bands and the
   per-frame light trail are all built in assets/js/preloader.js, which
   also injects this element. See that file for why the effect is masks
   over one continuous stroke rather than a dashed stroke. */
.preloader {
  position: fixed;
  inset: 0;
  z-index: 10000; /* above the custom cursor (9999), the highest thing otherwise */
  display: flex;
  align-items: center;
  justify-content: center;
  /* Near-black, very slightly lifted behind the symbol so the red bloom
     has something to fall off into instead of clipping straight to #000. */
  background: radial-gradient(circle at 50% 47%, #0e1015 0%, #050609 58%, #000 100%);
  opacity: 1;
  transition: opacity 0.45s ease;
}
.preloader.is-done { opacity: 0; pointer-events: none; }

.preloader__stage {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: clamp(14px, 2vw, 30px);
}
.preloader__canvas {
  display: block;
  /* Sized so the 12-unit tube of the 440-unit design space lands in the
     8–12px range on screen while the symbol still dominates the view.
     The canvas keeps that aspect so the light's bloom has room to spill
     without being clipped at the edges. */
  width: clamp(300px, 34vw, 500px);
  aspect-ratio: 440 / 280;
  height: auto;
}

.preloader__text {
  margin: 0;
  font-family: var(--font-ui);
  font-weight: 600;
  font-size: clamp(12px, 1vw, 15px);
  letter-spacing: 0.18em;
  color: rgba(255, 255, 255, 0.45);
}

html.is-preloading,
html.is-preloading body { overflow: hidden; }

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

/* ============ MOBILE ============ */
@media (max-width: 900px) {
  .container { padding-inline: 24px; }
  .counter1 .container,
  .about1 .container { padding-inline: 24px; }

  /* ---- Mobile nav: hamburger opens .header1-nav as a full-screen
     overlay instead of the desktop inline link row (assets/js/main.js
     toggles .is-open / aria-expanded). z-index 950 sits above
     .back-to-top (900) so that button can't peek through the overlay;
     the burger itself (960) stays clickable above the open overlay to
     close it again. */
  .header1-burger { display: flex; z-index: 960; }
  .header1-nav {
    position: fixed;
    inset: 0;
    z-index: 950;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--near-black);
    border: none;
    opacity: 0;
    visibility: hidden;
    transform: translateY(-16px);
    transition: opacity 0.3s ease, transform 0.3s ease, visibility 0s linear 0.3s;
  }
  .header1-nav.is-open {
    opacity: 1;
    visibility: visible;
    transform: translateY(0);
    transition: opacity 0.3s ease, transform 0.3s ease;
  }
  .header1-nav ul { flex-direction: column; justify-content: center; gap: 4px; padding-block: 0; }
  .header1-nav a { display: block; padding: 14px 24px; font-size: 28px; text-align: center; }

  /* ---- Header: 2-row grid — row 1 is all 4 social icons (left) +
     logo (right); row 2 is "Download Resume" (left) + hamburger
     (right). Figma's mobile header keeps every desktop element, just
     rearranged into two rows instead of one, not the trimmed-down
     version an earlier pass here guessed at. Grid (not flex-wrap) so
     the pairing is explicit regardless of each item's own width. */
  .header1-menu {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    row-gap: 16px;
    column-gap: 12px;
  }
  .header1-social { grid-column: 1; grid-row: 1; gap: 8px; }
  .header1-logo { grid-column: 2; grid-row: 1; justify-self: end; }
  .header1-cta { grid-column: 1; grid-row: 2; }
  .header1-burger { grid-column: 2; grid-row: 2; justify-self: end; }

  /* ---- Hero (home) ---- */
  /* Matches the current mobile Figma frame (node 146:7835 -> hero sub-
     frame 167:9455): badge -> photo pill -> desc -> heading, all
     centered, each gap a uniform ~24px (Figma: 25px at its 430px
     reference width) — desktop is desc+badge side by side, photo
     pulled out of flow, no such uniform rhythm. */
  .hero1-content { flex-direction: column; align-items: center; text-align: center; gap: 24px; }
  .hero1-content-time { order: 1; align-items: center; }
  .hero1-content-time__label,
  .hero1-content-time__date { text-align: center; }
  /* Figma (node 167:9433) sizes the badge label at 15.366px — close to
     the shared 16px base but not exact. */
  .hero1-content-time__label { font-size: 15px; }
  .hero1-content-time__date { font-size: 32px; margin-top: 12px; }
  /* Figma's mobile portrait (node 167:9423) is a much bigger pill than
     the desktop-tuned clamp() floor this was inheriting (which bottomed
     out at a fixed 190x299px well before mobile widths) — 292x158px at
     its 430px-wide reference frame, reproduced here as a vw-scaled clamp
     off that same canvas (292/430 ≈ 67.91vw, 158/430 ≈ 36.74vw) so the
     pill's aspect ratio holds at every breakpoint instead of a guessed
     flat size. */
  .hero1-content__thumb-spacer { order: 2; width: clamp(200px, 67.91vw, 292px); height: clamp(108px, 36.74vw, 158px); }
  /* This paragraph sits much lower in the mobile layout than on desktop
     — over the faded-to-cream part of the gradient, not the dark top —
     so Figma sets it in near-black, not the desktop white. */
  .hero1-content__desc { order: 3; text-align: center; max-width: 100%; color: var(--near-black); font-size: 22px; }

  /* Figma's current mobile hero drops the two rotated pill tags
     entirely (an earlier version of this frame had them — see the git
     history on this block — but the live design no longer does). */
  .hero1-titleArea__lists { display: none; }
  /* PRODUCT stays right-aligned (same as desktop) — a small padding-right
     keeps it just clear of the viewport edge instead of desktop's huge
     clamp() offset (which existed to dodge the desktop pill, now moot
     here too, but the same small clearance still reads correctly). */
  .hero1-titleArea__title-line--product { padding-right: 15px; }
  .hero1-titleArea__title-line--designer { padding-left: 15px; }
  /* Figma (node 167:9439/9441) sizes "PRODUCT"/"DESIGNER" at 55.854px
     with line-height equal to font-size — the previous 46px guess was
     never checked against the actual node. */
  .hero1-titleArea__title { font-size: 56px; line-height: 1; }
  .hero1-titleArea { padding-top: 24px; margin-bottom: 40px; }

  /* ---- Counter / stats (home) ----
     Figma's mobile frame (430px-wide canvas, node 167:9458/146:8072-92)
     renders the big numerals at a fixed 131.711px regardless of digit
     count ("5", "200", "15" all share the same font-size) — the old
     clamp(60px, 11vw, 216px) bottoms out at its 60px floor across the
     whole mobile range and never reaches that. Reproduced here as a
     vw-scaled clamp anchored to that 430px canvas (131.711 / 430 ≈
     30.63vw) so it tracks the Figma value at every breakpoint instead
     of guessing a flat px number. */
  .counter1-item { flex-direction: column; align-items: flex-start; gap: 40px; }
  .counter1-item-box h1 { font-size: clamp(64px, 30.63vw, 132px); }
  .counter1-item-box__label { padding: 12px 20px; }
  .counter1-item-box__label span { font-size: 14px; white-space: normal; }

  /* ---- About stat row (home) ----
     Figma (node 146:8118) keeps this as a horizontal row — numeral
     beside the icon+label column, gap 16.464px — centered as a block
     within its parent (symmetric left/right offset in the metadata).
     The old mobile override switched it to a stacked column, which
     doesn't match the design at all and is why centering it via
     align-items alone wouldn't have looked right. */
  .about1 { padding-block: 64px; }
  .about1-item { justify-content: center; align-items: center; padding-right: 0; padding-top: 48px; gap: 16px; }
  .about1-item-numb .odometer-digit { font-size: clamp(64px, 30.63vw, 132px); }
  /* icon-years-badge.svg is a literal plus-sign graphic (not a badge) —
     fixed at a 116x116 HTML attribute size with no responsive rule of
     its own, so at mobile it rendered ~3x larger than the shrunk "5"
     number next to it, a huge disconnected plus-shape between the
     number and the "years experience" label. Figma's own mobile node
     sizes it at 44px — shrink to match. */
  .about1-item-content img { width: 44px; height: 44px; }
  .about1-item-content { align-items: center; gap: 10px; }
  .about1-item-content span { font-size: 10px; }
  .about1__desc { padding-top: 48px; }
  /* .about1__desc2-lowercase ("More about me") is `inline-flex` so it
     kicks off the paragraph text inline — reads fine on desktop's wide
     column, but at mobile width "MORE ABOUT ME" alone nearly fills the
     first line, jamming the paragraph's first words right up against
     it with no visual break. Force it onto its own line instead. */
  .about1__desc2-lowercase { display: flex; margin-right: 0; margin-bottom: 16px; }

  /* ---- Portfolio grid (home) ---- */
  .project1-titleArea .container { padding-block: 64px; }
  /* Figma's mobile cards sit on a clean black gap with no visible cell
     border — just a ~17px inset each side, not the desktop's 75px
     bordered-cell divider grid. */
  .project1-grid { grid-template-columns: 1fr; padding-inline: 16px; }
  .project1-cell { padding: 20px 0; border: none; }
  .section-top__title2 { padding-right: 0; }
  .project1-btn-wrapper { padding-block: 64px; }
  .project1-see-all { width: 180px; height: 180px; border-radius: 90px; }
  /* The title link is the primary way to reach a case study on touch —
     give it real block-level tap height instead of just its text line. */
  .project1-card-content a { display: block; padding-block: 10px; font-size: 14px; }
  /* Figma's mobile cards (node 146:8150 etc.) — re-checked after the user
     bumped these up in Figma: tags/year-badge are 10px/12px, not the ~7px
     from the previous pass. */
  .project1-card-meta__item { padding: 3px 4px; font-size: 10px; }
  .project1-card-content__button { padding: 3px 9px; font-size: 12px; }
  /* Figma's mobile frame (node 146:8238) reorders the cards to
     Avenir, AlphaX, LisBon, Safex, Eventra Africa, Fundex — different
     from the desktop DOM order (Eventra, Fundex, Avenir, AlphaX, LisBon,
     Safex). Re-ordered visually here rather than in the DOM so desktop's
     order (and its own Figma-matched layout) stays untouched. */
  .project1-cell:nth-child(1) { order: 5; } /* Eventra Africa */
  .project1-cell:nth-child(2) { order: 6; } /* Fundex */
  .project1-cell:nth-child(3) { order: 1; } /* Avenir */
  .project1-cell:nth-child(4) { order: 2; } /* AlphaX */
  .project1-cell:nth-child(5) { order: 3; } /* LisBon */
  .project1-cell:nth-child(6) { order: 4; } /* Safex */
  /* Figma's mobile cards also shorten two titles to fit the smaller card
     width — "LisBon (Dubai) - Drivers App Design" drops the "(Dubai)",
     and Eventra drops its "— Marketplace Design" subtitle entirely. */
  .project1-card-content a .project1-card-content__title-full { display: none; }
  .project1-card-content a .project1-card-content__title-short { display: inline; }

  /* ---- Skills marquee (home) ---- */
  /* The clamp() floors (160px-tall images, effectively 48px text) were
     tuned for desktop's min viewport and never actually shrink further —
     Figma's mobile ticker uses noticeably smaller thumbnails and tighter
     spacing than that floor allows. */
  .marquee1-row { padding-block: 16px; }
  .marquee1-item { gap: 16px; padding-right: 16px; }
  .marquee1-item img { width: 90px; height: 44px; }
  .marquee1-item span { font-size: clamp(32px, 11vw, 48px); }

  /* ---- Testimonials (home) ---- */
  .testimonial1 { padding-block: 64px; }
  .testimonial1-card { padding: 32px 20px 24px; }
  /* Figma's mobile card (node 146:8258) keeps the quote body near its
     desktop floor (~18px, already what the clamp() renders here) but
     drops the name/designation/pager to tiny caption sizes — 9.3px,
     5.6px and 6.2px respectively — a much bigger jump than the 22px
     this block guessed before checking the actual node. */
  .testimonial1-card__name { font-size: 9px; }
  .testimonial1-card__designation { font-size: 6px; }
  .testimonial1-card-controls__numb { font-size: 6px; }

  /* ---- Awards (home) ---- */
  /* Each row was `flex-wrap: wrap` + a `margin-left: auto` date — fine
     while numb+name+date fit one line, but the instant one row's name
     was a little longer than the others (e.g. "Xtrempay Awards" vs
     "Design Awards") that ONE row wrapped its date onto its own line
     while the others didn't, so consecutive rows visibly disagreed on
     layout. Forcing nowrap and shrinking the type keeps every row on a
     single line, matching Figma (numeral, name, date, always one row). */
  .award1 { padding-block: 64px; }
  .award1-top, .award1-bottom { flex-direction: column; align-items: flex-start; }
  /* .award1-bottom's align-items: flex-start (needed so the avatar above
     doesn't stretch full-width) also shrinks .award1-content to its
     content width in this column flex context instead of filling the
     container — forcing full width here so the list actually spans
     edge-to-edge like every other mobile section. */
  .award1-content { width: 100%; }
  /* Figma's "{Awards}" title (node 146:8322) sits at 24px on this canvas —
     the clamp() floor (32px) never comes down that far since it was
     tuned for desktop's min viewport. */
  .award1-content__title { font-size: 28px; }
  .award1-content-list li { flex-wrap: nowrap; gap: 8px; padding-block: 20px; }
  .award1-content-list__numb { min-width: 20px; font-size: 12px; }
  .award1-content-list__name { margin-left: 0; font-size: 18px; }
  .award1-content-list__date { margin-left: auto; font-size: 12px; }

  /* ---- Footer (all pages) ---- */
  /* Matches the Figma mobile footer: avatar stacked ABOVE the heading
     and both centered, rather than desktop's avatar-beside-heading,
     right-aligned layout. */
  .footer1 { padding-top: 56px; }
  .footer1-content { padding-inline: 0; }
  .footer1-content__avatar {
    /* Reads noticeably larger than the desktop clamp()'s 90px floor in
       the mobile design — about 126px at the 430px reference width. */
    width: clamp(96px, 29.3vw, 126px);
    height: clamp(96px, 29.3vw, 126px);
  }
  .footer1-content__title1,
  .footer1-content__title2 { flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 16px; padding-bottom: 0; }
  /* Figma's mobile heading (node 146:8354) renders at ~55px — the shared
     desktop clamp() floors at 40px on narrow widths since it was tuned
     for a much wider min viewport, never reaching the mobile value. */
  .footer1-content__title1 h2, .footer1-content__title2 h2 { text-align: center; font-size: 55px; }
  .get-touch-btn { padding: 16px 26px; gap: 12px; }
  .get-touch-btn span { font-size: 20px; }
  .get-touch-btn img { width: 22px; height: 22px; }
  /* Figma keeps the same alternating ±10deg tilt as desktop (just a
     smaller pill) — the earlier `transform: none !important` flattened
     them out entirely, which also isn't what Figma shows. Shrinking the
     pill itself is what actually gets 3-then-1 wrapping (Linkedin/
     Behance/Twitter on one row, Dribbble alone below) instead of the
     2x2 grid the larger desktop-sized pills were forcing. */
  /* Row gap has to clear the ±10deg tilt: the pills are rotated, so their
     corners reach well past their unrotated box and a tight row gap had
     Dribbble's top corner cutting into Behance below it. */
  .footer1-content-socialBtn { padding-top: 32px; gap: 16px 7px; }
  /* Padding trimmed to offset the font-size bump below (12px -> 15px,
     Figma node 146:8366 etc.) — otherwise the wider pills wrap 2-per-row
     instead of Figma's 3-then-1 (Linkedin/Behance/Twitter, Dribbble alone). */
  /* Sized off the 430px reference width (15px / 13px land exactly there)
     and scaled below it, so the 3-then-1 arrangement survives down to
     ~360px instead of collapsing to a 2x2 grid the moment the viewport
     is narrower than the design. Below that it does wrap to 2x2, which
     is the honest fallback — three of these can't fit a 320px screen
     without shrinking the type past legibility. */
  .footer1-content-socialBtn__item { padding: clamp(8px, 2.33vw, 10px) clamp(9px, 3.02vw, 13px); gap: clamp(5px, 1.63vw, 7px); }
  .footer1-content-socialBtn__item span { font-size: clamp(12px, 3.49vw, 15px); }
  .footer1-content-socialBtn__item img { width: 12px; height: 12px; }

  /* The bottom bar is a centred stack on mobile, and the nav row sits
     ABOVE the copyright line — the reverse of the DOM order, which is
     built for desktop's copyright-left / links-right row. Ordered here
     rather than in the markup so desktop is untouched. */
  .footer1-bottom {
    flex-direction: column;
    align-items: center;
    text-align: center;
    gap: 18px;
    flex-wrap: nowrap;
    /* Extra room at the end so the copyright line clears the floating
       back-to-top button, which sits bottom-right over whatever is last
       on the page — and the copyright now IS last. */
    padding-block: 35px 72px;
  }
  .footer1-bottom-item { display: flex; justify-content: center; width: 100%; }
  .footer1-bottom-item:nth-child(1) { order: 2; } /* copyright */
  .footer1-bottom-item:nth-child(2) { order: 1; } /* Home / About / Portfolio / Contact */
  /* Terms + Privacy aren't part of the mobile footer design. */
  .footer1-bottom-item:nth-child(3) { display: none; }
  /* Figma's bottom bar (node 146:8376-88) drops the copyright line and
     nav links to ~15px from the shared desktop 16px flat value. */
  .footer1-bottom-item p, .footer1-bottom-item a { font-size: 15px; }
  .footer1-bottom-item ul { gap: 10px 20px; justify-content: center; }

  /* ---- Case study pages (shared template) ---- */
  .case-details { padding-block: 64px; }
  .case-details-row { flex-direction: column; gap: 20px; padding-block: 36px; }
  /* .case-details__label/__content keep their desktop flex-basis
     (320px/500px) even after the row above flips to flex-direction:
     column — in column mode flex-basis sets HEIGHT, not width, so
     without this reset the "(01) About the project" label was pinned to
     a fixed 320px-tall box and its content to 500px, opening a large
     dead gap between label and paragraph on every row. */
  .case-details__label,
  .case-details__content { flex: none; max-width: 100%; }
  .case-gallery { grid-template-columns: 1fr; gap: 32px; margin-top: 48px; }
  .case-hero__case-label { display: none; }
  /* 1920/908 (~2.11:1) renders as a ~184px-tall strip at mobile widths —
     far too letterboxed for a hero product shot. A taller ratio gives
     the mockup/illustration real visible size. */
  .case-hero__media { aspect-ratio: 4 / 3; }
  .case-behance-btn {
    padding: 14px 24px;
    border: 1px solid var(--border-light);
    border-radius: 999px;
  }

  .case-info-card { flex-wrap: wrap; }
  .case-info-card__item { flex: 1 1 50%; min-width: 0; border-left: none; border-top: 1px solid var(--border-light); }
  .case-info-card__item:nth-child(-n+2) { border-top: none; }
  .case-info-card__item:nth-child(odd) { border-left: none; }
  .case-info-card__value { white-space: normal; word-break: break-word; }

  /* Fundex hero: the wallet illustration + logo are decorative and get
     crowded at narrow widths, so they drop out; the tagline widens and
     the phone illustration re-centers to fill the freed-up space. */
  .case-hero__media-wallet,
  .case-hero__media-logo { display: none; }
  .case-hero__media-tagline { width: 90%; left: 50%; font-size: 5.5cqw; top: 8%; }
  .case-hero__media-illustration { left: 50%; transform: translateX(-50%); width: 90%; height: 140%; top: 30%; }

  /* Eventra hero: the layered subject-photo + watermark composition is
     tuned against the 1920px desktop reference (percentages), so at
     mobile widths the photo (64% of an already-narrow box) covers most
     of the "EVENTRA" watermark, leaving fragmented, illegible letters
     around it. Shrink the watermark and let the subject breathe. */
  .case-hero__watermark { font-size: 14vw; }
  .case-hero__media-subject { width: 78%; left: 11%; top: -6%; }

  /* ---- About page ----
     Re-checked against the actual mobile Figma frame (node 192:9745) —
     every value below is traced to that frame's own metadata/design
     context, not approximated from the desktop clamp()s. */

  /* Hero (node 192:9746): badge -> dashed-border photo -> statement ->
     title, all centered, same 25px rhythm as the homepage hero. The two
     rotated pill tags have no equivalent node in this mobile frame at
     all — Figma drops them here the same way it drops the homepage
     hero's own pill tags on mobile. The "5+ years experience" stat DOES
     have a real node (192:9851), positioned directly under
     hero3-numbArea__thumb (the large portrait) — missed on the first
     pass because it reuses the homepage's about1-item-content class
     name rather than hero3-numbArea-item-content, which read as a
     leftover duplicate layer. It isn't: its y-position starts exactly
     where the portrait ends, confirmed against the live design. */
  .hero3-content { flex-direction: column; align-items: center; text-align: center; gap: 24px; }
  .hero3-content__title { font-size: 32px; }
  .hero3-content__thumb { width: clamp(180px, 58.14vw, 250px); }
  .hero3-content--desc { flex-direction: column; align-items: center; gap: 24px; padding-top: 0; }
  /* Desktop staggers these two spans as independent absolutely-positioned
     lines (label top-left, paragraph bottom-right) inside a fixed box —
     doesn't fit a narrow column. Figma's mobile version reads as ONE
     continuous centered sentence instead, so this drops the split
     entirely rather than just left-aligning each half in place. */
  .hero3-content__desc { position: static; width: 100%; height: auto; font-size: 21px; text-align: center; margin-top: 30px; color: var(--white); }
  .hero3-content__desc-left,
  .hero3-content__desc-right { position: static; transform: none; display: inline; width: auto; text-align: inherit; }
  .hero3-content__desc-left::after { content: ' '; }
  .hero3-content__title2 { font-size: 55px; line-height: 1; text-align: center; }
  .hero3-content__title2-full { display: none; }
  .hero3-content__title2-mobile { display: block; margin-bottom: 30px; }
  .hero3-content__title2-mobile-line { display: block; }
  .hero3-numbArea { padding-top: 0; flex-direction: column; align-items: center; gap: 24px; }
  .hero3-titleArea__list { display: none; }
  .hero3-numbArea__thumb { width: 100%; border-radius: 20px; }
  /* Figma (node 192:9851): numeral 131.711px on its 430px-wide reference
     canvas — same vw-scaled clamp anchored to that canvas as every other
     big stat numeral on this site (131.711 / 430 ≈ 30.63vw), so it
     tracks the exact Figma value at every mobile breakpoint. */
  .hero3-numbArea-item { justify-content: center; gap: 16px; }
  .hero3-numbArea-item-numb h1 { font-size: clamp(64px, 30.63vw, 132px); }
  .hero3-numbArea-item-content { gap: 7px; }
  .hero3-numbArea-item-content img { width: 44px; height: 44px; }
  .hero3-numbArea-item-content span { font-size: 14px; }

  /* about2 (node 192:10229): both lines centered as one block — 24px
     headline, 20px body — not the 15px guess this had before, which was
     never checked against the actual node. */
  .about2 { padding-block: 64px 80px; }
  .about2__text1 { white-space: normal; font-size: 24px; line-height: 1.3; text-align: center; width: 100%; }
  .about2__text2 { padding-inline: 0; font-size: 20px; margin-top: 32px; }
  .about2__shape { display: none; }

  /* marquee2 (node 192:10274): the crossed ribbons + download button are
     dramatically smaller than the desktop-tuned clamp() floors — ribbon
     text 24px->19px, the circular button 160px->100px with 14px->6px
     type, ribbon band 140px->45px tall. */
  .marquee2-row { height: 45px; }
  .marquee2-item { font-size: 19px; padding-inline: 8px; }
  .marquee2-dot { margin-inline: 6px; }
  .marquee2-btn { position: relative; margin-top: 24px; width: clamp(80px, 23.15vw, 100px); }
  .marquee2-btn span { font-size: 7px; }

  /* about-tabs (nodes 192:10256 / 192:10275): Figma keeps the SAME
     column layout as desktop (big circle on top, the other two side by
     side below with a connecting line) just resized — the previous
     override flipped it to a row and stacked the sub-pair vertically,
     the opposite of what the frame actually shows. */
  /* flex-wrap:wrap survives from desktop's row layout — combined with
     flex-direction:column here (and no constrained container height),
     that made the nav and list wrap into separate side-by-side column
     TRACKS instead of stacking, with the list's track width driven by
     its 500px flex-basis (rendering ~446px wide, blowing past the
     viewport). nowrap forces the intended single-column stack. */
  .about-tabs-row { flex-direction: column; flex-wrap: nowrap; }
  .about-tabs-list { flex-basis: auto; width: 100%; }
  /* Figma's own about-tabs-nav (node 192:10256) is 413.54px wide on its
     430px reference canvas — i.e. the three circles + connecting line
     run almost edge-to-edge, not inset inside the page's usual 24px
     container padding. A flat 151px per circle (fine for the single top
     button alone) left literally no room for the line between the
     bottom two, blowing the group ~120px past the viewport and cutting
     both circles off-screen. Bleeding past the container padding and
     scaling every width off that same 430px canvas (vw-anchored, same
     approach as the big stat numerals) is what actually gets all three
     circles + the connector to fit at every mobile width. */
  .about-tabs-nav { gap: 40px; padding-top: 0; margin-inline: -24px; padding-inline: 8px; }
  .about-tabs-nav__btn { width: 35.19vw; font-size: 15px; }
  .about-tabs-nav__group { gap: 2.72vw; }
  .about-tabs-nav__line { width: 20.37vw; }
  .about-tabs-nav__connector { display: none; }
  .about-tabs-exp__title { font-size: 14px; }
  .about-tabs-exp__time { font-size: 12px; }
  .about-tabs-exp__skills span { font-size: 12px; padding: 5px 14px; }

  /* video2 (node 192:10331): role-tag ticker pills go from a 16px floor
     down to 7px, with tighter padding/radius/gap to match. */
  .video2-ticker-row { height: 28px; }
  .video2-ticker-item { font-size: 7px; padding: 6px 12px; border-radius: 19px; gap: 4px; }

  /* work-process2 (node 192:10767): the numb and title are BIGGER than
     their desktop clamp() floors, not smaller — 70px->118px numb,
     30px->51px title — since this card reads at near-full mobile width
     instead of shrinking proportionally with the rest of the desktop
     layout. */
  .work-process1-card { flex-direction: column; align-items: flex-start; padding: 40px 24px 40px 90px; width: calc(100% - 32px); gap: 24px; }
  .work-process1-card__numb { position: static; transform: none; margin-bottom: 0; font-size: clamp(80px, 27.5vw, 118px); }
  .work-process1-card-content { gap: 16px; }
  .work-process1-card-content__step { font-size: 17px; }
  .work-process1-card-content__title { font-size: clamp(36px, 11.8vw, 51px); }
  .work-process1-card-content__text { font-size: 16px; }
  .work-process2 .section-top__title1,
  .work-process2 .section-top__title2,
  .service2 .section-top__title1,
  .service2 .section-top__title2 { font-size: 34px; }

  /* service2 (node 192:10824): the number badge shrinks to fit the
     row, title drops to its actual 24px value (was floor-ing at 26px). */
  .service2-item { flex-wrap: wrap; gap: 12px; }
  .service2-item__number { width: 44px; height: 44px; }
  .service2-item__title { font-size: 24px; }
  .service2-item__text { max-width: 100%; }

  /* ---- Contact page ---- */
  .contact-row { flex-direction: column; }
  /* Name/Email were relying on flex-wrap math that didn't hold once the
     card's own padding left less width than the pair's combined
     260px+24px+260px basis — force them one-per-row instead. */
  .contact-form1__field { flex: 1 1 100%; }
  /* h1/h2/h3 share line-height:1 with no margin between them (global
     h1-h6 reset) — fine on desktop where h2 fits one line, but once it
     wraps to two lines at mobile widths the outlined h3 below sat
     jammed right against it. */
  .contact-hero__title h2,
  .contact-hero__title h3 { margin-top: 0.15em; }
  /* Figma's mobile contact frame (node 215:10992) drops the vertical
     right-edge social strip entirely — on this narrow layout it's a
     plain horizontal bar sitting below the photo instead, label on the
     left and the icon row on the right. Re-flowing the same markup
     (icons -> divider -> title) rather than restructuring the DOM: the
     title reorders in front, the divider (a vertical rule, meaningless
     once horizontal) just hides. */
  .contact-photo { aspect-ratio: auto; display: flex; flex-direction: column; }
  .contact-photo img { height: auto; aspect-ratio: 885 / 720; }
  .contact-social {
    position: static;
    inset: auto;
    width: 100%;
    flex-direction: row;
    justify-content: space-between;
    align-items: center;
    padding: 16px 20px;
    border: 0;
    border-top: 2px solid var(--black);
    border-radius: 0;
  }
  .contact-social__title { order: -1; writing-mode: horizontal-tb; transform: none; }
  .contact-social__divider { display: none; }
  .contact-social__icons { flex-direction: row; }
  .contact-social__icons a { width: 40px; height: 40px; }
  /* .contact-info has no .container wrapper (it's a full-bleed color
     bar), so the two-line address text needs its own inline padding on
     narrow screens or it runs edge-to-edge. */
  .contact-info { padding-inline: 24px; }

  /* ---- Portfolio page ---- */
  .portfolio-hero__row3 { justify-content: flex-start; }
  .portfolio-hero__photo { aspect-ratio: 4 / 3; border-width: 1px; }
}

/* Info card still tries 2-up at 900px, which leaves 5 items as
   2/2/1 — a half-empty row. Full single column below ~560px reads much
   cleaner than a dangling last item. */
@media (max-width: 560px) {
  .case-info-card__item { flex: 1 1 100%; border-left: none; border-top: 1px solid var(--border-light); }
  .case-info-card__item:first-child { border-top: none; }
}
