/* ===================================================================
   LAYOUT — le sezioni della pagina
   ===================================================================
   Navbar, il cubo 3D del logo, lo sfondo fluido, la hero, le card col
   bordo luminoso, le intestazioni di sezione, Progetti, Risultati, Chi
   Sono, la CTA finale e il footer.

   In coda ci sono i due @media (980px e 640px) che chiudono questo
   gruppo. Stavano gia' qui e qui restano: spostarli in responsive.css
   li porterebbe DOPO scene.css, e a quel punto vincerebbero loro dove
   oggi perdono.

   ATTENZIONE ALL'ORDINE
   Questi quattro file erano un solo css/style.css da 1615 righe, tagliato
   in sequenza il 04/09/2026: nessuna riga e' stata spostata rispetto alle
   altre, ne' riscritta. Nel CSS, a parita' di specificita', vince chi
   arriva dopo — quindi in index.html vanno collegati in QUEST'ORDINE e in
   nessun altro:

       base.css  ->  layout.css  ->  scene.css  ->  responsive.css

   Invertirne due cambia quale regola vince, e rompe la pagina in punti
   difficili da ricollegare alla causa.
   =================================================================== */


/* ===== Navbar ===== */
.navbar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background 0.5s var(--ease), backdrop-filter 0.5s var(--ease), border-color 0.5s var(--ease);
}
.navbar.scrolled {
  background: rgba(0, 0, 0, 0.8);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-bottom-color: rgba(255, 255, 255, 0.08);
}

.nav-inner {
  max-width: 1280px;
  margin: 0 auto;
  padding: 18px 24px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
}

.logo { display: flex; align-items: center; gap: 14px; flex-shrink: 0; }

/* ===== Logo mark: interactive 3D cube badge =====
   A real six-faced cube rather than a flat tile — white "LC" plates front and
   back, accent-amber sides. js/hud-3d.js drives --cube-rx / --cube-ry so it
   banks toward the pointer and swings a quarter turn on hover; the defaults
   below hold a fixed three-quarter view, so it still reads as solid without
   JS and under prefers-reduced-motion. */
.logo-icon {
  position: relative;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  perspective: 300px;
}

/* Amber bloom behind the cube, lit on hover. */
.logo-icon::after {
  content: '';
  position: absolute;
  inset: -10px;
  z-index: -1;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(219, 107, 43, 0.5), rgba(219, 107, 43, 0) 70%);
  opacity: 0;
  transition: opacity 0.5s var(--ease);
  pointer-events: none;
}
.logo:hover .logo-icon::after { opacity: 1; }

.logo-cube {
  position: relative;
  /* A bare <span> is inline, and width/height don't apply to inline boxes —
     without this the cube collapses to 0x0 and takes every face with it. */
  display: block;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
  transform: rotateX(var(--cube-rx, -14deg)) rotateY(var(--cube-ry, -20deg));
}

.cube-face {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 12px;
  letter-spacing: 0.02em;
  /* Kept tight: rounder corners would open visible gaps where the faces meet. */
  border-radius: 3px;
  backface-visibility: hidden;
}

/* Half the 36px cube — every face is pushed out by this much. */
.cube-face--front  { transform: translateZ(18px); }
.cube-face--back   { transform: rotateY(180deg) translateZ(18px); }
.cube-face--right  { transform: rotateY(90deg) translateZ(18px); }
.cube-face--left   { transform: rotateY(-90deg) translateZ(18px); }
.cube-face--top    { transform: rotateX(90deg) translateZ(18px); }
.cube-face--bottom { transform: rotateX(-90deg) translateZ(18px); }

