/* ==========================================================================
   base.css — the shared foundation: tokens, reset, section frame, header,
   preloader, form, footer.
   Character — type, rhythm, cards, hero — lives in theme-final.css.
   Colours come from the client's palette: #050018 ground, #f8f1b4 accent.
   ========================================================================== */

/* --------------------------------------------------------------------------
   PALETTE
   #050018 is the ground colour named in the client's brief. It is rgb(5,0,24),
   so there is a little red in it and the darkness reads faintly violet — that
   is intended, and it matches the material the client already uses.

   --ink-rgb holds the same colour as numbers. The veils laid over photographs
   are built from it — rgb(var(--ink-rgb) / 0.7) — so the dimming always
   belongs to the current ground rather than to a hard-coded one.
   -------------------------------------------------------------------------- */
:root {
  --ink-rgb:    5 0 24;
  --ink:        #050018;
  --ink-soft:   #0a0327;
  --ink-lift:   #0d0530;
  --gold:       #f8f1b4;
  --gold-dim:   rgba(248, 241, 180, 0.55);
  --hairline:   rgba(248, 241, 180, 0.20);
  --hairline-2: rgba(248, 241, 180, 0.10);
  --white:      #ffffff;
  --muted:      rgba(255, 255, 255, 0.68);
  --muted-2:    rgba(255, 255, 255, 0.45);

  --shell:      min(1280px, 100% - 2 * var(--gutter));
  --gutter:     clamp(1.25rem, 4vw, 4rem);
  --section-y:  clamp(4.5rem, 9vw, 9rem);

  --ease:       cubic-bezier(0.22, 0.61, 0.36, 1);
  /* Header height, at the client's request: 108 px with a larger mark inside it.
     It is a token rather than a number on .nav because half the page depends on
     it — the first screen's top padding, the anchor scroll offset and the mobile
     menu panel all read it. Change it here and they follow. */
  --nav-h:      108px;
}

*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  /* An anchor must not land underneath the sticky header. */
  scroll-padding-top: var(--nav-h);
  -webkit-text-size-adjust: 100%;
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  background: var(--ink);
  color: var(--white);
  /* No synthesised faces. Where a weight or an italic is missing the browser
     will fake it by slanting or smearing the letterforms, and at the size of
     the first-screen headline that is immediately visible and looks cheap.
     An upright face is better than a counterfeit italic. */
  font-synthesis: none;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img, video, svg { display: block; max-width: 100%; }
/* <picture> defines the box and the image inside fills it. Left inline, as it
   is by default, <picture> would collapse to its contents and drag the layout
   with it. */
