/*
 * Retiform Labs — component layer.
 *
 * Everything below is composed from tokens.css. The identity shows up here as
 * three recurring decisions:
 *   panels, not bubbles   — content sits in hairline-ruled panels, not cards
 *                           with shadows and rounded corners
 *   mono eyebrows         — small labels are the mono face, letterspaced and
 *                           uppercased, like instrument markings
 *   the lattice           — a node-line motif that runs under the hero and
 *                           separates major sections
 *
 * Motion is deliberately small: things arrive, they do not perform. Every
 * transition already degrades to nothing under prefers-reduced-motion via the
 * global rule in base.css, so no component re-declares that.
 */

/* ── layout ─────────────────────────────────────────────────────────────── */
.wrap {
  width: min(100% - 2 * var(--space-m), var(--wrap));
  margin-inline: auto;
}
.wrap--narrow {
  width: min(100% - 2 * var(--space-m), var(--wrap-narrow));
  margin-inline: auto;
}

.section { padding-block: var(--space-section); }
.section + .section { border-top: var(--border); }

/* ── eyebrow ────────────────────────────────────────────────────────────── */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  font-family: var(--font-mono);
  font-size: var(--fs--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--text-2);
}
.eyebrow::before {
  /* a single node — the motif at its smallest scale */
  content: "";
  width: 0.4em;
  height: 0.4em;
  background: var(--signal);
}

/* ── hero ───────────────────────────────────────────────────────────────── */
.hero {
  position: relative;
  padding-block: var(--space-hero);
  border-bottom: var(--border);
  overflow: hidden;
}
.hero__grid {
  display: grid;
  gap: var(--space-l);
  max-width: 46rem;
}
.hero__line {
  font-family: var(--font-display);
  font-size: var(--fs-6);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
}
.hero__line .accent {
  /* The gradient lands on the operative word: the thing that acts. It DRIFTS
   * rather than sweeps — a three-stop gradient (signal -> iris -> signal) laid
   * wider than the word, so both accents stay present at all times and only
   * their WEIGHT shifts. A two-stop gradient would read as a colour swap; this
   * reads as the thesis breathing. Slow, ease-in-out, named duration. */
  background: linear-gradient(90deg, var(--signal), var(--iris), var(--signal));
  background-size: 180% 100%;
  background-position: 0% 50%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: gradient-drift var(--dur-drift) ease-in-out infinite;
}
@keyframes gradient-drift {
  0%, 100% { background-position: 0% 50%; }
  50%      { background-position: 100% 50%; }
}
.hero__positioning {
  font-size: var(--fs-1);
  color: var(--text-2);
  max-width: 40rem;
}
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-s); }


/* ── buttons ────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2xs);
  padding: var(--space-xs) var(--space-m);
  border: var(--border-strong);
  border-radius: var(--radius);
  font-family: var(--font-mono);
  font-size: var(--fs--1);
  letter-spacing: 0.04em;
  color: var(--text-1);
  transition: border-color var(--dur) var(--ease), background var(--dur) var(--ease);
}
.btn:hover { border-color: var(--signal); text-decoration: none; }
.btn--primary {
  background: var(--signal);
  border-color: var(--signal);
  color: var(--ink);
}
.btn--primary:hover { background: var(--paper); border-color: var(--paper); }

/* ── panels (the grid of hairline-ruled cells) ──────────────────────────── */
.panel-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  /* 1px gaps become the rules between cells — the grid IS the divider */
  gap: 1px;
  background: var(--line);
  border: var(--border);
}
.panel {
  background: var(--surface-0);
  padding: var(--space-l);
  display: grid;
  gap: var(--space-xs);
  align-content: start;
}
.panel h3 { font-size: var(--fs-2); }
.panel p { color: var(--text-2); font-size: var(--fs-0); }
.panel__icon { color: var(--signal); font-family: var(--font-mono); font-size: var(--fs-1); }

/* ── work strip ─────────────────────────────────────────────────────────── */
.work {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
  gap: var(--space-m);
}
.work__item {
  border-top: var(--border);          /* muted at rest; the thread (below) draws signal */
  padding-top: var(--space-s);
  display: grid;
  gap: var(--space-2xs);
  color: inherit;           /* anchors keep the strip's own ink */
  text-decoration: none;
  transition: border-color var(--dur) var(--ease), transform var(--dur) var(--ease);
}
a.work__item:hover { transform: translateY(-2px); }
.work__name { font-family: var(--font-display); font-size: var(--fs-1); }
a.work__item:hover .work__name { color: var(--signal); }
.work__desc { color: var(--text-2); font-size: var(--fs--1); }

/* ── section header ─────────────────────────────────────────────────────── */
.section-head { display: grid; gap: var(--space-s); margin-bottom: var(--space-xl); max-width: 42rem; }
.section-head h2 { font-size: var(--fs-4); }
.section-head p { color: var(--text-2); }