.cube-face--front,
.cube-face--back {
  background: linear-gradient(150deg, #ffffff 0%, #d2d2d2 100%);
  color: #050505;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9);
}

.cube-face--right,
.cube-face--left {
  background: linear-gradient(150deg, #e8813c 0%, #8f3f12 100%);
  color: rgba(255, 255, 255, 0.92);
  font-size: 14px;
}

.cube-face--top,
.cube-face--bottom {
  background: linear-gradient(150deg, #303030 0%, #0a0a0a 100%);
}
.logo-word { font-family: var(--font-serif); font-style: italic; font-size: 17px; letter-spacing: -0.01em; }

.nav-links { display: flex; gap: 36px; }
.nav-links a {
  position: relative;
  font-size: 14px;
  color: var(--text-50);
  transition: color 0.3s var(--ease);
  padding-bottom: 4px;
}
.nav-links a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  height: 1px;
  width: 0;
  background: var(--accent);
  transition: width 0.4s var(--ease);
}
.nav-links a:hover { color: var(--text); }
.nav-links a:hover::after { width: 100%; }

.cta-button {
  font-size: 13px;
  font-weight: 500;
  padding: 10px 22px;
  border-radius: 999px;
  background: var(--accent);
  color: #050505;
  animation: pulse-shadow 2.6s var(--ease) infinite;
  flex-shrink: 0;
}

.nav-toggle {
  display: none;
  flex-direction: column;
  /* Centrate: il padding qui sotto rende il pulsante molto piu' grande del
     disegno, e le tre righe devono restare in mezzo a quell'area. */
  align-items: center;
  justify-content: center;
  gap: 5px;
  background: none;
  border: none;
  cursor: pointer;
  /* 44x44, che e' la misura minima che Apple e Google indicano entrambe per
     qualcosa che si preme con un dito. Il disegno resta di 20x17: cresce
     l'AREA, non il segno. Col padding di 6px il bersaglio era 32x25 — si
     mancava, e su un menu che e' l'unico modo di navigare mancarlo significa
     restare bloccati. */
  padding: 0;
  width: 44px;
  height: 44px;
  flex-shrink: 0;
  /* Recupera la meta' dei 44px che sborda oltre il disegno, cosi' il pulsante
     non allarga la barra: l'area invisibile si sovrappone all'aria che c'era
     gia' intorno. */
  margin: -8px -10px -8px 0;
}
.nav-toggle span { width: 20px; height: 1px; background: var(--text); transition: transform 0.3s var(--ease), opacity 0.3s var(--ease); }
.nav-toggle.open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle.open span:nth-child(2) { opacity: 0; }
.nav-toggle.open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* ===== LiquidEther background (every section except the hero) =====
   One shared, viewport-fixed fluid field — see js/liquid-ether.js. A single
   layer rather than one canvas per section: it is a fluid solve, and six of
   them is not a thing a GPU should be asked to do.

   z-index -1 keeps it under everything (sections are z-index 1). It is still
   visible down there because `body`'s background propagates to the root
   element and is painted as the page canvas, which leaves `body` itself with
   no background box for a negative-z child to hide behind.

   Opacity is the "delicate" dial, and it is also what excludes the hero: the
   layer only reaches it with .is-on, which js/liquid-ether.js adds and removes
   as the active section changes. The transition duration is mirrored by that
   file's `fadeMs`, which is how it knows when the layer is invisible and the
   simulation can stop — keep the two in step if you change either. */
.liquid-ether {
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.6s var(--ease);
}

.liquid-ether.is-on { opacity: 0.38; }

.liquid-ether canvas { display: block; }

/* ===== Hero ===== */
.hero {
  min-height: 100vh;
  /* svh keeps the hero from overflowing behind mobile browser chrome */
  min-height: 100svh;
  display: flex;
  align-items: center;
  padding-top: 110px;
  padding-bottom: 60px;
  position: relative;
  z-index: 1;
}

.hero-grid {
  position: relative;
  z-index: 1;
  display: grid;
  /* Single column since the ProfileCard moved to #chi-sono. The title carries
     its own line breaks and .hero-body is capped at 480px, so the copy keeps
     its shape without a second track to balance against. */
  grid-template-columns: 1fr;
  gap: 64px;
  align-items: center;
  width: 100%;
}

.lightning-bg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  z-index: 0;
  opacity: 0.45;
  mix-blend-mode: screen;
  pointer-events: none;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 15%, #000 85%, transparent);
  mask-image: linear-gradient(to bottom, transparent, #000 15%, #000 85%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .lightning-bg { display: none; }
}

.tech-label {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--text-50);
  margin-bottom: 28px;
}

.hero-title {
  font-family: var(--font-serif);
  font-weight: 250;
  font-size: 92px;
  line-height: 0.95;
  letter-spacing: -0.03em;
  margin-bottom: 28px;
}
.hero-title em {
  font-style: italic;
  font-weight: 400;
  color: var(--accent);
}

.hero-body {
  font-size: 17px;
  font-weight: 300;
  color: var(--text-50);
  max-width: 480px;
  margin-bottom: 40px;
}

.hero-cta { display: flex; gap: 16px; flex-wrap: wrap; }

/* ===== Spotlight Cards ===== */
.spotlight-card {
  position: relative;
  padding: 40px;
  border-radius: 24px;
  background: var(--glass-bg);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--glass-border);
  /* NIENTE overflow: hidden qui, ed e' una correzione, non una dimenticanza.

     Il sintomo: passando il mouse sulla card — in "Cosa faccio per te" e in
     "I miei lavori" — il bordo superiore si tagliava. Non era un'illusione:
     a riposo il filo di luce bianco corre netto lungo tutto il lato alto,
     in hover spariva, e un bordo che perde la sua luce si legge come un
     bordo tagliato.

     La causa, trovata spegnendo un ingrediente alla volta e fotografando
     l'angolo ingrandito: era proprio overflow:hidden. La card si alza di 6px
     (transform), e il ritaglio non segue la forma dipinta — il filo di luce,
     che e' un box-shadow interno di 1px sul bordo alto, finiva tagliato via.
     Rimesso overflow:visible, l'hover e' identico al riposo, solo sollevato.

     Perche' si puo' togliere senza perdere niente: c'era per contenere la
     vecchia cornice animata (.spotlight-card::after, con inset:-1px, che
     sbordava di 1px). Quella cornice non esiste piu' — css/liquid-glass.css
     ridefinisce lo stesso ::after con inset:0, e non sborda. L'anteprima dei
     siti, l'unico contenuto che avrebbe bisogno di essere ritagliato, ha il
     suo overflow:hidden in css/scroll-expand.css.

     Se un giorno si rimette qualcosa che sborda dentro a queste card,
     ritagliare QUELLO, non la card: la card non puo' ritagliarsi da sola
     senza perdere il proprio bordo quando si alza. */
  transition: transform 0.5s var(--ease), border-color 0.5s var(--ease);
}
/* ===== L'hover, solo dove esiste un puntatore che passa sopra =====
   Su un telefono il browser lascia lo stato :hover attaccato all'ultimo punto
   toccato. Il binario delle card scorre SOTTO quel punto, e ogni card che ci
   passa davanti si comporta come se ci passasse sopra un mouse: si alza di
   6px, la sua anteprima zooma, la scritta in fondo cambia da "Pagina intera"
   a "Clicca per aprire".

   E' il bug della lista: "le card dei siti web nel tornare indietro e' un po'
   buggato perche' ci sono piu' animazioni di scrolling, c'e' animazione
   scrolling per le card, apparizione del pulsante apri dentro la card che
   appare scrollando". Tre cose diverse, una causa sola — e nessuna di esse
   era voluta: erano l'effetto del mouse, applicato dove il mouse non c'e'.

   (hover: hover) e' la domanda giusta e non "e' un telefono?": un tablet con
   trackpad o un portatile touch hanno entrambe le cose e tengono l'effetto,
   un telefono no. */
