/* ============================================================
   Boran Asena — portfolio
   Neon on near black, matching the CV: heavy grotesk display,
   lime for emphasis, mono for labels.
   Vanilla CSS. No framework, no build step.
   ============================================================ */

/* Contrast against --bg (WCAG): ink 17.6, muted 7.5, faint 5.0, lime 16.5.
   Text on lime always uses --on-accent (16.5:1). */
:root {
  --bg:        #0b0d10;
  --surface:   #12151a;
  --raise:     #1a1e24;
  --ink:       #f2f4ef;
  --muted:     #9ba2aa;
  --faint:     #7a828b;
  --line:      #232830;
  --accent:    #c6ff3d;
  --on-accent: #0b0d10;
  --glow:      rgba(198, 255, 61, .35);

  --display: "Inter Tight", "Inter", ui-sans-serif, -apple-system, "Segoe UI", sans-serif;
  --sans:    "Inter", ui-sans-serif, -apple-system, "Segoe UI", sans-serif;
  --mono:    "JetBrains Mono", ui-monospace, "Cascadia Code", Consolas, monospace;

  --shell: 78rem;
  --pad:   1.5rem;

  --ease:  cubic-bezier(.22, .61, .28, 1);
}

@media (min-width: 48rem) { :root { --pad: 2.5rem; } }   /* tablet */
@media (min-width: 60rem) { :root { --pad: 4rem; } }

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* The CV's top-right corner light lives on the page background: a background
   can't overflow, so it can never widen the page on a phone. */
