/* ==========================================================================
   STRAND INTERGALACTIC — BASE
   Loads after strand-design-tokens.css. Every colour and type value below
   resolves to a token; the only literals are geometry (px radii, blur,
   durations), which the token file does not govern.
   ========================================================================== */

/* ---- Derived values -----------------------------------------------------
   Not new colours — compositions of existing tokens, kept here (never in the
   token file) so the source of truth stays a flat list of decided values.
   --hairline is the token file's "dividers/borders on dark backgrounds"
   role, which needs an alpha the flat token cannot carry.                   */
:root {
  --hairline:        color-mix(in srgb, var(--gray-on-dark) 20%, transparent);
  --hairline-strong: color-mix(in srgb, var(--gray-on-dark) 32%, transparent);
  --hairline-light:  color-mix(in srgb, var(--gray-on-light) 24%, transparent);
  --wash-blue:       color-mix(in srgb, var(--cta-blue) 8%, transparent);
  --wash-accent:     color-mix(in srgb, var(--mood-accent) 10%, transparent);
  --edge-blue:       color-mix(in srgb, var(--cta-blue) 28%, transparent);
  --edge-accent:     color-mix(in srgb, var(--mood-accent) 30%, transparent);
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--navy-ink);
  color: var(--headline-white);
  font-family: var(--font-display);
  font-size: var(--body-3-size);
  line-height: var(--body-3-line-height);
  -webkit-font-smoothing: antialiased;
}

a { color: var(--cta-blue); text-decoration: none; }
a:hover { color: var(--headline-light-blue); }
::selection { background: var(--cta-blue); color: var(--pure-white); }

@keyframes strandPulse { 0%,100% { opacity: .55; } 50% { opacity: 1; } }
@keyframes strandSpin  { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }

image-slot { display: block; width: 100%; height: 100%; }

/* dc-runtime.js injects "html,body,#dc-root,#dc-root>.sc-host{height:100%}" at
   load time, into a <style> appended to <head> — so it always lands after this
   file and only !important beats it. On a page taller than one viewport that
   clamps each wrapper to exactly 100vh, and a position:sticky element can only
   stick inside its containing block: once you scroll past the first screen the
   nav runs out of block and slides away up the page.

   html and body are in this list because the nav now lives outside the x-dc
   element, which makes body its containing block rather than #dc-root. */
html, body, #dc-root, #dc-root > .sc-host { height: auto !important; min-height: 100%; }

/* ==========================================================================
   NAV + MOBILE DRAWER
   The token file makes the wordmark nowrap and requires a hamburger to exist
   for that rule to survive narrow viewports. This is that hamburger.
   Open/closed state is a data-nav-open attribute on the nav, set by the small
   script at the foot of index.html. The nav sits outside the x-dc element, so
   that attribute is plain DOM that dc-runtime's React root never overwrites.
   ========================================================================== */
[data-nav] {
  background: var(--space-black-scrim);
  border-bottom: 1px solid var(--hairline);
}
[data-nav-links] a { color: var(--gray-on-dark); transition: color .15s ease; }
[data-nav-links] a:hover { color: var(--headline-white); }
[data-nav-links] a[data-nav-cta] { color: var(--pure-white); background: var(--cta-blue); transition: background .15s ease; }
[data-nav-links] a[data-nav-cta]:hover { color: var(--pure-white); background: var(--cta-blue-hover); }

/* Hamburger — hidden until the link row would start crowding the wordmark.
   Measured in Chrome at the token sizes: the wordmark is 300px wide and the
   five nav items 870px, which with the 16px gap and the 48px gutters needs
   1282px. Below that the row has to either wrap or squeeze the wordmark, and
   the token file rules out both — so 1280 is where the drawer takes over. */
[data-nav-toggle] {
  display: none;
  flex: none;
  width: 44px; height: 44px;
  padding: 0;
  align-items: center;
  justify-content: center;
  gap: 5px;
  flex-direction: column;
  background: transparent;
  border: 1px solid var(--hairline);
  border-radius: 8px;
  cursor: pointer;
}
[data-nav-toggle] span {
  display: block;
  width: 18px; height: 1.5px;
  background: var(--headline-white);
  border-radius: 2px;
  transition: transform .22s ease, opacity .18s ease;
}
[data-nav][data-nav-open="1"] [data-nav-toggle] span:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
[data-nav][data-nav-open="1"] [data-nav-toggle] span:nth-child(2) { opacity: 0; }
[data-nav][data-nav-open="1"] [data-nav-toggle] span:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

