/* Kodera Studio — bundled stylesheet.
   All sources concatenated in dependency order (was 6 separate files
   imported via @import). Single HTTP request, no @import waterfall. */

/* ============ Self-hosted Geist + Geist Mono ============
   Downloaded from fonts.gstatic.com — latin + latin-ext subsets only
   (covers Croatian diacritics č ć š ž đ via latin-ext U+0100-02BA).
   Geist is a variable font, so one file covers weights 400-700. */
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../assets/fonts/geist-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../assets/fonts/geist-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("../assets/fonts/geist-mono-latin.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Geist Mono';
  font-style: normal;
  font-weight: 400 500;
  font-display: swap;
  src: url("../assets/fonts/geist-mono-latin-ext.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* ============ tokens.css ============ */
/* ───────────────────────────────────────────────────────────
   Design tokens — single source of truth for the entire site.
   Theme: deep void black + ice-blue electric accent.
   ─────────────────────────────────────────────────────────── */

:root {
  /* Surfaces — pulled darker so the WebGL stage reads as a true void */
  --bg:           #04060B;
  --bg-elev:      #0B0F1A;
  --bg-card:      #10172A;
  --bg-overlay:   rgba(4, 6, 11, 0.78);

  /* Text */
  --text:         #E8EAF6;
  --text-mute:    #8A8FAB;
  --text-dim:     #4F5475;

  /* Brand — ice-blue energy palette */
  --accent:       #7FD6FF;
  --accent-soft:  rgba(127, 214, 255, 0.16);
  --accent-glow:  rgba(127, 214, 255, 0.55);
  --accent-2:     #DFF3FF;

  /* Lines & dividers */
  --border:       rgba(255, 255, 255, 0.08);
  --border-strong:rgba(255, 255, 255, 0.16);

  /* Status */
  --danger:       #FF6188;
  --warn:         #FFC857;

  /* Type scale — every size is fluid (clamp(min, base + vw, max)) so the
     whole site reads proportionally across phone → ultrawide. */
  --fs-xs:    clamp(0.7rem,  0.66rem + 0.15vw, 0.8rem);
  --fs-sm:    clamp(0.82rem, 0.77rem + 0.2vw,  0.95rem);
  --fs-base:  clamp(0.92rem, 0.86rem + 0.25vw, 1.08rem);
  --fs-md:    clamp(1rem,    0.94rem + 0.3vw,  1.2rem);
  --fs-lg:    clamp(1.2rem,  1.05rem + 0.6vw,  1.55rem);
  --fs-xl:    clamp(1.6rem,  1.3rem + 1.2vw,   2.35rem);
  --fs-2xl:   clamp(2rem,    1.45rem + 2.5vw,  3.6rem);
  --fs-3xl:   clamp(2.6rem,  1.8rem + 4vw,     5.6rem);
  --fs-hero:  clamp(2.8rem,  1.8rem + 6vw,     8rem);

  /* Spacing — small values stay touch-friendly; larger rhythm scales with
     viewport so the page density feels right at any width. */
  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: clamp(0.55rem, 0.45rem + 0.35vw, 0.85rem);
  --space-4: clamp(0.75rem, 0.6rem + 0.5vw,   1.15rem);
  --space-5: clamp(1rem,    0.8rem + 0.8vw,   1.65rem);
  --space-6: clamp(1.3rem,  1rem + 1.2vw,     2.25rem);
  --space-7: clamp(1.8rem,  1.3rem + 1.8vw,   3.4rem);
  --space-8: clamp(2.4rem,  1.8rem + 2.4vw,   4.5rem);
  --space-9: clamp(3.4rem,  2.4rem + 4vw,     6.4rem);
  --space-10:clamp(4.5rem,  3.2rem + 5.4vw,   8.6rem);
  --space-11:clamp(6.5rem,  4.6rem + 7.6vw,  13rem);

  /* Radii */
  --r-sm: 6px;
  --r-md: 12px;
  --r-lg: 20px;
  --r-xl: 28px;
  --r-pill: 999px;

  /* Layout — container is fluid (scales with viewport, capped on both ends). */
  --container:    clamp(1040px, 86vw, 1480px);
  --gutter:       clamp(1.25rem, 1rem + 1.5vw, 2.5rem);
  --nav-h:        clamp(96px, 70px + 5vw, 140px);

  /* Motion */
  --ease-out:     cubic-bezier(0.22, 1, 0.36, 1);
  --ease-in-out:  cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:  cubic-bezier(0.34, 1.56, 0.64, 1);
  --t-fast:       150ms;
  --t-med:        320ms;
  --t-slow:       640ms;

  /* Type families */
  --font-sans: "Geist", "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  --font-mono: "Geist Mono", "JetBrains Mono", ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}

@media (prefers-reduced-motion: reduce) {
  :root {
    --t-fast: 0ms;
    --t-med:  0ms;
    --t-slow: 0ms;
  }
}

/* ============ reset.css ============ */
/* Modern reset — distilled from Andy Bell + Josh Comeau */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html, body { height: 100%; }
html {
  -webkit-text-size-adjust: 100%;
  -webkit-tap-highlight-color: transparent;
  scroll-behavior: smooth;
}
body {
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}
img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
  height: auto;
}
input, button, textarea, select { font: inherit; color: inherit; }
button { background: none; border: none; cursor: pointer; }
p, h1, h2, h3, h4, h5, h6 { overflow-wrap: break-word; }
ul, ol { list-style: none; }
a { color: inherit; text-decoration: none; }
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 2px;
}
::selection {
  background: var(--accent);
  color: var(--bg);
}

/* ============ base.css ============ */
/* Body, typography, ambient background, scroll behaviour */

html {
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-sans);
  font-size: 16px;
  font-feature-settings: "ss01", "cv11";
  /* Belt-and-braces: body already clips horizontally, but some mobile
     browsers still expose a horizontal scrollbar if a transient child
     (scrub-driven slide-ins, sticky stages) briefly overflows.  */
  overflow-x: hidden;
}

body {
  position: relative;
  min-height: 100dvh;
  overflow-x: hidden;
  background: var(--bg);
}

/* ── Layer 1: scroll-driven colour blobs ─────────────────────────
   Each radial gradient's anchor point + intensity is interpolated against
   --scroll-p (0..1, written by centerpiece.js every frame). The whole
   palette also dims slightly toward the bottom of the page so the
   contact section reads as quieter / "landing pad". */
:root {
  --scroll-p: 0;
  --assemble-p: 0;
  --bg-fade: calc(1 - var(--scroll-p) * 0.35); /* 1 → 0.65 */
}

body::before {
  content: "";
  position: fixed;
  inset: -10%;
  pointer-events: none;
  z-index: 0;
  /* Deep ice-blue void: a vertical "stage" wash + a top light shaft that
     reinforces the WebGL light shaft, so the layered look reads as one. */
  background:
    /* Top centre — soft ice-blue shaft falling from above */
    radial-gradient(ellipse 35% 60% at
      calc(50% + var(--scroll-p) * 4%) -5%,
      rgba(127, 214, 255, calc(0.22 * var(--bg-fade))),
      transparent 70%),
    /* Left edge cool wash */
    radial-gradient(ellipse 38% 50% at
      calc(8% + var(--scroll-p) * 10%)
      calc(35% + var(--scroll-p) * 15%),
      rgba(58, 159, 216, calc(0.16 * var(--bg-fade))),
      transparent 70%),
    /* Right edge cool wash */
    radial-gradient(ellipse 38% 50% at
      calc(92% - var(--scroll-p) * 10%)
      calc(55% + var(--scroll-p) * 10%),
      rgba(40, 110, 165, calc(0.14 * var(--bg-fade))),
      transparent 70%),
    /* Bottom centre — faint floor glow that intensifies as scroll completes */
    radial-gradient(ellipse 50% 30% at 50% 105%,
      rgba(127, 214, 255, calc(0.18 * var(--scroll-p) + 0.04)),
      transparent 70%);
  filter: blur(22px);
  transition: filter 400ms var(--ease-out);
  will-change: background;
}

/* Tab is unfocused / no JS → fall back to a slow autonomous drift so the
   page never looks frozen if --scroll-p never updates. */
@media (prefers-reduced-motion: no-preference) {
  body::before {
    animation: bg-drift 28s ease-in-out infinite alternate;
  }
}
@keyframes bg-drift {
  0%   { transform: translate3d(0,    0,   0) scale(1);    }
  100% { transform: translate3d(-1.5%, 1.5%, 0) scale(1.03); }
}

/* ── Layer 2: faint techy grid + grain overlay ─────────────────── */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1;
  background-image:
    linear-gradient(rgba(255,255,255,0.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.025) 1px, transparent 1px),
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 0.4 0'/></filter><rect width='100%' height='100%' filter='url(%23n)'/></svg>");
  background-size: 48px 48px, 48px 48px, 220px 220px;
  mix-blend-mode: overlay;
  opacity: 0.6;
}

/* ── Layer 3: ambient stage — orbiting blobs + scroll-rotating conic.
   Sits at z-index 0 alongside body::before. All purely decorative. */
.bg-stage {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: hidden;
  isolation: isolate;
}

/* Conic ring that sweeps with scroll — restrained ice-blue energy
   sweep behind the K. 540° per full scroll. */
.bg-conic {
  position: absolute;
  inset: -25%;
  background: conic-gradient(
    from 0deg at 50% 50%,
    transparent 0deg,
    rgba(127, 214, 255, 0.14) 40deg,
    transparent 110deg,
    rgba(223, 243, 255, 0.10) 170deg,
    transparent 230deg,
    rgba(58, 159, 216, 0.12) 280deg,
    transparent 340deg
  );
  filter: blur(70px);
  transform:
    rotate(calc(var(--scroll-p, 0) * 540deg))
    scale(calc(0.85 + var(--scroll-p, 0) * 0.5));
  transition: transform 320ms var(--ease-out);
  mix-blend-mode: screen;
  opacity: 0.7;
}

/* Three big colour orbs that orbit independently. blur + screen blend
   gives them a soft "northern lights" feel without overpowering text. */
.bg-orb {
  position: absolute;
  width: clamp(420px, 55vw, 780px);
  aspect-ratio: 1;
  border-radius: 50%;
  filter: blur(90px);
  mix-blend-mode: screen;
  opacity: 0.55;
  will-change: transform;
}
/* Orbs retinted to the ice-blue spectrum — deep navy / cool blue /
   pale ice — and their overall opacity halved so they don't fight with
   the WebGL plexus in the foreground. */