body {
  margin: 0;
  background:
    radial-gradient(46rem 46rem at 100% 0, rgba(198, 255, 61, .12), transparent 60%) no-repeat,
    var(--bg);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { max-width: 100%; height: auto; display: block; }
a   { color: inherit; text-decoration: none; }

::selection { background: var(--accent); color: var(--on-accent); }

:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

.mono {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* Lime words inside display type, with a soft neon bleed. */
.hl {
  color: var(--accent);
  text-shadow: 0 0 42px rgba(198, 255, 61, .28);
}

/* Film grain over everything. The tile repeats, so this only ever needs to
   cover the viewport — no overhang, no oversized compositing layer. */
.grain {
  position: fixed;
  inset: 0;
  z-index: 9;
  pointer-events: none;
  opacity: 0.16;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='220' height='220' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  background-repeat: repeat;
}

/* Touch screens: the grain is a full-screen translucent layer blended over
   every frame while scrolling — the cost isn't worth texture this subtle on
   a small, bright, close-up screen. */
@media (pointer: coarse) {
  .grain { display: none; }
}


/* ─────────────────────── Nav ─────────────────────── */

.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.1rem var(--pad);
  background: rgba(11, 13, 16, 0.72);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid transparent;
  transform: translateY(-100%);
  transition: transform .5s var(--ease), border-color .5s var(--ease);
}

.nav.is-visible {
  transform: none;
  border-bottom-color: var(--line);
}

/* Phones and tablets: a live blur behind a fixed bar is re-rendered on every
   scroll frame and is a classic cause of scroll stutter. A near-opaque bar
   looks the same on a dark page and costs nothing. */
@media (max-width: 63.99rem), (pointer: coarse) {
  .nav {
    backdrop-filter: none;
    background: rgba(11, 13, 16, 0.94);
  }
}

.nav__name {
  font-family: var(--display);
  font-weight: 900;
  font-size: 1.05rem;
  letter-spacing: -0.01em;
  text-transform: uppercase;
}

.nav__name span { color: var(--accent); }

.nav__cta {
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 0.55rem 1rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  transition: border-color .3s, color .3s, box-shadow .3s;
}

.nav__cta:hover { border-color: var(--accent); color: var(--accent); box-shadow: 0 0 18px rgba(198, 255, 61, .2); }


/* ───────────────────── Buttons ───────────────────── */
/* Lime fill always carries dark text (16.5:1). */

.button {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  margin-top: 2.5rem;
  padding: 0.95rem 1.4rem;
  border: 1px solid var(--accent);
  border-radius: 100px;
  background: var(--accent);
  color: var(--on-accent);
  font-family: var(--mono);
  font-size: 0.75rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  transition: background .3s, box-shadow .3s, transform .3s var(--ease), color .3s, border-color .3s;
}

.button:hover {
  background: #d8ff7a;
  box-shadow: 0 0 28px var(--glow);
  transform: translateY(-1px);
}

.button--ghost {
  background: transparent;
  border-color: var(--line);
  color: var(--ink);
}

.button--ghost:hover {
  background: transparent;
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 18px rgba(198, 255, 61, .18);
}


/* ────────────────────── Hero ─────────────────────── */

.hero {
  position: relative;
  min-height: 100svh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 6.5rem var(--pad) 6rem;
  max-width: var(--shell);
  margin: 0 auto;
}

/* Faint bloom behind the name. It only ever overhangs to the left, which
   can't create a sideways scroll. (The corner light is on <body>.) */
.hero::before {
  content: "";
  position: absolute;
  top: 34%; left: 12%;
  width: 45rem; height: 45rem;
  max-width: 90vw;
  transform: translate(-50%, -50%);
  background: radial-gradient(circle, rgba(198, 255, 61, .07), transparent 62%);
  pointer-events: none;
  z-index: -1;
}

/* Single column until there's genuinely room for the editor beside it. */
.hero__inner { display: grid; gap: 3.5rem; }

@media (min-width: 64rem) {
  .hero__inner {
    grid-template-columns: 1.08fr 0.92fr;
    align-items: center;
    gap: 4rem;
  }
}

/* Tight enough to stay on one line at 390px; opens up once there's room. */
.hero__tags {
  margin: 0 0 1.75rem;
  color: var(--accent);
  letter-spacing: 0.06em;
}

@media (min-width: 40rem) { .hero__tags { letter-spacing: 0.16em; } }

/* The CV's two-tone name. Uppercase heavy grotesk has no descenders, so the
   tight line-height can't clip anything inside the reveal mask. */
.hero__name {
  margin: 0 0 1.75rem;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(3.9rem, 18vw, 8rem);
  line-height: 0.9;
  letter-spacing: -0.035em;
  text-transform: uppercase;
}

@media (min-width: 64rem) {
  .hero__name { font-size: clamp(5.5rem, 8.8vw, 9rem); }
}

/* The reveal mask (overflow: hidden) would clip a text-shadow into a visible
   box. A filter is applied after the clip, so the glow can spill outside. */
.hero__name .hl { text-shadow: none; }
.hero__name .line:nth-child(2) { filter: drop-shadow(0 0 26px rgba(198, 255, 61, .3)); }

.hero__title {
  margin: 0 0 1.25rem;
  max-width: 21ch;
  font-family: var(--display);
  font-weight: 700;
  font-size: clamp(1.55rem, 5.2vw, 2.6rem);
  line-height: 1.18;
  letter-spacing: -0.02em;
}

@media (min-width: 64rem) {
  .hero__title { font-size: clamp(1.9rem, 2.5vw, 2.6rem); }
}

/* The CV's lime box behind "AI". */
.hero__title mark {
  padding: 0 0.16em;
  border-radius: 0.14em;
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 0 28px var(--glow);
}

.hero__sub {
  max-width: 40ch;
  margin: 0;
  font-size: clamp(1rem, 1.6vw, 1.1875rem);
  color: var(--muted);
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2.25rem;
}

.hero__actions .button { margin-top: 0; }

/* Entrance: the name slides up out of a mask, everything else fades in. */
.line {
  display: block;
  overflow: hidden;
}

.line > span { display: block; }

.js .line > span { transform: translateY(105%); }

.js .hero.is-ready .line > span {
  transform: none;
  transition: transform 1.05s var(--ease);
}

.js .hero.is-ready .line:nth-child(2) > span { transition-delay: .09s; }

.js .hero__tags,
.js .hero__title,
.js .hero__sub,
.js .hero__actions {
  opacity: 0;
  transform: translateY(10px);
}

.js .hero.is-ready .hero__tags,
.js .hero.is-ready .hero__title,
.js .hero.is-ready .hero__sub,
.js .hero.is-ready .hero__actions {
  opacity: 1;
  transform: none;
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}

.js .hero.is-ready .hero__title   { transition-delay: .3s; }
.js .hero.is-ready .hero__sub     { transition-delay: .45s; }
.js .hero.is-ready .hero__actions { transition-delay: .6s; }


/* ───────────────────── Hero editor ───────────────────── */

/* Below 64rem this sits under the copy; above, it takes the right column.
   Opaque rather than blurred — one less compositing layer, same look. */
.editor {
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  box-shadow: 0 40px 80px -40px rgba(0, 0, 0, .9), 0 0 0 1px rgba(198, 255, 61, .04);
  overflow: hidden;
}

.editor__bar {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.85rem 1.1rem;
  border-bottom: 1px solid var(--line);
  background: rgba(26, 30, 36, .6);
}

.editor__dots { display: flex; gap: 0.4rem; }

.editor__dots i {
  width: 9px;
  height: 9px;
  border-radius: 50%;
  background: var(--line);
}

.editor__dots i:first-child { background: rgba(198, 255, 61, .45); }

.editor__file { color: var(--faint); }

.editor__code {
  margin: 0;
  padding: 1.25rem 1.1rem 1.5rem;
  font-family: var(--mono);
  /* Small enough that the longest line clears a 375px screen without
     sideways scrolling; grows once there's room. */
  font-size: 0.625rem;
  line-height: 1.9;
  /* Reserve the finished height so the hero can't jump while typing. */
  min-height: 15rem;
  white-space: pre;
  overflow-x: auto;
  scrollbar-width: none;
}

@media (min-width: 48rem) {
  .editor__code { font-size: 0.75rem; min-height: 16.5rem; }
}

@media (min-width: 64rem) {
  .editor__code {
    padding: 1.5rem 1.4rem 1.75rem;
    font-size: 0.8125rem;
    line-height: 1.85;
    min-height: 17.5rem;
  }
}

.editor__code::-webkit-scrollbar { display: none; }

/* All measured on the editor surface: kw 15.5, fn 15.2, str 11.0,
   num 8.8, punctuation 7.1, comments 4.7 (:1). */
.editor__code .kw  { color: var(--accent); }
.editor__code .fn  { color: #e8ebe6; }
.editor__code .str { color: #8fd6c9; }
.editor__code .num { color: #b9a8ff; }
.editor__code .com { color: var(--faint); font-style: italic; }
.editor__code .pun,
.editor__code .id  { color: var(--muted); }

.editor__caret {
  display: inline-block;
  width: 7px;
  height: 1.05em;
  vertical-align: -0.18em;
  background: var(--accent);
  box-shadow: 0 0 10px var(--glow);
  animation: blink 1.05s steps(1) infinite;
}

@keyframes blink { 50% { opacity: 0; } }

.hero__cue {
  position: absolute;
  left: var(--pad);
  bottom: 2.25rem;
  display: flex;
  align-items: center;
  gap: 1rem;
  color: var(--faint);
  transition: color .3s;
}

.hero__cue:hover { color: var(--accent); }

.hero__cue-line {
  width: 3.5rem;
  height: 1px;
  background: currentColor;
  transform-origin: left;
  animation: cue 2.4s var(--ease) infinite;
}

@keyframes cue {
  0%, 100% { transform: scaleX(.4); opacity: .5; }
  50%      { transform: scaleX(1);  opacity: 1; }
}


/* ───────────────────── Intro ─────────────────────── */

main { position: relative; z-index: 2; }

.intro {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 4rem var(--pad) 6rem;
  display: grid;
  gap: 3rem;
  align-items: center;
}

/* ── Base = mobile: single column, centred ──
   ALL base rules live here, before the media queries. Every override below
   has the same specificity, so it only wins by coming later in source order. */

/* The CV's portrait: colour, tight crop, lime block offset behind it. */
.intro__portrait {
  position: relative;
  margin: 0 auto;
  width: min(74%, 17rem);
}

.intro__portrait::before {
  content: "";
  position: absolute;
  inset: 0;
  transform: translate(14px, 14px);
  border-radius: 16px;
  background: var(--accent);
  box-shadow: 0 0 48px rgba(198, 255, 61, .25);
}

.intro__portrait img {
  position: relative;
  width: 100%;
  aspect-ratio: 618 / 758;
  object-fit: cover;
  border-radius: 16px;
  background: var(--raise);
}

.intro__body { text-align: center; }

.intro__body p {
  margin: 0 auto;               /* centre the constrained block on mobile */
  max-width: 24ch;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.35rem, 2.6vw, 2.05rem);
  line-height: 1.28;
  letter-spacing: -0.015em;
}

/* ── 40rem up: two columns, left-aligned ── */
@media (min-width: 40rem) {
  .intro {
    grid-template-columns: 15rem 1fr;
    gap: 4rem;
    padding-bottom: 7rem;
  }
  .intro__portrait { margin: 0; width: auto; }
  .intro__body { text-align: left; }
  .intro__body p { margin: 0; max-width: 30ch; }
}

/* ── Desktop: bigger portrait ── */
@media (min-width: 64rem) {
  .intro {
    grid-template-columns: 21rem 1fr;
    gap: 5.5rem;
  }
}

.intro__meta {
  margin-top: 2rem !important;
  font-family: var(--mono) !important;
  font-size: 0.6875rem !important;
  font-weight: 500 !important;
  line-height: 1.6 !important;
  letter-spacing: 0.1em !important;
  color: var(--faint);
  max-width: none !important;
}


/* ─────────────────── At a glance ─────────────────── */
/* The CV's stat column: big numbers on a thick lime bar. */

.stats {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--pad) 7rem;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 2.25rem 1.5rem;
}

@media (min-width: 64rem) {
  .stats { grid-template-columns: repeat(4, 1fr); gap: 2rem; padding-bottom: 11rem; }
}

.stat {
  padding-left: 1rem;
  border-left: 4px solid var(--accent);
}

.stat__num {
  display: block;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.4rem, 7vw, 4.25rem);
  line-height: 1;
  letter-spacing: -0.04em;
}

.stat__label {
  display: block;
  margin-top: 0.6rem;
  max-width: 22ch;
  color: var(--muted);
  font-size: 0.9375rem;
  line-height: 1.4;
}


/* ────────────────────── Work ─────────────────────── */

.work {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--pad) 8rem;
}

