/* ════════════════════════════════════════════════════════════════
   RYAN BORG — ryanborg.net
   Mediterranean tech-noir · dark, cinematic, motion-rich
   Pure CSS — no frameworks, no build step
   ════════════════════════════════════════════════════════════════ */

:root {
  --bg: #06090e;
  --bg-2: #0a0f16;
  --bg-3: #0e1520;
  --ink: #f5f8fb;
  --ink-dim: #dde4ed;
  --ink-faint: #bfc9d6;
  --line: rgba(232, 236, 241, .09);
  --accent: #3fd0c4;          /* teal pulled from the Malta sea */
  --accent-deep: #1a8f86;
  --accent-glow: rgba(63, 208, 196, .35);
  --font-display: "Space Grotesk", system-ui, sans-serif;
  --font-body: "Inter", system-ui, sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
  --ease-out: cubic-bezier(.19, 1, .22, 1);
  --ease-snap: cubic-bezier(.65, 0, .35, 1);
  --nav-h: 76px;
  --radius: 18px;
}

/* ── Reset ── */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
html:focus-within { scroll-behavior: smooth; }
body {
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-body);
  font-weight: 300;
  font-size: 16px;
  line-height: 1.7;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
  /* text selection switched off site-wide (see main.js for right-click) */
  -webkit-user-select: none;
  -ms-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
}
img { display: block; max-width: 100%; }
/* class-level display rules would otherwise beat the UA [hidden] rule */
[hidden] { display: none !important; }
a { color: inherit; text-decoration: none; }
ul { list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
em { font-style: normal; }
::selection { background: var(--accent); color: #04211e; }

.mono {
  font-family: var(--font-mono);
  font-size: .76rem;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--ink-dim);
}
/* sits above the drifting pattern / aurora layers behind each section */
.container { width: min(1200px, calc(100% - 3rem)); margin-inline: auto; position: relative; z-index: 1; }
.accent-dot { color: var(--accent); }

/* Sections get breathing room + anchor offset */
.section { padding: clamp(6rem, 12vh, 9rem) 0; position: relative; }
[id] { scroll-margin-top: calc(var(--nav-h) + 12px); }

/* ════════════════ PRELOADER ════════════════ */
.preloader {
  position: fixed; inset: 0; z-index: 200;
  background: var(--bg);
  display: grid; place-content: center; gap: 2rem; justify-items: center;
  transition: opacity .7s var(--ease-out), visibility .7s;
}
.preloader.done { opacity: 0; visibility: hidden; }
.preloader__mark { color: var(--ink-faint); }
.preloader .lm-ring { animation: spin 8s linear infinite; transform-origin: 50px 50px; }
.preloader .lm-letters path {
  stroke-dasharray: 220; stroke-dashoffset: 220;
  animation: draw 1.1s var(--ease-snap) forwards;
}
.preloader .lm-letters .lm-stem { animation-delay: .1s; }
.preloader .lm-letters .lm-b { animation-delay: .25s; }
.preloader__bar {
  width: 140px; height: 1px; background: var(--line); overflow: hidden;
}
.preloader__bar span {
  display: block; height: 100%; width: 100%;
  background: var(--accent);
  transform: translateX(-100%);
  animation: load 1s var(--ease-snap) .15s forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes load { to { transform: translateX(0); } }
@keyframes spin { to { transform: rotate(360deg); } }

/* ════════════════ GRAIN / CURSOR / PROGRESS ════════════════ */
/* -12% not -100%: the old value made this layer 9x the viewport area for a
   ±6% drift that needs barely a tenth of that. Same effect, ~1.5x the area. */
.grain {
  position: fixed; inset: -12%; z-index: 120; pointer-events: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.5'/%3E%3C/svg%3E");
  opacity: .045;
  animation: grain 7s steps(8) infinite;
}
@keyframes grain {
  0%, 100% { transform: translate3d(0, 0, 0); }
  25% { transform: translate3d(3%, -6%, 0); }
  50% { transform: translate3d(-5%, 4%, 0); }
  75% { transform: translate3d(6%, 6%, 0); }
}

.cursor, .cursor-ring {
  position: fixed; top: 0; left: 0; z-index: 150; pointer-events: none;
  border-radius: 50%;
  opacity: 0;
}
.cursor {
  width: 7px; height: 7px; background: var(--accent);
  transform: translate(-50%, -50%);
}
.cursor-ring {
  width: 38px; height: 38px;
  border: 1px solid rgba(232, 236, 241, .35);
  transform: translate(-50%, -50%);
  transition: width .3s var(--ease-out), height .3s var(--ease-out),
              border-color .3s, background-color .3s;
}
.cursor-ring.is-hover {
  width: 64px; height: 64px;
  border-color: var(--accent);
  background: rgba(63, 208, 196, .07);
}
@media (hover: hover) and (pointer: fine) {
  .cursor, .cursor-ring { opacity: 1; }
}

.scroll-progress {
  position: fixed; top: 0; left: 0; z-index: 130;
  width: 100%; height: 2px;
  background: linear-gradient(90deg, var(--accent-deep), var(--accent));
  transform-origin: 0 50%;
  transform: scaleX(0);
}

/* ════════════════ NAV ════════════════ */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  height: var(--nav-h);
  display: flex; align-items: center; justify-content: space-between;
  padding-inline: clamp(1.25rem, 4vw, 3rem);
  transition: transform .5s var(--ease-out), background-color .4s, border-color .4s;
  border-bottom: 1px solid transparent;
}
.nav.is-scrolled {
  /* blur radius kept modest and the tint raised to compensate: a
     backdrop-filter re-filters everything behind it on every scroll
     frame, and the cost climbs steeply with the radius */
  background: rgba(6, 9, 14, .86);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  border-bottom-color: var(--line);
}
.nav.is-hidden { transform: translateY(-100%); }
.nav__logo { display: flex; align-items: center; gap: .8rem; color: var(--ink-faint); }
.nav__logo .lm-ring--spin { animation-duration: 18s; }
.nav__logo:hover .lm-ring--spin { animation-duration: 4s; }
.nav__wordmark {
  font-family: var(--font-display); font-weight: 500;
  letter-spacing: .02em; color: var(--ink); font-size: 1.05rem;
}
.nav__links { display: flex; align-items: center; gap: clamp(1.2rem, 2.5vw, 2.4rem); }
.nav__links a {
  position: relative;
  font-family: var(--font-display); font-weight: 400; font-size: .92rem;
  color: var(--ink-dim);
  transition: color .3s;
  padding-block: .35rem;
}
.nav__links a:hover { color: var(--ink); }
.nav__num {
  font-family: var(--font-mono); font-size: .6rem; color: var(--accent);
  vertical-align: super; margin-right: .3rem;
}
.nav__links a:not(.nav__cta)::after {
  content: ""; position: absolute; left: 0; bottom: 0;
  width: 100%; height: 1px; background: var(--accent);
  transform: scaleX(0); transform-origin: 100% 50%;
  transition: transform .45s var(--ease-out);
}
.nav__links a:not(.nav__cta):hover::after { transform: scaleX(1); transform-origin: 0 50%; }
.nav__cta {
  border: 1px solid var(--line);
  padding: .55rem 1.2rem !important; border-radius: 999px;
  color: var(--ink) !important;
  transition: border-color .3s, background-color .3s, color .3s;
}
.nav__cta:hover { border-color: var(--accent); background: rgba(63, 208, 196, .08); }
.nav__burger { display: none; }

/* Mobile nav */
@media (max-width: 820px) {
  .nav__links {
    position: fixed; inset: 0; z-index: -1;
    flex-direction: column; justify-content: center; gap: 2.2rem;
    background: rgba(6, 9, 14, .96);
    -webkit-backdrop-filter: blur(20px);
    backdrop-filter: blur(20px);
    opacity: 0; visibility: hidden;
    transition: opacity .45s var(--ease-out), visibility .45s;
  }
  .nav__links a { font-size: 1.6rem; opacity: 0; transform: translateY(18px);
    transition: opacity .5s var(--ease-out), transform .5s var(--ease-out), color .3s; }
  .nav__links.is-open { opacity: 1; visibility: visible; }
  .nav__links.is-open a { opacity: 1; transform: none; }
  .nav__links.is-open a:nth-child(1) { transition-delay: .08s; }
  .nav__links.is-open a:nth-child(2) { transition-delay: .14s; }
  .nav__links.is-open a:nth-child(3) { transition-delay: .2s; }
  .nav__links.is-open a:nth-child(4) { transition-delay: .26s; }
  .nav__links.is-open a:nth-child(5) { transition-delay: .32s; }
  .nav__burger {
    display: grid; gap: 6px; padding: .6rem; z-index: 10;
    min-width: 44px; min-height: 44px;
    place-content: center;
  }
  .nav__burger span {
    display: block; width: 26px; height: 1.6px; background: var(--ink);
    transition: transform .4s var(--ease-snap);
  }
  .nav__burger[aria-expanded="true"] span:first-child { transform: translateY(3.8px) rotate(45deg); }
  .nav__burger[aria-expanded="true"] span:last-child { transform: translateY(-3.8px) rotate(-45deg); }
}

/* ════════════════ HERO ════════════════ */
.hero {
  position: relative; min-height: 100svh;
  display: flex; align-items: center;
  overflow: hidden;
  /* shared by the headline and the monogram beside it, so the two
     always stay the same size — see .hero__mark */
  --hero-fs: clamp(4rem, 14vw, 10.5rem);
  --hero-lh: .92;
}
.hero__bg { position: absolute; inset: 0; z-index: -2; }
.hero__bg img {
  width: 100%; height: 115%; object-fit: cover; object-position: 70% 30%;
  animation: kenburns 18s var(--ease-out) forwards;
  will-change: transform;
}
@keyframes kenburns { from { transform: scale(1.12); } to { transform: scale(1.02); } }
.hero__veil {
  position: absolute; inset: 0; z-index: -1;
  background:
    linear-gradient(75deg, rgba(6, 9, 14, .92) 18%, rgba(6, 9, 14, .55) 46%, rgba(6, 9, 14, .12) 75%),
    linear-gradient(to top, var(--bg) 2%, transparent 26%),
    linear-gradient(to bottom, rgba(6, 9, 14, .55), transparent 30%);
}
.hero__content {
  width: min(1200px, calc(100% - 3rem)); margin-inline: auto;
  padding-top: var(--nav-h);
  position: relative; z-index: 2;
}
/* Monogram to the left of the headline, matched to the height of the
   two title lines. align-self:stretch takes the height from the flex
   row; aspect-ratio then derives the width, so it stays square. */
.hero__headline { display: flex; align-items: stretch; gap: clamp(.9rem, 2vw, 1.8rem); }
.hero__mark {
  flex: none;
  align-self: center;
  /* two title lines tall: font-size x line-height x 2 */
  width: calc(var(--hero-fs) * var(--hero-lh) * 2);
  height: calc(var(--hero-fs) * var(--hero-lh) * 2);
  pointer-events: none;
  animation: mark-in 1.4s var(--ease-out) .5s both, mark-float 9s ease-in-out 2.2s infinite;
}
.hero__mark .logo-mark { display: block; width: 100%; height: 100%; }
@keyframes mark-in {
  from { opacity: 0; transform: scale(.84) rotate(-8deg); }
  to { opacity: 1; transform: none; }
}
@keyframes mark-float {
  0%, 100% { transform: translateY(0) scale(1); }
  50% { transform: translateY(-10px) scale(1.02); }
}
@media (max-width: 560px) { .hero__mark { display: none; } }
.hero__eyebrow { display: flex; align-items: center; gap: .7rem; margin-bottom: 1.6rem; color: var(--ink-dim); }
.pulse-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  box-shadow: 0 0 0 0 var(--accent-glow);
  animation: pulse 2.4s infinite;
  flex: none;
}
@keyframes pulse {
  0% { box-shadow: 0 0 0 0 var(--accent-glow); }
  70% { box-shadow: 0 0 0 12px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }
}
.hero__title {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: var(--hero-fs);
  line-height: var(--hero-lh);
  letter-spacing: -.03em;
  text-transform: uppercase;
  margin-left: -.05em;
}
.hero__line { display: block; overflow: hidden; padding-bottom: .06em; margin-bottom: -.06em; }
/* --ci is a single running index across RYAN + BORG (set in main.js),
   so the colour wave sweeps R→Y→A→N→B→O→R→G as one continuous pass. */
