/* =========================================================================
   inomba — landing (3D)
   Ported from "inomba 3D hero.html" prototype (React + WebGL bundle).
   Vanilla CSS, no build step.

   Renderer classes set by hero.js:
     .hero--gl  WebGL ribbons; colour-reveal figure layer active
     .hero--2d  no WebGL; previous /site 2D-strands look, subtle figure
     (neither)  no JS/canvas; static dim figure + vignette
   ========================================================================= */

/* -------------------------------------------------------------------------
   1. Fonts — self-hosted subsets. unicode-range keeps unused subsets off the
   wire, so all of them can be declared at zero cost.
   ------------------------------------------------------------------------- */

/* Space Grotesk is a variable font: one file serves weights 400–700. */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url('../fonts/space-grotesk-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/space-mono-400-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/space-mono-400-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/space-mono-400-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/space-mono-700-vietnamese.woff2') format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/space-mono-700-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Space Mono';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/space-mono-700-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* -------------------------------------------------------------------------
   2. Tokens
   ------------------------------------------------------------------------- */
:root {
  /* Palette — lifted verbatim from the prototype */
  --ink:          #0a0a0d;
  --text-hi:      #f6f4f0;
  --text-brand:   #eceae6;
  --text-mid:     #bdb9b3;
  --text-btn:     #d3cfc8;
  --accent:       #e66633;
  --hairline:     rgba(255, 255, 255, 0.22);
  --select:       #ffc414;

  --font-sans: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'Space Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Fluid type — linear 360px → 1440px, then capped at the prototype's values.
     Overridden wholesale in the large-screen / TV blocks below. */
  --fs-title:   clamp(2.125rem, 1.458rem + 2.963vw, 4.125rem); /* 34 → 66px */
  --fs-sub:     clamp(1.0625rem, 0.794rem + 1.194vw, 1.869rem); /*  17 → 29.9px */
  --fs-brand:   clamp(1.0625rem, 0.958rem + 0.463vw, 1.375rem); /*  17 → 22px */
  --fs-eyebrow: clamp(0.6875rem, 0.66rem + 0.05vw, 0.75rem);    /*  11 → 12px */
  --fs-btn:     clamp(0.6875rem, 0.66rem + 0.06vw, 0.78125rem); /*  11 → 12.5px */

  --mark-size:  clamp(1.75rem, 1.583rem + 0.741vw, 2.25rem);    /*  28 → 36px */
  --figure-w:   min(660px, 52vw);

  /* Frame */
  --pad-x: max(1.25rem, 6vw);
  --pad-y: clamp(1.125rem, 0.7rem + 1.85vw, 1.875rem);          /*  18 → 30px */
  --content-bottom: max(2rem, calc(15vh - var(--pad-y)));
}

/* svh landed across browsers in 2022; older smart-TV Chromium builds predate
   it. Declared separately so an unsupported unit falls back instead of
   invalidating the custom property at computed-value time. */
@supports (height: 100svh) {
  :root { --content-bottom: max(2rem, calc(15svh - var(--pad-y))); }
}

/* Tablet — the figure would be lost at 52vw, so let it breathe. */
@media (max-width: 1024px) {
  :root { --figure-w: min(660px, 66vw); }
}
@media (max-width: 640px) {
  :root { --figure-w: min(660px, 80vw); }
}

/* Large desktop / TV. Beyond ~1800px the viewer is further away, so type
   scales past the prototype cap rather than stranding it in a corner. */
@media (min-width: 1800px) {
  :root {
    --fs-title:   5.25rem;   /*  84px */
    --fs-sub:     2.375rem;  /*  38px */
    --fs-brand:   1.75rem;   /*  28px */
    --fs-eyebrow: 0.9375rem; /*  15px */
    --fs-btn:     1rem;      /*  16px */
    --mark-size:  2.875rem;  /*  46px */
    --figure-w:   min(920px, 46vw);
    --pad-y:      2.5rem;
  }
}
@media (min-width: 2560px) {
  :root {
    --fs-title:   7.5rem;    /* 120px */
    --fs-sub:     3.375rem;  /*  54px */
    --fs-brand:   2.5rem;    /*  40px */
    --fs-eyebrow: 1.25rem;   /*  20px */
    --fs-btn:     1.375rem;  /*  22px */
    --mark-size:  4rem;      /*  64px */
    --figure-w:   min(1400px, 44vw);
    --pad-y:      3.5rem;
  }
}