@media (min-width: 60rem) { .work { padding-bottom: 12rem; } }

.work__head {
  padding-top: 3rem;
  border-top: 1px solid var(--line);
  margin-bottom: 3.5rem;
}

.work__index {
  display: block;
  color: var(--accent);
  margin-bottom: 1.75rem;
}

.work__title {
  margin: 0 0 1rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(2.4rem, 6.5vw, 5rem);
  line-height: 1;
  letter-spacing: -0.035em;
}

/* Engineering is deliberately shorter: a smaller headline, same rhythm. */
.work__title--sm {
  font-size: clamp(1.9rem, 4.4vw, 3.4rem);
  line-height: 1.05;
  max-width: 20ch;
}

/* The CV's lime subtitle line under each project name. */
.work__sub {
  margin: 0 0 1.5rem;
  color: var(--accent);
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1rem, 1.7vw, 1.25rem);
  line-height: 1.35;
}

.work__lede {
  margin: 0;
  max-width: 46ch;
  color: var(--muted);
  font-size: 1.0625rem;
}

.work__meta {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 2.5rem;
  margin: 2.5rem 0 0;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
}

.work__meta dt { color: var(--faint); margin-bottom: 0.4rem; }
.work__meta dd { margin: 0; color: var(--ink); text-transform: none; letter-spacing: 0.02em; }

