/* ==========================================================================
   Hahami Connect — temporary site
   Palette is taken verbatim from the designer's logo artwork:
     teal #32b9cc · orange #f39441 · purple #624592 · black · white
   Each of those becomes a theme; main.js picks one at random per page load.
   ========================================================================== */

/* ---------- Themes -------------------------------------------------------- */

/* Every stop below is the same hue as the designer's colour, kept saturated and
   only stepped down in lightness. Desaturating the dark end is what turns a
   brand gradient muddy, so none of these do. --base is the foot of the page. */

:root {
  /* Teal is the default so the page is still on-brand with JS disabled. */
  --brand:       #32b9cc;
  --brand-light: #6ad5e4;
  --brand-deep:  #14707f;
  --base:        #0d5462;

  --ink:      #ffffff;
  --ink-soft: rgba(255, 255, 255, .78);
  --ink-dim:  rgba(255, 255, 255, .55);
  --rule:     rgba(255, 255, 255, .18);
  --plate:    rgba(255, 255, 255, .16);
}

[data-theme="teal"] {
  --brand: #32b9cc; --brand-light: #6ad5e4; --brand-deep: #14707f; --base: #0d5462;
}

[data-theme="orange"] {
  --brand: #f39441; --brand-light: #ffbd80; --brand-deep: #a85c1c; --base: #7a3f10;
}

[data-theme="purple"] {
  --brand: #624592; --brand-light: #9a7ecb; --brand-deep: #3b2759; --base: #281a3d;
}

[data-theme="ink"] {
  --brand: #1d3742; --brand-light: #33505d; --brand-deep: #101f26; --base: #080f13;
}

/* The designer also supplies a black logo for light grounds — that variant. */
[data-theme="light"] {
  --brand: #ffffff; --brand-light: #ffffff; --brand-deep: #e9f2f4; --base: #dceaee;

  --ink:      #0f1c21;
  --ink-soft: rgba(15, 28, 33, .76);
  --ink-dim:  rgba(15, 28, 33, .55);
  --rule:     rgba(15, 28, 33, .16);
  --plate:    rgba(15, 28, 33, .10);
}

/* ---------- Base ---------------------------------------------------------- */

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  position: relative;   /* containing block for .backdrop, so it spans the document */
  margin: 0;
  background: var(--base);
  color: var(--ink);
  font-family: "Helvetica Neue", -apple-system, BlinkMacSystemFont, "Segoe UI",
               Inter, Roboto, system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  /* `clip`, not `hidden`: overflow-x:hidden forces overflow-y to compute to
     auto, which turns <body> into a scroll container and stops the page
     scrolling entirely. Browsers without `clip` ignore this line harmlessly. */
  overflow-x: clip;
}

img, svg { display: block; max-width: 100%; }

a { color: inherit; }

.wrap {
  width: min(100% - 2.5rem, 62rem);
  margin-inline: auto;
}

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: .75rem 1.25rem;
  background: var(--ink);
  color: var(--base);
  font-size: .875rem;
  text-decoration: none;
}
.skip-link:focus { left: 0; }