@media (hover: hover) {
  .spotlight-card:hover { transform: translateY(-6px); border-color: rgba(255,255,255,0.18); }
}

/* shimmer border */
.spotlight-card::after {
  content: '';
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(120deg, transparent 30%, rgba(219, 107, 43, 0.55) 50%, transparent 70%);
  background-size: 200% 200%;
  -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: shimmer 4s linear infinite;
  pointer-events: none;
}
@keyframes shimmer {
  0%   { background-position: 200% 200%; }
  100% { background-position: -200% -200%; }
}

.card-icon {
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: rgba(255,255,255,0.04);
  border: 1px solid var(--glass-border);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--accent);
  margin-bottom: 24px;
  transition: transform 0.5s var(--ease), background 0.5s var(--ease);
  position: relative;
  z-index: 1;
}
.card-icon svg { width: 22px; height: 22px; }
@media (hover: hover) {
  .spotlight-card:hover .card-icon { transform: rotate(12deg) scale(1.05); background: var(--accent-soft); }
}

.spotlight-card h3 {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 24px;
  margin-bottom: 12px;
  position: relative;
  z-index: 1;
}
.spotlight-card p {
  font-size: 14.5px;
  font-weight: 300;
  color: var(--text-40);
  position: relative;
  z-index: 1;
}