.work__meta a {
  border-bottom: 1px solid var(--accent);
  transition: color .3s;
}

.work__meta a:hover { color: var(--accent); }


/* Two live demos under the 12 Goods screens: side by side once there's room. */
.demos {
  display: grid;
  gap: 1.75rem;
  margin-top: 3.5rem;
}

@media (min-width: 48rem) {
  .demos { grid-template-columns: 1fr 1fr; gap: 2rem; }
}


/* ───────────────────── Results ───────────────────── */

.results { margin-top: 5rem; }

.results__line {
  margin: 0;
  padding-top: 2.5rem;
  border-top: 1px solid var(--line);
  max-width: 52ch;
  font-size: clamp(1.125rem, 1.8vw, 1.375rem);
  line-height: 1.5;
}

/* The callout sits beside its proof on desktop, above it on mobile. */
.callout {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  margin: 3.5rem 0;
}

@media (min-width: 64rem) {
  .callout { grid-template-columns: 1.1fr 0.9fr; gap: 4.5rem; }
}

.callout__big {
  margin: 0 0 1.25rem;
  padding-left: 1.25rem;
  border-left: 4px solid var(--accent);
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.85rem, 3.8vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.03em;
}

.callout__big em {
  font-style: normal;
  color: var(--accent);
  text-shadow: 0 0 36px rgba(198, 255, 61, .25);
}

.callout__big--solo {
  margin-bottom: 2.5rem;
  font-size: clamp(1.6rem, 3vw, 2.4rem);
  max-width: 26ch;
}

.callout__note {
  margin: 0;
  padding-left: calc(1.25rem + 4px);
  max-width: 44ch;
  color: var(--muted);
  font-size: 1.0625rem;
}

.proof { margin: 0; }

.proof img,
.proof video {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 12px;
  border: 1px solid var(--line);
  background: var(--surface);
}

.proof figcaption { margin-top: 1rem; color: var(--faint); }

.proof--early { max-width: 32rem; }

/* Insights is a tall phone capture, the summary is landscape: pair them
   rather than stretching the tall one to full width. */
.proof-pair {
  display: grid;
  gap: 2rem;
  align-items: start;
}

.proof--insights { max-width: 22rem; }

@media (min-width: 48rem) {
  .proof-pair { grid-template-columns: minmax(0, 20rem) minmax(0, 1fr); gap: 2.5rem; }
}

@media (min-width: 64rem) {
  .proof-pair { grid-template-columns: minmax(0, 22rem) minmax(0, 1fr); }
}


/* ───────────────── AI and engineering ────────────── */

