/* ============================================================
   AI MADE THIS — shared design system
   One stylesheet, linked by every page, so the visual system
   stays unified and maintenance happens in one place.
   ============================================================ */

:root {
  /* Color */
  --green:      #6CF79E;   /* blended midpoint — solid anchor for small accents & focus rings */
  --green-deep: #4FE0B8;   /* hover / pressed solid fallback */
  /* Brand gradient (lime → cyan) — the primary brand accent on prominent marks */
  --grad-brand:      linear-gradient(105deg, #D2FC56 0%, #07F2E6 100%);
  --grad-brand-deep: linear-gradient(105deg, #B8E63D 0%, #05D0C6 100%);   /* hover/pressed */
  --ink:        #0A0A0A;   /* near-black — text, buttons, dark sections */
  --paper:      #FAF9F5;   /* warm off-white — default page bg */
  --muted:      #5C5C57;   /* secondary text on paper */
  --line:       #E6E4DC;   /* hairlines on paper */
  --card-ink:   #14141A;   /* dark card surfaces */

  /* Gradient used on the "hey!" wordmark + accents */
  --grad: linear-gradient(105deg,#8EC5FF 0%,#C9A8FF 42%,#FF9ECf 100%);

  /* Type */
  --font-sans: "Instrument Sans", Arial, sans-serif;
  --font-heading: "Geist Pixel", "Instrument Sans", Arial, sans-serif;

  --display-hero: clamp(40px, 13vw, 160px);
  --display-mega: clamp(67px, 8.4vw, 96px);
  --display-xl: clamp(48px, 5vw, 64px);
  --display-lg: clamp(40px, 4vw, 52px);
  --display-md: clamp(38px, 3.6vw, 53px);
  --display-sm: clamp(28px, 2.5vw, 36px);

  --title-lg: 32px;
  --title-md: 24px;

  --body-lg: 18px;
  --body-md: 16px;
  --body-sm: 14px;
  --caption: 12px;

  /* Radius */
  --r-pill: 999px;
  --r-card: 24px;
  --r-lg:   32px;

  /* Spacing rhythm */
  --pad:    clamp(20px, 5vw, 64px);
  --gap:    clamp(20px, 3vw, 32px);
  --sect:   clamp(72px, 10vw, 140px);

  /* Container */
  --maxw: 1240px;

  /* Layout */
  --nav-h: 64px;
  --nav-top: clamp(14px, 2.4vw, 24px);
  --header-offset: calc(var(--nav-top) + var(--nav-h) + 24px);
  /* Scroll-triggered hide/show toggle: quick, since it happens repeatedly
     as the user scrolls and needs to feel snappy rather than deliberate. */
  --nav-transition-duration: .45s;
  --nav-transition-easing: cubic-bezier(0.16, 0.84, 0.44, 1);
  /* Time-reverse of the easing above (mirrored control points), used only
     while the nav is hiding — see the comment on .nav.nav--hidden. */
  --nav-hide-easing: cubic-bezier(0.56, 0, 0.84, 0.16);
  /* First-load entrance: a one-time flourish, not a repeated interaction,
     so it's deliberately slower than the scroll toggle above — sharing the
     same quick duration made it read as too fast/abrupt. Same easing shape. */
  --nav-enter-duration: 1s;
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation: none !important; transition: none !important; }
}

/* Looping decorative animations are paused while off-screen (toggled by the
   IntersectionObserver in nav-scroll.js) so they stop consuming frame budget
   during scroll when nobody can see them. */
.anim-paused { animation-play-state: paused !important; }

body {
  margin: 0;
  padding-top: var(--header-offset);
  font-family: var(--font-sans);
  background: var(--paper);
  color: var(--ink);
  -webkit-font-smoothing: antialiased;
  font-size: var(--body-md);
  font-weight: 400;
  line-height: 1.5;
}

.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--pad); }

/* Soft dot-grid texture behind the hero, fading to nothing before the
   content below — opted into per-page via body.dots-hero. Anchored to
   body (not a section) so it starts at the true top of the page and
   spans the full viewport width, not the .wrap-constrained content
   column some heroes (e.g. About) sit inside. z-index:-1 keeps it behind
   in-flow content without needing an extra stacking context. */
body.dots-hero::before {
  content: "";
  position: fixed;
  top: 0; left: 0; right: 0;
  height: clamp(300px, 40vw, 480px);
  background-image: radial-gradient(rgba(10,10,10,.14) 1px, transparent 1.6px);
  background-size: 16px 16px;
  -webkit-mask-image: linear-gradient(to bottom, black 0%, transparent 85%);
  mask-image: linear-gradient(to bottom, black 0%, transparent 85%);
  pointer-events: none;
  z-index: -1;
}