/* ── site chrome ────────────────────────────────────────────────────────── */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  border-bottom: var(--border);
  background: color-mix(in oklab, var(--ink) 88%, transparent);
  backdrop-filter: blur(8px);
}
.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-m);
  padding-block: var(--space-s);
}
.brandmark { display: inline-flex; align-items: center; gap: var(--space-2xs); }
.brandmark__name {
  animation: bloom 7s ease-in-out infinite;
  font-family: var(--font-display);
  font-size: var(--fs-1);
  letter-spacing: var(--tracking-tight);
}
.nav { display: flex; gap: var(--space-m); }
.nav a { color: var(--text-2); font-size: var(--fs--1); font-family: var(--font-mono); }
.nav a:hover { color: var(--text-1); }

.site-footer {
  border-top: var(--border);
  padding-block: var(--space-xl);
  color: var(--text-2);
  font-size: var(--fs--1);
}
.site-footer__inner { display: flex; flex-wrap: wrap; gap: var(--space-m); justify-content: space-between; align-items: center; }

/* ── motion: things arrive, they do not perform ─────────────────────────── */
/* Applied only where JS is present (main.js adds .reveal-ready to <html>), so
   with scripting off nothing is ever hidden — the content is default-visible
   and enhancement only ever ADDS the entrance. */
/* NOTE: the selector is the ATTRIBUTE the markup actually carries ([data-reveal])
   — an earlier build targeted a .reveal class that was never authored, so the
   entrance never fired. The attribute is the contract; keep them in step. */
.reveal-ready [data-reveal] {
  opacity: 0;
  transform: translateY(0.5rem);
  transition: opacity var(--dur-slow) var(--ease), transform var(--dur-slow) var(--ease);
}
.reveal-ready [data-reveal].is-visible {
  opacity: 1;
  transform: none;
  transition-delay: var(--reveal-delay, 0ms);
}

/* ── responsive ─────────────────────────────────────────────────────────── */
@media (max-width: 40rem) {
  .site-header__inner { flex-wrap: wrap; }
  .nav { gap: var(--space-s); }
  .hero__grid { gap: var(--space-m); }
  .panel-grid { grid-template-columns: 1fr; } /* single column; rules still divide */
}


/* ── partners ───────────────────────────────────────────────────────────── */
/* The team block. Same panel language as the services grid — hairline-ruled
   cells, no cards with shadows — so the people sit in the same material world
   as everything else. The role list is deliberately plain and comprehensive:
   the scope of the officer's authority is a claim we stand behind. */
.about-prose { max-width: var(--wrap-narrow); }
.about-prose p + p { margin-top: var(--space-m); }

.partners {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(19rem, 1fr));
  gap: 1px;
  background: var(--line);
  border: var(--border);
  margin-top: var(--space-l);
}
.partner {
  background: var(--surface-0);
  padding: var(--space-l);
  display: grid;
  gap: var(--space-s);
  align-content: start;
}
.partner__name {
  font-family: var(--font-display);
  font-size: var(--fs-2);
  letter-spacing: var(--tracking-tight);
}
.partner__title {
  font-family: var(--font-mono);
  font-size: var(--fs--1);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--signal);
}
.partner__lede { color: var(--text-2); }
.partner__domains {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--space-2xs);
  border-top: var(--border);
  padding-top: var(--space-s);
}
.partner__domains li {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: var(--space-2xs);
  font-size: var(--fs--1);
  color: var(--text-2);
}
.partner__domains li::before {
  content: "";
  width: 0.4em;
  height: 0.4em;
  margin-top: 0.55em;
  background: var(--iris);
}
.partner__note { font-size: var(--fs--1); color: var(--text-2); }

/* Origin — a quieter, narrative block that closes the About section. Sits
   after the partner cells as the "how we got here" before the contact line. */
.origin {
  margin-top: var(--space-xl);
  border-top: var(--border);
  padding-top: var(--space-l);
}
.origin__head {
  font-family: var(--font-display);
  font-size: var(--fs-2);
  letter-spacing: var(--tracking-tight);
  line-height: 1.25;
  margin: var(--space-xs) 0 var(--space-s);
  max-width: 28ch;
}
.origin p + p { margin-top: var(--space-m); }

/* ═══════════════════════════════════════════════════════════════════════════
 * The lattice, in motion
 * ─────────────────────────────────────────────────────────────────────────
 * The node-line lattice — dots joined by thread-fine lines — is the Retiform Labs
 * signature motif (see BRAND.md §4: our texture, our divider, the logo's
 * parent). So what follows is not an effect borrowed from another site; it is
 * our own motif, drawn. Four gestures, each on a named step of the motion
 * scale. All of it collapses under prefers-reduced-motion (see base.css).
 * ═══════════════════════════════════════════════════════════════════════════ */

/* ── T3 · the join: two nodes, one thread — the lattice edge ─────────────────
 * Top edge draws left→right into a node at the top-left; the bottom edge mirrors
 * it, drawing right→left into a node at the bottom-right. Together the pair reads
 * as ONE lattice edge — two nodes joined by a thread, which is the motif itself.
 *
 * Both edges live on pseudo-elements (`inset: -2px`) because a BACKGROUND LAYER
 * CLIPS TO ITS BOX and can never straddle a hairline; a pseudo can overhang it.
 * ::before carries the top edge, ::after the bottom. Each pseudo holds two
 * background layers (thread + node) so they share one transition.
 */