.ai__also {
  margin: 4.5rem 0 0;
  padding-top: 2rem;
  border-top: 1px solid var(--line);
  max-width: 34ch;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.3rem, 2.5vw, 1.9rem);
  line-height: 1.25;
  letter-spacing: -0.015em;
}

.eng__media {
  display: grid;
  gap: 1.5rem;
  align-items: start;
}

/* Photo (1.76:1) and video (16:9) are near-identical shapes, so equal
   columns keep their heights level. */
@media (min-width: 48rem) {
  .eng__media { grid-template-columns: 1fr 1fr; gap: 2rem; }
}

.eng__notes {
  display: grid;
  gap: 0.85rem;
  margin-top: 3rem;
  max-width: 62ch;
}

.eng__notes p { margin: 0; color: var(--muted); }
.eng__notes p:last-child { color: var(--ink); }


/* ──────────────────── Carousel ───────────────────── */

.carousel { position: relative; }

.carousel__track {
  display: flex;
  gap: 1.25rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  scrollbar-width: none;
  outline: none;
  /* Bleed to the screen edge on mobile so it reads as swipeable. */
  margin: 0 calc(var(--pad) * -1);
  padding: 0 var(--pad);
}

.carousel__track::-webkit-scrollbar { display: none; }

.slide {
  flex: 0 0 100%;
  scroll-snap-align: center;
  margin: 0;
}

.slide img {
  width: 100%;
  border-radius: 10px;
  border: 1px solid var(--line);
  background: var(--surface);
  box-shadow: 0 30px 70px -30px rgba(0, 0, 0, .9);
  /* Sources land between 2.07 and 2.14 after cropping. Pinning the ratio
     keeps every slide the same height so the carousel never jumps; anchoring
     to the top means the trim comes off the bottom, never off the nav. */
  aspect-ratio: 2.1 / 1;
  object-fit: cover;
  object-position: top center;
}

.slide figcaption {
  display: flex;
  gap: 1rem;
  margin-top: 1.5rem;
  font-size: 0.9375rem;
  color: var(--muted);
  max-width: 52ch;
}

.slide figcaption .mono { color: var(--accent); flex: none; padding-top: .28rem; }

.carousel__ui {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  margin-top: 2.5rem;
}

.carousel__dots { display: flex; gap: 0.5rem; }

.carousel__dots button {
  width: 2rem;
  height: 3px;
  padding: 0;
  border: 0;
  border-radius: 2px;
  background: var(--line);
  cursor: pointer;
  transition: background .4s var(--ease), box-shadow .4s var(--ease);
}

.carousel__dots button.is-active {
  background: var(--accent);
  box-shadow: 0 0 12px var(--glow);
}

.carousel__arrows { display: flex; gap: 0.5rem; }

.carousel__arrows button {
  width: 2.75rem;
  height: 2.75rem;
  display: grid;
  place-items: center;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: none;
  color: var(--ink);
  font-size: 0.9rem;
  cursor: pointer;
  transition: border-color .3s, color .3s, opacity .3s, box-shadow .3s;
}

.carousel__arrows button:hover:not(:disabled) {
  border-color: var(--accent);
  color: var(--accent);
  box-shadow: 0 0 16px rgba(198, 255, 61, .2);
}

.carousel__arrows button:disabled { opacity: .25; cursor: default; }

/* Film strip (AI section): wide and phone screenshots share a height and keep
   their own shape, instead of being cover-cropped into the 2.1:1 box. Both
   width and height stay auto so max-width/max-height scale proportionally. */
.carousel--film .carousel__track { align-items: center; }

.carousel--film .slide { flex: 0 0 auto; }

.carousel--film .slide img {
  width: auto;
  height: auto;
  aspect-ratio: auto;
  object-fit: contain;
  max-height: min(72vh, 34rem);
  max-width: calc(100vw - 2 * var(--pad));
}

/* Desktop: the third cap is the wide shots' own height at full width
   (1.637:1), so phone slides never come out taller than the wide ones. */
@media (min-width: 64rem) {
  .carousel--film .slide img {
    max-height: min(76vh, 44rem, calc((min(100vw, var(--shell)) - 2 * var(--pad)) / 1.637));
    max-width: calc(min(100vw, var(--shell)) - 2 * var(--pad));
  }
}

/* Below desktop the wide shots hit the screen width long before the phone
   shots hit their height, so the strip is taller than the wide slides. Give
   every slide the same dark stage so that difference reads as a frame, not
   as a gap in the page. */
@media (max-width: 63.99rem) {
  .carousel--film .slide {
    height: min(66vh, 28rem);
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 12px;
    overflow: hidden;
  }

  .carousel--film .slide img {
    max-height: 100%;
    border: 0;
    border-radius: 0;
    box-shadow: none;
  }
}