.bg-orb--1 {
  top: -10%; left: -5%;
  background: radial-gradient(circle, #1c4a78, transparent 65%);
  animation: orb-1 28s var(--ease-in-out) infinite alternate;
  opacity: 0.42;
}
.bg-orb--2 {
  top: 25%; right: -10%;
  background: radial-gradient(circle, #7FD6FF, transparent 65%);
  animation: orb-2 36s var(--ease-in-out) infinite alternate;
  opacity: 0.30;
}
.bg-orb--3 {
  bottom: -15%; left: 30%;
  background: radial-gradient(circle, #2a78b8, transparent 65%);
  animation: orb-3 32s var(--ease-in-out) infinite alternate;
  opacity: 0.32;
}

@keyframes orb-1 {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  35%  { transform: translate3d(38vw, 18vh, 0) scale(1.25); }
  70%  { transform: translate3d(58vw, 52vh, 0) scale(0.85); }
  100% { transform: translate3d(20vw, 64vh, 0) scale(1.10); }
}
@keyframes orb-2 {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  30%  { transform: translate3d(-44vw, -18vh, 0) scale(1.2); }
  60%  { transform: translate3d(-28vw, 30vh, 0) scale(0.9); }
  100% { transform: translate3d(-58vw, 50vh, 0) scale(1.35); }
}
@keyframes orb-3 {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  40%  { transform: translate3d(28vw, -42vh, 0) scale(1.15); }
  75%  { transform: translate3d(-34vw, -28vh, 0) scale(0.75); }
  100% { transform: translate3d(-12vw, -55vh, 0) scale(1.25); }
}

@media (prefers-reduced-motion: reduce) {
  .bg-orb { animation: none; }
  .bg-conic { transform: none; transition: none; }
}

@media (prefers-reduced-motion: reduce) {
  body::before { animation: none; }
}

h1, h2, h3, h4 {
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.02em;
}
h1 { font-size: var(--fs-hero); letter-spacing: -0.035em; }
h2 { font-size: var(--fs-3xl); letter-spacing: -0.025em; }
h3 { font-size: var(--fs-xl); }
h4 { font-size: var(--fs-lg); }

p { color: var(--text-mute); font-size: var(--fs-md); line-height: 1.55; }

.mono { font-family: var(--font-mono); letter-spacing: 0.02em; }
.upper { text-transform: uppercase; letter-spacing: 0.18em; font-size: var(--fs-xs); }

/* Lenis smooth-scroll requirements */
html.lenis, html.lenis body { height: auto; }
.lenis.lenis-smooth { scroll-behavior: auto !important; }
.lenis.lenis-smooth [data-lenis-prevent] { overscroll-behavior: contain; }
.lenis.lenis-stopped { overflow: hidden; }
.lenis.lenis-smooth iframe { pointer-events: none; }

/* ── Performance: skip rendering of off-screen sections ─────────────
   `content-visibility: auto` tells the browser it may skip rendering
   (layout, paint, hit-testing) of these elements while they are far
   from the viewport. Massive scroll-perf win on a long single-page
   site. `contain-intrinsic-size` reserves a placeholder height so the
   scrollbar doesn't jump when sections snap into render.

   #services and #rezultati are excluded — they're animated with
   xPercent: ±100 by GSAP/ScrollTrigger on desktop, and CV interferes
   with the off-viewport state those animations require. */
#work, #process, #contact {
  content-visibility: auto;
  contain-intrinsic-size: 0 800px;
}

/* `contain: layout paint` isolates these heavy elements so a paint
   in one doesn't force a re-layout of the whole page. Cheap perf win
   for elements with backdrop-filter / box-shadow. */
.panel,
.feature-preview,
.results__card,
.project {
  contain: layout paint;
}

/* GPU-promote the hero canvas wrap (Three.js renders into it every
   frame) so its repaints are isolated from the document. */
.hero__canvas-wrap {
  will-change: transform, opacity;
  transform: translateZ(0);
}

/* ============ layout.css ============ */
/* Container, grid, nav, footer, sections */

.container {
  width: min(100% - var(--gutter) * 2, var(--container));
  margin-inline: auto;
}

section {
  position: relative;
  padding-block: var(--space-11);
  z-index: 2;
  /* When anchor links target a section, the section padding alone
     would push the content far below the nav. Set scroll-margin-top
     so the section's *content* lands cleanly below the nav. */
  scroll-margin-top: var(--nav-h);
}

@media (max-width: 720px) {
  section { padding-block: var(--space-9); }
}

/* ── Section heading kit ─────────────────────────── */
.section-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-mute);
  background: rgba(255, 255, 255, 0.02);
  backdrop-filter: blur(8px);
}
.section-eyebrow::before {
  content: "";
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent-glow);
}

/* Big chrome-gradient section heading — same treatment as the
   "Mali studio. Veliki standardi." line in the hero. Section eyebrow
   above stays as a small mono pill (.section-eyebrow rule). Any <em>
   inside the title picks up the ice-blue accent gradient so a single
   phrase can carry the brand colour. */
.section-title {
  margin-top: var(--space-5);
  max-width: 24ch;
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(2.4rem, 1.6rem + 3.6vw, 4.8rem);
  line-height: 0.98;
  letter-spacing: -0.015em;
  background: linear-gradient(180deg, #ffffff 0%, #c7cbda 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  margin-block-end: 0;
}
.section-title em {
  font-style: italic;
  background: linear-gradient(180deg, #b8e2ff 0%, #7fd6ff 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}

.section-lead {
  margin-top: var(--space-5);
  max-width: 56ch;
  font-size: var(--fs-md);
  color: var(--text-mute);
}

/* ── Navigation ─────────────────────────── */
/* Two-state nav:
   • At top of page → full-width opaque bar with bottom border (so hero
     content can't visually bleed into it).
   • Past the scroll threshold (.is-scrolled, toggled in nav.js) → the
     bar dissolves and the inner row morphs into a centered floating
     pill that's both shorter and narrower. Brand logo shrinks too.
   All shape/colour changes animate together for a single fluid morph. */
.nav {
  position: fixed;
  top: 0; left: 0; right: 0;
  z-index: 100;
  height: var(--nav-h);
  display: flex;
  align-items: flex-start;
  padding-top: 0;
  background: var(--bg-overlay);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  backdrop-filter: blur(14px) saturate(140%);
  border-bottom: 1px solid var(--border);
  transition: background var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out),
              height var(--t-med) var(--ease-out),
              padding-top var(--t-med) var(--ease-out);
}
.nav__inner {
  width: min(100% - var(--gutter) * 2, var(--container));
  margin-inline: auto;
  /* Fill the full nav height (default state). Items inside are still
     vertically centred via align-items:center, so the logo doesn't move.
     This ensures the drawer (which attaches at top: 100% of .nav__inner)
     sits at the bar's true bottom edge instead of mid-bar. */
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-5);
  /* Anchor for the absolutely-positioned mobile drawer, which sticks
     to the bottom of this element via top: 100% so it follows the bar
     in both default-bar and pill states. */
  position: relative;
  /* Transparent shell by default — the parent .nav supplies the
     surface. The pill state below turns this element into the surface. */
  background: transparent;
  border: 1px solid transparent;
  border-radius: 0;
  transition: width var(--t-med) var(--ease-out),
              height var(--t-med) var(--ease-out),
              padding var(--t-med) var(--ease-out),
              background var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out),
              border-radius var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out);
}

/* Scrolled state — shrink the bar, float a centred pill inside it. */
.nav.is-scrolled {
  height: 96px;
  padding-top: 12px;
  background: transparent;
  backdrop-filter: none;
  border-bottom-color: transparent;
}
.nav.is-scrolled .nav__inner {
  align-self: flex-start;
  width: min(100% - var(--gutter) * 2, 880px);
  height: 72px;
  padding: 6px 20px;
  background: var(--bg-overlay);
  -webkit-backdrop-filter: blur(16px) saturate(150%);
  backdrop-filter: blur(16px) saturate(150%);
  border-color: var(--border);
  border-radius: 999px;
  box-shadow:
    0 10px 30px rgba(0, 0, 0, 0.32),
    0 0 0 1px rgba(127, 214, 255, 0.06) inset;
}
.nav__brand {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  color: var(--text);
  text-decoration: none;
  transition: opacity var(--t-fast) var(--ease-out);
}
.nav__brand:hover { opacity: 0.7; }
.nav__brand img {
  height: 112px;
  width: auto;
  display: block;
  user-select: none;
  -webkit-user-drag: none;
  /* Flex children shrink by default — without this the brand image
     gets compressed when the pill narrows, distorting the wordmark. */
  flex-shrink: 0;
  transition: height var(--t-med) var(--ease-out);
}
.nav__brand { flex-shrink: 0; }
@media (max-width: 720px) {
  .nav__brand img { height: 72px; }
}
/* Logo shrinks to fit the pill on scroll. Pill is 72px tall with
   6px vertical padding → 60px internal; logo sits centred within. */
.nav.is-scrolled .nav__brand img { height: 60px; }

/* ── Intermediate-width navbar ─────────────────────────────────────
   Between the hamburger breakpoint (≤960px) and full-size desktop
   (>=1280px), shrink the logo, tighten link gaps, and reduce link
   font-size so the full row of nav items + lang toggle + CTA fits on
   one line without wrapping below the logo. */
@media (min-width: 961px) and (max-width: 1279px) {
  .nav__brand img { height: 80px; }
  .nav.is-scrolled .nav__brand img { height: 52px; }
  .nav__links { gap: var(--space-4); }
  .nav__link { font-size: 0.82rem; }
  .nav__inner { gap: var(--space-3); }
  .nav__cta { gap: var(--space-2); }
}
@media (min-width: 961px) and (max-width: 1099px) {
  .nav__brand img { height: 68px; }
  .nav.is-scrolled .nav__brand img { height: 48px; }
  .nav__links { gap: var(--space-3); }
  .nav__link { font-size: 0.78rem; }
}
.nav__links {
  display: flex;
  align-items: center;
  gap: var(--space-6);
}
.nav__link {
  font-size: var(--fs-sm);
  color: var(--text-mute);
  transition: color var(--t-fast) var(--ease-out);
  position: relative;
}
.nav__link:hover { color: var(--text); }
.nav__link::after {
  content: "";
  position: absolute;
  left: 0; bottom: -6px;
  width: 100%; height: 1px;
  background: var(--accent);
  transform: scaleX(0);
  transform-origin: left;
  transition: transform var(--t-med) var(--ease-out);
}
.nav__link:hover::after { transform: scaleX(1); }

.nav__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

/* ── Hamburger button (mobile-only) ─────────────────────────── */
.nav__hamburger {
  display: none;
  appearance: none;
  background: transparent;
  border: 1px solid var(--border);
  border-radius: 10px;
  width: 44px;
  height: 44px;
  padding: 0;
  cursor: pointer;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  /* Sit above adjacent siblings inside .nav__cta so the desktop CTA's
     hover/focus styles can never end up overlapping the hit-target. */
  position: relative;
  z-index: 2;
  touch-action: manipulation;
  transition: border-color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
}
.nav__hamburger:hover { border-color: var(--accent); }
.nav__hamburger-line {
  display: block;
  width: 20px;
  height: 2px;
  background: var(--text);
  border-radius: 2px;
  /* Opacity snaps quickly (90ms) so the middle bar is gone long before
     the outer bars finish rotating into the X — earlier it lingered
     through ≈half the animation and looked late. */
  transition: transform var(--t-med) var(--ease-out),
              opacity 90ms linear;
  transform-origin: center;
}