.panel,
.work__item { position: relative; }

.panel::before,
.work__item::before,
.panel::after,
.work__item::after {
  content: "";
  position: absolute;
  inset: -4px;                 /* spill 4px so an 8px node can straddle the hairline */
  pointer-events: none;
  background-repeat: no-repeat, no-repeat;
  background-size: 0 1px, 0 0;
  transition: background-size var(--dur-lattice) var(--ease);
}

/* Top edge — thread draws left→right, node ignites at the top-left. */
.panel::before,
.work__item::before {
  background-image:
    linear-gradient(to right, var(--signal), var(--signal)),
    radial-gradient(circle closest-side, var(--signal) 92%, transparent 100%);
  background-position: 4px 4px, 0 0;
}

/* Bottom edge — thread draws right→left, node ignites at the bottom-right. */
.panel::after,
.work__item::after {
  background-image:
    linear-gradient(to left, var(--signal), var(--signal)),
    radial-gradient(circle closest-side, var(--signal) 92%, transparent 100%);
  background-position: right 4px bottom 4px, right bottom;
}

.panel:hover::before,
.work__item:hover::before,
.panel:hover::after,
.work__item:hover::after {
  background-size: calc(100% - 8px) 1px, 8px 8px;
}

/* Paint order: the grid's cells share DOM order, so a panel's bottom-right node
   spills into the NEXT cell's area — which paints after it and covers the node.
   (The top-left node spills into an EARLIER sibling, so it always survived —
   hence the asymmetry.) Lift the card on hover so its node sits above the grid. */
.panel:hover,
.work__item:hover { z-index: 1; }

/* ── T4 · rule-draw: a section's hairline signs itself in ─────────────────── */
.section-head {
  position: relative;
  padding-top: var(--space-s);
}
.section-head::before {
  content: "";
  position: absolute;
  top: 0; left: 0;
  width: 100%; height: 1px;
  background: var(--line);
  transform: scaleX(1);           /* default: a plain rule, always present */
  transform-origin: left center;
}
.reveal-ready .section-head::before {
  transform: scaleX(0);
  transition: transform var(--dur-draw) var(--ease);
}
.reveal-ready .section-head.is-visible::before { transform: scaleX(1); }

/* ── T5 · aurora breathe: the signature drifts behind the hero ────────────── */
.hero::before {
  content: "";
  position: absolute;
  inset: -20% -10%;
  z-index: -1;
  pointer-events: none;
  background:
    radial-gradient(60% 60% at 72% 26%,
      color-mix(in oklab, var(--signal) 30%, transparent), transparent 72%),
    radial-gradient(55% 55% at 26% 74%,
      color-mix(in oklab, var(--iris) 26%, transparent), transparent 72%);
  animation: aurora-breathe var(--dur-breathe) ease-in-out infinite;
}
@keyframes aurora-breathe {
  0%, 100% { opacity: 0.62; transform: scale(0.94); }
  50%      { opacity: 1;    transform: scale(1.14); }
}

/* ── T6 · sheen: light runs the primary edge ──────────────────────────────── */
.btn--primary { position: relative; overflow: hidden; }
.btn--primary::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(100deg,
    transparent 30%,
    color-mix(in oklab, var(--signal) 55%, transparent) 50%,
    transparent 70%);
  transform: translateX(-120%);
  pointer-events: none;
}
.btn--primary:hover::after {
  animation: sheen var(--dur-sheen) var(--ease) forwards;
}
@keyframes sheen { to { transform: translateX(120%); } }

/* ── reduced motion — the four new gestures, explicitly ───────────────────── */
@media (prefers-reduced-motion: reduce) {
  .hero::before { animation: none; opacity: 0.5; }
  .btn--primary:hover::after { animation: none; transform: translateX(-120%); }
  .panel::before, .panel::after,
  .work__item::before, .work__item::after {
    transition: none;
    background-size: calc(100% - 8px) 1px, 8px 8px;  /* resolve to the end state */
  }
  .reveal-ready .section-head::before { transform: scaleX(1); }
}

/* ── T7 · bloom: the wordmark breathes, slowly ─────────────────────────────── */
@keyframes bloom {
  /* The whole breath lives in the Signal hue: rest at the accent green, peak at
   * a lighter shade of the SAME green. It must never touch --text-1/--paper —
   * resting at near-white is what made the wordmark read white, and the brief
   * green flash mid-cycle was invisible against it. */
  0%, 100% { color: var(--signal); }
  50%      { color: var(--bloom); }
}

@media (prefers-reduced-motion: reduce) {
  .brandmark__name { animation: none; color: var(--signal); }
  .hero__line .accent { animation: none; background-position: 50% 50%; }
}