.char {
  display: inline-block;
  transform: translateY(110%) rotate(6deg);
  animation:
    char-in 1s var(--ease-out) forwards,
    char-wave 7s ease-in-out infinite;
  animation-delay: calc(.35s + var(--ci) * .07s), calc(1.9s + var(--ci) * .42s);
}
@keyframes char-in { to { transform: translateY(0) rotate(0); } }
/* colour runs through the name letter by letter, forever */
@keyframes char-wave {
  0%, 100% { color: var(--ink); text-shadow: none; }
  6% { color: var(--accent); text-shadow: 0 0 28px var(--accent-glow); }
  17% { color: var(--ink); text-shadow: none; }
}
.hero__line--accent .char {
  color: transparent; -webkit-text-stroke: 1.5px var(--ink);
  animation:
    char-in 1s var(--ease-out) forwards,
    char-wave-stroke 7s ease-in-out infinite;
  animation-delay: calc(.35s + var(--ci) * .07s), calc(1.9s + var(--ci) * .42s);
}
@keyframes char-wave-stroke {
  0%, 100% { -webkit-text-stroke-color: var(--ink); color: transparent; }
  6% { -webkit-text-stroke-color: var(--accent); color: rgba(63, 208, 196, .28); }
  17% { -webkit-text-stroke-color: var(--ink); color: transparent; }
}
.hero__sub {
  max-width: 34rem; margin-top: 2rem;
  font-size: clamp(1.05rem, 1.6vw, 1.25rem);
  color: var(--ink-dim); font-weight: 300;
}
.hero__sub em { color: var(--ink); border-bottom: 1px solid var(--accent-deep); }
.hero__actions { display: flex; flex-wrap: wrap; gap: 1rem; margin-top: 2.6rem; }