/* Desktop: hide the emoji glyph (the label + arrow show instead).
   !important so a cached older rule can never override it. */
.nav__cta-glyph { display: none !important; }

/* Breakpoint bumped from 720px → 960px so any phone (incl. larger
   Android handsets and landscape orientation) gets the hamburger,
   not the desktop link row. Matches the hero/contact mobile cutoff. */
@media (max-width: 960px) {
  .nav__hamburger { display: inline-flex; }

  /* Mobile CTA — collapse to a 44×44 round-cornered icon button so it
     sits next to the hamburger without "Razgovarajmo" overlapping it. */
  .nav__cta-btn {
    padding: 0;
    width: 44px;
    height: 44px;
    min-width: 0;
    border-radius: 12px;
    justify-content: center;
    flex-shrink: 0;
  }
  .nav__cta-label { display: none; }
  .nav__cta-btn .btn__icon--arrow { display: none; }
  /* Phone glyph — a Unicode emoji (U+1F4DE 📞) in a plain <span>.
     Emojis are guaranteed to render on iOS and Android, no SVG quirks.
     !important needed because the desktop hide rule above also uses it. */
  .nav__cta-glyph {
    display: inline-block !important;
    font-size: 22px;
    line-height: 1;
  }

  /* Nav drawer — absolutely-positioned underneath .nav__inner so it
     attaches directly to the bottom edge in BOTH default-bar and pill
     states (previous fixed-position version sat at top: var(--nav-h)
     and left a gap below the scrolled pill). */
  .nav__links {
    display: flex;
    position: absolute;
    top: 100%;  /* flush with the bar/pill bottom — no overlap */
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    padding: var(--space-4) var(--space-5) var(--space-5);
    /* Flat solid background — no opacity, no blur. */
    background: #04060B;
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
    border: 1px solid var(--border);
    border-top: none;
    border-radius: 0 0 22px 22px;
    box-shadow: 0 18px 36px rgba(0, 0, 0, 0.55);
    transform: translateY(-8px);
    opacity: 0;
    pointer-events: none;
    transition: transform 280ms var(--ease-out),
                opacity 200ms var(--ease-out);
  }
  .nav.is-open .nav__links {
    transform: translateY(0);
    opacity: 1;
    pointer-events: auto;
  }
  /* When the drawer is open, square the bottom of the bar/pill so the
     drawer reads as a continuation of it rather than a floating panel. */
  .nav.is-open .nav__inner {
    border-bottom-left-radius: 0;
    border-bottom-right-radius: 0;
  }
  /* Hide the .nav's own bottom border when open — the drawer carries
     the visual edge instead. Prevents a faint line across the seam. */
  .nav.is-open { border-bottom-color: transparent; }

  .nav__links .nav__link {
    font-size: var(--fs-md);
    padding: var(--space-3) 0;
    border-bottom: 1px solid var(--border);
  }
  .nav__links .nav__link:last-child { border-bottom: 0; }
  .nav__link::after { display: none; }

  /* Animate the three bars into an X when open. Middle bar uses
     `transform: scale(0)` in addition to opacity so the visual collapse
     reads as instant even on low-end browsers that smooth the opacity. */
  .nav.is-open .nav__hamburger-line:nth-child(1) {
    transform: translateY(7px) rotate(45deg);
  }
  .nav.is-open .nav__hamburger-line:nth-child(2) {
    opacity: 0;
    transform: scaleX(0);
  }
  .nav.is-open .nav__hamburger-line:nth-child(3) {
    transform: translateY(-7px) rotate(-45deg);
  }
}

/* ── Footer ─────────────────────────── */
.footer {
  padding-block: var(--space-9) var(--space-7);
  border-top: 1px solid var(--border);
  position: relative;
  z-index: 2;
}
.footer__inner {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  gap: var(--space-7);
  align-items: start;
}
@media (max-width: 720px) {
  .footer__inner { grid-template-columns: 1fr; gap: var(--space-6); }
}
.footer h4 {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--space-4);
  font-weight: 500;
}
.footer ul { display: grid; gap: var(--space-3); }
.footer a {
  color: var(--text-mute);
  font-size: var(--fs-sm);
  transition: color var(--t-fast) var(--ease-out);
}
.footer a:hover { color: var(--text); }

/* Footer navigation column — render the five page-section links as a
   compact two-column list so the column reads at a glance and balances
   the brand block on the left + the lone social icon on the right. */
.footer__nav {
  grid-template-columns: repeat(2, minmax(0, auto));
  column-gap: var(--space-6);
  row-gap: var(--space-3);
}
@media (max-width: 720px) {
  .footer__nav { grid-template-columns: 1fr; }
}

/* Social column — single round-bordered icon button. Mirrors the
   hamburger/CTA chrome elsewhere so the footer reads cohesively. */
.footer__socials {
  display: flex;
  gap: var(--space-3);
}
.footer__social {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--border);
  border-radius: 12px;
  color: var(--text-mute);
  transition: color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.footer__social svg { width: 20px; height: 20px; display: block; }
.footer__social:hover {
  color: var(--accent);
  border-color: var(--accent);
  transform: translateY(-1px);
}
.footer__legal {
  margin-top: var(--space-7);
  padding-top: var(--space-5);
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
}
@media (max-width: 720px) {
  .footer__legal { flex-direction: column; }
}

/* ============ components.css ============ */
/* Buttons, cards, badges, hero-specific */

/* ── Glass panel ─────────────────────────────────────────────────
   Frosted glass surface that anchors text against the moving 3D scene.
   Use sparingly: hero copy block, about lead, contact CTA. The blur
   does the heavy lifting — it separates "panel" from "ambient" without
   killing the cinematic feel. */
.panel {
  position: relative;
  background:
    linear-gradient(180deg,
      rgba(15, 17, 28, 0.62),
      rgba(11, 13, 22, 0.50)
    );
  -webkit-backdrop-filter: blur(18px) saturate(140%);
          backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: var(--r-lg);
  padding: clamp(1.4rem, 1rem + 1.6vw, 2.4rem);
  box-shadow:
    0 1px 0 rgba(255, 255, 255, 0.04) inset,
    0 24px 60px -32px rgba(0, 0, 0, 0.6);
  isolation: isolate;
  /* Subtle scroll-driven parallax — drifts up a few pixels as you scroll
     so the panel feels anchored to the scene, not pasted on. */
  transform: translate3d(0, calc(var(--scroll-p, 0) * -12px), 0);
  transition: transform 200ms linear;
}

/* Soft accent edge — a thin gradient on the top edge that picks up
   the brand violet, ties panels to the K's chrome reflection. */
.panel::before {
  content: "";
  position: absolute;
  top: 0; left: 8%;
  width: 35%; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(123, 97, 255, 0.6), transparent);
  pointer-events: none;
}

/* Browsers without backdrop-filter: bump the background opacity so text
   remains readable. (Looks "panel-ier", less "glass-ier".) */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .panel {
    background: linear-gradient(180deg, rgba(11, 13, 22, 0.92), rgba(8, 9, 16, 0.88));
  }
}


/* ── Buttons ─────────────────────────── */
.btn {
  --btn-bg: var(--accent);
  --btn-fg: var(--bg);
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: 0.85rem 1.4rem;
  background: var(--btn-bg);
  color: var(--btn-fg);
  border-radius: var(--r-pill);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: 0.01em;
  position: relative;
  isolation: isolate;
  overflow: hidden;
  transition: transform var(--t-med) var(--ease-spring),
              box-shadow var(--t-med) var(--ease-out);
  box-shadow: 0 0 0 0 var(--accent-glow);
  will-change: transform;
}
.btn:hover {
  box-shadow: 0 8px 32px -8px var(--accent-glow);
}
.btn:active { transform: scale(0.98); }
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(120deg,
    transparent 30%, rgba(255,255,255,0.35) 50%, transparent 70%);
  transform: translateX(-110%);
  transition: transform 700ms var(--ease-out);
  z-index: -1;
}
.btn:hover::before { transform: translateX(110%); }

.btn--ghost {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  border: 1px solid var(--border-strong);
}
.btn--ghost:hover {
  border-color: var(--accent);
  background: var(--accent-soft);
}

.btn__icon {
  width: 14px; height: 14px;
  transition: transform var(--t-med) var(--ease-spring);
}
.btn:hover .btn__icon { transform: translate(2px, -2px); }

/* ── Language toggle ─────────────────────────── */
.lang-toggle {
  display: inline-flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  padding: 3px;
  background: rgba(255, 255, 255, 0.02);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.1em;
}
.lang-toggle__btn {
  padding: 6px 12px;
  border-radius: var(--r-pill);
  color: var(--text-mute);
  transition: color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
  text-transform: uppercase;
}
.lang-toggle__btn[aria-current="true"] {
  background: var(--text);
  color: var(--bg);
}

/* ── Hero ─────────────────────────── */
.hero {
  position: relative;
  min-height: 100dvh;
  display: grid;
  align-items: center;
  /* Top padding always reserves the nav bar so hero content can't slip
     underneath. Bottom padding is vh-aware so we don't waste 240px on
     a 1080p viewport. */
  padding-block:
    calc(var(--nav-h) + clamp(0.5rem, 1.5vh, 1.25rem))
    clamp(1.75rem, 5vh, 4rem);
  z-index: 2;
  overflow: hidden;
}
.hero__inner {
  position: relative;
  z-index: 3;
  display: grid;
  gap: var(--space-6);
}

/* ── Horizontal slide-in sections ──────────────────────────────────
   #services slides in from the LEFT (xPercent: -100 → 0) and
   #rezultati slides in from the RIGHT (xPercent: 100 → 0) as they
   enter view. Both keep transparent backgrounds so the GLB centerpiece
   behind stays visible during the K's scroll assembly. `min-height:
   100vh` keeps each on screen long enough to read. */
#services,
#rezultati {
  min-height: 100vh;
  will-change: transform;
}

/* ── Hero slider ────────────────────────────────────────────────────
   The hero is now a two-slide horizontal carousel:
     slide 0 → Results / Solucije / Technologies / Slogan
     slide 1 → original "Stvaramo brze ..." brand statement
   .hero__track is twice the viewport wide and translateXes between
   the slides; nav arrows + dots drive the current index. */
.hero--slider { overflow: hidden; }

.hero__track {
  display: flex;
  width: 200%;
  transition: transform 800ms cubic-bezier(0.65, 0, 0.05, 1);
  will-change: transform;
}
.hero__track[data-current="0"] { transform: translateX(0%); }
.hero__track[data-current="1"] { transform: translateX(-50%); }