@media (max-width: 1280px) {
  [data-nav] { padding: 12px 18px !important; }
  [data-nav-toggle] { display: flex; }

  /* The row becomes a drawer: full-width, below the bar, stacked. It is
     absolutely positioned, so it overlays the page instead of moving it and
     needs no height animation at all — it fades and slides in on opacity and
     transform, which also keeps the reveal on the compositor.

     Nothing here toggles visibility or display, and nothing animates a
     height: the element stays rendered in both states and only opacity and
     transform change. An earlier version collapsed the drawer with a
     max-height transition and it did not reveal reliably, which is the usual
     outcome — a max-height animation also needs a hard-coded cap and eases
     against a value the content never reaches.

     Keeping the closed links out of the tab order is therefore the `inert`
     attribute's job, set by the nav script: it removes them from focus and
     from the accessibility tree without touching rendering. The max-height
     below is a static cap for short viewports, never an animated value. */
  [data-nav-links] {
    position: absolute !important;
    top: 100% !important; left: 0 !important; right: 0 !important;
    flex-direction: column !important;
    align-items: stretch !important;
    gap: 0 !important;
    padding: 0 18px !important;
    background: var(--space-black);
    border-bottom: 1px solid var(--hairline);
    max-height: 78vh;
    overflow-y: auto;
    opacity: 0;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity .2s ease, transform .22s ease;
  }
  [data-nav][data-nav-open="1"] [data-nav-links] {
    opacity: 1;
    transform: none;
    pointer-events: auto;
  }
  [data-nav-links] a {
    padding: 16px 2px !important;
    border-bottom: 1px solid var(--hairline);
  }
  [data-nav-links] a[data-nav-cta] {
    margin: 16px 0 20px !important;
    text-align: center;
    border-bottom: 0;
  }
}

/* ============ RESPONSIVE ============
   The page is authored as inline styles (Claude Design canvas output), so a
   stylesheet can only reach them with !important — hence every rule below.
   Targets are data-* hooks on the markup: dc-runtime re-serialises every inline
   style on render ('padding:52px' becomes 'padding: 52px'), so [style*=...]
   selectors written in the source's compact form silently never match.

   The type scale itself is fluid in strand-type.css, so nothing here needs to
   restate a font-size — these rules are layout only. */
@media (max-width: 760px) {

  /* 48px of gutter each side ate 26% of a 375px viewport. */
  section { padding-left: 22px !important; padding-right: 22px !important;
            padding-top: 66px !important; padding-bottom: 66px !important; }

  /* Every auto-fit grid demands a 200-420px minimum track inside a ~330px
     column, so each one overflowed. Collapse them all to a single column. */
  [style*="minmax("] { grid-template-columns: 1fr !important; }

  /* Inner panel padding, same story as the section gutters. */
  [data-pad="proof"]       { padding: 24px !important; }
  [data-pad="contact"]     { padding: 26px !important; }
  [data-pad="split"]       { padding: 34px 24px !important; }
  [data-pad="loop-detail"] { padding: 22px !important; }

  /* The attribution donut is a fixed 360px SVG. */
  svg { max-width: 100% !important; height: auto !important; }

  /* Guardrail rail: five nodes on one line need more width than a phone has.
     Drop the connecting line and the travelling dot — the dot's offset is
     computed from bounding rects, which a wrapped layout invalidates — and
     grid the nodes instead. */
  [data-guardrail-line], [data-guardrail-dot] { display: none !important; }
  /* minmax(0,1fr), not 1fr: a grid track's implicit minimum is min-content, so
     the "GENERATION" column grew past its third and pushed the whole rail 7px
     wider than the section. Flooring the minimum at 0 keeps the three columns
     equal and inside the gutters. */
  [data-guardrail-track] > div:last-child { display: grid !important;
      grid-template-columns: repeat(3, minmax(0, 1fr)) !important; gap: 20px 6px !important; }
  [data-guardrail-node] { padding: 4px !important; }
  [data-guardrail-node] > span:last-child { white-space: normal !important;
      text-align: center; }

  /* The "Cycle" loop is a 640px ring with chips placed on a 45%-radius circle;
     at ~330px a chip centred at left:95% hangs 70px past the edge and no
     amount of shrinking fixes it. Unroll the ring into a plain stack and drop
     the two decorative circles. */
  [data-loop-ring] { width: 100% !important; height: auto !important;
      display: flex !important; flex-direction: column !important; gap: 10px !important; }
  [data-loop-deco] { display: none !important; }
  [data-loop-node] { position: static !important; transform: none !important; }
  [data-loop-center] { position: static !important; inset: auto !important;
      padding: 22px 0 0 !important; }

  /* The about column reserved a 380px minimum inside a ~330px row. Clearing
     the minimum alone let it shrink to 91px beside the 140px portrait, so the
     row stacks instead. */
  [data-about-row] { flex-direction: column !important; align-items: flex-start !important;
      gap: 24px !important; }
  [data-about-col] { min-width: 0 !important; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  [data-loop-deco] { animation: none !important; }
}
