/* apinae.dev — placeholder site
   Tokens are the same ones the logo generator emits (brand/src/build_logo.py).
   Keep them in sync; nothing here should invent a new colour. */

@font-face {
  font-family: 'Space Grotesk';
  src: url('/fonts/SpaceGrotesk.ttf') format('truetype');
  font-weight: 300 700; font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/fonts/SpaceMono-Regular.ttf') format('truetype');
  font-weight: 400; font-display: swap;
}
@font-face {
  font-family: 'Space Mono';
  src: url('/fonts/SpaceMono-Bold.ttf') format('truetype');
  font-weight: 700; font-display: swap;
}

:root {
  --ink:      #14120F;
  --cream:    #FBF7EF;
  --honey:    #F7B500;
  --pollen:   #FFD24A;
  --amber:    #8A5C00;   /* darkened for WCAG AA (4.5:1) on the cream/panel backgrounds */

  --bg:       var(--cream);
  --fg:       var(--ink);
  --muted:    #6C6455;
  --rule:     #E7DFCE;
  --panel:    #FFFCF6;

  /* bee + comb + pointer, consumed by the generated sprite */
  --wing-a:   var(--pollen);
  --wing-b:   #FFE9A8;
  --antenna:  var(--ink);
  --glint:    var(--cream);

  /* honey, as a body rather than a flat fill: light face, mid, and the dark
     it goes where it is thick or pooling against something */
  --honey-lt: var(--pollen);
  --honey-dk: #8A5E00;

  --comb-wax:    #F0C14B;                /* the wax slab, lit */
  --comb-wax-dk: #CF9C24;                /* and its shaded side */
  --comb-mid:    #6B4A05;                /* inside a cell, near the mouth */
  --comb-deep:   #35240B;                /* and at the bottom of it */

  --ptr-fill: var(--cream);
  --ptr-edge: var(--ink);

  --depth:    9px;                        /* isometric extrusion */

  --measure:  min(1180px, 100% - 2 * clamp(20px, 5vw, 56px));
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  position: relative;                 /* the canvas is measured against this */
  background-color: var(--bg);
  color: var(--fg);
  font-family: 'Space Grotesk', system-ui, sans-serif;
  font-size: clamp(16px, 1.05vw, 17.5px);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ── the ground ───────────────────────────────────────────────────────────
   Absolute, not fixed: the honeycomb and the comb belong to the page and
   scroll with it. The cells are filled, and a section's colour is a property
   of the cells inside it, so the change from one section to the next happens
   cell by cell. Painted by paintGround() in site.js, which measures the real
   sections — there are no magic heights here. */
.canvas {
  position: absolute; inset: 0; z-index: -2;
  overflow: hidden; pointer-events: none;
}

.ground { position: absolute; top: 0; left: 0; display: block; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 99;
  background: var(--ink); color: var(--cream); padding: 12px 18px;
  border-radius: 0 0 10px 0; font-size: 14px;
}
.skip:focus { left: 0; }

a { color: inherit; }
:focus-visible { outline: 2px solid var(--amber); outline-offset: 3px; border-radius: 4px; }

/* ── the hive in the corner ───────────────────────────────────────────────
   Inside .canvas, so it hangs off the top of the page and scrolls away with
   it rather than following the viewport like a widget. .canvas clips it,
   which is what makes it read as attached to the edge. */
.comb {
  position: absolute; top: clamp(-58px, -5vw, -30px); right: clamp(-46px, -3.6vw, -22px);
  transform-origin: 100% 0; transform: rotate(7deg);
  filter: drop-shadow(0 10px 18px rgba(0,0,0,.45));
}
.comb svg { display: block; width: clamp(196px, 20vw, 320px); height: auto; }

/* ── header ───────────────────────────────────────────────────────────────
   Sits in the dark half of the ground, so it is styled for ink, not wax. */
.site-head {
  position: relative; z-index: 4;
  width: var(--measure); margin: 0 auto;
  padding: clamp(18px, 2.6vw, 30px) 0;
  display: flex; align-items: center; justify-content: space-between; gap: 24px;
  color: var(--cream);
}
.brand img { display: block; width: clamp(168px, 17vw, 232px); height: auto; }
.site-nav { display: flex; align-items: center; gap: clamp(14px, 2vw, 26px); }
.site-nav > a:not(.btn) {
  font-size: 14px; color: #B8AE9A; text-decoration: none;
  border-bottom: 1px solid transparent; padding-bottom: 2px;
}
.site-nav > a:not(.btn):hover { color: var(--cream); border-bottom-color: var(--honey); }
.site-head .btn--ghost {
  background: rgba(251,247,239,.05); border-color: rgba(251,247,239,.22);
  color: var(--cream);
}
.site-head .btn--ghost:hover {
  border-color: var(--honey); background: rgba(247,181,0,.14);
}
/* The hive owns the top-right corner and nothing clickable goes under it,
   so the nav is held off by roughly the width the comb actually occupies. */
.site-nav { margin-right: clamp(74px, 10vw, 168px); }

.btn {
  display: inline-block; font: inherit; font-size: 14.5px; font-weight: 500;
  text-decoration: none; border-radius: 999px; padding: 10px 20px;
  white-space: nowrap; cursor: pointer;
  transition: transform .18s ease, background-color .18s ease, border-color .18s ease;
}
.btn--ghost { border: 1px solid var(--rule); background: var(--panel); }
.btn--ghost:hover { border-color: var(--honey); transform: translateY(-1px); }
.btn--solid {
  background: var(--ink); color: var(--cream); border: 1px solid var(--ink);
  padding: 14px 26px; font-size: 15.5px;
}
.btn--solid:hover { background: #241F19; transform: translateY(-1px); }

/* On a narrow screen the hive owns the top-right corner; the nav link is
   redundant there because the section is one scroll away. */
@media (max-width: 620px) {
  .site-nav > a:not(.btn) { display: none; }
  /* the comb, the logo and the one button have to share ~350px without
     touching — every number here is measured against the others */
  .comb svg { width: 120px; }
  .site-nav { margin-right: 86px; }
  .brand img { width: 132px; }
  .site-head .btn { font-size: 13px; padding: 8px 14px; }
  .site-head { padding-bottom: 6px; gap: 12px; }
}

/* ── hero ─────────────────────────────────────────────────────────────── */
/* The top padding is not decoration. The head/hero boundary is a ragged one,
   and cells defect up to BLEED rows either side of it — this is the room that
   ragged edge needs to land in without touching the header above it or the
   headline below it. Shrink it and ink hexagons come down on the cap line. */
.hero {
  width: var(--measure); margin: 0 auto;
  padding: clamp(142px, 16vh, 190px) 0 clamp(40px, 7vh, 76px);
}
.hero__title { margin: 0; }

.stage {
  display: block;
  font-size: clamp(2.05rem, 8.4vw, 7.6rem);
  font-weight: 700;
  letter-spacing: -0.035em;
  line-height: 1.06;
  /* room for a letter to fall over without clipping or nudging the layout */
  padding-bottom: .16em;
  /* last-resort guard: never let the headline push the page sideways */
  overflow-wrap: anywhere;
}

/* Each character is its own box so it can topple independently.
   Depth is a stacked shadow at a fixed 45°, honey-coloured — it rotates with
   the glyph, so the extruded side sweeps into view as one falls. */
.ch {
  display: inline-block;
  position: relative;
  transform-origin: 50% 92%;
  will-change: transform;
  color: var(--ink);
  text-shadow:
     .008em .008em 0 var(--honey), .016em .016em 0 var(--honey),
     .024em .024em 0 var(--honey), .032em .032em 0 var(--honey),
     .040em .040em 0 var(--honey), .048em .048em 0 var(--honey),
     .056em .056em 0 var(--honey), .064em .064em 0 var(--honey),
     .072em .072em 0 var(--amber);
}

/* a machine put the wrong glyph here */
.ch.is-corrupt {
  font-family: 'Space Mono', ui-monospace, monospace;
  font-weight: 700;
  color: var(--amber);
  text-shadow:
     .010em .010em 0 rgba(201,138,0,.30), .020em .020em 0 rgba(201,138,0,.28),
     .030em .030em 0 rgba(201,138,0,.24), .040em .040em 0 rgba(201,138,0,.20),
     .050em .050em 0 rgba(201,138,0,.16);
}

/* the replacement glyph a bee carries in, and the corrupt one it carries out */
/* transform-origin sits on the flight point, not on the glyph's own middle.
   hangCargo() cancels the flyer's heading so the letter stays upright and
   underneath — and a rotation can only cancel another rotation if both turn
   about the same point. */
.cargo {
  position: fixed; top: 0; left: 0; z-index: 6;
  transform-origin: 0 0;
  font-family: 'Space Grotesk', sans-serif; font-weight: 700;
  letter-spacing: -0.035em; line-height: 1;
  pointer-events: none; will-change: transform;
  color: var(--ink);
  text-shadow:
     .008em .008em 0 var(--honey), .016em .016em 0 var(--honey),
     .024em .024em 0 var(--honey), .032em .032em 0 var(--honey),
     .040em .040em 0 var(--honey), .048em .048em 0 var(--honey),
     .056em .056em 0 var(--honey), .064em .064em 0 var(--honey),
     .072em .072em 0 var(--amber);
}
.cargo.is-corrupt {
  font-family: 'Space Mono', monospace; color: var(--amber);
  text-shadow: 2px 2px 0 rgba(201,138,0,.28), 4px 4px 0 rgba(201,138,0,.22);
}

/* hero bees fly above the type */
/* Zero-sized on purpose. The flyer is a *point* on the flight path: gsap
   writes its position and heading, and rotation must happen about that point.
   Give it a box and transform-origin becomes the middle of whatever it
   happens to contain — so the bee drifts off the path, and it drifts by a
   different amount once a carried letter changes the box's size. */
.flyer {
  position: fixed; top: 0; left: 0; width: 0; height: 0; z-index: 7;
  pointer-events: none; will-change: transform;
}
.flyer svg { display: block; width: 96px; height: auto; overflow: visible; }

.hero__sub {
  margin: clamp(22px, 3.4vh, 40px) 0 0;
  /* wide enough that each sentence takes one line once .br-lg kicks in */
  max-width: 54ch;
  font-size: clamp(1.02rem, 1.55vw, 1.32rem);
  color: var(--muted);
}
.br-lg { display: none; }
@media (min-width: 720px) { .br-lg { display: inline; } }

.hero__honest {
  display: inline-flex; align-items: center; gap: 10px;
  margin: clamp(20px, 3vh, 32px) 0 0;
  padding: 8px 16px 8px 12px;
  border: 1px solid var(--rule); border-radius: 999px;
  background: var(--panel);
  font-size: 14px; color: var(--muted);
}
.hero__honest .dot {
  width: 8px; height: 8px; border-radius: 50%; background: var(--honey);
  box-shadow: 0 0 0 4px rgba(247,181,0,.18);
}

/* ── figures ──────────────────────────────────────────────────────────── */
.eyebrow {
  font-size: 12px; letter-spacing: .15em; text-transform: uppercase;
  color: var(--muted); font-weight: 500; margin: 0 0 clamp(20px, 3vw, 30px);
}
.figures {
  width: var(--measure); margin: 0 auto;
  padding: clamp(46px, 8vh, 88px) 0 clamp(20px, 4vh, 40px);
  border-top: 1px solid var(--rule);
}
.figures__grid {
  display: grid; gap: clamp(24px, 3.4vw, 44px);
  grid-template-columns: repeat(auto-fit, minmax(224px, 1fr));
}
.fig { display: flex; flex-direction: column; gap: 10px; }
.fig__n {
  font-size: clamp(2.1rem, 4.4vw, 3.4rem); font-weight: 700;
  letter-spacing: -0.03em; line-height: 1;
  font-variant-numeric: tabular-nums;
}
.fig:nth-child(2) .fig__n { color: var(--amber); }
.fig__l { font-size: 14.5px; color: var(--muted); max-width: 30ch; }

.figures__note {
  margin: clamp(30px, 4vw, 46px) 0 0; max-width: 68ch;
  font-size: 14.5px; color: var(--muted);
}

.report {
  display: grid; gap: 6px;
  /* the wax-dim -> pollen boundary is ragged and lands in this gap, so it
     has to be at least twice R_CELL + BLEED * DY (see bandEdges) */
  margin-top: clamp(150px, 15vw, 200px);
  padding: clamp(22px, 2.6vw, 30px);
  border: 1px solid var(--rule); border-radius: 16px;
  background: var(--panel); text-decoration: none;
  transition: border-color .2s ease, transform .2s ease;
}
.report:hover { border-color: var(--honey); transform: translateY(-2px); }
.report__k { font-size: 11.5px; letter-spacing: .13em; text-transform: uppercase; color: var(--muted); }
.report__t { font-size: clamp(1.2rem, 2.2vw, 1.6rem); font-weight: 600; letter-spacing: -0.02em; }
.report__d { font-size: 14.5px; color: var(--muted); max-width: 56ch; }
.report__go { margin-top: 6px; font-size: 14px; color: var(--amber); font-weight: 500; }

/* ── talk + capture ───────────────────────────────────────────────────── */
.talk {
  width: var(--measure); margin: clamp(46px, 8vh, 90px) auto 0;
  padding: clamp(40px, 6vh, 76px) 0 clamp(46px, 8vh, 90px);
  border-top: 1px solid var(--rule);
  display: grid; gap: clamp(34px, 5vw, 66px);
  grid-template-columns: 1fr;
}
@media (min-width: 940px) { .talk { grid-template-columns: 1.15fr .85fr; } }

.talk__copy h2 {
  margin: 0 0 18px; font-size: clamp(1.5rem, 3.1vw, 2.3rem);
  font-weight: 600; letter-spacing: -0.028em; line-height: 1.2;
}
.talk__copy p { margin: 0 0 16px; max-width: 52ch; color: var(--muted); }
.talk__meta {
  font-family: 'Space Mono', monospace; font-size: 13px;
  color: var(--amber); margin-bottom: 22px !important;
}

.capture {
  align-self: start;
  padding: clamp(24px, 3vw, 32px);
  border: 1px solid var(--rule); border-radius: 16px; background: var(--panel);
}
.capture h3 { margin: 0 0 8px; font-size: 1.05rem; font-weight: 600; }
.capture p { margin: 0 0 18px; font-size: 14px; color: var(--muted); }
.capture__row { display: flex; gap: 8px; flex-wrap: wrap; }
.capture input {
  flex: 1 1 190px; min-width: 0; font: inherit; font-size: 15px;
  padding: 12px 14px; border-radius: 10px;
  border: 1px solid var(--rule); background: var(--bg); color: var(--fg);
}
.capture input::placeholder { color: #756D5C; }
.capture input:focus-visible { border-color: var(--honey); }
.capture button {
  font: inherit; font-size: 14.5px; font-weight: 500; cursor: pointer;
  padding: 12px 20px; border-radius: 10px;
  border: 1px solid var(--ink); background: var(--ink); color: var(--cream);
  transition: background-color .18s ease;
}
.capture button:hover { background: #241F19; }
.capture button[disabled] { opacity: .55; cursor: progress; }
.capture__msg { margin: 12px 0 0 !important; font-size: 13.5px; min-height: 1.2em; }
.capture__msg.is-ok { color: var(--amber); }
.capture__msg.is-err { color: #B4442B; }

/* ── footer ───────────────────────────────────────────────────────────── */
.site-foot {
  width: var(--measure); margin: 0 auto;
  padding: clamp(30px, 4vh, 44px) 0 clamp(46px, 7vh, 72px);
  border-top: 1px solid var(--rule);
  display: flex; gap: 26px; justify-content: space-between;
  flex-wrap: wrap; align-items: flex-start;
}
.foot__who { display: flex; gap: 14px; align-items: flex-start; max-width: 56ch; }
.foot__who img { flex: none; margin-top: 2px; }
.foot__who p { margin: 0; font-size: 14px; color: var(--muted); }
.foot__who strong { color: var(--fg); font-weight: 600; }
.foot__social { display: flex; gap: 20px; flex-wrap: wrap; }
.foot__social a { font-size: 14px; color: var(--muted); text-decoration: none; }
.foot__social a:hover { color: var(--fg); text-decoration: underline; text-underline-offset: 3px; }

/* The footer sits after its own base rules so nothing overrides it on a
   narrow screen: it stacks, and who + socials each centre their row. */
@media (max-width: 620px) {
  .site-foot { flex-direction: column; align-items: center; text-align: center; gap: 24px; }
  .foot__who { flex-direction: column; align-items: center; }
  .foot__social { justify-content: center; }
}

/* ── sections that sit on ink ─────────────────────────────────────────────
   The ground alternates dark and light down the page, so the three sections
   that land on ink carry their own type colours. Everything here is the same
   token as its light-ground counterpart, read against the other end of the
   palette — no new colours. */
.on-ink { color: var(--cream); }
.on-ink h2, .on-ink h3, .on-ink strong { color: var(--cream); }
.on-ink p, .on-ink .fig__l { color: #E0D7C3; }
.on-ink a { color: var(--pollen); }
.talk.on-ink, .site-foot.on-ink { border-top-color: rgba(251,247,239,.12); }
.on-ink .talk__meta { color: var(--pollen); }

.on-ink .btn--solid {
  background: var(--honey); color: var(--ink); border-color: var(--honey);
}
.on-ink .btn--solid:hover { background: var(--pollen); border-color: var(--pollen); }

/* The panel has to be a surface, not a hint of one. Over a near-black
   honeycomb a 4% wash disappears completely and the form reads as floating
   text — the fields in particular have to look like fields. Glassy frosted
   glass: a light tint blurred behind it, so the comb stays a suggestion and
   the form still reads clean. */
.on-ink .capture {
  background: rgba(251,247,239,.08);
  border-color: rgba(251,247,239,.30);
  backdrop-filter: blur(10px) saturate(1.4);
  -webkit-backdrop-filter: blur(10px) saturate(1.4);
}
.on-ink .capture input {
  background: rgba(251,247,239,.18); border-color: rgba(251,247,239,.5);
  color: var(--cream);
}
.on-ink .capture input::placeholder { color: #C6BBA2; }
.on-ink .capture input:focus-visible {
  border-color: var(--pollen); background: rgba(251,247,239,.26);
}
.on-ink .capture button {
  background: var(--honey); color: var(--ink); border-color: var(--honey);
}
.on-ink .capture button:hover { background: var(--pollen); }
.on-ink .capture__msg.is-ok { color: var(--pollen); }
.on-ink .capture__msg.is-err { color: #E8785C; }

.on-ink .foot__social a { color: #CFC6B1; font-weight: 500; }
.on-ink .foot__social a:hover { color: var(--cream); }

/* ── bees ─────────────────────────────────────────────────────────────────
   Every bee on the page is one <use href="#bee">, so one rule flaps all of
   them. The leaf is drawn root-at-origin, tip at +x — fill-box puts the hinge
   on the wing root instead of the corner of the sprite's own viewBox. */
.wing {
  transform-box: fill-box; transform-origin: 0 50%;
  animation: flutter .105s linear infinite;
}
.wing--near { animation-delay: -.035s; animation-duration: .098s; }
@keyframes flutter {
  0%, 100% { transform: rotate(-13deg) scaleX(1); }
  50%      { transform: rotate(14deg)  scaleX(.86); }
}

/* ── custom cursor ────────────────────────────────────────────────────── */
.cursor, .beefield { position: fixed; inset: 0; z-index: 9; pointer-events: none; }
/* Opacity and the slide-out offset are written by the script every frame, in
   the same transform string as the position. They are deliberately not CSS
   transitions or a separate `scale` property: the spec applies `scale` before
   `transform`, so a scaled pointer collapses toward the element's origin at
   the top-left of the viewport rather than toward its own tip. */
.cursor__ptr {
  position: absolute; top: 0; left: 0;
  width: 34px; height: 44px; overflow: visible;
  will-change: transform, opacity;
  opacity: 0;
  filter: drop-shadow(0 2px 3px rgba(20,18,15,.22));
}

.cbee { position: absolute; top: 0; left: 0; will-change: transform; }
.cbee__in { will-change: transform; }
.cbee svg { display: block; width: 36px; height: auto; overflow: visible; }
.cursor__ptr.is-down { filter: drop-shadow(0 1px 2px rgba(20,18,15,.3)); }
.drop {
  position: absolute; top: -3px; left: 10px; width: 10px; height: 11px;
  border-radius: 50% 50% 50% 50% / 62% 62% 38% 38%;
  background: radial-gradient(60% 55% at 36% 30%,
              var(--pollen) 0%, var(--honey) 52%, var(--honey-dk) 100%);
  box-shadow: 0 1px 2px rgba(138,94,0,.45);
  will-change: transform;
}

/* Only take over the cursor when there is a real pointer to take over, and
   only once the script says it is ready. */
html.has-cursor,
html.has-cursor * { cursor: none !important; }
html:not(.has-cursor) .cursor,
html:not(.has-cursor) .beefield { display: none; }

@media (hover: none), (pointer: coarse) {
  html.has-cursor, html.has-cursor * { cursor: auto !important; }
  .cursor, .beefield { display: none !important; }
}

/* ── motion off ───────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  html.has-cursor, html.has-cursor * { cursor: auto !important; }
  .cursor, .beefield { display: none !important; }
  .flyer, .cargo { display: none !important; }
  * { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ── ?still — capture mode ────────────────────────────────────────────────
   The share card is a screenshot of this page's hero (see build_og). The
   sections below it would show as a cut-off heading along the bottom edge of
   a 1200x630 frame, which reads as a rendering accident rather than a design.

   visibility, not display: paintGround() measures the real sections to decide
   where its colour bands go, so their geometry has to stay exactly where it
   is. Hiding the ink is enough. */
.is-still main > section:not(.hero),
.is-still .site-foot { visibility: hidden; }

/* ?pose — the capture page with the bee systems staged (see posePage()).
   The cursor layer is normally gated behind a real fine pointer, and headless
   Chrome does not always report one, so it is forced on here. Specificity
   plus !important, because the touch-device rule it has to beat also uses
   !important. */
.is-pose .cursor,
.is-pose .beefield { display: block !important; }

/* ── 404 ────────────────────────────────────────────────────────────────
   The not-found page is intentionally static: no canvas, no GSAP, no
   analytics. It must render with CSS alone, so these rules are plain. */
.nf {
  min-height: 60vh;
  display: flex; flex-direction: column; align-items: center;
  justify-content: center; text-align: center;
  padding: clamp(48px, 8vw, 120px) 24px;
}
.nf__code {
  font-family: 'Space Mono', ui-monospace, monospace;
  font-size: clamp(72px, 16vw, 160px); font-weight: 700; line-height: 1;
  letter-spacing: -.04em; color: var(--honey); margin: 0 0 8px;
}
.nf__title { margin: 0 0 12px; font-size: clamp(22px, 3vw, 30px); }
.nf__sub { margin: 0 auto 28px; max-width: 46ch; color: var(--muted); }
.nf__actions { display: flex; gap: 12px; flex-wrap: wrap; justify-content: center; }
.nf__note { margin-top: 34px; font-size: 13px; color: var(--muted); }
.nf__note a { color: var(--honey); }

/* The 404 is the index hero stretched over the whole page: ink ground with
   faint honeycomb cells painted behind it by site.js (band mode '404'). The
   ground paints after first paint, so the body colour covers the pre-paint
   flash and any JS-less fallback. */
body[data-ground='404'] {
  background: var(--ink);
  color: var(--cream);
}
/* Ghost buttons inherit the light-panel look; on ink they need the same
   quiet dark treatment the site-head nav uses. */
body[data-ground='404'] .btn--ghost {
  background: rgba(251,247,239,.05); border-color: rgba(251,247,239,.22);
  color: var(--cream);
}
body[data-ground='404'] .btn--ghost:hover {
  border-color: var(--honey); background: rgba(247,181,0,.14);
}