.hero__slide {
  flex: 0 0 50%;
  min-width: 50%;
  /* Subtract the hero's reserved top/bottom padding (nav-h up top,
     ~4rem bottom) so each slide fits inside the viewport without
     forcing a scroll. */
  min-height: calc(100dvh - var(--nav-h) - 6rem);
  display: grid;
  align-items: center;
}

/* ── Intermediate-width tweaks for hero slide 2 ────────────────────
   Between full desktop and mobile, the .feature-title's vw-driven
   font size grows faster than the panel can hold. Cap it so the
   title can't overflow under the navbar at narrow desktops. */
@media (max-width: 1280px) {
  .feature-title { font-size: clamp(2rem, 1rem + 3vw, 4rem); }
}
@media (max-width: 1024px) {
  .feature-title { font-size: clamp(1.8rem, 0.9rem + 2.8vw, 3.4rem); }
  .feature-desc  { font-size: var(--fs-sm); }
}

/* Mobile + small-screen tweaks for hero slide 2 (the project spotlight).
   At narrow widths the feature-copy + feature-preview stack vertically;
   without explicit clearance the stack centres into the navbar at the
   top and the hero__nav pill at the bottom. Reserve those regions and
   cap the preview's height so the whole composition fits the viewport. */
@media (max-width: 960px) {
  .hero {
    /* Bottom: room for the hero__nav pill (≈56px tall + space-7 gap). */
    padding-block-end: calc(var(--space-7) + 72px);
  }
  .hero__slide { min-height: calc(100dvh - var(--nav-h) - 8rem); }

  .hero__inner--feature { gap: var(--space-5); }
  .feature-title  { font-size: clamp(1.6rem, 1rem + 3.5vw, 3rem); }
  .feature-desc   { font-size: var(--fs-sm); }
  .feature-preview__viewport { max-height: 38dvh; }
  .feature-preview__slide img,
  .feature-preview__slide:not(:first-child) img {
    height: 100%;
    max-height: 38dvh;
    object-fit: cover;
    object-position: top center;
  }
}
@media (max-width: 600px) {
  .feature-title { font-size: clamp(1.4rem, 0.8rem + 3vw, 2.4rem); }
}

/* Hide the non-current slide from AT + tab order until it's active. */
.hero__slide[aria-hidden="true"] { pointer-events: none; }

/* ── Results slide ──────────────────────────────────────────────────
   Two-column layout: Results block on the LEFT, Solucije/Technologies/
   Slogan cluster on the RIGHT. Collapses to a single column under
   ~960px so neither side gets crushed. */
.hero__inner--results {
  position: relative;
  z-index: 3;
  display: grid;
  grid-template-columns: 1.05fr 1fr;
  gap: var(--space-8);
  align-items: start;
}
@media (max-width: 960px) {
  .hero__inner--results {
    grid-template-columns: 1fr;
    gap: var(--space-7);
  }
}

.results {
  display: grid;
  gap: var(--space-5);
  align-content: start;
}

.results__head {
  display: grid;
  gap: var(--space-3);
  max-width: 56ch;
}
.results__title {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(3rem, 2rem + 5vw, 6.5rem);
  letter-spacing: 0.04em;
  line-height: 0.95;
  background: linear-gradient(180deg, #ffffff 0%, #c7cbda 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  text-transform: uppercase;
  margin: 0;
}
.results__lead {
  font-size: var(--fs-md);
  color: var(--text-mute);
  max-width: 56ch;
}
.results__lead em {
  color: var(--text);
  font-style: normal;
  font-weight: 500;
}

/* ── About hero (slide 1) ───────────────────────────────────────────
   "O nama" sits as a small mono eyebrow tag, "Mali studio. Veliki
   standardi." is the big chrome-gradient headline, the prose lead and
   the stats grid each get their own glass panel. */
.about-hero {
  display: grid;
  gap: var(--space-5);
  align-content: start;
}
.about-hero__head {
  display: grid;
  gap: var(--space-4);
}
.about-hero__eyebrow {
  /* Inherit .section-eyebrow tag look — pill, mono, ice-blue dot. */
  align-self: start;
}
.about-hero__title {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(2.6rem, 1.8rem + 4.2vw, 5.5rem);
  line-height: 0.98;
  letter-spacing: -0.015em;
  background: linear-gradient(180deg, #ffffff 0%, #c7cbda 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  margin: 0;
}
.about-hero__title em {
  font-style: italic;
  background: linear-gradient(180deg, #b8e2ff 0%, #7fd6ff 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.about-hero__lead p {
  margin: 0;
  font-size: var(--fs-md);
  line-height: 1.55;
  color: var(--text);
}
.about-hero__lead em {
  color: var(--accent);
  font-style: normal;
  font-weight: 500;
}

/* Right side of the About hero — studio stats grid in a glass panel,
   centered both axes so the numbers align with the lead/title on the
   left. */
.solutions-cluster--stats {
  align-self: center;
}
.stats--hero {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-5) var(--space-6);
  text-align: center;
  align-content: center;
  justify-items: center;
}
.stats--hero .stat {
  display: grid;
  gap: var(--space-2);
  justify-items: center;
}
.stats--hero .stat__num {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(2rem, 1.4rem + 1.6vw, 2.8rem);
  line-height: 1;
  background: linear-gradient(180deg, #ffffff 0%, #c7cbda 100%);
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
  letter-spacing: -0.01em;
}
.stats--hero .stat__label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-mute);
}
@media (max-width: 520px) {
  .stats--hero { grid-template-columns: 1fr 1fr; }
}

/* Highlight inside body text — accent colour + bold weight. Used by
   the Usluge intro panel ("uz potpunu transparentnost"). */
.hi {
  color: var(--accent);
  font-weight: 600;
  font-style: normal;
}

/* Usluge intro panel — spans the full container width so it matches
   the Usluge + Tehnologije cluster row exactly underneath. The
   container itself is clamp(1040px, 86vw, 1480px) and shrinks with
   the viewport, so the panel naturally gets smaller on narrow
   screens without any extra rules. */
#services > .container > .section-lead.panel,
#rezultati > .container > .section-lead.panel {
  max-width: none;
  width: 100%;
}

.results__preview {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  align-items: stretch;
  /* Breathing room below the .section-lead.panel above — `* { margin: 0 }`
     in reset means there's otherwise no gap between the glass paragraph
     and the image cards. */
  margin-top: var(--space-6);
}

/* ── About hero (slide 1) — single centered column ──────────────────
   Eyebrow, headline, lead panel, CTAs, stats row, slogan all stack in
   a single axis-symmetric column. The .container handles horizontal
   centering for the whole stack so it can never lean. All gaps + paddings
   use vmin so they shrink on shorter viewports (1080p, laptops) and the
   column fits without forcing a scroll. */
.hero__inner--about {
  display: grid;
  gap: clamp(0.7rem, 1.8vmin, 1.6rem);
  justify-items: center;
  text-align: center;
  width: 100%;
  max-width: 980px;
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.hero__inner--about .about-hero__head {
  display: grid;
  gap: clamp(0.4rem, 1vmin, 0.9rem);
  justify-items: center;
  width: 100%;
}
.hero__inner--about .about-hero__title {
  max-width: 22ch;
  font-size: clamp(1.8rem, 0.8rem + 3vmin, 4rem);
  line-height: 1.02;
  margin: 0;
}

/* Lead glass panel — readable max width, paragraph text reads
   left-aligned inside the centered card. Tighter padding on this
   slide so the column fits in shorter viewports. */
.hero__inner--about .about-hero__lead {
  width: 100%;
  max-width: 720px;
}
.hero__inner--about .about-hero__lead.panel {
  padding: clamp(0.85rem, 1.6vmin, 1.6rem) clamp(1.1rem, 2vmin, 2rem);
}
.hero__inner--about .about-hero__lead p {
  text-align: left;
  margin: 0;
  font-size: clamp(0.95rem, 0.85rem + 0.4vmin, 1.05rem);
}

.hero__inner--about .hero__cta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}

/* Stats row — 4 columns at desktop, 2×2 at tablet, 1 column on
   small phones. Tighter panel padding + smaller stat values so the
   whole row stays compact vertically. */
.hero__inner--about .stats--hero {
  width: 100%;
  max-width: 820px;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(0.4rem, 1vmin, 1rem) clamp(0.8rem, 1.5vmin, 1.6rem);
}
.hero__inner--about .stats--hero.panel {
  padding: clamp(0.7rem, 1.4vmin, 1.4rem) clamp(1rem, 2vmin, 1.8rem);
}
.hero__inner--about .stat { gap: 0.15rem; }
.hero__inner--about .stat__num {
  font-size: clamp(1.3rem, 0.8rem + 1.4vmin, 2.4rem);
}
.hero__inner--about .stat__label {
  font-size: clamp(0.55rem, 0.5rem + 0.3vmin, 0.7rem);
}

@media (max-width: 720px) {
  .hero__inner--about .stats--hero {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
@media (max-width: 380px) {
  .hero__inner--about .stats--hero {
    grid-template-columns: 1fr;
  }
}

.hero__inner--about .slogan-inline {
  text-align: center;
  width: 100%;
  font-size: clamp(0.8rem, 0.7rem + 0.4vmin, 0.95rem);
}

/* Final safety net: on very short viewports (e.g., laptop 768px tall),
   collapse the slogan to free vertical space. */
@media (max-height: 720px) {
  .hero__inner--about { gap: clamp(0.4rem, 1.2vmin, 0.9rem); }
  .hero__inner--about .slogan-inline { display: none; }
}
@media (max-width: 520px) {
  .results__preview { grid-template-columns: 1fr; }
}
.results__card {
  margin: 0;
  display: grid;
  gap: var(--space-2);
}
.results__media {
  aspect-ratio: 16 / 10;
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background:
    linear-gradient(135deg, rgba(127,214,255,0.04), rgba(127,214,255,0.0)),
    rgba(255,255,255,0.015);
  position: relative;
  overflow: hidden;
  display: grid;
  place-items: center;
}
/* Subtle grid texture sits behind the <img> — so until the screenshot
   file exists at the referenced path, the card still reads as a
   designed surface instead of a broken-image icon. */
.results__media::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(127,214,255,0.05) 1px, transparent 1px),
    linear-gradient(90deg, rgba(127,214,255,0.05) 1px, transparent 1px);
  background-size: 32px 32px;
  mask-image: radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 75%);
  pointer-events: none;
  z-index: 0;
}
.results__media img {
  position: relative;
  z-index: 1;
  width: 100%;
  height: 100%;
  /* Fill the 16:10 frame; any edge whitespace in the screenshot gets
     cropped at the top/bottom, which is preferable to letterboxing. */
  object-fit: cover;
  object-position: center;
  display: block;
  cursor: zoom-in;
  transition: transform var(--t-fast) var(--ease-out);
}
.results__media img:hover { transform: scale(1.015); }
/* Hide the alt-text + broken-icon when the <img> fails to load. The
   ::after grid below stays visible so the card still looks intentional. */