/* A 4K panel reporting 3840 CSS px (rather than 1920 @2x) needs another rung,
   or the type holds at the 2560 values and ends up *relatively* smaller than
   on a laptop — backwards for something viewed from a sofa. Each step keeps
   the title at ~4.7% of viewport width, matching the 66px/1440px original. */
@media (min-width: 3200px) {
  :root {
    --fs-title:   11.25rem;  /* 180px */
    --fs-sub:     5rem;      /*  80px */
    --fs-brand:   3.75rem;   /*  60px */
    --fs-eyebrow: 1.75rem;   /*  28px */
    --fs-btn:     2rem;      /*  32px */
    --mark-size:  6rem;      /*  96px */
    --figure-w:   min(2100px, 44vw);
    --pad-y:      5rem;
  }
}

/* -------------------------------------------------------------------------
   3. Base
   ------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  background: var(--ink);
}

body {
  font-family: var(--font-sans);
  color: var(--text-hi);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

a {
  color: inherit;
  text-decoration: none;
  transition: opacity 0.2s ease;
}
@media (hover: hover) {
  a:hover { opacity: 0.6; }
}

::selection { background: var(--select); color: #141414; }

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

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: 10px 16px;
  background: var(--select);
  color: #141414;
  font-family: var(--font-mono);
  font-size: 13px;
}
.skip-link:focus { left: 8px; top: 8px; }

/* -------------------------------------------------------------------------
   4. Hero
   The prototype absolutely-positioned every layer against a 100vh box. Here
   the content is a flex column instead, so a short landscape phone pushes
   text down gracefully instead of overlapping the header.
   ------------------------------------------------------------------------- */
.hero {
  position: relative;
  display: flex;
  flex-direction: column;
  min-height: 100vh;          /* fallback */
  min-height: 100svh;         /* excludes mobile browser chrome */
  padding: var(--pad-y) var(--pad-x);
  padding-top: max(var(--pad-y), env(safe-area-inset-top));
  overflow: hidden;
  background: var(--ink);
  isolation: isolate;
}
@media (hover: hover) and (pointer: fine) {
  .hero { cursor: crosshair; }
}

.hero__canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  z-index: 0;
}

/* Figure — a wrapper hero.js moves for parallax, holding two copies of the
   image: a dim grayscale base and a colour layer revealed through a
   pointer-following radial mask. Both blend with screen, so they brighten
   over the ribbons rather than occluding them. */
.hero__figure {
  position: absolute;
  left: 50%;
  top: 52%;
  transform: translate(-50%, -50%);
  width: var(--figure-w);
  pointer-events: none;
  will-change: transform;
  z-index: 1;
}

.hero__figure picture { display: block; }

.hero__figure-base {
  display: block;
  width: 100%;
  height: auto;
  filter: grayscale(1) brightness(2.1) contrast(0.7);
  opacity: 0.2;
  mix-blend-mode: screen;
}

/* Hidden until hero.js confirms WebGL and adds .hero--gl — a no-JS page or
   the 2D fallback never flashes the unmasked colour figure. The pre-mask
   below covers the first frames before JS writes the following mask; it is
   overwritten inline every animation frame. */
.hero__figure-reveal {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: auto;
  opacity: 0;
  mix-blend-mode: screen;
  -webkit-mask-image: radial-gradient(circle at 50% 45%, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.28) 45%, transparent 72%);
  mask-image: radial-gradient(circle at 50% 45%, rgba(0, 0, 0, 0.9) 0%, rgba(0, 0, 0, 0.28) 45%, transparent 72%);
  transition: opacity 0.5s ease;
}