.hero__meta {
  position: absolute; right: clamp(1.25rem, 4vw, 3rem); bottom: 2.4rem;
  display: flex; align-items: center; gap: .9rem;
  color: var(--ink-faint);
}
.hero__meta-line { width: 52px; height: 1px; background: var(--line); }
.hero__scroll {
  position: absolute; left: clamp(1.25rem, 4vw, 3rem); bottom: 2.1rem;
  display: flex; align-items: center; gap: .8rem;
  color: var(--ink-faint);
}
.hero__scroll-track {
  width: 1px; height: 44px; background: var(--line);
  position: relative; overflow: hidden; display: block;
}
.hero__scroll-thumb {
  position: absolute; left: 0; top: 0; width: 100%; height: 40%;
  background: var(--accent);
  animation: scroll-hint 2s var(--ease-snap) infinite;
  display: block;
}
@keyframes scroll-hint {
  0% { transform: translateY(-110%); }
  60%, 100% { transform: translateY(260%); }
}
@media (max-width: 640px) {
  .hero__meta { display: none; }
}

/* ── Buttons ── */
.btn {
  display: inline-flex; align-items: center; gap: .6rem;
  font-family: var(--font-display); font-weight: 500; font-size: .95rem;
  padding: .9rem 1.7rem; border-radius: 999px;
  position: relative; overflow: hidden;
  transition: color .35s var(--ease-out), border-color .35s, box-shadow .35s, background-color .35s;
  will-change: transform;
}
.btn svg { transition: transform .35s var(--ease-out); }
.btn:hover svg { transform: translateX(4px); }
.btn--solid { background: var(--ink); color: #0b1016; }
.btn--solid::before {
  content: ""; position: absolute; inset: 0; z-index: -1; border-radius: inherit;
  background: linear-gradient(100deg, var(--accent-deep), var(--accent));
  transform: translateY(101%);
  transition: transform .45s var(--ease-out);
}
.btn--solid:hover { color: #04211e; box-shadow: 0 8px 32px -8px var(--accent-glow); }
.btn--solid:hover::before { transform: translateY(0); }
.btn--ghost { border: 1px solid var(--line); color: var(--ink); }
.btn--ghost:hover { border-color: var(--accent); background: rgba(63, 208, 196, .07); }

/* ════════════════ MARQUEE ════════════════ */
.marquee {
  border-block: 1px solid var(--line);
  background: var(--bg-2);
  overflow: hidden; white-space: nowrap;
  padding: 1.1rem 0;
  position: relative; z-index: 2;
}
.marquee__inner { display: inline-flex; animation: marquee 58s linear infinite; will-change: transform; }
.marquee span {
  font-family: var(--font-display); font-weight: 500;
  font-size: 1.05rem; letter-spacing: .18em; text-transform: uppercase;
  color: rgba(242, 245, 248, .95);
  padding-right: .5rem;
}
.marquee i { color: var(--accent); font-style: normal; margin: 0 1.1rem; }
@keyframes marquee { to { transform: translateX(-50%); } }

/* ════════════════ GEOMETRIC MESH ════════════════
   A single fixed layer behind the whole page rather than one per section —
   per-section layers made the pattern restart at every boundary, which read
   as a seam. Because it is fixed it holds still while the content scrolls;
   main.js adds a slow counter-shift on top for parallax depth.
   Oversized by 20% so the parallax offset never exposes an edge. */
/* Split into two layers on purpose. Animating background-position forces a
   full repaint of the layer on every frame, which is what made scrolling
   stutter. Both layers now animate transform only, so each is rastered once
   and the compositor just moves it.
   .mesh        — fixed, masked, carries the scroll parallax (vertical only,
                  hence the vertical-only overhang)
   .mesh__drift — oversized by one whole tile and translated by exactly that
                  tile, so the drift loops with no visible jump */
.mesh {
  position: fixed; inset: -280px 0; z-index: 0;
  pointer-events: none;
  overflow: hidden;
  opacity: .2;
  will-change: transform;
  -webkit-mask-image: radial-gradient(135% 105% at 50% 45%, #000 30%, transparent 88%);
  mask-image: radial-gradient(135% 105% at 50% 45%, #000 30%, transparent 88%);
}
.mesh__drift {
  position: absolute; top: 0; left: 0;
  width: calc(100% + 700px); height: calc(100% + 700px);
  background-image: url(../assets/pattern.svg);
  background-size: 680px 680px;
  animation: pattern-drift 120s linear infinite;
  will-change: transform;
}
@keyframes pattern-drift { to { transform: translate3d(-680px, -680px, 0); } }
/* The hero owns its own photo, so keep the mesh out of it: isolate makes
   the hero a stacking context and stops its negative-z children falling
   behind the fixed layer. */
.hero { isolation: isolate; }

/* ════════════════ AURORA GLOW ════════════════ */
.aurora { position: absolute; inset: 0; overflow: hidden; pointer-events: none; }
.aurora span {
  position: absolute; border-radius: 50%;
  filter: blur(90px);
  opacity: .5;
  will-change: transform;
}
.aurora span:first-child {
  width: 46vw; height: 46vw; max-width: 640px; max-height: 640px;
  left: -12%; top: -10%;
  background: radial-gradient(circle, rgba(63, 208, 196, .10), transparent 65%);
  animation: aurora-a 22s ease-in-out infinite alternate;
}
.aurora span:last-child {
  width: 38vw; height: 38vw; max-width: 540px; max-height: 540px;
  right: -10%; bottom: -14%;
  background: radial-gradient(circle, rgba(56, 120, 210, .09), transparent 65%);
  animation: aurora-b 26s ease-in-out infinite alternate;
}
/* translate only — animating scale on a 90px-blurred layer can force it to
   be re-rasterised at every step instead of just being moved */
@keyframes aurora-a {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(14vw, 12vh, 0); }
}
@keyframes aurora-b {
  from { transform: translate3d(0, 0, 0); }
  to { transform: translate3d(-12vw, -10vh, 0); }
}

/* ════════════════ SECTION HEADS ════════════════ */
.section__head { margin-bottom: clamp(3rem, 6vh, 4.5rem); position: relative; }
.section__num {
  display: block; color: var(--accent); margin-bottom: 1rem;
}
.section__num::after {
  content: ""; display: inline-block; vertical-align: middle;
  width: 64px; height: 1px; background: var(--line); margin-left: 1rem;
}
.section__title {
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(2.4rem, 5.5vw, 4rem);
  letter-spacing: -.02em; line-height: 1.05;
}
.section__intro {
  margin-top: 1.1rem; color: var(--ink-dim); max-width: 36rem; font-size: 1.05rem;
  text-wrap: pretty;
}

/* ════════════════ ABOUT ════════════════ */
.about { background: transparent; }
.about__grid {
  display: grid; grid-template-columns: minmax(280px, 420px) 1fr;
  gap: clamp(2.5rem, 6vw, 5.5rem); align-items: start;
}
.about__frame {
  position: relative; border-radius: var(--radius); overflow: hidden;
  transform-style: preserve-3d;
  clip-path: inset(100% 0 0 0 round var(--radius));
  transition: clip-path 1.2s var(--ease-out) .15s;
}
.about__media.in .about__frame { clip-path: inset(0 0 0 0 round var(--radius)); }
.about__frame img {
  width: 100%; aspect-ratio: 4 / 5; object-fit: cover; object-position: 50% 22%;
  /* monochrome by default — colour returns on hover */
  filter: grayscale(1) contrast(1.12) brightness(.92);
  transition: transform 1s var(--ease-out), filter 1.1s var(--ease-out);
}
/* stays monochrome always — only a gentle push-in on hover */
@media (hover: hover) and (pointer: fine) {
  .about__frame:hover img { transform: scale(1.04); }
}
/* teal duotone wash sitting over the greyscale */
.about__frame-tint {
  position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(158deg, rgba(63, 208, 196, .30), rgba(12, 28, 44, .55) 70%);
  mix-blend-mode: color;
  opacity: 1;
  transition: opacity 1.1s var(--ease-out);
}
/* faint scanlines — subtle tech texture, invisible until you look */
.about__frame-scan {
  position: absolute; inset: 0; pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(255, 255, 255, .035) 0 1px,
    transparent 1px 4px
  );
  opacity: .8;
  transition: opacity .8s;
}
.about__frame-ring {
  position: absolute; inset: 14px; border: 1px solid rgba(232, 236, 241, .3);
  border-radius: calc(var(--radius) - 8px);
  pointer-events: none;
  z-index: 2;
}
.about__frame::after {
  content: ""; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(to top, rgba(6, 9, 14, .5), transparent 45%);
  pointer-events: none;
}
.about__caption { margin-top: 1rem; text-align: center; }
.about__lead {
  font-family: var(--font-display); font-weight: 400;
  font-size: clamp(1.4rem, 2.6vw, 1.9rem); line-height: 1.4;
  margin-bottom: 1.6rem; color: var(--ink);
}
.about__body p:not(.about__lead) { color: var(--ink-dim); margin-bottom: 1.2rem; max-width: 42rem; }
.about__body strong { color: var(--ink); font-weight: 500; }
.about__thanks {
  margin-top: 1.6rem;
  padding-left: 1.1rem;
  border-left: 2px solid var(--accent-deep);
  color: var(--ink-dim);
  max-width: 42rem;
  text-wrap: pretty;
}
.about__thanks strong { color: var(--accent); font-weight: 500; }
.about__facts {
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem;
  margin-top: 2.6rem; padding-top: 2.2rem; border-top: 1px solid var(--line);
}
.about__facts li {
  display: flex; flex-direction: column; align-items: center; gap: .55rem;
  text-align: center;
  padding: 1.5rem 1rem;
  background: linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--line); border-radius: 14px;
  color: var(--ink-dim); font-size: .74rem; letter-spacing: .14em; text-transform: uppercase;
  transition: border-color .4s var(--ease-out), transform .5s var(--ease-out);
}
.about__facts li:hover {
  border-color: rgba(63, 208, 196, .32);
  transform: translateY(-5px);
}
.about__facts .mono {
  font-size: clamp(2rem, 3.2vw, 2.8rem); color: var(--accent);
  letter-spacing: 0; line-height: 1;
  font-variant-numeric: tabular-nums; /* stops the count-up jittering */
  display: block;
}
/* the counters re-run on a loop; the infinity mark turns forever */
/* 4s matches the JS roll cycle (800ms roll + 3200ms hold) so the glow
   lands on the moment the digit settles */
.about__facts .mono[data-count] { animation: fact-pulse 4s ease-in-out infinite; }
@keyframes fact-pulse {
  0%, 12% { text-shadow: none; }
  20% { text-shadow: 0 0 26px var(--accent-glow); }
  45%, 100% { text-shadow: none; }
}
/* Infinity drawn as a real lemniscate path so a light can travel along it.
   pathLength="100" normalises the geometry, so the dash values below are
   simply percentages of the loop regardless of the path's real length. */
.fact-infinity {
  display: block;
  /* same layout box as the numerals so all three labels stay on one line;
     the scale makes it read larger without shifting anything */
  height: clamp(2rem, 3.2vw, 2.8rem);
  width: auto; aspect-ratio: 2 / 1;
  overflow: visible;
  transform: scale(1.22);
}
.fact-infinity path { fill: none; stroke-linecap: round; stroke-width: 7; }
.fi-base { stroke: rgba(63, 208, 196, .25); }
.fi-run {
  stroke: var(--accent);
  stroke-dasharray: 16 84;
  filter: drop-shadow(0 0 5px var(--accent-glow));
  animation: fi-run 3.4s linear infinite;
}
@keyframes fi-run { to { stroke-dashoffset: -100; } }
/* stop repainting the filtered stroke while the row is off screen */
.about__facts.is-idle .fi-run,
.about__facts.is-idle .mono[data-count] { animation-play-state: paused; }
@media (max-width: 420px) {
  .about__facts { gap: .6rem; }
  .about__facts li { padding: 1.1rem .5rem; font-size: .62rem; letter-spacing: .08em; }
}
@media (max-width: 860px) {
  .about__grid { grid-template-columns: 1fr; }
  .about__media { max-width: 400px; }
}

/* ════════════════ SERVICES ════════════════ */
/* transparent so the one fixed mesh reads continuously through the page —
   no fills or borders that would draw a line between sections */
.services { background: transparent; }
.services__grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(290px, 1fr));
  gap: 1.4rem;
}
.card {
  position: relative; overflow: hidden;
  background: linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 2.2rem 1.9rem 2rem;
  transform-style: preserve-3d;
  transition: border-color .4s;
}
.card:hover { border-color: rgba(63, 208, 196, .35); }
.card__glow {
  position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(420px circle at var(--mx, 50%) var(--my, 50%), rgba(63, 208, 196, .12), transparent 65%);
  transition: opacity .4s;
}
.card:hover .card__glow { opacity: 1; }
.card__num {
  position: absolute; top: 1.6rem; right: 1.8rem;
  color: var(--ink-faint); font-size: .8rem;
}
.card__icon {
  width: 52px; height: 52px; color: var(--accent);
  display: grid; place-content: center;
  border: 1px solid var(--line); border-radius: 14px;
  margin-bottom: 1.6rem;
  background: rgba(63, 208, 196, .05);
  transition: transform .5s var(--ease-out), background-color .4s;
}
.card__icon svg { width: 28px; height: 28px; }
.card:hover .card__icon { transform: translateY(-4px) rotate(-4deg); background: rgba(63, 208, 196, .12); }
.card__title {
  font-family: var(--font-display); font-weight: 500;
  font-size: 1.35rem; letter-spacing: -.01em; margin-bottom: .8rem;
}
.card__text { color: var(--ink-dim); font-size: .96rem; margin-bottom: 1.5rem; }
.card__num { font-weight: 500; }
.card__tags { display: flex; flex-wrap: wrap; gap: .5rem; }
.card__tags li {
  font-size: .66rem; padding: .38rem .75rem;
  border: 1px solid var(--line); border-radius: 999px;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s;
}
.card:hover .card__tags li { border-color: rgba(63, 208, 196, .3); color: var(--ink); }