.results__media img:not([src]),
.results__media img[src=""] { display: none; }
/* (.results__media--placeholder removed — no card uses it; the dashed-
   grid texture now sits behind every img automatically.) */

/* ── Optimisation stats row (between cards and CTA) ─────────────────
   Compact "+178% Pregledi" pills. Up-arrows go ice-blue (gain), down
   arrows go a calmer accent — for Bandwidth/Hits, less is faster. */
.results__stats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  /* Each stat box should only grow as tall as its own content.
     Without this, hovering one stat expands the whole row, making
     the neighbouring boxes visually drop down too. */
  align-items: start;
  gap: var(--space-3);
  margin-top: var(--space-1);
}
@media (max-width: 720px) {
  .results__stats { grid-template-columns: repeat(2, 1fr); }
}
.results__stat {
  position: relative;
  display: grid;
  gap: 2px;
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  background: rgba(127, 214, 255, 0.04);
  cursor: help;
  transition: border-color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.results__stat:hover {
  transform: translateY(-2px);
  border-color: rgba(127, 214, 255, 0.35);
  background: rgba(127, 214, 255, 0.07);
}

/* Inline expanding description — same behaviour on every screen size.
   The pill grows IN PLACE, pushing whatever follows (next stat in the
   column, the stats-note paragraph, the section CTA) down the page.
   No absolute popover, no overlap risk. */
.results__stat[data-tooltip]::after {
  content: attr(data-tooltip);
  display: block;
  width: 100%;
  margin-top: 0;
  padding: 0 14px;
  font-family: var(--font-sans);
  font-size: 0.95rem;
  font-weight: 500;
  line-height: 1.5;
  letter-spacing: 0.01em;
  text-transform: none;
  color: var(--text);
  /* Glass-panel styling — matches .panel elsewhere. */
  background-image: linear-gradient(180deg,
    rgba(15, 17, 28, 0.62),
    rgba(11, 13, 22, 0.50));
  backdrop-filter: blur(18px) saturate(140%);
  -webkit-backdrop-filter: blur(18px) saturate(140%);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: var(--r-md);
  box-shadow:
    0 12px 28px rgba(0, 0, 0, 0.45),
    0 0 0 1px rgba(127, 214, 255, 0.05) inset;
  isolation: isolate;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  /* Start clipped on the left so the text reveals left-to-right
     ("type-out" feel) as the pill expands. */
  clip-path: inset(0 100% 0 0);
  transition: max-height 340ms var(--ease-out),
              margin-top 340ms var(--ease-out),
              padding 340ms var(--ease-out),
              opacity 220ms var(--ease-out),
              clip-path 1100ms linear;
  white-space: normal;
  word-break: normal;
  overflow-wrap: break-word;
  hyphens: auto;
}
/* Touch devices use the .is-open class set by tapTooltip.js — tap to
   open, tap again to close. Hover is suppressed on touch since it's
   "sticky" after tap and fights the toggle. */
@media (hover: hover) {
  .results__stat[data-tooltip]:hover::after,
  .results__stat[data-tooltip]:focus-visible::after {
    max-height: 320px;
    margin-top: 12px;
    padding: 12px 14px;
    opacity: 1;
    clip-path: inset(0 0 0 0);
  }
}
.results__stat[data-tooltip].is-open::after {
  max-height: 320px;
  margin-top: 12px;
  padding: 12px 14px;
  opacity: 1;
  clip-path: inset(0 0 0 0);
}
.results__stat-value {
  font-family: var(--font-mono);
  font-size: clamp(1.4rem, 1rem + 1.2vw, 1.9rem);
  font-weight: 600;
  letter-spacing: 0.01em;
  line-height: 1;
}
.results__stat--up   .results__stat-value { color: var(--accent); }
.results__stat--down .results__stat-value { color: #cfe7ff; }
.results__stat-label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-mute);
  /* Allow long labels (e.g. "Bandwidth") to wrap inside the pill
     instead of spilling out of the right edge on narrow screens. */
  min-width: 0;
  overflow-wrap: anywhere;
  word-break: break-word;
}
.results__stat {
  /* Grid items default to min-width: max-content, which prevents the
     children from shrinking even when the cell is narrow — forcing the
     label off-screen. Reset so the stat pill respects its grid cell.
     Do NOT add overflow:hidden here — the [data-tooltip]::after popover
     sits below the box (top: 100% + 8px) and would get clipped. */
  min-width: 0;
}
@media (max-width: 480px) {
  /* Stack stats one-per-row so each label has the full container width
     and "BANDWIDTH" (uppercase, wide tracking) can't spill out. */
  .results__stats { grid-template-columns: 1fr; }
  .results__stat-label {
    letter-spacing: 0.08em;
    font-size: 0.7rem;
  }
}

.results__stats-note {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
  color: var(--text-dim);
  margin: var(--space-2) 0 var(--space-2);
}
.results__stats-note em {
  font-style: normal;
  color: var(--accent);
}
.results__badge {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  text-transform: uppercase;
  letter-spacing: 0.18em;
  padding: var(--space-1) var(--space-3);
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: rgba(10, 14, 22, 0.55);
  backdrop-filter: blur(6px);
  position: absolute;
  top: var(--space-3);
  left: var(--space-3);
  z-index: 2;
}
.results__badge--after {
  border-color: rgba(127, 214, 255, 0.55);
  color: var(--accent);
}
.results__note {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  color: var(--text-dim);
  position: relative;
  z-index: 2;
}
.results__card figcaption {
  font-size: var(--fs-sm);
  color: var(--text-mute);
}
.results__preview-all {
  justify-self: start;
  white-space: nowrap;
}

/* ── Usluge / Tehnologije / Slogan cluster ──────────────────────────
   Usluge + Tehnologije share a row; Slogan (when present) spans the
   full width below them with a thin divider rule. */
.solutions-cluster {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-6) var(--space-7);
}
/* Standalone services-section variant — each column gets its own glass
   panel surface, and the list text stays compact so 11 services + 7
   technologies fit comfortably in a single viewport. */
.solutions-cluster--services {
  margin-top: var(--space-7);
  gap: var(--space-6) var(--space-7);
  align-items: start;
}
.solutions-cluster--services .solutions-col {
  /* Inherits .panel — give it consistent internal padding so it reads
     like a card. */
  padding: var(--space-6) var(--space-6) var(--space-5);
}
.solutions-cluster--services .solutions-col__title {
  font-size: var(--fs-xs);
  margin: 0 0 var(--space-4) 0;
  padding-bottom: var(--space-3);
  border-bottom: 1px solid var(--border);
}
.solutions-cluster--services .solutions-col__icon {
  width: 22px;
  height: 22px;
}
.solutions-cluster--services .solutions-list li {
  font-size: var(--fs-sm);
}
.solutions-cluster--services .solutions-list--tech li {
  font-size: var(--fs-xs);
}
.solutions-cluster .solutions-col--slogan {
  grid-column: 1 / -1;
  padding-top: var(--space-4);
}
@media (max-width: 620px) {
  .solutions-cluster { grid-template-columns: 1fr; }
  .solutions-cluster .solutions-col--slogan { grid-column: auto; }
}

.solutions-col__title {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-mute);
  margin: 0 0 var(--space-4) 0;
}
.solutions-col__icon {
  width: 22px;
  height: 22px;
  color: var(--accent);
  opacity: 0.85;
}

.solutions-list {
  display: grid;
  gap: var(--space-2);
  list-style: none;
  padding: 0;
  margin: 0;
}
.solutions-list li {
  font-size: var(--fs-sm);
  color: var(--text);
  padding: var(--space-1) var(--space-3) var(--space-1) var(--space-4);
  position: relative;
  border-radius: var(--r-sm);
  transition: color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out);
  cursor: default;
}
.solutions-list li::before {
  content: "";
  position: absolute;
  left: 0; top: 1.1em;
  width: 6px; height: 1px;
  background: var(--accent);
  transition: width var(--t-fast) var(--ease-out);
}
/* Touch: tap-toggle via .is-open. Hover gated to hover-capable devices. */
@media (hover: hover) {
  .solutions-list li[data-tooltip]:hover {
    background: rgba(127, 214, 255, 0.05);
    color: var(--text);
  }
  .solutions-list li[data-tooltip]:hover::before {
    width: 10px;
  }
}
.solutions-list li[data-tooltip].is-open {
  background: rgba(127, 214, 255, 0.05);
  color: var(--text);
}
.solutions-list li[data-tooltip].is-open::before {
  width: 10px;
}
.solutions-list--tech li {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.04em;
}

/* ── Hover dropdown description ────────────────────────────────────
   Each [data-tooltip] li expands inline on hover/focus — the
   description grows IN the list flow, pushing the next items down
   smoothly, instead of floating over them as an absolute popover. */
.solutions-list li[data-tooltip]::after {
  content: attr(data-tooltip);
  display: block;
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: normal;
  text-transform: none;
  color: var(--text-mute);
  white-space: normal;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding: 0;
  transition: max-height 320ms var(--ease-out),
              opacity 220ms var(--ease-out),
              padding 320ms var(--ease-out);
}
@media (hover: hover) {
  .solutions-list li[data-tooltip]:hover::after,
  .solutions-list li[data-tooltip]:focus-visible::after {
    max-height: 240px;
    opacity: 1;
    padding-top: var(--space-2);
    padding-bottom: var(--space-2);
  }
}
.solutions-list li[data-tooltip].is-open::after {
  max-height: 240px;
  opacity: 1;
  padding-top: var(--space-2);
  padding-bottom: var(--space-2);
}
.solutions-list li[data-tooltip] { outline: none; }
.solutions-list li[data-tooltip]:focus-visible {
  background: rgba(127, 214, 255, 0.07);
}

.slogan {
  font-family: var(--font-sans);
  font-size: clamp(1.25rem, 0.9rem + 1.2vw, 1.65rem);
  line-height: 1.2;
  color: var(--text);
  margin: 0 0 var(--space-4) 0;
}
.slogan__line { display: block; }
.slogan em {
  font-style: italic;
  color: var(--accent);
}

/* Inline slogan variant — single line per language, stacked compactly
   beneath the "Pogledaj sve" button. Fills horizontal space without
   eating vertical room. */
.slogan-inline {
  margin-top: var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  display: grid;
  gap: var(--space-1);
}
.slogan.slogan--inline {
  margin: 0;
  font-size: clamp(1.05rem, 0.85rem + 0.7vw, 1.3rem);
  line-height: 1.35;
  white-space: normal;
}
.slogan--alt {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.04em;
  color: var(--text-mute);
  margin-bottom: 0;
}
.slogan--alt em {
  color: var(--text-mute);
  font-style: normal;
  opacity: 0.85;
}