/* Tablets have room for a taller stage; the phone shots stay readable. */
@media (min-width: 48rem) and (max-width: 63.99rem) {
  .carousel--film .slide { height: min(62vh, 34rem); }
}


/* ──────────────────── More note ──────────────────── */

.more {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 0 var(--pad) 8rem;
}

@media (min-width: 60rem) { .more { padding-bottom: 12rem; } }

.more p {
  margin: 0;
  max-width: 34ch;
  font-family: var(--display);
  font-weight: 600;
  font-size: clamp(1.3rem, 2.5vw, 1.9rem);
  line-height: 1.3;
  letter-spacing: -0.015em;
  color: var(--muted);
}


/* ──────────────────── Design grid ────────────────── */
/* Deliberately quieter than the case studies above: mono label and a plain
   lede, no display heading, smaller images. It supports, not competes. */

.design {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 3rem var(--pad) 8rem;
  border-top: 1px solid var(--line);
}

@media (min-width: 60rem) { .design { padding-bottom: 12rem; } }

.design__label { display: block; color: var(--accent); margin-bottom: 2rem; }

.design__lede {
  margin: 0 0 3rem;
  max-width: 52ch;
  color: var(--muted);
  font-size: 1.0625rem;
}

/* Default (no JS): CSS multi-column. Works, but can leave a balancing gap
   when a tall image won't fit — so script.js upgrades this to true masonry,
   placing each image in the shortest column. Each image keeps its native
   ratio; nothing is hard-cropped into a box. */
.gallery {
  columns: 1;
  column-gap: 1rem;
}

@media (min-width: 40rem) { .gallery { columns: 2; column-gap: 1.25rem; } }
@media (min-width: 64rem) { .gallery { columns: 3; } }

.gallery figure {
  margin: 0 0 1rem;
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
}

@media (min-width: 40rem) { .gallery figure { margin-bottom: 1.25rem; } }

/* JS masonry: real columns, each filled independently — no interior gaps. */
.gallery.is-masonry {
  columns: auto;
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

@media (min-width: 40rem) { .gallery.is-masonry { gap: 1.25rem; } }

.gallery__col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 1rem;
}

@media (min-width: 40rem) { .gallery__col { gap: 1.25rem; } }

.gallery.is-masonry figure { margin: 0; }

.gallery img {
  width: 100%;
  height: auto;
  border-radius: 8px;
  border: 1px solid var(--line);
  transition: transform .5s var(--ease), border-color .5s var(--ease);
}

.gallery img:hover { transform: translateY(-3px); border-color: rgba(198, 255, 61, .4); }


/* ─────────────────── What I build ────────────────── */

.build {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 3rem var(--pad) 8rem;
  border-top: 1px solid var(--line);
}

@media (min-width: 60rem) { .build { padding-bottom: 12rem; } }

.build__label { display: block; color: var(--accent); margin-bottom: 3rem; }

.build__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1px;
  background: var(--line);
  border: 1px solid var(--line);
  border-radius: 12px;
  overflow: hidden;
}

@media (min-width: 40rem) {
  .build__grid { grid-template-columns: 1fr 1fr; }
  /* Five services: the odd last card spans the row, otherwise the empty
     sixth cell shows the grid's line-coloured background as a grey block. */
  .build__grid li:last-child:nth-child(odd) { grid-column: 1 / -1; }
}

.build__grid li {
  position: relative;
  background: var(--bg);
  padding: 2.5rem 2rem;
  transition: background .4s var(--ease);
}

/* A lime bar slides in along the top edge on hover. */
.build__grid li::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 3px;
  background: var(--accent);
  box-shadow: 0 0 16px var(--glow);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .5s var(--ease);
}

.build__grid li:hover { background: var(--surface); }
.build__grid li:hover::before { transform: scaleX(1); }

.build__grid .mono { color: var(--accent); }

.build__grid h3 {
  margin: 1rem 0 0.75rem;
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.7rem;
  letter-spacing: -0.025em;
}

.build__grid p {
  margin: 0;
  color: var(--muted);
  font-size: 0.9375rem;
  max-width: 34ch;
}

/* The CV's toolbox: filled pills are the daily drivers. */
.toolbox { margin-top: 3.5rem; }

.toolbox__label { display: block; color: var(--accent); margin-bottom: 1.25rem; }

.pills {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.55rem;
}

.pill {
  padding: 0.5rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  color: var(--ink);
  font-size: 0.875rem;
  line-height: 1.2;
}

.pill--on {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
}


/* ───────────────────── Contact ───────────────────── */

.contact {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 3rem var(--pad) 6rem;
  border-top: 1px solid var(--line);
}