picture { display: block; }
picture > img { width: 100%; height: 100%; object-fit: cover; }
img, video { height: auto; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
ul { margin: 0; padding: 0; list-style: none; }
h1, h2, h3, h4, p { margin: 0; text-wrap: pretty; }
h1, h2, h3 { text-wrap: balance; font-weight: 400; }

:focus-visible { outline: 2px solid var(--gold); outline-offset: 3px; }

.shell { width: var(--shell); margin-inline: auto; }
.section { position: relative; padding-block: var(--section-y); }
.rule { height: 1px; background: var(--hairline); border: 0; margin: 0; }
.gold { color: var(--gold); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* GRADIENTS ONLY EVER SIT ON TOP OF IMAGERY.
   The page ground is flat #050018 from the client's palette — no glows, no
   washes. A gradient here does exactly one job: dim a photograph or a video
   frame so that text stays readable over it. Sections have no background
   gradient of their own. There used to be radial pools here and they pulled
   the colour towards violet, away from the palette. If the urge to "liven up"
   the background returns, this is not the place for it. */

/* --------------------------------------------------------------------------
   Preloader: the mark draws itself as a line, then the curtain lifts.
   This answers the reference site's grand opening, which costs 200 KB of
   Lottie. Here it is CSS.
   -------------------------------------------------------------------------- */
.preloader {
  position: fixed; inset: 0; z-index: 100;
  display: grid; place-items: center;
  background: var(--ink);
  transition: transform 0.9s var(--ease) 0.15s, visibility 0s linear 1.05s;
}
.preloader__mark { width: clamp(120px, 18vw, 190px); color: var(--gold); }
 /* The curve declares pathLength="100" in the SVG, so the dash figures here
    are exactly 100 — no fitting to the ellipse's real perimeter. */
.preloader__mark ellipse {
  stroke-dasharray: 100;
  stroke-dashoffset: 100;
  animation: draw 1.5s var(--ease) forwards;
}
.preloader__mark ellipse:nth-child(1) { animation-delay: 0.00s; }
.preloader__mark ellipse:nth-child(2) { animation-delay: 0.10s; }
.preloader__mark ellipse:nth-child(3) { animation-delay: 0.20s; }
.preloader__mark ellipse:nth-child(4) { animation-delay: 0.30s; }
.preloader__mark ellipse:nth-child(5) { animation-delay: 0.40s; }
.preloader__mark ellipse:nth-child(6) { animation-delay: 0.50s; }
/* Delays are declared with room to spare: without them any curve beyond the
   listed ones would start at zero seconds along with the first. */
.preloader__mark ellipse:nth-child(7) { animation-delay: 0.60s; }
.preloader__mark ellipse:nth-child(8) { animation-delay: 0.70s; }
.preloader__mark ellipse:nth-child(9) { animation-delay: 0.80s; }
.preloader__mark ellipse:nth-child(10) { animation-delay: 0.90s; }
.preloader__mark ellipse:nth-child(11) { animation-delay: 1.00s; }
.preloader__mark ellipse:nth-child(12) { animation-delay: 1.10s; }
.preloader__word {
  margin-top: 1.5rem; text-align: center;
  font-size: clamp(0.72rem, 1.4vw, 0.9rem);
  letter-spacing: 0.42em; text-indent: 0.42em;
  color: var(--gold-dim);
  opacity: 0; animation: fade 0.8s var(--ease) 1.05s forwards;
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes fade { to { opacity: 1; } }

body.is-loaded .preloader { transform: translateY(-101%); visibility: hidden; }

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

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
.nav {
  position: fixed; inset-block-start: 0; inset-inline: 0; z-index: 50;
  height: var(--nav-h);
  display: flex; align-items: center;
  transition: background 0.4s var(--ease), border-color 0.4s var(--ease);
  border-block-end: 1px solid transparent;
}
.nav.is-stuck {
  background: rgb(var(--ink-rgb) / 0.82);
  backdrop-filter: blur(14px) saturate(140%);
  -webkit-backdrop-filter: blur(14px) saturate(140%);
  border-block-end-color: var(--hairline-2);
}
.nav__inner {
  width: var(--shell); margin-inline: auto;
  display: flex; align-items: center; justify-content: space-between; gap: 2rem;
}
.brand { display: flex; align-items: center; gap: 0.9rem; color: var(--gold); }
/* The mark and the wordmark grew with the header, and grew again at the
   client's request — he asked for the weight the mark carries on helarb.com,
   where it is the largest thing in the bar. 72 px inside a 108 px header
   leaves 18 px of air above and below, which is the most the header can give
   without the mark touching its edges. The width/height attributes in the
   markup stay as a fallback for a stylesheet that has not arrived yet; the
   size that counts is this one. */
.brand svg { width: 72px; height: 72px; flex: none; }
.brand__word {
  font-size: 1.12rem; letter-spacing: 0.3em; text-indent: 0.3em;
  white-space: nowrap; color: var(--white);
}
.nav__links { display: flex; align-items: center; gap: clamp(1rem, 2.2vw, 2.25rem); }
.nav__link {
  position: relative; padding-block: 0.4rem;
  font-size: 0.82rem; letter-spacing: 0.09em;
  color: var(--muted); transition: color 0.25s var(--ease);
}
.nav__link::after {
  content: ""; position: absolute; inset-inline: 0; inset-block-end: 0;
  height: 1px; background: var(--gold);
  transform: scaleX(0); transform-origin: right;
  transition: transform 0.3s var(--ease);
}
.nav__link:hover { color: var(--white); }
.nav__link:hover::after,
.nav__link.is-active::after { transform: scaleX(1); transform-origin: left; }
.nav__link.is-active { color: var(--gold); }

/* Menu button: three gold bars.
   A 1 px white hairline disappeared on the first screen, where the header is
   transparent and the photograph behind it is bright sky. So the bars became
   thicker, took the accent colour and gained a soft shadow — that holds
   contrast over any frame without giving the button a visible plate. */
.nav__burger { display: none; width: 34px; height: 34px; position: relative; }
.nav__burger span {
  position: absolute; inset-inline: 4px; height: 2px; border-radius: 1px;
  background: var(--gold);
  filter: drop-shadow(0 1px 2px rgb(var(--ink-rgb) / 0.65));
  transition: transform 0.3s var(--ease), opacity 0.2s var(--ease);
}
.nav__burger span:nth-child(1) { top: 10px; }
.nav__burger span:nth-child(2) { top: 16px; }
.nav__burger span:nth-child(3) { top: 22px; }
/* Open menu becomes a cross: the middle bar fades, the outer two meet and turn. */
body.is-menu-open .nav__burger span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
body.is-menu-open .nav__burger span:nth-child(2) { opacity: 0; }
body.is-menu-open .nav__burger span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* The mark, the wordmark and the burger have to fit across a 320 px phone in
   one row, so the brand steps down here — the header keeps its height. The
   step is smaller than it was, because the client asked for a bigger logo on
   the phone specifically; 56 px plus the letterspaced wordmark plus the burger
   comes to about 305 px, which still clears the narrowest screen we support.
   Anything larger and the wordmark collides with the burger. */
@media (max-width: 560px) {
  .brand svg { width: 56px; height: 56px; }
  .brand__word { font-size: 0.92rem; }
}

@media (max-width: 900px) {
  .nav__burger { display: block; }
  .nav__links {
    position: fixed; inset: var(--nav-h) 0 0; z-index: 49;
    flex-direction: column; justify-content: center; gap: 1.75rem;
    background: rgb(var(--ink-rgb) / 0.97);
    backdrop-filter: blur(18px);
    opacity: 0; visibility: hidden; transition: opacity 0.35s var(--ease), visibility 0.35s;
  }
  .nav__link { font-size: 1.15rem; }
  body.is-menu-open .nav__links { opacity: 1; visibility: visible; }
  body.is-menu-open { overflow: hidden; }
}

/* --------------------------------------------------------------------------
   Section heading
   -------------------------------------------------------------------------- */
.sec-head { position: relative; z-index: 1; margin-block-end: clamp(2.5rem, 5vw, 4rem); }
.sec-head__eyebrow {
  display: flex; align-items: center; gap: 0.9rem;
  font-size: 0.7rem; letter-spacing: 0.34em; text-indent: 0.34em;
  color: var(--gold-dim); margin-block-end: 1.1rem;
}
.sec-head__eyebrow::before {
  content: ""; width: clamp(24px, 4vw, 56px); height: 1px; background: var(--gold); flex: none;
}
.sec-head__intro { max-width: 48ch; margin-block-start: 1.1rem; color: var(--muted); line-height: 1.65; }

/* --------------------------------------------------------------------------
   Blocks revealing on scroll
   -------------------------------------------------------------------------- */
/* A block may be hidden ONLY when something is guaranteed to show it again:
   the .js class is set by the inline script in <head>. With scripting off, or
   if the file never arrives, the page stays completely readable. It goes to
   investors as a link, and a blank page costs more than any animation is
   worth. */
.js .reveal { opacity: 0; transform: translateY(22px); transition: opacity 0.8s var(--ease), transform 0.8s var(--ease); }
.js .reveal.is-in { opacity: 1; transform: none; }

/* The preloader follows the same rule: no JS, no curtain. */
html:not(.js) .preloader { display: none; }

/* --------------------------------------------------------------------------
   Form (beyond the brief — added by us)
   -------------------------------------------------------------------------- */
.form { display: grid; gap: 1.4rem; }
.form__row { display: grid; gap: 1.4rem; grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .form__row { grid-template-columns: 1fr; } }
.field { position: relative; }
.field input, .field textarea {
  width: 100%; padding: 0.95rem 0 0.7rem; color: var(--white);
  background: none; border: 0; border-block-end: 1px solid var(--hairline);
  font: inherit; font-size: 0.95rem; border-radius: 0;
  transition: border-color 0.3s var(--ease);
}
.field textarea { resize: vertical; min-height: 100px; }
.field input:focus, .field textarea:focus { outline: none; border-block-end-color: var(--gold); }
.field label {
  position: absolute; inset-block-start: 0.95rem; inset-inline-start: 0;
  font-size: 0.95rem; color: var(--muted-2); pointer-events: none;
  transition: transform 0.25s var(--ease), font-size 0.25s var(--ease), color 0.25s var(--ease);
}
.field input:focus + label,
.field textarea:focus + label,
.field input:not(:placeholder-shown) + label,
.field textarea:not(:placeholder-shown) + label {
  transform: translateY(-1.15rem); font-size: 0.68rem;
  letter-spacing: 0.16em; color: var(--gold-dim);
}
.btn {
  display: inline-flex; align-items: center; gap: 0.75rem; align-self: start;
  padding: 0.9rem 1.9rem; border: 1px solid var(--gold); color: var(--gold);
  font-size: 0.78rem; letter-spacing: 0.2em; text-transform: uppercase;
  transition: background 0.3s var(--ease), color 0.3s var(--ease);
}
.btn:hover { background: var(--gold); color: var(--ink); }
.btn svg { width: 14px; transition: transform 0.3s var(--ease); }
.btn:hover svg { transform: translateX(4px); }
.form__note { font-size: 0.78rem; color: var(--muted-2); }

/* The bot trap. Not display:none and not hidden — a fair share of spam scripts
   skip fields hidden that way, which defeats the point. The field is physically
   on the page but pushed off-screen, taking no space and no part in layout. */
.form__hp {
  position: absolute; left: -9999px; top: auto;
  width: 1px; height: 1px; opacity: 0; pointer-events: none;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */
.footer { padding-block: 2.5rem; border-block-start: 1px solid var(--hairline-2); }
.footer__inner {
  width: var(--shell); margin-inline: auto;
  display: flex; flex-wrap: wrap; gap: 1rem 2rem; align-items: center; justify-content: space-between;
  font-size: 0.75rem; letter-spacing: 0.08em; color: var(--muted-2);
}

/* A placeholder has to be loud, or it ships unnoticed. */
.placeholder {
  border-block-end: 1px dashed rgba(248, 241, 180, 0.5);
  color: var(--gold-dim);
}

/* Mobile strips use native scroll-snap rather than a carousel library.
   On desktop there is no horizontal scrolling at all, as the brief requires. */
@media (max-width: 760px) {
  .snap {
    display: flex; gap: 1rem;
    overflow-x: auto; scroll-snap-type: x mandatory;
    margin-inline: calc(-1 * var(--gutter)); padding-inline: var(--gutter);
    scrollbar-width: none;
  }
  .snap::-webkit-scrollbar { display: none; }
  .snap > * { flex: 0 0 78%; scroll-snap-align: start; }
}
