/* ==========================================================================
   Connexions x Batumi - generated stylesheet. DO NOT EDIT.
   Built by tools/build.py from 17 modules in src/css/modules/.
   Edit the module, then re-run the build.
   ========================================================================== */

/* --- src/css/modules/01-tokens.css --- */
/* ==========================================================================
   Design tokens and global reset.

   Every colour, blur value and layout width used anywhere on the site is
   declared here as a custom property. Changing a brand colour is therefore a
   one-line edit in this file, never a search-and-replace across the codebase.
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }

/* Snapping applies to the pinned story sections on pointer devices only, where
   one trackpad flick could otherwise carry the reader past three slides. On
   touch screens the sections are not pinned at all (see 06-story.css) and any
   snapping would only get in the way of the phone's own scrolling. */
@media (min-width: 701px) {
  html { scroll-snap-type: y proximity; }
}
body { font-family: 'Manrope', sans-serif; color: var(--ink); background: #051216; }
img { display: block; max-width: 100%; }

:root {
  /* Photos fade into this colour at their top and bottom edges so that the
     boundary between two stacked sections never shows a hard seam. */
  --seam: #051216;
  --batumi: #14B991;   /* teal used for the Batumi wordmark and all trip UI */
  /* palette */
  --azure: #1C86B0;
  --azure-light: #6FD6E8;
  --jade: #1F7A5C;
  --mint: #8FE3C0;
  --ink: #0A2530;
  --gold: #C9A24D;

  /* glass */
  --glass-bg: rgba(255, 255, 255, 0.10);
  --glass-border: rgba(255, 255, 255, 0.22);

  /* layout */
  --container: 1040px;
  --container-wide: 1360px;
  --gutter: 40px;
}

/* --- src/css/modules/02-layout.css --- */
/* ==========================================================================
   Layout helpers: page width containers, section padding and scrim overlays
   shared by every page.
   ========================================================================== */
.wrap {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
.wrap-wide {
  width: 100%;
  max-width: var(--container-wide);
  margin: 0 auto;
  padding: 0 var(--gutter);
}
@media (max-width: 700px) {
  :root { --gutter: 24px; }
}

.scene {
  position: relative;
  background-size: cover;
  background-position: center;
  background-attachment: fixed;
  padding: 170px 0;
  overflow: hidden;
}
@media (max-width: 800px) {
  .scene { background-attachment: scroll; padding: 110px 0; }
}
.scene::before { content: ''; position: absolute; inset: 0; z-index: 1; }
.scene.scrim-deep::before {
  background: linear-gradient(180deg, rgba(4,20,26,.88) 0%, rgba(5,26,30,.80) 30%, rgba(4,22,26,.85) 70%, rgba(3,16,20,.92) 100%);
}
.scene > .wrap, .scene > .wrap-wide { position: relative; z-index: 2; }

/* --- src/css/modules/03-nav.css --- */
/* ==========================================================================
   Sticky top navigation, brand lockup and the projects dropdown.
   ========================================================================== */
.nav {
  position: fixed; top: 20px; left: 50%; transform: translateX(-50%);
  z-index: 50;
  width: calc(100% - 56px); max-width: 1100px;
  display: flex; align-items: center; justify-content: space-between;
  padding: 10px 22px;
  border-radius: 20px;
  background: var(--glass-bg);
  border: 1px solid var(--glass-border);
  backdrop-filter: blur(18px) saturate(160%);
  -webkit-backdrop-filter: blur(18px) saturate(160%);
  box-shadow: 0 8px 32px rgba(0,0,0,.18);
  transition: box-shadow .3s ease;
}
.nav--scrolled { box-shadow: 0 8px 32px rgba(0,0,0,.32); }
/* Official brand lockup, supplied by the client as one finished file (icon,
   BATUMI, REALITY). The artwork itself is never edited, only scaled and, for
   this dark glass bar, swapped for the white-on-dark colour variant of the
   same file (logo-batumi-reality-ondark.svg vs. the plain one used on light
   backgrounds). The lockup is stacked rather than side-by-side, so the bar
   is a little taller than a typical slim nav to keep it legible. */
.nav__brand { display: flex; align-items: center; }
.nav__logo { height: 54px; width: auto; display: block; }
@media (max-width: 560px) { .nav__logo { height: 44px; } }
/* align-items keeps the <button> ("Projekty") level with the <a> elements
   around it. Without it the flex items line up on their baselines, and the
   button's box is a couple of pixels shorter, so its label sat lower than the
   rest and the menu read as a staircase. */
.nav__links { display: flex; align-items: center; gap: 28px; }
.nav__links a { color: rgba(255,255,255,.88); text-decoration: none; font-size: 14px; font-weight: 500; transition: opacity .2s; }
.nav__links a:hover { opacity: .65; }
@media (max-width: 760px) { .nav__links { display: none; } }

/* Projects dropdown. On desktop it opens on hover and on click; on touch
   devices click is the only option, which is why the trigger is a real
   <button> rather than a pure CSS hover. */
.nav__trip { color: var(--batumi) !important; font-weight: 700; }
.nav__drop { position: relative; }
/* Invisible bridge across the gap between trigger and panel. Without it the
   pointer leaves the element on its way down and the menu closes before it
   can be clicked. */
.nav__drop.is-open::after {
  content: ''; position: absolute; left: 50%; transform: translateX(-50%);
  top: 100%; width: 260px; height: 22px;
}
/* This is a <button> sitting among <a> elements. A button does not inherit
   line-height the way the links do, so it rendered 2px shorter and its text
   sat a pixel lower, which read as a step in the menu. The explicit
   line-height puts it back on the same baseline as its neighbours. */
.nav__drop-btn {
  font-family: inherit; font-size: 14px; font-weight: 500; line-height: normal;
  color: rgba(255,255,255,.88); background: none; border: none; padding: 0;
  cursor: pointer; display: inline-flex; align-items: baseline; gap: 6px;
  transition: opacity .2s;
}
.nav__drop-btn::after {
  content: ''; width: 5px; height: 5px; margin-top: -3px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); transition: transform .25s ease;
}
.nav__drop-btn:hover { opacity: .65; }
.nav__drop.is-open .nav__drop-btn::after { transform: rotate(225deg); margin-top: 2px; }

.nav__drop-menu {
  position: absolute; top: calc(100% + 14px); left: 50%; transform: translateX(-50%) translateY(-6px);
  min-width: 240px; padding: 8px; display: flex; flex-direction: column; gap: 2px;
  background: rgba(10,37,48,.82); border: 1px solid var(--glass-border);
  backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
  border-radius: 16px; box-shadow: 0 18px 50px rgba(0,0,0,.35);
  opacity: 0; visibility: hidden; pointer-events: none;
  transition: opacity .25s ease, transform .25s ease, visibility .25s;
}
.nav__drop.is-open .nav__drop-menu {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translateX(-50%) translateY(0);
}
.nav__drop-menu a {
  display: flex; flex-direction: column; gap: 2px;
  padding: 10px 14px; border-radius: 10px; text-decoration: none;
  transition: background .2s ease;
}
.nav__drop-menu a:hover { background: rgba(255,255,255,.10); }
.nav__drop-menu b { color: #fff; font-size: 14px; font-weight: 700; }
.nav__drop-menu span {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  letter-spacing: .1em; text-transform: uppercase; color: var(--mint);
}

/* ==========================================================================
   Mobile menu. Below 760px the inline links are hidden; this replaces them.
   Without it the only way to reach a project page was to scroll the whole
   landing page, which is what a visitor reported.
   ========================================================================== */
.nav__burger { display: none; }

@media (max-width: 760px) {
  /* .btn is defined in a later module, so it needs the extra class to win. */
  .nav .nav__cta { display: none; }

  .nav__burger {
    display: flex; flex-direction: column; justify-content: center; gap: 5px;
    width: 44px; height: 44px; padding: 0 11px;   /* 44px touch target */
    border-radius: 12px; cursor: pointer;
    background: rgba(255,255,255,.10); border: 1px solid rgba(255,255,255,.22);
  }
  .nav__burger span {
    display: block; height: 2px; border-radius: 2px; background: #fff;
    transition: transform .25s ease, opacity .2s ease;
  }
  .nav__burger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav__burger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .nav__burger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
}

/* The overlay is always in the layout. Only opacity and pointer-events
   change, and JavaScript writes both as inline styles so the open state does
   not depend on a class rule winning a cascade or on a transition having a
   usable start value. Earlier versions toggled the hidden attribute and then
   visibility; both worked in Chrome but left the panel invisible on iOS
   Safari while the burger already showed its open state. */
.navmob {
  position: fixed; inset: 0; z-index: 90;
  background: rgba(3,14,18,.72);
  opacity: 0; pointer-events: none;
  transition: opacity .25s ease;
}
.navmob__panel {
  position: absolute; left: 12px; right: 12px; top: 84px;
  display: flex; flex-direction: column; gap: 2px;
  max-height: calc(100svh - 100px); overflow-y: auto; overscroll-behavior: contain;
  padding: 14px; border-radius: 22px;
  background: rgba(8,32,42,.94); border: 1px solid rgba(255,255,255,.18);
  box-shadow: 0 30px 70px rgba(0,0,0,.55);
  transform: translateY(-10px); transition: transform .28s ease;
}
.navmob.is-open .navmob__panel { transform: translateY(0); }
.navmob a, .navmob__label {
  display: block; padding: 13px 14px; border-radius: 12px;
  color: #fff; font-size: 16px; font-weight: 600; text-decoration: none;
}
.navmob a:active { background: rgba(255,255,255,.10); }
.navmob__label {
  margin-top: 8px; padding-bottom: 4px;
  color: rgba(255,255,255,.5); font-family: var(--mono);
  font-size: 11px; font-weight: 500; letter-spacing: .14em; text-transform: uppercase;
}
/* Higher specificity than ".navmob a" above, which sets display:block. */
.navmob a.navmob__project { display: flex; flex-direction: column; gap: 3px; }
.navmob__project b { font-size: 16px; font-weight: 700; }
.navmob__project span { color: rgba(255,255,255,.55); font-size: 13px; font-weight: 400; }
.navmob__trip { color: var(--batumi); }
.navmob__cta { margin-top: 12px; width: 100%; justify-content: center; }

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

/* --- src/css/modules/04-hero.css --- */
/* ==========================================================================
   Landing hero: full-height stage, cross-fading project photos and the
   project label / indicator controls.
   ========================================================================== */
.hero {
  position: relative; width: 100%; overflow: hidden;
  display: flex; flex-direction: column; justify-content: flex-end;
  height: 100vh;
  height: 100svh;   /* svh, so it does not jump when mobile browser chrome hides */
  min-height: 560px;
}

/* Rotating hero backdrop.
   Each slide has two layers: .hero__mist is a 32px thumbnail stretched to
   full size (which yields a natural blur, with no CSS filter to compute per
   frame) and .hero__photo is the sharp image above it. On transition the
   sharp photo fades into the mist first, and only then does the next photo
   emerge out of that mist, so there is never a hard cut (RULES.md, rule 1).
   Only opacity and transform are animated, i.e. properties the browser can
   handle on the compositor. No filter and no run-time blur, which is why
   this stays smooth even on an older phone. */
.hero__stage { position: absolute; inset: 0; overflow: hidden; }

.hero__slide {
  position: absolute; inset: 0; overflow: hidden;
  opacity: 0;
  transition: opacity 1.5s cubic-bezier(.4,0,.2,1);
}
.hero__slide.is-active { opacity: 1; }

.hero__mist {
  position: absolute; inset: 0;
  background-size: cover; background-position: center 58%;
  transform: scale(1.08);
}

.hero__photo { position: absolute; inset: 0; }
.hero__photo img {
  width: 100%; height: 100%;
  object-fit: cover; object-position: center 58%;
  opacity: 0;
  transition: opacity 1.5s cubic-bezier(.4,0,.2,1);
}
/* The sharp photo fades in on a delay, so the blurred haze reads as a
   deliberate in-between state rather than a glitch. */
.hero__slide.is-active .hero__photo img { opacity: 1; transition-delay: .55s; }
.hero__slide.is-active .hero__photo { animation: kenburns 30s ease-in-out infinite alternate; }

@keyframes kenburns {
  0%   { transform: scale(1) translate(0,0); }
  100% { transform: scale(1.1) translate(-1.4%,-1%); }
}
.hero__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(6,28,36,.55) 0%, rgba(6,28,36,.05) 28%, rgba(6,28,36,.10) 55%, rgba(5,20,26,.75) 100%),
    linear-gradient(90deg, rgba(6,30,38,.55) 0%, rgba(6,30,38,.05) 45%);
}
.hero__content { position: relative; z-index: 10; width: 100%; padding-bottom: 7vh; display: flex; justify-content: center; }
.hero__inner { width: 100%; max-width: 1100px; padding: 0 40px; display: flex; flex-direction: column; gap: 26px; }