/* ---------- Type ---------- */
h1,h2,h3 { font-family: var(--font-heading); font-weight: 400; line-height: 1; margin: 0; }
.display,
.hero-title { font-size: var(--display-mega); font-weight: 400; line-height: 1; letter-spacing: -0.045em; }
h2.section-title,
.section-title { font-size: var(--display-lg); font-weight: 400; line-height: 1; letter-spacing: -0.035em; }

/* Visually hidden, but available to screen readers and crawlers. */
.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;
}
h3,
.card-title { font-size: var(--title-md); font-weight: 600; line-height: 1.25; letter-spacing: -0.01em; }
.eyebrow { font-family: var(--font-sans); font-weight: 600; text-transform: uppercase; letter-spacing: 0.14em; font-size: var(--caption); color: var(--muted); }
.lede,
.body-large { font-size: var(--body-lg); font-weight: 400; line-height: 1.55; }
.lede { color: var(--muted); max-width: 46ch; }
a { color: inherit; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-sans); font-weight: 600; font-size: 15px;
  padding: 13px 24px; border-radius: var(--r-pill);
  text-decoration: none; border: 1.5px solid transparent; cursor: pointer;
  transition: transform .15s ease, background .2s ease, color .2s ease;
}
.btn:hover { transform: translateY(-2px); }
.btn:focus-visible { outline: 3px solid var(--green); outline-offset: 3px; }
.btn--dark  { background: var(--ink); color: #fff; }
.btn--dark:hover { background: #000; }
.btn--ghost { background: transparent; color: var(--ink); border-color: var(--ink); }
.btn--ghost:hover { background: var(--ink); color: #fff; }
.btn--ghost-light { background: transparent; color: #fff; border-color: rgba(255,255,255,.6); }
.btn--ghost-light:hover { background: #fff; color: var(--ink); border-color: #fff; }
.btn--green { background: var(--grad-brand); color: var(--ink); }
.btn--green:hover { background: var(--grad-brand-deep); }
.btn .arrow { transition: transform .2s ease; }
.btn:hover .arrow { transform: translateX(3px); }

/* ---------- Nav (floating island) ---------- */
.nav {
  position: fixed; top: var(--nav-top); left: 50%;
  z-index: 100;
  height: var(--nav-h); box-sizing: border-box;
  width: max-content; max-width: calc(100% - 32px);
  display: flex; align-items: center; justify-content: center;
  gap: clamp(28px,4vw,56px); padding: 0 24px;
  background: var(--ink); border-radius: var(--r-pill);
  box-shadow: 0 12px 32px rgba(0,0,0,.18);
  transform: translate(-50%, 0) scale(1);
  transform-origin: top center;
  transition: transform var(--nav-transition-duration) var(--nav-transition-easing);
}
/* Hiding needs its own (mirrored) easing, not just the show one in reverse.
   The show curve is an ease-out (fast start, slow settle) which is right
   for something arriving. Applied to hiding, that front-loads the exit: the
   nav travels enough distance to fully clear the viewport well before the
   transition's own duration is up, so it visually vanishes partway through
   and "finishes" invisibly — reading as an abrupt cut rather than a glide.
   This rule's transition (matched on class-add, i.e. while hiding) uses the
   time-reverse of the show curve instead, so the slow/visible part of the
   motion happens while the nav is still on-screen, and the fast part is the
   bit that's rushing off past the edge anyway. Duration stays identical to
   the show transition — only the easing shape differs. */
.nav.nav--hidden {
  transform: translate(-50%, calc(-1 * (var(--nav-top) + var(--nav-h) + 20px))) scale(0.1);
  transition: transform var(--nav-transition-duration) var(--nav-hide-easing);
}

/* Load-in entrance: starts off-screen above (shrunk to 10%, same as the
   scroll-hidden state), drops into place and scales up once the page (and
   any intro overlay) is ready. Same easing shape as the scroll-up show
   above, but its own slower duration — see --nav-enter-duration. Cleaned up
   by JS after it finishes so it never fights with the scroll-hide state. */
.nav.nav-pre-enter { transform: translate(-50%, calc(-1 * (var(--nav-top) + var(--nav-h) + 20px))) scale(0.1); opacity: 0; }
body.page-in .nav.nav-pre-enter {
  transform: translate(-50%, 0) scale(1);
  opacity: 1;
  transition: transform var(--nav-enter-duration) var(--nav-transition-easing), opacity var(--nav-enter-duration) ease;
}
.brand { display: flex; align-items: center; gap: 10px; font-family: var(--font-sans); font-weight: 600; font-size: 16px; text-decoration: none; letter-spacing: -0.01em; color: #fff; white-space: nowrap; }
.brand .mark { width: 24px; height: 24px; border-radius: 6px; object-fit: cover; display: block; }
.brand-ast { background: var(--grad-brand); -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent; color: transparent; font-weight: 700; margin: 0 -0.38em; }
.nav-links { display: flex; align-items: center; gap: clamp(14px,1.8vw,28px); }
.nav-links a { text-decoration: none; font-weight: 500; font-size: 15px; padding: 4px 0; color: rgba(255,255,255,.72); border-bottom: 2px solid transparent; transition: color .15s ease; white-space: nowrap; }
.nav-links a:hover { color: #fff; }
.nav-links a[aria-current="page"] { color: #fff; font-weight: 600; }
.nav-links a.btn, .nav-links a.btn:hover { padding: 10px 20px; border-bottom: none; }
/* Subscribe button lives as the last item in .nav-links, so it sits at the
   right end of the pill on desktop and drops into the fullscreen menu on
   mobile. Uses .btn/.btn--green colors; these rules just fit it to the nav. */
.nav-links .nav-subscribe { padding: 9px 18px; border: none; margin-left: 4px; background: #fff; color: var(--ink); }
.nav-links .nav-subscribe:hover { background: rgba(255,255,255,.82); }
.nav-toggle { display: none; background:none; border:none; cursor:pointer; padding: 8px; margin-right: -8px; }
@media (max-width: 860px){
  .nav {
    left: 16px; right: 16px; top: var(--nav-top); transform: translate(0,0) scale(1);
    width: auto; max-width: none; justify-content: space-between; padding: 0 18px;
    transition: transform var(--nav-transition-duration) var(--nav-transition-easing),
                height .5s var(--nav-transition-easing),
                border-radius .5s var(--nav-transition-easing),
                top .5s var(--nav-transition-easing),
                left .5s var(--nav-transition-easing),
                right .5s var(--nav-transition-easing),
                padding .5s var(--nav-transition-easing);
  }
  .nav.nav--hidden { transform: translate(0, calc(-1 * (var(--nav-top) + var(--nav-h) + 20px))) scale(0.1); }
  .nav.nav-pre-enter { transform: translate(0, calc(-1 * (var(--nav-top) + var(--nav-h) + 20px))) scale(0.1); }
  body.page-in .nav.nav-pre-enter { transform: translate(0, 0) scale(1); }

  /* The pill itself morphs into the fullscreen menu — .nav is a transformed
     element, which makes it the containing block for its fixed .nav-links
     child (see nav-links below), so growing .nav's own box is what carries
     the overlay along with it, rather than fighting that containment. */
  .nav.menu-open {
    top: 0; left: 0; right: 0;
    height: 100vh; height: 100dvh;
    border-radius: 0;
    align-items: flex-start;
    padding: var(--nav-top) var(--pad) 24px;
  }

  .nav-links {
    display: flex; visibility: hidden; opacity: 0; pointer-events: none;
    position: fixed; inset: 0; z-index: -1;
    flex-direction: column; align-items: center; justify-content: center;
    gap: clamp(10px, 3vw, 18px);
    background: var(--ink);
    padding: 0 var(--pad);
    text-align: center;
    transition: opacity .3s ease, visibility 0s linear .3s;
  }
  .nav-links.open { visibility: visible; opacity: 1; pointer-events: auto; transition: opacity .3s ease .2s; }
  .nav-links a { font-family: var(--font-heading); font-size: clamp(32px, 11vw, 56px); font-weight: 400; letter-spacing: -0.02em; border-bottom: none; }
  .nav-links a.btn { font-family: var(--font-sans); font-size: 15px; margin-top: 12px; }
  /* In the fullscreen menu the Subscribe button reads as a normal-sized
     button, not a giant heading-font menu item. */
  .nav-links .nav-subscribe { font-size: 16px; padding: 14px 26px; margin-top: 20px; margin-left: 0; }
  .nav-toggle { display: block; }
  body.menu-open { overflow: hidden; }
}

/* ---------- Cursor trail ---------- */
.cursor-trail-dot {
  position: fixed;
  top: 0; left: 0;
  width: 8px; height: 8px;
  background: var(--grad-brand);
  opacity: .9;
  transition: opacity 1.4s ease;
  pointer-events: none;
  z-index: 9999;
}

/* ---------- Logo strip ---------- */
.logo-strip-label { margin: 80px 0 20px; text-align: center; }
.logo-strip {
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: 28px 56px;
}
.logo-strip img { height: 32px; width: auto; max-width: 100%; object-fit: contain; filter: brightness(0); opacity: .45; }
@media (max-width: 560px){
  .logo-strip { gap: 22px 32px; }
  .logo-strip img { height: 24px; }
}

/* ---------- Asterisk signature ---------- */
.asterisk { display:inline-block; line-height:0; }
.asterisk svg { display:block; }

/* ---------- Sections ---------- */
.section { padding-block: var(--sect); }
/* Standalone list pages (Experiments/Books/Resources) open straight onto
   their section-head right below the nav, so the full --sect padding-top
   on top of body's nav-clearance padding stacked into an oversized gap. */
.section--first { padding-top: clamp(24px, 4vw, 40px); }
.section-head { text-align:center; max-width: 640px; margin: 0 auto clamp(40px,6vw,72px); }
.section-head .lede { margin: 16px auto 0; }

/* Widens a .wrap to the same 1280px content width as the Articles band. */
.wrap--wide { max-width: calc(1280px + var(--pad) * 2); }

/* ---------- Staggered card reveal (Experiments / Resources / Books) ----------
   Uses a keyframe animation rather than a transition: transitions need a
   rendered "before" frame to animate from, which cards already in view at
   page load never get (class added, then immediately observed — no paint
   in between), so they'd just snap in with no motion. An animation plays
   its full timeline regardless of prior paint state. animation-delay is
   left out of the shorthand below so the per-card stagger set via JS
   (inline style) isn't reset by it.

   Book/resource cards separately run their own always-on
   `transition: transform` for the hover lift; having that transition and
   this animation both drive `transform` at the same time produced a
   visible double-motion glitch. The `.reveal-card` override below mutes
   that transition for as long as the class is present, and JS removes the
   class the moment the reveal animation ends — so hover goes right back
   to normal afterwards without ever overlapping the reveal. */
.exp-card.reveal-card,
.resource-card.reveal-card,
.book-card.reveal-card,
.featured-article.reveal-card,
.article-row.reveal-card {
  transition: none !important;
}

@keyframes cardReveal {
  from { opacity: 0; transform: translateY(28px); }
  to { opacity: 1; transform: translateY(0); }
}
.reveal-card {
  opacity: 0;
  transform: translateY(28px);
}
.reveal-card.is-visible {
  animation-name: cardReveal;
  animation-duration: 900ms;
  /* A gentler ease-out than the .22,1,.36,1 "expo" curve: that one front-loads
     ~90% of the opacity/translate motion into the first 300ms, so the tail of
     the duration is an imperceptible creep and the whole thing reads as an
     abrupt snap instead of a fluid glide. This curve spreads the motion more
     evenly across the full duration. */
  animation-timing-function: cubic-bezier(0.16, 0.84, 0.44, 1);
  /* Must be "both", not just "forwards": staggered cards get a non-zero
     animation-delay, and with only "forwards" the delay period isn't
     covered by the keyframes at all — the browser falls through to plain
     (non-animation) property values instead. This rule used to also set
     opacity:1/transform:translateY(0) as plain declarations, which meant
     every delayed card popped fully visible for its entire delay, then
     snapped back to hidden the instant the animation actually started —
     a visible flicker. "both" holds the `from` keyframe through the delay
     and the `to` keyframe after completion, so no plain fallback is needed.
   */
  animation-fill-mode: both;
}

/* ---------- Experiment / card grid ---------- */
.grid { display:grid; gap: var(--gap); }
.grid--3 { grid-template-columns: repeat(3, 1fr); }
.grid--auto { grid-template-columns: repeat(auto-fill, minmax(240px,1fr)); }
@media (max-width: 960px){ .grid--3 { grid-template-columns: 1fr 1fr; } }
@media (max-width: 620px){ .grid--3 { grid-template-columns: 1fr; } }

.exp-card { display:flex; flex-direction:column; text-decoration:none; color:inherit; }
.exp-card .thumb {
  border-radius: var(--r-card); aspect-ratio: 4/5; overflow:hidden;
  display:grid; place-items:center; position:relative;
  background: #ddd; margin-bottom: 20px;
}
.exp-card .thumb img { position:absolute; inset:0; width:100%; height:100%; object-fit:cover; }
/* Top-right "open" affordance on every experiment card (home carousel + the
   Experiments page grid share the .exp-card/.thumb markup). Decorative — the
   whole card is already the link — so it's a pseudo-element, not real markup. */
.exp-card .thumb::after {
  content: "";
  position: absolute; bottom: 12px; right: 12px; z-index: 2;
  width: 38px; height: 38px; border-radius: 50%;
  background-color: transparent;
  border: 1px solid rgba(255,255,255,.6);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23ffffff' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 16 16 8'/%3E%3Cpath d='M9 8h7v7'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: center; background-size: 18px 18px;
  transition: background-color .2s ease, border-color .2s ease;
  pointer-events: none;
}
.exp-card:hover .thumb::after {
  background-color: #fff;
  border-color: #fff;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%230A0A0A' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M8 16 16 8'/%3E%3Cpath d='M9 8h7v7'/%3E%3C/svg%3E");
}
.exp-card h3 { margin-bottom: 10px; }
.exp-card p { color: var(--muted); margin:0; max-width: 34ch; }
.exp-card .eyebrow { margin-bottom: 12px; }
.tag { display:inline-block; font-size:12px; font-weight:600; text-transform:uppercase; letter-spacing:.08em; padding:5px 11px; border-radius:var(--r-pill); background:var(--ink); color:#fff; margin-bottom:12px; align-self:flex-start; }
.tag--live { background: var(--grad-brand); color: var(--ink); }

/* ---------- Articles layout: featured card (image on top) + a list of
   smaller rows (square thumb + text) alongside it ---------- */
.articles-layout {
  display: grid;
  grid-template-columns: minmax(280px, 42%) 1fr;
  gap: clamp(32px,5vw,64px);
  margin-bottom: clamp(32px,5vw,48px);
}
.featured-article { display: flex; flex-direction: column; text-decoration: none; color: inherit; }
.featured-article-media { border-radius: var(--r-card); aspect-ratio: 6/5; margin-bottom: 24px; }
.featured-article-body h3 { font-size: var(--display-sm); font-weight: 600; letter-spacing: -0.02em; line-height: 1.1; margin: 0 0 16px; }
.featured-article-body p { color: var(--muted); font-size: var(--body-md); line-height: 1.6; max-width: 52ch; margin: 0 0 16px; }
.featured-link { display: inline-flex; align-items: center; gap: 8px; font-weight: 700; }
.featured-link .arrow { transition: transform .2s ease; }
.featured-article:hover .featured-link .arrow,
.article-row:hover .featured-link .arrow { transform: translateX(3px); }

.article-list { display: flex; flex-direction: column; gap: clamp(24px,3vw,36px); }
.article-row { display: grid; grid-template-columns: clamp(110px,14vw,160px) 1fr; gap: clamp(20px,2.5vw,32px); align-items: start; text-decoration: none; color: inherit; }
.article-row-media { border-radius: var(--r-card); aspect-ratio: 1/1; }
.article-row-body h3 { font-size: var(--title-md); margin: 0 0 10px; }
.article-row-body p { color: var(--muted); font-size: var(--body-sm); line-height: 1.55; margin: 0 0 10px; }
@media (max-width: 860px){
  .articles-layout { grid-template-columns: 1fr; }
}
@media (max-width: 560px){
  .article-row { grid-template-columns: 88px 1fr; }
}

/* ---------- Articles (light band) ---------- */
.articles-band { background: var(--paper); color: var(--ink); border-block: 1px solid var(--line); }
/* +2*--pad cancels out .wrap's own border-box padding, so the content
   (not the padding-inclusive box) actually measures 1280px. */
.articles-band .wrap { max-width: calc(1280px + var(--pad) * 2); }

/* ---------- Experiments (dark band) ---------- */
.experiments-band { color: var(--paper); }
.experiments-band .eyebrow { color: #A5A5A0; }
.experiments-band .lede { color: #A5A5A0; }
.experiments-band .exp-card p { color: #A5A5A0; }
.experiments-band .exp-card .thumb { background: var(--card-ink); }
.experiments-band .logo-strip img { filter: brightness(0) invert(1); opacity: .55; }

/* The dark Experiments/Books bands are transparent so the fixed atmospheric
   backdrop (.bg-atmos, below) shows through them. Their base tone is the same
   #0A0A0A the backdrop paints, so the seam with the hero's ink fade is clean. */
.experiments-band,
.books-band { background: transparent; }

/* ---------- Fixed atmospheric backdrop ----------------------------------
   Three fixed, full-viewport layers over a dark base, all pointer-events:none
   and behind every content layer (z-index:-1). Because they're fixed they stay
   put as the page scrolls, and they're revealed wherever a section sits on a
   transparent/dark background (hero video, Experiments, Books). Opaque light
   sections (Articles, Resources, footer) intentionally cover them.
     1. blobs — soft radial gradients for coloured, smoky atmosphere
     2. dots  — a fine staggered polka-dot grid, very low opacity
     3. grain — SVG fractalNoise, desaturated, low opacity, to break smoothness
   Normal blending keeps the blob colours true; the grey dots/grain only add
   light/dark speckle without shifting hue. */
.bg-atmos { position: fixed; inset: 0; z-index: -1; pointer-events: none; background: #0A0A0A; }
.bg-atmos-layer { position: fixed; inset: 0; pointer-events: none; }
.bg-atmos-blobs {
  background-image:
    radial-gradient(46% 40% at 12% 8%,  rgba(210,252,86,.20), transparent 60%),
    radial-gradient(42% 38% at 90% 14%, rgba(140,197,255,.15), transparent 62%),
    radial-gradient(55% 50% at 80% 96%, rgba(7,242,230,.15), transparent 60%),
    radial-gradient(50% 46% at 26% 82%, rgba(128,96,255,.12),  transparent 62%);
}
/* Two identical dot grids offset by half a tile give the staggered (half-drop)
   polka-dot look. Dots are light and very low-alpha so they read as a subtle
   texture on the dark base, not a bold pattern. */
.bg-atmos-dots {
  background-image:
    radial-gradient(rgba(255,255,255,.05) 0.5px, transparent 1px),
    radial-gradient(rgba(255,255,255,.05) 0.5px, transparent 1px);
  background-size: 6px 6px;
  background-position: 0 0, 3px 3px;
}
.bg-atmos-grain {
  opacity: .09;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='grain'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23grain)'/%3E%3C/svg%3E");
  background-size: 140px 140px;
}

/* ---------- Experiments carousel (looping, edge-bleeding) ---------- */
.exp-carousel-bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  overflow: hidden;
  margin-bottom: clamp(40px,6vw,72px);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.45) 9%, black 22%, black 78%, rgba(0,0,0,.45) 91%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, rgba(0,0,0,.45) 9%, black 22%, black 78%, rgba(0,0,0,.45) 91%, transparent 100%);
}
.exp-carousel-track {
  display: flex;
  gap: 24px;
  width: max-content;
  padding-inline: var(--pad);
  animation: expCarouselLoop 60s linear infinite;
  will-change: transform;
}
.exp-carousel-bleed:hover .exp-carousel-track { animation-play-state: paused; }
@keyframes expCarouselLoop { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.exp-carousel-track .exp-card { flex: 0 0 auto; width: clamp(240px, 24vw, 320px); }
.exp-carousel-track .exp-card .thumb { aspect-ratio: 4 / 5.5; }
@media (max-width: 780px){
  /* On mobile the marquee stops auto-scrolling and becomes a manual
     horizontal swipe. The bleed wrapper turns into the scroll container, and
     the duplicate loop set (only needed for the seamless animation) is hidden
     so the user swipes through each card once instead of repeats. */
  .exp-carousel-bleed {
    overflow-x: auto;
    overflow-y: hidden;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
  }
  .exp-carousel-bleed::-webkit-scrollbar { display: none; }
  .exp-carousel-track { animation: none; }
  .exp-carousel-track .exp-card[aria-hidden="true"] { display: none; }
  .exp-carousel-track .exp-card { width: 220px; scroll-snap-align: start; }
}

/* ---------- Resource chips ---------- */
.chips { display:flex; flex-wrap:wrap; gap:12px; }
.chip { display:inline-flex; align-items:center; gap:9px; padding:10px 16px; border:1px solid var(--line); border-radius:var(--r-pill); background:#fff; font-weight:500; font-size:15px; text-decoration:none; transition:border-color .15s ease, transform .15s ease; }
.chip:hover { border-color: var(--ink); transform: translateY(-2px); }
.chip .dot { width:22px; height:22px; border-radius:50%; background:var(--grad-brand); display:grid; place-items:center; font-size:11px; }

/* ---------- Home resources marquee ---------- */
.home-resource-bleed {
  width: 100vw;
  margin-left: calc(50% - 50vw);
  margin-bottom: var(--gap);
  display: flex;
  justify-content: center;
}
.home-resource-rows {
  width: 100%;
  max-width: 1600px;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  gap: 14px;
  padding: 14px 0;
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
}
.home-resource-row {
  --row-offset: 0px;
  display: flex;
  align-items: center;
  gap: 14px;
  min-width: max-content;
  width: max-content;
  animation: homeMarqueeLeft 58s linear infinite;
  will-change: transform;
}
.home-resource-row:nth-child(1) { --row-offset: -40px; }
.home-resource-row:nth-child(2) { --row-offset: 60px; animation-name: homeMarqueeRight; animation-duration: 68s; }
.home-resource-row:nth-child(3) { --row-offset: -20px; animation-duration: 62s; }
@keyframes homeMarqueeLeft { from { transform: translateX(var(--row-offset)); } to { transform: translateX(calc(var(--row-offset) - 33.3333%)); } }
@keyframes homeMarqueeRight { from { transform: translateX(calc(var(--row-offset) - 33.3333%)); } to { transform: translateX(var(--row-offset)); } }
.home-resource-pill {
  height: 72px;
  width: max-content;
  padding: 0 24px 0 12px;
  border-radius: var(--r-pill);
  background: #F1EFE7;
  border: 1px solid var(--line);
  color: var(--ink);
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  transition: background .15s ease, transform .15s ease, box-shadow .15s ease, border-color .15s ease;
}
.home-resource-pill:hover { transform: translateY(-2px); box-shadow: 0 8px 20px rgba(0,0,0,.08); border-color:#cfcdc4; }
.home-resource-logo { width:48px; height:48px; border-radius:50%; object-fit:contain; background:#F1EFE7; padding:10px; flex-shrink:0; }
.home-resource-name { font-family: var(--font-sans); font-size:15px; font-weight:600; white-space:nowrap; }
@media (max-width: 640px){ .home-resource-rows { mask-image: none; -webkit-mask-image: none; } }

/* ---------- Books ---------- */
.books-band { color: var(--paper); overflow: hidden; }
.books-band .section-head .lede,
.books-band .eyebrow { color: #A5A5A0; }
.home-books-orbit {
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  width: min(1300px, 90vw);
  aspect-ratio: 1;
  margin-block: clamp(10px,2vw,24px);
  --radius: 480px;
}
.home-books-ring {
  position: absolute;
  inset: 0;
  animation: homeBooksSpin 90s linear infinite;
}
@keyframes homeBooksSpin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } }
.home-books-orbit:hover .home-books-ring { animation-play-state: paused; }
.home-book-orbit-item {
  position: absolute;
  top: 50%;
  left: 50%;
  width: 140px;
  height: 200px;
  margin: -100px 0 0 -70px;
  transform: rotate(calc(var(--i) * 22.5deg)) translateY(calc(-1 * var(--radius)));
  display: block;
  border-radius: 20px;
  overflow: hidden;
  box-shadow: 0 10px 28px rgba(0,0,0,.35);
  transition: box-shadow .18s ease;
}
.home-book-orbit-item img { width:100%; height:100%; object-fit:cover; display:block; }
.home-book-orbit-item:hover { box-shadow: 0 16px 34px rgba(0,0,0,.5); }
.home-books-center {
  position: absolute;
  inset: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(16px,4vw,32px);
}
.home-books-center .section-head { margin: 0; }
.home-books-center .mt-btn { margin-top: clamp(20px,3vw,28px); }
@media (max-width: 780px){
  .home-books-orbit { width: min(420px, 94vw); --radius: 190px; }
  .home-book-orbit-item { width: 50px; height: 72px; margin: -36px 0 0 -25px; border-radius: 12px; }
  .home-book-orbit-item:nth-child(even) { display: none; }
}

/* ---------- Subscribe + footer band (full-bleed) ---------- */
.subscribe-footer {
  /* Same staggered dot texture as the hero, layered over the brand gradient.
     Dots are dark (the footer gradient is bright) and sit in the element's own
     background so they always paint behind the footer content — no z-index. */
  background-image:
    radial-gradient(rgba(10,10,10,.10) 0.6px, transparent 1.2px),
    radial-gradient(rgba(10,10,10,.10) 0.6px, transparent 1.2px),
    var(--grad-brand);
  background-size: 6px 6px, 6px 6px, cover;
  background-position: 0 0, 3px 3px, center;
  background-repeat: repeat, repeat, no-repeat;
  width: 100vw;
  margin-left: calc(50% - 50vw);
  padding-top: var(--sect);
  position: relative;
  overflow: hidden;
  border-radius: 32px 32px 0 0;
}
.subscribe-footer-content { position: relative; }
.subscribe-footer .footer { border-top: 1px solid rgba(10,10,10,.15); margin-top: 40px; color: rgba(10,10,10,.7); }

/* ---- Footer top: title + subscribe left, contact/socials right ---- */
.footer-top {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--pad);
  align-items: start;
}

.footer-left { display: flex; flex-direction: column; gap: var(--gap); }

.footer-title {
  font-size: clamp(48px, 6.4vw, 100px);
  line-height: .96;
  letter-spacing: -0.03em;
}
.footer-title-line { display: flex; align-items: center; gap: 0.16em; }

.footer-blocks { display: flex; flex-direction: column; gap: var(--gap); }
.footer-block .eyebrow { margin: 0; }
.footer-block-text { color: rgba(10,10,10,.8); max-width: 440px; margin: 0 0 16px; }
/* Native subscribe form (posts to Kit via kitSubscribe in nav-scroll.js) —
   white pill with the email input and dark Subscribe button inline. */
/* Native subscribe form (posts to Kit via kitSubscribe in nav-scroll.js) —
   shared by the footer band and the nav Subscribe pop-up. */
.footer-subscribe .form,
.subscribe-modal .form { display:flex; gap:10px; width:100%; max-width:440px; background:#fff; border-radius:var(--r-pill); padding:6px; margin:0; }
.footer-subscribe .form input,
.subscribe-modal .form input { flex:1; min-width:0; border:none; background:none; padding:12px 18px; font-family:var(--font-sans); font-size:15px; color:var(--ink); outline:none; }
.form-msg { margin:12px 0 0; font-size:14px; font-weight:600; color:var(--ink); min-height:1em; }
.form-msg.is-error { color:#b00020; }

/* ---------- Subscribe pop-up ---------- */
.subscribe-modal { position: fixed; inset: 0; z-index: 200; visibility: hidden; opacity: 0; transition: opacity .25s ease, visibility 0s linear .25s; }
.subscribe-modal.open { visibility: visible; opacity: 1; transition: opacity .25s ease; }
.subscribe-modal-backdrop { position: absolute; inset: 0; background: rgba(10,10,10,.6); }
.subscribe-modal-card {
  position: absolute; top: 50%; left: 50%;
  transform: translate(-50%, -46%);
  width: min(460px, calc(100% - 32px));
  background: var(--paper); color: var(--ink);
  border-radius: var(--r-lg); padding: clamp(28px, 4vw, 40px);
  box-shadow: 0 24px 64px rgba(0,0,0,.35);
  transition: transform .25s var(--nav-transition-easing);
}
.subscribe-modal.open .subscribe-modal-card { transform: translate(-50%, -50%); }
.subscribe-modal-close {
  position: absolute; top: 14px; right: 14px;
  width: 36px; height: 36px; border-radius: 50%;
  border: none; background: rgba(10,10,10,.06); color: var(--ink);
  font-size: 22px; line-height: 1; cursor: pointer;
  display: grid; place-items: center; transition: background .15s ease;
}
.subscribe-modal-close:hover { background: rgba(10,10,10,.12); }
.subscribe-modal-card .eyebrow { margin: 0 0 10px; }
.subscribe-modal-title { font-size: var(--display-sm); margin: 0 0 12px; }
.subscribe-modal-text { color: var(--muted); margin: 0 0 20px; max-width: 40ch; }
body.modal-open { overflow: hidden; }

.footer-email { display: inline-block; margin-top: 10px; font-size: var(--title-md); font-weight: 600; letter-spacing: -0.01em; text-decoration: none; }
.footer-email:hover { text-decoration: underline; }

.footer-social-list { display: flex; flex-direction: column; gap: 10px; margin-top: 10px; }
.footer-social-list a { display: inline-flex; align-items: center; gap: 6px; width: fit-content; font-weight: 600; font-size: var(--title-md); text-decoration: none; }
.footer-social-list a:hover { text-decoration: underline; }
.footer-social-list a .arrow { display: inline-block; transition: transform .2s ease; }
.footer-social-list a:hover .arrow { transform: translate(3px,-3px); }

@media (max-width: 780px) {
  .footer-top { grid-template-columns: 1fr; gap: 40px; }
}

/* ---------- Footer (default, non-lime pages) ---------- */
.footer { border-top:1px solid var(--line); padding-block: 40px; display:flex; flex-wrap:wrap; gap:20px; justify-content:space-between; align-items:center; color:var(--muted); font-size:14px; }
.footer a { text-decoration:none; }
.footer a:hover { text-decoration:underline; }
/* Small asterisk (from images/asterisk-icon.svg) in the copyright line, sized to
   the text and recoloured to near-black with brightness(0) — the file is green. */
.footer-heart { display: inline-block; }
.footer-heart img { width: 0.9em; height: auto; vertical-align: -0.1em; filter: brightness(0); }

/* ---------- Utility ---------- */
.sq { width:26px; height:26px; background:var(--grad-brand); border-radius:4px; }
.center { text-align:center; }
.mt-btn { margin-top: clamp(32px,5vw,48px); display:flex; justify-content:center; }

/* ---------- Filter sidebar (Resources / Books category panels) ----------
   Shared between resources.html and books.html — was previously declared
   identically in each page's own <style> block. */
.sidebar-item {
  display:flex; align-items:center; justify-content:space-between; gap:10px;
  width:100%; padding: 10px 14px; border-radius: 14px; border:none; background:none;
  font-family: var(--font-sans); font-size:15px; font-weight:500; color: var(--ink); cursor:pointer; text-align:left;
  transition: background .12s ease;
}
.sidebar-item:hover { background: rgba(10,10,10,.05); }
.sidebar-item.active { background:#fff; font-weight:700; box-shadow: 0 2px 8px rgba(0,0,0,.06); }
.sidebar-item-count { flex-shrink:0; font-size:13px; font-weight:600; color: var(--muted); }
.sidebar-item.active .sidebar-item-count { color: var(--ink); }