:focus-visible {
  outline: 2px solid var(--ink);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ---------- Backdrop -----------------------------------------------------
   Two very large, slowly drifting radial pools plus a film grain. This is what
   keeps a flat brand colour from reading as flat — it stays subtle enough never
   to cost text contrast.
   ------------------------------------------------------------------------- */

/* One smooth top-to-bottom gradient spanning the whole document — no radial
   pools or drifting blobs, which read as off-brand dark patches rather than
   depth. Absolute (not fixed) so the gradient maps to the page: the hero sits
   in the bright brand colour and the copy below lands on the deep end. */
.backdrop {
  /* inset:0 stretches to the full document height; `height:100%` would resolve
     to auto against an auto-height body and collapse. */
  position: absolute;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
  background: linear-gradient(
    180deg,
    var(--brand-light) 0%,
    var(--brand)       15%,
    var(--brand-deep)  54%,
    var(--base)        100%
  );
}

.backdrop__grain {
  position: absolute;
  inset: 0;
  opacity: .035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='220' height='220'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.82' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ---------- Hero ---------------------------------------------------------- */

.hero {
  position: relative;
  min-height: 100vh;
  min-height: 100svh;   /* excludes mobile browser chrome */
  display: grid;
  place-items: center;
  padding:
    clamp(3.5rem, 12vh, 8rem)
    calc(1.25rem + env(safe-area-inset-right))
    clamp(4.5rem, 14vh, 9rem)
    calc(1.25rem + env(safe-area-inset-left));
}

.hero__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
}

/* --- the masked mark --- */

/* The mark is 612x440 (ratio 1.391). Deriving the width from a viewport-height
   cap as well as a width cap keeps it fully visible on short and landscape
   screens instead of pushing the wordmark off the bottom of the hero. */
.mark {
  width: min(88vw, 40rem, calc(44vh * 1.391));
  width: min(88vw, 40rem, calc(44svh * 1.391));
  height: auto;
  overflow: visible;
}

/* Entrance: every pill starts as a dot on the centre line, then a wave runs
   left to right — each overshoots its resting height and settles, the way a
   signal hits a level meter. Only the clip geometry animates, so rx stays 50
   against a constant 100 width and the caps stay perfectly circular throughout.
   Once the wave has passed, a slow idle breath keeps the mark alive. */
/* Per-pill geometry. These live here rather than in `style` attributes on the
   SVG because the production CSP sets `style-src 'self'`, which blocks inline
   styles outright — the custom properties never landed and the wave animated
   from a circle to nothing, leaving the hero blank.
     --h/--y   resting height and top edge
     --peak    overshoot the travelling wave passes through
   Every pill stays centred on y=220, so --y is always 220 - --h/2. */
.pill-shape--1 { --i: 0; --h: 409px; --y: 15.5px;  --peak: 466px; --peak-y: -13px;   }
.pill-shape--2 { --i: 1; --h: 118px; --y: 161px;   --peak: 135px; --peak-y: 152.5px; }
.pill-shape--3 { --i: 2; --h: 197px; --y: 121.5px; --peak: 225px; --peak-y: 107.5px; }
.pill-shape--4 { --i: 3; --h: 102px; --y: 169px;   --peak: 116px; --peak-y: 162px;   }
.pill-shape--5 { --i: 4; --h: 233px; --y: 103.5px; --peak: 266px; --peak-y: 87px;    }

.mark__pill--1 { --i: 0; }
.mark__pill--2 { --i: 1; }
.mark__pill--3 { --i: 2; }
.mark__pill--4 { --i: 3; }
.mark__pill--5 { --i: 4; }

.pill-shape {
  animation:
    wave-in   1.7s both,
    wave-idle 7s   ease-in-out infinite;
  animation-delay:
    calc(var(--i) * 120ms + 180ms),
    calc(var(--i) * 220ms + 2.4s);
}

/* A CSS timing function applies to each keyframe segment separately, so the rise
   and the settle are eased independently: the rise leads out fast, the fall
   back from the overshoot eases in and out so it never snaps down. */
@keyframes wave-in {
  0% {
    height: 100px; y: 170px;                      /* a circle on the centre line */
    animation-timing-function: cubic-bezier(.2, .75, .3, 1);
  }
  46% {
    height: var(--peak); y: var(--peak-y);        /* overshoot */
    animation-timing-function: cubic-bezier(.45, 0, .25, 1);
  }
  100% {
    height: var(--h); y: var(--y);                /* settle */
  }
}

@keyframes wave-idle {
  0%, 100% { height: var(--h); y: var(--y); }
  50%      { height: calc(var(--h) * 1.055);
             y:      calc(220px - var(--h) * 1.055 / 2); }
}

/* The photograph fades up with its pill. */
.mark__pill {
  animation: pill-fade .8s ease both;
  animation-delay: calc(var(--i) * 120ms + 180ms);
}

@keyframes pill-fade {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* Visible if a photograph fails to load — the logo shape still reads. */
.mark__plate { fill: var(--plate); }

/* Slow drift inside each pill. The clip lives on the parent <g>, so moving the
   image never moves the mask. */
.mark__photo {
  transform-box: fill-box;
  transform-origin: center;
  animation: photo-drift 26s ease-in-out infinite alternate;
  animation-delay: calc(var(--i) * -5s);
}

@keyframes photo-drift {
  from { transform: scale(1);    }
  to   { transform: scale(1.06); }
}

/* --- wordmark + tagline --- */

.lockup {
  margin: clamp(2.75rem, 6vh, 4.25rem) 0 0;
  animation: rise 900ms cubic-bezier(.16, .84, .28, 1) both;
  animation-delay: 700ms;
}

.lockup__img {
  width: clamp(9rem, 21vw, 14rem);
  height: auto;
  /* The wordmark SVG is monochrome; tint it to the theme's foreground. */
  filter: brightness(0) invert(1);
}

[data-theme="light"] .lockup__img,
[data-theme="light"] .footer__mark { filter: none; }

.tagline {
  margin: clamp(2rem, 4.5vh, 3.25rem) 0 0;
  font-size: clamp(1.0625rem, 2.4vw, 1.5rem);
  font-weight: 300;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--ink);
  text-shadow: 0 1px 22px color-mix(in srgb, var(--brand-deep) 70%, transparent);
  animation: rise 900ms cubic-bezier(.16, .84, .28, 1) both;
  animation-delay: 840ms;
}

[data-theme="light"] .tagline { text-shadow: none; }

@keyframes rise {
  from { transform: translateY(18px); opacity: 0; }
  to   { transform: translateY(0);    opacity: 1; }
}

/* --- scroll cue --- */

.scroll-cue {
  position: absolute;
  bottom: clamp(1.5rem, 4vh, 2.75rem);
  left: 50%;
  translate: -50% 0;
  display: grid;
  place-items: center;
  width: 2.5rem;
  height: 3.5rem;
  animation: rise 900ms ease both;
  animation-delay: 1.15s;
}

.scroll-cue__line {
  width: 1px;
  height: 2.75rem;
  background: linear-gradient(180deg, transparent, var(--ink-soft));
  transform-origin: top;
  animation: cue 2.6s ease-in-out infinite;
}

@keyframes cue {
  0%, 100% { transform: scaleY(.35); opacity: .35; }
  50%      { transform: scaleY(1);   opacity: 1; }
}

/* ---------- About --------------------------------------------------------- */

.about {
  position: relative;
  padding: clamp(4.5rem, 13vh, 8.5rem) 0 clamp(3.5rem, 9vh, 6rem);
}

.about__kicker {
  margin: 0 0 1.75rem;
  font-size: .75rem;
  font-weight: 500;
  letter-spacing: .34em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.about__lead {
  margin: 0 0 1.5rem;
  max-width: 34ch;
  font-size: clamp(1.5rem, 4.4vw, 2.5rem);
  font-weight: 300;
  line-height: 1.28;
  letter-spacing: -.015em;
}

.about__lead strong {
  font-weight: 400;
  color: var(--brand-light);
}

[data-theme="light"] .about__lead strong { color: #1d8fa0; }

.about__body {
  margin: 0;
  max-width: 52ch;
  font-size: clamp(1rem, 1.9vw, 1.125rem);
  color: var(--ink-soft);
}

/* --- pillars --- */

.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  margin: clamp(3rem, 8vh, 5rem) 0 0;
  padding: 0;
  list-style: none;
  border-top: 1px solid var(--rule);
}

.pillars__item {
  padding: 2rem 0 .5rem;
}

/* Stacked on narrow screens, so the divider is a top rule between rows. */
.pillars__item + .pillars__item { border-top: 1px solid var(--rule); }

/* Side by side once there is room — the divider becomes a vertical hairline. */
@media (min-width: 48rem) {
  .pillars__item { padding-right: 2rem; }
  .pillars__item + .pillars__item {
    border-top: 0;
    border-left: 1px solid var(--rule);
    padding-left: 2rem;
  }
}

.pillars__word {
  display: block;
  font-size: 1.25rem;
  font-weight: 400;
  letter-spacing: .01em;
}

.pillars__note {
  display: block;
  margin-top: .5rem;
  max-width: 26ch;
  font-size: .9375rem;
  color: var(--ink-soft);
}

/* ---------- Contact ------------------------------------------------------- */

.contact {
  position: relative;
  padding: clamp(3.5rem, 10vh, 6.5rem) 0 clamp(4rem, 11vh, 7rem);
}

.contact__note {
  margin: 0 0 1rem;
  font-size: .8125rem;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.contact__title {
  margin: 0 0 1.25rem;
  font-size: clamp(2rem, 6vw, 3.25rem);
  font-weight: 300;
  letter-spacing: -.02em;
}

.contact__list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(14rem, 1fr));
  gap: 2rem 2.5rem;
  margin: clamp(2rem, 5vh, 3rem) 0 0;
  padding: 0;
  list-style: none;
}

.contact__label {
  display: block;
  margin-bottom: .5rem;
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .28em;
  text-transform: uppercase;
  color: var(--ink-dim);
}

.contact__value {
  display: inline-block;
  font-size: clamp(1rem, 2.2vw, 1.25rem);
  font-weight: 300;
  letter-spacing: .01em;
  text-decoration: none;
  padding-bottom: .3rem;
  border-bottom: 1px solid var(--rule);
  /* Long strings (email, address) must not push the grid wider on small screens. */
  overflow-wrap: break-word;
  transition: border-color .35s ease, color .35s ease;
}

.contact__value:hover,
.contact__value:focus-visible {
  color: var(--brand-light);
  border-bottom-color: currentColor;
}

[data-theme="light"] .contact__value:hover,
[data-theme="light"] .contact__value:focus-visible { color: #1d8fa0; }

/* ---------- Footer -------------------------------------------------------- */

.footer {
  padding: 2rem 0 clamp(2rem, 5vh, 3rem);
  border-top: 1px solid var(--rule);
}

.footer__inner {
  display: flex;
  align-items: center;
  gap: .875rem;
}

.footer__mark {
  width: 1.125rem;
  height: auto;
  opacity: .8;
  filter: brightness(0) invert(1);
}

.footer__copy {
  margin: 0;
  font-size: .8125rem;
  color: var(--ink-dim);
}

/* ---------- Responsive ----------------------------------------------------
   Type and spacing are fluid via clamp() throughout, so these are the cases
   fluid sizing alone does not cover.
   ------------------------------------------------------------------------- */

/* Keep the page clear of notches and home indicators. */
.wrap {
  padding-inline: max(0px, env(safe-area-inset-left)) max(0px, env(safe-area-inset-right));
}

.footer { padding-bottom: calc(clamp(2rem, 5vh, 3rem) + env(safe-area-inset-bottom)); }

/* Phones. Tighten the hero and give links a comfortable tap target. */
@media (max-width: 40rem) {
  .hero { padding-bottom: clamp(3.5rem, 11vh, 5rem); }

  .tagline { letter-spacing: .12em; }

  .contact__list { gap: 1.75rem; }

  .contact__value,
  .scroll-cue {
    min-height: 44px;          /* WCAG target size */
    display: flex;
    align-items: center;
  }

  .scroll-cue { justify-content: center; }
}

/* Landscape phones and other short viewports: the hero must still fit, so drop
   the vertical rhythm rather than let the lockup slide off-screen. */
@media (max-height: 34rem) and (orientation: landscape) {
  .hero {
    min-height: 0;
    padding-block: 3rem 3.5rem;
  }
  .mark { width: min(62vw, 30rem, calc(52vh * 1.391)); }
  .lockup { margin-top: 1.25rem; }
  .tagline { margin-top: .875rem; }
  .scroll-cue { display: none; }
}

/* Large desktops: stop the measure from stretching past comfortable reading. */
@media (min-width: 90rem) {
  .wrap { width: min(100% - 4rem, 68rem); }
}

/* ---------- Scroll reveal -------------------------------------------------
   The .reveal class is added by main.js, so anything below the fold stays
   visible when JavaScript does not run.
   ------------------------------------------------------------------------- */

/* The scroll-reveal that used to live here has been removed deliberately.
   Hiding copy with opacity:0 and relying on a script to reveal it fails closed:
   a throttled background tab, a prerender, a bfcache restore or one JS error
   leaves the whole lower half of the page blank. Body copy is now visible from
   first paint. The hero's wave animation stays - it animates a mask, so if it
   never runs the artwork is simply static rather than missing. */

/* ---------- Reduced motion ------------------------------------------------ */

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .pill-shape,
  .mark__pill,
  .mark__photo,
  .lockup,
  .tagline,
  .scroll-cue,
  .scroll-cue__line {
    animation: none !important;
  }

  /* Clip rects keep their authored geometry, so the mark renders at rest. */
  .mark__pill { opacity: 1; transform: none; }
  .lockup, .tagline, .scroll-cue { opacity: 1; transform: none; }
}