/* ════════════════ MALTA INTERLUDE ════════════════ */
.interlude {
  position: relative; overflow: hidden;
  min-height: 82svh;
  display: flex; align-items: center;
}
.interlude__bg { position: absolute; inset: -12% 0; z-index: 0; }
.interlude__bg img,
.interlude__bg video {
  width: 100%; height: 100%; object-fit: cover;
  will-change: transform;
  background: var(--bg-2);
}
/* Both ends resolve to var(--bg) — the exact colour of the transparent
   sections above and below — so the video dissolves into the page instead
   of stopping at a visible edge. The old gradient ended on --bg-2, and that
   mismatch was the line. Long ramps keep the blend gradual. */
.interlude__veil {
  position: absolute; inset: 0; z-index: 1;
  background:
    linear-gradient(to bottom,
      var(--bg) 0%,
      rgba(6, 9, 14, .97) 7%,
      rgba(6, 9, 14, .55) 20%,
      rgba(6, 9, 14, .3) 42%,
      rgba(6, 9, 14, .3) 58%,
      rgba(6, 9, 14, .55) 80%,
      rgba(6, 9, 14, .97) 93%,
      var(--bg) 100%),
    radial-gradient(65% 80% at 30% 55%, rgba(4, 12, 16, .5), transparent 70%);
}
.interlude__quote { position: relative; z-index: 2; }
.interlude__quote p {
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.7rem, 4.4vw, 3.3rem);
  line-height: 1.25; letter-spacing: -.01em;
  max-width: 22ch;
  text-shadow: 0 2px 30px rgba(4, 10, 14, .7);
}
.interlude__quote em { color: var(--accent); }
.interlude__quote footer { margin-top: 2rem; color: rgba(242, 245, 248, .9); }