.contact__label { display: block; color: var(--accent); margin-bottom: 2.5rem; }

.contact__title {
  margin: 0 0 3.5rem;
  font-family: var(--display);
  font-weight: 900;
  font-size: clamp(2.75rem, 9.5vw, 6.75rem);
  line-height: 0.95;
  letter-spacing: -0.04em;
  text-transform: uppercase;
}

.contact__list { list-style: none; margin: 0; padding: 0; }

.contact__list li { border-top: 1px solid var(--line); }
.contact__list li:last-child { border-bottom: 1px solid var(--line); }

.contact__list a {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 0.35rem 2rem;
  padding: 1.6rem 0;
  transition: color .3s, padding-left .4s var(--ease);
}

.contact__list a:hover { color: var(--accent); padding-left: 1rem; }

/* Narrow screens: label always on its own line, so long and short
   values can't align differently from each other. */
.contact__list span {
  flex: 0 0 100%;
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--faint);
}

.contact__list a:hover span { color: var(--accent); }

@media (min-width: 40rem) {
  .contact__list span { flex: 0 0 8rem; }
}

.contact__list em {
  font-family: var(--display);
  font-style: normal;
  font-weight: 700;
  font-size: clamp(1.3rem, 3.2vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
}

.contact__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem 3.5rem;
  margin: 2.5rem 0 0;
}

.contact__facts dt { color: var(--faint); margin-bottom: 0.4rem; }
.contact__facts dd { margin: 0; color: var(--ink); text-transform: none; letter-spacing: 0.02em; font-size: 0.8125rem; }

/* The CV's closing band: lime, dark text, the last thing on the page. */
.cta-band {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 2rem;
  margin-top: 4rem;
  padding: 1.6rem 1.75rem;
  border-radius: 14px;
  background: var(--accent);
  color: var(--on-accent);
  box-shadow: 0 0 60px rgba(198, 255, 61, .16);
  transition: transform .35s var(--ease), box-shadow .35s var(--ease);
}

.cta-band:hover {
  transform: translateY(-2px);
  box-shadow: 0 0 80px rgba(198, 255, 61, .3);
}

.cta-band__text {
  font-family: var(--display);
  font-weight: 800;
  font-size: clamp(1.35rem, 3.4vw, 2.2rem);
  line-height: 1.1;
  letter-spacing: -0.025em;
}

.cta-band__go { font-size: 0.75rem; }


/* ────────────────────── Footer ───────────────────── */

.foot {
  max-width: var(--shell);
  margin: 0 auto;
  padding: 2.5rem var(--pad) 3rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  flex-wrap: wrap;
  color: var(--faint);
  border-top: 1px solid var(--line);
}


/* ─────────────── Reveal on scroll ────────────────── */
/* .js is set inline in <head> so nothing hides without JS. */

.js .reveal {
  opacity: 0;
  transform: translateY(24px);
}

.js .reveal.is-in {
  opacity: 1;
  transform: none;
  transition: opacity .9s var(--ease), transform .9s var(--ease);
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal,
  .js .line > span,
  .js .hero__tags,
  .js .hero__title,
  .js .hero__sub,
  .js .hero__actions { opacity: 1; transform: none; }
  .js .reveal.is-in { transition: none; }
  .hero__cue-line { animation: none; }
  .carousel__track { scroll-behavior: auto; }
  .button,
  .cta-band,
  .gallery img,
  .build__grid li::before { transition: none; }
}


/* ───────── Mobile AI strip: wide shots fill their frame ───────── */
/* Below desktop the two wide composites used to sit letterboxed in the tall
   stage. Fill the frame instead, cropped to the centre: that keeps the
   headline and the middle phone, matching the full-bleed phone slides. */
@media (max-width: 63.99rem) {
  .carousel--film .slide--wide { width: calc(100vw - 2 * var(--pad)); }

  .carousel--film .slide--wide img {
    width: 100%;
    height: 100%;
    max-width: none;
    max-height: none;
    object-fit: cover;
    object-position: center top;
  }
}


/* ───────── La Casa de Alberto: size-filter feature ───────── */
.feature {
  margin-top: 4.5rem;
  padding-top: 2.5rem;
  border-top: 1px solid var(--line);
}

.feature__label { display: block; color: var(--accent); margin-bottom: 1.25rem; }

.feature__text {
  margin: 0 0 2.5rem;
  max-width: 52ch;
  font-size: clamp(1.125rem, 1.8vw, 1.375rem);
  line-height: 1.5;
}


/* AI strip, third slide: the three phone screens together, side by side. */
.carousel--film .slide--trio {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
}