/* ── Hero slider nav (arrows + dots) ────────────────────────────── */
.hero__nav {
  position: absolute;
  bottom: var(--space-7);
  left: 50%;
  transform: translateX(-50%);
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  background: rgba(10, 14, 22, 0.55);
  backdrop-filter: blur(10px);
  z-index: 4;
}
.hero__nav-arrow {
  width: 28px; height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid transparent;
  background: transparent;
  color: var(--text-mute);
  cursor: pointer;
  transition: color var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.hero__nav-arrow svg { width: 14px; height: 14px; }
.hero__nav-arrow:hover {
  color: var(--text);
  border-color: var(--border);
  transform: scale(1.05);
}
.hero__nav-dots {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0 var(--space-2);
}
.hero__nav-dot {
  width: 8px; height: 8px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: transparent;
  padding: 0;
  cursor: pointer;
  transition: background var(--t-fast) var(--ease-out),
              border-color var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.hero__nav-dot.is-current {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1.15);
  box-shadow: 0 0 12px var(--accent-glow);
}

/* ── Hero meta strip (under the panel) ──────────────────────────────
   Two compact rows: a live availability pill with a pulsing ice-blue dot,
   and a row of mono-space tech-stack chips. Fills the empty space on the
   hero with signal-rich content without competing with the title. */
.hero__meta {
  margin-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: clamp(320px, 36vw, 560px);
}
.hero__avail {
  display: inline-flex;
  align-items: center;
  gap: 0.6em;
  width: fit-content;
  padding: 0.4em 0.85em;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--text);
  background: rgba(127, 214, 255, 0.06);
  border: 1px solid rgba(127, 214, 255, 0.18);
  border-radius: var(--r-pill);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
}
.hero__avail-dot {
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: #7FD6FF;
  box-shadow:
    0 0 0 0 rgba(127, 214, 255, 0.55),
    0 0 10px rgba(127, 214, 255, 0.85);
  animation: hero-avail-pulse 2.2s var(--ease-in-out) infinite;
}
@keyframes hero-avail-pulse {
  0%, 100% {
    box-shadow:
      0 0 0 0 rgba(127, 214, 255, 0.55),
      0 0 10px rgba(127, 214, 255, 0.85);
  }
  50% {
    box-shadow:
      0 0 0 8px rgba(127, 214, 255, 0.0),
      0 0 14px rgba(127, 214, 255, 0.95);
  }
}
.hero__stack {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4em 0.5em;
}
.hero__stack li {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--text-mute);
  padding: 0.25em 0.7em;
  background: rgba(255, 255, 255, 0.03);
  border: 1px solid rgba(255, 255, 255, 0.07);
  border-radius: var(--r-sm);
  transition: color var(--t-fast) var(--ease-out), border-color var(--t-fast) var(--ease-out);
}
.hero__stack li:hover {
  color: var(--accent);
  border-color: rgba(127, 214, 255, 0.35);
}
@media (prefers-reduced-motion: reduce) {
  .hero__avail-dot { animation: none; }
}

/* The hero panel sits below the title; fluid max-width so it scales with
   viewport without ever spanning the full row (keeps the K visible). */
.hero__panel {
  max-width: clamp(320px, 36vw, 560px);
  display: grid;
  gap: var(--space-5);
  padding: clamp(1.4rem, 1rem + 1.4vw, 2rem) clamp(1.6rem, 1rem + 1.6vw, 2.2rem);
}
.hero__panel .hero__lead { margin: 0; }
.hero__panel .hero__cta  { margin: 0; }
@media (max-width: 720px) {
  .hero__panel { max-width: 100%; }
}
.hero__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.hero__eyebrow::before {
  content: "";
  width: 28px; height: 1px;
  background: var(--accent);
}
.hero__title {
  max-width: 16ch;
}
.hero__title em {
  font-style: normal;
  background: linear-gradient(120deg, var(--accent), #a78bfa 60%, #06d6a0);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* Hero line: each line is a block with overflow:hidden, content slides up
   from below. Works for any direct child element (span, em, etc). */
.hero__line {
  display: block;
  overflow: hidden;
  padding-bottom: 0.08em;        /* prevent descenders from being clipped */
  line-height: 1.05;
}
.hero__line > * {
  display: inline-block;
  transform: translateY(110%);
  will-change: transform;
}
html.no-js .hero__line > *,                /* if JS missing */
.hero__line.is-revealed > * {
  transform: translateY(0);
  transition: transform 1100ms var(--ease-out);
}
.hero__lead {
  max-width: 48ch;
  font-size: var(--fs-md);
  color: var(--text-mute);
}
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  margin-top: var(--space-3);
}
.hero__scroll {
  position: absolute;
  bottom: var(--space-6);
  left: 50%;
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  z-index: 3;
}
.hero__scroll-bar {
  width: 1px; height: 36px;
  background: linear-gradient(to bottom, var(--accent), transparent);
  animation: scroll-bar 2s var(--ease-in-out) infinite;
}
@keyframes scroll-bar {
  0%   { transform: scaleY(0); transform-origin: top; }
  50%  { transform: scaleY(1); transform-origin: top; }
  51%  { transform-origin: bottom; }
  100% { transform: scaleY(0); transform-origin: bottom; }
}

/* ── Hero slide 2 — featured project spotlight ─────────────────────
   Two-column on desktop: copy on the LEFT, live iframe preview framed
   like a browser window on the RIGHT. Collapses to a single column
   under ~960px so the preview doesn't get crushed. */
.hero__inner--feature {
  display: grid;
  grid-template-columns: 1fr 1.15fr;
  gap: var(--space-8);
  align-items: center;
}
@media (max-width: 960px) {
  .hero__inner--feature {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }
}

.feature-copy {
  display: grid;
  gap: var(--space-5);
  align-content: center;
  max-width: 52ch;
}
.feature-title {
  font-family: var(--font-sans);
  font-weight: 700;
  font-size: clamp(2.6rem, 1.6rem + 4.4vw, 5.4rem);
  letter-spacing: -0.01em;
  line-height: 0.98;
  margin: 0;
}
.feature-title em {
  font-style: normal;
  background: linear-gradient(120deg, var(--accent), #a78bfa 60%, #06d6a0);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}
.feature-tags {
  margin: 0;
  padding: 0;
  list-style: none;
}
.feature-desc {
  color: var(--text-mute);
  font-size: var(--fs-md);
  max-width: 48ch;
  margin: 0;
}
.feature-desc em {
  font-style: normal;
  color: var(--text);
}

/* Browser-chrome frame around the live iframe. */
.feature-preview {
  position: relative;
  border-radius: var(--r-lg, 14px);
  overflow: hidden;
  border: 1px solid var(--border);
  background: rgba(8, 10, 16, 0.65);
  backdrop-filter: blur(8px);
  box-shadow:
    0 30px 60px -20px rgba(0, 0, 0, 0.55),
    0 0 0 1px rgba(255, 255, 255, 0.02) inset;
  transition: transform var(--t-med) var(--ease-out),
              box-shadow var(--t-med) var(--ease-out);
}
.feature-preview:hover {
  transform: translateY(-2px);
  box-shadow:
    0 40px 70px -20px rgba(0, 0, 0, 0.6),
    0 0 0 1px rgba(255, 255, 255, 0.04) inset;
}
.feature-preview__chrome {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: rgba(255, 255, 255, 0.03);
  border-bottom: 1px solid var(--border);
}
.feature-preview__dot {
  width: 10px; height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.18);
}
.feature-preview__dot:nth-child(1) { background: #ff5f57; }
.feature-preview__dot:nth-child(2) { background: #febc2e; }
.feature-preview__dot:nth-child(3) { background: #28c840; }
.feature-preview__url {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.06em;
  color: var(--text-mute);
}

/* Carousel viewport — sized by the current image so screenshots show
   in full without being cropped. The first slide takes part in flow
   (sets the box height); the rest are absolutely-positioned overlays
   that fade between. */
.feature-preview__viewport {
  position: relative;
  width: 100%;
  overflow: hidden;
  background: #0a0c12;
}
.feature-preview__slide {
  display: block;
  opacity: 0;
  visibility: hidden;
  transition: opacity 600ms var(--ease-out);
}
.feature-preview__slide:not(:first-child) {
  position: absolute;
  inset: 0;
}
.feature-preview__slide.is-current {
  opacity: 1;
  visibility: visible;
}
.feature-preview__slide img {
  width: 100%;
  height: auto;
  display: block;
}
.feature-preview__slide:not(:first-child) img {
  height: 100%;
  object-fit: contain;
}

/* Prev/next arrows — sit above slides, semi-transparent until hover. */
.feature-preview__arrow {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 3;
  width: 40px; height: 40px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.14);
  background: rgba(8, 10, 16, 0.55);
  backdrop-filter: blur(6px);
  color: var(--text);
  cursor: pointer;
  opacity: 0;
  transition: opacity var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.feature-preview__arrow svg { width: 14px; height: 14px; }
.feature-preview:hover .feature-preview__arrow,
.feature-preview__arrow:focus-visible {
  opacity: 1;
}
.feature-preview__arrow:hover {
  background: rgba(8, 10, 16, 0.8);
}
.feature-preview__arrow--prev { left: 12px; }
.feature-preview__arrow--next { right: 12px; }
.feature-preview__arrow--prev:hover { transform: translateY(-50%) translateX(-2px); }
.feature-preview__arrow--next:hover { transform: translateY(-50%) translateX(2px); }
@media (hover: none) {
  .feature-preview__arrow { opacity: 1; }
}

/* The 3D centerpiece lives in a fixed full-viewport stage so it persists
   across the entire scroll. Sections overlay it via z-index: 2 (set in
   layout.css) — the canvas sits at z-index: 1, behind everything. */
.hero__canvas-wrap {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  will-change: transform;
}
.hero__canvas-wrap canvas {
  width: 100%; height: 100%;
  display: block;
}

/* Dim vignette layered between the canvas (z:1) and section content (z:2).
   Keeps body text readable when it overlaps the bright chrome K. */
.centerpiece-veil {
  position: fixed;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  /* Pure black core fading out — gives the futuristic stage a deep void
     to read against and lets the ice-blue energy lines really pop. */
  background:
    radial-gradient(ellipse 75% 60% at 50% 50%,
      rgba(0, 2, 6, 0.62) 0%,
      rgba(0, 2, 6, 0.32) 38%,
      transparent 72%);
}

/* Wordmark that resolves under the assembled K at the bottom of the page.
   Styled to feel like the chrome K — metallic vertical gradient on the
   glyphs, soft violet glow underneath, and a thin halo behind. */
.centerpiece-wordmark {
  position: fixed;
  /* Pinned to the bottom of the viewport — independent of the canvas
     wrap's scroll-driven fade so it stays visible all the way down.
     Sits above section content (z:2) but below the nav (z:100). */
  bottom: clamp(0.75rem, 2.5vh, 2rem);
  left: 50%;
  z-index: 50;
  transform: translateX(-50%) !important;
  font-family: var(--font-sans);
  font-weight: 700;
  /* Tightened lower bound + slope so on 1280×720-ish screens the
     wordmark stays compact and can't bleed up into the contact panel. */
  font-size: clamp(1.1rem, 0.6rem + 1.6vw, 3rem);
  letter-spacing: 0.22em;
  text-indent: 0.22em;       /* compensates the right-side letter-spacing pad */
  text-transform: uppercase;
  white-space: nowrap;
  /* Fade in over the last ~18% of scroll, then fade back out together with
     the GLB when the footer enters view. --scroll-p (0..1) and
     --stage-opacity (1→0 near footer) are written by centerpiece.js. */
  opacity: min(
    clamp(0, calc((var(--scroll-p, 0) - 0.82) * 6), 1),
    var(--stage-opacity, 1)
  ) !important;
  pointer-events: none;
  will-change: opacity, transform;
  transition: opacity 200ms linear;

  /* Chrome gradient on the letterforms — brighter for stronger readability */
  background: linear-gradient(
    180deg,
    #ffffff 0%,
    #f4f6ff 45%,
    #dde2f2 75%,
    #b5bcd1 100%
  );
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;

  /* Stronger ice-blue under-glow + crisper drop shadows for visibility */
  filter:
    drop-shadow(0 0 1px rgba(255, 255, 255, 0.9))
    drop-shadow(0 2px 4px rgba(0, 0, 0, 0.55))
    drop-shadow(0 6px 28px rgba(127, 214, 255, 0.85))
    drop-shadow(0 0 18px rgba(223, 243, 255, 0.45));
}
@media (prefers-reduced-motion: reduce) {
  .centerpiece-wordmark { transform: translateX(-50%); }
}

/* On phones the wordmark sits dangerously close to the footer (and to
   the per-letter shadow halo) — once the GLB has assembled it visually
   crashes into the footer copy. Drop it entirely on small viewports;
   the GLB carries the brand at the bottom on its own. */
@media (max-width: 720px) {
  .centerpiece-wordmark { display: none !important; }
}
/* Fail-safe — the moment the footer enters the wordmark's bottom-of-
   viewport zone (set by an IntersectionObserver in centerpiece.js with
   rootMargin: -100px on the bottom), force the wordmark fully invisible.
   This guarantees zero overlap on any viewport, even if the scroll-
   driven --stage-opacity math is off by a frame. The existing 200ms
   opacity transition keeps the disappearance smooth. */
body.is-footer-near .centerpiece-wordmark {
  opacity: 0 !important;
}
/* Short-height viewports (e.g. 1280×720) — push the wordmark closer
   to the bottom edge and shrink it further so it doesn't crowd the
   contact section. */
@media (max-height: 800px) {
  .centerpiece-wordmark {
    font-size: clamp(0.9rem, 0.4rem + 1.2vw, 2.2rem);
    bottom: 0.4rem;
    letter-spacing: 0.18em;
  }
}

/* Per-letter wrappers retained only as a safety net in case any cached JS
   still splits the wordmark — letters render fully visible regardless. */
.centerpiece-wordmark .cw-letter {
  display: inline-block;
  opacity: 1 !important;
}
.centerpiece-wordmark.is-assembled .cw-letter {
  /* No animation — keep letters visible at rest. */
  animation: none;
}
@keyframes cw-letter-in {
  0% {
    opacity: 0;
    transform:
      translateY(60px)
      translateX(var(--cw-tx, 0))
      rotateZ(var(--cw-rz, 0))
      scale(0.4);
    filter: blur(14px);
  }
  55% {
    opacity: 1;
    transform:
      translateY(-6px)
      translateX(0)
      rotateZ(0)
      scale(1.08);
    filter: blur(2px);
  }
  100% {
    opacity: 1;
    transform: translateY(0) translateX(0) rotateZ(0) scale(1);
    filter: blur(0);
  }
}
@media (prefers-reduced-motion: reduce) {
  .centerpiece-wordmark .cw-letter {
    opacity: 1;
    transform: none;
    filter: none;
    animation: none;
  }
}

/* Faint horizontal accent rules on either side of the wordmark, like
   a brand-mark seal. They scale with the wordmark's own opacity via
   currentColor + opacity inheritance from the JS-driven parent. */
.centerpiece-wordmark::before,
.centerpiece-wordmark::after {
  content: "";
  position: absolute;
  top: 50%;
  width: clamp(28px, 6vw, 80px);
  height: 1px;
  background: linear-gradient(90deg, transparent, rgba(127, 214, 255, 0.75), transparent);
  transform: translateY(-50%);
}
.centerpiece-wordmark::before { right: calc(100% + 18px); }
.centerpiece-wordmark::after  { left:  calc(100% + 18px); }

/* ── Cards ─────────────────────────── */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-5);
  margin-top: var(--space-7);
}

.card {
  position: relative;
  padding: var(--space-6);
  background: linear-gradient(180deg, var(--bg-card), var(--bg-elev));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  transition: transform var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out);
  overflow: hidden;
  isolation: isolate;
}
.card::before {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(135deg, var(--accent), transparent 60%);
  opacity: 0;
  transition: opacity var(--t-med) var(--ease-out);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
          mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
          mask-composite: exclude;
  z-index: -1;
}
.card:hover { transform: translateY(-4px); }
.card:hover::before { opacity: 1; }

.card__num {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  color: var(--text-dim);
  margin-bottom: var(--space-5);
  display: flex; gap: var(--space-3); align-items: center;
}
.card__num::after {
  content: "";
  flex: 1; height: 1px;
  background: var(--border);
}
.card__title {
  font-size: var(--fs-lg);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
.card__body {
  font-size: var(--fs-sm);
  color: var(--text-mute);
}

/* ── Process steps ─────────────────────────── */
.process {
  margin-top: var(--space-7);
  display: grid;
  gap: var(--space-4);
}
.process__step {
  display: grid;
  grid-template-columns: 80px 1fr 2fr;
  gap: var(--space-6);
  align-items: start;
  /* When also `.panel`, the glass card supplies its own padding/border;
     drop the legacy divider lines so they don't double up. */
}
.process__step:not(.panel) {
  padding: var(--space-6) 0;
  border-top: 1px solid var(--border);
}
.process__step:not(.panel):last-child { border-bottom: 1px solid var(--border); }
.process__num {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--accent);
  letter-spacing: 0.08em;
}
.process__title {
  font-size: var(--fs-lg);
  font-weight: 500;
}
.process__body { color: var(--text-mute); font-size: var(--fs-sm); }

@media (max-width: 720px) {
  .process__step { grid-template-columns: 1fr; gap: var(--space-3); }
}

/* ── Project (work) cards ─────────────────────────── */
.work-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(380px, 1fr));
  gap: var(--space-6);
  margin-top: var(--space-7);
}
@media (max-width: 720px) {
  .work-grid { grid-template-columns: 1fr; }
}