/* ===== Section headers ===== */
.section-header { text-align: center; margin-bottom: 64px; }
.section-header.align-left { text-align: left; margin-bottom: 0; }
.section-header h2 {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: 48px;
  letter-spacing: -0.02em;
  line-height: 1.1;
}
.section-header h2 em { color: var(--accent); font-style: italic; }

.features, .projects, .stats, .about, .skills { padding-top: 140px; padding-bottom: 60px; position: relative; z-index: 1; }

.feature-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}

/* ===== Projects ===== */
.projects-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 24px;
}
.project-tag {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.15em;
  color: var(--accent);
  margin-bottom: 20px;
  position: relative;
  z-index: 1;
}
.project-preview {
  height: 120px;
  border-radius: 14px;
  background: linear-gradient(135deg, rgba(219,107,43,0.1), rgba(255,255,255,0.02));
  border: 1px solid var(--hairline);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 24px;
  position: relative;
  z-index: 1;
}
.preview-glyph { font-family: var(--font-serif); font-style: italic; font-size: 40px; color: var(--accent); opacity: 0.7; }
.project-card h3 { font-size: 21px; margin-bottom: 12px; }

/* ===== Titolo e comando di apertura sulla stessa riga =====
   Il markup avvolge l'h3 di ogni card di Progetti in .project-head, insieme
   alla scritta "push" che invita ad aprire la pagina intera.

   Nato come correzione per il solo telefono, esteso a ogni larghezza su
   richiesta di Luca: la ragione per cui li' funzionava meglio — l'invito
   accanto al titolo, dove l'occhio arriva per primo, invece che in fondo
   all'immagine dove si legge come una didascalia — non dipendeva dalla
   dimensione dello schermo.

   Non e' un pulsante e non deve esserlo: js/scroll-expand.js ascolta il click
   sull'INTERA card (_onActivate), quindi premere qui apre come premere
   l'anteprima. Nel markup e' aria-hidden per la stessa ragione: il comando
   vero, con la sua etichetta, e' il bottone dell'anteprima, e annunciarne un
   secondo per la stessa azione sarebbe un doppione. */
.project-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
}
.project-head h3 { margin-bottom: 0; }