/* ════════════════ PORTFOLIO ════════════════ */
.portfolio { background: transparent; }
.portfolio__grid {
  display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
  gap: 1.4rem;
}
.pcard {
  position: relative; overflow: hidden;
  display: flex; flex-direction: column; gap: 1.3rem;
  background: linear-gradient(160deg, var(--bg-3), var(--bg-2));
  border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.9rem 1.7rem 1.7rem;
  transition: border-color .4s, transform .5s var(--ease-out), box-shadow .5s;
}
.pcard:hover {
  border-color: rgba(63, 208, 196, .4);
  transform: translateY(-6px);
  box-shadow: 0 24px 48px -24px rgba(0, 0, 0, .6);
}
.pcard__logo {
  height: 78px; border-radius: 12px;
  display: flex; align-items: center;
  border: 1px solid var(--line);
  background: rgba(232, 236, 241, .03);
  overflow: hidden;
  padding: 16px 18px;
  transition: transform .5s var(--ease-out), border-color .4s;
}
.pcard:hover .pcard__logo { transform: scale(1.03); border-color: rgba(63, 208, 196, .25); }
.pcard__logo img {
  max-height: 100%; max-width: 100%; width: auto; object-fit: contain;
  transition: filter .4s;
}
/* logos whose original colours vanish on dark get rendered pure white */
.pcard__logo--mono img { filter: brightness(0) invert(1); opacity: .92; }
.pcard__initial {
  font-family: var(--font-display); font-weight: 600; font-size: 1.5rem;
  color: var(--accent);
}
.pcard__name {
  font-family: var(--font-display); font-weight: 500; font-size: 1.15rem;
  display: flex; align-items: center; gap: .5rem;
}
.pcard__name svg { opacity: 0; transform: translate(-4px, 4px); transition: opacity .3s, transform .4s var(--ease-out); flex: none; color: var(--accent); }
.pcard:hover .pcard__name svg { opacity: 1; transform: translate(0, 0); }
.pcard__desc { color: var(--ink-dim); font-size: .88rem; flex: 1; }
.pcard__tag { align-self: flex-start; font-size: .64rem; color: var(--accent);
  border: 1px solid rgba(63, 208, 196, .35); border-radius: 999px; padding: .32rem .75rem; }