.project {
  position: relative;
  display: block;
  border-radius: var(--r-lg);
  overflow: hidden;
  background: var(--bg-card);
  border: 1px solid var(--border);
  isolation: isolate;
  transition: transform var(--t-med) var(--ease-out),
              border-color var(--t-med) var(--ease-out);
}
.project:hover {
  transform: translateY(-6px);
  border-color: var(--border-strong);
}
.project__media {
  aspect-ratio: 16 / 10;
  position: relative;
  overflow: hidden;
  background:
    linear-gradient(135deg, var(--accent-soft), transparent),
    var(--bg-elev);
}
.project__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform 800ms var(--ease-out);
}
.project:hover .project__media img { transform: scale(1.04); }
.project__placeholder {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--text-dim);
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.project__body {
  padding: var(--space-5) var(--space-6) var(--space-6);
}
.project__meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-bottom: var(--space-3);
}
.project__title {
  font-size: var(--fs-lg);
  font-weight: 600;
  margin-bottom: var(--space-3);
}
.project__desc {
  color: var(--text-mute);
  font-size: var(--fs-sm);
  margin-bottom: var(--space-5);
}
.project__tags {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}
.tag {
  display: inline-flex;
  padding: 4px 10px;
  border: 1px solid var(--border);
  border-radius: var(--r-pill);
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--text-mute);
}
.project__cta {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-5);
  font-size: var(--fs-sm);
  color: var(--accent);
  font-weight: 500;
}
.project__cta-icon {
  transition: transform var(--t-med) var(--ease-spring);
}
.project:hover .project__cta-icon {
  transform: translate(3px, -3px);
}

/* ── Contact CTA ─────────────────────────── */
.contact {
  text-align: center;
  padding-block: var(--space-11);
}

/* Centered contact panel by default — switches to a left-anchored layout
   on wide viewports so the WebGL K stays visible to the right of it. */
.contact__panel {
  max-width: 720px;
  margin-inline: auto;
  display: grid;
  gap: var(--space-5);
  /* Fluid panel padding — tighter on phones so the inner column is wider
     and long words ("Razgovarajmo") fit without hyphenation breaks. */
  padding: clamp(1.25rem, 1rem + 2vw, 3.4rem);
}
.contact__panel .section-eyebrow { justify-self: center; }
.contact__title {
  margin-bottom: var(--space-6);
  margin-inline: auto;
  max-width: 22ch;
  /* Fluid font scale spans phones → ultrawide. Low minimum (1.4rem) keeps
     "Razgovarajmo." on one line even inside very narrow panels. */
  font-size: clamp(1.4rem, 0.7rem + 2.4vw, 2.9rem);
  line-height: 1.08;
  /* No hyphens: auto — that was inserting mid-word breaks on narrow
     viewports even when the word would have fit otherwise. Keep
     overflow-wrap as a last-resort safety net. */
  overflow-wrap: break-word;
}

/* Wide screens: pin the contact panel to the VIEWPORT's left gutter (not
   the centered container's edge), and let its width flex with viewport.
   The negative margin breaks the panel out of .container's centering so
   it sits flush at `var(--gutter)` from the screen edge. The formula
   `var(--gutter) - (100vw - 100%) / 2` self-cancels on smaller screens
   where .container is already gutter-bound. */
@media (min-width: 960px) {
  .contact { text-align: left; }

  /* Full-bleed container inside the contact section so the two panels can
     sit flush at each viewport edge. Overrides .container's intrinsic
     width cap (min(100% - gutter*2, var(--container))) so the flex row
     spans the full viewport. Scoped via child combinator so other
     sections are untouched. */
  .contact > .container {
    width: 100%;
    max-width: none;
    padding-inline: var(--gutter);
    display: flex;
    align-items: stretch;
    justify-content: space-between;
    gap: var(--space-7);
  }

  .contact__panel {
    max-width: clamp(300px, 30vw, 520px);
    margin: 0;
    flex: 0 1 clamp(300px, 30vw, 520px);
  }
  .contact__panel .section-eyebrow { justify-self: start; }
  .contact__title {
    margin-inline: 0;
    max-width: 22ch;
  }
  .contact .section-lead { margin-inline: 0 !important; }
}
.contact__email {
  display: inline-block;
  font-family: var(--font-mono);
  font-size: var(--fs-lg);
  color: var(--accent);
  margin-top: var(--space-5);
  letter-spacing: 0.04em;
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-med) var(--ease-out);
}
.contact__email:hover { border-color: var(--accent); }