.hero--gl .hero__figure-reveal { opacity: 0.9; }

/* 2D fallback: previous /site figure treatment — fainter, softer. */
.hero--2d .hero__figure-base {
  filter: grayscale(1) brightness(1.85) contrast(0.72) blur(0.4px);
  opacity: 0.08;
  mix-blend-mode: normal;
}
.hero--2d .hero__figure-reveal { display: none; }

.hero__vignette {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(130% 100% at 50% 40%, transparent 36%, rgba(5, 5, 8, 0.8) 100%);
  z-index: 2;
}

/* Anchors the copy block: deepens the bottom-left corner so the headline
   sits on shadow rather than competing with ribbon glow. Sized in vmin so
   it scales from phone to 4K without a media-query ladder. */
.hero__corner-shade {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(52vmin 35vmin at 12% 92%, rgba(5, 5, 8, 0.72), rgba(5, 5, 8, 0.3) 55%, transparent 75%);
  z-index: 2;
}

/* --- header --- */
.hero__header {
  position: relative;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: clamp(0.5rem, 0.833vw, 0.75rem);
  min-width: 0;
}

.brand__mark {
  height: var(--mark-size);
  width: auto;
  display: block;
  flex: none;
}

.brand__word {
  font-size: var(--fs-brand);
  font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--text-brand);
  line-height: 1;
}

.btn {
  flex: none;
  font-family: var(--font-mono);
  font-size: var(--fs-btn);
  letter-spacing: 0.02em;
  color: var(--text-btn);
  border: 1px solid var(--hairline);
  padding: 0.5625em 1.44em;
  border-radius: 999px;
  white-space: nowrap;
  transition: opacity 0.2s ease, border-color 0.2s ease, background-color 0.2s ease;
}
@media (hover: hover) {
  .btn:hover {
    opacity: 1;
    border-color: rgba(255, 255, 255, 0.45);
    background-color: rgba(255, 255, 255, 0.05);
  }
}

/* Contact button. Default state assumes JS; the <noscript> block in the
   document head flips these if it is unavailable. */
.contact { display: inline-block; }
.contact-fallback {
  display: none;
  font-size: max(0.6875rem, calc(var(--fs-btn) * 0.92));
  letter-spacing: 0.01em;
  cursor: text;
  user-select: all;
}

/* --- copy --- */
/* No max-width here. The prototype let both lines run full-bleed and pinned
   the sub-headline with white-space:nowrap; leaving the column unconstrained
   reproduces that on wide screens and lets the text wrap naturally once the
   viewport is genuinely too narrow — which is exactly the mobile behaviour
   the nowrap was blocking. */
.hero__content {
  position: relative;
  z-index: 3;
  margin-top: auto;
  padding-bottom: var(--content-bottom);
  pointer-events: none;
}

.eyebrow {
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--fs-eyebrow);
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--accent);
}

.hero__title {
  margin: 0.21em 0 0.18em;
  font-size: var(--fs-title);
  line-height: 0.96;
  font-weight: 600;
  letter-spacing: -0.038em;
  color: var(--text-hi);
  text-wrap: balance;
}

.hero__sub {
  margin: 0;
  font-size: var(--fs-sub);
  line-height: 1.3;
  letter-spacing: -0.01em;
  font-weight: 400;
  color: var(--text-mid);
  text-wrap: balance;
}

/* --- short landscape phones: reclaim vertical space --- */
@media (max-height: 480px) and (orientation: landscape) {
  :root {
    --fs-title: clamp(1.75rem, 4.4vh + 0.5rem, 2.5rem);
    --fs-sub: 1rem;
    --content-bottom: 1.25rem;
    --figure-w: min(660px, calc(45vh * 1.07));
  }
  .hero__figure { top: 50%; }
}

/* -------------------------------------------------------------------------
   5. Motion preferences — hero.js also reads this and renders one static
   frame instead of starting a rAF loop.
   ------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  * {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
  .hero__figure { will-change: auto; }
}