.headline { color: #fff; font-weight: 800; font-size: clamp(38px, 6.4vw, 84px); line-height: .98; letter-spacing: -.02em; max-width: 14ch; text-shadow: 0 2px 30px rgba(0,0,0,.25); }
.headline .accent { background: linear-gradient(100deg, var(--azure-light), var(--mint) 60%); -webkit-background-clip: text; background-clip: text; color: transparent; }
.sub { color: rgba(255,255,255,.86); font-size: clamp(15px, 1.7vw, 19px); font-weight: 500; max-width: 46ch; line-height: 1.5; }

.hero__row { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 24px; }
.cta-group { display: flex; gap: 14px; flex-wrap: wrap; }
.stats { display: flex; gap: 14px; flex-wrap: wrap; }
.stat {
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  backdrop-filter: blur(16px) saturate(160%); -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-radius: 16px; padding: 12px 18px; min-width: 118px;
  box-shadow: 0 6px 24px rgba(0,0,0,.15), inset 0 1px 0 rgba(255,255,255,.25);
}
.stat .val { font-family: 'IBM Plex Mono', monospace; font-weight: 600; font-size: 20px; color: #fff; }
.stat .lbl { font-size: 11px; color: rgba(255,255,255,.72); margin-top: 2px; }
@media (max-width: 600px) { .stats { display: none; } }

.btn {
  font-family: 'Manrope', sans-serif; font-weight: 700; font-size: 15px;
  padding: 15px 26px; border-radius: 14px; cursor: pointer; border: none;
  display: inline-flex; align-items: center; gap: 8px; text-decoration: none;
  transition: transform .18s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn--primary { background: linear-gradient(135deg, var(--azure), var(--jade)); color: #fff; box-shadow: 0 10px 30px rgba(28,134,176,.35); }
.btn--sm { padding: 10px 18px; font-size: 13px; }
.btn--glass { background: var(--glass-bg); border: 1px solid var(--glass-border); color: #fff; backdrop-filter: blur(14px); }

.scrolldown { position: absolute; bottom: 22px; right: 6vw; z-index: 10; color: rgba(255,255,255,.75); font-size: 11px; font-family: 'IBM Plex Mono', monospace; display: flex; flex-direction: column; align-items: center; gap: 8px; letter-spacing: .14em; text-transform: uppercase; }
.scrolldown .line { width: 1px; height: 34px; background: linear-gradient(180deg, rgba(255,255,255,.8), transparent); animation: pulse 1.8s ease-in-out infinite; }
@keyframes pulse { 0%, 100% { opacity: .3; } 50% { opacity: 1; } }

/* Label naming whichever project is currently on screen. */
.hero__caption {
  display: inline-flex; align-items: center; align-self: flex-start; gap: 12px;
  background: rgba(31,122,92,.24); border: 1px solid rgba(143,227,192,.42);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  border-radius: 100px; padding: 8px 18px;
}
.hero__caption::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--mint); box-shadow: 0 0 8px var(--mint);
}
.hero__caption-label {
  font-family: 'IBM Plex Mono', monospace; font-size: 11px; letter-spacing: .14em;
  text-transform: uppercase; color: rgba(234,255,246,.78);
}
.hero__caption-sep { width: 1px; height: 13px; background: rgba(255,255,255,.28); }
.hero__caption-name {
  font-weight: 700; font-size: 13.5px; color: #fff; min-width: 96px;
  transition: opacity .55s ease;
}
.hero__caption-name.is-swapping { opacity: 0; }
.hero__ticks { display: flex; gap: 6px; margin-left: 2px; }
.hero__tick {
  width: 18px; height: 3px; border-radius: 3px; border: none; padding: 0; cursor: pointer;
  background: rgba(255,255,255,.32); transition: background .4s ease, width .4s ease;
}
.hero__tick.is-active { background: var(--mint); width: 28px; }
@media (max-width: 560px) {
  .hero__caption-label, .hero__caption-sep { display: none; }
  .hero__caption-name { min-width: 82px; }
}

@media (prefers-reduced-motion: reduce) {
  .hero__slide.is-active .hero__photo { animation: none; }
  .hero__slide, .hero__photo img { transition-duration: .01ms; transition-delay: 0s; }
  .scrolldown .line { animation: none; }
}

/* No backdrop-filter anywhere on a phone.

   The nav bar is position:fixed, so a blur on it forces the browser to
   re-blur whatever is behind it on every single scroll frame, on every page,
   for the whole visit. That is what made the entire site shudder while
   scrolling on a phone, not the story sections. The glass buttons sit over
   moving photos and cost the same for the same reason.

   A flat translucent surface reads almost identically at this size and costs
   nothing per frame. */
@media (max-width: 760px) {
  .nav {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(6, 26, 34, .88);
  }
  .hero__caption,
  .btn--glass {
    backdrop-filter: none; -webkit-backdrop-filter: none;
  }
  .hero__caption { background: rgba(20, 58, 52, .55); }
  .btn--glass { background: rgba(255, 255, 255, .16); }
}

/* --- src/css/modules/05-primitives.css --- */
/* ==========================================================================
   Small shared primitives: section headings and the glass card surface that
   most components are built on.
   ========================================================================== */
.section-eyebrow {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; letter-spacing: .14em; text-transform: uppercase;
  color: var(--mint); margin-bottom: 18px;
}
.section-eyebrow::before { content: ''; width: 22px; height: 1px; background: var(--mint); }
.section-eyebrow.center { justify-content: center; }

.section-head { max-width: 780px; margin-bottom: 68px; }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }
.section-head h2 { font-size: clamp(28px, 4vw, 48px); font-weight: 800; letter-spacing: -.02em; line-height: 1.1; color: #fff; text-shadow: 0 2px 24px rgba(0,0,0,.25); }
.section-head p { margin-top: 18px; font-size: 16.5px; line-height: 1.6; color: rgba(255,255,255,.82); max-width: 58ch; }
.section-head.center p { margin-left: auto; margin-right: auto; }

/* Glass card surface, reused by cards, panels and modals across the site. */
.card {
  background: rgba(255,255,255,.10);
  border: 1px solid rgba(255,255,255,.22);
  backdrop-filter: blur(20px) saturate(160%);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  border-radius: 20px;
  box-shadow: 0 20px 60px rgba(0,0,0,.25), inset 0 1px 0 rgba(255,255,255,.15);
}

/* Phones: the glass card is the single most expensive thing on the page.
   A landing page carries fifteen of them, and each one re-blurs whatever sits
   behind it on every scroll frame, which is what made scrolling stutter on a
   real device. Below 760px they become a flat translucent surface instead.
   The look barely changes; the scroll goes from janky to smooth.
   See RULES.md rule 4. */
@media (max-width: 760px) {
  .card, .stat {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(10, 38, 48, .82);
  }
}

/* --- src/css/modules/06-story.css --- */
/* ==========================================================================
   Pinned scrollytelling sections ("Why Batumi", "Partner").

   One photo stays fixed while data slides cross-fade over it as the user
   scrolls. Multiple such sections can coexist on a page; the JS drives each
   independently. See main.js for the scroll logic.
   ========================================================================== */
.story { position: relative; background: var(--seam); }
/* Fade the photo's top and bottom edges into the seam colour so the join
   between two sections never reads as a hard line. */
.story__pin::after, .scene::after {
  content: ''; position: absolute; inset: 0; z-index: 3; pointer-events: none;
  background:
    linear-gradient(180deg, var(--seam), transparent 88px),
    linear-gradient(0deg, var(--seam), transparent 88px);
}
.story__track { position: relative; height: calc(var(--n, 7) * 170vh); }
/* Invisible stops, one per slide. They give the browser something to settle
   on, so a hard trackpad flick lands on a slide instead of between two. Only
   active on pointer devices; the snap rule itself lives in 01-tokens.css. */
.story__stops {
  position: absolute; inset: 0; z-index: 0;
  display: flex; flex-direction: column;
  pointer-events: none;
}
.story__stops span { flex: 1 1 0; scroll-snap-align: start; }

/* Cards inside a pinned section sit over a photo that is moving under them,
   so each one re-blurs it on every frame. Elsewhere on the site the glass is
   cheap enough; here there are up to seven of them at once. Flat surface,
   same colour, no per-frame cost. */
.story .card,
.story .stat {
  backdrop-filter: none; -webkit-backdrop-filter: none;
  background: rgba(10, 38, 48, .82);
}

.story__pin { position: sticky; top: 0; height: 100vh; height: 100svh; overflow: hidden; }
.story__bg { position: absolute; inset: 0; background-size: cover; background-position: center; }
.story__scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(4,20,26,.75) 0%, rgba(5,26,30,.55) 45%, rgba(3,16,20,.85) 100%); }

.story__slide {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center;
  /* Fade and lift, no blur. Animating filter means the browser re-renders a
     full-screen blur on every frame of the change; together with the glass
     cards below it accounted for a fifth of all dropped frames while
     scrolling this section. Measured: 21% of frames over 32ms with both,
     1.6% with neither. RULES.md rule 5 says animate only opacity and
     transform, and this is why. The transition still reads as soft. */
  opacity: 0; transform: translateY(24px);
  transition: opacity .8s ease, transform .8s ease;
  pointer-events: none;
}
.story__slide.active { opacity: 1; transform: translateY(0); pointer-events: auto; }

/* Final "reveal" slide: blurs the shared background just for this slide, so a
   logo reads clearly against it.

   The blur is attached only while the slide is active. A full-screen
   backdrop-filter is recomputed on every frame for as long as it exists, even
   when its slide is faded out, and that alone accounted for most of the
   dropped frames in this section. */
.story__slide--reveal::before {
  content: '';
  position: absolute; inset: 0; z-index: 0;
  background: rgba(3, 16, 20, .45);
}
.story__slide--reveal.active::before {
  backdrop-filter: blur(34px) saturate(120%);
  -webkit-backdrop-filter: blur(34px) saturate(120%);
}
.story__slide--reveal .wrap { position: relative; z-index: 1; text-align: center; }
.story__slide--reveal .story__lead { margin: 24px auto 0; }
.reveal-logo { width: 220px; height: auto; margin: 0 auto; }
.story__title {
  font-size: clamp(28px, 4vw, 46px); font-weight: 800; color: #fff;
  line-height: 1.15; letter-spacing: -.02em; margin-bottom: 36px;
  text-shadow: 0 2px 24px rgba(0,0,0,.25);
}
.story__lead { color: rgba(255,255,255,.85); font-size: 16px; line-height: 1.65; max-width: 640px; margin-bottom: 28px; }

.story__dots { position: absolute; bottom: 36px; left: 50%; transform: translateX(-50%); z-index: 5; display: flex; gap: 10px; }
.story__dot { width: 8px; height: 8px; border-radius: 50%; background: rgba(255,255,255,.3); border: none; cursor: pointer; padding: 0; transition: all .3s; }
.story__dot.active { background: var(--mint); width: 22px; border-radius: 5px; }

.stat-row { display: grid; grid-template-columns: repeat(4, 1fr); gap: 18px; }
/* Narrower two-column variant, used by slides carrying fewer figures. */
.stat-row--pair { grid-template-columns: repeat(2, 1fr); max-width: 640px; }
.stat-row--spaced { margin-top: 28px; }
.stat-card { padding: 28px 24px; }
.stat-card .num { font-family: 'IBM Plex Mono', monospace; font-weight: 600; font-size: clamp(24px, 2.4vw, 32px); color: #fff; }
.stat-card .num em { font-style: normal; color: var(--mint); }
.stat-card .lbl { margin-top: 8px; font-size: 13px; color: rgba(255,255,255,.72); line-height: 1.4; }
@media (max-width: 900px) { .stat-row { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .stat-row { grid-template-columns: 1fr; } }

.highlight { max-width: 640px; padding: 15px 18px; border-radius: 14px; background: rgba(143,227,192,.12); border: 1px solid rgba(143,227,192,.32); font-size: 13.5px; color: #eafff2; font-weight: 600; line-height: 1.5; }

.chain { display: flex; justify-content: space-between; gap: 14px; position: relative; }
.chain::before { content: ''; position: absolute; top: 17px; left: 8%; right: 8%; height: 1px; background: linear-gradient(90deg, transparent, rgba(255,255,255,.4), rgba(255,255,255,.4), transparent); }
@media (max-width: 900px) { .chain { flex-wrap: wrap; } .chain::before { display: none; } }
.chain__item { flex: 1; min-width: 160px; position: relative; z-index: 2; text-align: center; }
.chain__num { width: 34px; height: 34px; border-radius: 50%; margin: 0 auto 14px; display: flex; align-items: center; justify-content: center; background: rgba(255,255,255,.12); border: 2px solid var(--mint); color: #fff; font-family: 'IBM Plex Mono', monospace; font-weight: 700; font-size: 13px; }
.chain__item p { font-size: 13.5px; color: rgba(255,255,255,.8); line-height: 1.5; padding: 0 6px; }
.chain__item h4 { font-size: 15px; font-weight: 800; color: #fff; margin-bottom: 8px; padding: 0 6px; }
.chain__stat { font-family: 'IBM Plex Mono', monospace; font-weight: 700; font-size: 28px; color: var(--mint); margin-bottom: 6px; }
.chain--points .chain__item { text-align: left; }
.chain--points .chain__num { margin: 0 0 14px; }
.chain--points .chain__item p, .chain--points .chain__item h4 { padding: 0; }


/* ==========================================================================
   Phones: same pinned behaviour as the desktop, but a cheaper transition.

   The slides used to cross-fade through an 18px blur. Animating filter means
   the browser re-renders a full-screen blur on every frame of every change,
   which is the single most expensive thing it can be asked to do on a phone
   and is what made scrolling shake and stutter. RULES.md rule 5 already says
   to animate only opacity and transform; this section brings the story slides
   in line with it. The fade stays soft, it just no longer costs a repaint.

   Scroll snapping stays off here: on a touch screen it fights the phone's own
   momentum. On pointer devices it is still on (see 01-tokens.css), where a
   single trackpad flick would otherwise skip several slides.
   ========================================================================== */
@media (max-width: 700px) {
  /* 75svh per slide: measured on a 390x844 screen, this gives one slide for a
     normal swipe and two or three for a deliberate hard flick. */
  .story__track { height: calc(var(--n, 7) * 75vh); height: calc(var(--n, 7) * 75svh); }

  .story__slide {
    transform: translateY(14px);
    transition: opacity .45s ease, transform .45s ease;
    /* A slide can be taller than the phone screen (the five core strengths
       are, by about 70px). Without this the bottom of it is simply cut off by
       the pinned panel, so the slide scrolls internally instead. */
    /* "safe" keeps the slide centred, but falls back to top alignment when the
       content is taller than the panel, instead of cutting the top off. */
    align-items: safe center;
    overflow-y: auto; overscroll-behavior: contain;
    padding: 76px 0 56px;
    scrollbar-width: none;
  }
  .story__slide::-webkit-scrollbar { width: 0; }
  .story__slide.active { transform: translateY(0); }

  /* A full-screen backdrop-filter behind the reveal slide is the same kind of
     per-frame cost as the blur above. */
  .story__slide--reveal::before {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(3, 16, 20, .72);
  }
}

/* --- src/css/modules/07-partner.css --- */
/* ==========================================================================
   Partner section: ONE Development key figures and core strengths.
   ========================================================================== */
.badge-row { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 18px; }
.badge-card { padding: 28px 22px; text-align: center; }
.badge-card .num { font-family: 'IBM Plex Mono', monospace; font-weight: 700; font-size: 22px; color: #fff; }
.badge-card .lbl { margin-top: 8px; font-size: 12.5px; color: rgba(255,255,255,.75); line-height: 1.4; }

.strengths { display: flex; flex-wrap: wrap; justify-content: center; gap: 18px; }
.strength-card { flex: 1 1 260px; max-width: 300px; padding: 26px 24px; }
.strength-card h4 { font-size: 16px; font-weight: 800; color: #fff; margin-bottom: 10px; }
.strength-card p { font-size: 13.5px; color: rgba(255,255,255,.78); line-height: 1.55; }

/* --- src/css/modules/08-projects.css --- */
/* ==========================================================================
   Projects section: location map and the project cards grid.
   ========================================================================== */

/* The map is an overview only, so it does not need the full section width.
   The image is supplied finished by the client (its own title and callouts
   are baked into the artwork), so nothing is overlaid on top of it. */
.pmap { margin: 0 auto 40px; max-width: 860px; }
.pmap__frame {
  position: relative; border-radius: 22px; overflow: hidden;
  border: 1px solid rgba(255,255,255,.28);
  box-shadow: 0 20px 60px rgba(0,0,0,.32);
}
.pmap__frame img { width: 100%; height: auto; display: block; }

.project-grid { display: grid; grid-template-columns: 1fr; gap: 22px; }
@media (min-width: 640px) { .project-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1100px) { .project-grid { grid-template-columns: repeat(4, 1fr); } }

.project-card {
  position: relative; display: flex; flex-direction: column; justify-content: flex-end;
  aspect-ratio: 4 / 5; border-radius: 22px; overflow: hidden; text-decoration: none;
  border: 1px solid rgba(255,255,255,.18);
  box-shadow: 0 20px 60px rgba(0,0,0,.28);
}
.project-card picture { position: absolute; inset: 0; }
.project-card img {
  width: 100%; height: 100%; object-fit: cover;
  transition: transform .7s cubic-bezier(.4,0,.2,1);
}
.project-card:hover img { transform: scale(1.05); }
.project-card::after {
  content: ''; position: absolute; inset: 0; z-index: 1;
  background: linear-gradient(180deg, rgba(4,20,26,0) 38%, rgba(4,20,26,.55) 62%, rgba(3,16,20,.94) 100%);
}
.project-card__body { position: relative; z-index: 2; padding: 24px 22px 22px; }
.project-card__tag {
  display: inline-block; font-family: 'IBM Plex Mono', monospace; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: var(--mint); margin-bottom: 8px;
}
.project-card__name {
  color: #fff; font-size: 24px; font-weight: 800; letter-spacing: -.01em; line-height: 1.1;
}
.project-card__facts { display: flex; flex-direction: column; gap: 5px; margin: 12px 0 16px; }
.project-card__facts span { font-size: 13px; line-height: 1.45; color: rgba(255,255,255,.8); }
.project-card__cta {
  display: inline-flex; align-items: center; gap: 6px; min-height: 44px;
  font-size: 13.5px; font-weight: 700; color: #fff; transition: gap .2s ease;
}
.project-card:hover .project-card__cta { gap: 12px; }

/* --- src/css/modules/09-agents.css --- */
/* ==========================================================================
   "Our agents" horizontal carousel.
   ========================================================================== */
.agents { background: #06181f; padding: 92px 0 96px; overflow: hidden; }
.agents .section-head { margin-bottom: 44px; }

.agents__viewport { position: relative; }
/* Darken the strip's edges so cards fade out instead of being cut off. */
.agents__viewport::before,
.agents__viewport::after {
  content: ''; position: absolute; top: 0; bottom: 0; width: 90px; z-index: 2;
  pointer-events: none;
}
.agents__viewport::before { left: 0; background: linear-gradient(90deg, #06181f, rgba(6,24,31,0)); }
.agents__viewport::after { right: 0; background: linear-gradient(270deg, #06181f, rgba(6,24,31,0)); }

.agents__row {
  display: flex; gap: 20px; width: max-content; padding: 10px 20px 24px;
  animation: agentsScroll 46s linear infinite;
}
.agents__viewport:hover .agents__row,
.agents__viewport:focus-within .agents__row { animation-play-state: paused; }
@keyframes agentsScroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}
@media (prefers-reduced-motion: reduce) {
  .agents__row { animation: none; overflow-x: auto; width: auto; }
  .agents__viewport { overflow-x: auto; }
}

.agent {
  flex: 0 0 clamp(250px, 26vw, 310px);
  background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.16);
  border-radius: 20px; overflow: hidden;
  transition: transform .3s cubic-bezier(.4,0,.2,1), border-color .3s ease, box-shadow .3s ease;
}
.agent:hover {
  transform: scale(1.06); border-color: rgba(143,227,192,.45);
  box-shadow: 0 22px 55px rgba(0,0,0,.4);
}
.agent__photo { display: block; aspect-ratio: 1 / 1; }
.agent__photo img { width: 100%; height: 100%; object-fit: cover; }
.agent__body { padding: 20px 20px 22px; display: flex; flex-direction: column; gap: 5px; }
.agent__region {
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; letter-spacing: .12em;
  text-transform: uppercase; color: var(--mint);
}
.agent__name { color: #fff; font-size: 18px; font-weight: 700; }
.agent__role { color: rgba(255,255,255,.6); font-size: 12.5px; margin-bottom: 4px; }
.agent__role:empty { display: none; }
.agent__link {
  color: rgba(255,255,255,.78); font-size: 13.5px; text-decoration: none;
  min-height: 26px; display: inline-flex; align-items: center;
}
a.agent__link:hover { color: var(--mint); }

/* --- src/css/modules/10-footer.css --- */
/* ==========================================================================
   Site footer.
   ========================================================================== */
.footer { background: #04141a; }

.footer__lead {
  display: flex; flex-wrap: wrap; gap: 30px; align-items: center;
  justify-content: space-between; padding: 66px 0 58px;
}
.footer__lead h3 {
  color: #fff; font-size: clamp(21px, 2.6vw, 30px); font-weight: 800;
  line-height: 1.3; max-width: 30ch;
}
.footer__cta { display: inline-flex; gap: 14px; flex-wrap: wrap; }

.footer__body { border-top: 1px solid rgba(255,255,255,.10); }
.footer__cols {
  display: grid; grid-template-columns: 1fr; gap: 34px;
  padding: 52px 0 42px;
}
@media (min-width: 720px) { .footer__cols { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .footer__cols { grid-template-columns: 1.6fr 1fr 1fr 1.3fr; gap: 40px; } }

.footer__col { display: flex; flex-direction: column; gap: 12px; align-items: flex-start; }
.footer__col h4 {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px; font-weight: 500;
  letter-spacing: .16em; text-transform: uppercase; color: var(--mint);
  margin-bottom: 2px;
}
.footer__col a {
  color: rgba(255,255,255,.8); text-decoration: none; font-size: 14.5px;
  min-height: 26px; display: inline-flex; align-items: center;
  transition: color .2s ease;
}
.footer__col a:hover { color: #fff; }
.footer__col span { color: rgba(255,255,255,.6); font-size: 14px; line-height: 1.5; }

.footer__trip { color: var(--batumi); font-weight: 700; }
.footer__mark { font-weight: 800; font-size: 17px; letter-spacing: .04em; color: #fff; }
.footer__mark span { color: var(--batumi); }
.footer__col--brand p {
  color: rgba(255,255,255,.62); font-size: 14px; line-height: 1.6; max-width: 42ch;
}

.footer__bottom {
  display: flex; flex-wrap: wrap; gap: 10px;
  border-top: 1px solid rgba(255,255,255,.10); padding: 22px 0 26px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11px;
  letter-spacing: .04em; color: rgba(255,255,255,.42);
}

/* --- src/css/modules/11-contact-modal.css --- */
/* ==========================================================================
   Contact dialog. Built on the native <dialog> element, so the browser
   handles Escape-to-close, focus trapping and top-layer stacking for us.
   ========================================================================== */
.modal {
  /* Centre the dialog on screen rather than pinning it to the top. */
  position: fixed; inset: 0; margin: auto;
  border: none; padding: 0; background: transparent;
  width: min(520px, calc(100% - 32px)); max-height: calc(100% - 40px);
  color: #fff; overflow: visible;
}
.modal::backdrop {
  background: rgba(3,14,18,.72);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
}
.modal__card {
  position: relative; padding: 38px 34px 32px; border-radius: 24px;
  background: rgba(10,37,48,.94); border: 1px solid var(--glass-border);
  box-shadow: 0 30px 80px rgba(0,0,0,.5);
}
.modal[open] .modal__card { animation: modalIn .34s cubic-bezier(.4,0,.2,1); }
@keyframes modalIn {
  from { opacity: 0; transform: translateY(14px) scale(.98); }
  to   { opacity: 1; transform: none; }
}
.modal__close {
  position: absolute; top: 14px; right: 14px;
  width: 44px; height: 44px; border-radius: 50%; border: none; cursor: pointer;
  /* Teal rather than grey: on a dark photo the neutral cross was easy to miss,
     and the brand colour marks it as the one control on the panel. */
  background: rgba(20, 185, 145, .18); color: var(--batumi);
  border: 1px solid rgba(20, 185, 145, .38);
  font-size: 22px; line-height: 1;
  transition: background .2s ease, color .2s ease, border-color .2s ease;
}
.modal__close:hover {
  background: var(--batumi); color: var(--seam);
  border-color: var(--batumi);
}
.modal__eyebrow {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--mint);
}
.modal__title { margin-top: 8px; font-size: 27px; font-weight: 800; color: #fff; }
.modal__lead { margin-top: 12px; font-size: 14.5px; line-height: 1.6; color: rgba(255,255,255,.76); }

.modal__list { list-style: none; margin-top: 26px; }
.modal__list li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 16px;
  padding: 13px 0; border-bottom: 1px solid rgba(255,255,255,.10);
}
.modal__list li:last-child { border-bottom: none; }
.modal__list li > span:first-child {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  letter-spacing: .14em; text-transform: uppercase; color: rgba(255,255,255,.5);
  flex: none;
}
.modal__list a, .modal__list li > span:last-child {
  color: #fff; font-size: 15px; font-weight: 600; text-decoration: none; text-align: right;
}
.modal__list a:hover { color: var(--mint); }
@media (max-width: 480px) {
  .modal__card { padding: 32px 22px 26px; }
  .modal__list li { flex-direction: column; gap: 4px; }
  .modal__list a, .modal__list li > span:last-child { text-align: left; }
}
@media (prefers-reduced-motion: reduce) {
  .modal[open] .modal__card { animation: none; }
}

/* --- src/css/modules/12-project-pages.css --- */
/* ==========================================================================
   Project subpages: hero with stats, content blocks and shared page furniture.
   Used by sportcity, onetower, radissonred and home.
   ========================================================================== */
.phero {
  position: relative; display: flex; align-items: flex-end;
  min-height: 88vh; min-height: 88svh; overflow: hidden;
  /* No bottom padding: the stats row sits flush with the end of the hero. With
     padding here the content floated a centimetre too high and left a thick
     black band between the last card and the next section. */
  padding: 150px 0 0;
}
.phero__photo { position: absolute; inset: 0; }
.phero__photo img { width: 100%; height: 100%; object-fit: cover; object-position: center 82%; }
.phero__scrim {
  /* Stays translucent almost to the bottom edge so the photo is still visible
     behind the stats; only the last few percent fade into the seam colour. */
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(5,20,26,.72) 0%, rgba(5,20,26,.18) 34%,
    rgba(5,18,22,.86) 94%, var(--seam) 100%);
}
.phero__content { position: relative; z-index: 2; }
.phero__back {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; letter-spacing: .12em;
  text-transform: uppercase; color: rgba(255,255,255,.7); text-decoration: none;
}
.phero__back::before { content: ''; width: 18px; height: 1px; background: currentColor; }
.phero__back:hover { color: #fff; }
.phero__tag {
  display: block; margin-top: 6px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11.5px; letter-spacing: .14em;
  text-transform: uppercase; color: var(--mint);
}
.phero__title {
  margin-top: 10px; color: #fff; font-weight: 800; line-height: .98;
  font-size: clamp(40px, 7vw, 88px); letter-spacing: -.02em;
}
.phero__lead {
  margin-top: 18px; max-width: 56ch; font-size: clamp(15px, 1.7vw, 18px);
  line-height: 1.55; color: rgba(255,255,255,.85);
}

.pstats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; margin-top: 52px; }
@media (min-width: 800px) { .pstats { grid-template-columns: repeat(4, 1fr); } }
.pstat {
  background: var(--glass-bg); border: 1px solid var(--glass-border);
  backdrop-filter: blur(16px) saturate(160%); -webkit-backdrop-filter: blur(16px) saturate(160%);
  border-radius: 16px; padding: 16px 18px;
}
.pstat .val { font-family: 'IBM Plex Mono', monospace; font-weight: 600; font-size: clamp(17px, 2vw, 21px); color: #fff; }
.pstat .lbl { margin-top: 4px; font-size: 12px; color: rgba(255,255,255,.68); }

.psection { position: relative; padding: 96px 0; background: #051216; }
.psection--alt { background: #06181f; }
@media (max-width: 700px) { .psection { padding: 68px 0; } }

.pmedia { margin: 0 0 40px; }
/* A media block that follows a card grid or a list block needs the same gap
   above it as the one the preceding image leaves below itself, otherwise the
   cards sit flush against the next photo. */
.pgrid + .pmedia,
.plist-grid + .pmedia,
.pgrid + .plist-grid { margin-top: 40px; }
.pmedia img { width: 100%; height: auto; border-radius: 20px; border: 1px solid rgba(255,255,255,.14); }
.pmedia--pair { display: grid; grid-template-columns: 1fr; gap: 18px; margin-top: 44px; margin-bottom: 0; }
@media (min-width: 900px) { .pmedia--pair { grid-template-columns: 1fr 1fr; } }

.pgrid { display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 640px) { .pgrid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) {
  .pgrid--3 { grid-template-columns: repeat(3, 1fr); }
  .pgrid--4 { grid-template-columns: repeat(4, 1fr); }
  .pgrid--5 { grid-template-columns: repeat(5, 1fr); }
}
.pbox { padding: 24px 22px; }
.pbox__key {
  display: inline-flex; align-items: center; justify-content: center;
  width: 28px; height: 28px; border-radius: 8px; margin-bottom: 12px;
  background: rgba(143,227,192,.16); border: 1px solid rgba(143,227,192,.45);
  font-family: 'IBM Plex Mono', monospace; font-size: 13px; font-weight: 600; color: var(--mint);
}
.pbox h3 { color: #fff; font-size: 17px; font-weight: 700; }
.pbox__num {
  margin-top: 8px; font-family: 'IBM Plex Mono', monospace;
  font-size: 20px; font-weight: 600; color: var(--mint);
}
.pbox p { margin-top: 10px; font-size: 14px; line-height: 1.55; color: rgba(255,255,255,.78); }

.plist-grid { display: grid; grid-template-columns: 1fr; gap: 28px; margin-top: 8px; }
@media (min-width: 800px) { .plist-grid { grid-template-columns: repeat(3, 1fr); } }
.plist h3 {
  color: #fff; font-size: 15px; font-weight: 700; padding-bottom: 12px;
  border-bottom: 1px solid rgba(255,255,255,.16);
}
.plist ul { list-style: none; margin-top: 14px; }
.plist li {
  position: relative; padding: 7px 0 7px 18px;
  font-size: 14.5px; line-height: 1.5; color: rgba(255,255,255,.8);
}
.plist li::before { content: ''; position: absolute; left: 0; top: 15px; width: 6px; height: 1px; background: var(--mint); }

.plocation { display: grid; grid-template-columns: 1fr; gap: 30px; align-items: start; }
@media (min-width: 900px) { .plocation { grid-template-columns: 1.4fr .6fr; } }
/* On wide screens the availability list breaks into two columns. */
@media (min-width: 700px) { .pnear--split { column-count: 2; column-gap: 40px; } }
.pnear--split li { break-inside: avoid; }
.pnear { list-style: none; }
.pnear li {
  display: flex; align-items: baseline; justify-content: space-between; gap: 14px;
  padding: 10px 0; border-bottom: 1px solid rgba(255,255,255,.10);
  font-size: 14.5px; color: rgba(255,255,255,.8);
}
.pnear li:last-child { border-bottom: none; }
.pnear b {
  font-family: 'IBM Plex Mono', monospace; font-weight: 500; font-size: 13px;
  color: #fff; white-space: nowrap;
}
.plocation__side .highlight { margin-top: 20px; }
.paddr { margin-top: 18px; font-family: 'IBM Plex Mono', monospace; font-size: 12.5px; color: rgba(255,255,255,.55); }
.psection .highlight { max-width: none; margin-top: 30px; }

/* The four hero figures sit over the project photo. Same per-frame cost as
   every other glass surface, so phones get a flat panel instead. */
@media (max-width: 760px) {
  .pstat {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(10, 38, 48, .82);
  }
}

/* --- src/css/modules/13-not-found.css --- */
/* ==========================================================================
   404 page.
   ========================================================================== */
.notfound {
  min-height: 74vh; min-height: 74svh;
  display: flex; align-items: center; background: #051216;
  padding: 160px 0 90px;
}
.notfound__code {
  font-family: 'IBM Plex Mono', monospace; font-size: 13px; letter-spacing: .2em;
  color: var(--mint);
}
.notfound__title {
  margin-top: 12px; color: #fff; font-weight: 800; letter-spacing: -.02em;
  font-size: clamp(30px, 5vw, 56px); line-height: 1.05;
}
.notfound__lead {
  margin-top: 18px; max-width: 52ch; font-size: 16px; line-height: 1.6;
  color: rgba(255,255,255,.78);
}
.notfound__cta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 30px; }

/* --- src/css/modules/14-project-sections.css --- */
/* ==========================================================================
   Project subpages: section treatments that keep long pages from turning
   into three identical dark blocks in a row.
   ========================================================================== */

/* Section with a background photo, dimmed to keep the text legible. */
.psection--photo { background-size: cover; background-position: center; background-attachment: fixed; }
@media (max-width: 800px) { .psection--photo { background-attachment: scroll; } }
.psection--photo::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(180deg,
    var(--seam) 0%, rgba(4,18,24,.93) 7%, rgba(5,24,31,.86) 45%,
    rgba(4,18,24,.95) 93%, var(--seam) 100%);
}
.psection--photo > * { position: relative; z-index: 1; }

/* Section with a colour wash, used to break up repeated dark surfaces. */
.psection--tint {
  background:
    radial-gradient(120% 90% at 12% 0%, rgba(28,134,176,.22), transparent 60%),
    radial-gradient(90% 80% at 90% 100%, rgba(31,122,92,.20), transparent 60%),
    #06181f;
}

.pmaplink {
  display: inline-flex; align-items: center; gap: 8px; min-height: 44px; margin-top: 8px;
  font-size: 14px; font-weight: 700; color: var(--mint); text-decoration: none;
}
.pmaplink::after { content: '→'; transition: transform .2s ease; }
.pmaplink:hover::after { transform: translateX(4px); }

/* Photo pair: one tall image beside two shorter stacked ones. */
.ptwo { display: grid; grid-template-columns: 1fr; gap: 18px; }
@media (min-width: 900px) { .ptwo { grid-template-columns: .82fr 1.18fr; align-items: start; } }
.ptwo img { width: 100%; height: auto; border-radius: 20px; border: 1px solid rgba(255,255,255,.14); }
.ptwo__tall { display: block; }
.ptwo__stack { display: grid; gap: 18px; }

/* --- src/css/modules/15-trip-modal.css --- */
/* ==========================================================================
   Investment trip modal. Opens once per visit, three seconds after load
   (see main.js). The page behind it blurs; the modal itself stays sharp.
   ========================================================================== */
.modal--trip::backdrop {
  background: rgba(2,10,14,.78);
  backdrop-filter: blur(18px) saturate(120%); -webkit-backdrop-filter: blur(18px) saturate(120%);
}
.modal--trip {
  width: min(860px, calc(100% - 24px));
  max-height: calc(100% - 24px); overflow-y: auto; overscroll-behavior: contain;
  /* The scrollbar sits on top of the rounded card and breaks its edge, so it
     is hidden. Scrolling itself still works, including keyboard and wheel. */
  scrollbar-width: none; -ms-overflow-style: none;
}
.modal--trip::-webkit-scrollbar { width: 0; height: 0; }
.trip {
  position: relative; border-radius: 26px; overflow: hidden;
  background: var(--seam); border: 1px solid rgba(255,255,255,.22);
  box-shadow: 0 40px 100px rgba(0,0,0,.6);
}
.modal[open] .trip { animation: modalIn .34s cubic-bezier(.4,0,.2,1); }
@media (prefers-reduced-motion: reduce) { .modal[open] .trip { animation: none; } }
.trip__close { z-index: 5; background: rgba(20, 185, 145, .20); }

/* Same glass surface as everywhere else on the site. */
.trip .glass {
  background: rgba(8,32,42,.58); border: 1px solid rgba(255,255,255,.20);
  backdrop-filter: blur(16px) saturate(150%); -webkit-backdrop-filter: blur(16px) saturate(150%);
}

/* Upper half: photo ------------------------------------------------------ */
.trip__top {
  position: relative; padding: 22px 22px 24px;
  background-image: url('../img/zajazd-bg.jpg');
  background-size: cover; background-position: center 58%;
}
.trip__scrim {
  position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgba(4,18,26,.72) 0%, rgba(4,20,28,.42) 40%, rgba(5,20,27,.92) 100%),
    linear-gradient(90deg, rgba(4,18,26,.55), rgba(4,18,26,0) 70%);
}
.trip__head { position: relative; display: grid; grid-template-columns: 1fr; gap: 16px; }
@media (min-width: 700px) { .trip__head { grid-template-columns: auto 1fr; align-items: start; gap: 26px; } }

.trip__brand {
  color: #fff; font-size: 26px; font-weight: 300; letter-spacing: .01em;
  text-transform: uppercase; line-height: 1; white-space: nowrap;
}
.trip__brand b { font-weight: 800; }
.trip__brand span {
  display: block; margin-top: 8px;
  font-family: 'IBM Plex Mono', monospace; font-size: 10px; font-weight: 500;
  letter-spacing: .46em; color: var(--batumi);
}

.trip__intro { border-radius: 16px; padding: 16px 20px; }
.trip__eyebrow {
  font-family: 'IBM Plex Mono', monospace; font-size: 10.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--batumi);
}
.trip__intro-lead {
  margin-top: 10px; color: #fff; font-size: 17px; font-weight: 700; line-height: 1.35;
}
.trip__intro-sub { margin-top: 6px; font-size: 13px; color: rgba(255,255,255,.78); }

.trip__headline {
  position: relative; margin: 22px 0 0; border-radius: 18px; padding: 18px 22px;
  color: #fff; font-weight: 800; letter-spacing: -.02em; line-height: 1.02;
  font-size: clamp(26px, 4.6vw, 44px); text-transform: uppercase;
}

.trip__strip { position: relative; display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 20px; }
@media (min-width: 700px) { .trip__strip { grid-template-columns: 1fr 1fr; } }

.trip__date { border-radius: 16px; padding: 16px 20px; border-left: 3px solid var(--batumi); }
.trip__date b { display: block; color: #fff; font-size: 19px; font-weight: 800; }
.trip__date span {
  display: block; margin-top: 8px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: rgba(255,255,255,.66);
}

.trip__price { border-radius: 16px; padding: 16px 20px; border-color: rgba(20,185,145,.42); }
.trip__price-label {
  display: block; font-family: 'IBM Plex Mono', monospace; font-size: 9.5px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--batumi);
}
.trip__price b {
  display: block; margin-top: 6px; color: var(--batumi);
  font-size: 34px; font-weight: 800; line-height: 1;
}
.trip__price i {
  font-style: normal; margin-left: 10px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.62);
}
.trip__price p { margin-top: 10px; font-size: 12.5px; line-height: 1.6; color: rgba(255,255,255,.86); }

/* Lower half: dark panel -------------------------------------------------- */
.trip__bottom { padding: 26px 26px 24px; }

.trip__program {
  list-style: none; counter-reset: trip;
  display: grid; grid-template-columns: 1fr; gap: 16px;
  padding-bottom: 24px; border-bottom: 1px solid rgba(255,255,255,.12);
}
@media (min-width: 640px) { .trip__program { grid-template-columns: repeat(3, 1fr); } }
.trip__program li { counter-increment: trip; position: relative; padding-left: 52px; }
.trip__program li::before {
  content: counter(trip, decimal-leading-zero);
  position: absolute; left: 0; top: 2px;
  width: 38px; height: 38px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: var(--batumi); color: #04231c;
  font-family: 'IBM Plex Mono', monospace; font-size: 13px; font-weight: 600;
}
.trip__program b {
  display: block; color: #fff; font-size: 15px; font-weight: 800;
  letter-spacing: .02em; text-transform: uppercase;
}
.trip__program span { display: block; margin-top: 4px; font-size: 13px; color: rgba(255,255,255,.7); }

.trip__foot { display: grid; grid-template-columns: 1fr; gap: 22px; padding-top: 26px; align-items: center; }
@media (min-width: 640px) { .trip__foot { grid-template-columns: 1fr 190px; } }
.trip__foot-text h3 {
  margin-top: 12px; color: #fff; font-weight: 800; line-height: 1.06;
  text-transform: uppercase; font-size: clamp(22px, 3.2vw, 32px);
}
.trip__foot-text p { margin-top: 12px; font-size: 13.5px; color: rgba(255,255,255,.72); }
.trip__actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; margin-top: 20px; }

.btn--trip {
  background: var(--batumi); color: #04231c; border: none;
  justify-content: center; font-weight: 800; min-width: 170px;
}
.btn--trip:hover { background: #17d0a3; }
.trip__later {
  background: none; border: none; cursor: pointer; min-height: 44px; padding: 0 4px;
  font-family: inherit; font-size: 13px; color: rgba(255,255,255,.55);
  transition: color .2s ease;
}
.trip__later:hover { color: #fff; }

.trip__qr { background: #fff; border-radius: 18px; padding: 13px 13px 10px; text-align: center; }
.trip__qr span {
  display: block; margin-bottom: 8px;
  font-family: 'IBM Plex Mono', monospace; font-size: 9px;
  letter-spacing: .14em; text-transform: uppercase; color: #0a2530;
}
.trip__qr img { width: 100%; height: auto; display: block; }

.trip__note { margin-top: 22px; font-size: 11px; line-height: 1.5; color: rgba(255,255,255,.42); }

@media (max-width: 560px) {
  .trip__top { padding: 20px 18px 20px; }
  .trip__bottom { padding: 22px 18px 20px; }
  .trip__headline { padding: 14px 16px; }
}
@media (max-width: 760px) {
  /* Glass over a photo is the most expensive case on phones, so ease off. */
  .trip .glass { backdrop-filter: blur(9px); -webkit-backdrop-filter: blur(9px); background: rgba(7,28,37,.76); }
}

/* --- src/css/modules/16-trip-page.css --- */
/* ==========================================================================
   Investment trip page (zajazd.html).
   ========================================================================== */
.zbrand {
  display: block; margin-bottom: 14px;
  color: #fff; font-size: 22px; font-weight: 300; text-transform: uppercase; line-height: 1;
}
.zbrand b { font-weight: 800; }
.zbrand span {
  display: block; margin-top: 7px;
  font-family: 'IBM Plex Mono', monospace; font-size: 9.5px; font-weight: 500;
  letter-spacing: .46em; color: var(--batumi);
}

.zstrip { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 28px; }
@media (min-width: 700px) { .zstrip { grid-template-columns: 1fr 1fr; max-width: 720px; } }
.zcard {
  border-radius: 16px; padding: 16px 20px;
  background: rgba(8,32,42,.58); border: 1px solid rgba(255,255,255,.20);
  backdrop-filter: blur(16px) saturate(150%); -webkit-backdrop-filter: blur(16px) saturate(150%);
}
.zcard--date { border-left: 3px solid var(--batumi); }
.zcard--date b { display: block; color: #fff; font-size: 19px; font-weight: 800; }
.zcard--date span {
  display: block; margin-top: 8px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11px;
  letter-spacing: .1em; text-transform: uppercase; color: rgba(255,255,255,.66);
}
.zcard--price { border-color: rgba(20,185,145,.42); }
.zcard--price b { display: block; color: var(--batumi); font-size: 32px; font-weight: 800; line-height: 1; }
.zcard--price i {
  font-style: normal; margin-left: 10px;
  font-family: 'IBM Plex Mono', monospace; font-size: 11px;
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.62);
}
.zcard--price p { margin-top: 10px; font-size: 12.5px; line-height: 1.6; color: rgba(255,255,255,.86); }

.zcta { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 26px; }
.zcta--center { justify-content: center; }
.zcta__note { margin-top: 12px; font-size: 12px; color: rgba(255,255,255,.5); }
.zcta__note--center { text-align: center; }
.btn--trip { background: var(--batumi); color: #04231c; border: none; font-weight: 800; }
.btn--trip:hover { background: #17d0a3; }

.section-head--center { text-align: center; margin-left: auto; margin-right: auto; }
.section-head--center p { margin-left: auto; margin-right: auto; }

/* Day-by-day itinerary ---------------------------------------------------- */
/* Three days sit side by side on wide screens so the full programme fits in
   one screenful instead of one long scroll. Below 1000px they stack. */
.zdays { display: grid; grid-template-columns: 1fr; gap: 20px; align-items: start; }
@media (min-width: 1000px) { .zdays { grid-template-columns: repeat(3, 1fr); gap: 22px; } }

.zday {
  margin-bottom: 0; border-radius: 20px; padding: 24px 26px;
  background: rgba(8,32,42,.55); border: 1px solid rgba(255,255,255,.16);
  backdrop-filter: blur(14px) saturate(150%); -webkit-backdrop-filter: blur(14px) saturate(150%);
}
.zday__head {
  display: flex; flex-direction: column; align-items: flex-start; gap: 8px;
  padding-bottom: 16px; border-bottom: 1px solid rgba(255,255,255,.14);
}
.zday__head span {
  font-family: 'IBM Plex Mono', monospace; font-size: 12px;
  letter-spacing: .16em; text-transform: uppercase; color: var(--batumi);
}
.zday__head h3 { color: #fff; font-size: clamp(18px, 2.4vw, 24px); font-weight: 800; }

.zday__list { list-style: none; margin-top: 6px; }
.zday__list li {
  display: grid; grid-template-columns: 1fr; gap: 3px;
  padding: 13px 0; border-bottom: 1px solid rgba(255,255,255,.08);
}
/* In three-column mode the time sits above the entry, not beside it: a
   132px time column would leave the description too narrow to read. */
@media (min-width: 620px) and (max-width: 999px) {
  .zday__list li { grid-template-columns: 132px 1fr; gap: 18px; align-items: baseline; }
}
.zday__list li:last-child { border-bottom: none; }
.zday__list b {
  font-family: 'IBM Plex Mono', monospace; font-weight: 500; font-size: 12.5px;
  letter-spacing: .06em; color: var(--batumi); white-space: nowrap;
}
.zday__list strong { display: block; color: #fff; font-size: 15px; font-weight: 700; margin-bottom: 3px; }
.zday__list span { font-size: 14px; line-height: 1.55; color: rgba(255,255,255,.75); }

.zclaim { text-align: center; font-size: 16px; }

/* Two-column block with a photo ------------------------------------------- */
.zsplit { display: grid; grid-template-columns: 1fr; gap: 28px; align-items: center; }
@media (min-width: 900px) { .zsplit { grid-template-columns: 1.35fr .65fr; } }
@media (min-width: 900px) { .zsplit--reverse { grid-template-columns: .9fr 1.1fr; } }
.zsplit__photo img { width: 100%; height: auto; border-radius: 20px; border: 1px solid rgba(255,255,255,.14); }

.zchecks { list-style: none; }
.zchecks li {
  position: relative; padding: 13px 0 13px 40px;
  border-bottom: 1px solid rgba(255,255,255,.10);
  font-size: 15.5px; color: rgba(255,255,255,.84);
}
.zchecks li:last-child { border-bottom: none; }
.zchecks li::before {
  content: ''; position: absolute; left: 0; top: 16px;
  width: 20px; height: 20px; border-radius: 6px;
  border: 1px solid rgba(20,185,145,.55); background: rgba(20,185,145,.16);
}
.zchecks li::after {
  content: ''; position: absolute; left: 7px; top: 21px;
  width: 5px; height: 9px; border-right: 2px solid var(--batumi); border-bottom: 2px solid var(--batumi);
  transform: rotate(45deg);
}

/* Hero headline. The page has to read as a TRIP first and a location second,
   so "Investičný zájazd" is the H1 and the subline carries the invitation. */
.ztitle { text-transform: uppercase; letter-spacing: -.025em; }
.zsub {
  margin-top: 14px; color: var(--batumi);
  font-size: clamp(20px, 3vw, 34px); font-weight: 800; line-height: 1.1;
}

/* Trip hero panels and day cards, flat on phones for the same reason. */
@media (max-width: 760px) {
  .zcard, .zday {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(8, 32, 42, .84);
  }
}

/* --- src/css/modules/17-trip-band.css --- */
/* ==========================================================================
   Trip invitation band on the landing page.
   ========================================================================== */
.zband { position: relative; padding: 90px 0; background-size: cover; background-position: center 62%; }
.zband::before {
  content: ''; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(180deg,
    var(--seam) 0%, rgba(4,18,24,.90) 8%, rgba(5,24,31,.84) 50%,
    rgba(4,18,24,.94) 92%, var(--seam) 100%);
}
.zband > * { position: relative; z-index: 1; }
/* Single centred column. Used to be text on the left, QR on the right; the
   QR was removed from this band (still lives on the trip modal and on
   zajazd.html), so the text block now just centres itself in the wide
   section instead of sharing a two-column grid. */
.zband__inner { max-width: 720px; margin: 0 auto; }
.zband__text h2 {
  margin-top: 12px; color: #fff; font-weight: 800; letter-spacing: -.02em;
  font-size: clamp(26px, 3.6vw, 40px); line-height: 1.08;
}
.zband__text p { margin-top: 16px; max-width: 60ch; font-size: 16px; line-height: 1.6; color: rgba(255,255,255,.82); }

.zband__facts { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px; }
.zband__facts div {
  padding: 12px 18px; border-radius: 14px;
  background: rgba(8,32,42,.55); border: 1px solid rgba(255,255,255,.18);
  backdrop-filter: blur(12px); -webkit-backdrop-filter: blur(12px);
}
.zband__facts b { display: block; color: var(--batumi); font-size: 18px; font-weight: 800; }
.zband__facts span {
  display: block; margin-top: 3px;
  font-family: 'IBM Plex Mono', monospace; font-size: 10px;
  letter-spacing: .12em; text-transform: uppercase; color: rgba(255,255,255,.6);
}

/* Same reasoning as the nav and the cards: these three sit over a photo, so
   each of them re-blurs it while the band is on screen. Flat on phones. */
@media (max-width: 760px) {
  .zband__facts > div {
    backdrop-filter: none; -webkit-backdrop-filter: none;
    background: rgba(10, 38, 48, .82);
  }
}