/* Phone-panel button row: Mobile / WhatsApp / Viber. Centers on mobile,
   left-aligns on desktop to match the surrounding text-align switch. */
.contact__channels {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  justify-content: center;
}
@media (min-width: 960px) {
  .contact__channels { justify-content: flex-start; }
}

/* When panels stack on mobile, add breathing room between them. */
.contact__panel + .contact__panel { margin-top: var(--space-7); }
@media (min-width: 960px) {
  .contact__panel + .contact__panel { margin-top: 0; }
}

/* Phone-panel: stacked name + number. The name reads as the contact
   person/brand, the number sits below it slightly smaller than the
   .contact__email mono treatment used on the email panel. */
.contact__person {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin-top: var(--space-5);
  align-items: center;
}
@media (min-width: 960px) {
  .contact__person { align-items: flex-start; }
}
.contact__name {
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 500;
  color: var(--text);
  letter-spacing: 0.01em;
}
.contact__phone-number,
.contact__handle {
  display: inline-block;
  max-width: 100%;
  font-family: var(--font-mono);
  font-size: var(--fs-md);
  color: var(--accent);
  letter-spacing: 0.04em;
  border-bottom: 1px solid transparent;
  transition: border-color var(--t-med) var(--ease-out);
  /* Long handles (e.g. the email address) must wrap inside narrow
     panels instead of spilling out of the right edge. */
  word-break: break-all;
  overflow-wrap: anywhere;
}
.contact__phone-number:hover,
.contact__handle:hover { border-color: var(--accent); }

/* (Former .about-grid / .about__body styles removed — the standalone
   #about section no longer exists; its content lives in the hero now.
   See .about__lead--hero above for the hero-embedded variant.) */

/* ── Stats strip ─────────────────────────── */
.stats {
  margin-top: var(--space-8);
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-6);
  padding: var(--space-6) 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.stat__num {
  font-size: var(--fs-2xl);
  font-weight: 600;
  letter-spacing: -0.03em;
  background: linear-gradient(180deg, var(--text), var(--text-mute));
  -webkit-background-clip: text;
          background-clip: text;
  color: transparent;
}
.stat__label {
  font-family: var(--font-mono);
  font-size: var(--fs-xs);
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-dim);
  margin-top: var(--space-2);
}
/* When the counter lands (or for non-numeric stats, when it enters view)
   the digits flash a brief ice-blue glow so the eye catches the moment. */
.stat__num { transition: filter 320ms var(--ease-out); }
.stat__num.is-counted {
  filter: drop-shadow(0 0 14px rgba(127, 214, 255, 0.45));
  animation: stat-glow-pop 800ms var(--ease-out);
}
@keyframes stat-glow-pop {
  0%   { filter: drop-shadow(0 0 0   rgba(127, 214, 255, 0.0)); }
  35%  { filter: drop-shadow(0 0 22px rgba(127, 214, 255, 0.7)); }
  100% { filter: drop-shadow(0 0 14px rgba(127, 214, 255, 0.45)); }
}

/* ── Custom cursor ─────────────────────────────────────────────────────
   Ice-blue HUD pointer with a lag-trailing ring and a tight centre dot.
   Activated by JS adding `.has-custom-cursor` to <html>. */
.has-custom-cursor,
.has-custom-cursor body { cursor: none; }
.has-custom-cursor a,
.has-custom-cursor button,
.has-custom-cursor [role="button"],
.has-custom-cursor input,
.has-custom-cursor textarea,
.has-custom-cursor select,
.has-custom-cursor label { cursor: none; }
.cursor {
  position: fixed;
  top: 0; left: 0;
  pointer-events: none;
  z-index: 9999;
  will-change: transform;
  mix-blend-mode: screen;
  transition: opacity 200ms var(--ease-out);
}
.cursor--ring {
  width: 32px;
  height: 32px;
  border: 1px solid rgba(127, 214, 255, 0.85);
  border-radius: 50%;
  box-shadow:
    0 0 14px rgba(127, 214, 255, 0.35),
    inset 0 0 6px rgba(127, 214, 255, 0.15);
  transition:
    opacity 200ms var(--ease-out),
    width   220ms var(--ease-out),
    height  220ms var(--ease-out),
    border-color 220ms var(--ease-out);
}
.cursor--ring.is-hover {
  width: 54px;
  height: 54px;
  border-color: rgba(223, 243, 255, 0.95);
  box-shadow:
    0 0 22px rgba(127, 214, 255, 0.55),
    inset 0 0 10px rgba(127, 214, 255, 0.2);
}
.cursor--ring.is-press {
  width: 24px;
  height: 24px;
  border-color: rgba(223, 243, 255, 1);
}
.cursor--dot {
  width: 4px;
  height: 4px;
  border-radius: 50%;
  background: rgba(223, 243, 255, 0.95);
  box-shadow: 0 0 6px rgba(127, 214, 255, 0.9);
}
@media (pointer: coarse), (prefers-reduced-motion: reduce) {
  .cursor { display: none; }
}

/* ── Lightbox ──────────────────────────────────────────────────────
   Full-viewport image preview opened by clicking any .results__media
   img. Click on the backdrop, the close button, or pressing Escape
   dismisses it. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 200;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(1rem, 4vw, 4rem);
  background: rgba(2, 4, 8, 0.85);
  backdrop-filter: blur(14px) saturate(140%);
  opacity: 0;
  transition: opacity 220ms var(--ease-out);
}
.lightbox.is-open {
  display: flex;
  opacity: 1;
}
.lightbox__figure {
  margin: 0;
  max-width: min(1400px, 96vw);
  max-height: 92vh;
  display: grid;
  gap: var(--space-3);
  justify-items: center;
  transform: scale(0.96);
  transition: transform 260ms var(--ease-spring);
}
.lightbox.is-open .lightbox__figure { transform: scale(1); }
.lightbox__img {
  max-width: 100%;
  max-height: 80vh;
  width: auto;
  height: auto;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  box-shadow:
    0 30px 80px rgba(0, 0, 0, 0.6),
    0 0 0 1px rgba(127, 214, 255, 0.10) inset;
  background: rgba(255, 255, 255, 0.03);
  display: block;
}
.lightbox__caption {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  letter-spacing: 0.08em;
  color: var(--text-mute);
  text-align: center;
}
.lightbox__close {
  position: absolute;
  top: clamp(0.75rem, 2vw, 1.5rem);
  right: clamp(0.75rem, 2vw, 1.5rem);
  width: 44px; height: 44px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: rgba(8, 12, 20, 0.75);
  backdrop-filter: blur(10px);
  color: var(--text);
  cursor: pointer;
  transition: border-color var(--t-fast) var(--ease-out),
              background var(--t-fast) var(--ease-out),
              transform var(--t-fast) var(--ease-out);
}
.lightbox__close svg { width: 18px; height: 18px; }
.lightbox__close:hover {
  border-color: rgba(127, 214, 255, 0.55);
  background: rgba(127, 214, 255, 0.10);
  transform: scale(1.06);
}

/* Lock background scroll while the lightbox is open. */
body.has-lightbox-open { overflow: hidden; }

/* ============ animations.css ============ */
/* Reveal-on-scroll classes — GSAP toggles `.is-in`.
   CSS provides the resting state + transitions so anything renders
   correctly even if JS fails to load. */

[data-reveal] {
  opacity: 0;
  transform: translateY(28px);
  transition: opacity 800ms var(--ease-out),
              transform 800ms var(--ease-out);
  will-change: transform, opacity;
}
[data-reveal].is-in {
  opacity: 1;
  transform: none;
}
[data-reveal][data-delay="1"] { transition-delay: 80ms;  }
[data-reveal][data-delay="2"] { transition-delay: 160ms; }
[data-reveal][data-delay="3"] { transition-delay: 240ms; }
[data-reveal][data-delay="4"] { transition-delay: 320ms; }
[data-reveal][data-delay="5"] { transition-delay: 400ms; }

/* (Hero line styles moved to components.css next to .hero__title — they
   live with their owning component now.) */

/* Section edge accents — when a section enters view, four thin lines
   draw in around its edges, framing the content like a viewport reticle.
   Subtle, not loud. */
section[data-frame] {
  position: relative;
}
section[data-frame]::before,
section[data-frame]::after,
section[data-frame] > .frame-edge-l,
section[data-frame] > .frame-edge-r {
  content: "";
  position: absolute;
  background: linear-gradient(var(--frame-dir, 180deg),
              transparent, rgba(123, 97, 255, 0.45), transparent);
  pointer-events: none;
  opacity: 0;
  transition: opacity 700ms var(--ease-out),
              transform 1200ms var(--ease-out);
}
/* Top edge */
section[data-frame]::before {
  --frame-dir: 90deg;
  top: 0; left: 50%;
  width: 0; height: 1px;
  transform: translateX(-50%);
}
/* Bottom edge */
section[data-frame]::after {
  --frame-dir: 90deg;
  bottom: 0; left: 50%;
  width: 0; height: 1px;
  transform: translateX(-50%);
}
section[data-frame].is-framed::before,
section[data-frame].is-framed::after {
  opacity: 1;
  width: min(60%, 720px);
}

/* Reveal hint label — tiny "section / 02" style marker that fades in */
.section-eyebrow {
  transition: opacity 600ms var(--ease-out),
              transform 600ms var(--ease-out);
}

/* Marquee row */
@keyframes marquee {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
.marquee {
  --speed: 40s;
  display: flex;
  overflow: hidden;
  mask-image: linear-gradient(to right, transparent, #000 10%, #000 90%, transparent);
}
.marquee__track {
  display: flex;
  gap: var(--space-7);
  flex-shrink: 0;
  animation: marquee var(--speed) linear infinite;
  padding-right: var(--space-7);
}
.marquee__item {
  font-family: var(--font-mono);
  font-size: var(--fs-sm);
  color: var(--text-dim);
  letter-spacing: 0.2em;
  text-transform: uppercase;
  white-space: nowrap;
}
.marquee__item span { color: var(--accent); margin-right: var(--space-3); }

/* Magnetic-cursor target uses transform-gpu */
[data-magnet] {
  display: inline-block;
  will-change: transform;
  transition: transform 350ms var(--ease-spring);
}

/* Page-loaded gate (prevents FOUC for i18n swap) */
html:not(.i18n-ready) [data-i18n] { visibility: hidden; }