/* ===== L'invito ad aprire: una parola nell'angolo, che respira =====
   Ha avuto tre forme, e ognuna ha corretto la precedente.

   Prima: una scritta in fondo all'anteprima. In quel posto si leggeva come la
   didascalia di un'immagine, non come un comando.

   Poi: "push" accanto al titolo. Meglio come posto — l'occhio ci arriva
   leggendo — ma doveva dividere la riga con un titolo lungo, e finiva
   schiacciata a destra di una riga gia' piena. E "push" e' l'imperativo di un
   verbo inglese: dice cosa deve fare il lettore, non cosa succede.

   Poi ancora: "Aprimi" in una pastiglia ambra qui nell'angolo. Il posto e la
   parola erano giusti — l'angolo in alto a destra e' dove si cercano i comandi
   di una scheda, ed e' vuoto perche' la categoria sta a sinistra; e "Aprimi"
   nomina il risultato invece di ordinare un gesto. Ma la pastiglia era troppo:
   un contorno, un fondo e un alone per tre parole di una card che si apre
   comunque toccandola in qualunque punto. Luca: "leviamo il badge e lasciamo
   solo la scritta".

   Ora: la parola sola. Il farsi notare non viene piu' da una cornice ma dal
   RESPIRO — l'intensita' sale e scende, molto piano. E' l'unico modo di
   muoversi che non aggiunge nessuna forma nuova alla card: quel che cambia e'
   solo quanto e' accesa una cosa che c'era gia'.

   Lenta apposta, 3.4s: a questo ritmo si nota guardando la card ferma per un
   momento, e non tira l'occhio mentre si legge il testo qui sotto.

   Fuori dal flusso, non spostata nel markup: la card e' gia' position:
   relative, quindi basta ancorarla. Spostarla anche nell'HTML non avrebbe
   aggiunto niente e avrebbe cambiato l'ordine in cui la legge chi naviga a
   voce — che pero' non la incontra affatto, perche' e' aria-hidden.

   Non e' un pulsante e non deve esserlo: js/scroll-expand.js ascolta il click
   sull'INTERA card (_onActivate), quindi premere qui apre come premere
   l'anteprima. E' aria-hidden per la stessa ragione: il comando vero, con la
   sua etichetta, e' il bottone dell'anteprima, e annunciarne un secondo per la
   stessa azione sarebbe un doppione. */
.project-open {
  position: absolute;
  top: 18px;
  right: 18px;
  z-index: 2;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--accent);
  animation: project-open-respiro 3.4s var(--ease) infinite;
}

/* Non fino a spegnersi: a 0.5 la parola resta leggibile per intero anche nel
   momento piu' basso. Quel che si nota e' il MOVIMENTO, non l'assenza — una
   scritta che sparisce e torna si legge come un difetto, non come un invito. */
@keyframes project-open-respiro {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.5; }
}

/* Chi ha chiesto meno movimento tiene la parola, ferma e a piena forza: quel
   che perde e' il respiro, non il comando. */
@media (prefers-reduced-motion: reduce) {
  .project-open { animation: none; opacity: 1; }
}


/* ===== Le tre pastiglie in fondo alla card: via =====
   Ripetevano in etichette quello che il testo dice meglio, e si prendevano lo
   spazio che serviva al testo per dirlo.

   NASCOSTE, non tolte dal markup, e la differenza conta: la scheda a schermo
   intero le legge da li' per rifarle al proprio interno (js/scroll-expand.js,
   o.tags da '.tag-row .tag'). Cancellarle dall'HTML avrebbe pulito la card e
   svuotato la scheda, che e' il posto dove servono davvero.

   Il selettore prende il FIGLIO DIRETTO della card, e non un .tag-row
   qualsiasi: la scheda espansa costruisce il suo con la stessa classe, ma lo
   appende al <body>. Un selettore piu' largo l'avrebbe spenta anche li'. */
.project-card > .tag-row { display: none; }
.tag-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 20px; position: relative; z-index: 1; }
.tag {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: 999px;
  border: 1px solid var(--glass-border);
  color: var(--text-50);
}

/* ===== Risultati =====
   The benchmark table that used to live here is gone: the section is now the
   ButtonCarousel, whose styles live in css/button-carousel.css alongside the
   component that draws it. */