@media (max-width: 63.99rem) {
  .carousel--film .slide--trio {
    width: calc(100vw - 2 * var(--pad));
    gap: 0.5rem;
    padding: 0 0.5rem;
  }

  .carousel--film .slide--trio img {
    flex: 1 1 0;
    min-width: 0;
    width: 100%;
    height: auto;
    max-height: 100%;
    object-fit: contain;
  }
}

/* AI strip: desktop shows the three phones as one slide, phones/tablets
   show them as three separate full-frame slides. script.js builds the
   dots from whichever set is visible. */
.carousel--film .slide--single { display: none; }

@media (max-width: 63.99rem) {
  .carousel--film .slide--trio   { display: none; }
  .carousel--film .slide--single { display: flex; }
}
@media (max-width: 63.99rem) {
  /* Keep the phone slides' shape before their images load, so arrow
     positions are right even if someone taps early. */
  .carousel--film .slide--single img { height: 100%; width: auto; aspect-ratio: 900 / 1948; }
}

/* The cropped home hero is squarer than the 2.1:1 slide: centre it so the
   bag stays whole (the other slides keep their top anchor). */
.slide img[src$="work-01-home-hero.jpg"] { object-position: top center; }


/* ───────────────────── Email design ───────────────────── */

.email-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 1.5rem;
}

/* One column on phones, three equal columns from 40rem up: never 2 + 1. */
@media (min-width: 40rem) { .email-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 1.25rem; } }
@media (min-width: 64rem) { .email-grid { gap: 2rem; } }

.email-card {
  display: flex;
  flex-direction: column;
  width: 100%;
  height: 100%;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--surface);
  color: var(--ink);
  font: inherit;
  text-align: left;
  cursor: pointer;
  overflow: hidden;
  transition: border-color .4s var(--ease), transform .4s var(--ease), box-shadow .4s var(--ease);
}

.email-card:hover {
  border-color: rgba(198, 255, 61, .45);
  transform: translateY(-3px);
  box-shadow: 0 0 32px rgba(198, 255, 61, .12);
}

/* Only the top of each email: same height on every card. */
.email-card__img { display: block; border-bottom: 1px solid var(--line); }

.email-card__img img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 6 / 7;         /* equal columns -> identical heights; no side crop */
  object-fit: cover;
  object-position: top;
}

.email-card__body { display: flex; flex-direction: column; flex: 1; padding: 1.5rem 1.5rem 1.6rem; }

.email-card__name {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.6rem;
  letter-spacing: -0.025em;
  line-height: 1.1;
}

.email-card__sub {
  margin-top: 0.35rem;
  color: var(--accent);
  font-family: var(--display);
  font-weight: 600;
  font-size: 1rem;
}

.email-card__text { margin-top: 0.85rem; color: var(--muted); font-size: 0.9375rem; line-height: 1.5; }

.email-card__open { margin-top: auto; padding-top: 1.25rem; color: var(--faint); transition: color .3s; }

.email-card:hover .email-card__open { color: var(--accent); }

/* Lightbox */
.lightbox {
  width: min(100vw, 46rem);
  max-width: 100vw;
  height: 100dvh;
  max-height: 100dvh;
  margin: 0 auto;
  padding: 0;
  border: 0;
  border-left: 1px solid var(--line);
  border-right: 1px solid var(--line);
  background: var(--bg);
  color: var(--ink);
  overflow: hidden;
}

.lightbox[open] { display: flex; flex-direction: column; }

.lightbox::backdrop { background: rgba(5, 6, 8, .88); }

.lightbox__bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 1rem;
  padding: 0.9rem 1rem;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.lightbox__title {
  font-family: var(--display);
  font-weight: 800;
  font-size: 1.15rem;
  letter-spacing: -0.02em;
}

.lightbox__tabs { display: flex; flex-wrap: wrap; gap: 0.4rem; order: 3; width: 100%; }

.lightbox__tabs button {
  padding: 0.45rem 0.85rem;
  border: 1px solid var(--line);
  border-radius: 100px;
  background: none;
  color: var(--ink);
  font-family: var(--mono);
  font-size: 0.6875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}

.lightbox__tabs button[aria-selected="true"] {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.lightbox__close {
  margin-left: auto;
  width: 2.5rem;
  height: 2.5rem;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: none;
  color: var(--ink);
  font-size: 1rem;
  cursor: pointer;
}

.lightbox__close:hover { border-color: var(--accent); color: var(--accent); }

.lightbox__scroll {
  flex: 1;
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  outline: none;
}

.lightbox__scroll img { display: block; width: 100%; height: auto; }

html.lightbox-open { overflow: hidden; }

@media (prefers-reduced-motion: reduce) {
  .email-card { transition: none; }
}