.pcard--soon { pointer-events: none; border-style: dashed; }
.pcard--soon .pcard__name, .pcard--soon .pcard__desc { opacity: .82; }
.pcard--soon .pcard__tag { color: var(--ink-faint); border-color: var(--line); }
/* animated hazard strip standing in for a logo */
.pcard__strip {
  height: 78px; border-radius: 12px;
  border: 1px solid var(--line);
  display: flex; align-items: center;
  overflow: hidden;
  background: repeating-linear-gradient(
    -45deg,
    rgba(63, 208, 196, .09) 0 10px,
    transparent 10px 22px
  );
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
.pcard__strip span {
  white-space: nowrap;
  font-family: var(--font-mono); font-size: .68rem;
  letter-spacing: .3em; text-transform: uppercase;
  color: var(--accent);
  opacity: .75;
  animation: strip-scroll 40s linear infinite;
}
@keyframes strip-scroll { to { transform: translateX(-50%); } }

/* ════════════════ CONTACT ════════════════ */
.contact { overflow: hidden; background: transparent; }
.contact__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.contact__bg img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: .2;
  filter: grayscale(.25) contrast(1.05);
  animation: contact-drift 38s ease-in-out infinite alternate;
  will-change: transform;
}
@keyframes contact-drift {
  from { transform: scale(1.1) translate(1.5%, 1%); }
  to { transform: scale(1.22) translate(-1.5%, -2%); }
}
.contact__bg-veil {
  position: absolute; inset: 0; display: block;
  background:
    linear-gradient(to bottom, var(--bg) 0%, rgba(6, 9, 14, .62) 38%, rgba(6, 9, 14, .72) 62%, var(--bg) 100%),
    radial-gradient(70% 60% at 50% 50%, rgba(6, 9, 14, .5), transparent 75%);
}
.contact .section__head { text-align: center; }
.contact .section__intro { margin-inline: auto; max-width: 40rem; text-wrap: balance; }
.contact .section__num::after { display: none; }
.contact__center {
  display: flex; flex-direction: column; align-items: center; text-align: center;
  gap: 2.2rem;
}
.contact__blurb {
  color: var(--ink-dim); max-width: 40rem;
  text-wrap: balance; /* avoids a lone word stranded on the last line */
}
.contact__reveal { min-height: 72px; display: grid; place-items: center; }
.contact__reveal-btn { font-size: 1.05rem; padding: 1.05rem 2.1rem; }
.contact__revealed {
  display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap; justify-content: center;
  animation: reveal-pop .6s var(--ease-out);
}
@keyframes reveal-pop {
  from { opacity: 0; transform: translateY(14px) scale(.96); filter: blur(6px); }
  to { opacity: 1; transform: none; filter: none; }
}
.contact__mail {
  display: inline-flex; align-items: center; gap: .7rem;
  font-family: var(--font-display); font-weight: 500;
  font-size: clamp(1.4rem, 3vw, 2.2rem);
  color: var(--ink);
  border-bottom: 1px solid var(--line);
  padding-bottom: .4rem;
  transition: color .3s, border-color .3s;
}
.contact__mail:hover { color: var(--accent); border-color: var(--accent); }
.contact__mail svg { transition: transform .35s var(--ease-out); }
.contact__mail:hover svg { transform: translate(3px, -3px); }
.contact__copy {
  border: 1px solid var(--line); border-radius: 999px;
  padding: .55rem 1.2rem;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s, background-color .3s;
}
.contact__copy:hover { border-color: var(--accent); color: var(--accent); background: rgba(63, 208, 196, .07); }
.contact__loc { display: flex; align-items: center; gap: .7rem; }