/* ===== About ===== */
.about-grid {
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 64px;
}
/* Left column: the heading with the ProfileCard under it (see
   css/profile-card.css). align-items keeps the card at its intrinsic width
   instead of stretching the wrapper the glow is drawn into. */
.about-side {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 40px;
}
.about-content p { color: var(--text-50); font-weight: 300; margin-bottom: 20px; font-size: 15.5px; }
.about-lead { font-family: var(--font-serif); font-style: italic; font-size: 22px; color: var(--text) !important; margin-bottom: 24px !important; }

.about-facts {
  display: grid;
  gap: 18px;
  margin-top: 36px;
  padding-top: 32px;
  border-top: 1px solid var(--hairline);
}
.fact { display: flex; justify-content: space-between; align-items: baseline; gap: 16px; flex-wrap: wrap; }
.fact-label { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em; color: var(--text-30); }
.fact-value { font-family: var(--font-serif); font-style: italic; color: var(--accent); font-size: 16px; text-align: right; }

/* ===== Final CTA ===== */
.final-cta {
  text-align: center;
  padding: 160px 24px 180px;
  position: relative;
  z-index: 1;
}
.final-cta .eyebrow { margin-bottom: 20px; }
.gradient-text {
  font-family: var(--font-serif);
  font-weight: 300;
  font-size: 58px;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin-bottom: 24px;
  background: linear-gradient(90deg, #EBEBEB 0%, #db6b2b 25%, #EBEBEB 50%, #db6b2b 75%, #EBEBEB 100%);
  background-size: 300% auto;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: gradient-shift 6s linear infinite;
}
@keyframes gradient-shift {
  0% { background-position: 0% 50%; }
  100% { background-position: 300% 50%; }
}
.final-cta p { color: var(--text-40); font-weight: 300; margin-bottom: 40px; font-size: 16px; }

/* ===== Footer ===== */
.footer {
  border-top: 1px solid var(--hairline);
  padding: 40px 24px;
  position: relative;
  z-index: 1;
}
.footer-inner {
  max-width: 1280px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  flex-wrap: wrap;
}
.footer-contacts { display: flex; gap: 28px; flex-wrap: wrap; }
.footer-contacts a { font-size: 13.5px; color: var(--text-50); position: relative; padding-bottom: 3px; transition: color 0.3s var(--ease); }
.footer-contacts a::after {
  content: ''; position: absolute; left: 0; bottom: 0; height: 1px; width: 0;
  background: var(--accent); transition: width 0.4s var(--ease);
}
.footer-contacts a:hover { color: var(--text); }
.footer-contacts a:hover::after { width: 100%; }
.footer-copy { font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.1em; color: var(--text-30); text-transform: uppercase; }

/* ===== Responsive ===== */
@media (max-width: 980px) {
  .hero-title { font-size: 64px; }
  .nav-links { display: none; }
  .cta-button { display: none; }
  .nav-toggle { display: flex; }
  .feature-grid { grid-template-columns: repeat(2, 1fr); }
  .projects-grid { grid-template-columns: repeat(2, 1fr); }
  .about-grid { grid-template-columns: 1fr; }
  .section-header.align-left { margin-bottom: 40px; }
  .gradient-text { font-size: 40px; }

  .nav-links.open {
    display: flex;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    gap: 0;
    background: rgba(0,0,0,0.92);
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    border-bottom: 1px solid var(--glass-border);
  }
  .nav-links.open a { padding: 18px 24px; border-bottom: 1px solid var(--hairline); }
}

@media (max-width: 640px) {
  .hero-title { font-size: 46px; }
  .hero-body { font-size: 15.5px; }
  .feature-grid, .projects-grid { grid-template-columns: 1fr; }
  .section-header h2 { font-size: 32px; }
  .footer-inner { flex-direction: column; text-align: center; }
  .gradient-text { font-size: 30px; }
  .final-cta { padding: 100px 24px 120px; }
}