/* ════════════════ FOOTER ════════════════ */
.footer {
  position: relative;
  background: transparent;
  border-top: 1px solid var(--line);
  padding-bottom: 2.5rem;
  overflow: hidden;
}
.footer__word {
  overflow: hidden; white-space: nowrap;
  border-bottom: 1px solid var(--line);
  padding: 1.2rem 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
/* two identical halves side by side; shifting the track by exactly half
   its width lands copy 2 where copy 1 began, so the loop never shows a seam */
.footer__word-track {
  display: inline-flex;
  animation: marquee-word 42s linear infinite;
  will-change: transform;
}
.footer__word-half {
  flex: none;
  display: inline-block; white-space: nowrap;
  font-family: var(--font-display); font-weight: 600;
  font-size: clamp(3rem, 8vw, 6rem);
  letter-spacing: -.02em;
  color: transparent;
  -webkit-text-stroke: 1.2px #ffffff;
}
@keyframes marquee-word { to { transform: translateX(-50%); } }
/* colour "types" through the letters, same idea as the hero name;
   at rest the outline stays solid white so the word is always legible */
.fw-char {
  display: inline-block;
  animation: fw-wave 6s ease-in-out infinite;
  animation-delay: calc(var(--fi) * .15s);
}
@keyframes fw-wave {
  0%, 100% { -webkit-text-stroke-color: #ffffff; color: transparent; }
  7% { -webkit-text-stroke-color: var(--accent); color: rgba(63, 208, 196, .32); }
  19% { -webkit-text-stroke-color: #ffffff; color: transparent; }
}
.footer__row {
  display: grid; grid-template-columns: 1fr auto 1fr;
  gap: 2rem; align-items: center;
  padding-top: 3rem;
}
.footer__brand { display: flex; align-items: center; gap: 1.1rem; color: var(--ink-faint); }
.footer__brand .mono { text-transform: none; letter-spacing: .04em; line-height: 1.6; }
.lm-ring--spin { animation: spin 24s linear infinite; transform-origin: 50px 50px; }
.lm-ring--spin-rev { animation: spin 16s linear infinite reverse; transform-origin: 50px 50px; }
.footer__links { display: flex; gap: .4rem 1.8rem; flex-wrap: wrap; justify-content: center; }
/* padding keeps these above the 44px minimum touch target */
.footer__links a { transition: color .3s; padding: .6rem .35rem; }
.footer__links a:hover { color: var(--accent); }
.footer__copy { text-align: right; text-transform: none; letter-spacing: .04em; line-height: 1.8; }
.footer__credit {
  color: var(--accent);
  display: inline-block; padding-block: .35rem;
  white-space: nowrap; /* keep the company name on one line */
  border-bottom: 1px solid transparent;
  transition: border-color .3s, color .3s;
}
.footer__credit:hover { border-bottom-color: var(--accent); }
.back-top {
  position: absolute; right: clamp(1.25rem, 4vw, 3rem); bottom: 2.5rem;
  width: 46px; height: 46px; border-radius: 50%;
  border: 1px solid var(--line);
  display: grid; place-content: center;
  color: var(--ink-dim);
  transition: border-color .3s, color .3s, background-color .3s;
}
.back-top:hover { border-color: var(--accent); color: var(--accent); background: rgba(63, 208, 196, .07); }
@media (max-width: 860px) {
  .footer__row { grid-template-columns: 1fr; justify-items: center; text-align: center; gap: 1.6rem; }
  .footer__copy { text-align: center; }
  .back-top { position: static; margin: 1.5rem auto 0; display: grid; }
}

/* ════════════════ REVEAL SYSTEM ════════════════ */
.reveal-up {
  opacity: 0;
  transform: translateY(42px);
  filter: blur(6px);
  transition:
    opacity .9s var(--ease-out) var(--d, 0s),
    transform .9s var(--ease-out) var(--d, 0s),
    filter .9s var(--ease-out) var(--d, 0s);
  will-change: opacity, transform, filter;
}
.reveal-up.in { opacity: 1; transform: none; filter: none; }

/* Hero entrance handled separately (plays on load, not on scroll) */
.hero .reveal-up {
  animation: hero-in 1s var(--ease-out) forwards;
  animation-delay: var(--d, 0s);
  transition: none;
}
@keyframes hero-in {
  to { opacity: 1; transform: none; filter: none; }
}

/* ════════════════ PARAGRAPH TYPOGRAPHY ════════════════
   Running body copy is justified with hyphenation, which looks tight and
   even at this measure. The card columns are only ~240–310px wide: at that
   width justification stretches word gaps to several times their natural
   size and opens "rivers" down the paragraph, so those stay ragged-right
   with text-wrap:pretty, which evens the line lengths without stretching. */
.about__body p:not(.about__lead) {
  text-align: justify;
  text-wrap: pretty; /* stops a single word widowing onto the last line */
  -webkit-hyphens: auto;
  hyphens: auto;
  hyphenate-limit-chars: 7 3 3;
}
.card__text, .pcard__desc {
  text-wrap: pretty;
  -webkit-hyphens: auto;
  hyphens: auto;
  hyphenate-limit-chars: 9 4 4;
}
.about__lead, .hero__sub, .section__intro, .contact__blurb {
  text-wrap: balance;
}

/* Section titles decode with a scramble effect (JS adds .scrambling) */
.section__title { min-height: 1.05em; }

/* Marquee + interlude quote skew with scroll velocity (JS-driven) */
.marquee, .footer__word { transition: transform .25s ease-out; will-change: transform; }

/* ════════════════ REDUCED MOTION ════════════════ */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .001s !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001s !important;
  }
  .reveal-up, .hero .reveal-up, .char { opacity: 1 !important; transform: none !important; filter: none !important; }
  .cursor, .cursor-ring, .grain { display: none; }
}
